DLL 函數中使用結構體指針做函數參數(C# 調用 C++ 的 DLL)

存在的問題:數組

問題1:C++ 與 C# 一樣定義的結構體在內存佈局上有時並不一致;函數

問題2:C# 中引入了垃圾自動回收機制,垃圾回收器可能會從新定位指針所指向的結構體變量。佈局

解決方案:spa

問題1方案:強制指定 C++、C# 結構體的內存佈局,使其一致(二者都固定爲:結構體的成員按其聲明時出現的順序依次佈局結構體成員的內存對齊爲1字節對齊);指針

爲題2方案:C# 調用時將待傳遞的結構體轉化爲字節數組,並使用 fixed 語句將該字節數組固定住。內存

 

示例代碼以下:it

一、C++結構體定義:io

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

 

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

 

二、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

  }

相關文章
相關標籤/搜索