共用方式為


在 Windows 執行階段元件中引發事件

如果您的 Windows 執行階段元件會使用背景執行緒 (背景工作執行緒) 引發具有使用者定義之委派類型的事件,而且您希望 JavaScript 可以接收事件,則可以透過下列其中一種方式實作和 (或) 引發此事件:

  1. (選項 1) 透過 CoreDispatcher 引發事件,將事件封送處理至 JavaScript 執行緒內容。 雖然這通常是最佳選擇,但在某些情況下卻無法提供最佳效能。

  2. (選項 2) 使用 Windows.Foundation.EventHandler<Object> (但是會遺失事件類型資訊)。 如果選項 1 不可行或效能不足,而且您可以接受遺失類型資訊的缺點,那麼選項 2 也是不錯的選擇。

  3. (選項 3) 為元件建立您的專屬 Proxy 和虛設常式 COM 物件。 這個是最難實作的選項,但是對於有需要的案例來說,與選項 1 相比,這個選項不僅可以保留類型資訊,可能還會提供更佳的效能。

如果您僅使用背景執行緒引發事件,卻沒有使用上述任何選項,JavaScript 用戶端就不會接收事件。

背景

所有 Windows 執行階段元件和應用程式基本上都是 COM 物件,無論您使用什麼語言建立都一樣。 在 Windows 應用程式開發介面中,大部分元件都是「敏捷式」(Agile) COM 物件,這些元件使用背景執行緒與 UI 執行緒與物件通訊的能力都相同。 如果 COM 物件無法成為 Agile,則它需要稱為 Proxy 和虛設常式的協助程式物件,協助跨越 UI 執行緒背景的執行緒界限,才能與其他 COM 物件通訊 (從 COM 方面來說,這稱為執行緒 Apartment 之間的通訊)。

Windows 應用程式開發介面中的大部分物件都是敏捷式物件或內建 Proxy 和虛設常式。 不過,您無法為泛型類型 (例如 Windows.Foundation.TypedEventHandler<TSender, TResult>) 建立 Proxy 和虛設常式,因為除非提供類型引數,否則它們都不是完整類型。 如果 JavaScript 用戶端缺少 Proxy 或虛設常式才會有問題,但是如果您希望自己的元件在 JavaScript 以及 C++ 或 .NET 語言中都無法使用,就必須使用下列其中一個選項。

(選項 1) 透過 CoreDispatcher 引發事件

您可以使用 Windows.UI.Core.CoreDispatcher 傳送具有使用者定義委派類型的事件,如此 JavaScript 就可以接收這些事件。 如果不確定要使用哪個選項,請先嘗試這一個。 如果事件的引發和處理之間的延遲情況造成問題,請嘗試其他兩個選項。

下列範例示範如何使用 CoreDispatcher 引發強類型事件。 請注意,類型引數是 Toast 而非 Object。


public event EventHandler<Toast> ToastCompletedEvent;
private void OnToastCompleted(Toast args)
{
    var completedEvent = ToastCompletedEvent;
    if (completedEvent != null)
    {
        completedEvent(this, args);
    }
}

public void MakeToastWithDispatcher(string message)
{
    Toast toast = new Toast(message);
    // Assume you have a CoreDispatcher at class scope.
    // Initialize it here, then use it from the background thread.
    var window = Windows.UI.Core.CoreWindow.GetForCurrentThread();
    m_dispatcher = window.Dispatcher;

    Task.Run( () =>
    {
        if (ToastCompletedEvent != null)
        {
            m_dispatcher.RunAsync(CoreDispatcherPriority.Normal,
            new DispatchedHandler(() =>
            {
                this.OnToastCompleted(toast);
            })); // end m_dispatcher.RunAsync
         }
     }); // end Task.Run
}

(選項 2) 使用 EventHandler<Object>,但是會遺失類型資訊

另一種從背景執行緒傳送事件的方式,是使用 Windows.Foundation.EventHandler<Object> 做為事件的型别。 Windows 會提供這項泛型類型具體安裝,並提供其 Proxy 和虛設常式。 這個選項的缺點是,事件引數的類型資訊和傳送者都會遺失。 C++ 和 .NET 用戶端必須透過文件知道收到事件時要轉換回的類型。 JavaScript 用戶端不需要原始類型資訊, 而是會根據其在中繼資料內的名稱尋找 arg 屬性。

下列範例示範如何在 C# 中使用 Windows.Foundation.EventHandler<Object>

public sealed Class1
{
// Declare the event
public event EventHandler<Object> ToastCompletedEvent;

    // Raise the event
    public async void MakeToast(string message)
    {
        Toast toast = new Toast(message);
        // Fire the event from a background thread to allow this thread to continue 
        Task.Run(() =>
        {
            if (ToastCompletedEvent != null)
            {
                OnToastCompleted(toast);
            }
        });
    }

    private void OnToastCompleted(Toast args)
    {
        var completedEvent = ToastCompletedEvent;
        if (completedEvent != null)
        {
            completedEvent(this, args);
        }
    }
}

在 JavaScript 端使用這個事件的方式如下所示:

toastCompletedEventHandler: function (event) {
        
        var toastType = event.toast.toastType; 
        document.getElementById("toasterOutput").innerHTML = "<p>Made " + toastType + " toast</p>";
    },

(選項 3) 建立您的專屬 Proxy 和虛設常式

如需激發使用者定義之事件類型的潛在效能並保留完整的類型資訊,您必須建立專屬 Proxy 和虛設常式物件並將其內嵌在應用程式套件中。 通常,只有另外兩個選項不適用時才必須使用這個選項,這是極少見的情況。 此外,這個選項也不保證能提供比其他兩個選項更佳的效能。 執際效能取決於諸多因素。 請使用 Visual Studio 分析工具或其他程式碼剖析工具測量應用程式中的執行效能,並且判斷事件是否確實是效能瓶頸。

本文其餘部分將說明如何使用 C# 建立基本的 Windows 執行階段元件,然後使用 C++ 為 Proxy 和虛設常式建立 DLL,讓 JavaScript 使用由元件在非同步作業中引發的 Windows.Foundation.TypedEventHandler<TSender, TResult> 事件 (您也可以使用 C++ 或 Visual Basic 建立元件。 建立 Proxy 和虛設常式的相關步驟都相同)。本逐步解說是以建立 Windows 執行階段同處理序元件範例 (C++/CX) 為基礎,並說明其用途。

本逐步解說包含下列部分:

  1. 建立 Windows 執行階段元件:您將在這部分建立兩個基礎 Windows 執行階段類別。 其中一個類別會公開類型為 Windows.Foundation.TypedEventHandler<TSender, TResult> 的事件,另一個類別則是傳回 JavaScript 做為 TValue 之引數的類型。 除非您完成接下來的步驟,否則這些類別都不能與 JavaScript 通訊。

  2. 撰寫 JavaScript 應用程式:這個應用程式會啟動主要類別物件、呼叫方法,然後處理 Windows 執行階段元件引發的事件。

  3. 為元件的介面產生 GUID:用來產生 Proxy 和虛設常式類別的工具需要這些 GUID。

  4. 產生元件的 IDL 檔案:然後使用 IDL 檔案產生 Proxy 和虛設常式的 C 原始程式碼。

  5. 將 Proxy 和虛設常式程式碼編譯成 DLL

  6. 註冊並使用 Proxy 虛設常式 DLL:註冊 Proxy 虛設常式物件,讓 COM 執行階段能找到並在應用程式專案的 Proxy 虛設常式 DLL 中參考這些物件。

若要建立 Windows 執行階段元件

  1. 在 Visual Studio 的功能表列上,選擇 [檔案] > [新增專案]。 在 [新增專案] 對話方塊中,展開 [JavaScript] > [Windows 市集],然後選取 [空白應用程式]。 將專案命名為 ToasterApplication,然後選擇 [確定] 按鈕。

  2. 將 C# Windows 執行階段元件加入至方案:在 [方案總管] 中開啟方案的捷徑功能表,然後選擇 [加入] > [新增專案]。 展開 [Visual C#] > [Windows 市集],然後選取 [Windows 執行階段元件]。 將專案命名為 ToasterComponent,然後選擇 [確定] 按鈕。 ToasterComponent 將是您在接下來的步驟中建立之元件的根命名空間。

    在 [方案總管] 中開啟方案的捷徑功能表,然後選擇 [屬性]。 在 [屬性頁] 對話方塊的左窗格中選取 [組態屬性],然後將對話方塊頂端的 [組態] 設定為 [偵錯],並將 [平台] 設定為 [x86]、[x64] 或 [ARM]。 選擇 [確定] 按鈕。

    重要

    將 [平台] 設定為 [任何 CPU] 會無法運作,因為它並不適用於您稍後會加入至方案的機器碼架構 Win32 DLL。

  3. 在 [方案總管] 中,將 class1.cs 重新命名為 ToasterComponent.cs,使其符合專案的名稱。 Visual Studio 會自動重新命名檔案中的類別以符合新的檔案名稱。

  4. 在 .cs 檔案中,為 Windows.Foundation 命名空間加上 using 指示詞,以便將 TypedEventHandler 納入範圍。

  5. 需要 Proxy 和虛設常式時,您的元件必須使用介面公開其公用成員。 在 ToasterComponent.cs 中,分別為快顯通知程式及其產生的 Toast 定義介面。

    注意事項注意事項

    在 C# 中,您可以略過此步驟,改為先建立類別,然後開啟其捷徑功能表並選擇 [重構]> [擷取介面]。在產生的程式碼中,手動為介面提供公用存取範圍。

    public interface IToaster
        {
            void MakeToast(String message);
            event TypedEventHandler<Toaster, Toast> ToastCompletedEvent;
    
        }
        public interface IToast
        {
            String ToastType { get; }
        }
    

    IToast 介面包含可擷取用來描述快顯通知類型的字串。 IToaster 介面包含建立快顯通知的方法,以及表示已建立快顯通知的事件。 由於這個事件會傳回快顯通知的特定部分 (也就是類型),因此也稱為具類型事件。

  6. 接著,我們需要類別來實作這些介面,而是必須是公用和密封類別,方便您之後將撰寫的 JavaScript 應用程式進行存取。

    public sealed class Toast : IToast
        {
            private string _toastType;
    
            public string ToastType
            {
                get
                {
                    return _toastType;
                }
            }
            internal Toast(String toastType)
            {
                _toastType = toastType;
            }
    
        }
        public sealed class Toaster : IToaster
        {
            public event TypedEventHandler<Toaster, Toast> ToastCompletedEvent;
    
            private void OnToastCompleted(Toast args)
            {
                var completedEvent = ToastCompletedEvent;
                if (completedEvent != null)
                {
                    completedEvent(this, args);
                }
            }
    
            public void MakeToast(string message)
            {
                Toast toast = new Toast(message);
                // Fire the event from a thread-pool thread to enable this thread to continue 
                Windows.System.Threading.ThreadPool.RunAsync(
                (IAsyncAction action) =>
                {
                    if (ToastCompletedEvent != null)
                    {
                        OnToastCompleted(toast);
                    }
                });
            }
        }
    

    在上述程式碼中,我們建立了快顯通知,然後備妥執行緒集區工作項目以引發告知。 雖然 IDE 可能會建議您將 await 關鍵字套用至非同步呼叫,但是這種情況下不必這麼做,因為方法不會執行任何取決於作業結果的工作。

    重要

    上述程式碼中的非同步呼叫會單獨使用 ThreadPool.RunAsync,示範以簡單的方式使用背景執行緒引發事件。您可以如下列範例所示撰寫這個特殊的方法,因為 .NET 工作排程器會自動將非同步/等候呼叫封送處理回 UI 執行緒,所以這個方法可以正常運作。

    public async void MakeToast(string message)
    {
        Toast toast = new Toast(message)
        await Task.Delay(new Random().Next(1000));
        OnToastCompleted(toast);
    }
    

    如果您現在就建置專案,應該沒有問題。

若要撰寫 JavaScript 應用程式

  1. 現在我們可以將按鈕加入至 JavaScript 應用程式,讓它使用我們剛才定義的類別建立快顯通知。 在這麼做之前,我們必須加入剛才所建立 ToasterComponent 專案的參考。 在 [方案總管] 中,開啟 ToasterApplication 專案的捷徑功能表,依序選擇 [新增] > [參考],然後選擇 [加入新參考] 按鈕。 在 [加入參考] 對話方塊的左窗格中,選取 [方案] 底下的元件專案,然後選取中間窗格內的 [ToasterComponent]。 選擇 [確定] 按鈕。

  2. 在 [方案總管] 中開啟 ToasterApplication 專案的捷徑功能表,然後選擇 [設定為啟始專案]。

  3. 在 default.js 檔案的結尾加入命名空間,以包含元件的呼叫函式及其回呼函式。 命名空間將包含兩個函式,一個是建立快顯通知的函式,另一個是處理快顯通知完成事件的函式。 makeToast 的實作會建立 Toaster 物件、註冊事件處理常式,以及建立快顯通知。 到目前為止,事件處理常式還沒做什麼事,如下所示:

    WinJS.Namespace.define("ToasterApplication", {
            makeToast: function () {
    
                var toaster = new ToasterComponent.Toaster();
            //toaster.addEventListener("ontoastcompletedevent", ToasterApplication.toastCompletedEventHandler);
            toaster.ontoastcompletedevent = ToasterApplication.toastCompletedEventHandler;
            toaster.makeToast("Peanut Butter");
    
            },
    
            toastCompletedEventHandler: function (event) {
                // The sender of the event (the delegate’s first type parameter)
                // is mapped to event.target. The second argument of the delegate
                // is contained in event, which means event in this case is a 
                // Toast class, with a toastType string.
                var toastType = event.toastType;
    
                document.getElementById("toasterOutput").innerHTML = "<p>Made " + toastType + " toast</p>";
            },
    
        }); 
    
  4. makeToast 函式必須連接到按鈕。 請更新 default.html 內容,在其中加入按鈕和一些空間,方便輸出快顯通知的建立結果:

    <body>
        <h1>Click the button to make toast</h1>
        <button onclick="ToasterApplication.makeToast()">Make Toast!</button>
        <div id="toasterOutput">
            <p>No Toast Yet...</p>
        </div>
    </body>
    

    如果不使用 TypedEventHandler,我們現在就可以在本機電腦上執行應用程式,並且按一下按鈕建立快顯通知。 但是,我們的應用程式中則不會發生任何事。 如需了解原因,我們就必須偵錯引發 ToastCompletedEvent 的 Managed 程式碼。 請停止專案,然後選擇功能表列上的 [偵錯] > [快顯通知程式應用程式屬性]。 將 [偵錯工具類型] 變更為 [僅限 Managed]。 再次選擇功能表列上的 [偵錯] > [例外狀況],然後選取 [Common Language Runtime 例外狀況]。

    現在,執行應用程式並按一下快顯通知建立按鈕。 偵錯工具隨即攔截無效的轉型例外狀況。 雖然從這個例外狀況的訊息中看不出問題,但是發生原因是因為介面的 Proxy 已遺失。

    指出遺失 Proxy 的偵錯工具錯誤視窗

若要為元件建立 Proxy 和虛設常式,首先必須加入介面的唯一識別碼或 GUID。 不過,要使用的 GUID 格式會根據您的撰寫語言是 C#、Visual Basic、C++ 或其他 .NET 語言而異。

若要為元件的介面產生 GUID

  • C#、Visual Basic 或其他 .NET 語言:

    1. 選擇功能表列上的 [工具] > [建立 GUID]。 在對話方塊中,依序選取 [5. [GUID(“xxxxxxxx-xxxx...xxxx)]]、 、[新增 GUID] 按鈕和 [複製] 按鈕。

    2. 返回介面定義,然後在 IToaster 介面之前貼上這個新 GUID,如下列範例所示 (請勿使用這個範例中的 GUID, 每個唯一的介面應該有其專屬 GUID)。

      [Guid("FC198F74-A808-4E2A-9255-264746965B9F")]
          public interface IToaster...
      
    3. 加入 System.Runtime.InteropServices 命名空間的 using 指示詞。

    4. IToast 介面重複執行上述步驟。

  • C++:

    1. 選擇功能表列上的 [工具] > [建立 GUID]。 在對話方塊中,依序選取 [3. static const struct GUID = {…}]、 、[新增 GUID] 按鈕和 [複製] 按鈕。

      Visual Studio 中的 GUID 產生器

    2. IToaster 介面定義之前貼上 GUID。 貼上之後,GUID 應該類似下列範例 (請勿使用這個範例中的 GUID, 每個唯一的介面應該有其專屬 GUID)。

      // {F8D30778-9EAF-409C-BCCD-C8B24442B09B}
          static const GUID <<name>> = { 0xf8d30778, 0x9eaf, 0x409c, { 0xbc, 0xcd, 0xc8, 0xb2, 0x44, 0x42, 0xb0, 0x9b } };
      
    3. 加入 Windows.Foundation.Metadata 的 using 指示詞,將 GuidAttribute 納入範圍。

    4. 現在,手動將常數 GUID 轉換為 GuidAttribute,其格式如下列範例所示。 請注意,要使用圓弧括弧和方括弧取代大括號,並移除尾端的分號。

      // {E976784C-AADE-4EA4-A4C0-B0C2FD1307C3}
          [GuidAttribute(0xe976784c, 0xaade, 0x4ea4, 0xa4, 0xc0, 0xb0, 0xc2, 0xfd, 0x13, 0x7, 0xc3)]
          public interface IToaster
          {...
      
    5. IToast 介面重複執行上述步驟。

現在介面都已經有唯一識別碼,我們就可以在 winmdidl 命令列工具中填入 .winmd 檔案來建立 IDL 檔案,然後在 MIDL 命令列工具中填入 IDL 檔案來產生 Proxy 和虛設常式的 C# 原始程式碼。 如下列步驟所示,如果我們建立建置後事件,Visual Studio 就能為我們執行上述工作。

若要產生 Proxy 和虛設常式原始程式碼

  1. 若要加入自訂建置後事件,請在 [方案總管] 中開啟 ToasterComponent 專案的捷徑功能表,然後選擇 [屬性]。 在屬性頁的左窗格中,選取 [建置事件],然後選擇 [建置後進行編輯] 按鈕。 在建置後命令列中加入下列命令 (您必須先呼叫批次檔,設定環境變數以尋找 winmdidl 工具)。

    call "$(DevEnvDir)..\..\vc\vcvarsall.bat" $(PlatformName)
    winmdidl /outdir:output "$(TargetPath)"
    midl /metadata_dir "%WindowsSdkDir%References\CommonConfiguration\Neutral" /iid "$(ProjectDir)$(TargetName)_i.c" /env win32 /h "$(ProjectDir)$(TargetName).h" /winmd "Output\$(TargetName).winmd" /W1 /char signed /nologo /winrt /dlldata "$(ProjectDir)dlldata.c" /proxy "$(ProjectDir)$(TargetName)_p.c" "Output\$(TargetName).idl"
    
    
    

    重要

    如果是 ARM 或 x64 專案組態,請將 MIDL /env 參數的值變更為 x64 或 arm32。

  2. 為了確保每次變更 .winmd 檔案時都會重新產生 IDL 檔案,請將 [執行建置後事件] 變更為 [當組建更新專案輸出時]。

    [建置事件] 屬性頁看起來應該如下:

    Visual Studio [屬性] 頁面中的建置後步驟

  3. 重建方案以產生和編譯 IDL。

    如果 ToasterComponent 專案目錄中有 ToasterComponent.h、ToasterComponent_i.c、ToasterComponent_p.c 和 dlldata.c,就表已正確編譯 MIDL。

若要將 Proxy 和虛設常式程式碼編譯成 DLL

  1. 現在您已經有了必要的檔案,就可以編譯它們以產生 DLL (C++ 檔案)。 為了讓這個步驟盡可能簡單化,請加入新專案以支援 Proxy 建置工作。 開啟 ToasterApplication 方案的捷徑功能表,然後選擇 [加入] > [新增專案]。 在 [新增專案] 對話方塊的左窗格中,展開 [Visual C++] > [Windows 市集],然後選取中間窗格內的 [DLL (Windows 市集應用程式)] (請注意,這並不是 C++ Windows 執行階段元件專案)。將專案命名為 Proxies,然後選擇 [確定] 按鈕。 當 C# 類別的內容變更時,建置後事件就會更新這些檔案。

  2. 根據預設,Proxies 專案會產生標頭 .h 檔案和 C++ .cpp 檔案。 由於 DLL 是由 MIDL 產生的檔案所建置,因此我們不需要 .h 和 .cpp 檔案。 在 [方案總管] 中開啟這兩個檔案的捷徑功能表,然後選擇 [移除] 並確認將其刪除。

  3. 現在我們已清空專案,您可以加回 MIDL 產生的檔案。 開啟 Proxies 專案的捷徑功能表,然後選擇 [加入] > [現有項目]。 在對話方塊中,巡覽至 ToasterComponent 專案目錄並選取下列檔案:ToasterComponent.h、ToasterComponent_i.c、ToasterComponent_p.c 和 dlldata.c。 選擇 [加入] 按鈕。

  4. 在 Proxies 專案中建立 .def 檔,定義 dlldata.c 中描述的 DLL 匯出。 開啟專案的捷徑功能表,然後選擇 [加入] > [新增項目]。 在對話方塊的左窗格中選取 [程式碼],然後選取中間窗格內的 [模組定義檔]。 將檔案命名為 proxies.def,然後選擇 [加入] 按鈕。 開啟並修改這個 .def 檔案,加入 dlldata.c 中定義的 EXPORTS:

    EXPORTS
        DllCanUnloadNow         PRIVATE
        DllGetClassObject       PRIVATE
    
  5. 如果您現在就建置專案,建置會失敗。 若要正確編譯此專案,您必須變更專案的編譯及連結方式。 在 [方案總管] 中開啟 Proxies 專案的捷徑功能表,然後選擇 [屬性]。 變更屬性頁內容,如下所示:

    • 在左窗格中選取 [C/C++] > [前置處理器],然後在右窗格中選取 [前置處理器定義],再選擇向下鍵按鈕,然後選取 [編輯]。 在方塊中輸入下列定義:

      WIN32;_WINDOWS
      
    • 在 [C/C++] > [先行編譯標頭檔] 底下,將 [先行編譯標頭檔] 變更為 [未使用先行編譯標頭檔],然後選擇 [套用] 按鈕。

    • 在 [連結器] > [一般] 底下,將 [忽略匯入程式庫] 變更為 [],然後選擇 [套用] 按鈕。

    • 在 [連結器] > [輸入] 底下,選取 [其他相依性],然後選擇向下鍵按鈕,再選取 [編輯]。 在方塊中加入下列文字:

      rpcrt4.lib;runtimeobject.lib
      

      不要在清單資料列中直接貼上上述程式庫。 請使用 [編輯] 方塊確保 Visual Studio 中的 MSBuild 會維護正確的其他相依性。

    執行上述變更之後,請選擇 [屬性頁] 對話方塊中的 [確定] 按鈕。

  6. 接著,我們要使用 ToasterComponent 專案的相依性,這麼做可確保 Toaster 會在 Proxy 專案之前建置。 我們必須這麼做,因為 Toaster 專案是負責產生用來建置 Proxy 的檔案。

    開啟 Proxies 專案的捷徑功能表,然後選擇 [專案相依性]。 選取核取方塊,表示 Proxies 專案相依於 ToasterComponent 專案,確定 Visual Studio 會以正確的順序建置這兩個專案。

  7. 選擇 Visual Studio 功能表列上的 [建置] > [重建方案],確定正確建置方案。

若要註冊 Proxy 和虛設常式

  1. 在 ToasterApplication 專案中,開啟 package.appxmanifest 的捷徑功能表,然後選擇 [開啟方式...]。 選取 [開啟方式...] 對話方塊中的 [XML 文字編輯器],然後選擇 [確定] 按鈕。 我們將貼上一些 XML 內容,這些內容可提供 windows.activatableClass.proxyStub 擴充功能註冊資訊,而這些資訊是以 Proxy 中的 GUID 為基礎。 若要尋找用於 .appxmanifest 檔案中的 GUID,請開啟 ToasterComponent_i.c, 然後尋找類似下列範例中的項目。 此外,請注意 IToastIToaster 和第三個介面 (具有 Toaster 和 Toast 參數的具類型事件處理常式) 的定義。 該處理常式符合在 Toaster 類別中定義的事件。 請注意,IToastIToaster 的 GUID 符合 C# 檔案中針對介面定義的 GUID。 因為具類型事件處理常式介面會自動產生,所以這個介面的 GUID 也會自動產生。

    MIDL_DEFINE_GUID(IID, IID___FITypedEventHandler_2_ToasterComponent__CToaster_ToasterComponent__CToast,0x1ecafeff,0x1ee1,0x504a,0x9a,0xf5,0xa6,0x8c,0x6f,0xb2,0xb4,0x7d);
    
    
    MIDL_DEFINE_GUID(IID, IID___x_ToasterComponent_CIToast,0xF8D30778,0x9EAF,0x409C,0xBC,0xCD,0xC8,0xB2,0x44,0x42,0xB0,0x9B);
    
    
    MIDL_DEFINE_GUID(IID, IID___x_ToasterComponent_CIToaster,0xE976784C,0xAADE,0x4EA4,0xA4,0xC0,0xB0,0xC2,0xFD,0x13,0x07,0xC3);
    

    現在我們要複製 GUID 並於我們在 package.appxmanifest 中加入且命名為 Extensions 的節點內貼上,然後再重新設定這些 GUID 的格式。 資訊清單項目與下列範例類似,但是再次提醒您,請記得使用您的專屬 GUID。 請注意,XML 中的 ClassId GUID 與 ITypedEventHandler2 相同, 因為它是在 ToasterComponent_i.c 中列出的第一個 GUID。 這裡的 GUID 不區分大小寫。 您可以返回介面定義中並取得 GuidAttribute 值 (因為它具有正確的格式),而不必手動重新設定 IToastIToaster 的 GUID 格式。 在 C++ 中,註解裡有格式正確的 GUID。 無論如何,您都必須手動重新設定用於 ClassId 和事件處理常式之 GUID 的格式。

    <Extensions> <!—Use your own GUIDs!!!-->
        <Extension Category="windows.activatableClass.proxyStub">
          <ProxyStub ClassId="1ecafeff-1ee1-504a-9af5-a68c6fb2b47d">
            <Path>Proxies.dll</Path>
            <Interface Name="IToast" InterfaceId="F8D30778-9EAF-409C-BCCD-C8B24442B09B"/>
            <Interface Name="IToaster"  InterfaceId="E976784C-AADE-4EA4-A4C0-B0C2FD1307C3"/>  
            <Interface Name="ITypedEventHandler_2_ToasterComponent__CToaster_ToasterComponent__CToast" InterfaceId="1ecafeff-1ee1-504a-9af5-a68c6fb2b47d"/>
          </ProxyStub>      
        </Extension>
      </Extensions>
    

    將 Extensions XML 節點當做 Package 節點的直接子系以及像是 Resources 節點的對等節點貼上。

  2. 在繼續之前,下列條件務必要成立:

    • 在 ToasterComponent_i.c 檔案中,將 ProxyStub ClassId 設定為第一個 GUID。 請使用這個檔案中定義的第一個 GUID 做為 ClassId (這可能與 ITypedEventHandler2 的 GUID 相同)。

    • Path 是 Proxy 二進位檔案的封裝相對路徑 (在本逐步解說中,proxies.dll 與 ToasterApplication.winmd 都位於相同資料夾)。

    • GUID 的格式正確 (這部分很容易出錯)。

    • 資訊清單中的介面識別碼與 ToasterComponent_i.c 檔案中的 IID 相符。

    • 資訊清單中的介面名稱都是唯一名稱。 由於系統不會使用這些名稱,所以您可以選擇值。 最好是選擇與您定義之介面完全相符的介面名稱。 如果是產生的介面,名稱應該要能夠表示這是產生的介面。 您可以使用 ToasterComponent_i.c 檔案協助產生介面名稱。

  3. 如果您嘗試現在就執行方案,將會發生 proxies.dll 不是承載一部分的錯誤。 在 ToasterApplication 專案中開啟 [參考] 資料夾的捷徑功能表,然後選擇 [加入參考]。 選取 Proxies 專案旁邊的核取方塊。 此外,也請確定已選取 ToasterComponent 旁邊的核取方塊。 選擇 [確定] 按鈕。

    現在應該可以建置專案了。 請執行專案並確認是否可以建立快顯通知。