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

时间:2020-03-05 18:42:00  来源:igfitidea点击:

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

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

现在说我们的客户有一个.NET应用程序,它可以是32位或者64位,并且它是一个纯净的.NET应用程序,它使CLR可以从一组程序集中进行处理。问题是应用程序代码如何在运行时动态地在32位和64位CLR / DLL组合之间进行选择?

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

解决方案

回答

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

可以强制程序集以32位模式工作,但这需要修补CLR标头(在Framework中有一个工具可以对此进行修补),并且如果程序集是强命名的,则无法解决。

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

回答

我大约一年前就可以做到这一点,但我不再记得所有细节。基本上,可以使用IntPtr.Size确定要加载的DLL,然后通过p / Invoke执行实际的LoadLibrary。到那时,我们已经将该模块存储在内存中,并且应该应该只能从其内部p / Invoke函数-相同的模块名称不应再次重新加载。

不过,我认为,在我的应用程序中,我实际上已经将C ++ DLL自身注册为COM服务器,然后通过生成的.NET包装器访问其功能-因此,我不知道是否直接测试了p / Invoking。

回答

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

将托管和非托管的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和普通应用程序,以及另一个切换应用程序,该应用程序选择要加载的位。
请注意,我自己对此的细节无法赞誉。我的一位同事怀疑这是我的初衷。如果并且当他注册了StackOverflow时,我会为他分配答案