ArtinSoft's Blogs

Software Migration Experts
Welcome to ArtinSoft's Blogs Sign in | Join | Help
in Search

Mauricio Rojas Blog

December 2008 - Posts

  • Use C++ in C#

    COM


    The idea is to make a class or several classes available thru COM. Then the compiled dll or the TLB is used to generate and Interop Assembly and call the desired functions.

    With this solution the current C++ code base line can be kept or might require just subtle changes. 

    Calling a function thru com is involved in a lot of marshalling and can add an additional layer that is not really needed in the architecture of the solution.

    Creating a Managed Wrapper with Managed C++

    The idea with this scenario is to provide a class in Managed C++ that will be available in C#. This class is just a thin proxy that redirects calls to the Managed object. 

    Let’s see the following example: 

    If we have a couple of unmanaged classes like: 

    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);

    }; 
     

    The first thing we can try, to expose our classes to .NET it to set the setting for managed compilation: 

    Es posible que tu navegador no permita visualizar esta imagen.Es posible que tu navegador no permita visualizar esta imagen. 

    If your project compiles then you are just very close, and what you need is to add some managed classes to your C++ project to expose your native classes: 

    Let’s see the Shape class: 

    //We can use another namespace, to avoid name collition.

    //In this way we can replicate the structure of our C++ classes. 

    namespace exposedToNET

    {

          //Shape is an abstract class so the better thing

        // to do is to generate an interface 

          public interface class Shape : IDisposable

          {

          public:  

                //public variables must be exposed as properties

                property double x

                {

                      double get();

                      void set(double value);

                }

                property double y

                {

                      double get();

                      void set(double value);

                }

                //method do not expose any problems

                void move(double dx, double dy);

                double area();

                double perimeter();

                //public static variables must

            //be exposed as static properties

            //However we might need to create a new class

            //for all public static variables and methods

            //because C# does not accept methods in an interface

                static property int nshapes;

          };

          //Static methods or variables of abstract class are added here

          public ref class Shape_Methods

          {

                            //public static variables must be exposed as static properties

          public:

                static property int nshapes

                {

                      int get()

                      {

                            return ::Shape::nshapes;

                      }

                      void set(int value)

                      {

                            ::Shape::nshapes = value;

                      }

                } 

          };

    } 

    And for the Circle class we will have something like this: 

    namespace exposedToNET

    { 
     

          public ref class Circle : Shape

          {

          private:

                ::Circle* c;

          public:

                Circle(double radius)

                {

                      c = new ::Circle(radius);

                }

                ~Circle()

                {

                      delete c;

                }

                //public variables must be exposed as properties

                property double x

                {

                      virtual double get()

                      {

                            return c->x;

                      }

                      virtual void set(double value)

                      {

                            c->x = value;

                      }

                }

                property double y

                {

                      virtual double get()

                      {

                            return c->y;

                      }

                      virtual void set(double value)

                      {

                            c->y = value;

                      }

                }

                //method do not expose any problems

                virtual void move(double dx, double dy)

                {

                      return c->move(dx,dy);

                }

                virtual double area()

                {

                      return c->area();

                }

                virtual double perimeter()

                {

                      return c->perimeter();

                }

                //public static variables must be exposed as static properties

                static property int nshapes

                {

                      int get()

                      {

                            return ::Shape::nshapes;

                      }

                      void set(int value)

                      {

                            ::Shape::nshapes = value;

                      }

                } 
     

          }; 

    }

    DOWNLOAD EXAMPLE CODE

    SWIG

     

    SWIG is a software development tool that connects programs written in C and C++ with a variety of high-level programming languages.

    This is a great tool used for several languages like Python, Perl, Ruby, Scheme, and even in different platforms.

    The exposure mechanism used in this scheme is platform invoke, the issues here are similar to those of COM because there is some marshaling going on. This scheme might be more efficient than the COM one but I haven’t really test it to be completely sure that it is better. 

    I have reviewed the SWIG code and it might also be possible to modify its code to generate wrappers using managed C++, but this is an interesting exercise that I have to leave for my readers. Sorry I just don’t have enough time. 

    But how is SWIG used? 

    In SWIG what you do is that you add a .i file to your project. This file provides directives for some code generation that specify exactly what you want to expose and how. 

    This can very helpful if you just want to expose some methods. 

    If you are lazy like me you can just add something like: 

    /* File : example.i */

    %module example 

    %{

    #include "example.h"  ß you put here includes with the definitions for your classes

    %} 

    /* Let's just grab the original header file here */

    %include "example.h" ß add alse the include here 

    And SWIG will add a file like example_wrap.cxx that you have to compile with the rest of your C++ code. 

    It will also generate a set of C# classes that you use in your C# application, so it seams to your program that all the code is just C#.  

    SWIG is a great tool and has been testing in a lot of platforms.

  • Migration to 64-bit: ODBC

    Most people migrating their application want to move ahead and take advantage of new technologies and new operating systems.

    So if you had a VB6 application and you migrated it with us to .NET we will recommend and automate the process to use ADO.NET.

    Why?

    You can still use ODBC but i will list some compelling reasons:

    * There a very fast ADO.NET drivers available. Using ODBC implies addind an interop overhead that can affect performance.
    * Some vendors do not support and/or certify the use of ODBC drivers for .NET. So in those cases if you use ODBC your are on your own.
    During my consulting experience I have seen several problems using ODBC drivers ranging from just poor performance, problems with some SQL statements, stored procedures calls, database specific features or complete system inestability.
    * and also problems running in 64-bit.

    This last one is very concerning. If you made all the effort to migrate an application to .NET and run it on for example on a Windows 2003 64 bit server it wont be able to use your 32-bit ODBC drivers unless you go to the the Build tab, and set Platform Target to "x86".

    This is very sad because your application cannot take advantage of all the 64 bit resources.

    If you are lucky enough you might find a 64 bit version of your ODBC driver but I will really recommend going straigth to 64-bit and use ADO.NET. And that's exactly what we can really help you to do specially in our version 2.2 of the VBUC.

     

This Blog

Syndication

Powered by Community Server (Non-Commercial Edition), by Telligent Systems