次の方法で共有


C++/WinRT アプリから使用するための C# Windows ランタイム コンポーネントの作成

このトピックでは、シンプルな C# コンポーネントを C++/WinRT プロジェクトに追加する処理を順を追って説明します。

Visual Studio を使用すると、C# または Visual Basic で記述された Windows ランタイム コンポーネント (WRC) プロジェクト内に独自のカスタム Windows ランタイム型を簡単に作成して配置し、次に C++ アプリケーション プロジェクトからその WRC を参照して、そのアプリケーションからそれらのカスタム型を使用することができます。

内部的には、UWP アプリケーションで許可されているすべての .NET 機能をその Windows ランタイム型で使用できます。

外部的には、型のメンバーによってパラメーターと戻り値の Windows ランタイム型のみを公開できます。 ソリューションをビルドすると、Visual Studio によって .NET WRC プロジェクトがビルドされ、Windows メタデータ (.winmd) ファイルを作成するビルド ステップが実行されます。 これが、Visual Studio によってアプリに含められる Windows ランタイム コンポーネント (WRC) です。

注意

.NET により、一般的に使用される .NET の型 (プリミティブ データ型やコレクション型など) が対応する Windows ランタイム型に自動的にマップされます。 .NET のこれら型は、Windows ランタイム コンポーネントのパブリック インターフェイス内で使用でき、対応する Windows ランタイム型としてコンポーネントのユーザーに表示されます。 「C# および Visual Basic を使用した Windows ランタイム コンポーネント」を参照してください。

前提条件

空のアプリの作成

Visual Studio で [空のアプリ (C++WinRT)] プロジェクト テンプレートを使用して新しいプロジェクトを作成します。 (ユニバーサル Windows) テンプレートではなく、(C++/WinRT) テンプレートを使用していることをご確認ください。

新しいプロジェクトの名前を CppToCSharpWinRT に設定して、フォルダー構造がこのチュートリアルと一致するようにします。

C# Windows ランタイム コンポーネントをソリューションに追加する

Visual Studio で、コンポーネント プロジェクトを作成します。ソリューション エクスプローラーで、CppToCSharpWinRT ソリューションのショートカット メニューを開き、[追加][新しいプロジェクト] の順にクリックして、新しい C# プロジェクトをソリューションに追加します。 [新しいプロジェクトの追加] ダイアログ ボックスの [インストールされたテンプレート] セクションで、[Visual C#] を選択し、[Windows][ユニバーサル] の順に選択します。 [Windows ランタイム コンポーネント (ユニバーサル Windows)] テンプレートを選択し、プロジェクト名として「SampleComponent」と入力します。

注意

[新しいユニバーサル Windows プラットフォーム プロジェクト] ダイアログ ボックスで、[Windows 10 Creators Update (10.0; Build 15063)] を最小バージョンとして選択します。 詳しくは、後述の「アプリケーションの最小バージョン」セクションを参照してください。

C# GetMyString メソッドを追加する

SampleComponent プロジェクトで、クラスの名前を Class1 から Example に変更します。 次に、2 つの単純なメンバー (プライベート int フィールドと、GetMyString という名前のインスタンス メソッド) をクラスに追加します。

    public sealed class Example
    {
        int MyNumber;

        public string GetMyString()
        {
            return $"This is call #: {++MyNumber}";
        }
    }

注意

既定では、クラスは public sealed とマークされます。 コンポーネントから公開するすべての Windows ランタイム クラスを保護する必要があります。

注意

省略可能: 新しく追加したメンバーで IntelliSense を有効にするには、ソリューション エクスプローラーで SampleComponent プロジェクトのショートカット メニューを開き、[ビルド] を選びます。

CppToCSharpWinRT プロジェクトから C# SampleComponent を参照する

ソリューション エクスプローラーの C++/WinRT プロジェクトで、[参照] のショートカット メニューを開き、[参照の追加] を選択して [参照の追加] を開きます。 プロジェクト を選択し、ソリューション を選択します。 SampleComponent プロジェクトのチェック ボックスをオンにし、[OK] をクリックして参照を追加します。

注意

省略可能: C++/WinRT プロジェクトで IntelliSense を有効にするには、ソリューション エクスプローラーで CppToCSharpWinRT プロジェクトのショートカット メニューを開き、[ビルド] を選びます。

MainPage.h を編集する

CppToCSharpWinRT プロジェクトで MainPage.h を開き、2 つの項目を追加します。 まず、#include ステートメントの最後に #include "winrt/SampleComponent.h" を追加してから、winrt::SampleComponent::Example フィールドを MainPage 構造体に追加します。

// MainPage.h
...
#include "winrt/SampleComponent.h"

namespace winrt::CppToCSharpWinRT::implementation
{
    struct MainPage : MainPageT<MainPage>
    {
...
        winrt::SampleComponent::Example myExample;
...
    };
}

注意

Visual Studio では、MainPage.hMainPage.xaml の下に一覧表示されます。

MainPage.cpp を編集する

MainPage.cpp で、C# メソッド GetMyString を呼び出すように Mainpage::ClickHandler 実装を変更します。

void MainPage::ClickHandler(IInspectable const&, RoutedEventArgs const&)
{
    //myButton().Content(box_value(L"Clicked"));

    hstring myString = myExample.GetMyString();

    myButton().Content(box_value(myString));
}

プロジェクトを実行する

これでプロジェクトをビルドして実行できるようになりました。 ボタンをクリックするたびに、ボタンの数値が増加します。

C++/WinRT Windows calling into a C# component screenshot

ヒント

Visual Studio で、コンポーネント プロジェクトを作成します。ソリューション エクスプローラーで、CppToCSharpWinRT プロジェクトのショートカット メニューを開き、[プロパティ] を選択してから、[構成プロパティ] の下の [デバッグ] をクリックします。 C# (マネージド)と C++ (ネイティブ) の両方のコードをデバッグする場合は、[デバッガーの種類] を "[マネージド] または [ネイティブ]" に設定します。 C++ Debugging Properties

アプリケーションの最小バージョン

アプリケーションのコンパイルに使用される .NET のバージョンは、C# プロジェクト バージョンの [Application Minimum]\(アプリケーションの最小\) で制御されます。 たとえば、[Windows 10 Fall Creators Update (10.0; Build 16299)] 以上を選ぶと、.NET Standard 2.0 と Windows Arm64 プロセッサのサポートが有効になります。

ヒント

.NET Standard 2.0 または Arm64 のサポートが不要な場合は、16299 より前の [Application Minimum]\(アプリケーションの最小\) バージョンを使用して追加のビルド構成を回避することをお勧めします。

Windows 10 Fall Creators Update (10.0; Build 16299) を構成する

次の手順に従って、C++/WinRT プロジェクトから参照されている C# プロジェクト内で .NET Standard 2.0 または Windows Arm64 のサポートを有効にします。

Visual Studio で、ソリューション エクスプローラーにアクセスし、CppToCSharpWinRT プロジェクトのショートカット メニューを開きます。 [プロパティ] を選択し、ユニバーサル Windows アプリの最小バージョンを Windows 10 Fall Creators Update (10.0; Build 16299) (またはそれ以降) に設定します。 SampleComponent プロジェクトについても同じ操作を行います。

Visual Studio で、CppToCSharpWinRT プロジェクトのショートカット メニューを開き、[プロジェクトのアンロード] を選んで CppToCSharpWinRT.vcxproj をテキスト エディターで開きます。

次の XML をコピーして、CPPWinRTCSharpV2.vcxproj の最初の PropertyGroup に貼り付けます。

   <!-- Start Custom .NET Native properties -->
   <DotNetNativeVersion>2.2.12-rel-31116-00</DotNetNativeVersion>
   <DotNetNativeSharedLibrary>2.2.8-rel-31116-00</DotNetNativeSharedLibrary>
   <UWPCoreRuntimeSdkVersion>2.2.14</UWPCoreRuntimeSdkVersion>
   <!--<NugetPath>$(USERPROFILE)\.nuget\packages</NugetPath>-->
   <NugetPath>$(ProgramFiles)\Microsoft SDKs\UWPNuGetPackages</NugetPath>
   <!-- End Custom .NET Native properties -->

DotNetNativeVersionDotNetNativeSharedLibrary、および UWPCoreRuntimeSdkVersion の値は、Visual Studio のバージョンによって異なる可能性があります。 正しい値に設定するには、%ProgramFiles(x86)%\Microsoft SDKs\UWPNuGetPackages を開き、次の表の各値のサブディレクトリを確認します。 %ProgramFiles(x86)%\Microsoft SDKs\UWPNuGetPackages\Microsoft.Net.Native.Compiler ディレクトリには、.NET ネイティブの 2.2 以降のインストールされたバージョンが含まれるサブディレクトリがあります。 次の例では、2.2.12-rel-31116-00 です。

MSBuild 変数 ディレクトリ
DotNetNativeVersion %ProgramFiles(x86)%\Microsoft SDKs\UWPNuGetPackages\Microsoft.Net.Native.Compiler 2.2.12-rel-31116-00
DotNetNativeSharedLibrary %ProgramFiles(x86)%\Microsoft SDKs\UWPNuGetPackages\runtime.win10-x64.microsoft.net.native.sharedlibrary 2.2.8-rel-31116-00
UWPCoreRuntimeSdkVersion %ProgramFiles(x86)%\Microsoft SDKs\UWPNuGetPackages\Microsoft.Net.UWPCoreRuntimeSdk 2.2.14

注意

Microsoft.Net.Native.SharedLibrary には、サポートされているアーキテクチャが複数あります。 x64 を適切なアーキテクチャに置き換えます。 たとえば、arm64 アーキテクチャは %ProgramFiles(x86)%\Microsoft SDKs\UWPNuGetPackages\runtime.win10-arm64.microsoft.net.native.sharedlibrary ディレクトリにあります。

次に、最初の PropertyGroup の直後に以下を (変更なしで) 追加します。

  <!-- Start Custom .NET Native targets -->
  <!-- Import all of the .NET Native / CoreCLR props at the beginning of the project -->
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\Microsoft.Net.UWPCoreRuntimeSdk\$(UWPCoreRuntimeSdkVersion)\build\Microsoft.Net.UWPCoreRuntimeSdk.props" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-x86.Microsoft.Net.UWPCoreRuntimeSdk\$(UWPCoreRuntimeSdkVersion)\build\runtime.win10-x86.Microsoft.Net.UWPCoreRuntimeSdk.props" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-x64.Microsoft.Net.UWPCoreRuntimeSdk\$(UWPCoreRuntimeSdkVersion)\build\runtime.win10-x64.Microsoft.Net.UWPCoreRuntimeSdk.props" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-arm.Microsoft.Net.UWPCoreRuntimeSdk\$(UWPCoreRuntimeSdkVersion)\build\runtime.win10-arm.Microsoft.Net.UWPCoreRuntimeSdk.props" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\Microsoft.Net.Native.Compiler\$(DotNetNativeVersion)\build\Microsoft.Net.Native.Compiler.props" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-x86.Microsoft.Net.Native.Compiler\$(DotNetNativeVersion)\build\runtime.win10-x86.Microsoft.Net.Native.Compiler.props" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-x64.Microsoft.Net.Native.Compiler\$(DotNetNativeVersion)\build\runtime.win10-x64.Microsoft.Net.Native.Compiler.props" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-arm.Microsoft.Net.Native.Compiler\$(DotNetNativeVersion)\build\runtime.win10-arm.Microsoft.Net.Native.Compiler.props" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-arm64.Microsoft.Net.Native.Compiler\$(DotNetNativeVersion)\build\runtime.win10-arm64.Microsoft.Net.Native.Compiler.props" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-x86.Microsoft.Net.Native.SharedLibrary\$(DotNetNativeSharedLibrary)\build\runtime.win10-x86.Microsoft.Net.Native.SharedLibrary.props" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-x64.Microsoft.Net.Native.SharedLibrary\$(DotNetNativeSharedLibrary)\build\runtime.win10-x64.Microsoft.Net.Native.SharedLibrary.props" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-arm.Microsoft.Net.Native.SharedLibrary\$(DotNetNativeSharedLibrary)\build\runtime.win10-arm.Microsoft.Net.Native.SharedLibrary.props" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-arm64.Microsoft.Net.Native.SharedLibrary\$(DotNetNativeSharedLibrary)\build\runtime.win10-arm64.Microsoft.Net.Native.SharedLibrary.props" />
  <!-- End Custom .NET Native targets -->

プロジェクト ファイルの最後で、終了 Project タグの直前に以下を (変更なしで) 追加します。

  <!-- Import all of the .NET Native / CoreCLR targets at the end of the project -->
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-x86.Microsoft.Net.UWPCoreRuntimeSdk\$(UWPCoreRuntimeSdkVersion)\build\runtime.win10-x86.Microsoft.Net.UWPCoreRuntimeSdk.targets" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-x64.Microsoft.Net.UWPCoreRuntimeSdk\$(UWPCoreRuntimeSdkVersion)\build\runtime.win10-x64.Microsoft.Net.UWPCoreRuntimeSdk.targets" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-arm.Microsoft.Net.UWPCoreRuntimeSdk\$(UWPCoreRuntimeSdkVersion)\build\runtime.win10-arm.Microsoft.Net.UWPCoreRuntimeSdk.targets" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\Microsoft.Net.Native.Compiler\$(DotNetNativeVersion)\build\Microsoft.Net.Native.Compiler.targets" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-x86.Microsoft.Net.Native.Compiler\$(DotNetNativeVersion)\build\runtime.win10-x86.Microsoft.Net.Native.Compiler.targets" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-x64.Microsoft.Net.Native.Compiler\$(DotNetNativeVersion)\build\runtime.win10-x64.Microsoft.Net.Native.Compiler.targets" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-arm.Microsoft.Net.Native.Compiler\$(DotNetNativeVersion)\build\runtime.win10-arm.Microsoft.Net.Native.Compiler.targets" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-arm64.Microsoft.Net.Native.Compiler\$(DotNetNativeVersion)\build\runtime.win10-arm64.Microsoft.Net.Native.Compiler.targets" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-x86.Microsoft.Net.Native.SharedLibrary\$(DotNetNativeSharedLibrary)\build\runtime.win10-x86.Microsoft.Net.Native.SharedLibrary.targets" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-x64.Microsoft.Net.Native.SharedLibrary\$(DotNetNativeSharedLibrary)\build\runtime.win10-x64.Microsoft.Net.Native.SharedLibrary.targets" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-arm.Microsoft.Net.Native.SharedLibrary\$(DotNetNativeSharedLibrary)\build\runtime.win10-arm.Microsoft.Net.Native.SharedLibrary.targets" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-arm64.Microsoft.Net.Native.SharedLibrary\$(DotNetNativeSharedLibrary)\build\runtime.win10-arm64.Microsoft.Net.Native.SharedLibrary.targets" />
  <!-- End Custom .NET Native targets -->

Visual Studio 内でプロジェクト ファイルを再読み込みします。 これを行うには、Visual Studio ソリューション エクスプローラーで CppToCSharpWinRT プロジェクトのショートカット メニューを開き、[プロジェクトの再読み込み] を選択します。

.NET ネイティブのビルド

.NET ネイティブ用に構築された C# コンポーネントを使用して、アプリケーションのビルドとテストを行うことをお勧めします。 Visual Studio で、CppToCSharpWinRT プロジェクトのショートカット メニューを開き、[プロジェクトのアンロード] を選んで CppToCSharpWinRT.vcxproj をテキスト エディターで開きます。

次に、C++ プロジェクト ファイル内のリリースおよび Arm64 構成で、UseDotNetNativeToolchain プロパティを true に設定します。

Visual Studio ソリューション エクスプローラーで CppToCSharpWinRT プロジェクトのショートカット メニューを開き、[プロジェクトの再読み込み] を選択します。

  <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
...
    <UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Platform)'=='Arm64'" Label="Configuration">
    <UseDotNetNativeToolchain Condition="'$(UseDotNetNativeToolchain)'==''">true</UseDotNetNativeToolchain>
  </PropertyGroup>

その他の C# NuGet パッケージを参照する

C# コンポーネントが他の NuGet パッケージを参照している場合、アプリケーションのプロジェクト ファイルで、NuGet パッケージからの展開コンテンツとして、ファイルの依存関係の一覧が必要になる場合があります。 たとえば、C# コンポーネントによって Newtonsoft.Json NuGet パッケージが参照される場合、同じ NuGet パッケージとファイルの依存関係も、アプリケーション プロジェクト内で参照される必要があります。

SampleComponent.csproj ファイルで、NuGet パッケージ参照を追加します。

    <PackageReference Include="Newtonsoft.Json">
      <Version>13.0.1</Version>
    </PackageReference>

CppToCSharpWinRT プロジェクトで、packages.config ファイルを見つけ、適切な NuGet 参照を追加します。 これにより、NuGet パッケージがソリューションのパッケージ フォルダーにインストールされます。

packages.config で、同じ NuGet パッケージ参照を追加します。

  <package id="Newtonsoft.Json" version="13.0.1" targetFramework="native" developmentDependency="true" />

次に、アプリケーション プロジェクト ファイルに以下を追加して、ソリューションのパッケージ フォルダーからの適切なファイルの依存関係を参照します。 たとえば、CppToCSharpWinRT.vcxproj に以下を追加します。

  <ItemGroup>
    <None Include="..\packages\Newtonsoft.Json.13.0.1\lib\netstandard2.0\Newtonsoft.Json.dll">
      <Link>%(Filename)%(Extension)</Link>
      <DeploymentContent>true</DeploymentContent>
    </None>
  </ItemGroup>