zoukankan      html  css  js  c++  java
  • DLL 函数中使用结构体指针作函数参数(C# 调用 C++ 的 DLL)

    存在的问题:

    问题1:C++ 与 C# 同样定义的结构体在内存布局上有时并不一致;

    问题2:C# 中引入了垃圾自动回收机制,垃圾回收器可能会重新定位指针所指向的结构体变量。

    解决方案:

    问题1方案:强制指定 C++、C# 结构体的内存布局,使其一致(两者都固定为:结构体的成员按其声明时出现的顺序依次布局结构体成员的内存对齐为1字节对齐);

    为题2方案:C# 调用时将待传递的结构体转化为字节数组,并使用 fixed 语句将该字节数组固定住。

    示例代码如下:

    1、C++结构体定义:

      #pragma pack(1)
      struct Person
      {
          #define Count_FavoriteNumbers 6
      
          int id;
      
          float favoriteNumbers[Count_FavoriteNumbers];
      
      };
      #pragma pack()        // #pragma pack(1) end

      C++ 导出函数:

      #define DllExport extern "C" __declspec(dllexport)

      DllExport void __stdcall InitPersonInfo_DLL(Person* p_Person)
      {
          p_Person->id = 0;
      
          for (int i = 1; i <= Count_FavoriteNumbers; i++)
          {
              p_Person->favoriteNumbers[i - 1] = 1.11 * i;
          }    
      }

    2、C# 结构体定义:

      [StructLayout(LayoutKind.Sequential, Pack = 1)]
          public class Person
          {
              public const int Count_FavoriteNumbers = 6;

              public int id;

              [MarshalAs(UnmanagedType.ByValArray, SizeConst = Count_FavoriteNumbers, ArraySubType = UnmanagedType.U4)]
              public float[] favoriteNumbers = new float[Count_FavoriteNumbers];  
          }

      C# 调用(WPF窗体程序):

      public partial class MainWindow : Window
      {

        [DllImport("MFCLibrary_ExportFunction.dll", EntryPoint = "InitPersonInfo_DLL")]
              static extern unsafe void InitPersonInfo_DLL(byte* p_Person);
              public unsafe void InitPersonInfo(ref Person person)
              {
                  byte[] structBytes = StructToBytes(person);
                  fixed (byte* p_Person = &structBytes[0])
                  {
                      InitPersonInfo_DLL(p_Person);

                      person = (Person)BytesToStruct(structBytes, person.GetType());
                  }

        public MainWindow()
              {
          InitializeComponent();

          Person zhangSan = new Person();
          InitPersonInfo(ref zhangSan);
              }

        #region // 结构体与 byte[] 互转

        // Struct 转换为 byte[]
              public static byte[] StructToBytes(object structure)
              {
                  int size = Marshal.SizeOf(structure);
                  IntPtr buffer = Marshal.AllocHGlobal(size);

                  try
                  {
                      Marshal.StructureToPtr(structure, buffer, false);
                      byte[] bytes = new byte[size];
                      Marshal.Copy(buffer, bytes, 0, size);

                      return bytes;
                  }
                  finally
                  {
                      Marshal.FreeHGlobal(buffer);
                  }
              }

              // byte[] 转换为 Struct
              public static object BytesToStruct(byte[] bytes, Type strcutType)
              {
                  int size = Marshal.SizeOf(strcutType);
                  IntPtr buffer = Marshal.AllocHGlobal(size);

                  try
                  {
                      Marshal.Copy(bytes, 0, buffer, size);

                      return Marshal.PtrToStructure(buffer, strcutType);
                  }
                  finally
                  {
                      Marshal.FreeHGlobal(buffer);
                  }
              }
              #endregion

      }

  • 相关阅读:
    Panda 交易所带我们一起来聊聊2021年区块链未来趋势
    Panda 交易所视点“区块链+政务”深度融合开启智慧城市政务新时代
    Panda 交易所热点关注,区块链数字溯源系统平台研发搭建
    熊猫交易所视点,2021年“区块链+”前景如何?
    Adroid Studio 消息推送
    .net core 设计模式--->代理模式
    .net core 邮件发送封装并生成dll文件
    U3D PC端桌面应用程序远程升级
    .net core 带附件邮件发送
    Copula函数
  • 原文地址:https://www.cnblogs.com/dhqy/p/10192062.html
Copyright © 2011-2022 走看看