.Net P/Invoke 非托管内存的访问
在使用P/Invoke时经常需要分配、释放非托管内存,实际上.Net的Marshal类提供了非常全面的功能,可以按照开发者的意愿去组织内存结构,只是使用上大大不如C++方便了。下面举例说明。
C++的结构:
struct t_Inner
{
char* name;
int type;
};
struct t_Outer
{
t_Inner* inners; //t_Inner结构的数组
int count; //t_Inner数组的长度
};
void TestStruct(t_Outer* outer); //此函数将生成outer结构的具体内容
C#调用
首先定义结构:
[StructLayout(LayoutKind.Sequential)]
public struct t_Inner
{
public IntPtr name;
public int type;
};
[StructLayout(LayoutKind.Sequential)]
public struct t_Outer
{
public IntPtr inners;
public int count;
};
引用C++的函数
[DllImport(@"D:/test.dll", CharSet = System.Runtime.InteropServices.CharSet.Unicode)]
public extern static int TestStruct(ref t_Outer outer);
调用函数:
public void TestStruct()
{
t_Outer outer = new t_Outer();
IntPtr strPtr, innerPtr;
outer.count = 3;
outer.inners = Marshal.AllocHGlobal(3 * Marshal.SizeOf(typeof(t_Inner)));
for (int i = 0; i < outer.count; i++)
{
innerPtr = Marshal.ReadIntPtr(outer.inners, Marshal.SizeOf(typeof(t_Inner)) * i);
strPtr = Marshal.AllocHGlobal(BufferLen.BASMAX_FILE_NAME);
Marshal.WriteIntPtr(outer.inners, Marshal.SizeOf(typeof(t_Inner)) * i, strPtr);
}
BaSFunctions.TestStruct(ref outer);
for (int i = 0; i < outer.count; i++)
{
strPtr = Marshal.ReadIntPtr(outer.inners, Marshal.SizeOf(typeof(t_Inner)) * i);
string str = Marshal.PtrToStringAuto(strPtr);
Debug.WriteLine(str);
}
}
在内存分配上可以采用.Net分配并释放内存,或者C++代码分配并释放内存,这两种方法各有优缺点。这里采用的是.Net分配并释放非托管内存的方法。