web-dev-qa-db-ja.com

C ++ / C#ソリューションで使用できないCPU

C#とマネージC++プロジェクトを含むソリューションがあります。ソリューションプラットフォームx64およびx86でコンパイルされます。 C++で管理されているので、「任意のCPU」ソリューションを作成して、古いソリューションを削除したいと思いました。

C++プロジェクトのリンカー設定をx64とx86の両方でForceSafe ILImageに変更しました。

次に、Configuration Managerを使用して、「AnyCPU」という新しいソリューションプラットフォームを作成しました。次に、「AnyCPU」とも呼ばれるプロジェクトプラットフォームを追加しました。

すべてのC#プロジェクトを「任意のCPU」に設定しましたが、C++の場合はそれができません。プロジェクトプラットフォーム「AnyCPU」はドロップダウンになく、オプション「New ...」もありません。

VSはそれについて熱心に取り組んでいるので、私はそれをそのままにしてビルドを開始しました。驚いたことに、C++のプラットフォームがx64であったとしても、結果DLL(C++プロジェクトから)はMSILでした。x32をコンパイルするときにも同じことが起こり、結果はDLL MSILにあります。

何が得られますか? C++プロジェクトを「任意のCPU」に設定できないのはなぜですか?

17
Frank Kaaijk

私の知る限り、C++/CLIプロジェクト用にVisualStudioで「AnyCPU」プロジェクトタイプを作成することはできません。ただし、canC++/CLIプロジェクト(「Win32」プロジェクトタイプの下)を構成して、ターゲットなしで純粋で安全なMSILとしてコンパイルすることができます。プラットホーム。そうすることで、C++/CLI DLLアセンブリを「AnyCPU」C#プロジェクトで使用できるようになります。つまり、構成マネージャーでの実際の名前ではありませんが、事実上「AnyCPU」になります。

「C/C++」プロジェクト設定の場合:

  • 共通言語ランタイムのサポート:Safe MSIL Common Language RunTime Support (/clr:safe)

「リンカー」プロジェクト設定:

  • CLRイメージタイプ:これがIJWまたはPUREに明示的に設定されていないことを確認してください

ノート:

  • 「安全な」プロジェクトタイプを使用することにより、プラットフォームタイプに影響を与えると思われるコンパイラとリンカーのオプションのいくつかは無視されます。つまりすべてを特定されていないプラットフォームタイプに設定する必要はありません。ちょうど上記。ただし、気分が良くなる場合は、他のオプションを適切なものに設定できます。 :)
  • 「安全」はポインタの使用を防ぎます。これが重要な問題である場合、より複雑なプロセスではありますが、明らかに可能です。詳細については、 C++/CLIプロジェクトから純粋なMSILアセンブリを作成しますか? を参照してください。
  • デフォルトでは、Visual Studioは「AnyCPU」であり、64ビットOSで実行されていても、32ビットプロセスとして起動するC#プロジェクトを作成することを忘れないでください。依存関係が意図したとおり純粋で安全なMSILではなくx86である場合、これによりプラットフォームの不一致の問題を隠すことができます。注意すべき点があります(これは、C#プロジェクトの[ビルド]プロジェクトのプロパティページで[32ビットを優先する]オプションをオフにすることで制御できます)。
14
Peter Duniho

C++機能をC#dllで使用するには、C++プロジェクトでx86バージョンとx64バージョンの両方のdllを生成する必要があります。 AnyCPU設定でコンパイルされたC#dllからx86またはx64dllだけを参照することはできません。

AnyCPUdllをC++ dllで再生するための秘訣は、実行時に、アセンブリがC++ dllをロードできないことを確認してから、AppDomainAssemblyResolveイベントをサブスクライブすることです。アセンブリが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;
}

AnyCPUdllからC++機能にアクセスする方法を示す簡単なプロジェクトを作成しました。

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

6
Kevin Marshall