任何 CPU 在 C++/C# 解决方案中不可用

Any CPU not available in C++/C# solution

我有一个包含 C# 和托管 C++ 项目的解决方案。 它在解决方案平台 x64 和 x86 中编译。由于它是托管 C++,我想创建一个 'Any CPU' 解决方案并摆脱旧的解决方案。

我将 C++ 项目链接器设置更改为适用于 x64 和 x86 的 Force Safe IL Image。

接下来,我使用配置管理器创建了一个名为 'Any CPU' 的新解决方案平台。接下来我添加了一个项目平台也叫'Any CPU'。

我继续将所有 C# 项目设置为 'Any CPU',但对于 C++,我不能这样做。项目平台 'Any CPU' 不在下拉列表中,也没有选项 'New...'.

VS 对其进行了改进,所以我保持原样并开始构建。令我惊讶的是,尽管 C++ 的平台是 x64,但结果 DLL(来自 C++ 项目)是 MSIL。编译 x32 时也会发生同样的情况,生成的 DLL 在 MSIL 中。

什么给了? 为什么我不能将 C++ 项目设置为 'Any CPU'?

据我所知,您无法在 Visual Studio 中为 C++/CLI 项目创建 "AnyCPU" 项目类型。但是,您 可以 配置您的 C++/CLI 项目(在 "Win32" 项目类型下),以便它编译为纯净、安全的 MSIL,而无需目标平台。这样做将允许您的 C++/CLI DLL 程序集与 "AnyCPU" C# 项目一起使用。 IE。它实际上是 "AnyCPU",即使这不是它在配置管理器中的实际名称。

在"C/C++"项目设置中:

  • 公共语言运行时支持:Safe MSIL Common Language RunTime Support (/clr:safe)

在"Linker"项目设置中:

  • CLR 图像类型:只需确保未将其明确设置为 IJWPURE

备注:

  • 通过使用 "safe" 项目类型,一些似乎影响平台类型的编译器和链接器选项将被忽略。 IE。您不必将 everything 设置为非特定平台类型。仅以上。但您可以将其他选项设置为适当的值,如果这会让您感觉更好的话。 :)
  • "Safe" 将阻止使用指针。如果这是一个重要问题,显然可以通过更复杂的过程来解决。有关详细信息,请参阅 Creating a pure MSIL assembly from a C++/CLI project?
  • 不要忘记,默认情况下,Visual Studio 将创建 C# 项目,即使它们是 "AnyCPU" 并且即使它们在 64 位 OS 上执行,也会作为 32 位进程启动。如果依赖项是 x86 而不是预期的 pure/safe MSIL,这可以隐藏平台不匹配问题。请注意(您可以通过取消选中 C# 项目的 "Build" 项目属性页面中的 "Prefer 32-bit" 选项来控制这一点)。

为了让 C# dll 使用 C++ 功能,C++ 项目必须生成 dll 的 x86 和 x64 版本。无法从使用 AnyCPU 设置编译的 C# dll 中仅引用 x86 或 x64 dll。

让 AnyCPU 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.LoadFile(assembly_directory + @"\x64\" + assembly_dll);
     }
     else
     {
            assembly = Assembly.LoadFile(assembly_directory + @"\x86\" + assembly_dll);
     }
     return assembly;
}

我创建了一个简单的项目来演示如何从 AnyCPU dll 访问 C++ 功能。

https://github.com/kevin-marshall/Managed.AnyCPU