使用 C++/WinRT 的 Windows 執行階段元件

本主題說明如何使用 C++/WinRT 來建立及使用 Windows 執行階段元件,此元件是可使用任何 Windows 執行階段語言所建立通用 Windows 應用程式呼叫的元件。

使用 C++/WinRT 建置 Windows 執行階段元件有幾個原因。

  • 在複雜或計算密集型操作中享有 C++ 的效能優勢。
  • 重複使用已撰寫和測試的標準 C++ 程式碼。
  • 將 Win32 功能公開給用 C# 等語言撰寫的通用 Windows 平台 (UWP) 應用程式。

一般來說,當您撰寫 C++/WinRT 元件時,可以使用標準 C++ 程式庫中的類型和內建類型,但在應用程式二進位介面 (ABI) 邊界處除外,其會在另一個 .winmd 套件中的程式碼之間傳遞資料。 在 ABI 中,使用 Windows 執行階段類型。 此外,在 C++/WinRT 程式碼中,使用委派和事件等類型來實作可以從元件引發並以另一種語言處理的事件。 有關 C++/WinRT 的詳細資訊,請參閱 C++/WinRT

本主題的其餘部分將引導您了解如何使用 C++/WinRT 撰寫 Windows 執行階段元件,以及如何從應用程式使用它。

您將在本主題中建置的 Windows 執行階段元件包含一個表示溫度計的執行階段類別。 本主題還會示範一個核心應用程式,它使用溫度計執行時間類別,並呼叫函式來調整溫度。

注意

如需安裝和使用 C++/WinRT Visual Studio 延伸模組 (VSIX) 與 NuGet 套件 (一起提供專案範本和建置支援) 的資訊,請參閱 C++/WinRT 的 Visual Studio 支援

重要

如需支援您了解如何使用 C++/WinRT 使用及撰寫執行階段類別的基本概念和詞彙,請參閱使用 C++/WinRT 使用 API使用 C++/WinRT 撰寫 API

Windows 執行階段元件 dll 的最佳命名做法

重要

本節說明建議您在建置 Windows 執行階段元件的 .dll 檔案 (DLL) 中所使用的命名慣例。 其重點在於使用 Windows 執行階段元件中的執行階段類別時,C++/WinRT 所遵循的啟動順序。

啟動類別處理站時,C++/WinRT 會先嘗試呼叫 RoGetActivationFactory。 如果失敗,C++/WinRT 會嘗試尋找 DLL 以直接載入。 Windows 執行階段啟動始終以完整類別名稱為基礎。 邏輯是移除類別名稱 (從完整類別名稱),然後尋找以剩餘的完整命名空間命名的 DLL。 如果找不到,請移除特定區段名稱,然後重複此步驟。

例如,如果要啟動的類別具有完整名稱 Contoso.Instruments.ThermometerWRC.Thermometer,並且 RoGetActivationFactory 失敗,那麼我們將先尋找 Contoso.Instruments.ThermometerWRC.dll 如果找不到,則會尋找 Contoso.Instruments.dll,然後尋找 Contoso.dll

當找到 DLL (按該順序) 時,我們將使用該 DLL 的 DllGetActivationFactory 進入點來嘗試直接取得處理站 (而不是透過我們第一次嘗試的 RoGetActivationFactory 函式間接取得)。 即便如此,最終結果對於呼叫者和 DLL 來說是無法區分的。

此處理序是完全自動的,無需註冊或使用工具。 如果您要撰寫 Windows 執行階段元件,則只需對 DLL 使用適用於前述處理序的命名慣例。 如果您正在使用 Windows 執行階段元件且其命名不正確,那麼您可以選擇按照描述的方式對其進行重新命名。

建立 Windows 執行階段元件 (ThermometerWRC)

請先在 Microsoft Visual Studio 中,建立新的專案。 建立 Windows 執行階段元件 (C++/WinRT) 專案,並將其命名為 ThermometerWRC (適用於「溫度計 Windows 執行階段元件」)。 確定已將 [將方案和專案放置於同一個目錄] 取消核取。 以 Windows SDK 最新的正式推出版本 (即非預覽版本) 為目標。 為 ThermometerWRC 專案命名可讓您在本主題的其餘步驟中提供最簡單的使用體驗。

尚未建置專案。

新建立的專案中包含一個名為 Class.idl 的檔案。 在方案總管中,將該檔案 Thermometer.idl 重新命名 (重新命名 .idl 檔案也會自動將相依的 .h.cpp 檔案重新命名)。 以下面的清單取代 Thermometer.idl 的內容。

// Thermometer.idl
namespace ThermometerWRC
{
    runtimeclass Thermometer
    {
        Thermometer();
        void AdjustTemperature(Single deltaFahrenheit);
    };
}

儲存檔案。 此專案此刻不會建置完成,但立即建置是實用的做法,因為它會產生原始程式碼檔案,而您會在其中實作 Thermometer 執行階段類別。 因此請繼續並立即建置 (您可預期在這個階段看到的建置錯誤有找不到 Class.hClass.g.h有關)。

在建置程序期間,執行 midl.exe 工具建立元件的 Windows 執行階段中繼資料檔案 (其為 \ThermometerWRC\Debug\ThermometerWRC\ThermometerWRC.winmd)。 然後,執行 cppwinrt.exe 工具 (有 -component 選項) 產生原始碼檔案在撰寫您的元件中支援您。 這些檔案包含虛設常式,可協助您開始實作您在 IDL 中宣告的 Thermometer 執行階段類別。 這些虛設常式為 \ThermometerWRC\ThermometerWRC\Generated Files\sources\Thermometer.hThermometer.cpp

以滑鼠右鍵按一下專案節點,然後按一下 [在檔案總管中開啟資料夾]。 這會在檔案總管中開啟專案資料夾。 然後,從 \ThermometerWRC\ThermometerWRC\Generated Files\sources\ 資料夾將虛設常式檔案 Thermometer.hThermometer.cpp 複製到包含專案檔案的資料夾中,也就是 \ThermometerWRC\ThermometerWRC\ 並取代目的地中的檔案。 現在,我們開啟 Thermometer.hThermometer.cpp 並實作我們的執行階段類別。 在 Thermometer.h 中,將新的私人成員新增至 (「不是」處理站實作) Thermometer 的實作。

// Thermometer.h
...
namespace winrt::ThermometerWRC::implementation
{
    struct Thermometer : ThermometerT<Thermometer>
    {
        ...

    private:
        float m_temperatureFahrenheit { 0.f };
    };
}
...

Thermometer.cpp 中,實作 AdjustTemperature 方法,如下方清單所示。

// Thermometer.cpp
...
namespace winrt::ThermometerWRC::implementation
{
    void Thermometer::AdjustTemperature(float deltaFahrenheit)
    {
        m_temperatureFahrenheit += deltaFahrenheit;
    }
}

您會在 Thermometer.hThermometer.cpp 的頂端看到 static_assert,您需要將其移除。 現在即會建置專案。

如果有任何警告妨礙您建置,則加以解決或將專案屬性 C/C++>一般>視警告為錯誤 設定為 No (/WX-),並再試一次建置專案。

建立核心應用程式 (ThermometerCoreApp) 以測試 Windows 執行階段元件

現在建立新的專案 (在您的 ThermometerWRC 解決方案中,或在新解決方案中)。 建立核心應用程式 (C++/WinRT) 專案,並將它命名為 ThermometerCoreApp。 如果兩個專案位於相同的方案中,請將 ThermometerCoreApp 設定為啟始專案。

注意

如先前所述,Windows 執行階段元件的 Windows 執行階段中繼資料檔案 (命名為 ThermometerWRC的專案) 是建立於 \ThermometerWRC\Debug\ThermometerWRC\ 資料夾中。 該路徑的第一個區段是包含解決方案檔案的資料夾名稱;下一個區段是名為 Debug 的子目錄;最後一個區段是為 Windows 執行階段元件所命名的子目錄。 如果您未將專案命名為 ThermometerWRC,則您的中繼資料檔案將會在 \<YourProjectName>\Debug\<YourProjectName>\ 資料夾中。

現在,在核心應用程式專案 (ThermometerCoreApp) 新增參考,並瀏覽至 \ThermometerWRC\Debug\ThermometerWRC\ThermometerWRC.winmd (或者如果有兩個專案在相同的解決方案中,新增專案對專案參考)。 按一下 [新增],然後按一下 [確定]。 現在建置 ThermometerCoreApp。 萬一您看到承載檔案 readme.txt 不存在的錯誤,請將該檔案從 Windows 執行階段元件專案中排除,進行重建,然後重建 ThermometerCoreApp

在建置程序期間,執行 cppwinrt.exe 工具將被參考的 .winmd 檔案處理到包含投影類型的原始碼檔案中,在使用元件裡支援您。 適用於您元件執行階段類別的投影類型標頭 (名為 ThermometerWRC.h) 會在資料夾 \ThermometerCoreApp\ThermometerCoreApp\Generated Files\winrt\ 中產生。

App.cpp 中包含該標頭。

// App.cpp
...
#include <winrt/ThermometerWRC.h>
...

另外,在 App.cpp 中,加入以下程式碼來具現化 Thermometer 物件 (使用投影類型的預設建構函式),並呼叫溫度計物件上的方法。

struct App : implements<App, IFrameworkViewSource, IFrameworkView>
{
    ThermometerWRC::Thermometer m_thermometer;
    ...
    
    void OnPointerPressed(IInspectable const &, PointerEventArgs const & args)
    {
        m_thermometer.AdjustTemperature(1.f);
        ...
    }
    ...
};

每次點擊視窗時,溫度計物件的溫度都會增加。 如果您想要逐步執行程式碼以確認應用程式確實正在呼叫 Windows 執行階段元件,則可以設定斷點。

下一步

若要為 C++/WinRT Windows 執行階段元件新增更多功能或新的 Windows 執行階段類型,可以採用上述的模式進行。 首先,使用 IDL 定義要公開的功能。 然後在 Visual Studio 中建置專案以產生虛設常式實作。 然後視需要完成實作。 使用 Windows 執行階段元件的應用程式可以看到您在 IDL 中定義的任何方法、屬性和事件。 有關 IDL 的詳細資訊,請參閱 Microsoft 介面定義語言 3.0 簡介

有關如何將事件新增至 Windows 執行階段元件的範例,請參閱使用 C++/WinRT 撰寫事件

疑難排解

徵兆 補救方法
在 C++/WinRT 應用程式中,當取用使用 XAML 的 C# Windows 執行階段元件時,編譯器會產生形式為「'MyNamespace_XamlTypeInfo': 不是 'winrt::MyNamespace' 成員」的錯誤,其中 MyNamespace 是 Windows 執行階段元件命名空間的名稱。 在取用 C++/WinRT 應用程式的 pch.h 中,視適當情況新增 #include <winrt/MyNamespace.MyNamespace_XamlTypeInfo.h> 以取代 MyNamespace