[DotGNU]Strategy for dealing with C++ virtual functions in a managed binding.

David Sugar dyfet at ostel.com
Fri Dec 6 15:13:26 GMT 2002


Certainly there are places and applications where direct use of existing
and already well optimized native libraries is desirable, rather than
having to rewrite such things into a managed C# or try to make use of
limited bindings, intermediary things, etc.  I happen to think the
potential role of pnet can be varied in many ways, including use as an
embedded extension environment, as well as the foundation and focus for
creating new applications, web services, etc.  Being able to use
unmodified native optimized C++ libraries (and 3d or multi-media libraries
were what originally came to mind) could certainly be very useful in
creating optimized hybrid native/portable runtime applications.  I would
like to see how this relates to qt# and similar efforts to provide qt/kde
bindings to c#.  My own favorite cross-platform gui happens to be the fox
toolkit and if I could link to fox and build fox apps written in c# with
pnet, that I would find a very interesting and useful capability.

On Thu, 5 Dec 2002, Neil Cawse wrote:

> Automatically reusing c++ libraries in c#
> =========================================
> Ive spent quite a bit of time researching how best to reuse the existing
> great libraries written 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!
> 
> 
> ----- Original Message -----
> From: "Adam Treat" <manyoso at yahoo.com>
> To: "James Michael DuPont" <mdupont777 at yahoo.com>; <developers at dotgnu.info>
> Cc: <kde-devel at kde.org>; <kde-core-devel at kde.org>
> Sent: Tuesday, December 03, 2002 12:47 AM
> Subject: Re: [DotGNU]Strategy for dealing with C++ virtual functions in a
> managed binding.
> 
> 
> > On Tuesday 03 December 2002 12:09 am, James Michael DuPont wrote:
> > > --- Adam Treat <manyoso at yahoo.com> wrote:
> > > > Hello All,
> > > >
> > > > I would like to pick the brains of the collective intelligence and
> > > > come up
> > > > with a good solid strategy for dealing with C++ virtual functions in
> > > > a
> > > > binding.
> > >
> > > /me ears pick up something interesting
> > >
> > > > Our new strategy is then to call the libqt.so directly using mangled
> > > > method
> > > > names in our DllImport attributes.
> > > >
> > > > This is accomplished by using a
> > > > combination of 'nm' and 'cppfilt' during Qt# binding creation.
> > >
> > > I would like too see this code. /me thinks you can use libiberty and
> > > the   introspector or gcc_xml for this.
> >
> > Oh, we already have a strategy for mangling the names.  A script and
> > nm+cppfilt works nicely.  I can produce this script for you tomorrow (it's
> > late ;)  We looked at libiberty for this, but it only provides a mechanism
> > for 'demangling' and does not provide a way to 'mangle' given a string
> > representing a function prototype.
> >
> > > >  The
> > > > idea is
> > > > to use an instance pointer as an invisible first parameter and then,
> > > > using
> > > > the mangled name, call libqt directly.
> > >
> > > like the gnu libjava
> >
> > Oh?  libjava uses this method?  Is this part of gcj then?
> >
> > > >  Oh, and our binding generator
> > > > is also
> > > > capable of an easy extension to bind any C++ lib in case anyone is
> > > > interested
> > > > in binding other C++ libraries ;)
> > >
> > > yes, let us see the basic axioms, we can build this in a standard
> > > process.
> > >
> > > at this point, I would like to know why cannot you use the internal
> > > call system? that has a binding generator as well, no?
> >
> > The binding generator is pretty flexible and easy to extend to other C++
> > API's.  We use a custom C++ header parser written in C# to produce an XML
> > file representing the C++ API.  This XML file is then processed through
> our
> > binding generator called 'binge'.  What do you mean by 'use the internal
> call
> > system' ??  I have no idea what you are referring to nor do I understand
> 'has
> > a binding generator as well, no' ... what has a binding generator as well?
> >
> > > >  The preferred solution would
> > > > be to
> > > > somehow override the virtual table to call a managed function
> > > > directly and
> > > > then somehow forward this to the appropriate C# virtual function.
> > >
> > > you can grab pointers to virtual function entries,
> > > and given an object and a vf pointer call the object.
> > >
> > > please send me more info,
> > > I just might be able to help.
> >
> > Awesome!  I don't know what kind of info would be helpful ... Our ideal
> > solution would allow us to associate a delegate with a C# virtual function
> > ... when the virtual function is implemented the binding would pass the
> > delegate to a C glue method as a function pointer ... the C glue method
> could
> > then do some magic with the virtual table in libqt.so and install the
> > delegate in place of the existing function pointer.  I know how to do all
> of
> > this except play with the Qt vtable in native code ...
> >
> > Hope this info helps,
> >
> > Adam
> > _______________________________________________
> > Developers mailing list
> > Developers at dotgnu.org
> > http://www.dotgnu.org/mailman/listinfo/developers
> >
> _______________________________________________
> Developers mailing list
> Developers at dotgnu.org
> http://www.dotgnu.org/mailman/listinfo/developers
> 

 
>> Visit http://mail.kde.org/mailman/listinfo/kde-devel#unsub to unsubscribe <<




More information about the kde-core-devel mailing list