【问题标题】:Calling 32-bit unmanaged DLL files from C# randomly failing从 C# 调用 32 位非托管 DLL 文件随机失败
【发布时间】:2010-06-01 10:00:23
【问题描述】:

从 C# 网站调用 32 位 Delphi DLL 文件时遇到问题。代码一般运行良好,但偶尔会报错,

*无法加载 DLL '':找不到指定的模块。 (HRESULT 异常:0x8007007E)。

此问题一直存在,直到我为该站点回收应用程序池,然后它再次正常工作。

在同一台服务器上,还有一个 Web 服务正在调用同一组 DLL 文件。此 Web 服务似乎与该网站没有相同的问题。

两个应用程序都使用.NET Framework 3.5,IIS 上的单独应用程序池。

这是我用来包装 DLL 文件的代码:

public sealed  class Mapper
{
    static Mapper instance = null;

    [DllImport("kernel32.dll")]
    private static extern bool SetDllDirectory(string lpPathName);

    private Mapper()
    {
        SetDllDirectory(ConfigManager.Path);
    }

    public static Mapper Instance
    {
        get
        {
            if (instance == null)
            {
                instance = new Mapper();
            }
            return instance;
        }
    }

    public int Foo(string bar, ref double val)
    {
        return Loader.Foo(bar, ref val);
    }
}


public static class Loader
{
    [DllImport("some.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, EntryPoint = "foo")]
    public static extern int Foo(string bar, ref double val);
}

那我这样称呼它:

double val = 0.0; 
Mapper.Instance.Foo("bar", ref val);

为什么会“随机”无法加载 DLL '':找不到指定的模块。 (HRESULT 异常:0x8007007E)。

另一个问题是我无法在开发环境中复制该问题。我认为由于两个应用程序调用相同的 DLL 文件,可能会发生一些锁定。为了复制这一点,我创建了一个应用程序,它产生多个线程并重复调用 32 位 DLL 文件,然后使用网站调用这些相同的 DLL 文件。我仍然无法复制该问题。

我能想到的一些可能的修复方法:

  1. 将 32 位 DLL 文件包装在 Web 服务中(因为 Web 服务似乎没有遇到同样的问题)。但是,如果事实证明 Web 服务也失败了,这可能毫无价值。
  2. 为会话状态设置状态服务器,并定期为站点回收应用程序池。这不是解决问题,只是避免它。
  3. 将 DLL 文件包装在一个 EXE 文件中,然后调用该 EXE 文件。然后我不应该遇到同样的问题。但这似乎也是一个 hacky 解决方案。
  4. 以不同的方式实现 mapper 类?但是我应该怎么打电话呢?另一个缺点是其他应用程序正在使用此映射器,所以我也需要更改那里的代码。

我该怎么办?

【问题讨论】:

  • 请贴出异常的融合日志
  • 嘿杰克,我明天看看能不能设置一下,如果出现错误,我会发帖的。谢谢

标签: c# winapi unmanaged dllimport


【解决方案1】:

我不知道这个问题的真正原因,但根据我的经验,这个错误消息可能是由以下原因引起的:

  • 您正在使用的 DLL 文件需要一个在加载时不可用的运行时库(如 Visual C++ 运行时库)。您需要库的确切版本。例如,如果您的 DLL 文件是使用运行时 Visual Studio 2008 SP1 编写的,则您需要完全相同的版本。

  • DLL 文件的依赖项之一不可用。您可以使用Dependency Walker 进行检查。

  • 另外,您必须确保您的 DLL 文件和调用应用程序都是 32 位或 64 位的。当我想从 64 位应用程序调用 32 位 DLL 文件时,有时我会遇到同样的错误。

我知道这不是你真正的答案,但我希望它能帮助你找到解决方案。

【讨论】:

  • 感谢 Nima,但问题是它在一段时间内有效,然后会突然停止工作。 dll是def 32位的。无论如何,我都会检查那些 32 位 dll 的依赖关系。谢谢。
【解决方案2】:

为了解决这个问题(现在已经停止),我保留了映射器代码,但在调用应用程序中我手动设置了路径(即使映射器 DLL 文件大部分时间都这样做)。

所以在主应用程序中,我调用了附加DLL文件所在目录的路径。

private static void AddEnvironmentPaths(string[] paths)
{
    string path = Environment.GetEnvironmentVariable("PATH") ?? string.Empty;
    path += ";" + string.Join(";", paths);

    Environment.SetEnvironmentVariable("PATH", path);
}

奇怪的是,mapper 类大部分时间都在工作,但有时会停止。使用上面的代码添加路径似乎已经解决了这个问题。

【讨论】:

    猜你喜欢
    • 2017-04-01
    • 1970-01-01
    • 2011-03-04
    • 2011-12-22
    • 1970-01-01
    • 2013-01-07
    • 2011-02-06
    • 2011-05-22
    • 2017-12-18
    相关资源
    最近更新 更多