Generazione di eventi nei componenti Windows Runtime
Se il componente Windows Runtime genera un evento di un tipo delegato definito dall'utente su un thread in background (thread di lavoro) e desideri che JavaScript riceva l'evento, puoi implementarlo e/o generarlo in uno dei seguenti modi:
(Opzione 1) Generare l'evento attraverso l'oggetto CoreDispatcher per effettuare il marshalling dell'evento nel contesto del thread JavaScript. In genere questa opzione rappresenta la scelta migliore, ma in alcuni scenari la velocità delle prestazioni potrebbe risultare ridotta.
(Opzione 2) Utilizzare Windows.Foundation.EventHandler<object> (senza definire le informazioni sul tipo di evento). Se l'opzione 1 non è fattibile o le prestazioni che offre non sono adeguate, puoi applicare questa seconda opzione, se la perdita delle informazioni sul tipo non rappresenta un problema.
(Opzione 3) Creare oggetti COM stub e proxy personali per il componente. Questa opzione è la più difficile da implementare, ma permette di conservare le informazioni sul tipo e, in scenari complessi, consente di ottenere prestazioni migliori rispetto all'opzione 1.
Se ti limiti a generare un evento in un thread in background senza utilizzare una di queste opzioni, il client JavaScript non riceverà l'evento.
Background
Tutti i componenti e le app Windows Runtime sono fondamentalmente oggetti COM, indipendentemente dal linguaggio utilizzato per crearli. Nell'API di Windows, la maggior parte dei componenti sono oggetti COM agile in grado di comunicare correttamente con gli oggetti nel thread in background e nel thread UI. Se un oggetto COM non può essere impostato come Agile, avrà bisogno di oggetti helper noti come proxy e stub per comunicare con altri oggetti COM entro i limiti del thread in background e il thread UI. In termini COM, questa situazione è nota come comunicazione tra apartment di thread.
La maggior parte degli oggetti dell'API Windows sono Agile o dispongono di proxy e stub incorporati. Tuttavia, non è possibile creare proxy e stub per i tipi generici come Windows.Foundation.TypedEventHandler<TSender, TResult> perché non sono tipi completi finché non fornisci l'argomento di tipo. È solo con i client JavaScript che la mancanza di proxy o di stub diventa un problema, ma se desideri che il componente sia utilizzabile da JavaScript, nonché da C++ o da un linguaggio .NET, devi utilizzare una delle tre opzioni seguenti.
(Opzione 1) Generare l'evento attraverso l'oggetto CoreDispatcher
Puoi inviare eventi di qualsiasi tipo delegato definito dall'utente utilizzando Windows.UI.Core.CoreDispatcher così JavaScript potrà riceverli. Se non sei certo di quale opzione utilizzare, prova prima questa. Se la latenza tra la generazione dell'evento e la relativa gestione diventa un problema, prova una delle altre opzioni.
Di seguito viene illustrato come utilizzare l'oggetto CoreDispatcher per generare un evento fortemente tipizzato. Nota che l'argomento del tipo è Toast, non 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
}
(Opzione 2) Utilizzare EventHandler<Object> rinunciando a conservare le informazioni sul tipo
Un altro modo per inviare un evento da un thread in background consiste nell'utilizzare Windows.Foundation.EventHandler<Object> come tipo dell'evento. Windows crea l'istanza concreta del tipo generico e fornisce un proxy e uno stub. Lo svantaggio è che le informazioni sul tipo del mittente e degli argomenti dell'evento vengono perse. I client .NET e C++ devono utilizzare la documentazione per determinare di quale tipo eseguire di nuovo il cast quando viene ricevuto l'evento. I client JavaScript non necessitano delle informazioni sul tipo originali. Individuano le proprietà di argomento in base ai nomi nei metadati.
In questo esempio viene illustrato come utilizzare Windows.Foundation.EventHandler<Object> in C#:
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);
}
}
}
Puoi utilizzare questo evento sul lato di JavaScript nel seguente modo:
toastCompletedEventHandler: function (event) {
var toastType = event.toast.toastType;
document.getElementById("toasterOutput").innerHTML = "<p>Made " + toastType + " toast</p>";
},
(Opzione 3) Creare un proxy e uno stub personali
Per ottenere un potenziale miglioramento delle prestazioni su tipi di evento definiti dall'utente che conservano le informazioni complete sul tipo, devi creare degli oggetti proxy e stub personali e incorporarli nel pacchetto dell'app. In genere, è necessario utilizzare questa opzione solo in rare situazioni, dove le altre due opzioni non risultano adeguate. Inoltre, non vi è alcuna garanzia che questa opzione fornisca prestazioni migliori rispetto alle altre due opzioni. Le prestazioni effettive dipendono da diversi fattori. Puoi utilizzare il profiler di Visual Studio o altri strumenti di profilatura per misurare le prestazioni effettive nell'applicazione e determinare se l'evento è effettivamente un collo di bottiglia.
Nel resto di questo articolo viene illustrato come utilizzare il linguaggio C# per creare un componente Windows Runtime di base e quindi utilizzare C++ per creare una DLL per il proxy e lo stub che consentirà a JavaScript di utilizzare un evento Windows.Foundation.TypedEventHandler<TSender, TResult> generato dal componente in un'operazione asincrona. Per creare il componente, puoi utilizzare anche C++ o Visual Basic. I passaggi per creare i proxy e gli stub sono uguali. Questa procedura dettagliata è basata sull'articolo Creating a Windows Runtime in-process component sample (C++/CX) e ne spiega gli scopi.
Questa procedura dettagliata presenta le seguenti parti:
Creare il componente Windows Runtime: dove creerai due classi base di Windows Runtime. Una classe espone un evento di tipo Windows.Foundation.TypedEventHandler<TSender, TResult> e l'altra è il tipo che viene restituito a JavaScript come argomento per TValue. Queste classi non possono comunicare con JavaScript fino a che non completi i passaggi successivi.
Programmare l'app JavaScript: questa app attiva l'oggetto della classe principale, chiama un metodo e gestisce un evento generato dal componente Windows Runtime.
Generare i GUID per le interfacce del componente: questi GUID sono richiesti dagli strumenti che generano le classi del proxy e dello stub.
Generare un file IDL per il componente: utilizza a questo punto il file IDL per generare il codice sorgente C per il proxy e lo stub.
Compilare il codice del proxy e dello stub in una DLL
Registrare e utilizzare la DLL dello stub e del proxy: registra gli oggetti stub e proxy in modo che siano individuabili dal runtime COM, poi fa riferimento alla DLL dello stub e del proxy nel progetto dell'app.
Per creare il componente Windows Runtime
Nella barra dei menu di Visual Studio scegli File > Nuovo progetto. Nella finestra di dialogo Nuovo progetto espandi JavaScript > Windows Store, quindi seleziona Applicazione vuota. Assegna al progetto il nome ToasterApplication e scegli OK.
Aggiungi un componente Windows Runtime C# alla soluzione: in Esplora soluzioni apri il menu di scelta rapida per la soluzione e scegli Aggiungi > Nuovo progetto. Espandi Visual C# > Windows Store e seleziona Componente Windows Runtime. Assegna al progetto il nome ToasterComponent e scegli OK. ToasterComponent sarà lo spazio dei nomi radice per i componenti che creerai nei passaggi successivi.
In Esplora soluzioni apri il menu di scelta rapida della soluzione, quindi scegli Proprietà. Nella finestra di dialogo Pagine delle proprietà seleziona Proprietà di configurazione nel riquadro a sinistra, quindi nella parte superiore della finestra di dialogo, imposta Configurazione su Debug e Piattaforma su x86, x64 o ARM. Scegli OK.
Importante
L'opzione Piattaforma = Qualsiasi CPU non funzionerà perché non è valida per la DLL Win32 di codice nativo che aggiungerai alla soluzione in un secondo momento.
In Esplora soluzioni rinomina class1.cs in ToasterComponent.cs in modo che corrisponda al nome del progetto. In Visual Studio la classe nel file viene automaticamente rinominata in modo da corrispondere al nuovo nome file.
Nel file .cs aggiungi una direttiva using per lo spazio dei nomi Windows.Foundation per inserire TypedEventHandler nell'ambito.
Quando il componente che crei necessita di proxy e stub, deve utilizzare delle interfacce per esporre i propri membri pubblici. Nel file ToasterComponent.cs definisci un'interfaccia per il toaster e un'altra per il toast prodotto dal toaster.
Nota
In C# puoi ignorare questo passaggio.Crea invece una classe e apri il relativo menu di scelta rapida per scegliere Refactoring > Estrai interfaccia.Nel codice generato, imposta manualmente l'accessibilità pubblica delle interfacce.
public interface IToaster { void MakeToast(String message); event TypedEventHandler<Toaster, Toast> ToastCompletedEvent; } public interface IToast { String ToastType { get; } }
L'interfaccia di IToast è una stringa che può essere recuperata per descrivere il tipo di toast. L'interfaccia di IToaster dispone di un metodo per generare il toast e di un evento per indicare l'avvenuta creazione del toast. Poiché questo evento restituisce la parte particolare, ovvero il tipo, di toast, è noto come evento tipizzato.
A questo punto servono delle classi che implementino queste interfacce. Le classi devono essere pubbliche e sealed in modo che siano accessibili dall'app JavaScript che programmerai in un secondo momento.
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); } }); } }
Nel codice precedente abbiamo creato il toast e fatto girare un elemento di lavoro del pool di thread per generare la notifica. Sebbene IDE suggerisca di applicare la parola chiave await alla chiamata asincrona, in questo caso non è necessario perché l'attività del metodo è indipendente dai risultati dell'operazione.
Importante
La chiamata asincrona nel codice precedente utilizza ThreadPool.RunAsync esclusivamente per dimostrare un modo semplice di generare l'evento in un thread in background. Puoi scrivere questo particolare metodo come illustrato nell'esempio che segue. Il metodo funzionerà correttamente perché l'utilità di pianificazione di .NET esegue automaticamente il marshalling delle chiamate async/await nel thread UI.
public async void MakeToast(string message) { Toast toast = new Toast(message) await Task.Delay(new Random().Next(1000)); OnToastCompleted(toast); }
Se compili il progetto a questo punto, la compilazione non dovrebbe presentare problemi.
Per programmare l'app JavaScript
A questo punto possiamo aggiungere un pulsante all'app JavaScript per indurla a utilizzare la classe definita per la creazione del toast. Prima però dobbiamo aggiungere un riferimento al progetto ToasterComponent che abbiamo appena creato. In Esplora soluzioni, apri il menu di scelta rapida nel progetto ToasterApplication, scegli Aggiungi > Riferimenti, quindi scegli il pulsante Aggiungi nuovo riferimento. Nella finestra di dialogo Aggiungi riferimento, nel riquadro sinistro sotto Soluzione, seleziona il progetto del componente, quindi, nel riquadro centrale, seleziona ToasterComponent. Scegli OK.
In Esplora soluzioni apri il menu di scelta rapida per il progetto ToasterApplication e scegli Imposta come progetto di avvio.
Alla fine del file default.js aggiungi uno spazio dei nomi per includere le funzioni chiamanti e chiamate dal componente. Lo spazio dei nomi avrà due funzioni: generare il toast e gestire l'evento di completamento del toast. L'implementazione di makeToast crea un oggetto Toaster, registra il gestore eventi e produce il toast. Finora il gestore eventi non serve a molto, come illustrato di seguito:
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>"; }, });
La funzione makeToast deve essere associata a un pulsante. Aggiorna il file default.html per includere un pulsante e dello spazio per restituire il risultato della creazione del toast:
<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>
Se non stessimo utilizzando TypedEventHandler, si potrebbe eseguire l'app nel computer locale e fare clic sul pulsante per generare il toast. Ma nella nostra app non accade nulla. Per determinarne il motivo, eseguiamo il debug del codice gestito che genera l'evento ToastCompletedEvent. Arresta il progetto, quindi sulla barra dei menu scegli Debug > Proprietà dell'applicazione Toaster. Cambia Tipo di debugger in Solo gestito. Sulla barra dei menu scegli di nuovo Debug > Eccezioni, quindi seleziona Eccezioni Common Language Runtime.
Esegui l'app e fai clic sul pulsante per la generazione del toast. Il debugger rileva un'eccezione di cast non valido. Sebbene non sia evidente dal messaggio, questa eccezione si verifica perché ai proxy manca l'interfaccia.
Il primo passaggio per creare un proxy e uno stub per un componente consiste nell'aggiungere un ID o un GUID univoco alle interfacce. Tuttavia, il formato del GUID da utilizzare varia a seconda che i codice sia scritto in C#, Visual Basic o un altro linguaggio .NET, o in C++.
Per generare i GUID per le interfacce del componente
Per C#, Visual Basic o altri linguaggi .NET:
Sulla barra dei menu scegli Strumenti > Crea GUID. Nella finestra di dialogo seleziona 5. [Guid("xxxxxxxx-xxxx...xxxx)]. Scegli il pulsante Nuovo GUID, quindi il pulsante Copia.
Torna alla definizione dell'interfaccia e incolla il nuovo GUID appena prima dell'interfaccia IToaster, come illustrato nell'esempio seguente. Non utilizzare il GUID nell'esempio. Ogni interfaccia univoca deve avere un proprio GUID.
[Guid("FC198F74-A808-4E2A-9255-264746965B9F")] public interface IToaster...
Aggiungi una direttiva using per lo spazio dei nomi System.Runtime.InteropServices.
Ripeti questi passaggi per l'interfaccia di IToast.
Per C++:
Sulla barra dei menu scegli Strumenti > Crea GUID. Nella finestra di dialogo seleziona 3. GUID struttura costruttore statico = {...}. Scegli il pulsante Nuovo GUID, quindi il pulsante Copia.
Incolla il GUID appena prima della definizione dell'interfaccia di IToaster. Il GUID incollato dovrebbe essere come nell'esempio seguente. Non utilizzare il GUID nell'esempio. Ogni interfaccia univoca deve avere un proprio GUID.
// {F8D30778-9EAF-409C-BCCD-C8B24442B09B} static const GUID <<name>> = { 0xf8d30778, 0x9eaf, 0x409c, { 0xbc, 0xcd, 0xc8, 0xb2, 0x44, 0x42, 0xb0, 0x9b } };
Aggiungi una direttiva using per Windows.Foundation.Metadata per inserire GuidAttribute nell'ambito.
A questo punto converti manualmente il GUID del costruttore in GuidAttribute in modo da formattarlo come illustrato nell'esempio seguente. Nota che le parentesi graffe vengono sostituite con le parentesi quadre e tonde e il punto e virgola finale viene rimosso.
// {E976784C-AADE-4EA4-A4C0-B0C2FD1307C3} [GuidAttribute(0xe976784c, 0xaade, 0x4ea4, 0xa4, 0xc0, 0xb0, 0xc2, 0xfd, 0x13, 0x7, 0xc3)] public interface IToaster {...
Ripeti questi passaggi per l'interfaccia di IToast.
Ora che le interfacce dispongono di un ID univoco, possiamo creare il file IDL inserendo il file .winmd nello strumento da riga di comando winmdidl e generare il codice sorgente C per il proxy e lo stub inserendo il file IDL nello strumento da riga di comando MIDL. In Visual Studio questa operazione viene eseguita automaticamente se crei degli eventi post-compilazione come illustrato di seguito.
Per generare il codice sorgente del proxy e dello stub
Per aggiungere un evento di post-compilazione personalizzato, in Esplora soluzioni apri il menu di scelta rapida del progetto ToasterComponent, quindi scegli Proprietà. Nel riquadro sinistro delle pagine delle proprietà seleziona Eventi di compilazione, quindi scegli il pulsante Modifica post-compilazione. Aggiungi i seguenti comandi alla riga di comando di post-compilazione. Il file batch deve essere chiamato per primo in modo da impostare le variabili di ambiente per individuare lo strumento 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"
Importante
Per la configurazione di un progetto ARM o x64, modifica il parametro /env di MIDL in x64 o arm32.
Per assicurarti che il file IDL sia rigenerato ad ogni modifica del file .winmd, modifica Esegui evento post-compilazione in Quando la compilazione aggiorna l'output del progetto.
La pagina delle proprietà Eventi di compilazione dovrebbe essere simile alla seguente:
Ricompila la soluzione per generare e compilare il file IDL.
Puoi verificare se MIDL ha compilato correttamente la soluzione cercando ToasterComponent.h, ToasterComponent_i.c, ToasterComponent_p.c e dlldata.c nella directory del progetto ToasterComponent.
Per compilare il codice del proxy e dello stub in una DLL
Dopo avere creato i file necessari, puoi compilarli per produrre una DLL, che è un file C++. Per semplificare il più possibile questa attività, aggiungi un nuovo progetto per supportare la compilazione dei proxy. Apri il menu di scelta rapida della soluzione ToasterApplication e scegli Aggiungi > Nuovo progetto. Nel riquadro sinistro della finestra di dialogo Nuovo progetto espandi Visual C++ > Windows Store, quindi, nel riquadro centrale, seleziona DLL (applicazioni Windows Store). Nota che questo non è un progetto di componente Windows Runtime C++. Assegna al progetto il nome Proxy e scegli OK. Questi file verranno aggiornati dagli eventi post-compilazione quando vengono apportate modifiche nella classe C#.
Per impostazione predefinita, il progetto Proxy genera file di intestazione .h e file .cpp di C++. Poiché la DLL viene compilata dai file scritti da MIDL, i file con estensione .h e . cpp non sono necessari. In Esplora soluzioni apri il relativo menu di scelta rapida, scegli Rimuovi e conferma l'eliminazione.
Ora che il progetto è vuoto, puoi aggiungere di nuovo i file generati da MIDL. Apri il menu di scelta rapida del progetto Proxy e scegli Aggiungi > Elemento esistente. Nella finestra di dialogo passa alla directory del progetto ToasterComponent e seleziona questi file: ToasterComponent.h, ToasterComponent_i.c, ToasterComponent_p.c e dlldata.c. Scegli Aggiungi.
Nel progetto Proxy crea un file con estensione .def per definire le esportazioni di DLL descritte in dlldata.c. Apri il menu di scelta rapida del progetto Proxy e scegli Aggiungi > Nuovo elemento. Nel riquadro sinistro della finestra di dialogo seleziona Codice, quindi, nel riquadro centrale, seleziona File di definizione moduli. Assegna al file il nome proxies.def e scegli Aggiungi. Apri il file .def e modificalo per includere le esportazioni definite nel file dlldata.c:
EXPORTS DllCanUnloadNow PRIVATE DllGetClassObject PRIVATE
Se compili il progetto a questo punto, la compilazione non riuscirà. Per poter compilare il progetto, devi modificare il modo in cui il progetto viene compilato e collegato. In Esplora soluzioni apri il menu di scelta rapida del progetto Proxy, quindi scegli Proprietà. Modifica le pagine delle proprietà come segue:
Nel riquadro sinistro seleziona C/C++ > Preprocessore e nel riquadro destro seleziona Definizioni preprocessore, fai clic sul pulsante freccia GIÙ e seleziona Modifica. Aggiungi le definizioni nella casella:
WIN32;_WINDOWS
In C/C++ > Intestazioni precompilate modifica Intestazione precompilata in Senza intestazioni precompilate scegli il pulsante Applica.
In Linker > Generale modifica Ignora libreria di importazione in Sì, quindi scegli il pulsante Applica.
In Linker > Input seleziona Dipendenze aggiuntive, fai clic sul pulsante freccia GIÙ e seleziona Modifica. Aggiungi questo testo nella casella:
rpcrt4.lib;runtimeobject.lib
Non inserire queste librerie direttamente nella riga dell'elenco. Utilizza la casella Modifica per assicurarti che MSBuild in Visual Studio mantenga le dipendenze aggiuntive corrette.
Una volta apportate queste modifiche, nella finestra di dialogo Pagine delle proprietà scegli OK.
Successivamente, inserisci una dipendenza nel progetto ToasterComponent. In questo modo, Toaster verrà compilato prima del progetto Proxy. Ciò è fondamentale perché il progetto Toaster è responsabile della generazione dei file necessari a compilare il proxy.
Apri il menu di scelta rapida del progetto Proxy e scegli Dipendenze progetto. Seleziona le caselle di controllo per indicare che il progetto Proxy dipende dal progetto ToasterComponent, per assicurarti che Visual Studio li compili nell'ordine corretto.
Assicurati la corretta compilazione della soluzione scegliendo Compila > Ricompila soluzione sulla barra dei menu di Visual Studio.
Per registrare il proxy e lo stub
Nel progetto ToasterApplication apri il menu di scelta rapida per package.appxmanifest, quindi scegli Apri con. Nella finestra di dialogo Apri con seleziona Editor XML (testo), quindi scegli OK. Incolleremo un determinato XML che fornisce una registrazione dell'estensione windows.activatableClass.proxyStub e che è basato sui GUID del proxy. Per individuare i GUID da utilizzare nel file .appxmanifest, apri il file ToasterComponent_i.c. Cerca le voci simili a quelle nell'esempio seguente. Nota inoltre le definizioni per IToast, IToaster e una terza interfaccia, un gestore eventi tipizzato che presenta due parametri: un Toaster e un Toast. Questo corrisponde all'evento definito nella classe Toaster. Nota che i GUID per IToast e IToaster corrispondono ai GUID definiti nelle interfacce nel file C#. Poiché l'interfaccia del gestore eventi tipizzato viene generata automaticamente, anche il GUID corrispondente viene generato automaticamente.
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);
Ora copiamo i GUID e li incolliamo in package.appxmanifest in un nodo che aggiungiamo e denominiamo Extensions, quindi li riformattiamo. La voce del manifesto è simile al seguente esempio, ma anche in questo caso è necessario utilizzare i propri GUID. Nota che il GUID di ClassId in XML è lo stesso di ITypedEventHandler2. Questo perché il GUID è il primo elencato in ToasterComponent_i.c. I GUID sono senza distinzione tra maiuscole e minuscole. Anziché riformattare manualmente i GUID per IToast e IToaster, puoi tornare alle definizioni dell'interfaccia e ottenere il valore GuidAttribute, che ha il formato corretto. In C++, nel commento è presente un GUID formattato correttamente. Ad ogni modo, è necessario riformattare il GUID utilizzato sia per ClassId che per il gestore eventi.
<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>
Incolla il nodo XML Extensions come figlio diretto del nodo Package e allo stesso livello, ad esempio, del nodo Resources.
Prima di proseguire assicurati che:
Il ClassId di ProxyStub sia impostato sul primo GUID nel file ToasterComponent_i.c. Utilizza il primo GUID definito in questo file per il classId, che potrebbe essere lo stesso GUID di ITypedEventHandler2.
Path sia il percorso relativo del pacchetto del binario proxy. In questa procedura dettagliata, il file proxies.dll si trova nella stessa cartella di ToasterApplication.winmd.
I GUID siano in formato corretto, dal momento che è facile che sia errato.
Gli ID di interfaccia nel manifesto corrispondano agli ID nel file ToasterComponent_i.c.
I nomi di interfaccia siano univoci nel manifesto. Poiché questi non vengono utilizzati dal sistema, puoi scegliere i valori. È consigliabile scegliere nomi di interfaccia che corrispondano chiaramente alle interfacce definite. Per le interfacce generate, i nomi devono essere indicativi delle interfacce generate. Puoi utilizzare il file ToasterComponent_i.c per generare nomi di interfaccia.
A questo punto se tenti di eseguire la soluzione, verrà visualizzato un errore che indicherà che il file proxies.dll non fa parte del payload. Apri il menu di scelta rapida per la cartella Riferimenti nel progetto ToasterApplication, quindi scegli Aggiungi riferimento. Seleziona la casella di controllo accanto al progetto Proxy. Assicurati che anche la casella di controllo accanto a ToasterComponent sia selezionata. Scegli OK.
La compilazione del progetto dovrebbe avvenire senza problemi. Esegui il progetto e verifica di poter generare il toast.