引用命名空間 using System.Runtime.InteropServices
調用方法:
一、靜態加載
用DllImprot方式來加載c++DLL。如下格式:
//對應c++方法 //void DogInit(WORD*,HWND) //錯誤返回值,窗口句柄 [DllImport("DOG.dll", EntryPoint = "DogInit", CallingConvention = CallingConvention.Cdecl)] public static extern void DogInit(out short x, IntPtr hwnd); //對應c++方法 //void DogReadInfo(WORD*,int,unsigned char*,unsigned short) //錯誤返回值,讀取哪項,返回的內容,初始化長度 [DllImport("DOG.dll", EntryPoint = "DogReadInfo", CallingConvention = CallingConvention.Cdecl)] public static extern void DogReadInfo(out short x, int y,[MarshalAs(UnmanagedType.LPArray,SizeConst=512)]byte[] z,short w); /// <summary> /// 初始化加密狗 /// </summary> public static void DogInit() { IntPtr zero = IntPtr.Zero; short x = -1; DogInit(out x,zero); //此時x保存了返回的錯誤碼,如0、1、2 } public static void DogReadInfo() { short x; int y = 0; byte[] z = new byte[512]; short w = 512; DogReadInfo(out x,y,z,w); //此時x保存了返回的錯誤碼 //z保存了返回的讀取內容 string content = System.Text.Encoding.Default.GetString(z); }
注意:
1、如果只有一個DLL可以用這種方式,把DLL放在bin/Debug或bin文件夾下,在控制台窗體應用程序和Web網頁應用程序都有效。如果有多個DLL,存在依賴調用,如A、B兩個DLL,A會調用B里面的方法,因為[DllImport("A.dll")] 這樣寫只能調用一個DLL,在控制台窗體應用程序中,會自動加載B,但是在Web網頁應用程序不會自動加載B,導致返回錯誤碼找不到文件。要是這樣寫[DllImport("A.dll")] 、[DllImport("B.dll")] ,還是不會加載B。用下面二中的動態加載,依然只能加載一個DLL。解決方法:把A、B復制到系統文件夾下,32位系統復制到c/windows/system32下,64位系統復制到c/windows/syswow64文件夾下,寫的時候只用[DllImport("A.dll")],就會自動加載B。這種方式只適用於你可以控制電腦,如果用的別人的服務器空間,沒法復制,有可能的話最好把A、B編譯到一個DLL中來調用。
2、數據格式對應問題。
二、動態加載
1、用Assembly方式加載,這種方式只適用於托管代碼。c++也可以編譯為托管代碼。依然只能加載一個DLL。
2、用LoadLibrary和GetProcAddress方式加載,這種方式可以加載非托管代碼。依然只能加載一個DLL。
如下格式:
public class DllInvoke { [DllImport("kernel32.dll")] private extern static IntPtr LoadLibrary(String path); [DllImport("kernel32.dll")] private extern static IntPtr GetProcAddress(IntPtr lib, String funcName); [DllImport("kernel32.dll")] private extern static bool FreeLibrary(IntPtr lib); private IntPtr hLib; public DllInvoke(String DLLPath) { hLib = LoadLibrary(DLLPath); } ~DllInvoke() { FreeLibrary(hLib); } //將要執行的函數轉換為委托 public Delegate Invoke(String APIName,Type t) { IntPtr api = GetProcAddress(hLib, APIName); return (Delegate)Marshal.GetDelegateForFunctionPointer(api,t); } }
//使用時候 public class Class1 { //定義委托變量 public delegate int C(); public ActionResult Index() { //在方法里初始化類 DllInvoke dllInvoke = new DllInvoke("DLL絕對路徑"); //也可以把Dll保存在bin下,用相對路徑轉換為絕對路徑 //調用類里面方法 C c = (C) dllInvoke.Invoke("DLL里面方法名如DogInit", typeof (C)); //得到返回值 int result = c.Invoke(); } }
三、其他方式
在搜索過程中有些關鍵字也有啟示,但沒有往下找。如更改Dll搜索目錄,加入bin目錄到DLL搜索順序,DllImport加載依賴項Dll。
四、其他文章,看看
http://www.cnblogs.com/szytwo/archive/2011/12/11/2283780.html
http://www.cnblogs.com/kvspas/archive/2008/12/15/1355033.html
如有地方不正確,歡迎提出。