zoukankan      html  css  js  c++  java
  • .net 互操作之p/invoke 数据封送(结构体传参,返回值,内存管理)(3)

    除了简单的数据类型传值之外,还可以传递自定义的结构体

    传参

    一.同时定义非托管和托管的结构体

    //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);

    输出

    image_2

    二.以指针传递

    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);

    输出结果

    image_6

    结构体返回值

    主要是注意内存的释放方式,若不以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;
     }


    3.测试

    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);
     
     }
  • 相关阅读:
    面向对象 (11)求交并集 判断字符形式
    软件工程 课程总结
    面向对象 (10)正则判邮箱
    面向对象 (9)计算时间差 找随机数范围内规律
    面向对象 (8)字符串出现字符个数统计 字母组成回文串判定
    面向对象 (7)中介买房 平均数异常处理
    面向对象 (6)买房付首款
    第16周作业
    第15周作业
    迟到的第14周作业
  • 原文地址:https://www.cnblogs.com/Clingingboy/p/1809621.html
Copyright © 2011-2022 走看看