2

我正在开发 C#/.NET 3.5 应用程序。我正在使用用 C 编写的旧版 dll,signals.dll。我使用 P/Invoke 从 .NET 包装器中调用它。我正在调用 2 种类型的处理函数,类型 A 和 B。当我只调用一种类型的处理时,一切正常。当我交错调用 A 和 B 处理时,数据结果已损坏。我相信 dll、signals.dll 正在使用 C 风格的全局变量,并且数据被破坏了。

为了解决这个问题,我在磁盘上创建了 2 个 dll 副本,signals.dll 和 signals2.dll。然后我使用 P/Invoke 修改了 .NET 包装器,将 A 类处理定向到一个 dll,将 B 类处理定向到另一个实例。现在,一切正常。

然后我在论坛和那里的解决方案上看到了类似的问题。(支持具有全局数据的插件 DLL 的多个实例)。基本上,该提议的解决方案是从代码动态放置,在磁盘上创建一个新的 .dll 实例(根据需要),然后加载它并从中调用函数。代码的关键部分如下所示:

private IntPtr dllHandle;
string myDllPath = Path.Combine(dllDir, String.Format("mylib-{0}.dll", GetHashCode()));
        File.Copy(origDllPath, myDllPath);
        dllPath = myDllPath;
        dllHandle = LoadLibrary(dllPath);
        _getVersion = GetProcEntryDelegate<_getVersionDelegate>(dllHandle, "GetVersion");

    private delegate int _getVersionDelegate();
    private readonly _getVersionDelegate _getVersion;

public int GetVersion()
    {
        return _getVersion();
    }

private static D GetProcEntryDelegate<D>(IntPtr hModule, string name)
        where D: class
    {
        IntPtr addr = _getProcAddress(hModule, name);
        if (addr == IntPtr.Zero)
            throw new Win32Exception();
        return Marshal.GetDelegateForFunctionPointer(addr, typeof(D)) as D;
    }

我想到的是,是否可以修改上面的代码以在内存中创建 dll 的副本,而不是在磁盘上并从那里加载它。我认为只是需要欺骗 IntPtr dllHandle 从内存中获取价值,而不是从 LoadLibrary 中获取价值。怎么做?

4

2 回答 2

1

LoadLibraryLoadLibraryEx都需要文件路径。您将需要一个自定义加载过程,包括内存映射等。我找到了一篇描述该过程的博文(“从内存中加载 DLL”)和一个匹配的 GitHub 项目;内存模块

于 2013-04-14T08:29:10.067 回答
1

什么都没有just:) - 它要复杂得多,涉及

这是一个可能有帮助的链接 -从内存中加载库/模块

正如@Hans Passant 所说,我不鼓励你这样做——即使它在某些情况下可能是一个诱人的解决方案(但我不认为你真的需要这样,也许很好)。

它涉及处理可移植的可执行格式——我怀疑该项目是否涵盖了所有需要完成的工作。

您可以尝试制作您的 C++/CLI 包装器 - 或导出MemoryLoadLibrary并尝试 P/Invoking - 但我怀疑这会很容易。

于 2013-04-14T11:41:04.223 回答