Generazione di eventi in componenti Windows Runtime

Nota

Per altre info sulla generazione di eventi in un componente Windows Runtime C++/WinRT , vedi Creare eventi in C++/WinRT.

Se il componente Windows Runtime genera un evento di un tipo delegato definito dall'utente in un thread in background (thread di lavoro) e si vuole che JavaScript possa ricevere l'evento, è possibile implementarlo e/o generarlo in uno di questi modi.

  • (Opzione 1) Generare l'evento tramite Windows.UI.Core.CoreDispatcher per effettuare il marshalling dell'evento nel contesto del thread JavaScript. Anche se in genere questa è l'opzione migliore, in alcuni scenari potrebbe non offrire le prestazioni più veloci.
  • (Opzione 2) Utilizzare l'oggetto> Windows.Foundation.EventHandler<(ma perdono le informazioni sul tipo di evento). Se l'opzione 1 non è fattibile o se le prestazioni non sono adeguate, questa è una buona seconda scelta a condizione che la perdita di informazioni sul tipo sia accettabile. Se si sta creando un componente Windows Runtime C#, il tipo di oggetto> Windows.Foundation.EventHandler<non è disponibile; invece, tale tipo viene proiettato in System.EventHandler, quindi è consigliabile usarlo.
  • (Opzione 3) Creare un proxy e uno stub personalizzati per il componente. Questa opzione è la più difficile da implementare, ma mantiene le informazioni sul tipo e potrebbe offrire prestazioni migliori rispetto all'opzione 1 in scenari impegnativi.

Se si genera solo un evento in un thread in background senza usare una di queste opzioni, un client JavaScript non riceverà l'evento.

Background

Tutti i componenti e le app di Windows Runtime sono fondamentalmente oggetti COM, indipendentemente dal linguaggio usato per crearli. Nell'API Windows, la maggior parte dei componenti sono oggetti COM agile che possono comunicare altrettanto bene con gli oggetti nel thread in background e nel thread dell'interfaccia utente. Se un oggetto COM non può essere reso agile, richiede oggetti helper noti come proxy e stub per comunicare con altri oggetti COM attraverso il limite del thread in background dell'interfaccia utente. (In termini COM, questo è noto come comunicazione tra appartamenti thread.

La maggior parte degli oggetti nell'API di Windows è agile o ha proxy e stub incorporati. Tuttavia, i proxy e gli stub non possono essere creati per tipi generici come Windows.Foundation.TypedEventHandler<TSender, TResult> perché non sono tipi completi fino a quando non si specifica l'argomento di tipo. È solo con i client JavaScript che la mancanza di proxy o stub diventa un problema, ma se si vuole che il componente sia utilizzabile da JavaScript e da C++ o da un linguaggio .NET, è necessario usare una delle tre opzioni seguenti.

(Opzione 1) Generare l'evento tramite CoreDispatcher

È possibile inviare eventi di qualsiasi tipo delegato definito dall'utente usando Windows.UI.Core.CoreDispatcher e JavaScript sarà in grado di riceverli. Se non si è certi dell'opzione da usare, provare prima questa opzione. Se la latenza tra la generazione di eventi e la gestione degli eventi diventa un problema, provare una delle altre opzioni.

L'esempio seguente illustra come usare CoreDispatcher per generare un evento fortemente tipizzato. Si noti che l'argomento di 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) Usare l'oggetto> EventHandler<ma perdere informazioni sul tipo

Nota

Se si sta creando un componente Windows Runtime C#, il tipo di oggetto> Windows.Foundation.EventHandler<non è disponibile; invece, tale tipo viene proiettato in System.EventHandler, quindi è consigliabile usarlo.

Un altro modo per inviare un evento da un thread in background consiste nell'usare l'oggetto> Windows.Foundation.EventHandler<come tipo dell'evento. Windows fornisce questa istanza concreta del tipo generico e fornisce un proxy e uno stub. Lo svantaggio è che le informazioni sul tipo degli argomenti dell'evento e del mittente andranno perse. I client C++ e .NET devono conoscere la documentazione su quale tipo eseguire il castback quando viene ricevuto l'evento. I client JavaScript non necessitano delle informazioni sul tipo originale. Trovano le proprietà arg, in base ai relativi nomi nei metadati.

Questo esempio illustra come usare l'oggetto> Windows.Foundation.EventHandler<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);
        }
    }
}

Questo evento viene usato sul lato JavaScript come segue:

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 personalizzati

Per potenziali miglioramenti delle prestazioni sui tipi di evento definiti dall'utente con informazioni sui tipi completamente mantenuti, è necessario creare oggetti proxy e stub personalizzati e incorporarli nel pacchetto dell'app. In genere, è necessario usare questa opzione solo in rari casi in cui nessuna delle altre due opzioni è adeguata. Inoltre, non esiste alcuna garanzia che questa opzione fornirà prestazioni migliori rispetto alle altre due opzioni. Le prestazioni effettive dipendono da molti fattori. Usare 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.

Il resto di questo articolo illustra come usare C# per creare un componente Windows Runtime di base e quindi usare 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. È anche possibile usare C++ o Visual Basic per creare il componente. I passaggi correlati alla creazione dei proxy e degli stub sono gli stessi. Questa procedura dettagliata si basa sulla creazione di un esempio di componente in-process di Windows Runtime (C++/CX) e ne spiega gli scopi.

Questa procedura dettagliata include queste parti.

  • Qui creerai due classi di Base di Windows Runtime. Una classe espone un evento di tipo Windows.Foundation.TypedEventHandler<TSender, TResult> e l'altra classe è il tipo restituito a JavaScript come argomento per TValue. Queste classi non possono comunicare con JavaScript fino a quando non si completano i passaggi successivi.
  • Questa app attiva l'oggetto classe principale, chiama un metodo e gestisce un evento generato dal componente Windows Runtime.
  • Questi sono richiesti dagli strumenti che generano le classi proxy e stub.
  • Usare quindi il file IDL per generare il codice sorgente C per il proxy e lo stub.
  • Registrare gli oggetti proxy-stub in modo che il runtime COM possa trovarli e fare riferimento alla DLL proxy-stub nel progetto dell'app.

Per creare il componente Windows Runtime

Nella barra dei menu di Visual Studio scegliere File > nuovo progetto. Nella finestra di dialogo Nuovo progetto espandere Windows universale JavaScript > e quindi selezionare App vuota. Assegnare al progetto il nome TostapaneApplication e quindi scegliere il pulsante OK .

Aggiungere un componente Windows Runtime C# alla soluzione: in Esplora soluzioni aprire il menu di scelta rapida per la soluzione e quindi scegliere Aggiungi > nuovo progetto. Espandere Visual C# > Microsoft Store e quindi selezionare Componente Windows Runtime. Assegnare al progetto il nome TostapaneComponent e quindi scegliere il pulsante OK . PaneComponent sarà lo spazio dei nomi radice per i componenti che verranno creati nei passaggi successivi.

In Esplora soluzioni aprire il menu di scelta rapida per la soluzione e quindi scegliere Proprietà. Nella finestra di dialogo Pagine delle proprietà selezionare Proprietà di configurazione nel riquadro sinistro e quindi nella parte superiore della finestra di dialogo impostare Configurazione su Debug e piattaforma su x86, x64 o ARM. Scegli il pulsante OK.

Importante Platform = Qualsiasi CPU non funzionerà perché non è valida per la DLL Win32 di codice nativo che verrà aggiunta alla soluzione in un secondo momento.

In Esplora soluzioni rinominare class1.cs in ToasterComponent.cs in modo che corrisponda al nome del progetto. Visual Studio rinomina automaticamente la classe nel file in modo che corrisponda al nuovo nome file.

Nel file .cs aggiungere una direttiva using per lo spazio dei nomi Windows.Foundation per portare TypedEventHandler nell'ambito.

Quando sono necessari proxy e stub, il componente deve usare le interfacce per esporre i relativi membri pubblici. In ToasterComponent.cs definire un'interfaccia per il tostapane e un'altra per l'avviso popup prodotto dal tostapane.

Nota In C# è possibile ignorare questo passaggio. Creare invece prima una classe e quindi aprire il relativo menu di scelta rapida e scegliere RefactorIng Extract Interface (Esegui refactoring > dell'interfaccia di estrazione). Nel codice generato, assegnare manualmente l'accessibilità pubblica alle interfacce.

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

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

L'interfaccia IToast include una stringa che può essere recuperata per descrivere il tipo di avviso popup. L'interfaccia IToaster ha un metodo per creare un avviso popup e un evento per indicare che l'avviso popup viene eseguito. Poiché questo evento restituisce la parte specifica , ovvero il tipo, dell'avviso popup, è nota come evento tipizzato.

A questo punto, sono necessarie classi che implementano queste interfacce e sono pubbliche e sealed in modo che siano accessibili dall'app JavaScript che verrà programmata 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 si crea l'avviso popup e quindi si attiva un elemento di lavoro del pool di thread per generare la notifica. Anche se l'IDE potrebbe suggerire di applicare la parola chiave await alla chiamata asincrona, in questo caso non è necessario perché il metodo non esegue alcuna operazione che dipende dai risultati dell'operazione.

Nota La chiamata asincrona nel codice precedente usa threadPool.RunAsync esclusivamente per illustrare un modo semplice per generare l'evento in un thread in background. È possibile scrivere questo particolare metodo come illustrato nell'esempio seguente e funziona correttamente perché l'utilità di pianificazione dell'attività .NET esegue automaticamente il marshalling delle chiamate asincrone/await al thread dell'interfaccia utente.  

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

Se si compila ora il progetto, dovrebbe essere compilato in modo pulito.

Per programmare l'app JavaScript

È ora possibile aggiungere un pulsante all'app JavaScript per fare in modo che usi la classe appena definita per creare un avviso popup. Prima di eseguire questa operazione, è necessario aggiungere un riferimento al progetto TostapaneComponent appena creato. In Esplora soluzioni aprire il menu di scelta rapida per il progetto ToastApplication, scegliere Aggiungi riferimenti e quindi scegliere il pulsante Aggiungi nuovo riferimento>. Nella finestra di dialogo Aggiungi riferimento, nel riquadro sinistro in Soluzione selezionare il progetto componente e quindi nel riquadro centrale selezionare TostapaneComponent. Scegli il pulsante OK.

In Esplora soluzioni aprire il menu di scelta rapida per il progetto TostapaneApplication e quindi scegliere Imposta come progetto di avvio.

Alla fine del file default.js aggiungere uno spazio dei nomi per contenere le funzioni per chiamare il componente e richiamarlo. Lo spazio dei nomi avrà due funzioni, una per creare un avviso popup e una per gestire l'evento di completamento dell'avviso popup. L'implementazione di makeToast crea un oggetto Tostapane, registra il gestore eventi e imposta l'avviso popup. Finora, il gestore eventi non esegue molte operazioni, 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 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>";
        },
    });

La funzione makeToast deve essere collegato a un pulsante. Aggiornare default.html per includere un pulsante e uno spazio per restituire il risultato dell'avviso popup:

    <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 si usasse un TypedEventHandler, è ora possibile eseguire l'app nel computer locale e fare clic sul pulsante per creare un avviso popup. Ma nell'app non succede nulla. Per scoprire perché, eseguire il debug del codice gestito che genera ToastCompletedEvent. Arrestare il progetto e quindi sulla barra dei menu scegliere Debug > Delle proprietà dell'applicazione tostapane. Modificare il tipo di debugger in Solo gestito. Nella barra dei menu scegliere Debug > eccezioni e quindi fare clic su Eccezioni di Common Language Runtime.

Eseguire ora l'app e fare clic sul pulsante make-toast. Il debugger rileva un'eccezione cast non valida. Anche se non è ovvio dal messaggio, questa eccezione si verifica perché mancano proxy per tale interfaccia.

missing proxy

Il primo passaggio per la creazione di un proxy e uno stub per un componente consiste nell'aggiungere un ID o un GUID univoco alle interfacce. Tuttavia, il formato GUID da usare varia a seconda che si stia codificando in C#, Visual Basic o in un altro linguaggio .NET o in C++.

Per generare GUID per le interfacce del componente (C# e altri linguaggi .NET)

Nella barra dei menu scegliere Strumenti > Crea GUID. Nella finestra di dialogo selezionare 5. [Guid("xxxxxxxx-xxxx... xxxx")]. Scegliere il pulsante Nuovo GUID e quindi scegliere il pulsante Copia.

guid generator tool

Tornare alla definizione dell'interfaccia e quindi incollare il nuovo GUID subito prima dell'interfaccia IToaster, come illustrato nell'esempio seguente. Non usare il GUID nell'esempio. Ogni interfaccia univoca deve avere un proprio GUID.

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

Aggiungere una direttiva using per lo spazio dei nomi System.Runtime.InteropServices.

Ripetere questi passaggi per l'interfaccia IToast.

Per generare GUID per le interfacce del componente (C++)

Nella barra dei menu scegliere Strumenti > Crea GUID. Nella finestra di dialogo selezionare 3. static const struct GUID = {...}. Scegliere il pulsante Nuovo GUID e quindi scegliere il pulsante Copia.

Incollare il GUID subito prima della definizione dell'interfaccia IToaster. Dopo aver incollato, il GUID dovrebbe essere simile all'esempio seguente. Non usare 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 } };

Aggiungere una direttiva using per Windows.Foundation.Metadata per inserire GuidAttribute nell'ambito.

Convertire ora manualmente il GUID const in un GuidAttribute in modo che sia formattato come illustrato nell'esempio seguente. Si noti che le parentesi graffe vengono sostituite da parentesi quadre e parentesi 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
    {...

Ripetere questi passaggi per l'interfaccia IToast.

Ora che le interfacce hanno ID univoci, è possibile creare un file IDL inserendo il file winmd nello strumento da riga di comando winmdidl e quindi generare il codice sorgente C per il proxy e lo stub inserendo il file IDL nello strumento da riga di comando MIDL. Visual Studio esegue questa operazione se si creano eventi di post-compilazione, come illustrato nei passaggi seguenti.

Per generare il codice sorgente proxy e stub

Per aggiungere un evento di post-compilazione personalizzato, in Esplora soluzioni aprire il menu di scelta rapida per il progettoPaneComponent e quindi scegliere Proprietà. Nel riquadro sinistro delle pagine delle proprietà selezionare Eventi di compilazione e quindi scegliere il pulsante Modifica post-compilazione. Aggiungere i comandi seguenti alla riga di comando post-compilazione. Il file batch deve essere chiamato per prima cosa per impostare le variabili di ambiente per trovare 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 una configurazione di progetto ARM o x64, modificare il parametro MIDL /env in x64 o arm32.

Per assicurarsi che il file IDL venga rigenerato ogni volta che il file con estensione winmd viene modificato, modificare Esegui l'evento di post-compilazione in Quando la compilazione aggiorna l'output del progetto. La pagina delle proprietà Eventi di compilazione dovrebbe essere simile alla seguente: build events

Ricompilare la soluzione per generare e compilare il file IDL.

È possibile verificare che MIDL abbia compilato correttamente la soluzione cercandoPaneComponent.h, ToasterComponent_i.c, ToasterComponent_p.c e dlldata.c nella directory del progetto ToastComponent.

Per compilare il codice proxy e stub in una DLL

Dopo aver creato i file necessari, è possibile compilarli per produrre una DLL, ovvero un file C++. Per semplificare il più possibile questa operazione, aggiungere un nuovo progetto per supportare la compilazione dei proxy. Aprire il menu di scelta rapida per la soluzione TostapaneApplication e quindi scegliere Aggiungi > nuovo progetto. Nel riquadro sinistro della finestra di dialogo Nuovo progetto espandere Visual C++ > Windows Univeral Windows >e quindi selezionare DLL (app UWP) nel riquadro centrale. Si noti che non si tratta di un progetto di componente Windows Runtime C++. Denominare i proxy del progetto e quindi scegliere il pulsante OK . Questi file verranno aggiornati dagli eventi di post-compilazione quando qualcosa cambia nella classe C#.

Per impostazione predefinita, il progetto Proxy genera file con estensione h di intestazione e file di .cpp C++. Poiché la DLL viene compilata dai file prodotti da MIDL, i file con estensione h e .cpp non sono necessari. In Esplora soluzioni aprire il menu di scelta rapida, scegliere Rimuovi e quindi confermare l'eliminazione.

Ora che il progetto è vuoto, è possibile aggiungere nuovamente i file generati da MIDL. Aprire il menu di scelta rapida per il progetto Proxy e quindi scegliere Aggiungi > elemento esistente. Nella finestra di dialogo passare alla directory del progetto ToastComponent e selezionare i file seguenti:PaneComponent.h, ToasterComponent_i.c, ToasterComponent_p.c e file dlldata.c. Scegliere il pulsante Aggiungi .

Nel progetto Proxy creare un file con estensione def per definire le esportazioni dll descritte in dlldata.c. Aprire il menu di scelta rapida per il progetto e quindi scegliere Aggiungi > nuovo elemento. Nel riquadro sinistro della finestra di dialogo selezionare Codice e quindi nel riquadro centrale selezionare File di definizione modulo. Assegnare al file il nome proxy.def e quindi scegliere il pulsante Aggiungi . Aprire questo file con estensione def e modificarlo per includere le ESPORTAZIONi definite in dlldata.c:

EXPORTS
    DllCanUnloadNow         PRIVATE
    DllGetClassObject       PRIVATE

Se si compila ora il progetto, l'operazione avrà esito negativo. Per compilare correttamente questo progetto, è necessario modificare la modalità di compilazione e collegamento del progetto. In Esplora soluzioni aprire il menu di scelta rapida per il progetto Proxy e quindi scegliere Proprietà. Modificare le pagine delle proprietà come indicato di seguito.

Nel riquadro sinistro selezionare Preprocessore C/C++ > e quindi nel riquadro destro selezionare Definizioni preprocessore, scegliere il pulsante freccia giù e quindi selezionare Modifica. Aggiungere queste definizioni nella casella:

WIN32;_WINDOWS

In Intestazioni precompilate C/C++ > impostare Intestazione precompilata su Non usare intestazioni precompilate e quindi scegliere il pulsante Applica.

In Generale del linker > modificare Ignora importazione libreria in Yes e quindi scegliere il pulsante Applica.

In Input del linker > selezionare Dipendenze aggiuntive, scegliere il pulsante freccia giù e quindi selezionare Modifica. Aggiungere questo testo nella casella:

rpcrt4.lib;runtimeobject.lib

Non incollare queste librerie direttamente nella riga dell'elenco. Usare la casella Modifica per assicurarsi che MSBuild in Visual Studio mantenga le dipendenze aggiuntive corrette.

Dopo aver apportato queste modifiche, scegliere il pulsante OK nella finestra di dialogo Pagine delle proprietà.

Successivamente, prendere una dipendenza dal progetto TostapaneComponent. In questo modo si garantisce che il tostapane venga compilato prima della compilazione del progetto proxy. Questo è necessario perché il progetto Tostapane è responsabile della generazione dei file per compilare il proxy.

Aprire il menu di scelta rapida per il progetto Proxy e quindi scegliere Dipendenze progetto. Selezionare le caselle di controllo per indicare che il progetto Proxy dipende dal progetto TostapaneComponent per assicurarsi che Visual Studio li compila nell'ordine corretto.

Verificare che la soluzione venga compilata correttamente scegliendo Compilacompila > soluzione nella barra dei menu di Visual Studio.

Per registrare il proxy e lo stub

Nel progetto TostapaneApplication aprire il menu di scelta rapida per package.appxmanifest e quindi scegliere Apri con. Nella finestra di dialogo Apri con selezionare Editor di testo XML e quindi scegliere il pulsante OK . Incollare alcuni XML che forniscono una registrazione dell'estensione windows.activatableClass.proxyStub e basate sui GUID nel proxy. Per trovare i GUID da usare nel file con estensione appxmanifest, aprire ToasterComponent_i.c. Trovare voci simili a quelle dell'esempio seguente. Si notino anche le definizioni per IToast, IToaster e una terza interfaccia, ovvero un gestore eventi tipizzato con due parametri: un tostapane e un avviso popup. Corrisponde all'evento definito nella classe Tostapane. Si noti che i GUID per IToast e IToaster corrispondono ai GUID definiti nelle interfacce nel file C#. Poiché l'interfaccia del gestore eventi tipizzata viene generata automaticamente, viene generato automaticamente anche il GUID per questa interfaccia.

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 si copiano i GUID, incollarli in package.appxmanifest in un nodo aggiunto e denominare estensioni e quindi riformattarli. La voce del manifesto è simile all'esempio seguente, ma anche in questo caso ricordarsi di usare i propri GUID. Si noti che il GUID ClassId nel codice XML è uguale a ITypedEventHandler2. Questo perché tale GUID è il primo elencato in ToasterComponent_i.c. I GUID qui non fanno distinzione tra maiuscole e minuscole. Invece di riformattare manualmente i GUID per IToast e IToaster, è possibile tornare alle definizioni di interfaccia e ottenere il valore GuidAttribute, che ha il formato corretto. In C++, nel commento è presente un GUID formattato correttamente. In ogni caso, è necessario riformattare manualmente il GUID usato 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>

Incollare il nodo XML Estensioni come figlio diretto del nodo Pacchetto e un peer di, ad esempio il nodo Risorse.

Prima di procedere, è importante assicurarsi che:

  • ProxyStub ClassId è impostato sul primo GUID nel file ToasterComponent_i.c. Usare il primo GUID definito in questo file per classId. Potrebbe essere uguale al GUID per ITypedEventHandler2.
  • Path è il percorso relativo del pacchetto del file binario proxy. In questa procedura dettagliata proxies.dll si trova nella stessa cartella di ToastApplication.winmd.
  • I GUID sono nel formato corretto. (Questo è facile da sbagliare.
  • Gli ID di interfaccia nel manifesto corrispondono ai IID nel file ToasterComponent_i.c.
  • I nomi dell'interfaccia sono univoci nel manifesto. Poiché questi non vengono usati dal sistema, è possibile 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. È possibile usare il file ToasterComponent_i.c per generare nomi di interfaccia.

Se si tenta di eseguire la soluzione ora, verrà visualizzato un errore che proxies.dll non fa parte del payload. Aprire il menu di scelta rapida per la cartella Riferimenti nel progetto TostapaneApplication e quindi scegliere Aggiungi riferimento. Selezionare la casella di controllo accanto al progetto Proxy. Assicurarsi inoltre che sia selezionata anche la casella di controllo accanto a TostapaneComponent. Scegli il pulsante OK.

Il progetto dovrebbe ora compilare. Eseguire il progetto e verificare che sia possibile creare un avviso popup.