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进行。 可想而知,最后的结果不会反映到托管内存中去。

posted @ 2015-01-29 07:47  deeeeeed  阅读(342)  评论(0编辑  收藏  举报

pppppppppppppp