参见default marshaling behaviour
interop封组器(marshaler)的内存管理
interop封组器总是会试图去释放由非托管代码分配的内存。这个行为和COM内存管理一致,但是和原生C++内存管理规则不同。
从C++中调用下面的函数不会自动释放任何内存
BSTR MethodOne (BSTR b) {
return b;
}
注:BSTR(Basic string or binary string)是一种用于COM,Automation和Interop函数的字符串数据类型。它是一个复合数据类型,包含长度前缀,字符串和结束符。
然而,假如定义一个该函数的平台调用原型,使用String类型替换BSTR,然后调用该函数,公共语言运行库试图两次释放b的内存(第一次是当参数被传递到非托管端,第二次是从调用返回的时候)。可以通过使用IntPtr类型替代String类型来改变这种封组行为。
运行库总是使用CoTaskMemFree方法去释放内存。如果使用中的内存不是使用CoTaskMemAlloc方法分配的,就必须使用一个IntPtr来指向该内存(就不会被自动释放掉)然后再使用一个合适的方法将其手动释放掉。可以用这种方法在内存不能被释放的场合避免自动释放。
例如下面例子
C++
LPTSTR WINAPI GetCommandLine(void);
C#
[DllImport("Kernel32.dll", CharSet=CharSet.Auto)]
publicstaticextern IntPtr GetCommandLine();
[DllImport("Kernel32.dll", CharSet=CharSet.Auto)]
publicstaticextern string GetCommandLineFreeAuto();
==>C#调用
IntPtr cmdLineStr = LibWrap.GetCommandLine();
string commandLine = Marshal.PtrToStringAuto(cmdLineStr);
这里GetCommandLine返回的一段系统核心内存的数据,所以必须保证该内存段不能被自动释放,因而需要将返回类型写成IntPtr,然后再从该IntPtr指向的内存段拷贝数据。而假如使用GetCommandLineFreeAuto的话,interop封组器会去释放该string对象所表示的那块内存区域,会导致核心内存资源被释放从而导致系统问题。
方向属性
每个函数的参数都可以和InAttribute属性、OutAttribute属性或者两者关联起来。在设计函数原型的时候通过应用方向属性,可以在托管和非托管内存之间改变运行时的数据封组。
方向属性是可选的,如果想要改变封组器的默认行为的话可以将它们应用到函数参数。如果不使用方向属性,封组器通过参数的类型(值类型或引用类型)和它的修改器(如果有的话)来决定方向流向。
Visual Basic 2005 |
C# |
IDL attribute |