首页 > 代码库 > p/invoke碎片--对类的封送处理

p/invoke碎片--对类的封送处理

主要是看默认封送处理行为

按类成员的类型是否为“可直接传递到非托管内存”的类型来分类;按照成员中是否有“可直接传递到非托管内存”的类型来讨论。

  所有成员都是“可直接传递到非托管内存”的类型

  托管代码和非托管代码:

    //托管代码                   ClassStruct cs = new ClassStruct();            cs.a = 90;            cs.d = 23;            DoClassStruct(cs);            Console.Read();        }        [StructLayout(LayoutKind.Sequential)]        class ClassStruct        {            public int a;            public double d;        }、、、、、、、、、、、////////////非托管代码typedef struct 
{
    int a;
    double d;
}CLASSSTRUCT;

extern "C" __declspec(dllexport) void DoClassStruct(CLASSSTRUCT *cs)
{
    printf("%d\n",cs->a);
    printf("%lf\n",cs->d);
    cs->a=100;
}

   下断点,在DoClassStruct(cs);处,发现cs的地址是0x01bcbaa0;进入 非托管函数中,下断点,发现cs的地址不变。如下:

0x01BCBAA0  5a 00 00 00 00 00 00 00 00 00 00 00 00 00 37 40  Z.............7@   其中的5a是指90,后面8位是指double值23.0 。

  结论:如果类的字段都是“可直接传递到非托管代码中”的类型,那么传递是引用,或者说是指针。这是在非托管代码中的修改也会反映到托管代码中了。这个过程就是锁定

 类的成员不包含“非可直接传递到非托管代码中”的类型

   看下面一个例子,满足条件的类型有bool和string类型等。

            cs.a = 90;            cs.d = 23;            cs.str = "abcd";            DoClassStruct(cs);            Console.WriteLine(cs.a);            Console.Read();        }        [StructLayout(LayoutKind.Sequential)]        class ClassStruct        {            public int a;            public double d;            public string str;        }/////////////////////////////非托管代码typedef struct {    int a;    double d;    char *pStr;}CLASSSTRUCT;extern "C" __declspec(dllexport) void DoClassStruct(CLASSSTRUCT *cs){    printf("%d\n",cs->a);    printf("%lf\n",cs->d);    cs->a=100;}

 

   通过跟踪发现,依然使用普通结构体的过程:在非托管内存中开辟空间---把托管内存中数据复制一份到非托管内存M-----内存M的地址作为参数传递给函数---一切的操作都是围着内存M进行。 可想而知,最后的结果不会反映到托管内存中去。

p/invoke碎片--对类的封送处理