.net 互操作之p/invoke- 数据封送(结构体传参,返回值,内存管理)(3)
2010-08-26 23:47 Clingingboy 阅读(1276) 评论(0) 编辑 收藏 举报除了简单的数据类型传值之外,还可以传递自定义的结构体
传参
一.同时定义非托管和托管的结构体
//typedef struct _SIMPLESTRUCT //{ // int intValue; // short shortValue; // float floatValue; // double doubleValue; //} SIMPLESTRUCT, *PSIMPLESTRUCT; [StructLayout(LayoutKind.Sequential)] private struct ManagedSimpleStruct { public int intValue; public short shortValue; public float floatValue; public double doubleValue; }
在托管代码中,需要注意一下几点
1.以StructLayout 来标记此结构体,以Sequential来指定结构体内存布局是相同的
2.字段定义的顺序
3.字段类型
4.字段在内存中的大小
5.非托管与托管结构名称可以不同
二.在非托管和托管代码输出结构体
1.定义托管函数
// void __cdecl TestStructArgumentByVal(SIMPLESTRUCT simpleStruct); [DllImport(_dllName, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)] private extern static void TestStructArgumentByVal(ManagedSimpleStruct argStruct);
2.非托管代码
void __cdecl TestStructArgumentByVal(SIMPLESTRUCT simpleStruct) { ShowNativeStructSize(sizeof(SIMPLESTRUCT)); wprintf(L"\n结构体原数据?: int = %d, short = %d, float = %f, double = %f\n", simpleStruct.intValue, simpleStruct.shortValue, simpleStruct.floatValue, simpleStruct.doubleValue); simpleStruct.intValue += 10; }
3.测试
ManagedSimpleStruct simpleStruct = new ManagedSimpleStruct(); simpleStruct.intValue = 10; simpleStruct.shortValue = 20; simpleStruct.floatValue = 3.5f; simpleStruct.doubleValue = 6.8f; TestStructArgumentByVal(simpleStruct); Console.WriteLine("\n结构体新数据?:?int = {0}, short = {1}, float = {2:f6}, double = {3:f6}", simpleStruct.intValue, simpleStruct.shortValue, simpleStruct.floatValue, simpleStruct.doubleValue);
输出
二.以指针传递
1.定义托管函数和非托管函数
还是用原来的结构体
void __cdecl TestStructArgumentByRef(PSIMPLESTRUCT pStruct) { ShowNativeStructSize(sizeof(SIMPLESTRUCT)); if( NULL != pStruct) { // 打印初始数据 wprintf(L"\n结构体原数据: int = %d, short = %d, float = %f, double = %f\n", pStruct->intValue, pStruct->shortValue, pStruct->floatValue, pStruct->doubleValue); // 修改数据 pStruct->intValue++; pStruct->shortValue++; pStruct->floatValue += 1; pStruct->doubleValue += 1; } }
测试
ManagedSimpleStruct simpleStruct = new ManagedSimpleStruct(); simpleStruct.intValue = 10; simpleStruct.shortValue = 20; simpleStruct.floatValue = 3.5f; simpleStruct.doubleValue = 6.8f; TestStructArgumentByVal(simpleStruct); Console.WriteLine("\n结构体新数据:int = {0}, short = {1}, float = {2:f6}, double = {3:f6}", simpleStruct.intValue, simpleStruct.shortValue, simpleStruct.floatValue, simpleStruct.doubleValue);
输出结果
结构体返回值
主要是注意内存的释放方式,若不以CoTaskMemAlloc方法申请内存,则释放的时候,需从托管代码释放.CoTaskMemAlloc方法申请的内存则调用FreeCoTaskMem方法来释放
1.托管函数
// PSIMPLESTRUCT __cdecl TestStructAsResult(void); [DllImport(_dllName, CallingConvention = CallingConvention.Cdecl)] private extern static IntPtr TestReturnStruct(); // PSIMPLESTRUCT __cdecl TestReturnNewStruct(void) [DllImport(_dllName, CallingConvention = CallingConvention.Cdecl)] private extern static IntPtr TestReturnNewStruct(); // void __cdecl FreeStruct(PSIMPLESTRUCT pStruct) [DllImport(_dllName, CallingConvention = CallingConvention.Cdecl)] private extern static void FreeStruct(IntPtr pStruct);
2.非托管函数
PSIMPLESTRUCT __cdecl TestReturnNewStruct(void) { // 使用new分配内存 PSIMPLESTRUCT pStruct = new SIMPLESTRUCT(); pStruct->intValue = 5; pStruct->shortValue = 4; pStruct->floatValue = 3.0; pStruct->doubleValue = 2.1; return pStruct; } //****************************************************************** void __cdecl FreeStruct(PSIMPLESTRUCT pStruct) { if(NULL != pStruct) { delete pStruct; pStruct = NULL; } }
PSIMPLESTRUCT __cdecl TestReturnStruct(void) { // 使用CoTaskMemAlloc分配内存 PSIMPLESTRUCT pStruct = (PSIMPLESTRUCT)CoTaskMemAlloc( sizeof(SIMPLESTRUCT)); pStruct->intValue = 5; pStruct->shortValue = 4; pStruct->floatValue = 3.0; pStruct->doubleValue = 2.1; return pStruct; }
3.测试代码
private static void TestReturnStructByNew() { IntPtr pStruct = TestReturnNewStruct(); ManagedSimpleStruct retStruct = (ManagedSimpleStruct)Marshal.PtrToStructure(pStruct, typeof(ManagedSimpleStruct)); FreeStruct(pStruct); Console.WriteLine("\nint = {0}, short = {1}, float = {2:f6}, double = {3:f6}", retStruct.intValue, retStruct.shortValue, retStruct.floatValue, retStruct.doubleValue); }
private static void TestReturnStructByCoTaskMemAlloc() { IntPtr pStruct = TestReturnStruct(); ManagedSimpleStruct retStruct = (ManagedSimpleStruct)Marshal.PtrToStructure(pStruct, typeof(ManagedSimpleStruct)); Marshal.FreeCoTaskMem(pStruct); Console.WriteLine("\nint = {0}, short = {1}, float = {2:f6}, double = {3:f6}", retStruct.intValue, retStruct.shortValue, retStruct.floatValue, retStruct.doubleValue); }
指针传递
二级指针传递,同理,也需要用FreeCoTaskMem方法释放
1.托管函数
// void __cdecl TestReturnStructFromArg(PSIMPLESTRUCT* ppStruct) [DllImport(_dllName, CallingConvention = CallingConvention.Cdecl)] private extern static void TestReturnStructFromArg(ref IntPtr pStruct);
2.非托管函数
void __cdecl TestReturnStructFromArg(PSIMPLESTRUCT* ppStruct) { if( NULL != ppStruct) { *ppStruct = (PSIMPLESTRUCT)CoTaskMemAlloc( sizeof(SIMPLESTRUCT)); (*ppStruct)->intValue = 5; (*ppStruct)->shortValue = 4; (*ppStruct)->floatValue = 3.0; (*ppStruct)->doubleValue = 2.1; } return; }
private static void TestReturnStructByArg() { IntPtr ppStruct = IntPtr.Zero; TestReturnStructFromArg(ref ppStruct); ManagedSimpleStruct retStruct = (ManagedSimpleStruct)Marshal.PtrToStructure(ppStruct, typeof(ManagedSimpleStruct)); Marshal.FreeCoTaskMem(ppStruct); Console.WriteLine("\nint = {0}, short = {1}, float = {2:f6}, double = {3:f6}", retStruct.intValue, retStruct.shortValue, retStruct.floatValue, retStruct.doubleValue); }