从C#调用32位非托管DLL文件随机失败

时间:2010-06-01 10:00:24

标签: c# winapi unmanaged dllimport

从C#网站调用32位Delphi DLL文件时遇到问题。代码通常运行正常,但偶尔会出错,

  

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

在我回收网站的应用程序池之前,此问题仍然存在,然后再次正常运行。

在同一台服务器上,还有一个调用同一组DLL文件的Web服务。此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. 以不同方式实施映射器类?但是我该怎么做呢?另一个缺点是其他应用程序正在使用此映射器,因此我也需要更改代码。
  5. 我该怎么办?

2 个答案:

答案 0 :(得分:1)

我不知道究竟是什么导致了这个问题,但根据我的经验,此错误消息可能是由以下原因引起的:

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

  • DLL文件的一个依赖项不可用。您可以使用Dependency Walker

  • 进行检查
  • 此外,您必须确保您的DLL文件和调用应用程序都是32位或64位。当我想从64位应用程序调用32位DLL文件时,有时会出现相同的错误。

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

答案 1 :(得分:0)

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

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

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

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

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

相关问题