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

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

.NET 6 以降では、Windows メタデータ (WinMD) ファイルの使用がサポートされなくなりました (「WinRT の組み込みサポートは .NET から削除されています」を参照してください)。 代わりに、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 デスクトップ アプリを使用するために正しいランタイム バイナリが読み込まれるようになります。

Desktop Compatible property page

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] を選択します。

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

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

Solution Explorer showing projection project dependencies

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

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

    このチュートリアルおよび関連サンプル コードでは、ソリューションが x64 およびリリース向けにビルドされています。 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 spec (.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 仕様の例です。 ターゲット lib\net6.0-windows10.0.19041.0\SimpleMathProjection.dll の場合は、プロジェクション アセンブリ SimpleMathComponent.winmd の代わりに、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-neutral 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 出力ディレクトリの下に生成されます。 また、\SimpleMathProjection\nuget フォルダーの下にも NuGet パッケージ SimpleMathComponent0.1.0-prerelease.nupkg が生成されます。

重要

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

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

Solution Explorer showing projection generation

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>
    

    重要

    上に示した SimpleMathComponent パッケージの RestoreSources パスは、../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. 編集したファイルを保存して閉じ、コンソール アプリをビルドして実行します。 次の出力が表示されるはずです。

    Console NET5 output

既知の問題

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

その他の考慮事項

このトピックで作成方法を示した C# プロジェクション (相互運用) アセンブリは非常にシンプルです。他のコンポーネントへの依存関係はありません。 しかし、Windows App SDK の型への参照を持つ C++/WinRT コンポーネントの C# プロジェクションを生成するには、プロジェクション プロジェクトで、Windows App SDK NuGet パッケージへの参照を追加する必要があります。 このような参照がない場合は、"型 <T> が見つかりませんでした" などのエラーが表示されます。

このトピックで行うもう 1 つのことは、プロジェクションを NuGet パッケージとして配布することです。 これ "" 現在、必要なことです。

リソース