C#調用c++dll檔案是一件很麻煩的事情,首先面臨的是資料類型轉換的問題,相信經常做c#開發的都和我一樣把學校的那點c++底子都忘光了吧(語言特性類)。
網上有一大堆得轉換對應表,也有一大堆的轉換執行個體,但是都沒有強調一個更重要的問題,就是c#資料類型和c++資料類型占記憶體長度的對應關系。
如果dll檔案中隻包含一些基礎類型,那這個問題可能可以被忽略,但是如果是組合類型(這個叫法也許不妥),如結構體、類類型等,在其中的成員變量的長度的申明正确與否将決定你對dll檔案調用的成敗。
如有以下代碼,其實不是dll檔案的源碼,而是廠商給的c++例子代碼
c++中的結構體申明
[c-sharp] view plaincopy
- typedef struct
- {
- unsigned char Port;
- unsigned long Id;
- unsigned char Ctrl;
- unsigned char pData[8];
- }HSCAN_MSG;
c++中的函數申明(一個c++程式引用另一個c++的dll檔案)
- extern "C" int _stdcall HSCAN_SendCANMessage(unsigned char nDevice,unsigned char nPort,HSCAN_MSG *msg,int nLength);
c++中的調用:
- ....
- HSCAN_MSG msg[100];
- .....
- HSCAN_SendCANMessage(m_nDevice,m_nPort,msg,nFrames);
由上述代碼可見,msg是個結構體的數組。
下面是我的c#的代碼
c#結構體申明:(申明成)
- [StructLayout(LayoutKind.Sequential)]
- public struct HSCAN_MSG
- {
- // UnmanagedType.ByValArray, [MarshalAs(UnmanagedType.U1)]這個非常重要,就是申明對應類型和長度的
- [MarshalAs(UnmanagedType.U1)]
- public byte Port;
- [MarshalAs(UnmanagedType.U4)]
- public uint nId;
- public byte nCtrl;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
- public byte[] pData;
- };
c#函數申明
- [DllImport("HS2106API.dll")]
- public static extern int HSCAN_SendCANMessage(
- byte nDevice, byte nPort, HSCAN_MSG[] pMsg, int nLength);
C#函數調用
- HSCAN_MSG[] msg = new HSCAN_MSG[1]; //發送緩沖區大小可根據需要設定;
- for (int yy = 0; yy < msg.Length; yy++)
- msg[yy] = new HSCAN_MSG();
- }
- //...結構體中的成員的執行個體化略
- HSCAN_SendCANMessage(0x0, 0x0, msg, 1)
那些隻能用指針不能用結構體和類的地方
c++中的結構體申明
c#中的結構體申明:
- /// <summary>
- /// 節點辨別,nEFF=1 時(擴充幀),為29 位nEFF=0(标準幀)時,為11 位;
- /// </summary>
- HSCAN_MSG[] msg1 = new HSCAN_MSG[10];
- for (int i = 0; i < msg1.Length; i++)
- msg1[i] = new HSCAN_MSG();
- msg1[i].pData = new byte[8];
- IntPtr[] ptArray = new IntPtr[1];
- ptArray[0] = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(HSCAN_MSG)) * 10);
- IntPtr pt = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(HSCAN_MSG)));
- Marshal.Copy(ptArray, 0, pt, 1);
- int count = HSCAN_ReadCANMessage(0x0, 0,pt, 10);
- textBoxStatus.Text += "/r/n" + "讀取0口:" + count.ToString() + "幀資料";
- for (int j = 0; j < 10; j++)
- msg1[j] =
- (HSCAN_MSG)Marshal.PtrToStructure((IntPtr)((UInt32)pt+ j * Marshal.SizeOf(typeof(HSCAN_MSG)))
- , typeof(HSCAN_MSG));
- textBoxStatus.Text += "/r/n收到0口" + Convert.ToByte(msg1[j].pData[0]).ToString()
- + "|" + Convert.ToByte(msg1[j].pData[1]).ToString()
- + "|" + Convert.ToByte(msg1[j].pData[2]).ToString()
- + "|" + Convert.ToByte(msg1[j].pData[3]).ToString()
- + "|" + Convert.ToByte(msg1[j].pData[4]).ToString()
- + "|" + Convert.ToByte(msg1[j].pData[5]).ToString()
- + "|" + Convert.ToByte(msg1[j].pData[6]).ToString()
- + "|" + Convert.ToByte(msg1[j].pData[7]).ToString();