Visual Studio 2019 以降、 C++/CLI プロジェクト は .NET をターゲットにすることができます。 このサポートにより、C++/CLI 相互運用レイヤーを使用して Windows デスクトップ アプリケーションを .NET Framework から .NET に移植できます。 この記事では、C++/CLI プロジェクトを .NET Framework から .NET に移植する方法について説明します。
C++/CLI .NET Core の制限事項
C++/CLI プロジェクトと .NET には、.NET Framework と比較して、いくつかの重要な制限事項があります。
- C++/CLI プロジェクトの実行可能ファイルへのコンパイルはサポートされていません。 DLL にコンパイルする必要があります。
- .NET の C++/CLI サポートは Windows のみです。
- C++/CLI プロジェクトは 、.NET Standard をターゲットにすることはできません。
- C++/CLI プロジェクトでは、新しい SDK スタイルのプロジェクト ファイル形式はサポートされていません。 代わりに、C++/CLI プロジェクトでは、他の Visual Studio C++ プロジェクトで使用されるのと同じ .vcxproj ファイル形式が使用されます。
- C++/CLI プロジェクトは、複数の .NET プラットフォームをターゲットにすることはできません。 .NET と .NET Framework の両方の C++/CLI プロジェクトをビルドする必要がある場合は、個別のプロジェクト ファイルを使用します。
- .NET では、
-clr:pure
または-clr:safe
コンパイルはサポートされていません。新しい-clr:netcore
オプション (.NET Framework の-clr
と同等です)。
C++/CLI プロジェクトの移植
C++/CLI プロジェクトを .NET に移植するには、 .vcxproj ファイルに次の変更を加えます。 C++/CLI プロジェクトでは SDK スタイルのプロジェクト ファイルが使用されないため、これらの移行手順は、他のプロジェクトの種類に必要な手順とは異なります。
-
<CLRSupport>true</CLRSupport>
プロパティを<CLRSupport>NetCore</CLRSupport>
に置き換えます。 多くの場合、このプロパティは構成固有のプロパティ グループに含まれているため、複数の場所で置き換える必要がある場合があります。 -
<TargetFrameworkVersion>
プロパティを<TargetFramework>net8.0</TargetFramework>
に置き換えます。 必ずタグと値を変更してください。 -
System
など、System.Data
、System.Windows.Forms
、System.Xml
、<Reference Include="System" />
への .NET Framework 参照をすべて削除します。<CLRSupport>NetCore</CLRSupport>
を使用すると、.NET SDK アセンブリが自動的に参照されます。 - 必要に応じて 、.cpp ファイル内の API の使用状況を更新して、.NET で使用できない API を削除します。 C++/CLI プロジェクトは非常に薄い相互運用レイヤーになる傾向があるため、多くの場合、多くの変更は必要ありません。 .NET Portability Analyzer を使用して、C++/CLI バイナリで使用されているサポートされていない .NET API を特定できます。
- プロジェクトが実行可能ファイルである場合は、次の手順を実行します。
- プロジェクトの種類をライブラリに変更します。
- 新しい .NET 実行可能プロジェクトを作成します。
- .NET 実行可能ファイル プロジェクトで、C++/CLI .NET ライブラリの参照を追加します。
WPF フォームと Windows フォームの使用方法
.NET C++/CLI プロジェクトでは、Windows フォームと WPF API を使用できます。 これらの Windows デスクトップ API を使用するには、UI ライブラリに明示的なフレームワーク参照を追加する必要があります。 Windows デスクトップ API を使用する SDK スタイルのプロジェクトでは、 Microsoft.NET.Sdk.WindowsDesktop
SDK を使用して必要なフレームワーク ライブラリが自動的に参照されます。 C++/CLI プロジェクトは SDK スタイルのプロジェクト形式を使用しないため、.NET Core を対象とする場合は、明示的なフレームワーク参照を追加する必要があります。
Windows フォーム API を使用するには、次の参照を .vcxproj ファイルに追加します。
<!-- Reference all of Windows Forms -->
<FrameworkReference Include="Microsoft.WindowsDesktop.App.WindowsForms" />
WPF API を使用するには、次の参照を .vcxproj ファイルに追加します。
<!-- Reference all of WPF -->
<FrameworkReference Include="Microsoft.WindowsDesktop.App.WPF" />
Windows フォームと WPF API の両方を使用するには、次の参照を .vcxproj ファイルに追加します。
<!-- Reference the entirety of the Windows desktop framework:
Windows Forms, WPF, and the types that provide integration between them -->
<FrameworkReference Include="Microsoft.WindowsDesktop.App" />
現時点では、Visual Studio の参照マネージャーを使用してこれらの参照を追加することはできません。 代わりに、プロジェクト ファイルを手動で編集して更新します。 Visual Studio では、最初にプロジェクトをアンロードする必要があります。 Visual Studio Code などの別のエディターを使用することもできます。
MSBuild を使用せずにビルドする
MSBuild を使用せずに C++/CLI プロジェクトをビルドすることもできます。 cl.exe とlink.exeを使用して.NET Core 用の C++/CLI プロジェクトを直接ビルドするには、次の手順に従います。
コンパイルするときは、cl.exeに
-clr:netcore
を渡します。必要な .NET 参照アセンブリを参照します。
リンクする場合は、.NET アプリのホスト ディレクトリを
LibPath
として指定して、 ijwhost.lib を見つけることができます。.NET アプリのホスト ディレクトリからプロジェクト の出力ディレクトリにijwhost.dllをコピーします。
マネージド コードを実行 するアプリケーションの最初のコンポーネントにruntimeconfig.jsonファイルが存在することを確認します。 最新バージョンの Visual Studio では、 runtime.config ファイルが自動的に作成され、コピーされます。
以前のバージョンの Visual Studio では、アプリケーションにネイティブ エントリ ポイントがある場合は、.NET ランタイムを使用する最初の C++/CLI ライブラリ用に次の runtimeconfig.json ファイルを手動で作成する必要があります。 C++/CLI ライブラリがマネージド エントリ ポイントから呼び出された場合、エントリ ポイント アセンブリにはランタイムの起動時に使用されるファイルがあるため、ライブラリには runtimeconfig.json ファイルは必要ありません。
{ "runtimeOptions": { "tfm": "net8.0", "framework": { "name": "Microsoft.NETCore.App", "version": "8.0.0" } } }
注
.NET 7 以降のバージョンを対象とする C++/CLI アセンブリは、常に既定の AssemblyLoadContextに読み込まれます。 ただし、.NET 6 以前のバージョンでは、C++/CLI アセンブリが新しい AssemblyLoadContext
に毎回複数回読み込まれる場合があります。 C++/CLI アセンブリ内のマネージド コードを初めて実行する場合:
- ネイティブの呼び出し元からの場合、アセンブリは別の
AssemblyLoadContext
に読み込まれます。 - マネージド呼び出し元からのアセンブリは、呼び出し元と同じ
AssemblyLoadContext
(通常は既定) に読み込まれます。
C++/CLI アセンブリを常に既定の AssemblyLoadContext
に読み込むには、エントリ ポイント アセンブリから C++/CLI アセンブリに "initialize" スタイルの呼び出しを追加できます。 詳細については、この dotnet/runtime の問題を参照してください。
.NET