在 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。
為元件建立 Proxy 和虛設常式的第一步是向介面新增唯一識別碼或 GUID。 但是,要使用的 GUID 格式會有所不同,這取決於您是使用 C#、Visual Basic、其他 .NET 語言還是 C++ 進行編碼。
為元件的介面產生 GUID (C# 和其他 .NET 語言)
在功能表列上,選擇 [工具 > 建立 GUID]。 在對話方塊中選取 5。 [Guid("xxxxxxxx-xxxx...xxxx")]. 選擇 [新 GUID] 按鈕,然後選擇 [複製] 按鈕。
返回介面定義,然後在 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 文件,請將執行建置後事件變更為當建置更新專案輸出時。建置事件屬性頁面應該會像這樣:
重建解決方案以產生並編譯 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 旁邊的核取方塊也已選取。 選擇 [確定] 按鈕。
現在應該可以建置該專案了。 執行專案,確認您是否可以製作快顯通知。