Condividi tramite


Generazione di eventi in componenti Windows Runtime

Nota

Per altre info sulla generazione di eventi in un componente Windows Runtime C++/WinRT, vedere 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 sia in grado di 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 si 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 esigenti.

Se si genera solo un evento in un thread in background senza usare una di queste opzioni, un client JavaScript non potrà ricevere 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 integrati. Tuttavia, proxy e 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 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 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 si perdono 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 proxy e stub personalizzati

Per potenziali miglioramenti delle prestazioni sui tipi di evento definiti dall'utente con informazioni sui tipi completamente preservati, è necessario creare oggetti proxy e stub personalizzati e integrarli 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 consenta 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 si crea bo due classi 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.

Creare i componenti Windows Runtime

Nella barra dei menu di Visual Studio, selezionare File > Nuovo progetto. Nella finestra di dialogo Nuovo progetto, espandere JavaScript > Universal Windows e quindi selezionare Blank App. Denominare il progetto ToasterApplication, quindi selezionare 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 selezionare Aggiungere > nuovo progetto. Espandere Visual C# > Microsoft Store e quindi selezionare Componente Windows Runtime. Denominare il progetto ToasterComponent, quindi selezionare il pulsante OK. ToasterComponent 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 selezionare Proprietà. Nella finestra di dialogo Pagine delle proprietà selezionare Proprietà di configurazione nel riquadro sinistro, quindi nella parte superiore della finestra di dialogo impostare Configurazione su Debug e Piattaforma su x86, x64 o ARM. Scegli il pulsante OK.

Importante Piattaforma = 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 toaster e un'altra per il Toast prodotto dal toaster.

Nota In C# è possibile ignorare questo passaggio. Creare invece prima una classe e quindi aprire il relativo menu di scelta rapida e selezionare RefactorIng > Extract Interface. 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 toast. L'interfaccia IToaster ha un metodo per creare un toast e un evento per indicare che il toast viene eseguito. Poiché questo evento restituisce la parte specifica (ovvero il tipo) del toast, è 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 il toast 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.

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 toast. Prima di eseguire questa operazione, è necessario aggiungere un riferimento al progetto ToasterComponent appena creato. In Esplora soluzioni aprire il menu di scelta rapida per il progetto ToastApplication, selezionare Aggiungere > Riferimenti, quindi selezionare il pulsante Aggiungere nuovo riferimento. Nella finestra di dialogo Aggiungere riferimento, nel riquadro a sinistra in Soluzione selezionare il progetto componente e quindi nel riquadro centrale selezionare ToasterComponent. Scegli il pulsante OK.

In Esplora soluzioni aprire il menu di scelta rapida per il progetto ToasterApplication e quindi selezionare Impostare come progetto di Startup.

Alla fine del file default.js aggiungere uno spazio dei nomi per contenere le funzioni per richiamare il componente e richiamarlo di nuovo. Lo spazio dei nomi avrà due funzioni, una per creare un toast e una per gestire l'evento di completamento del toast. L'implementazione di makeToast crea un oggetto Toaster, registra il gestore eventi e crea il toast. 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 collegata a un pulsante. Aggiornare default.html per includere un pulsante e uno spazio per restituire 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 si usasse un TypedEventHandler, è ora possibile eseguire l'app nel computer locale e fare clic sul pulsante per creare un toast. 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 selezionare Debug > delle proprietà dell'applicazione Toaster. Modificare il tipo di debugger in Solo gestito. Nella barra dei menu selezionare Debug > Exceptions, quindo selezionare Common Language Runtime Exceptions.

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.

proxy mancante

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 selezionare Strumenti > Crea GUID. Nella finestra di dialogo selezionare 5. [Guid("xxxxxxxx-xxxx...xxxx")]. Selezionare il pulsante Nuovo GUID e quindi selezionare il pulsante Copia.

Strumento generatore guid

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.

Generare GUID per le interfacce del componente (C++)

Nella barra dei menu selezionare Strumenti > Crea GUID. Nella finestra di dialogo selezionare 3. static const struct GUID = {...}. Selezionare il pulsante Nuovo GUID e quindi selezionare 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 della riga di comando winmdidl e quindi generare il codice sorgente C per il proxy e lo stub inserendo il file IDL nello strumento della 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 progetto ToasterComponent e quindi selezionare Proprietà. Nel riquadro a sinistra delle pagine delle proprietà selezionare Eventi di compilazione, quindi selezionare il pulsante Modifica post-compilazione. Aggiungere i comandi seguenti alla riga di comando post-compilazione. (Il file batch deve essere richiamato per prima cosa per impostare le variabili 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 della proprietà Eventi di compilazione dovrebbe essere simile alla seguente: eventi di compilazione

Ricompilare la soluzione per generare e compilare il file IDL.

È possibile verificare che MIDL abbia compilato correttamente la soluzione cercando ToasterComponent.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 ToasterApplication e quindi selezionare Aggiungi > nuovo progetto. Nel riquadro sinistro della finestra di dialogo Nuovo progetto espandere Windows universale di Visual > C++ > e quindi nel riquadro centrale selezionare DLL (app UWP). (Si noti che non si tratta di un progetto di componente Windows Runtime C++). Denominare i proxy del progetto e quindi selezionare 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 .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, selezionare 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 selezionare Aggiungi > elemento esistente. Nella finestra di dialogo passare alla directory del progetto ToasterComponent e selezionare i file seguenti: ToasterComponent.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 selezionare Aggiungi > nuovo elemento. Nel riquadro a sinistra della finestra di dialogo selezionare Codice e quindi nel riquadro centrale selezionare File di definizione modulo. Assegnare al file il nome proxies.def e quindi selezionare 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à compilazione e collegamento del progetto. In Esplora soluzioni aprire il menu di scelta rapida per il progetto Proxies, quindi selezionare Proprietà. Modificare le pagine delle proprietà come indicato di seguito.

Nel riquadro a sinistra, selezionare C/C++ > Preprocessore, quindi nel riquadro a destra, selezionare Definizioni di preprocessore, selezionare il pulsante freccia giù e quindi selezionare Modifica. Aggiungere queste definizioni nella casella:

WIN32;_WINDOWS

In C/C++ > Intestazioni precompilate, cambiare Intestazione precompilata to Non usare intestazioni precompilate, quindi selezionare il pulsante Applica.

In Linker > Generale, cambiare Ignora importazione libreria in , quindi selezionare il pulsante Applica.

Under Linker > Input, selezionare Dipendenze aggiuntive, selezionare il pulsante freccia verso il basso, 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, selezionare il pulsante OK nella finestra di dialogo Pagine delle proprietà.

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

Aprire il menu di scelta rapida per il progetto Proxies e quindi selezionare Dipendenze progetto. Selezionare le caselle di spunta per indicare che il progetto Proxies dipende dal progetto ToasterComponent per assicurarsi che Visual Studio li compili nell'ordine corretto.

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

Registrare il proxy e lo stub

Nel progetto ToasterApplication aprire il menu di scelta rapida per package.appxmanifest e quindi selezionare Apri con. Nella finestra di dialogo Apri con selezionare Editor di testo XML e quindi selezionare il pulsante OK. Si stanno per 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 Toaster e un Toast. Corrisponde all'evento definito nella classe Toaster. 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 copiare 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 Estensioni XML 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 selezionare 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 come aiuto 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 ToasterApplication e quindi selezionare Aggiungi riferimento. Selezionare la casella di spinta accanto al progetto Proxies. Assicurarsi inoltre che sia selezionata anche la casella di spunta accanto a ToasterComponent. Scegli il pulsante OK.

La compilazione del progetto dovrebbe avvenire ora. Eseguire il progetto e verificare che sia possibile creare un toast.