ASP.Net中的DllImport如何查找DLL?
ASP.Net是如何为本地DLL设置搜索路径的? 我需要能够在我自己的代码中复制逻辑。
更多背景:我维护一个托管的库(比如Managed.DLL),它包装一个本地库(称为Native.DLL),该库本身又使用另一个本地DLL(如Driver.DLL)。 到目前为止,Managed.DLL一直使用.Net的DllImport属性从Native.DLL导入函数,但现在我必须将其更改为手动编码调用LoadLibrary和GetProcAddress以获得更多控制; 特别是,我需要能够调用FreeLibrary来卸载Native.DLL,并且当通过DllImport加载Native.DLL时,我无法执行此操作。
问题来了:虽然只有DllImport(“Native.DLL”)足以查找Native.DLL和Driver.DLL,但在ASP中使用Managed.DLL时,调用LoadLibrary(“Native.DLL”)失败,并显示ERROR_FILE_NOT_FOUND .Net应用程序,因为包含Managed.DLL的目录不在本机代码DLL的搜索路径中。
我的第一个想法是使用Assembly.GetExecutingAssembly()。位置,然后发出带有完整路径的LoadLibrary调用,但是Native.DLL无法找到Driver.DLL,因为包含它们的目录仍然不在搜索路径中。
我可以通过使用Assembly.GetExecutingAssembly()。位置值来设置本机DLL搜索路径与SetDllDirectory,但这有两个主要缺点:
1)SetDllDirectory更改全局WinAPI设置,并可能干扰同样使用本机代码DLL的同一ASP.Net工作进程中的其他代码; 我也已经证实,使用DllImport属性不会混淆这个设置,所以现在改变它可能确实会破坏以前工作的东西。
2)它仍然不适用于在Visual Studio中调试ASP.Net应用程序,因为VS会将受管资源复制到临时目录中,但会将本机DLL留在项目构建目录中,因此它们会在调试的不同位置结束会话(并且每个调试会话都会擦除临时目录,因此手动将本机DLL复制到它中也不起作用;我必须将本机DLL复制到IIS的目录中以便调试会话找到它们,这显然是不可接受的解决方案)。
我真的想在这里做兼容的事情,但到目前为止还没有能够找出这是什么,经过几天的无果搜索任何指针将不胜感激。
回答我自己的问题:
1)关于复制Managed.DLL的关键字我错过了“影子复制”(詹姆斯舒伯特解释它比我见过的任何微软官方文档都好),诀窍是使用Assembly.CodeBase
而不是Assembly.Location
,因为前者给出了Managed.DLL的原始位置,后者给出了影子副本的位置(John Sibly和Sneal共享了漂亮的代码片段以从Assembly.CodeBase
的URI中提取目录名称)。
2)使本地DLL的依赖性可用的方法是在需要之前使用LoadLibrary
显式加载它们(并且因为这增加了它们的引用计数,并且在完成时使用FreeLibrary
释放它们)。
所以,加载顺序是
string dir = Assembly.GetExecutingAssembly().CodeBase;
dir = new Uri(dir).LocalPath;
dir = Path.GetDirectoryName(dir);
IntPtr driver = LoadLibrary(dir + Path.DirectorySeparatorChar + "Driver.DLL");
IntPtr managed = LoadLibrary(dir + Path.DirectorySeparatorChar + "Managed.DLL");
和卸载顺序
FreeLibrary(managed);
FreeLibrary(driver);
(还要注意LoadLibrary
和FreeLibrary
调用的顺序)。
上一篇: How does DllImport in ASP.Net look for the DLL?
下一篇: Inno Setup 5.5.4(a) under Windows 7 with mistake "cannot import dll"