一:非托管 操作 托管,使用委托回调
二:托管 操作 非托管,使用封送
封送处理方式:
1.内存拷贝
2.固定内存地址
总结如下:
1.string类型:
把string封送到非托管函数:
Marshal.StringToHGlobalAnsi、Marshal.StringToHGlobalAuto、Marshal.StringToHGlobalUni,之后调用Marshal.FreeHGlobal释放内存;
从非托管函数里面取出string:
Marshal.PtrToStringAnsi、Marshal.PtrToStringAuto、Marshal.PtrToStringUni。
2.byte[ ](或者基础类型的数组),在封送到非托管函数时确保GC不要回收委托,需要保持引用但不需要Pinned:
从byte[]拷贝封送到非托管函数:
Marshal.Copy、GCHandle并指定GCHandleType.Pinned类型(其实就是固定内存直接传送byte[]的原始地址,省去了申请内存和拷贝的开销,速度更快)
从非托管函数拷贝封送到byte[]:
3.委托,在封送到非托管函数时需要确保GC不要回收委托,需要保持引用但不需要Pinned
从delegate封送到非托管函数:
Marshal.GetFunctionPointerForDelegate
从非托管函数里面取出:
Marshal.GetDelegateForFunctionPointer
4.结构体,只能使用基础类型和固定长度的数组,并且标记StructLayout的LayoutKind.Sequential属性
封送到非托管函数:
Marshal.StructureToPtr
从非托管函数里面取出:
Marshal.PtrToStructure
5.对象,C#的对象不能在Native中进行处理,只能保存以待之后再传回给C#调用,保存的方式为C#用GCHandle引用对象,然后把GCHandle转成IntPtr,传给Native作为指针保存。
注意:有几种情况还是需要手动进行封送的,string的编码是utf8之类的非ansi非utf16编码,则必须手动进行封送同时转换编码。和有频繁的对同一委托进行封送调用。