C++/WinRT アプリから使用するための C# Windows ランタイム コンポーネントの作成
このトピックでは、シンプルな C# コンポーネントを C++/WinRT プロジェクトに追加する処理を順を追って説明します。
Visual Studio を使用すると、C# または Visual Basic で記述された Windows ランタイム コンポーネント (WRC) プロジェクト内に独自のカスタム Windows ランタイム型を簡単に作成して配置し、次に C++ アプリケーション プロジェクトからその WRC を参照して、そのアプリケーションからそれらのカスタム型を使用することができます。
内部的には、UWP アプリケーションで許可されているすべての .NET 機能をその Windows ランタイム型で使用できます。
注意
詳しくは、「C# および Visual Basic を使用した Windows ランタイム コンポーネント」および「UWP アプリ用 .NET の概要」を参照してください。
外部的には、型のメンバーによってパラメーターと戻り値の Windows ランタイム型のみを公開できます。 ソリューションをビルドすると、Visual Studio によって .NET WRC プロジェクトがビルドされ、Windows メタデータ (.winmd) ファイルを作成するビルド ステップが実行されます。 これが、Visual Studio によってアプリに含められる Windows ランタイム コンポーネント (WRC) です。
注意
.NET により、一般的に使用される .NET の型 (プリミティブ データ型やコレクション型など) が対応する Windows ランタイム型に自動的にマップされます。 .NET のこれら型は、Windows ランタイム コンポーネントのパブリック インターフェイス内で使用でき、対応する Windows ランタイム型としてコンポーネントのユーザーに表示されます。 「C# および Visual Basic を使用した Windows ランタイム コンポーネント」を参照してください。
前提条件
- Windows 10
- Microsoft Visual Studio
空のアプリの作成
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.h
が MainPage.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));
}
プロジェクトを実行する
これでプロジェクトをビルドして実行できるようになりました。 ボタンをクリックするたびに、ボタンの数値が増加します。
ヒント
Visual Studio で、コンポーネント プロジェクトを作成します。ソリューション エクスプローラーで、CppToCSharpWinRT プロジェクトのショートカット メニューを開き、[プロパティ] を選択してから、[構成プロパティ] の下の [デバッグ] をクリックします。 C# (マネージド)と C++ (ネイティブ) の両方のコードをデバッグする場合は、[デバッガーの種類] を " [マネージド] または [ネイティブ] " に設定します。
アプリケーションの最小バージョン
アプリケーションのコンパイルに使用される .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 -->
DotNetNativeVersion
、DotNetNativeSharedLibrary
、および 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)' >= '10.0.16299.0'" Project="$(NugetPath)\Microsoft.Net.UWPCoreRuntimeSdk\$(UWPCoreRuntimeSdkVersion)\build\Microsoft.Net.UWPCoreRuntimeSdk.props" />
<Import Condition="'$(WindowsTargetPlatformMinVersion)' >= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-x86.Microsoft.Net.UWPCoreRuntimeSdk\$(UWPCoreRuntimeSdkVersion)\build\runtime.win10-x86.Microsoft.Net.UWPCoreRuntimeSdk.props" />
<Import Condition="'$(WindowsTargetPlatformMinVersion)' >= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-x64.Microsoft.Net.UWPCoreRuntimeSdk\$(UWPCoreRuntimeSdkVersion)\build\runtime.win10-x64.Microsoft.Net.UWPCoreRuntimeSdk.props" />
<Import Condition="'$(WindowsTargetPlatformMinVersion)' >= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-arm.Microsoft.Net.UWPCoreRuntimeSdk\$(UWPCoreRuntimeSdkVersion)\build\runtime.win10-arm.Microsoft.Net.UWPCoreRuntimeSdk.props" />
<Import Condition="'$(WindowsTargetPlatformMinVersion)' >= '10.0.16299.0'" Project="$(NugetPath)\Microsoft.Net.Native.Compiler\$(DotNetNativeVersion)\build\Microsoft.Net.Native.Compiler.props" />
<Import Condition="'$(WindowsTargetPlatformMinVersion)' >= '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)' >= '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)' >= '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)' >= '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)' >= '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)' >= '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)' >= '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)' >= '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)' >= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-x86.Microsoft.Net.UWPCoreRuntimeSdk\$(UWPCoreRuntimeSdkVersion)\build\runtime.win10-x86.Microsoft.Net.UWPCoreRuntimeSdk.targets" />
<Import Condition="'$(WindowsTargetPlatformMinVersion)' >= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-x64.Microsoft.Net.UWPCoreRuntimeSdk\$(UWPCoreRuntimeSdkVersion)\build\runtime.win10-x64.Microsoft.Net.UWPCoreRuntimeSdk.targets" />
<Import Condition="'$(WindowsTargetPlatformMinVersion)' >= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-arm.Microsoft.Net.UWPCoreRuntimeSdk\$(UWPCoreRuntimeSdkVersion)\build\runtime.win10-arm.Microsoft.Net.UWPCoreRuntimeSdk.targets" />
<Import Condition="'$(WindowsTargetPlatformMinVersion)' >= '10.0.16299.0'" Project="$(NugetPath)\Microsoft.Net.Native.Compiler\$(DotNetNativeVersion)\build\Microsoft.Net.Native.Compiler.targets" />
<Import Condition="'$(WindowsTargetPlatformMinVersion)' >= '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)' >= '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)' >= '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)' >= '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)' >= '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)' >= '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)' >= '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)' >= '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>