這個主題會帶你了解如何在你的 C++/WinRT 專案中加入一個簡單的 C# 元件。
Visual Studio 讓你可以輕鬆地在用 C# 或 Visual Basic 撰寫的 Windows 執行階段 元件(WRC)專案中撰寫並部署自訂Windows 執行階段型別,然後從 C++ 應用程式專案中引用該 WRC,並從該應用程式中取得這些自訂型別。
在內部,你的 Windows 執行階段 類型可以使用 UWP 應用程式允許的任何 .NET 功能。
Note
欲了解更多資訊,請參閱 Windows 執行階段 元件搭配 C# 與 Visual Basic 及 .NET 的 UWP 應用程式概覽。
在外部,你的型態成員只能對其參數和回傳值開放 Windows 執行階段 型別。 當你建立解決方案時,Visual Studio 會先建立你的 .NET WRC 專案,然後執行一個建置步驟,建立一個 Windows 的元資料(.winmd)檔案。 這是您的 Windows 執行階段 元件(WRC),Visual Studio 會將其包含在您的應用程式中。
Note
.NET 會自動將一些常用的 .NET 型別,例如原始資料型態和集合型態,映射到其 Windows 執行階段 的對應型態。 這些 .NET 類型可用於 Windows 執行階段 元件的公開介面,並會以對應的 Windows 執行階段 類型顯示給元件使用者。 請參閱 可搭配 C# 和 Visual Basic 使用的 Windows 執行階段 元件。
先決條件
- Windows 10
- Microsoft Visual Studio
建立一個空白應用程式
在 Visual Studio 中,使用 Blank App(C++/WinRT)專案範本建立新專案(WinUI 3 桌面應用程式則使用 Blank App, Packaged(WinUI 3 桌面版)範本)。 確定你使用的是(C++/WinRT)範本,而不是(通用 Windows)範本。
將新專案名稱設為 CppToCSharpWinRT ,這樣你的資料夾結構才會與攻略相符。
在解決方案中新增一個 C# Windows 執行階段 元件
在 Visual Studio 建立元件 project:在 方案總管 中,打開 CppToCSharpWinRT 解決方案的捷徑選單,選擇新增,然後選擇 New Project 以新增一個 C# project 到解決方案中。 在新增 Project 對話框的已安裝範本區塊中,選擇 Visual C#,然後選擇 Windows,最後選擇 Universal。 選擇 Windows 執行階段 Component(Universal Windows)範本,並輸入 SampleComponent 作為專案名稱。
Note
在 新增通用 Windows 平台專案 對話方塊中,選擇 Windows 10 Creators Update(10.0; Build 15063) 作為最低版本。 請參閱下方 的「應用程式最低版本 」章節以獲得更多資訊。
新增 C# GetMyString 方法
在 SampleComponent 專案中,將類別名稱從 Class1 改為 Example。 接著在類別中加入兩個簡單成員:一個私有 int 欄位和一個名為 GetMyString 的實例方法:
public sealed class Example { int MyNumber; public string GetMyString() { return $"This is call #: {++MyNumber}"; } }
Note
預設情況下,該類別會被標記 為公開封印。 你從元件中暴露的所有 Windows 執行階段 類別都必須被封存。
Note
可選:要啟用新加入成員的 IntelliSense,請在 方案總管 中開啟 SampleComponent 專案的捷徑選單,然後選擇建置。
參考 CppToCSharpWinRT 專案中的 C# SampleComponent 元件
在 方案總管 的 C++/WinRT 專案中,開啟「參考」捷徑選單,然後選擇「新增參考」以開啟「新增參考」對話框。 選擇 專案,再選擇 解決方案。 選擇 SampleComponent 專案的勾選框,並選擇 確定 以新增參考。
Note
可選:要啟用 C++/WinRT 專案的 IntelliSense,請在 方案總管 中開啟 CppToCSharpWinRT 專案的捷徑選單,然後選擇建置。
編輯 MainPage.h
在 MainPage.h 專案中開啟,然後新增兩個項目。 先在 #include "winrt/SampleComponent.h" 陳述句末加上 #include 欄位,再加 winrt::SampleComponent::Example 一個欄位到結構體 MainPage 。
// MainPage.h
...
#include "winrt/SampleComponent.h"
namespace winrt::CppToCSharpWinRT::implementation
{
struct MainPage : MainPageT<MainPage>
{
...
winrt::SampleComponent::Example myExample;
...
};
}
Note
在 Visual Studio 中,MainPage.h 列於 MainPage.xaml 底下。
編輯MainPage.cpp
在 MainPage.cpp 中,將 Mainpage::ClickHandler 的實作變更為呼叫 C# 方法 GetMyString。
void MainPage::ClickHandler(IInspectable const&, RoutedEventArgs const&)
{
//myButton().Content(box_value(L"Clicked"));
hstring myString = myExample.GetMyString();
myButton().Content(box_value(myString));
}
執行專案
您現在可以建置並執行專案。 每次點擊按鈕,按鈕上的數字都會遞增。
Tip
在 Visual Studio 建立元件專案:在 方案總管 中,開啟 CppToCSharpWinRT 專案的捷徑選單,選擇屬性,然後在設定屬性中選擇除錯。 如果你想同時除錯 C#(管理)和 C++(原生)程式碼,請將除錯器類型設為 受管理型和原生 。
應用程式最低版本
C# 專案版本的 Application Minimum 將控制用於編譯應用程式的 .NET 版本。 例如,選擇 Windows 10 秋季創作者更新(10.0;版本 16299)或更新版本將啟用 .NET Standard 2.0 及 Windows Arm64 處理器支援。
Tip
我們建議使用低於 16299 的 Application Minimum 版本,以避免在不需要 .NET Standard 2.0 或 Arm64 支援時進行額外的建置設定。
針對 Windows 10 秋季創意者更新(10.0;組建版本 16299)進行設定
請依照以下步驟啟用 .NET Standard 2.0 或 Windows Arm64 支援,這些專案是您 C++/WinRT 專案中引用的 C# 專案。
在 Visual Studio 中,進入 方案總管,開啟 CppToCSharpWinRT 專案的捷徑選單。 選擇 屬性,並將通用 Windows 應用程式最低版本設為 Windows 10 秋季創作者更新 (10.0; 組建 16299)(或更新版本)。 SampleComponent 專案也一樣。
在 Visual Studio 中,打開 CppToCSharpWinRT project 的捷徑選單,並在文字編輯器中選擇 Unload Project 開啟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 目錄中會有一個子目錄,其中包含以 2.2 開頭的已安裝 .NET Native 版本。 在下面的例子中,它為 2.2.12-rel-31116-00。
MSBuild 變數 Directory 範例 DotNetNativeVersion %ProgramFiles(x86)%\Microsoft SDKs\UWPNuGetPackages\Microsoft.Net.Native.Compiler2.2.12-rel-31116-00DotNetNativeSharedLibrary %ProgramFiles(x86)%\Microsoft SDKs\UWPNuGetPackages\runtime.win10-x64.microsoft.net.native.sharedlibrary2.2.8-rel-31116-00UWPCoreRuntimeSdkVersion %ProgramFiles(x86)%\Microsoft SDKs\UWPNuGetPackages\Microsoft.Net.UWPCoreRuntimeSdk2.2.14
Note
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 project的捷徑選單,並選擇重新載入Project。
為 .NET Native 建置
建議用 C# 元件在 .NET 原生環境中建置並測試你的應用程式。 在 Visual Studio 中,打開 CppToCSharpWinRT project 的捷徑選單,並在文字編輯器中選擇 Unload Project 開啟CppToCSharpWinRT.vcxproj。
接著,在 C++ 專案檔中的 Release 與 Arm64 配置中將屬性UseDotNetNativeToolchaintrue設定為。
在Visual Studio 方案總管中,打開 CppToCSharpWinRT project的捷徑選單,選擇重新載入Project。
<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>