非托pipeDLL无法加载到ASP.NET服务器上
这个问题涉及一个ASP.NET网站,最初是在VS 2005中开发的,现在在VS 2008中开发。
这个网站使用了两个非托pipe的外部DLL,它们不是.NET,我没有源代码来编译它们,并且必须按原样使用它们。
这个网站在Visual Studio中运行良好,正确定位和访问这些外部DLL。 但是,当网站发布到networking服务器(运行IIS6和ASP.NET 2.0)而不是开发PC时,它无法find并访问这些外部DLL,并且出现以下错误:
Unable to load DLL 'XYZ.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E)
外部DLL位于网站的bin目录中,以及包含它们的托pipeDLL以及网站的所有其他DLL。
search这个问题揭示了许多其他人似乎有相同的问题从ASP.NET网站访问外部非.NET DLL,但我还没有find一个解决scheme。
我已经尝试了以下内容:
- 运行DEPENDS以检查依赖关系,以确定前三个位于path中的System32目录中,最后一个位于.NET 2框架中。
- 我把这两个DLL和它们的依赖关系放在System32中,并重新启动服务器,但是网站仍然无法加载这些外部DLL。
- 给ASPNET,IIS_WPG和IUSR(对于那个服务器)的完全的权利到网站的bin目录,并重新启动,但网站仍然无法加载这些外部的DLL。
- 将外部DLL作为现有项添加到项目中,并将其“复制到输出”属性设置为“始终复制”,而网站仍然无法find这些DLL。
- 还将其“Build Action”属性设置为“Embedded resource”,网站仍然无法findDLL。
任何援助这个问题将不胜感激!
尝试将dll放在\ System32 \ Inetsrv目录中。 这是Windows Server上IIS的工作目录。
如果这不起作用,请将dll放在System32目录中,并将依赖文件放在Inetsrv目录中。
发生这种情况是因为受pipedll将影子复制到.NET Framework目录下的临时位置。 有关详细信息,请参阅http://msdn.microsoft.com/en-us/library/ms366723.aspx 。
不幸的是,非托pipedll不会被复制,并且ASP.NET进程在需要加载它们时将无法find它们。
一个简单的解决scheme是将非托pipedll放在系统path中的一个目录中(在命令行键入“path”以查看计算机上的path),以便ASP.NET进程可以find它们。 System32目录总是在path中,因此将非托pipedll放在那里总是有效,但我build议将其他文件夹添加到path中,然后添加dll以防止污染System32目录。 这种方法的一大缺点是你必须重命名每个版本的应用程序的非托pipeDLL,你可以很快有你自己的DLL地狱。
作为将dll置于path中的文件夹(如system32)的替代方法,可以使用以下代码更改进程中的path值
System.Environment.SetEnvironmentVariable("Path", searchPath + ";" + oldPath)
然后,当LoadLibrary尝试查找非托pipeDLL时,它也将扫描searchPath。 这可能比在System32或其他文件夹中弄得乱七八糟。
添加到马特的答案,这是最终为我的64位服务器2003 / IIS 6工作:
- 确保你的dlls / asp.net是相同的版本(32/64位)
- 把unmanaged dll放在inetsrv dir中(注意在64位的窗口下,尽pipesys32 / inetsrv目录已经创build,但仍在syswow64下)
- 将pipe理的dll保存在/ bin中
- 确保两套dll都具有读取/执行权限
用FileMon或ProcMon来查看并筛选有问题的DLL的名称。 这将向您显示searchDLL的扫描目录以及您可能遇到的任何许可问题。
另一种select是将本地DLL作为资源embedded到受pipeDLL中。 这在ASP.NET中更复杂,因为它需要在运行时写入临时文件夹。 该技术在另一个SO答案中解释 。
总是值得在环境设置中检查pathvariables。
在XYZ.dll上直接运行DEPENDS,并将其部署到该位置。 如果没有发现任何缺失,请使用平台SDK中的fuslogvw工具来跟踪加载器错误。 此外,事件日志有时包含有关加载DLL失败的信息。
我遇到了同样的问题。 而我尝试了以上所有选项,复制到system32,inetpub,设置path环境等没有任何工作。 这个问题最终通过将非托pipedll复制到Web应用程序或Web服务的bin目录来解决。
在这个问题上挣扎了一整天之后,终于find了适合我的解决scheme。 这只是一个testing,但方法正在工作。
namespace TestDetNet { static class NativeMethods { [DllImport("kernel32.dll")] public static extern IntPtr LoadLibrary(string dllToLoad); [DllImport("kernel32.dll")] public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName); [DllImport("kernel32.dll")] public static extern bool FreeLibrary(IntPtr hModule); } public partial class _Default : System.Web.UI.Page { [UnmanagedFunctionPointer(CallingConvention.StdCall)] private delegate int GetRandom(); protected System.Web.UI.WebControls.Label Label1; protected void Page_Load(object sender, EventArgs e) { Label1.Text = "Hell'ou"; Label1.Font.Italic = true; } protected void Button1_Click(object sender, EventArgs e) { if (File.Exists(System.Web.HttpContext.Current.Server.MapPath("html/bin")+"\\DelphiLibrary.dll")) { IntPtr pDll = NativeMethods.LoadLibrary(System.Web.HttpContext.Current.Server.MapPath("html/bin")+"\\DelphiLibrary.dll"); if (pDll == IntPtr.Zero) { Label1.Text = "pDll is zero"; } else { IntPtr pAddressOfFunctionToCall = NativeMethods.GetProcAddress(pDll, "GetRandom"); if (pAddressOfFunctionToCall == IntPtr.Zero) { Label1.Text += "IntPtr is zero"; } else { GetRandom _getRandom = (GetRandom)Marshal.GetDelegateForFunctionPointer(pAddressOfFunctionToCall,typeof(GetRandom)); int theResult = _getRandom(); bool result = NativeMethods.FreeLibrary(pDll); Label1.Text = theResult.ToString(); } } } } } }