同じソリューション/プロジェクトのVisual Studioで32ビットと64ビットの両方を対象とする


111

マルチターゲティング用にVisual Studioビルドを設定する方法について少しジレンマがあります。

背景:c#.NET v2.0とサードパーティの32ビットDLLへのp / invoking、SQLコンパクトv3.5 SP1、セットアッププロジェクト。現在、プラットフォームターゲットはx86に設定されているため、Windows x64で実行できます。

サードパーティ企業がDLLの64ビットバージョンをリリースしたばかりで、専用の64ビットプログラムを構築したいと考えています。

これは私がまだ答えを持っていないいくつかの質問を提起します。まったく同じコードベースが必要です。DLLの32ビットセットまたは64ビットDLLへの参照を使用してビルドする必要があります。(サードパーティとSQL Server Compactの両方)

これは、2つの新しい構成セット(Debug64とRelease64)で解決できますか?

2つの個別のセットアッププロジェクト(標準ビジュアルスタジオプロジェクト、Wixまたはその他のユーティリティなし)を作成する必要がありますか、それとも同じ.msi内で解決できますか?

任意のアイデアや推奨事項を歓迎します。


@Magnus Johansson:2つの構成を使用して目標の半分を達成できます。MSIは少し難しいです。
user7116 2008

回答:


83

はい、x86とx64の両方を同じプロジェクトの同じコードベースでターゲットにできます。一般に、VS.NETで適切なソリューション構成を作成すれば、問題なく機能します(完全に管理されていないDLLへのP / Invokeには、いくつかの条件付きコードが必要になる可能性が最も高いです)。

  • 同じ名前で独自の特定のビット数を持つ外部マネージアセンブリへの参照(これはCOM相互運用機能アセンブリにも適用されます)
  • MSIパッケージ(既に述べたように、x86またはx64のいずれかをターゲットにする必要があります)
  • MSIパッケージ内のカスタム.NETインストーラークラスベースのアクション

アセンブリ参照の問題は、特定の名前の参照をプロジェクトに一度だけ追加できるため、VS.NET内で完全に解決することはできません。これを回避するには、プロジェクトファイルを手動で編集します(VSでは、ソリューションエクスプローラーでプロジェクトファイルを右クリックし、[プロジェクトのアンロード]を選択してから、もう一度右クリックして[編集]を選択します)。たとえば、x86バージョンのアセンブリへの参照を追加すると、プロジェクトファイルには次のようなものが含まれます。

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

適用するソリューション構成を示すItemGroupタグ内にそのReferenceタグをラップします。例:

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

VS.NETでプロジェクトをリロードした後、これらの変更によって[アセンブリ参照]ダイアログが少し混乱し、間違ったターゲットプロセッサを使用したアセンブリに関する警告が表示される場合がありますが、すべてのビルドは正常に機能します。

MSIの問題の解決は次の段階です、残念ながらこれは非VS.NETツール必要になります。そのためには、CaphyonのAdvanced Installerが好まれます。および64ビット固有のMSI、および.EXEセットアップランチャーを使用して適切なバージョンを抽出し、実行時に必要な修正を行います)。

おそらく他のツールやWindowsインストーラーXML(WiX)ツールセットを使用しても同じ結果を得ることができますが、高度なインストーラーによって物事が非常に簡単になり(しかも非常に手頃な価格で)、他の方法を検討したことがありません。

ただし、高度なインストーラーを使用する場合でもWiXが必要な場合があるのは、.NETインストーラークラスのカスタムアクション用です。特定のプラットフォームでのみ実行する必要がある特定のアクションを指定するのは簡単です(それぞれ、VersionNT64およびNOT VersionNT64実行条件を使用)、組み込みのAIカスタムアクションは、64ビットマシンでも、32ビットフレームワークを使用して実行されます。

これは将来のリリースで修正される可能性がありますが、今のところ(または別のツールを使用して同じ問題のあるMSIを作成する場合)、WiX 3.0のマネージカスタムアクションサポートを使用して、適切なビット数のアクションDLLを作成できます対応するフレームワークを使用して実行されます。


編集:バージョン8.1.2以降、アドバンストインストーラーは64ビットのカスタムアクションを正しくサポートしています。私の元の回答以来、InstallShieldやそのilkと比較するとまだ非常に良い値ですが、残念ながらその価格はかなり高くなっています...


編集: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>

条件は、すべてのビルドタイプ、リリースまたはデバッグにまで縮小され、プロセッサアーキテクチャを指定するだけです。


Visual Studio 2008では、<ItemGroup>をネストできないことがわかりました。グループの下の新しい<ItemGroup>を残りの<Reference>にすると、このソリューションは問題なく機能しました。また、x86をAnyCPUに変更する必要がありました。これは、おそらく私の特定のプロジェクトの履歴に関連しています。
Oliver Bock

その高度なインストーラーはかなり素晴らしいです。
Pat

これは馬鹿げた質問かもしれませんが、手動でファイルを編集するにはどうすればよいですか?
HRH

1
VS内でファイルを編集するには、ソリューションエクスプローラーでプロジェクトを右クリックし、[プロジェクトのアンロード]を見つけます。プロジェクトがアンロードされたら、もう一度右クリックして、[<プロジェクトファイル名>の編集]をクリックします。プロジェクトファイルを編集したら、保存してプロジェクトファイルをもう一度右クリックし、ロードします。タイプミスやエラーがない場合は、再度読み込まれます。そうでない場合、VSはファイルの問題がほとんど何であるかを教えてくれます。お役に立てば幸いです。
John Baughman、2012年

正解です。ありがとうございました!
John Baughman、2012年

27

両方のプラットフォーム用の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は選択されたプラットフォームの正しいディレクトリを調べます。


これはうまくいけば素晴らしいでしょうが、うまくいきません。少なくとも私にとっては。
John Sheehan

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

私にとってはVisual Studio 2008で問題なく動作しましたが、通常の<Reference>とは異なり、DLLをビルドターゲットディレクトリに自動的にコピーしませんでした。mdbのソリューションの方がうまくいきました。
Oliver Bock

1

あなたの質問に対する完全な答えはわかりません-しかし、SQL Compact 3.5 SP1ダウンロードページの「追加情報」セクションにあるコメントを指摘して、x64が表示されていることを確認したいと思います。

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のプライベート展開を利用できます。

64ビットクライアントに配布する場合は、「32ビットSQLCEファイル 64ビットファイルを含める」と読みます。

人生を面白くしていると思います。「断続的な問題のように見えるもの」の行が好きだと言わなければなりません...「何かを想像しているのですが、念のために、これを行ってください...」


1

x86 / x64依存関係を持つ1つの.Netビルド

他のすべての答えは、プラットフォームに応じて異なるビルドを作成するためのソリューションを提供しますが、「AnyCPU」構成のみを使用して、x86およびx64 dllで動作するビルドを作成するオプションを提供します。

このためにいくつかの配管コードを記述する必要があります。

実行時の正しいx86 / x64-dllの解決

手順:

  1. csprojでAnyCPUを使用する
  2. csprojsでx86またはx64 dllのみを参照するかどうかを決定します。UnitTests設定を選択したアーキテクチャ設定に適合させます。VisualStudio内でテストをデバッグ/実行するために重要です。
  3. Reference-PropertiesでCopy LocalSpecific Versionfalseに設定します
  4. x86 / x64を参照するすべてのcsprojファイルの最初のPropertyGroupに次の行を追加して、アーキテクチャの警告を取り除きます。 <ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>None</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
  5. このポストビルドスクリプトをスタートアッププロジェクトに追加し、このスクリプトspのパスを使用および変更して、ビルドbin \ x86 \ bin \ x64 \の対応するサブフォルダーにすべてのx86 / x64 dllをコピーします

    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ビンからではなく解決されるため、ステップ2の決定が重要です。)

利点:

  • 両方のプラットフォームに1つのインストール/ビルド

欠点:-x86 / x64 dllが一致しない場合、コンパイル時にエラーが発生しません。-両方のモードでテストを実行する必要があります!

オプションで、ポストビルドスクリプトのCorflags.exeを使用して、x64アーキテクチャ専用の2番目の実行可能ファイルを作成します

試してみるその他のバリアント:-正しいDLLが開始時にバイナリフォルダーに確実にコピーされる場合は、AssemblyResolveイベントハンドラーは必要ありません(プロセスアーキテクチャの評価->対応するDLLをx64 / x86から​​binフォルダーに移動してから戻します。 )-インストーラーでアーキテクチャを評価し、誤ったアーキテクチャのバイナリを削除し、正しいものをbinフォルダーに移動します。


0

あなたの最後の質問について。ほとんどの場合、これを単一のMSI内で解決することはできません。レジストリ/システムフォルダまたは関連するものを使用している場合、MSI自体がこれを認識している必要があり、64ビットMSIを準備して32ビットマシンに適切にインストールする必要があります。

製品を32 itアプリケーションとしてインストールしても、64ビットアプリケーションとして実行できる可能性がありますが、それは少し難しいかもしれません。

言われていることは、すべてに対して単一のコードベースを維持できるはずだと思います。私の現在の職場では、なんとかそうすることができました。(しかし、すべてを一緒にプレイさせるために、いくつかのジャグリングが必要でした)

お役に立てれば。32/64ビットの問題に関連するいくつかの情報へのリンクを次に示します。http: //blog.typemock.com/2008/07/registry-on-windows-64-bit-double-your.html


0

MSIインストーラーの一部として.NETで記述されたカスタムアクションを使用する場合は、別の問題があります。

これらのカスタムアクションを実行する「シム」は常に32ビットであり、指定したターゲットに関係なく、カスタムアクションも32ビットで実行されます。

詳細と忍者の動きを回避する(基本的に、MSIを変更して、このシムの64ビットバージョンを使用する)

SharePoint 64で動作するようにVisual Studio 2005/2008でMSIを構築する

Visual Studioによる64ビットのマネージカスタムアクション


0

2つのソリューションを別々に生成し、後でマージすることができます!私はVS 2010でこれを行いました。CMakeによって生成された2つの異なるソリューションがあり、それらをマージしました


0

プロジェクトファイル内のdll参照のItemGroupに条件を使用できます。
これにより、アクティブな構成を変更するたびに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>
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.