在同一个解决方案/项目中使用 VisualStudio 同时瞄准32位和64位

对于如何为多目标设置我的视觉工作室构建,我有一个小小的进退两难的问题。

背景: c # . NET v2.0,p/调用第三方32位 DLL,SQL 精简版 v3.5 SP1,带有安装项目。 现在,平台目标设置为 x86,因此可以在 Windowsx64上运行。

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

这提出了一些问题,我还没有得到答案。 我想要一模一样的代码库。 我必须用32位 DLL 或64位 DLL 的引用来构建。 (第三方和 SQLServerCompact1)

这可以通过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?

任何想法和/或建议都将受到欢迎。

106604 次浏览

不知道你的问题的总体答案-但认为我会指出一个评论在 SQL Compact3.5 SP1下载页的附加信息部分看到你正在看 x64-希望它有所帮助。

由于 SQLServerCompact2.0中的更改 SP1 and additional 64-bit version 集中安装和混合支架 模式环境的32位版本 SQL Server Compact3.5和64位 SQL Server Compact3.5 SP1版本 可以创造出看起来像是 间歇性问题 potential for conflicts, and to enable 与平台无关的托管部署 客户端应用程序,集中 安装64位版本的 SQL 服务器 Compact3.5 SP1使用 Windows Installer (MSI)档案 需要安装32位版本 的 SQL Server Compact3.5 SP1 MSI 只适用于 需要本地64位,私有 部署64位版本的 SQL Server Compact3.5 SP1可以是 利用。

如果分发给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..."

Regarding your last question. Most likely you cant solve this inside a single MSI. 如果您正在使用注册表/系统文件夹或任何相关的东西,MSI 本身必须意识到这一点,您必须准备一个64位 MSI 正确安装在32位机器上。

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

也就是说,我认为你应该,能够保持一个单一的代码基础的一切。在我目前的工作场所,我们设法做到了这一点。(但是要让所有的东西都在一起,确实需要一些变戏法)

希望这个能帮上忙。 这里有一个关于32/64位问题的链接: Http://blog.typemock.com/2008/07/registry-on-windows-64-bit-double-your.html

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

  • References to outside managed assemblies with the same name but their own specific bitness (this also applies to COM interop assemblies)
  • MSI 包(如前所述,它将需要以 x86或 x64为目标)
  • MSI 包中的任何基于.NET 安装程序类的自定义操作

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

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

将 Reference 标记包装在 ItemGroup 标记中,指示它所应用的解决方案配置,例如:

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

然后,复制并粘贴整个 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.

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

你也许可以使用其他工具或者 Windows Installer XML (wiX)工具集来达到同样的效果,但是高级安装程序使事情变得如此简单(并且是相当实惠的) ,以至于我从来没有真正地去寻找替代品。

One thing you still 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.

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.


编辑: 从版本8.1.2开始,高级安装程序正确地支持64位自定义操作。自从我最初的回答,它的价格已经增加了相当多,不幸的是,即使它仍然是非常好的价值相比,安装盾牌和类似..。


编辑: 如果您的 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>

该条件还可以简化为所有构建类型、发布或调试,并且只指定处理器体系结构。

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

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

你只需要编辑你的.csproj 文件:

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

这样说:

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

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

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

运行这些自定义操作的“垫片”总是32位,那么不管你指定的目标是什么,你的自定义操作也将运行32位。

更多的信息和一些忍者动作得到(基本上改变微星使用64位版本的这垫片)

在 VisualStudio2005/2008中生成用于 SharePoint64的 MSI

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

You can generate two solutions differently and merge them afterwards! 我为 VS 2010做了这个。而且成功了。我有两个不同的解决方案生成的 CMake 和我合并他们

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

例如:

 <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>

使用 x86/x64依赖项的.Net 构建

虽然所有其他答案都提供了根据平台进行不同构建的解决方案,但是我给出的选项是只使用“ AnyCPU”配置并进行与 x86和 x64 dls 一起工作的构建。

You have to write some plumbing code for this.

Resolution of correct x86/x64-dlls at runtime

步骤:

  1. 在 csproj 中使用 AnyCPU
  2. 决定是否只引用 csprojs 中的 x86或 x64 dls。使 UnitTest 设置适应您选择的体系结构设置。在 VisualStudio 中调试/运行测试非常重要。
  3. 关于引用属性将 收到具体版本设置为 false
  4. 通过将这一行添加到所有引用 x86/x64的 csproj 文件中的第一个 PropertyGroup,可以消除体系结构警告: <ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>None</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
  5. 将这个 postbuild 脚本添加到您的启动项目中,使用并修改这个脚本 sp 的路径,使其将所有 x86/x64 dls 复制到相应的子文件夹中

    Xcopy/E/H/R/Y/I/D $(SolutionDir) YourPathToX86Dllls $(TargetDir) x86 Xcopy/E/H/R/Y/I/D $(SolutionDir) YourPathToX64Dllls $(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. 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.)

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!

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

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.