如何在运行时后期绑定 32 位/64 位库

Posted

技术标签:

【中文标题】如何在运行时后期绑定 32 位/64 位库【英文标题】:How to late bind 32bit/64 bit libs at runtime 【发布时间】:2010-09-06 13:04:10 【问题描述】:

我遇到了一个与here 描述的类似但略有不同的问题(加载程序集及其依赖项)。

我有一个用于 3D 渲染的 C++ DLL,这是我们出售给客户的。对于 .NET 用户,我们将有一个 CLR 包装器。 C++ DLL 可以在 32 位和 64 位版本中构建,但我认为这意味着我们需要有两个 CLR 包装器,因为 CLR 绑定到特定的 DLL?

假设现在我们的客户有一个可以是 32 位或 64 位的 .NET 应用程序,并且它是一个纯 .NET 应用程序,它让 CLR 从一组程序集中解决它。问题是应用程序代码如何在运行时动态选择我们的 32 位和 64 位 CLR/DLL 组合?

更具体地说,上述问题的建议答案是否也适用于此处(即创建 ResolveEvent 处理程序)?

【问题讨论】:

【参考方案1】:

我终于有了一个似乎可行的答案。

将 32 位和 64 位版本(托管和非托管)编译到单独的文件夹中。然后让 .NET 应用在运行时选择从哪个目录加载程序集。

使用 ResolveEvent 的问题在于,只有在找不到程序集时才会调用它,因此很容易意外地以 32 位版本结束。而是使用第二个 AppDomain 对象,我们可以在其中更改 ApplicationBase 属性以指向正确的文件夹。所以你最终得到如下代码:

static void Main(String[] argv)
  
     // Create a new AppDomain, but with the base directory set to either the 32-bit or 64-bit
     // sub-directories.

     AppDomainSetup objADS = new AppDomainSetup();

     System.String assemblyDir = System.IO.Path.GetDirectoryName(Application.ExecutablePath);
     switch (System.IntPtr.Size)
     
        case (4): assemblyDir += "\\win32\\";
           break;
        case (8): assemblyDir += "\\x64\\";
           break;
     

     objADS.ApplicationBase = assemblyDir;

     // We set the PrivateBinPath to the application directory, so that we can still
     // load the platform neutral assemblies from the app directory.
     objADS.PrivateBinPath = System.IO.Path.GetDirectoryName(Application.ExecutablePath);

     AppDomain objAD = AppDomain.CreateDomain("", null, objADS);
     if (argv.Length > 0)
        objAD.ExecuteAssembly(argv[0]);
     else
        objAD.ExecuteAssembly("MyApplication.exe");

     AppDomain.Unload(objAD);

  

您最终会得到 2 个 exe - 您的普通应用程序和第二个切换应用程序,用于选择要加载的位。 注意 - 我自己不能相信这个细节。鉴于我最初的指示,我的一位同事对此提出了质疑。如果他注册 ***,我会将答案分配给他

【讨论】:

【参考方案2】:

大约一年前我能够做到这一点,但我不再记得所有细节了。基本上,您可以使用 IntPtr.Size 来确定要加载哪个 DLL,然后通过 p/Invoke 执行实际的 LoadLibrary。此时,您已将模块保存在内存中,您应该能够从其中 p/Invoke 函数——不应再次重新加载相同的模块名称。

不过,我认为,在我的应用程序中,我实际上让 C++ DLL 将自己注册为 COM 服务器,然后通过生成的 .NET 包装器访问它的功能——所以我不知道我是否测试过 p/Invoking直接。

【讨论】:

【参考方案3】:

不久前我遇到了类似的情况。我使用的工具包在 64 位环境中表现不佳,我无法找到动态强制程序集绑定为 32 位的方法。

可以强制您的程序集在 32 位模式下工作,但这需要修补 CLR 标头(在框架中有一个工具可以做到这一点),如果您的程序集是强命名的,这将不起作用出去。

恐怕您需要为 32 位和 64 位平台构建和发布两组二进制文件。

【讨论】:

以上是关于如何在运行时后期绑定 32 位/64 位库的主要内容,如果未能解决你的问题,请参考以下文章

无法在 64 位 ubuntu 上安装 32 位库

ubuntu64运行32位程序安装过程

在 OS X 上将 32 位二进制库包装到 64 位库

将 32 位库链接到 64 位程序

在 Java 应用程序中混合运行 32 位和 64 位本机库

为 32 位 exe 加载 32 位库时,Windows 7 64 位路径不正确