windows 应用调用两个具有相同名称的 C++ DLL 和链接到另一个 DLL 的 API

A windows app calls two C++ DLLs with same name and APIs linking to another DLL

我正在尝试让我的 C# 应用 运行 同时使用两个不同版本的 C++ DLL。

两个具有相同文件名和API的DLL位于不同的目录:

App -> V1/A.dll -> V1/B.dll
    -> V2/A.dll -> V2/B.dll

来自 Dynamic-Link Library Search Order, I've learned how to make one A.dll call the B.dll in the same directory by LoadLibraryEx() and SetDllDirectory().

如果我的应用程序分别调用两个版本,它工作正常:

SetDllDirectory("V1");
v1 = LoadLibraryEx("V1/A.dll", null, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_USER_DIRS);
SetDllDirectory(null);
v1.open();
v1.runall();
v1.close();

SetDllDirectory("V2");
v2 = LoadLibraryEx("V2/A.dll", null, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_USER_DIRS);
SetDllDirectory(null);
v2.open();
v2.runall();
v2.close();

但是如果两个版本运行一帧一帧就出错了(被零除异常):

SetDllDirectory("V1");
v1 = LoadLibraryEx("V1/A.dll", null, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_USER_DIRS);
SetDllDirectory(null);
SetDllDirectory("V2");
v2 = LoadLibraryEx("V2/A.dll", null, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_USER_DIRS);
SetDllDirectory(null);

v1.open();
v2.open();
foreach (frame in frames)
{
    v1.run(frame);
    v2.run(frame); // divide-by-zero exception occurs
}
v1.close();
v2.close();

由于 v2 可能在 A.dll 或 B.dll 中调用了错误,我在 DLL 中添加了一些测试 API:

A.dll:
    int _a = 0;
    void set_var(int a, int b) {
        _a = a;
        set_var_b(b);
    }
    void get_var(int *a, int *b) {
        *a = _a;
        *b = get_var_b();
    }

B.dll:
    int _b = 0;
    void set_var_b(int b) {
        _b = b;
    }
    int get_var_b() {
        return _b;
    }

在B.dll中v1和v2似乎共享全局变量的相同数据内存,但在A.dll中却没有:

int a1, b1;
int a2, b2;
v1.get_var(&a1, &b1); // a1 = 0, b1 = 0
v2.get_var(&a2, &b2); // a2 = 0, b2 = 0
v1.set_var(1, 2);
v2.get_var(&a2, &b2); // a2 = 0, **b2 = 2**
v2.set_var(3, 4);
v1.get_var(&a1, &b2); // a1 = 1, **b1 = 4**

我的问题:

  1. 应用程序可以调用两个具有相同文件名的 DLL (A.dll) 和链接到另一个 DLL (B.dll) 的 API 吗?
  2. 如果对 1 的回答是肯定的,是否允许在 B.dll 中使用全局变量?如果不是,是什么原因?

感谢 Hans Passant 的评论。

在我之前的案例中,A.dll 的两个不同版本调用相同的 B.dll:

App -> V1/A.dll |-> V1/B.dll
    -> V2/A.dll |   V2/B.dll

清单可以解决这个问题:

  1. 为 A.dll 项目创建清单文件
    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
      <file name="B.dll" />
    </assembly>
    
  2. 将清单文件添加到 A.dll 项目的属性中:Manifest Tool -> Input and Output -> Additional Manifest Files

另请参阅: