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

注意

有關在 C++/WinRT Windows 執行階段元件中引發事件的詳細資訊,請參閱使用 C++/WinRT 撰寫事件

如果您的 Windows 執行階段元件在背景執行緒 (工作執行緒) 上引發使用者定義的委派類型事件,並且您希望 JavaScript 能夠接收該事件,那麼您可以使用一下任一方法實作和/或引發該事件。

  • (選項 1) 透過 Windows.UI.Core.CoreDispatcher 引發事件,以將事件封送到 JavaScript 執行緒內容。 雖然這通常是最佳選擇,但在某些情況下它可能無法提供最快的效能。
  • (選項 2) 使用 Windows.Foundation.EventHandler<Object> (但會遺失事件類型資訊)。 如果選項 1 不可行,或者其效能不夠,那麼這會是個不錯的次要選擇,前提是要能接受類型資訊遺失。 如果您要撰寫 C# Windows 執行階段元件,則會無法使用 Windows.Foundation.EventHandler<Object> 類型; 相反地,該類型會投影到 System.EventHandler,因此您應該改用它。
  • (選項 3) 為元件建立您自己的 Proxy 和虛設常式。 此選項最難實作,但它保留了類型資訊,並且在要求較高的情境中,它也許能比選項 1 提供更好的效能。

如果您只是在背景執行緒上引發事件而不使用這些選項之一,則 JavaScript 用戶端將不會收到該事件。

背景

所有 Windows 執行階段元件和應用程式從根本上來說都是 COM 物件,無論您使用什麼語言來建立它們。 在 Windows API 中,大多數元件都是敏捷式 COM 物件,它們同樣可以與背景執行緒和 UI 執行緒上的物件進行順暢的通訊。 如果 COM 物件無法設為敏捷形式,那麼它需要稱為 Proxy 和虛設常式的輔助物件來跨 UI 執行緒-背景執行緒邊界與其他 COM 物件進行通訊。 (在 COM 術語中,這稱為執行緒 Apartment 之間的通訊。)

Windows API 中的大多數物件要不是敏捷式,就是具有內建的 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>,但會遺失類型資訊

注意

如果您要撰寫 C# Windows 執行階段元件,則會無法使用 Windows.Foundation.EventHandler<Object> 類型; 相反地,該類型會投影到 System.EventHandler,因此您應該改用它。

另一種從背景執行緒發送事件的方法是使用 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) 為基礎,並協助說明其用途。

本逐步說明包含以下部分。

  • 在這裡,您將建立兩個基本的 Windows 執行階段類別。 一個類別公開 Windows.Foundation.TypedEventHandler<TSender, TResult> 類型的事件,另一個類別會作為 TValue 參數傳回到 JavaScript 的類型。 除非您完成後面的步驟,這些類別才能與 JavaScript 通訊。
  • 此應用程式會啟動主類別物件、呼叫方法,並處理由 Windows 執行階段元件引發的事件。
  • 這些是產生 Proxy 和虛設常式類別的工具所需要的。
  • 然後,您可以使用 IDL 檔案產生 Proxy 和虛設常式的 C 原始程式碼。
  • 註冊 proxy-stub 物件,以便 COM 執行階段可以找到它們,並在應用程式項目中引用 proxy-stub DLL。

若要建立 Windows 執行階段元件

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

將 C# Windows 執行階段元件新增至解決方案:在方案總管中,開啟解決方案的捷徑功能表,然後選擇新增>新專案。 展開 Visual C# >Microsoft Store,然後選擇 Windows 執行階段元件。 將專案命名為 ToasterComponent,然後選擇確定按鈕。 ToasterComponent 將是您將在後續步驟中建立的元件的根命名空間。

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

重要:Platform = Any CPU 無法運作,因為它對於稍後要新增到解決方案中的原生程式碼 Win32 DLL 無效。

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

在 .cs 檔案中,為 Windows.Foundation 命名空間新增 using 指令,以將 TypedEventHandler 納入範圍。

當您需要 Proxy 和虛設常式時,您的元件必須使用介面來公開其公用成員。 在 ToasterComponent.cs 中,為快顯通知工具定義一個介面,並為快顯通知工具產生的快顯通知定義另一個介面。

注意:在 C# 中可以跳過此步驟。 先建立一個類別,然後打開其捷徑功能表,並選擇重構>提取介面。 在產生的程式碼中,手動為介面提供公用協助工具。

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

        }
        public interface IToast
        {
            String ToastType { get; }
        }

IToast 介面有一個字串,可以擷取該字串來描述快顯通知的類型。 IToaster 介面有一個製作快顯通知的方法,以及一個指示快顯通知已製作的事件。 由於此事件傳回快顯通知的特定片段 (即類型),因此稱為類型化事件。

接下來,我們需要實作這些介面的類別,且這些類別是公用且密封的,以便可以從稍後編程的 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 工作排程器會自動將非同步/await 呼叫封送回 UI 執行緒。  

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

如果您現在建置該專案,它應該會完整建置。

若要對 JavaScript 應用程式進行程式設計

現在,我們可以為 JavaScript 應用程式新增一個按鈕,使其使用我們剛剛定義的類別來製作快顯通知。 在這麼做之前,我們必須新增剛才建立之 ToasterComponent 項目的參考。 在方案總管中,開啟 ToasterApplication 專案的捷徑功能表,選擇新增>參考,然後選擇新增參考按鈕。 在「新增參考」對話方塊的左窗格中的「解決方案」下,選擇元件專案,然後在中間窗格中選擇「ToasterComponent」。 選擇 [確定] 按鈕。

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

在 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 in this case event is a
           // Toast class, with a toastType string.
           var toastType = event.toastType;

           document.getElementById('toastOutput').innerHTML = "<p>Made " + toastType + " toast</p>";
        },
    });

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 的受控程式碼。 停止專案,然後在功能表列上選擇偵錯 >Toaster Application 屬性。 將偵錯工具類型變更為僅限受控。 再次在功能表列上選擇偵錯>例外狀況,然後選擇公用語言執行階段例外狀況

現在執行應用程式,然後按一下 [製作快顯通知] 按鈕。 偵錯工具會擷取無效的投射例外狀況。 儘管從訊息中看不出來,但發生此例外狀況是因為該介面缺少 Proxy。

missing proxy

為元件建立 Proxy 和虛設常式的第一步是向介面新增唯一識別碼或 GUID。 但是,要使用的 GUID 格式會有所不同,這取決於您是使用 C#、Visual Basic、其他 .NET 語言還是 C++ 進行編碼。

為元件的介面產生 GUID (C# 和其他 .NET 語言)

在功能表列上,選擇 [工具 > 建立 GUID]。 在對話方塊中選取 5。 [Guid("xxxxxxxx-xxxx...xxxx")]. 選擇 [新 GUID] 按鈕,然後選擇 [複製] 按鈕。

guid generator tool

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

[Guid("FC198F74-A808-4E2A-9255-264746965B9F")]
        public interface IToaster...

為 System.Runtime.InteropServices 命名空間新增 using 指示詞。

對 IToast 介面重複這些步驟。

為元件介面產生 GUID (C++)

在功能表列上,選擇 [工具 > 建立 GUID]。 在對話方塊中選取 3。 靜態常數結構 GUID = {...}。 選擇 [新 GUID] 按鈕,然後選擇 [複製] 按鈕。

將 GUID 貼上到 IToaster 介面定義之前。 貼上後,GUID 看起來應該會像以下範例。 (請勿在範例中使用 GUID。每個唯一介面都應該有自己的 GUID。)

// {F8D30778-9EAF-409C-BCCD-C8B24442B09B}
    static const GUID <<name>> = { 0xf8d30778, 0x9eaf, 0x409c, { 0xbc, 0xcd, 0xc8, 0xb2, 0x44, 0x42, 0xb0, 0x9b } };

為 Windows.Foundation.Metadata 新增 using 指示詞,以將 GuidAttribute 帶入範圍。

現在,手動將常數 GUID 轉換為 GuidAttribute,使其格式如以下範例所示。 請注意,大括號已替換為方括號和圓括號,並且末尾的分號已刪除。

// {E976784C-AADE-4EA4-A4C0-B0C2FD1307C3}
    [GuidAttribute(0xe976784c, 0xaade, 0x4ea4, 0xa4, 0xc0, 0xb0, 0xc2, 0xfd, 0x13, 0x7, 0xc3)]
    public interface IToaster
    {...

對 IToast 介面重複這些步驟。

現在介面已經具有唯一識別碼,我們可以透過將 .winmd 檔案輸入 winmdidl 命令列工具來建立 IDL 檔案,然後透過將該 IDL 檔案輸入 MIDL 命令列工具來產生 Proxy 和虛設常式的 C 原始程式碼。 如果我們建立建置後事件,則 Visual Studio 會為我們執行此動作,如下列步驟所示。

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

若要新增自訂建置後事件,請在「方案總管」中開啟 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。

若要確保每次變更 .winmd 檔案時都會重新產生 IDL 文件,請將執行建置後事件變更為當建置更新專案輸出時。建置事件屬性頁面應該會像這樣:build events

重建解決方案以產生並編譯 IDL。

您可以透過在 ToasterComponent 專案目錄中尋找 ToasterComponent.h、ToasterComponent_i.c、ToasterComponent_p.c 和 dlldata.c 來驗證 MIDL 是否正確編譯了解決方案。

將 Proxy 和虛設常式程式碼編譯到 DLL 中

現在您已經有了所需的檔案,您可以編譯它們以產生 DLL,也就是 C++ 檔案。 若要盡量簡化此作業,請新增一個專案來支援建置 Proxy。 開啟 ToasterApplication 解決方案的捷徑功能表,然後選擇新增>新專案。 在新專案對話方塊的左側窗格中,展開 Visual C++ >Windows >通用 Windows,然後在中間窗格中選擇 DLL (UWP 應用程式)。 (請注意,這不是 C++ Windows 執行階段元件專案。) 將專案命名為 Proxy,然後選擇確定按鈕。 當 C# 類別發生變更時,這些檔案將透過建置後事件進行更新。

預設情況下,Proxy 專案會產生標頭 .h 檔案和 C++ .cpp 檔案。 由於 DLL 是根據 MIDL 產生的檔案所建置,因此不需要 .h 和 .cpp 檔案。 在方案總管中,開啟專案其捷徑功能表,選擇移除,然後確認刪除。

現在該專案應該是空的,您可以新增 MIDL 產生的檔案。 開啟 Proxy 專案的捷徑功能表,然後選擇新增>現有項目。在對話方塊中,瀏覽至 ToasterComponent 專案目錄,然後選擇以下檔案:ToasterComponent.h、ToasterComponent_i.c、ToasterComponent_p.c 和 dlldata.c 檔案。 選擇 [ 加入 ] 按鈕。

在 Proxy 專案中,建立 .def 檔案來定義 dlldata.c 中所述的 DLL 匯出。 開啟專案的捷徑功能表,然後選擇新增>新項目。 在對話方塊的左側窗格中,選取 [程式碼],然後在中間窗格中選擇 [模組定義檔案]。 為檔案 proxies.def 命名,然後選擇新增按鈕。 打開此 .def 檔案並加以修改,以包含 dlldata.c 中定義的 EXPORTS:

EXPORTS
    DllCanUnloadNow         PRIVATE
    DllGetClassObject       PRIVATE

如果您現在建置該專案,作業將會失敗。 若要正確編譯此專案,您必須變更專案的編譯和連結方式。 在方案總管中,開啟 Proxy 的捷徑功能表,然後選擇屬性。 按照以下方式變更屬性頁面。

在左側窗格中,選擇 C/C++ >前置處理器,然後在右側窗格中選擇前置處理器定義,選擇向下箭頭按鈕,然後選擇編輯。 在方塊中新增以下定義:

WIN32;_WINDOWS

C/C++ >先行編譯標頭檔底下,將先行編譯標頭檔變更為不使用先行編譯標頭檔,然後選擇套用按鈕。

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

連結器>輸入底下,選擇其他相依性,選擇向下箭頭按鈕,然後選擇編輯。 在方塊中新增此文字:

rpcrt4.lib;runtimeobject.lib

請勿將這些程式庫直接貼到清單列中。 使用編輯方塊確保 Visual Studio 中的 MSBuild 將維護正確的其他相依性。

進行這些變更後,請選擇屬性頁面對話方塊中的確定按鈕。

接下來,取得 ToasterComponent 專案的相依性。 這確保了 Toaster 將在 Proxy 專案建置之前建置。 這是必要動作,因為 Toaster 專案負責產生用於建立 Proxy 的檔案。

開啟 Proxy 專案的捷徑功能表,然後選擇 [專案相依性]。 選取核取方塊以指示 Proxy 專案相依於 ToasterComponent 專案,以確保 Visual Studio 以正確的順序建置它們。

透過在 Visual Studio 功能表列上選擇建置>重建解決方案來驗證解決方案是否正確建置。

註冊 Proxy 和虛設常式

在 ToasterApplication 專案中,開啟 package.appxmanifest 的捷徑功能表,然後選擇開啟方式。 在「開啟方式」對話方塊中,選擇 XML 文字編輯器,然後選擇確定按鈕。 我們將貼上一些 XML,提供 windows.activatableClass.proxyStub 擴充註冊,並且這些 XML 是以 Proxy 中的 GUID 為基礎。 若要尋找要在 .appxmanifest 檔案中使用的 GUID,請開啟 ToasterComponent_i.c。 尋找類似以下範例中的項目。 另請注意 IToast、IToaster 和第三個介面 (具有兩個參數的類型化事件處理常式):Toaster 和 Toast 的定義。 這與 Toaster 類別中定義的事件相符。 請注意,IToast 和 IToaster 的 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。 請注意,XML 中的 ClassId GUID 與 ITypedEventHandler2 相同。 這是因為該 GUID 是 ToasterComponent_i.c 中列出的第一個 GUID。 此處的 GUID 不區分大小寫。 您可以返回介面定義並取得具有正確格式的 GuidAttribute 值,而不是手動重新格式化 IToast 和 IToaster 的 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>

將「擴充 XML」節點貼上為「套件」節點的直接子節點,以及「資源」節點等的對等節點。

在繼續之前,請務必確認:

  • ProxyStub ClassId 設定為 ToasterComponent_i.c 檔案中的第一個 GUID。 使用此檔案中定義的第一個 GUID 作為 classId。 (這可能與 ITypedEventHandler2 的 GUID 相同。)
  • Path 是 Proxy 二進位檔案的套件相對路徑。 (在本逐步說明中,proxies.dll 與 ToasterApplication.winmd 位於相同資料夾中。)
  • GUID 的格式正確。 (這很容易出錯。)
  • 資訊清單中的介面識別碼與 ToasterComponent_i.c 檔案中的 IID 相符。
  • 介面名稱在資訊清單中是唯一名稱。 由於系統不會使用這些值,因此您可以選擇這些值。 最好選擇與您定義的介面明確相符的介面名稱。 對於產生的介面,名稱應指示產生的介面。 您可以使用 ToasterComponent_i.c 檔案來幫助您產生介面名稱。

如果您現在嘗試執行該解決方案,您將收到錯誤訊息,表示 proxies.dll 不屬於承載。 開啟 ToasterApplication 專案中 References 資料夾的捷徑功能表,然後選擇新增參考。 選取 Proxy 專案旁的核取方塊。 另外,請確保 ToasterComponent 旁邊的核取方塊也已選取。 選擇 [確定] 按鈕。

現在應該可以建置該專案了。 執行專案,確認您是否可以製作快顯通知。