C# 如何在运行时延迟绑定 32 位/64 位库
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/22322/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to late bind 32bit/64 bit libs at runtime
提问by Greg Whitfield
I've got a problem similar to,but subtly different from, that described here(Loading assemblies and their dependencies).
我遇到了一个与此处描述的问题(加载程序集及其依赖项)类似但略有不同的问题。
I have a C++ DLL for 3D rendering that is what we sell to customers. For .NET users we will have a CLR wrapper around it. The C++ DLL can be built in both 32 and 64bit versions, but I think this means we need to have two CLR wrappers since the CLR binds to a specific DLL?
我有一个用于 3D 渲染的 C++ DLL,这是我们卖给客户的。对于 .NET 用户,我们将有一个 CLR 包装器围绕它。C++ DLL 可以在 32 位和 64 位版本中构建,但我认为这意味着我们需要有两个 CLR 包装器,因为 CLR 绑定到特定的 DLL?
Say now our customer has a .NET app that can be either 32 or 64bit, and that it being a pure .NET app it leaves the CLR to work it out from a single set of assemblies. The question is how can the app code dynamically choose between our 32 and 64bit CLR/DLL combinations at run-time?
现在假设我们的客户有一个 .NET 应用程序,它可以是 32 位或 64 位,并且它是一个纯 .NET 应用程序,它让 CLR 从一组程序集计算出来。问题是应用程序代码如何在运行时在我们的 32 位和 64 位 CLR/DLL 组合之间动态选择?
Even more specifically, is the suggested answer to the aforementioned question applicable here too (i.e. create a ResolveEvent handler)?
更具体地说,上述问题的建议答案是否也适用于此处(即创建 ResolveEvent 处理程序)?
采纳答案by Greg Whitfield
I finally have an answer for this that appears to work.
我终于有了一个似乎有效的答案。
Compile both 32 & 64 bit versions - both managed & unmanaged - into separate folders. Then have the .NET app choose at run time which directory to load the assemblies from.
将 32 位和 64 位版本(托管和非托管)编译到单独的文件夹中。然后让 .NET 应用程序在运行时选择从哪个目录加载程序集。
The problem with using the ResolveEvent is that it only gets called if assemblies aren't found, so it is all to easy to accidentally end up with 32 bit versions. Instead use a second AppDomain object where we can change the ApplicationBase property to point at the right folder. So you end up with code like:
使用 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);
}
You end up with 2 exes - your normal app and a second switching app that chooses which bits to load. Note - I can't take credit for the details of this myself. One of my colleagues sussed that out given my initial pointer. If and when he signs up to StackOverflow I'll assign the answer to him
您最终会得到 2 个 exe - 您的普通应用程序和第二个切换应用程序,用于选择要加载的位。注意 - 我自己不能相信这个细节。我的一位同事给出了我的初步建议。如果他注册 StackOverflow,我会把答案分配给他
回答by Ishmaeel
I encountered a similar scenario a while back. A toolkit I was using did not behave well in a 64-bit environment and I wasn't able to find a way to dynamically force the assemblies to bind as 32 bit.
不久前我遇到了类似的情况。我使用的工具包在 64 位环境中表现不佳,我无法找到一种方法来动态强制程序集绑定为 32 位。
It is possible to force your assemblies to work in 32 bit mode, but this requires patching the CLR header, (there is a tool that does that in the Framework) and if your assemblies are strongly-named, this does not work out.
可以强制您的程序集在 32 位模式下工作,但这需要修补 CLR 标头,(框架中有一个工具可以做到这一点),如果您的程序集是强命名的,这将不起作用。
I'm afraid you'll need to build and publish two sets of binaries for 32 and 64 bit platforms.
恐怕您需要为 32 位和 64 位平台构建和发布两组二进制文件。
回答by Curt Hagenlocher
I was able to do this about a year ago, but I no longer remember all of the details. Basically, you can use IntPtr.Size to determine which DLL to load, then perform the actual LoadLibrary through p/Invoke. At that point, you've got the module in memory and you ought to be able to just p/Invoke functions from inside of it -- the same module name shouldn't get reloaded again.
大约一年前我能够做到这一点,但我不再记得所有的细节。基本上,您可以使用 IntPtr.Size 来确定加载哪个 DLL,然后通过 p/Invoke 执行实际的 LoadLibrary。那时,您已经在内存中获得了该模块,并且您应该能够从它内部调用/调用函数——不应再次重新加载相同的模块名称。
I think, though, that in my application I actually had the C++ DLL register itself as a COM server and then accessed its functionality through a generated .NET wrapper -- so I don't know if I ever tested p/Invoking directly.
不过,我认为,在我的应用程序中,我实际上让 C++ DLL 将自身注册为 COM 服务器,然后通过生成的 .NET 包装器访问其功能——所以我不知道我是否曾经直接测试过 p/Invoking。