托管C++和AnyCPU

8

我有一个托管的C++ dll,我正在从一个C#项目中引用它。该C#项目将被编译为AnyCPU。是否有办法编译32位和64位版本的托管C++ dll,然后在运行时告诉C#项目加载正确的版本,取决于它正在运行的架构?

2个回答

3
任意CPU dll与C++ dll配合的技巧在于,在运行时确保程序集无法加载C++ dll,然后订阅AppDomain AssemblyResolve事件。当程序集尝试加载dll并失败时,您的代码就有机会确定需要加载哪个dll。
订阅该事件的方式如下:
System.AppDomain.CurrentDomain.AssemblyResolve += Resolver;

事件处理程序看起来像这样:

System.Reflection.Assembly Resolver(object sender, System.ResolveEventArgs args)
{
     string assembly_dll = new AssemblyName(args.Name).Name + ".dll";
     string assembly_directory = "Parent directory of the C++ dlls";

     Assembly assembly = null;
     if(Environment.Is64BitProcess)
     {
            assembly = Assembly.LoadFrom(assembly_directory + @"\x64\" + assembly_dll);
     }
     else
     {
            assembly = Assembly.LoadFrom(assembly_directory + @"\x86\" + assembly_dll);
     }
     return assembly;
}

我创建了一个简单的项目,演示如何从一个AnyCPU dll中访问C++功能。 https://github.com/kevin-marshall/Managed.AnyCPU

我也是。我不确定我是否会在生产中这样做,但这至少是一个可行的想法。点赞回到零以恢复公正。 - Ivan Krivyakov
谢谢Ivan!我很感激你的支持 :) - Kevin Marshall
谢谢Ivan的评论。我一直在思考你说的话,不要在生产中这样做。所以我在这里尝试学习:)你评论的来源是关于安全性吗?我确实意识到这是一个hack,但据我所知,这是我知道如何支持C#的AnyCPU声明的少数几种方法之一。我所知道的唯一其他方法是使用PInvoke,我认为它也存在同样的问题。我正在意识到正确的方法是在安装时解决问题。 - Kevin Marshall
1
在生产应用中使用程序集解析器来加载依赖项意味着必须将自定义依赖项解析逻辑添加到与您的代码一起工作的每个工具中:单元测试框架、覆盖工具等。否则,它们将无法找到所有所需的程序集。这个问题一开始可能看起来不是很大的问题,但很快就会变得非常烦人。我曾经为一家公司工作,他们整个库版本控制方案基于自定义程序集解析器;他们为此苦苦挣扎了几年,最后放弃,恢复到标准的.NET程序集加载。 - Ivan Krivyakov
汇编解析器封装在AnyCPU.dll中,因此所有客户端代码直接依赖于仅AnyCPU.dll接口。如果您查看我提供的源代码,将发现在AnyCPU.Test.Develop或AnyCPU.Test.Distribute中没有程序集解析代码。如果单元测试需要解析器代码,则说明正在测试的代码的依赖关系未完全封装,无法与客户端隔离开来。 - Kevin Marshall
显示剩余4条评论

1
我不知道你是如何“引用”C++ dll的(P/Invoke vs .net assembly reference),但无论哪种方式,你都可以在安装时交换两个版本的.dll文件。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接