在本主題中,我們將解說如何使用 C#/WinRT,從 C++/WinRT Windows 執行階段元件產生 C# .NET 投影(或互操作)程式集,並將其作為 .NET 應用程式的 NuGet 套件進行分發。
在 .NET 6 和更新版本中,不再支援對 Windows 元數據(WinMD)檔案的使用(請參閱 已從 .NET移除內建的 WinRT 支援)。 相反地,C#/WinRT 工具可用來為任何 WinMD 檔案產生投影組件,然後允許從 .NET 應用程式使用 WinRT 元件。 投影元件也稱為 Interop 元件。 本逐步指南說明如何執行下列動作:
- 使用 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++/WinRT Windows 運行時間元件(WRC),以便產生 C# 投射組件。
本逐步解說會使用您已從 GitHub 上的 C#/WinRT 投影範例 下載或複製的 SimpleMathComponent WRC。 SimpleMathComponent 是從 Windows 執行階段元件(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 屬性設為 [是]。 若要這樣做,請在
如需建立 C++/WinRT 元件和產生 WinMD 檔案的詳細步驟,請參閱 使用 C++/WinRT 的 Windows 執行階段元件。
備註
如果您要在元件中實作 IInspectable::GetRuntimeClassName,則 必須 返回有效的 WinRT 類別名稱。 因為 C#/WinRT 使用 Interop 的類別名稱字串,所以不正確的運行時間類別名稱會引發 InvalidCastException。
將投影專案新增至元件方案
首先,在 Visual Studio 中仍開啟 CppWinRTComponentProjectionSample 方案時,請從該解決方案中移除 SimpleMathProjection 專案。 然後從文件系統中刪除 SimpleMathProjection 資料夾(或視需要重新命名)。 這些步驟是必要的,這樣您才能逐步完成此逐步解說。
將新的 C# 連結庫專案新增至您的方案。
- 在 [方案總管]中,以滑鼠右鍵按您的方案節點,然後按一下 [新增>新專案]。
- 在 [新增專案] 對話框中,於搜尋方塊中輸入 類別庫。 從語言清單中選擇 C# ,然後從平臺清單中選擇 [Windows ]。 選擇名為 Class Library 的 C# 專案範本(不含前置詞或後綴),然後點擊 [下一步] 。
- 將新專案命名為 SimpleMathProjection。 位置應該已經設定為與
\CsWinRT\src\Samples\NetProjectionSample
資料夾相同的 資料夾,但請確認。 然後按一下 [下一步]。 - 在 [ 其他資訊] 頁面上,選取 [.NET 6.0(長期支援),然後選擇 [ 建立]。
從專案刪除 存根Class1.cs 檔案。
使用下列步驟來安裝 C#/WinRT NuGet 套件。
- 在
[方案總管] 中,以滑鼠右鍵點擊您的SimpleMathProjection 專案,然後選取 [管理 NuGet 套件]。 - 在 [ 流覽 ] 索引標籤中,輸入或貼上 Microsoft.Windows.CsWinRT 到搜尋方塊中,在搜尋結果中選取具有最新版本的專案,然後按兩下 [ 安裝 ] 將套件安裝到 SimpleMathProjection 專案中。
- 在
在 SimpleMathProjection 中加入對 SimpleMathComponent 專案的參考。 在 [方案總管]中,以滑鼠右鍵按兩下 [SimpleMathProjection 專案] 節點底下的 [相依性] 節點,選取 [[新增專案參考],然後選取 [SimpleMathComponent 專案] >[確定]。
請勿嘗試建置專案。 我們將在稍後的步驟中執行此動作。
到目前為止,您的 方案瀏覽器 看起來應該類似這樣(您的版本號碼會不同)。
從原始碼建置專案
針對
雖然這已經為 CppWinRTComponentProjectionSample 解決方案設定好,但請遵循下列步驟,嘗試自行設定。
若要設定解決方案以在來源以外的目錄中建置:
當
CppWinRTComponentProjectionSample 解決方案仍然開啟時,以滑鼠右鍵按一下方案節點,接著選擇 [新增新項目] 。 選取 XML 檔案 專案,並將它命名為 Directory.Build.props (不含 .xml
擴展名)。 按兩下 [[是] 覆寫現有的檔案。以下列組態取代 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>
儲存並關閉 Directory.Build.props 檔案。
編輯項目檔以執行 C#/WinRT
您必須先編輯項目檔以指定幾個項目屬性,然後才能使用 cswinrt.exe
工具來產生投影組件。
在 [方案總管] 中,按兩下 SimpleMathProjection 節點,在編輯器中開啟項目檔。
將
TargetFramework
元素更新為鎖定特定的 Windows SDK 版本。 這會新增用於 Interop 和投影支援的組件相依性。 此範例針對 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。
新增第二
PropertyGroup
個元素(在第一個元素後面緊接),以設定數個 C#/WinRT 屬性。<PropertyGroup> <CsWinRTIncludes>SimpleMathComponent</CsWinRTIncludes> <CsWinRTGeneratedFilesDir>$(OutDir)</CsWinRTGeneratedFilesDir> </PropertyGroup>
以下是此範例中設定的一些詳細資料:
-
CsWinRTIncludes
屬性指定了要投影的命名空間。 - 屬性
CsWinRTGeneratedFilesDir
設定生成投影源文件的輸出目錄。 此屬性設定為OutDir
,定義於上一節的 Directory.Build.props 中。
-
儲存並關閉 SimpleMathProjection.csproj 檔案,然後按一下以重新載入專案 (如有需要)。
使用投影建立 NuGet 套件
若要將投影元件分發給 .NET 應用程式開發人員,可以在建置方案時,透過新增一些附加的專案屬性,自動建立 NuGet 套件。 針對 .NET 目標,NuGet 套件必須包含投影組件和元件的實作組件。
使用下列步驟將 NuGet 規格 (
.nuspec
) 檔案新增至 SimpleMathProjection 專案。- 在 [方案總管]中,以滑鼠右鍵點擊 [SimpleMathProjection] 節點,選擇 [新增>新資料夾],並將資料夾命名為 nuget。
- 以滑鼠右鍵按兩下 [nuget] 資料夾,選擇 [新增>新增專案],選擇 [XML 檔案],並將它命名 為 simpleMathProjection.nuspec。
在 [方案總管] 中,按兩下 SimpleMathProjection 節點,在編輯器中開啟項目檔。 將以下屬性群組新增到目前開啟的 SimpleMathProjection.csproj (緊接在現有的兩個
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 建立套件。開啟 SimpleMathProjection.nuspec 檔案以編輯套件建立屬性,並貼上下列程式代碼。 以下代碼段是將 SimpleMathComponent 散發至多個目標架構的 NuGet 規格範例。 請注意,指定的是投影組件 SimpleMathProjection.dll,而不是 SimpleMathComponent.winmd,針對目標
lib\net6.0-windows10.0.19041.0\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 都是架構中立的。
儲存並關閉您剛才編輯的檔案。
建置方案以產生投影和 NuGet 套件
在建置解決方案之前,請務必檢查 Visual Studio 中的 Configuration Manager 設定,在 [建置>Configuration Manager] 底下。 在本逐步解說中,將 Configuration 設定為 Release,並將 平臺 設定為 x64。
此時,您現在可以建置解決方案。 右鍵點擊您的解決方案節點,然後選取 [[建置方案]]。 這會先建置 SimpleMathComponent 專案,然後建置 SimpleMathProjection 專案。 元件 WinMD 和實作元件 (SimpleMathComponent.winmd 和 SimpleMathComponent.dll)、投影來源檔案和投影元件 (SimpleMathProjection.dll),全都會在 _build 輸出目錄下產生。 您也可以在 \SimpleMathProjection\nuget 資料夾底下看到產生的 NuGet 套件 SimpleMathComponent0.1.0-prerelease.nupkg。
這很重要
如果未生成上述任何檔案,請重新建置方案。 在重建之前,您可能也需要關閉並重新開啟解決方案。
您可能需要關閉並重新開啟解決方案,以使 .nupkg
如所示出現在 Visual Studio 中(或只需選取然後取消選取「顯示所有檔案」)。
參考 C# .NET 6 控制台應用程式中的 NuGet 套件
若要從 .NET 專案取用 SimpleMathComponent,您只需在新的 .NET 專案中新增對 SimpleMathComponent0.1.0-prerelease.nupkg NuGet 套件的參考,該套件是我們在上一節中創建的即可。 下列步驟示範如何在個別解決方案中建立簡單的控制台應用程式來執行此動作。
使用下列步驟來建立包含 C# 控制台應用程式 專案的新方案(在新方案中建立此專案可讓您獨立還原 SimpleMathComponent NuGet 套件)。
這很重要
我們將在資料夾內建立這個新的
\CsWinRT\src\Samples\NetProjectionSample
專案,您可以在下載或複製 C#/WinRT 投影範例中找到該專案。- 在 Visual Studio 的新實例中,選取 檔案>新增>專案。
- 在 [建立新專案] 對話框中,搜尋 [主控台應用程式] 專案範本。 選擇直接稱為
主控台應用程式 (不含前置詞或後綴)的 C# 專案範本,然後按一下 [下一步]。 如果您使用 Visual Studio 2019,則專案範本是 主控台應用程式。 - 將新專案命名為 SampleConsoleApp,將其位置設定為與
\CsWinRT\src\Samples\NetProjectionSample
和 SimpleMathProjection 資料夾所在的相同 資料夾,然後點擊 [下一步]。 - 在 [ 其他資訊] 頁面上,選取 [.NET 6.0(長期支援),然後選擇 [ 建立]。
在 [方案總管] 中,按兩下SampleConsoleApp節點以開啟SampleConsoleApp.csproj項目檔,然後編輯 和
TargetFramework
屬性,使其看起來如下列清單所示。Platform
若不存在,請新增Platform
元素。<PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net6.0-windows10.0.19041.0</TargetFramework> <Platform>x64</Platform> </PropertyGroup>
當 SampleConsoleApp.csproj 專案檔仍然開啟時,我們接下來會在 SampleConsoleApp 專案中加入對 SimpleMathComponent NuGet 套件的參考。 若要在建置專案時還原 SimpleMathComponent NuGet,您可以使用
RestoreSources
屬性搭配元件方案中 NuGet 資料夾的路徑。 複製下列組態,並將它貼到 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>
這很重要
此上方顯示的
RestoreSources
套件的 路徑設定為../SimpleMathProjection/nuget
。 若您按照本逐步解說的步驟操作,則該路徑是正確的,因此 SimpleMathComponent 和 SampleConsoleApp 專案都應位於同一個資料夾中(此案例中為NetProjectionSample
資料夾)。 如果您做了一些不同的事情,那麼您需要據此調整路徑。 或者,您也可以 將本機 NuGet 套件資料來源新增至您的解決方案。編輯 Program.cs 檔案,以使用 SimpleMathComponent 所提供的功能。
var x = new SimpleMathComponent.SimpleMath(); Console.WriteLine("Adding 5.5 + 6.5 ..."); Console.WriteLine(x.add(5.5, 6.5).ToString());
儲存並關閉您剛才編輯的檔案,並建置並執行主控台應用程式。 您應該會看到下列輸出。
已知問題
- 建置投影專案時,您可能會看到如下的錯誤:錯誤MSB3271在建置專案 “MSIL” 的處理器架構與實作檔案 “x86” 的處理器架構之間不符。\SimpleMathComponent.dll“..\SimpleMathComponent.winmd”。此不符可能會導致運行時間失敗。請考慮透過 Configuration Manager 變更專案的目標處理器架構,以便在專案與實作檔案之間對齊處理器架構,或選擇具有符合專案目標處理器架構之處理器架構的 winmd 檔案。 若要解決此問題,請將下列屬性新增至 C# 連結庫項目檔:
<PropertyGroup> <!-- Workaround for MSB3271 error on processor architecture mismatch --> <ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>None</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch> </PropertyGroup>
進一步考慮
我們示範如何在本主題中建立的 C# 投影 (或 Interop) 元件相當簡單,它與其他元件沒有相依性。 但是,若要為具有 Windows App SDK 類型參考的 C++/WinRT 元件產生 C# 投影,您必須在投影專案中新增對 Windows App SDK NuGet 套件的參考。 如果遺漏任何這類參考,您會看到「找不到類型 <T> 」之類的錯誤。
我們在本主題中執行的另一件事是將投影散發為 NuGet 套件。 目前是必要的。