下图则概要描述了Managed和Unmanaged区域代码之间互相操作的方式:
更具体的,为了实现对于Unmanaged DLL function的调用,只需要简单的4步6:
1、确认DLL类库中需要被操作的函数;
2、创建一个C#类来关联被操作的这些函数(给函数穿上一个马甲,以便集中管理和反复调用);
3、使用DllImport标志在受管侧(C#)定义函数原型;
4、在受管侧随意调用相关非托管区域函数。
上图中,Standardmarshallingservice即负责将数据在两个区域进行封装/解封装传送(marshall/unmarshall),它主要定义了数据在两个不同内存区域进行拷贝(Copy)和引用(Reference)的规则7,而迷宫中的坑主要是和这些具体规则有关。
坑王驾到之封送(Marshall/Unmarshall)中的那些坑
坑一:sizeof(bool)=?
绝大多数的基本类型属于Blittable Types8:如System.Byte, System.Single等。System.Boolean虽然不属于Blittable types,但是Standard Marshalling Service默认将其转换为1,2,4字节的内存存储,当其值为true时,其对应的值为1。如果你想当然的直接将System.Boolean映射到Unmanaged侧的bool类型而不做特别处理的话,你并一定会理解碰到编译或者运行时错误,但是如果你严格的测试每个字段是,会惊讶的发现这些bool值跟你想象的不尽相同:有时正确,有时错误。
经过调试跟踪,动态打印sizeof(bool)来确认Unmanaged侧bool类型数据长度后,你会发现System.Boolean默认会被保存为4个字节长度,而在macOS环境下(对于其它环境,需要自行认证),C++定义的bool其实只有一个字节。因此当你在Unmanaged侧取bool值的时候,其实只读取了System.Boolean的1/4个字节而已。而当你声明了多个连续的System.Boolean/bool值时,可能在Unmanaged侧读取的这几个bool值仅仅是第一个System.Boolean值的不同偏移字节而已。