.net 在同一解决方案/项目中使用 Visual Studio 同时面向 32 位和 64 位

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/145803/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 10:07:49  来源:igfitidea点击:

Targeting both 32bit and 64bit with Visual Studio in same solution/project

.netvisual-studio64-bitx86-64

提问by Magnus Johansson

I have a little dilemma on how to set up my visual studio builds for multi-targeting.

我对如何为多目标设置我的 Visual Studio 构建有点进退两难。

Background: c# .NET v2.0 with p/invoking into 3rd party 32 bit DLL's, SQL compact v3.5 SP1, with a Setup project. Right now, the platform target is set to x86 so it can be run on Windows x64.

背景:c# .NET v2.0 与 p/invoking 到 3rd 方 32 位 DLL、SQL compact v3.5 SP1,以及一个安装项目。现在,平台目标设置为 x86,因此它可以在 Windows x64 上运行。

The 3rd party company has just released 64 bit versions of their DLL's and I want to build a dedicated 64bit program.

第 3 方公司刚刚发布了他们 DLL 的 64 位版本,我想构建一个专用的 64 位程序。

This raises some questions which I haven't got the answers to yet. I want to have the exact same code base. I must build with references to either the 32bit set of DLL's or 64bit DLL's. (Both 3rd party and SQL Server Compact)

这提出了一些我还没有得到答案的问题。我想要完全相同的代码库。我必须使用对 32 位 DLL 集或 64 位 DLL 的引用来构建。(第 3 方和 SQL Server Compact)

Can this be solved with 2 new sets of configurations (Debug64 and Release64) ?

这可以通过 2 组新配置(Debug64 和 Release64)解决吗?

Must I create 2 separate setup projects(std. visual studio projects, no Wix or any other utility), or can this be solved within the same .msi?

我必须创建 2 个单独的安装项目(std.visual studio 项目,没有 Wix 或任何其他实用程序),还是可以在同一个 .msi 中解决?

Any ideas and/or recommendations would be welcomed.

欢迎任何想法和/或建议。

采纳答案by mdb

Yes, you can target both x86 and x64 with the same code base in the same project. In general, things will Just Work if you create the right solution configurations in VS.NET (although P/Invoke to entirely unmanaged DLLs will most likely require some conditional code): the items that I found to require special attention are:

是的,您可以在同一个项目中使用相同的代码库同时面向 x86 和 x64。一般来说,如果您在 VS.NET 中创建正确的解决方案配置,事情就会正常工作(尽管 P/Invoke 到完全非托管的 DLL 很可能需要一些条件代码):我发现需要特别注意的项目是:

  • References to outside managed assemblies with the same name but their own specific bitness (this also applies to COM interop assemblies)
  • The MSI package (which, as has already been noted, will need to target either x86 or x64)
  • Any custom .NET Installer Class-based actions in your MSI package
  • 对具有相同名称但具有特定位数的外部托管程序集的引用(这也适用于 COM 互操作程序集)
  • MSI 包(如前所述,需要针对 x86 或 x64)
  • MSI 包中任何基于 .NET 安装程序类的自定义操作

The assembly reference issue can't be solved entirely within VS.NET, as it will only allow you to add a reference with a given name to a project once. To work around this, edit your project file manually (in VS, right-click your project file in the Solution Explorer, select Unload Project, then right-click again and select Edit). After adding a reference to, say, the x86 version of an assembly, your project file will contain something like:

程序集引用问题不能在 VS.NET 中完全解决,因为它只允许您向项目添加具有给定名称的引用一次。要解决此问题,请手动编辑您的项目文件(在 VS 中,在解决方案资源管理器中右键单击您的项目文件,选择卸载项目,然后再次右键单击并选择编辑)。添加对程序集的 x86 版本的引用后,您的项目文件将包含以下内容:

<Reference Include="Filename, ..., processorArchitecture=x86">
  <HintPath>C:\path\to\x86\DLL</HintPath>
</Reference>

Wrap that Reference tag inside an ItemGroup tag indicating the solution configuration it applies to, e.g:

将该 Reference 标签包裹在 ItemGroup 标签中,指示它适用的解决方案配置,例如:

<ItemGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
   <Reference ...>....</Reference>
</ItemGroup>

Then, copy and paste the entire ItemGroup tag, and edit it to contain the details of your 64-bit DLL, e.g.:

然后,复制并粘贴整个 ItemGroup 标记,并对其进行编辑以包含 64 位 DLL 的详细信息,例如:

<ItemGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
  <Reference Include="Filename, ..., processorArchitecture=AMD64">
     <HintPath>C:\path\to\x64\DLL</HintPath>
   </Reference>
</ItemGroup>

After reloading your project in VS.NET, the Assembly Reference dialog will be a bit confused by these changes, and you may encounter some warnings about assemblies with the wrong target processor, but all your builds will work just fine.

在 VS.NET 中重新加载您的项目后,“程序集参考”对话框将被这些更改弄得有些混乱,您可能会遇到一些有关使用错误目标处理器的程序集的警告,但您的所有构建都可以正常工作。

Solving the MSI issue is up next, and unfortunately this willrequire a non-VS.NET tool: I prefer Caphyon's Advanced Installerfor that purpose, as it pulls off the basic trick involved (create a common MSI, as well as 32-bit and 64-bit specific MSIs, and use an .EXE setup launcher to extract the right version and do the required fixups at runtime) very, very well.

接下来解决 MSI 问题,不幸的是,这需要一个非 VS.NET 工具:为此我更喜欢 Caphyon 的高级安装程序,因为它实现了所涉及的基本技巧(创建一个通用的 MSI,以及 32 位和 64 位特定的 MSI,并使用 .EXE 安装启动器来提取正确的版本并在运行时执行所需的修复)非常非常好。

You can probably achieve the same results using other tools or the Windows Installer XML (WiX) toolset, but Advanced Installer makes things so easy (and is quite affordable at that) that I've never really looked at alternatives.

您可能可以使用其他工具或Windows Installer XML (WiX) 工具集获得相同的结果,但 Advanced Installer 使事情变得如此简单(而且非常实惠),以至于我从未真正考虑过替代方案。

One thing you maystill require WiX for though, even when using Advanced Installer, is for your .NET Installer Class custom actions. Although it's trivial to specify certain actions that should only run on certain platforms (using the VersionNT64 and NOT VersionNT64 execution conditions, respectively), the built-in AI custom actions will be executed using the 32-bit Framework, even on 64-bit machines.

即使在使用高级安装程序时,您可能仍然需要 WiX 的一件事是用于您的 .NET 安装程序类自定义操作。虽然指定应该只在某些平台上运行的某些动作很简单(分别使用 VersionNT64 和 NOT VersionNT64 执行条件),但内置的 AI 自定义动作将使用 32 位框架执行,即使在 64 位机器上.

This may be fixed in a future release, but for now (or when using a different tool to create your MSIs that has the same issue), you can use WiX 3.0's managed custom action support to create action DLLs with the proper bitness that will be executed using the corresponding Framework.

这可能会在未来版本中修复,但就目前而言(或在使用不同工具创建具有相同问题的 MSI 时),您可以使用 WiX 3.0 的托管自定义操作支持来创建具有适当位数的操作 DLL将使用相应的框架执行。



Edit: as of version 8.1.2, Advanced Installer correctly supports 64-bit custom actions. Since my original answer, its price has increased quite a bit, unfortunately, even though it's still extremely good value when compared to InstallShield and its ilk...

编辑:从 8.1.2 版开始,高级安装程序正确支持 64 位自定义操作。不幸的是,自从我最初的回答以来,它的价格已经上涨了很多,尽管与 InstallShield 及其同类产品相比,它仍然非常物有所值......



Edit: If your DLLs are registered in the GAC, you can also use the standard reference tags this way (SQLite as an example):

编辑:如果您的 DLL 已在 GAC 中注册,您也可以通过这种方式使用标准参考标签(以 SQLite 为例):

<ItemGroup Condition="'$(Platform)' == 'x86'">
    <Reference Include="System.Data.SQLite, Version=1.0.80.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=x86" />
</ItemGroup>
<ItemGroup Condition="'$(Platform)' == 'x64'">
    <Reference Include="System.Data.SQLite, Version=1.0.80.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=AMD64" />
</ItemGroup>

The condition is also reduced down to all build types, release or debug, and just specifies the processor architecture.

该条件还简化为所有构建类型、发布或调试,并且仅指定处理器架构。

回答by Tim Booker

Let's say you have the DLLs build for both platforms, and they are in the following location:

假设您为两个平台构建了 DLL,它们位于以下位置:

C:\whatever\x86\whatever.dll
C:\whatever\x64\whatever.dll

You simply need to edit your .csproj file from this:

您只需要从这里编辑您的 .csproj 文件:

<HintPath>C:\whatever\x86\whatever.dll</HintPath>

To this:

对此:

<HintPath>C:\whatever$(Platform)\whatever.dll</HintPath>

You should then be able to build your project targeting both platforms, and MSBuild will look in the correct directory for the chosen platform.

然后,您应该能够针对两个平台构建您的项目,并且 MSBuild 将在所选平台的正确目录中查找。

回答by gleng

Not sure of the total answer to your question - but thought I would point out a comment in the Additional Information section of the SQL Compact 3.5 SP1 download pageseeing you are looking at x64 - hope it helps.

不确定您问题的完整答案 - 但我想我会在SQL Compact 3.5 SP1 下载页面的附加信息部分指出一条评论,因为看到您正在查看 x64 - 希望它有所帮助。

Due to changes in SQL Server Compact SP1 and additional 64-bit version support, centrally installed and mixed mode environments of 32-bit version of SQL Server Compact 3.5 and 64-bit version of SQL Server Compact 3.5 SP1 can create what appear to be intermittent problems. To minimize the potential for conflicts, and to enable platform neutral deployment of managed client applications, centrally installing the 64-bit version of SQL Server Compact 3.5 SP1 using the Windows Installer (MSI) file also requires installing the 32-bit version of SQL Server Compact 3.5 SP1 MSI file. For applications that only require native 64-bit, private deployment of the 64-bit version of SQL Server Compact 3.5 SP1 can be utilized.

由于 SQL Server Compact SP1 中的更改和额外的 64 位版本支持,32 位版本的 SQL Server Compact 3.5 和 64 位版本的 SQL Server Compact 3.5 SP1 的集中安装和混合模式环境可能会造成似乎是间歇性的问题。为了最大限度地减少冲突的可能性,并启用托管客户端应用程序的平台无关部署,使用 Windows 安装程序 (MSI) 文件集中安装 64 位版本的 SQL Server Compact 3.5 SP1 还需要安装 32 位版本的 SQL Server压缩 3.5 SP1 MSI 文件。对于只需要本机 64 位的应用程序,可以使用 64 位版本的 SQL Server Compact 3.5 SP1 的私有部署。

I read this as "include the 32bit SQLCE files as well asthe 64bit files" if distributing for 64bit clients.

如果分发给 64 位客户端,我将其读作“包括 32 位 SQLCE 文件以及64 位文件”。

Makes life interesting I guess.. must say that I love the "what appears to be intermittent problems" line... sounds a bit like "you are imagining things, but just in case, do this..."

让生活变得有趣我猜……必须说我喜欢“似乎是间歇性问题”这句话……听起来有点像“你在想象事情,但为了以防万一,这样做……”

回答by Felix Keil

One .Net build with x86/x64 Dependencies

一个具有 x86/x64 依赖项的 .Net 构建

While all other answers give you a solution to make different Builds according to the platform, I give you an option to only have the "AnyCPU" configuration and make a build that works with your x86 and x64 dlls.

虽然所有其他答案都为您提供了根据平台进行不同构建的解决方案,但我为您提供了一个选项,即仅具有“AnyCPU”配置并构建适用于您的 x86 和 x64 dll 的构建。

You have to write some plumbing code for this.

您必须为此编写一些管道代码。

Resolution of correct x86/x64-dlls at runtime

在运行时解析正确的 x86/x64-dll

Steps:

脚步:

  1. Use AnyCPU in csproj
  2. Decide if you only reference the x86 or the x64 dlls in your csprojs. Adapt the UnitTests settings to the architecture settings you have chosen. It's important for debugging/running the tests inside VisualStudio.
  3. On Reference-Properties set Copy Local& Specific Versionto false
  4. Get rid of the architecture warnings by adding this line to the first PropertyGroupin all of your csproj files where you reference x86/x64: <ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>None</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
  5. Add this postbuild script to your startup project, use and modify the paths of this script sp that it copies all your x86/x64 dlls in corresponding subfolders of your build bin\x86\ bin\x64\

    xcopy /E /H /R /Y /I /D $(SolutionDir)\YourPathToX86Dlls $(TargetDir)\x86 xcopy /E /H /R /Y /I /D $(SolutionDir)\YourPathToX64Dlls $(TargetDir)\x64

    --> When you would start application now, you get an exception that the assembly could not be found.

  6. Register the AssemblyResolve event right at the beginning of your application entry point

    AppDomain.CurrentDomain.AssemblyResolve += TryResolveArchitectureDependency;
    

    withthis method:

    /// <summary>
    /// Event Handler for AppDomain.CurrentDomain.AssemblyResolve
    /// </summary>
    /// <param name="sender">The app domain</param>
    /// <param name="resolveEventArgs">The resolve event args</param>
    /// <returns>The architecture dependent assembly</returns>
    public static Assembly TryResolveArchitectureDependency(object sender, ResolveEventArgs resolveEventArgs)
    {
        var dllName = resolveEventArgs.Name.Substring(0, resolveEventArgs.Name.IndexOf(","));
    
        var anyCpuAssemblyPath = $".\{dllName}.dll";
    
        var architectureName = System.Environment.Is64BitProcess ? "x64" : "x86";
    
        var assemblyPath = $".\{architectureName}\{dllName}.dll";
    
        if (File.Exists(assemblyPath))
        {
            return Assembly.LoadFrom(assemblyPath);
        }
    
        return null;
    }
    
  7. If you have unit tests make a TestClass with a Method that has an AssemblyInitializeAttribute and also register the above TryResolveArchitectureDependency-Handler there. (This won't be executed sometimes if you run single tests inside visual studio, the references will be resolved not from the UnitTest bin. Therefore the decision in step 2 is important.)
  1. 在 csproj 中使用 AnyCPU
  2. 决定在 csprojs 中是只引用 x86 还是 x64 dll。使 UnitTests 设置适应您选择的体系结构设置。在 VisualStudio 中调试/运行测试很重要。
  3. 在 Reference-Properties 上将Copy Local& Specific Version 设置false
  4. 通过将此行添加到所有引用 x86/x64 的 csproj 文件中的第一个PropertyGroup来消除架构警告: <ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>None</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
  5. 将此 postbuild 脚本添加到您的启动项目中,使用并修改此脚本 sp 的路径,它会将您的所有 x86/x64 dll 复制到您的 build bin\x86\ bin\x64\ 的相应子文件夹中

    xcopy /E /H /R /Y /I /D $(SolutionDir)\YourPathToX86Dlls $(TargetDir)\x86 xcopy /E /H /R /Y /I /D $(SolutionDir)\YourPathToX64Dlls $(TargetDir)\x64

    --> 当您现在启动应用程序时,您会收到无法找到程序集的异常。

  6. 在应用程序入口点的开头注册 AssemblyResolve 事件

    AppDomain.CurrentDomain.AssemblyResolve += TryResolveArchitectureDependency;
    

    用这种方法:

    /// <summary>
    /// Event Handler for AppDomain.CurrentDomain.AssemblyResolve
    /// </summary>
    /// <param name="sender">The app domain</param>
    /// <param name="resolveEventArgs">The resolve event args</param>
    /// <returns>The architecture dependent assembly</returns>
    public static Assembly TryResolveArchitectureDependency(object sender, ResolveEventArgs resolveEventArgs)
    {
        var dllName = resolveEventArgs.Name.Substring(0, resolveEventArgs.Name.IndexOf(","));
    
        var anyCpuAssemblyPath = $".\{dllName}.dll";
    
        var architectureName = System.Environment.Is64BitProcess ? "x64" : "x86";
    
        var assemblyPath = $".\{architectureName}\{dllName}.dll";
    
        if (File.Exists(assemblyPath))
        {
            return Assembly.LoadFrom(assemblyPath);
        }
    
        return null;
    }
    
  7. 如果您有单元测试,请使用具有 AssemblyInitializeAttribute 的方法创建一个 TestClass,并在那里注册上述 TryResolveArchitectureDependency-Handler。(如果您在 Visual Studio 中运行单个测试,有时不会执行此操作,引用将不会从 UnitTest bin 中解析。因此,步骤 2 中的决定很重要。)

Benefits:

好处:

  • One Installation/Build for both platforms
  • 两个平台的一次安装/构建

Drawbacks: - No errors at compile time when x86/x64 dlls do not match. - You should still run test in both modes!

缺点: - 当 x86/x64 dll 不匹配时,编译时不会出错。- 您仍然应该在两种模式下运行测试!

Optionally create a second executable that is exclusive for x64 architecture with Corflags.exe in postbuild script

(可选)在 postbuild 脚本中使用 Corflags.exe 创建 x64 体系结构专用的第二个可执行文件

Other Variants to try out: - You don't need the AssemblyResolve event handler if you assure that the right dlls are copied to your binary folder at start (Evaluate Process architecture -> move corresponding dlls from x64/x86 to bin folder and back.) - In Installer evaluate architecture and delete binaries for wrong architecture and move the right ones to the bin folder.

要尝试的其他变体: - 如果您确保在开始时将正确的 dll 复制到二进制文件夹,则不需要 AssemblyResolve 事件处理程序(评估进程架构 -> 将相应的 dll 从 x64/x86 移动到 bin 文件夹并返回。 ) - 在安装程序中评估架构并删除错误架构的二进制文件并将正确的二进制文件移动到 bin 文件夹。

回答by Lior Friedman

Regarding your last question. Most likely you cant solve this inside a single MSI. If you are using registry/system folders or anything related, the MSI itself must be aware of this and you must prepare a 64bit MSI to properly install on 32 bit machine.

关于你的最后一个问题。您很可能无法在单个 MSI 内解决此问题。如果您正在使用注册表/系统文件夹或任何相关内容,MSI 本身必须意识到这一点,并且您必须准备 64 位 MSI 才能在 32 位机器上正确安装。

There is a possibility that you can make you product installed as a 32 it application and still be able to make it run as 64 bit one, but i think that may be somewhat hard to achieve.

有一种可能性,您可以将产品安装为 32 位 it 应用程序,并且仍然能够使其以 64 位应用程序运行,但我认为这可能有点难以实现。

that being said i think you should be able to keep a single code base for everything. In my current work place we have managed to do so. (but it did took some juggling to make everything play together)

话虽如此,我认为您应该能够为所有内容保留一个单一的代码库。在我目前的工作场所,我们已经做到了。(但确实需要一些杂耍才能让所有东西一起玩)

Hope this helps. Heres a link to some info related to 32/64 bit issues: http://blog.typemock.com/2008/07/registry-on-windows-64-bit-double-your.html

希望这可以帮助。这是与 32/64 位问题相关的一些信息的链接:http: //blog.typemock.com/2008/07/registry-on-windows-64-bit-double-your.html

回答by Ryan

If you use Custom Actions written in .NET as part of your MSI installer then you have another problem.

如果您使用 .NET 编写的自定义操作作为 MSI 安装程序的一部分,那么您还有另一个问题。

The 'shim' that runs these custom actions is always 32bit then your custom action will run 32bit as well, despite what target you specify.

运行这些自定义操作的“垫片”始终为 32 位,那么您的自定义操作也将运行 32 位,无论您指定什么目标。

More info & some ninja moves to get around (basically change the MSI to use the 64 bit version of this shim)

更多信息和一些忍者动作(基本上更改 MSI 以使用此垫片的 64 位版本)

Building an MSI in Visual Studio 2005/2008 to work on a SharePoint 64

在 Visual Studio 2005/2008 中构建 MSI 以处理 SharePoint 64

64-bit Managed Custom Actions with Visual Studio

使用 Visual Studio 的 64 位托管自定义操作

回答by voidMainReturn

You can generate two solutions differently and merge them afterwards! I did this for VS 2010. and it works. I had 2 different solutions generated by CMake and I merged them

您可以以不同的方式生成两个解决方案,然后将它们合并!我为 VS 2010 做了这个。它有效。我有 2 个由 CMake 生成的不同解决方案并将它们合并

回答by Yochai Timmer

You can use a condition to an ItemGroupfor the dll references in the project file.
This will cause visual studio to recheck the condition and references whenever you change the active configuration.
Just add a condition for each configuration.

您可以将条件用于项目文件中的 dll 引用的ItemGroup
这将导致 Visual Studio 在您更改活动配置时重新检查条件和引用。
只需为每个配置添加一个条件。

Example:

例子:

 <ItemGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
    <Reference Include="DLLName">
      <HintPath>..\DLLName.dll</HintPath>
    </Reference>
    <ProjectReference Include="..\MyOtherProject.vcxproj">
      <Project>{AAAAAA-000000-BBBB-CCCC-TTTTTTTTTT}</Project>
      <Name>MyOtherProject</Name>
    </ProjectReference>
  </ItemGroup>