最近在项目中碰到需要调用非托管C++生成的dll,下面将自己遇到的问题,以及解决的办法总结如下: 1. 问题: 我们通常去映射dll的方法是使用
public const string dllPath = path; [DllImport(dllPath + " test.dll " , EntryPoint = " test() " , SetLastError = true , CharSet = CharSet.Ansi, ExactSpelling = true , CallingConvention = CallingConvention.Cdecl)] public static extern int test();这种方式有一个致命的缺陷,dll文件路径dllPath必须为const,而const是编译时常量,也就是说dllPath赋值必须是字符串常量,如果你想动态指定dll文件路径用这种方式基本上没办法实现,下面是一种解决方案。 解决方案:
[DllImport( " Kernel32.dll " )] public static extern IntPtr LoadLibrary( string lpFileName); [DllImport( " kernel32.dll " , SetLastError = true )] public static extern int GetProcAddress( IntPtr hModule, string lpProcName); [DllImport( " kernel32.dll " , EntryPoint = " FreeLibrary " , SetLastError = true )] public static extern bool FreeLibrary(IntPtr hModule);这种方式有点像C#的反射,先引入这3个API 函数: LoadLibrary(string lpFileName)是加载指定的dll文件,参数lpFileName为dll文件的路径,返回的为该dll的实例(指针) GetProcAddress(IntPtr hModule,string lpProcName)是获取dll中指定的方法委托,参数hModule为LoadLibrary()方法返回的值,lpProcName方法名,返回值为指定方法的委托,注意要强制转换. FreeLibrary(InPtr hModule)是释放加载的dll文件,参数hModule为LoadLibrary()返回值. 有了这些方法就能很容易的实现动态加载dll。 代码:
// dll实例 static private IntPtr instance; // 要加载方法的委托 delegate void Test(); // 导入引擎dll [DllImport( " Kernel32.dll " )] public static extern IntPtr LoadLibrary( string lpFileName); [DllImport( " kernel32.dll " , SetLastError = true )] public static extern int GetProcAddress( IntPtr hModule, string lpProcName); [DllImport(" kernel32.dll " , EntryPoint = " FreeLibrary " , SetLastError = true)] public static extern bool FreeLibrary(IntPtr hModule); // 获取方法指针 static private Delegate GetAddress(IntPtr dllModule, string functionname, Type t) { int addr = GetProcAddress(instance, functionname); if (addr == 0) return null; else return Marshal.GetDelegateForFunctionPointer(new IntPtr(addr), t); } // 加载DLL static public void LoadLib() { string dllPath; dllPath = ConfigurationSettings.AppSettings["dllPath"].ToString(); instance = LoadLibrary(dllPath); if (instance.ToInt32() == 0) { throw new LoadLibraryException("请在App.Config中配置引擎DLL的路径!"); } } /**/ /// <summary> /// 卸载DLL /// </summary> static public void FreeLib() { FreeLibrary(instance); } /**/ /// <summary> /// 实例 /// </summary> /// <param name="iptr"></param> /// <returns></returns> static public void test() { try { Test temp = (Test)GetAddress(instance, "test", typeof(Test)); return temp(); } catch (Exception ex) { throw new LoadLibraryException(""); }}
public delegate int MsgBox(int hwnd,string msg,string cpp,int ok); [DllImport("Kernel32")] public static extern int GetProcAddress(int handle, String funcname); [DllImport("Kernel32")] public static extern int LoadLibrary(String funcname); [DllImport("Kernel32")] public static extern int FreeLibrary(int handle); private static Delegate GetAddress(int dllModule, string functionname, Type t) { int addr = GetProcAddress(dllModule, functionname); if (addr == 0) return null; else return Marshal.GetDelegateForFunctionPointer(new IntPtr(addr), t); } private void button1_Click(object sender, EventArgs e) { int huser32 = 0; huser32 = LoadLibrary("user32.dll"); MsgBox mymsg = (MsgBox)GetAddress(huser32, "MessageBoxA", typeof(MsgBox)); mymsg(this.Handle.ToInt32(), txtmsg.Text, txttitle.Text , 64); FreeLibrary(huser32); }