前段時間公司做了個winform程序,需要調用c 的dll去讀取卡號的程序,期間遇到些問題,下面來分享下
一、dll路徑問題
相信很多開發者都會遇到這個問題,我總結了下我現在有3總方式去解決這個問題;
1.直接放在bin下面,跟exe文件在同一文件夾下,
ps:調試代碼的時候,如果是debug模式的話,就放bin/debug下,同理release 模式就放bin/debug下;如果這種方式不行的話,就試試第二種方式。
2.放在C:\Windows\System32下;
3.如果以上方式都不行的話就,那就只能寫物理路徑了。例
[System.Runtime.InteropServices.DllImportAttribute(@"E:\Source\GPTagReaderDll", EntryPoint = "OpenPort", CallingConvention = CallingConvention.Cdecl)] [return: System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)] public static extern bool OpenPort(string pPortname, uint dBaud);
該種方式只適合調一個dll的方式,如果調用的這個dll依賴於其他的dll的話這種方式是行不通的;這種方式還有局限性,如果發布出去,你得要求別人的機子上這個物理路徑下必須有這個文件,但是 這個太不現實了
除這3種方式外,還聽說過寫到環境變量裡,不過這種方式沒試過,就不在此提了。
二、類型轉換的問題
下面是c的結構體:
typedef struct { unsigned char DeviceIdentify[30];//Greenpow Usb IC card reader unsigned short res; }FindDeviceAck_Struct;
我們需要把它轉換成c#的結構體:
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, CharSet = System.Runtime.InteropServices.CharSet.Ansi,Pack =1)] public struct FindDeviceAck_Struct { /// unsigned char[30] [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = 30)] public string DeviceIdentify; /// unsigned short public ushort res; }
c# 跟c/c++類型的對應方式,可參考http://www.cnblogs.com/ausoldier/archive/2007/12/07/986141.html;
我這裡DeviceIdentify用String接收,但是出現了亂碼,後來改成了
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, CharSet = System.Runtime.InteropServices.CharSet.Ansi,Pack =1)] public struct FindDeviceAck_Struct { /// unsigned char[30] [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 30)] public byte[] DeviceIdentify; /// unsigned short public ushort res; }
string 對應的是ByValTStr,byte[] 對應的是ByValArray,sizeconst指的是大小,pack=1表示按1字節對齊
三、調用c裡的方法
c裡的方法是BOOL FindDevice(FindDeviceAck_Struct &finddeviceack);
剛開始我直接這樣寫,
[System.Runtime.InteropServices.DllImportAttribute("GPTagReaderDll", EntryPoint = "FindDevice", CallingConvention = CallingConvention.Cdecl)] public static extern bool FindDevice(FindDeviceAck_Struct finddeviceack);
調用的時候
FindDeviceAck_Struct findDeviceAck=new FindDeviceAck_Struct(); var result= NativeMethods.FindDevice(findDeviceAck);
結果報了下面這個錯誤:嘗試讀取或寫入受保護的程序。通常指示其他內存已經存在。
後來同事提醒才注意到BOOL FindDevice(FindDeviceAck_Struct &finddeviceack)參數&finddeviceack 有個'&'。
經改成
[System.Runtime.InteropServices.DllImportAttribute("GPTagReaderDll", EntryPoint = "FindDevice", CallingConvention = CallingConvention.Cdecl)] public static extern bool FindDevice(ref FindDeviceAck_Struct finddeviceack);
這樣就調用成功了