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 パッケージを使用します。

[前提条件]

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

  • Visual Studio 2022 以降ユニバーサル Windows プラットフォーム開発ワークロードがインストールされています。 Installation Details>ユニバーサル Windows プラットフォーム development で、C++ (v14x) ユニバーサル Windows プラットフォーム tools オプションを確認します。
  • .NET 8.0 SDK (LTS) 以降。

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

Von Bedeutung

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

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

このチュートリアルに従うには、まず C# プロジェクション アセンブリを生成する C++/WinRT Windows ランタイム コンポーネント (WRC) が必要です。

このチュートリアルでは、既にダウンロードまたは複製した GitHub の SimpleMathComponent WRC C#/WinRT プロジェクション サンプル を使用します。 SimpleMathComponent は、Windows ランタイム Component (C++/WinRT) Visual Studio プロジェクト テンプレートから作成されました。

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);
    };
}

Windows Desktop Compatible プロパティが、SimpleMathComponent C++/WinRT Windows ランタイム コンポーネント プロジェクトのYesに設定されていることを確認できます。 これを行うには、SimpleMathComponent のプロジェクトプロパティで、Configuration Properties>General>Project Defaults の下にあるプロパティ Windows Desktop CompatibleYes に設定します。 これにより、.NET デスクトップ アプリを使用するために、適切な .NET ランタイム バイナリが読み込まれることを保証します。

Desktop Compatible プロパティ ページ

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

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

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

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

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

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

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

    1. ソリューション エクスプローラー で、SimpleMathProjection プロジェクトを右クリックし、 Manage NuGet Packages を選択します。
    2. Browse タブで「Microsoft.Windows.CsWinRT」を検索ボックスに入力または貼り付けし、検索結果で最新バージョンのアイテムを選択して、Install をクリックし、パッケージを SimpleMathProjection プロジェクトにインストールします。
  4. SimpleMathProjection に、SimpleMathComponent プロジェクトへの参照を追加します。 ソリューション エクスプローラー で、SimpleMathProjection プロジェクト ノードの下にある Dependencies ノードを右クリックし、プロジェクト参照の追加 を選択し、SimpleMathComponent プロジェクトを選択して OK をクリックします。

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

ここまでは、ソリューション エクスプローラー は次のようになります (バージョン番号は異なります)。

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

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

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

これは 既に CppWinRTComponentProjectionSample ソリューション用に構成されていますが、次の手順に従って、自分で構成を実行する方法を確認してください。

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

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

  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>net8.0-windows10.0.19041.0</TargetFramework>
      <!-- Set Platform to AnyCPU to allow consumption of the projection assembly from any architecture. -->
      <Platform>AnyCPU</Platform>
    </PropertyGroup>
    

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

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

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

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

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

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

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

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

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

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

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

  3. SimpleMathProjection.nuspec ファイルを開いてパッケージ作成プロパティを編集し、次のコードを貼り付けます。 次のスニペットは、 SimpleMathComponent を複数のターゲット フレームワークに配布するための NuGet 仕様の例です。 ターゲット lib\net6.0-windows10.0.19041.0\SimpleMathProjection.dll の代わりに、プロジェクション アセンブリ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>
    

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

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

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

ソリューションをビルドする前に、必ず Visual Studio の Configuration Manager 設定を Build>Configuration Manager で確認してください。 このチュートリアルでは、ソリューションの 構成Release に、Platformx64 に設定します。

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

Von Bedeutung

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

ソリューションを閉じて再度開くことで、.nupkgが図のようにVisual Studioに表示される場合があります(または、すべてのファイルを表示を選択してから解除するだけでも表示されます)。

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

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

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

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

    Von Bedeutung

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

    1. Visual Studioの新しいインスタンスで、File>New>Project を選択します。
    2. [ 新しいプロジェクトの作成 ] ダイアログ ボックスで、 コンソール アプリ プロジェクト テンプレートを検索します。 C# プロジェクト テンプレートの中から、単に「Console App」とだけ書かれたもの(プレフィックスやサフィックスはなし)を選択し、[次へ]をクリックします。 Visual Studio 2019 を使用している場合、プロジェクト テンプレートは Console Application です。
    3. SampleConsoleAppに新しいプロジェクトの名前を付け、その場所を SimpleMathComponent フォルダーと SimpleMathProjection フォルダーと同じ フォルダーに設定し、[次へ]をクリックします
    4. [追加情報 ページで、.NET 8.0 (長期サポート) を選択し、Create を選択します。
  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 を復元するには、コンポーネント ソリューション内の 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>
    

    Von Bedeutung

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

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

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

その他の考慮事項

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

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

リソース