非托管DLL无法在ASP.NET服务器上加载

时间:2008-12-05 17:33:27

标签: asp.net dll iis-6 unmanaged

这个问题涉及一个ASP.NET网站,最初是在VS 2005中开发的,现在是在VS 2008中开发的。

这个网站使用两个非托管的外部DLL,它们不是.NET,我没有源代码来编译它们,必须按原样使用它们。

此网站在Visual Studio中运行良好,正确定位和访问这些外部DLL。但是,当网站发布在网络服务器(运行IIS6和ASP.NET 2.0)而不是开发PC时,它无法找到并访问这些外部DLL,我收到以下错误:

Unable to load DLL 'XYZ.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E)

外部DLL位于网站的bin目录中,以及包装它们的托管DLL以及网站的所有其他DLL。

搜索此问题表明,许多其他人似乎在从ASP.NET网站访问外部非.NET DLL时遇到同样的问题,但我找不到可行的解决方案。

我尝试了以下内容:

  • 运行DEPENDS以检查依赖关系以确定前三个 在路径中的System32目录中,最后一个在.NET 2中 框架。
  • 我把两个DLL及其依赖项放入 System32并重新启动服务器,但网站仍然 无法加载这些外部DLL。
  • 授予ASPNET,IIS_WPG和IUSR(针对该服务器)的完全权限 网站bin目录并重新启动,但网站仍然无法 加载这些外部DLL。
  • 将外部DLL作为现有项添加到项目中并进行设置 他们的“复制到输出”属性为“始终复制”和网站 仍然找不到DLL。
  • 还将其“Build Action”属性设置为“Embedded resource”和 网站仍然找不到DLL。

非常感谢任何有关此问题的帮助!

10 个答案:

答案 0 :(得分:44)

这是因为托管dll将阴影复制到.NET Framework目录下的临时位置。有关详细信息,请参阅http://msdn.microsoft.com/en-us/library/ms366723.aspx

不幸的是,非托管dll不会被复制,并且ASP.NET进程在需要加载它们时将无法找到它们。

一个简单的解决方案是将非托管dll放在系统路径中的目录中(在命令行中键入“path”以查看计算机上的路径),以便ASP.NET进程可以找到它们。 System32目录在路径中始终,因此将非托管dll放在那里总是有效,但我建议在路径中添加一些其他文件夹,然后在那里添加dll以防止污染System32目录。这种方法的一个很大的缺点是你必须为应用程序的每个版本重命名非托管dll,你可以快速拥有自己的dll地狱。

答案 1 :(得分:41)

作为将dll放在已经在路径中的文件夹(如system32)的替代方法,您可以使用以下代码更改流程中的路径值

System.Environment.SetEnvironmentVariable("Path", searchPath + ";" + oldPath)

然后,当LoadLibrary尝试查找非托管DLL时,它还将扫描searchPath。这可能比在System32或其他文件夹中乱七八糟。

答案 2 :(得分:22)

尝试将dll放在\ System32 \ Inetsrv目录中。这是Windows Server上IIS的工作目录。

如果这不起作用,请尝试将dll放在System32目录中,将依赖项文件放在Inetsrv目录中。

答案 3 :(得分:11)

添加到Matt的答案,这是我最终为64位服务器2003 / IIS 6工作的东西:

  1. 确保您的dlls / asp.net是相同的版本(32/64位)
  2. 将非托管dll放在inetsrv目录中(请注意,在64位窗口中,这是在syswow64下,即使创建了sys32 / inetsrv目录)
  3. 将托管dll保留在/ bin
  4. 确保两组dll都具有读/执行权限

答案 4 :(得分:6)

查看FileMonProcMon并过滤麻烦的DLL的名称。这将显示搜索DLL时扫描的目录以及您可能遇到的任何权限问题。

答案 5 :(得分:3)

另一个选项是将本机DLL作为资源嵌入到托管DLL中。这在ASP.NET中更复杂,因为它需要在运行时写入临时文件夹。 The technique is explained in another SO answer

答案 6 :(得分:2)

在您的环境设置中也始终值checking the path变量。

答案 7 :(得分:1)

直接在XYZ.dll上运行DEPENDS,位于您将其部署到的位置。如果这没有显示任何遗漏,请使用平台SDK中的fuslogvw工具来跟踪加载程序错误。此外,事件日志有时包含有关加载DLL失败的信息。

答案 8 :(得分:1)

А整天在这个问题上苦苦挣扎,最后我找到了一个适合我的解决方案。这只是一个测试,但方法正在发挥作用。

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();
                  }
                }
          }
        }
    }
}

答案 9 :(得分:0)

在Application_start上使用以下命令: (根据需要自定义/ bin / x64和bin / dll / x64文件夹)

String _path = String.Concat(System.Environment.GetEnvironmentVariable("PATH")
                ,";"
                , System.Web.Hosting.HostingEnvironment.MapPath("~/bin/x64")
                ,";"
                , System.Web.Hosting.HostingEnvironment.MapPath("~/bin/dll/x64")
                ,";"
                );
            System.Environment.SetEnvironmentVariable("PATH", _path, EnvironmentVariableTarget.Process);