Ive spent quite a bit of time researching how best to reuse the existing great libraries written in c++ - in c#. I was looking at some really good cross platform gui stuff for use in cross platform projects, for example. WxWindows (www.wxwindows.org) and swt (part of Eclipse www.eclipse.org).
C# is very good at accessing c libraries through pinvoke (using extern), but reusing c++ libraries are notoriously difficult (see other posts for info on different ways mangling is done and all the issues)
One option was using MS Visual C++ managed extensions to expose the functions to the managed world. Directly porting the existing c++ code like this looks like a lot of work! Adding a managed piece that then passes through the calls to the unmananged library would work but there were issues.
C++ supports having mixed dll's or exe's - ie you can embed managed and unmanaged code together. This works fine in a windows environment but without understanding the exact mechanics of how ms .net allows this, I suspect that it�s a problem for MONO/DotGNU. The other option would be my c# program calling a managed c++ dll (which will/should run under DotGNU/Mono) calling an unmanaged dll. Yuck!
Other posts I read pointed me to swig. www.swig.org this is a cross platform app that builds addons to allow c++ libraries to be used from java apps, Perl, Python etc. etc. But no .net
This stuff is pretty clever, it�s a partial compiler, including precompiler and parser that then builds the necessary c code to be added and compiled into your c++ dll and the java jni code (in the case of java). It also builds a wrapper around these jni calls so that you can use your object in java in exactly the same way as the c++ object.
V. cool stuff. So I grabbed the cvs and hacked the java stuff to see if I could get some decent results for .net. Now there is plenty of work left and ill need weeks before I find enough time to finish but basically - as an example - this is what it does at the moment:
 
Very simple c++ object example
==============================
class Shape {
public:
  Shape() {
    nshapes++;
  }
  virtual ~Shape() {
    nshapes--;
  };
  double  x, y;  
  void    move(double dx, double dy);
  virtual double area(void) = 0;
  virtual double perimeter(void) = 0;
  static  int nshapes;
  };
 
class Circle : public Shape {
private:
  double radius;
public:
  Circle(double r) : radius(r) { };
  virtual double area(void);
  virtual double perimeter(void);
};
 
class Square : public Shape {
private:
  double width;
public:
  Square(double w) : width(w) { };
  virtual double area(void);
  virtual double perimeter(void);
};
#define M_PI 3.14159265358979323846
 
/* Move the shape to a new location */
void Shape::move(double dx, double dy) {
  x += dx;
  y += dy;
}
 
int Shape::nshapes = 0;
 
double Circle::area(void) {
  return M_PI*radius*radius;
}
 
double Circle::perimeter(void) {
  return 2*M_PI*radius;
}
 
double Square::area(void) {
  return width*width;
}
 
double Square::perimeter(void) {
  return 4*width;
}
 
RUN .net SWIG, produces:
============================
 
#define DllExport   __declspec( dllexport )
extern "C" {
DllExport void delete_Shape(int jarg1) {
    Shape *arg1 = (Shape *) 0 ;
   
    arg1 = *(Shape **)&jarg1;
    delete arg1;
}
 
DllExport void set_Shape_x(int jarg1, double jarg2) {
    Shape *arg1 = (Shape *) 0 ;
    double arg2 ;
   
    arg1 = *(Shape **)&jarg1;
    arg2 = (double)jarg2;
    if (arg1) (arg1)->x = arg2;
   
}
 
DllExport double get_Shape_x(int jarg1) {
    double jresult = 0 ;
    Shape *arg1 = (Shape *) 0 ;
    double result;
   
    arg1 = *(Shape **)&jarg1;
    result = (double) ((arg1)->x);
   
    jresult = (double)result;
    return jresult;
}
 
DllExport void Shape_move(int jarg1, double jarg2, double jarg3) {
    Shape *arg1 = (Shape *) 0 ;
    double arg2 ;
    double arg3 ;
   
    arg1 = *(Shape **)&jarg1;
    arg2 = (double)jarg2;
    arg3 = (double)jarg3;
    (arg1)->move(arg2,arg3);
   
}
 
DllExport int get_Shape_nshapes() {
    int jresult = 0 ;
    int result;
   
    result = (int)Shape::nshapes;
   
    jresult = (int)result;
    return jresult;
}
 
�BLA BLA�
 
DllExport long SquareToShape(long jarg1) {
    long baseptr = 0;
    *(Shape **)&baseptr = *(Square **)&jarg1;
    return baseptr;
}
}
 
AND
The Matching c# code:
=====================
using System.Runtime.InteropServices;
class examplePINVOKE {
  [DllImport("example")]
  public static extern void delete_Shape(int jarg1);
  [DllImport("example")]
  public static extern void set_Shape_x(int jarg1, double jarg2);
  [DllImport("example")]
  public static extern double get_Shape_x(int jarg1);
 
 �BLA BLA�
 
  [DllImport("example")]
  public static extern int CircleToShape(int jarg1);
  [DllImport("example")]
  public static extern int SquareToShape(int jarg1);
}
 
AND
 
using System;
public class Shape : IDisposable {
  private int swigCPtr;
  protected bool swigCMemOwn;
 
  protected Shape(int cPtr, bool cMemoryOwn) {
    swigCMemOwn = cMemoryOwn;
    swigCPtr = cPtr;
  }
 
  protected Shape() : this(0, false) {
  }
 
  public virtual void Dispose() {
    delete();
  }
 
  protected void delete() {
    if(swigCPtr != 0 && swigCMemOwn) {
      examplePINVOKE.delete_Shape(swigCPtr);
      swigCMemOwn = false;
    }
    swigCPtr = 0;
  }
 
  protected static long getCPtr(Shape obj) {
    return (obj == null) ? 0 : obj.swigCPtr;
  }
 
  public void setX(double x) {
    examplePINVOKE.set_Shape_x(swigCPtr, x);
  }
 
  public double getX() {
    return examplePINVOKE.get_Shape_x(swigCPtr);
  }
 
�BLA BLA�
}
 
So if you got down this far ;) now what you have is:
using a single command you can reuse all the great c++ libraries in c#.
Sounds good?!
 
I think this route is the most robust and sensible way of reuse. Do you agree? Will this be useful?
I need to finish the work and then convince Dave to add this into his Swig project. Swig offers pretty complete support of c++ including templates, virtual methods - take a look at the website. Quite a lot of work remains to make sure we are writing decent c# code, to finish off and thoroughly test. I havnt had the time to even try it on a c++ library bigger than the example above - but I will!
 

Neil
416 436 6345

Reply via email to