天天看點

C#調用c++Dll結構體數組指針的問題

C#調用c++dll檔案是一件很麻煩的事情,首先面臨的是資料類型轉換的問題,相信經常做c#開發的都和我一樣把學校的那點c++底子都忘光了吧(語言特性類)。

網上有一大堆得轉換對應表,也有一大堆的轉換執行個體,但是都沒有強調一個更重要的問題,就是c#資料類型和c++資料類型占記憶體長度的對應關系。

    如果dll檔案中隻包含一些基礎類型,那這個問題可能可以被忽略,但是如果是組合類型(這個叫法也許不妥),如結構體、類類型等,在其中的成員變量的長度的申明正确與否将決定你對dll檔案調用的成敗。

如有以下代碼,其實不是dll檔案的源碼,而是廠商給的c++例子代碼

  c++中的結構體申明

[c-sharp] view plaincopy

  1. typedef struct  
  2. {  
  3.   unsigned char Port;  
  4.   unsigned long Id;  
  5.   unsigned char Ctrl;  
  6.   unsigned char pData[8];  
  7. }HSCAN_MSG;  

c++中的函數申明(一個c++程式引用另一個c++的dll檔案)

  1. extern "C" int _stdcall HSCAN_SendCANMessage(unsigned char nDevice,unsigned char nPort,HSCAN_MSG *msg,int nLength);  

c++中的調用:

  1. ....  
  2. HSCAN_MSG msg[100];  
  3. .....  
  4. HSCAN_SendCANMessage(m_nDevice,m_nPort,msg,nFrames);  

由上述代碼可見,msg是個結構體的數組。

下面是我的c#的代碼

c#結構體申明:(申明成)

  1. [StructLayout(LayoutKind.Sequential)]  
  2.    public struct HSCAN_MSG  
  3.    {  
  4.     // UnmanagedType.ByValArray, [MarshalAs(UnmanagedType.U1)]這個非常重要,就是申明對應類型和長度的  
  5.    [MarshalAs(UnmanagedType.U1)]  
  6.    public byte Port;  
  7.    [MarshalAs(UnmanagedType.U4)]  
  8.    public uint nId;  
  9.    public byte nCtrl;  
  10.    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]  
  11.    public byte[] pData;  
  12.    };  

c#函數申明

  1. [DllImport("HS2106API.dll")]  
  2.    public static extern int HSCAN_SendCANMessage(  
  3.    byte nDevice, byte nPort, HSCAN_MSG[] pMsg, int nLength);  

C#函數調用

  1. HSCAN_MSG[] msg = new HSCAN_MSG[1]; //發送緩沖區大小可根據需要設定;  
  2.    for (int yy = 0; yy < msg.Length; yy++)  
  3.    msg[yy] = new HSCAN_MSG();  
  4.    }  
  5.     //...結構體中的成員的執行個體化略  
  6.     HSCAN_SendCANMessage(0x0, 0x0, msg, 1)  

那些隻能用指針不能用結構體和類的地方

c++中的結構體申明

c#中的結構體申明:

  1.    /// <summary>  
  2.    /// 節點辨別,nEFF=1 時(擴充幀),為29 位nEFF=0(标準幀)時,為11 位;  
  3.    /// </summary>  
  1. HSCAN_MSG[] msg1 = new HSCAN_MSG[10];  
  2.    for (int i = 0; i < msg1.Length; i++)  
  3.    msg1[i] = new HSCAN_MSG();  
  4.    msg1[i].pData = new byte[8];  
  5.    IntPtr[] ptArray = new IntPtr[1];  
  6.    ptArray[0] = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(HSCAN_MSG)) * 10);  
  7.    IntPtr pt = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(HSCAN_MSG)));  
  8.    Marshal.Copy(ptArray, 0, pt, 1);  
  9.    int count = HSCAN_ReadCANMessage(0x0, 0,pt, 10);  
  10.    textBoxStatus.Text += "/r/n" + "讀取0口:" + count.ToString() + "幀資料";  
  11.    for (int j = 0; j < 10; j++)  
  12.    msg1[j] =  
  13.    (HSCAN_MSG)Marshal.PtrToStructure((IntPtr)((UInt32)pt+ j * Marshal.SizeOf(typeof(HSCAN_MSG)))  
  14.    , typeof(HSCAN_MSG));  
  15.    textBoxStatus.Text += "/r/n收到0口" + Convert.ToByte(msg1[j].pData[0]).ToString()  
  16.    + "|" + Convert.ToByte(msg1[j].pData[1]).ToString()  
  17.    + "|" + Convert.ToByte(msg1[j].pData[2]).ToString()  
  18.    + "|" + Convert.ToByte(msg1[j].pData[3]).ToString()  
  19.    + "|" + Convert.ToByte(msg1[j].pData[4]).ToString()  
  20.    + "|" + Convert.ToByte(msg1[j].pData[5]).ToString()  
  21.    + "|" + Convert.ToByte(msg1[j].pData[6]).ToString()  
  22.    + "|" + Convert.ToByte(msg1[j].pData[7]).ToString();  

繼續閱讀