havdone's guarden

博客园 首页 新随笔 联系 订阅 管理

C# p/invoke: marshaling class between C# and C++ class

Jin Tu

Blog: http://www.inblogs.net/havdone

1.0 Abstraction

This article provides basic information to realize how pass c# function pointer and class object to a c++ function as parameters.

2.0 Mechanism

The c++ function parameters could be an object pointer or a function pointer. Passing c# class object or a function as parameter to c++ function actually is passing a C# reference or a function pointer. To realize this mechanism properly, first should make sense of the basic knowledge in its scope.

3.0 Basic knowledge

3.1 C# pointer (*)

The c# unsafe code can use pointer directive (*). However, c# pointer has many constraints. As stated in MSDN, “C# pointer types do not inherit from object and no conversions exist between pointer types and object. Also, boxing and unboxing do not support pointers. However, you can convert between different pointer types and between pointer types and integral types.”

“Any of the following types may be a pointer type:

  • sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, or bool.
  • Any enum type.
  • Any pointer type.
  • Any user-defined struct type that contains fields of unmanaged types only.”

That means c# cannot make conversion from class object reference to pointer type (*). Using “&” operator on a reference, will cause a compiling error “Cannot take the address of, get the size of, or declare a pointer to a managed type”.

3.2 Reference parameters in C#

While reference object, such as a class object, is pass to function as a parameter, actually the address of object is passed, as reference is a pointer type.

3.3 Class data type in memory

[System.Runtime.InteropServices.StructLayout(LayoutKind.Sequential)]

    class Class1

    {

        public int i;

        private int _i;

        public System.Collections.ArrayList arr = new System.Collections.ArrayList();

        public void test()

        {

            Console.WriteLine("hello world!");

        }

 

        public Class1()

        {

            _i = 400;

           

        }    

 

    };

 

The above graph shows how a Class1 object is allocated memory.

3.4 Delegate in C#

The delegate keyword is used to declare a reference type that can be used to encapsulate a named or an anonymous method.”(MSDN)

4.0 Marshaling Example

This example passes class object that mentioned in chapter 3.3, to a c++ dll. C++ code use a class type object to accept the fields values of c# object and use a function pointer parameter to accept c# object function.

 

/////////////////////////////////////////////////////////

 //C# Code

 ///////////////////////////////////////////////////////////

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Runtime.InteropServices;

 

namespace interoperation

{

    class Program

    {

 

        //////////////////////////////////////////////////////////

        //P/Invoke a c++ function declare

        ///////////////////////////////////////////////////////////

        //if do not explcit point out entrypoint

        //the c# function name must be the same with c++ code

        [System.Runtime.InteropServices.DllImport("..\\..\\..\\debug\\sort.dll")]

        public static extern void func(Class1 arrays, Program.delgFunc func);

 

        //////////////////////////////////////////////////////////

        //C# function pointer declare

        ///////////////////////////////////////////////////////////

        public delegate void delgFunc();

 

        static void Main(string[] args)

        {        

            Class1 obj = new Class1();

            Program.delgFunc delg = obj.test;

 

            //pass a class reference and a function pointer to c++ function

            func(obj, delg);  

           

        }

    };

 

    [System.Runtime.InteropServices.StructLayout(LayoutKind.Sequential)]

    class Class1

    {

        public void test()

        {

            Console.WriteLine("c# function is called");

            Console.WriteLine("_i="+this._i.ToString());

        }

        public System.Collections.ArrayList arr = new System.Collections.ArrayList();

        private int _i;

        public int i;       

 

        public Class1()

        {

            _i = 400;

            i = 333;

        }

     

 

    };

}

 

 

/////////////////////////////////////////////////////////

 //C++ Code

 ///////////////////////////////////////////////////////////

// Sort.cpp : Defines the exported functions for the DLL application.

//

 

#include "stdafx.h"

#include <iostream>

using namespace std;

 

 

 

extern "C"

{

     //////////////////////////////////////////////////////////////////////

     //To accept C# class object,

     //remember c++ fileds are allocated memory sequentially

     ///////////////////////////////////////////////////////////////////////

     class Class1

     {

     public :

         void * unknow;//accept arr of c# object

         int _i;//accept _i of c# object

         int i;   //accept i of c# object

    

     };

 

      __declspec(dllexport) void func(Class1* class1,void (*   test)())

     {

         cout<<"(C# object is passed !) The value of  private field '_i': "<<class1->_i<<"\n";

         cout<<"(C# object is passed !) The value of  public field 'i': "<<class1->i<<"\n";

         test();

     }

}

The output like this:

 

posted on 2008-01-11 23:07  ajin  阅读(1733)  评论(0编辑  收藏  举报