是否在某处记录了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,但当使用Managed.DLL时,使用ERROR_FILE_NOT_FOUND调用LoadLibrary(“Native.DLL”)失败在ASP.Net应用程序中,因为包含Managed.DLL的目录不在本机代码DLL的搜索路径上。
我的第一个想法是使用Assembly.GetExecutingAssembly()。Location然后使用完整路径发出LoadLibrary调用,但是然后Native.DLL无法找到Driver.DLL,因为包含它们的目录仍然不在搜索路径。
我可以通过使用Assembly.GetExecutingAssembly()来解决这个问题。使用SetDllDirectory设置本机DLL搜索路径的位置值,但这有两个主要缺点:
1)SetDllDirectory更改了全局WinAPI设置,并且可能会干扰同样使用本机代码DLL的ASP.Net工作进程中的其他代码;我还验证了使用DllImport属性并没有弄乱这个设置,所以现在更改它确实可能会破坏之前正在运行的东西。
2)从Visual Studio中调试ASP.Net应用程序仍然无效,因为VS将托管资源复制到临时目录中,但将本机DLL保留在项目构建目录中,因此它们最终位于不同的位置在调试会话中(并且为每个调试会话擦除临时目录,因此手动将本机DLL复制到其中也不起作用;我必须将本机DLL复制到IIS的目录中以便调试会话找到它们,这很明显不可接受的解决方案)。
我真的想在这里做兼容的事情,但到目前为止还没有找到这是什么,经过几天毫无结果的搜索后,任何指针都会非常感激。
答案 0 :(得分:0)
回答我自己的问题:
1)关于Managed.DLL的复制缺少的关键字是“影子复制”(James Schubert比我见过的任何官方Microsoft文档解释得好得多)诀窍是使用{{ 1}}而不是Assembly.CodeBase
,因为前者给出了Managed.DLL的原始位置,后者给出了卷影副本的位置(John Sibly and Sneal共享好的代码片段以从URI中提取目录名称在Assembly.Location
)。
2)使本机DLL的依赖性可用的方法是在需要之前使用Assembly.CodeBase
显式加载它们(并且因为这会增加它们的引用计数,所以在完成时也会使用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
来电的顺序。