C++/WinRT コンポーネントから C# プロジェクションを生成し、.NET アプリ用の NuGet として配布する

このトピックでは、C#/WinRT を使用して C++/WinRT Windows ランタイム コンポーネントから C# .NET プロジェクション (または相互運用機能) アセンブリを生成し、それを .NET アプリケーション用の NuGet パッケージとして配布します。

.NET 6 以降では、Windows メタデータ (WinMD) ファイルの使用はサポートされなくなりました (「 .NET から WinRT の組み込みサポートが削除される」を参照してください)。 代わりに、C#/WinRT ツールを使用して任意の WinMD ファイルのプロジェクション アセンブリを生成できます。これにより、.NET アプリケーションから WinRT コンポーネントを使用できるようになります。 プロジェクション アセンブリは相互運用機能アセンブリとも呼ばれます。 このチュートリアルでは、以下を行う方法について説明します。

  • C#/WinRT パッケージを使用して、C++/WinRT コンポーネントから C# プロジェクションを生成する。
  • コンポーネントをプロジェクション アセンブリと共に NuGet パッケージとして配布する。
  • .NET コンソール アプリケーションから NuGet パッケージを使用する。

前提条件

このチュートリアルと対応するサンプルには、次のツールとコンポーネントが必要です。

  • ユニバーサル Windows プラットフォーム開発ワークロードがインストールされた Visual Studio 2022 (または Visual Studio 2019)。 [インストールの詳細]>[ユニバーサル Windows プラットフォーム開発][C++ (v14x) ユニバーサル Windows プラットフォーム ツール] オプションを選択します。
  • .NET 6.0 SDK 以降。

Visual Studio 2019 のみ。 C++/WinRT VSIX 拡張機能。Visual Studio で C++/WinRT プロジェクト テンプレートが提供されます。 プロジェクト テンプレートは、Visual Studio 2022 に組み込まれています。

このチュートリアルでは、Visual Studio 2022 と .NET 6 を使用します。

重要

また、このトピックのサンプル コードを GitHub の C#/WinRT プロジェクション サンプルからダウンロードまたは複製する必要もあります。 Cswinrt にアクセスし、緑色の [コード] ボタンをクリックして git clone の URL を取得します。 このサンプルの README.md ファイルを必ずお読みください。

シンプルな C++/WinRT Windows ランタイム コンポーネントを作成する

このチュートリアルを実行するには、最初に C# プロジェクション アセンブリを生成する C++/WinRT Windows ランタイム コンポーネント (WRC) を作成しておく必要があります。

このチュートリアルでは、事前にダウンロードまたは複製した GitHub の C#/WinRT プロジェクション サンプルSimpleMathComponent WRC を使用します。 SimpleMathComponentWindows ランタイム コンポーネント (C++/WinRT) Visual Studio プロジェクト テンプレート (Visual Studio 2022 または C++/WinRT VSIX 拡張機能に付属) から作成したものです。

Visual Studio で SimpleMathComponent プロジェクトを開くには、\CsWinRT\src\Samples\NetProjectionSample\CppWinRTComponentProjectionSample.sln ファイルを開きます。このファイルは、リポジトリのダウンロードまたは複製に含まれています。

このプロジェクトのコードは、次のヘッダー ファイルに示されている基本的な算術演算の機能を提供します。

// SimpleMath.h
...
namespace winrt::SimpleMathComponent::implementation
{
    struct SimpleMath: SimpleMathT<SimpleMath>
    {
        SimpleMath() = default;
        double add(double firstNumber, double secondNumber);
        double subtract(double firstNumber, double secondNumber);
        double multiply(double firstNumber, double secondNumber);
        double divide(double firstNumber, double secondNumber);
    };
}

SimpleMathComponent C++/WinRT Windows ランタイム コンポーネント プロジェクトの [Windows Desktop Compatible\(Windows デスクトップ互換\)]プロパティが [はい] に設定されていることを確認できます。 これを行うには、SimpleMathComponent の [プロジェクトのプロパティ] の [構成プロパティ]>[全般]>[プロジェクトの既定値] で、プロパティ [Windows Desktop Compatible\(Windows デスクトップ互換\)][はい] に設定します。 これにより、.NET デスクトップ アプリを使用するために正しいランタイム バイナリが読み込まれるようになります。

デスクトップ互換プロパティ ページ

C++/WinRT コンポーネントを作成し、WinMD ファイルを生成する方法の詳細については、「C++/WinRT を使用した Windows ランタイム コンポーネント」を参照してください。

Note

コンポーネントで IInspectable::GetRuntimeClassName を実装している場合は、有効な WinRT クラス名を返す 必要があります。 C#/WinRT は相互運用にクラス名文字列を使用するため、不適切なランタイム クラス名を使用すると InvalidCastException が発生します。

コンポーネント ソリューションにプロジェクション プロジェクトを追加する

まず、Visual Studio で CppWinRTComponentProjectionSample ソリューションを開いたまま、そのソリューションから SimpleMathProjection プロジェクトを削除します。 次に、ファイル システムから SimpleMathProjection フォルダーを削除します (または、必要に応じて名前を変更します)。 これらの手順は、このチュートリアルの手順を実行するために必要です。

  1. 新しい C# ライブラリ プロジェクトをソリューションに追加します。

    1. ソリューション エクスプローラーで、ソリューション ノードを右クリックし、[追加]>[新しいプロジェクト] をクリックします。
    2. [新しいプロジェクトを追加] ダイアログ ボックスで、検索ボックスにクラス ライブラリと入力します。 言語の一覧から [C#] を選択し、[プラットフォーム] ボックスの一覧から [Windows] を選択します。 (プレフィックスもサフィックスも付かない) 単にクラス ライブラリという名前の C# プロジェクト テンプレートを選択し、[次へ] をクリックします。
    3. 新しいプロジェクトに SimpleMathProjection という名前を付けます。 場所は、SimpleMathComponent フォルダーと同じ\CsWinRT\src\Samples\NetProjectionSampleフォルダーに既に設定されている必要がありますが、確認してください。 続けて、 [次へ] をクリックします。
    4. [追加情報] ページで、[.NET 6.0 (長期的なサポート)] を選択し、[作成] を選択します。
  2. プロジェクトから、このスタブの Class1.cs ファイルを削除します。

  3. C#/WinRT NuGet パッケージをインストールするには、次の手順に従います。

    1. ソリューション エクスプローラーで、SimpleMathProjection プロジェクトを右クリックし、[NuGet パッケージの管理] をクリックします。
    2. [参照] タブで、検索ボックスに Microsoft.Windows.CsWinRT と入力するか貼り付けます。検索結果で、最新バージョンの項目を選択し、[インストール] をクリックしてパッケージを SimpleMathProjection プロジェクトにインストールします。
  4. SimpleMathComponent プロジェクトへのプロジェクト参照を SimpleMathProjection に追加します。 ソリューション エクスプローラーで、SimpleMathProjection プロジェクト ノードの下にある [依存関係] ノードを右クリックし、[プロジェクト参照の追加] を選択し、SimpleMathComponent プロジェクト >[OK] を選択します。

プロジェクトはまだビルドしないでください。 これについては、後の手順で行います。

現時点で、ソリューション エクスプローラーは次のように表示されるはずです (バージョン番号は異なります)。

プロジェクション プロジェクトの依存関係を示すソリューション エクスプローラー

ソースからプロジェクトをビルドする

C#/WinRT プロジェクション サンプルCppWinRTComponentProjectionSample ソリューション (GitHub からダウンロードまたは複製され、現在は開いている) のビルド出力先は、ソースからビルドするための Directory.Build.props ファイルで構成されます。 これは、ビルド出力のファイルがソース フォルダーの外部で生成されることを意味します。 C#/WinRT ツールを使用する場合は、ソースからビルドすることをお勧めします。 そうすることで、C# コンパイラでプロジェクトのルート ディレクトリにあるすべての *.cs ファイルが誤って選択されないようにすることができます。誤って選択されると、(複数の構成やプラットフォーム用にコンパイルする場合などに) 重複型エラーが発生する可能性があります。

これは CppWinRTComponentProjectionSample ソリューションに対して既に構成されていますが、次の手順に従って、ご自身で構成を行ってみてください。

ソースからビルドするようにソリューションを構成するには:

  1. CppWinRTComponentProjectionSample ソリューションを開いたままの状態で、ソリューション ノードを右クリックし、[追加]>[新しい項目] を選択します。 [XML ファイル] 項目を選択し、Directory.Build.props という名前を付けます (.xml 拡張子は付けません)。 [はい] をクリックして、既存のファイルを上書きします。

  2. 次の構成を使用して、Directory.Build.props の内容を置き換えます。

    <Project>
      <PropertyGroup>
        <BuildOutDir>$([MSBuild]::NormalizeDirectory('$(SolutionDir)', '_build', '$(Platform)', '$(Configuration)'))</BuildOutDir>
        <OutDir>$([MSBuild]::NormalizeDirectory('$(BuildOutDir)', '$(MSBuildProjectName)', 'bin'))</OutDir>
        <IntDir>$([MSBuild]::NormalizeDirectory('$(BuildOutDir)', '$(MSBuildProjectName)', 'obj'))</IntDir>
      </PropertyGroup>
    </Project>
    
  3. Directory.Build.props ファイルを保存して閉じます。

プロジェクト ファイルを編集して C#/WinRT を実行する

cswinrt.exe ツールを呼び出してプロジェクション アセンブリを生成する前に、プロジェクト ファイルを編集してプロジェクトのプロパティをいくつか指定する必要があります。

  1. ソリューション エクスプローラーで、SimpleMathProjection ノードをダブルクリックして、エディターでプロジェクト ファイルを開きます。

  2. 特定のバージョンの Windows SDK がターゲットとなるように TargetFramework 要素を更新します。 これにより、相互運用とプロジェクションのサポートに必要なアセンブリの依存関係が追加されます。 このサンプルでは、Windows SDK バージョン net6.0-windows10.0.19041.0 (Windows 10 バージョン 2004 とも呼ばれます) を対象とします。 結果の Platform プロジェクション アセンブリを任意のアプリ アーキテクチャから参照できるように、 要素を AnyCPU に設定します。 以前のバージョンの Windows SDK をサポートするアプリケーションを参照できるようにするには、 プロパティを TargetPlatformMinimumVersion 設定することもできます。

    <PropertyGroup>
      <TargetFramework>net6.0-windows10.0.19041.0</TargetFramework>
      <!-- Set Platform to AnyCPU to allow consumption of the projection assembly from any architecture. -->
      <Platform>AnyCPU</Platform>
    </PropertyGroup>
    

    Note

    このチュートリアルと関連するサンプル コードでは、 ソリューションは x64Release 用に構築されています。 SimpleMathProjection プロジェクトは、すべてのソリューション アーキテクチャ構成に対して AnyCPU 用にビルドするように構成されていることに注意してください。

  3. いくつかの C#/WinRT プロパティを設定する 2 番目のPropertyGroup要素を (最初の要素の直後に) 追加します。

    <PropertyGroup>
      <CsWinRTIncludes>SimpleMathComponent</CsWinRTIncludes>
      <CsWinRTGeneratedFilesDir>$(OutDir)</CsWinRTGeneratedFilesDir>
    </PropertyGroup>
    

    この例の設定の詳細を次に示します。

    • CsWinRTIncludes プロパティは、プロジェクトに使用する名前空間を指定します。
    • CsWinRTGeneratedFilesDir プロパティは、プロジェクション ソース ファイルが生成される出力ディレクトリを設定します。 このプロパティは、上記のセクションの Directory.Build.props で定義されている にOutDir設定されています。
  4. SimpleMathProjection.csproj ファイルを保存して閉じ、必要に応じて [Reload projects]\(プロジェクトの再読み込み\) をクリックします。

プロジェクションを使用して NuGet パッケージを作成する

.NET アプリケーション開発者向けのプロジェクション アセンブリを配布するには、追加のプロジェクト プロパティを追加して、ソリューションのビルド時に NuGet パッケージを自動的に作成します。 .NET ターゲットの場合、NuGet パッケージには、コンポーネントからプロジェクション アセンブリおよび実装アセンブリを含める必要があります。

  1. 次の手順を使用して、NuGet 仕様 (.nuspec) ファイルを SimpleMathProjection プロジェクトに追加します。

    1. ソリューション エクスプローラーで、SimpleMathProjection ノードを右クリックし、[追加]>[新しいフォルダー] を選択し、フォルダーに nuget という名前を付けます。
    2. nuget フォルダーを右クリックし、[追加]>[新しい項目][XML ファイル] を選択し、SimpleMathProjection.nuspec という名前を付けます。
  2. ソリューション エクスプローラーで、SimpleMathProjection ノードをダブルクリックして、エディターでプロジェクト ファイルを開きます。 次のプロパティ グループを、今開いた SimpleMathProjection.csproj (2 つの既存の PropertyGroup 要素の直後) に追加して、パッケージを自動的に生成します。 これらのプロパティは NuspecFile と、NuGet パッケージを生成するディレクトリを指定します。

    <PropertyGroup>
      <GeneratedNugetDir>.\nuget\</GeneratedNugetDir>
      <NuspecFile>$(GeneratedNugetDir)SimpleMathProjection.nuspec</NuspecFile>
      <OutputPath>$(GeneratedNugetDir)</OutputPath>
      <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
    </PropertyGroup>
    

    Note

    パッケージを個別に生成する場合は、コマンド ラインから nuget.exe ツールを実行することもできます。 NuGet パッケージの作成の詳細については、「nuget.exe CLI を使用してパッケージを作成する」を参照してください。

  3. SimpleMathProjection.nuspec ファイルを開いてパッケージ作成プロパティを編集し、次のコードを貼り付けます。 次のスニペットは、 SimpleMathComponent を複数のターゲット フレームワークに配布するための NuGet 仕様の例です。 プロジェクション アセンブリ SimpleMathProjection.dllは、ターゲット の SimpleMathComponent.winmd の代わりに指定されることに注意してください lib\net6.0-windows10.0.19041.0\SimpleMathProjection.dll。 この動作は .NET 6 以降では新しく、C#/WinRT によって有効になっています。 実装アセンブリ SimpleMathComponent.dll( ) も分散する必要があり、実行時に読み込まれます。

    <?xml version="1.0" encoding="utf-8"?>
    <package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
      <metadata>
        <id>SimpleMathComponent</id>
        <version>0.1.0-prerelease</version>
        <authors>Contoso Math Inc.</authors>
        <description>A simple component with basic math operations</description>
        <dependencies>
          <group targetFramework="net6.0-windows10.0.19041.0" />
          <group targetFramework=".NETCoreApp3.0" />
          <group targetFramework="UAP10.0" />
          <group targetFramework=".NETFramework4.6" />
        </dependencies>
      </metadata>
      <files>
        <!--Support .NET 6, .NET Core 3, UAP, .NET Framework 4.6, C++ -->
        <!--Architecture-netural assemblies-->
        <file src="..\..\_build\AnyCPU\Release\SimpleMathProjection\bin\SimpleMathProjection.dll" target="lib\net6.0-windows10.0.19041.0\SimpleMathProjection.dll" />
        <file src="..\..\_build\x64\Release\SimpleMathComponent\bin\SimpleMathComponent\SimpleMathComponent.winmd" target="lib\netcoreapp3.0\SimpleMathComponent.winmd" />
        <file src="..\..\_build\x64\Release\SimpleMathComponent\bin\SimpleMathComponent\SimpleMathComponent.winmd" target="lib\uap10.0\SimpleMathComponent.winmd" />
        <file src="..\..\_build\x64\Release\SimpleMathComponent\bin\SimpleMathComponent\SimpleMathComponent.winmd" target="lib\net46\SimpleMathComponent.winmd" />
        <!--Architecture-specific implementation DLLs should be copied into RID-relative folders-->
        <file src="..\..\_build\x64\Release\SimpleMathComponent\bin\SimpleMathComponent\SimpleMathComponent.dll" target="runtimes\win10-x64\native\SimpleMathComponent.dll" />
        <!--To support x86 and Arm64, build SimpleMathComponent for those other architectures and uncomment the entries below.-->
        <!--<file src="..\..\_build\Win32\Release\SimpleMathComponent\bin\SimpleMathComponent\SimpleMathComponent.dll" target="runtimes\win10-x86\native\SimpleMathComponent.dll" />-->
        <!--<file src="..\..\_build\arm64\Release\SimpleMathComponent\bin\SimpleMathComponent\SimpleMathComponent.dll" target="runtimes\win10-arm64\native\SimpleMathComponent.dll" />-->
      </files>
    </package>
    

    Note

    コンポーネントの実装アセンブリの SimpleMathComponent.dll は、アーキテクチャによって異なります。 他のプラットフォーム (x86 や Arm64 など) をサポートしている場合は、最初に目的のプラットフォーム用に SimpleMathComponent をビルドし、これらのアセンブリ ファイルを適切な RID 相対フォルダーに追加する必要があります。 プロジェクション アセンブリ SimpleMathProjection.dll とコンポーネント SimpleMathComponent.winmd はどちらもアーキテクチャに依存しません。

  4. 編集したファイルを保存して閉じます。

ソリューションをビルドして、プロジェクションと NuGet パッケージを生成する

ソリューションをビルドする前に、Visual Studio の [ビルド]>[Configuration Manager][Configuration Manager] の設定を確認してください。 このチュートリアルでは、ソリューションの [構成][リリース ] に、[ プラットフォーム ] を [x64 ] に設定します。

この時点で、ソリューションをビルドできるようになりました。 ソリューション ノードを右クリックし、[ソリューションのビルド] を選択します。 これにより、まず SimpleMathComponent プロジェクトがビルドされ、次に SimpleMathProjection プロジェクトがビルドされます。 コンポーネント WinMD および実装アセンブリ (SimpleMathComponent.winmd および SimpleMathComponent.dll)、プロジェクション ソース ファイル、およびプロジェクション アセンブリ (SimpleMathProjection.dll) はすべて、_build 出力ディレクトリの下に生成されます。 生成された NuGet パッケージ SimpleMathComponent0.1.0-prerelease.nupkg は、 \SimpleMathProjection\nuget フォルダーの下にも表示されます。

重要

上記のいずれかのファイルが生成されない場合は、ソリューションをもう一度ビルドします。 再構築する前に、ソリューションを閉じて再度開くことが必要になる場合もあります。

図のように Visual Studio に 表示するには、ソリューション .nupkg を閉じて再度開く必要がある場合があります (または、[ すべてのファイルを表示] を選択して選択解除します)。

プロジェクションの生成を示すソリューション エクスプローラー

C# .NET 6 コンソール アプリケーションで NuGet パッケージを参照する

前のセクションで作成した SimpleMathComponent0.1.0-prerelease.nupkg NuGet パッケージへの参照を新しい .NET プロジェクトに追加するだけで、.NET プロジェクトから SimpleMathComponent を使用できます。 次の手順では、別のソリューションで簡単なコンソール アプリを作成することによって、その方法を示します。

  1. 次の手順を使用して、C# コンソール アプリ プロジェクトを含む新しいソリューションを作成します (新しいソリューションでこのプロジェクトを作成すると、SimpleMathComponent NuGet パッケージを個別に復元できます)。

    重要

    この新しいコンソール アプリ プロジェクトを \CsWinRT\src\Samples\NetProjectionSample フォルダー内に作成します。これは、ダウンロードした C#/WinRT プロジェクション サンプル、またはその複製に含まれています。

    1. Visual Studio の新しいインスタンスで、[ファイル]>[新規]>[プロジェクト] を選択します。
    2. [新しいプロジェクトの作成] ダイアログ ボックスで、コンソール アプリのプロジェクト テンプレートを検索します。 (プレフィックスもサフィックスも付かない) 単にコンソール アプリという名前の C# プロジェクト テンプレートを選択し、[次へ] をクリックします。 Visual Studio 2019 を使用している場合、プロジェクトテンプレートはコンソール アプリケーションになります。
    3. 新しいプロジェクトに SampleConsoleApp という名前を指定し、その場所を SimpleMathComponent フォルダーおよび SimpleMathProjection フォルダーがあるのと同じ \CsWinRT\src\Samples\NetProjectionSample フォルダーに設定して、[次へ] をクリックします。
    4. [追加情報] ページで、[.NET 6.0 (長期的なサポート)] を選択し、[作成] を選択します。
  2. ソリューション エクスプローラーで、SampleConsoleApp ノードをダブルクリックして SampleConsoleApp.csproj プロジェクト ファイルを開き、次の一覧のようになるように TargetFramework プロパティと Platform プロパティを編集します。 Platform 要素が存在しない場合は追加します。

    <PropertyGroup>
      <OutputType>Exe</OutputType>
      <TargetFramework>net6.0-windows10.0.19041.0</TargetFramework>
      <Platform>x64</Platform>
    </PropertyGroup>
    
  3. SampleConsoleApp.csproj プロジェクト ファイルを開いたまま、次に SampleConsoleApp プロジェクトに、SimpleMathComponent NuGet パッケージへの参照を追加します。 プロジェクトのビルド時に SimpleMathComponent NuGet を復元するには、コンポーネント ソリューションの nuget フォルダーへのパスで RestoreSources プロパティを使用できます。 次の構成をコピーし、SampleConsoleApp.csproj (Project 要素内) に貼り付けます。

    <PropertyGroup>
      <RestoreSources>
        https://api.nuget.org/v3/index.json;
        ../SimpleMathProjection/nuget
      </RestoreSources>
    </PropertyGroup>
    
    <ItemGroup>
      <PackageReference Include="SimpleMathComponent" Version="0.1.0-prerelease" />
    </ItemGroup>
    

    重要

    RestoreSources上に示した SimpleMathComponent パッケージのパスは に../SimpleMathProjection/nuget設定されています。 このチュートリアルの手順に従い、SimpleMathComponent プロジェクトと SampleConsoleApp プロジェクトが同じフォルダー (この場合は NetProjectionSample フォルダー) にあれば、これは正しいパスです。 チュートリアルの手順以外のことを行った場合は、それに応じてそのパスを調整する必要があります。 または、ソリューションにローカルの NuGet パッケージ フィードを追加することもできます。

  4. SimpleMathComponent によって提供される機能が使用されるように Program.cs ファイルを編集します。

    var x = new SimpleMathComponent.SimpleMath();
    Console.WriteLine("Adding 5.5 + 6.5 ...");
    Console.WriteLine(x.add(5.5, 6.5).ToString());
    
  5. 編集したファイルを保存して閉じ、コンソール アプリをビルドして実行します。 次の出力が表示されるはずです。

    コンソール NET5 の出力

既知の問題

  • プロジェクション プロジェクトをビルドするときに、次のようなエラーが表示されることがあります。エラー MSB3271 ビルド中のプロジェクトのプロセッサ アーキテクチャ "MSIL" と、実装ファイルのプロセッサ アーキテクチャ "x86" の間に不一致がありました。の\SimpleMathComponent.dll" です。\SimpleMathComponent.winmd"この不一致により、ランタイム エラーが発生する可能性があります。プロジェクトと実装ファイルの間でプロセッサ アーキテクチャを調整するために、Configuration Managerを使用してプロジェクトの対象プロセッサ アーキテクチャを変更するか、プロジェクトの対象プロセッサ アーキテクチャに一致するプロセッサ アーキテクチャを持つ実装ファイルを含む winmd ファイルを選択することを検討してください。 このエラーを回避するには、C# ライブラリ プロジェクト ファイルに次のプロパティを追加します。
    <PropertyGroup>
        <!-- Workaround for MSB3271 error on processor architecture mismatch -->
        <ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>None</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
    </PropertyGroup>
    

リソース