Generazione di eventi in componenti Windows RuntimeRaising events in Windows Runtime components

Nota

Per altre informazioni sulla generazione di eventi in un componente Windows Runtime c++/WinRT , vedere creare eventi in c++/WinRT.For more info about raising events in a C++/WinRT Windows Runtime Component, see Author events 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 desidera che JavaScript possa ricevere l'evento, è possibile implementare e/o generarlo in uno di questi modi.If your Windows Runtime component raises an event of a user-defined delegate type on a background thread (worker thread), and you want JavaScript to be able to receive the event, then you can implement and/or raise it in any one of these ways.

  • (Opzione 1) Generare l'evento tramite Windows. UI. Core. CoreDispatcher per eseguire il marshalling dell'evento nel contesto del thread JavaScript.(Option 1) Raise the event through the Windows.UI.Core.CoreDispatcher to marshal the event to the JavaScript thread context. Anche se in genere questa è l'opzione migliore, in alcuni scenari potrebbe non offrire prestazioni ottimali.Although typically this is the best option, in some scenarios it might not provide the fastest performance.
  • (Opzione 2) Usare ** Windows. Foundation. EventHandler <Object> ** (ma perdere le informazioni sul tipo di evento).(Option 2) Use Windows.Foundation.EventHandler<Object> (but lose the event type information). Se l'opzione 1 non è fattibile o se le prestazioni non sono adeguate, questa è una seconda scelta, a condizione che la perdita di informazioni sul tipo sia accettabile.If Option 1 is not feasible, or if its performance is not adequate, then this is a good second choice provided that loss of type information is acceptable. Se si sta creando un componente Windows Runtime C#, il tipo **Windows. Foundation. EventHandler <Object> ** non è disponibile, ma tale tipo viene proiettato in System. EventHandler, quindi è consigliabile usarlo in alternativa.If you're authoring a C# Windows Runtime Component, then the Windows.Foundation.EventHandler<Object> type is not available; instead, that type is projected to System.EventHandler, so you should use that instead.
  • Opzione 3: crea un proxy e uno stub personalizzati per il componente.(Option 3) Create your own proxy and stub for the component. Questa opzione è la più difficile da implementare, ma mantiene le informazioni sul tipo e può offrire prestazioni migliori in confronto all'opzione 1 in scenari più complessi.This option is the most difficult to implement, but it preserves type information and might provide better performance compared to Option 1 in demanding scenarios.

Se scegli di generare semplicemente un evento in un thread in background senza usare una di queste opzioni, un client JavaScript non riceverà l'evento.If you just raise an event on a background thread without using one of these options, a JavaScript client will not receive the event.

SfondoBackground

Tutti i componenti e le app Windows Runtime sono fondamentalmente oggetti COM, indipendentemente dal linguaggio usato per crearli.All Windows Runtime components and apps are fundamentally COM objects, no matter what language you use to create them. Nell'API Windows i componenti sono per la maggior parte oggetti COM agili in grado di comunicare ugualmente bene con oggetti nel thread in background e nel thread dell'interfaccia utente.In the Windows API, most of the components are agile COM objects that can communicate equally well with objects on the background thread and on the UI thread. Se un oggetto COM non può essere reso agile, richiede oggetti helper chiamati proxy e stub per comunicare con altri oggetti COM oltre il limite tra thread in background e thread dell'interfaccia utente.If a COM object can’t be made agile, then it requires helper objects known as proxies and stubs to communicate with other COM objects across the UI thread-background thread boundary. In termini di COM, questo comportamento è noto come comunicazione tra apartment thread.(In COM terms, this is known as communication between thread apartments.)

La maggior parte degli oggetti nell'API Windows è agile o ha proxy e stub integrati.Most of the objects in the Windows API are either agile or have proxies and stubs built in. Tuttavia, non è possibile creare proxy e stub per i tipi generici come Windows. Foundation. TypedEventHandler < TSender, TResult > perché non sono tipi completi finché non viene fornito l'argomento tipo.However, proxies and stubs can’t be created for generic types such as Windows.Foundation.TypedEventHandler<TSender, TResult> because they are not complete types until you provide the type argument. L'assenza di proxy e stub diventa un problema solo con i client JavaScript, ma se vuoi che il tuo componente possa essere usato da JavaScript e anche da un linguaggio C++ o .NET, devi usare una delle tre opzioni seguenti.It's only with JavaScript clients that the lack of proxies or stubs becomes an issue, but if you want your component to be usable from JavaScript as well as from C++ or a .NET language, then you must use one of the following three options.

Opzione 1: genera un evento tramite CoreDispatcher(Option 1) Raise the event through the CoreDispatcher

Puoi inviare eventi di qualsiasi tipo di delegato definito dall'utente usando Windows.UI.Core.CoreDispatcher perché JavaScript sia in grado di riceverli.You can send events of any user-defined delegate type by using the Windows.UI.Core.CoreDispatcher, and JavaScript will be able to receive them. In caso di dubbi sull'opzione da usare, prova questa per prima.If you are unsure which option to use, try this one first. Se la latenza tra la generazione dell'evento e la gestione dell'evento è un problema, prova una delle altre due opzioni.If latency between the event firing and the event handling becomes an issue, then try one of the other options.

L'esempio seguente mostra come usare CoreDispatcher per generare un evento fortemente tipizzato.The following example shows how to use the CoreDispatcher to raise a strongly-typed event. Osserva che l'argomento per il tipo è Toast e non Object.Notice that the type argument is Toast, not 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: usa EventHandler<Object>, ma con perdita delle informazioni sul tipo(Option 2) Use EventHandler<Object> but lose type information

Nota

Se si sta creando un componente Windows Runtime C#, il tipo **Windows. Foundation. EventHandler <Object> ** non è disponibile, ma tale tipo viene proiettato in System. EventHandler, quindi è consigliabile usarlo in alternativa.If you're authoring a C# Windows Runtime Component, then the Windows.Foundation.EventHandler<Object> type is not available; instead, that type is projected to System.EventHandler, so you should use that instead.

Un altro modo per inviare un evento da un thread in background consiste nell'usare l'oggetto Windows. Foundation. EventHandler < > come tipo dell'evento.Another way to send an event from a background thread is to use Windows.Foundation.EventHandler<Object> as the type of the event. Windows offre questa creazione concreta di un'istanza del tipo generico e fornisce un proxy e uno stub a questo scopo.Windows provides this concrete instantiation of the generic type and provides a proxy and stub for it. Lo svantaggio di questa opzione è la perdita delle informazioni sul tipo per gli argomenti dell'evento e il mittente.The downside is that the type information of your event args and sender is lost. I client C++ e .NET devono riconoscere tramite documentazione il tipo di cui eseguire di nuovo il casting alla ricezione dell'evento.C++ and .NET clients must know through documentation what type to cast back to when the event is received. I client JavaScript non hanno bisogno delle informazioni sul tipo originale.JavaScript clients don’t need the original type information. Questi client trovano le proprietà degli argomenti in base ai rispettivi nomi nei metadati.They find the arg properties, based on their names in the metadata.

Questo esempio mostra come usare Windows.Foundation.EventHandler<Object> in C#:This example shows how to use 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);
        }
    }
}

Utilizzerai questo evento sul lato JavaScript in questo modo:You consume this event on the JavaScript side like this:

toastCompletedEventHandler: function (event) {
   var toastType = event.toast.toastType;
   document.getElementById("toasterOutput").innerHTML = "<p>Made " + toastType + " toast</p>";
}

Opzione 3: crea un proxy e uno stub personalizzati(Option 3) Create your own proxy and stub

Per possibili prestazioni migliori nei tipi di evento definiti dall'utente con mantenimento completo delle informazioni sul tipo, devi creare oggetti proxy e stub personalizzati e incorporarli nel pacchetto dell'app.For potential performance gains on user-defined event types that have fully-preserved type information, you have to create your own proxy and stub objects and embed them in your app package. In genere, devi usare questa opzione solo in casi rari, quando le altre due non sono adeguate.Typically, you have to use this option only in rare situations where neither of the other two options are adequate. Inoltre, non è garantito che questa opzione offra prestazioni migliori rispetto alle altre due.Also, there is no guarantee that this option will provide better performance than the other two options. Le effettive prestazioni dipendono da molti fattori.Actual performance depends on many factors. Usa il profiler di Visual Studio o altri strumenti di profilatura per misurare le effettive prestazioni nell'applicazione e determinare se l'evento costituisce in realtà un collo di bottiglia.Use the Visual Studio profiler or other profiling tools to measure actual performance in your application and determine whether the event is in fact a bottleneck.

Le altre sezioni di questo articolo mostrano 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 per permettere a JavaScript di utilizzare un evento Windows.Foundation.TypedEventHandler<TSender, TResult> generato dal componente in un'operazione asincrona.The rest of this article shows how to use C# to create a basic Windows Runtime component, and then use C++ to create a DLL for the proxy and stub that will enable JavaScript to consume a Windows.Foundation.TypedEventHandler<TSender, TResult> event that's raised by the component in an async operation. Puoi anche usare C++ o Visual Basic per creare il componente.(You can also use C++ or Visual Basic to create the component. I passaggi per la creazione dei proxy e degli stub sono identici. Questa procedura dettagliata è basata sull'articolo Creazione di un esempio di componente Windows Runtime in-process (C++/CX) e aiuta a descriverne gli scopi.The steps that are related to creating the proxies and stubs are the same.) This walkthrough is based on Creating a Windows Runtime in-process component sample (C++/CX) and helps explain its purposes.

Questa procedura dettagliata è costituita da queste parti.This walkthrough has these parts.

  • Qui creerai due classi Windows Runtime di base.Here you will create two basic Windows Runtime classes. Una classe espone un evento di tipo Windows. Foundation. TypedEventHandler < TSender, TResult > e l'altra classe è il tipo che viene restituito a JavaScript come argomento per TValue.One class exposes an event of type Windows.Foundation.TypedEventHandler<TSender, TResult> and the other class is the type that's returned to JavaScript as the argument for TValue. Queste classi non potranno comunicare con JavaScript fino a quando non completi i passaggi successivi.These classes can't communicate with JavaScript until you complete the later steps.
  • L'app attiva l'oggetto classe principale, chiama un metodo e gestisce un evento generato dal componente Windows Runtime.This app activates the main class object, calls a method, and handles an event that's raised by the Windows Runtime component.
  • Queste operazioni sono richieste dagli strumenti che generano le classi proxy e stub.These are required by the tools that generate the proxy and stub classes.
  • Potrai quindi usare il file IDL per generare il codice sorgente C per il proxy e lo stub.You then use the IDL file to generate the C source code for the proxy and stub.
  • Registra gli oggetti proxy e stub in modo che il runtime COM possa trovarli e fai riferimento alla DLL per il proxy e lo stub nel progetto di app.Register the proxy-stub objects so that the COM runtime can find them, and reference the proxy-stub DLL in the app project.

Per creare il componente Windows RuntimeTo create the Windows Runtime component

Nella barra dei menu di Visual Studio scegliere file > nuovo progetto.In Visual Studio, on the menu bar, choose File > New Project. Nella finestra di dialogo Nuovo progetto espandi JavaScript > Windows universale e quindi seleziona App vuota.In the New Project dialog box, expand JavaScript > Universal Windows and then select Blank App. Assegna al progetto il nome ToasterApplication e quindi scegli il pulsante OK.Name the project ToasterApplication and then choose the OK button.

Aggiungi un componente Windows Runtime in C# alla soluzione: in Esplora soluzioni apri il menu di scelta rapida per la soluzione e quindi scegli Aggiungi > Nuovo progetto.Add a C# Windows Runtime component to the solution: In Solution Explorer, open the shortcut menu for the solution and then choose Add > New Project. Espandere Visual C# > Microsoft Store quindi selezionare Windows Runtime componente.Expand Visual C# > Microsoft Store and then select Windows Runtime Component. Assegna al progetto il nome ToasterComponent e quindi scegli il pulsante OK.Name the project ToasterComponent and then choose the OK button. ToasterComponent sarà lo spazio dei nomi radice per i componenti che creerai nei passaggi successivi.ToasterComponent will be the root namespace for the components you will create in later steps.

In Esplora soluzioni apri il menu di scelta rapida per la soluzione e quindi scegli Proprietà.In Solution Explorer, open the shortcut menu for the solution and then choose Properties. Nella finestra di dialogo Pagine delle proprietà seleziona Proprietà di configurazione nel riquadro sinistro e quindi nella parte superiore della finestra di dialogo imposta Configurazione su Debug e Piattaforma su x86, x64 o ARM.In the Property Pages dialog box, select Configuration Properties in the left pane, and then at the top of the dialog box, set Configuration to Debug and Platform to x86, x64, or ARM. Fare clic su OK .Choose the OK button.

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.Important Platform = Any CPU won’t work because it's not valid for the native-code Win32 DLL that you'll add to the solution later.

In Esplora soluzioni rinomina class1.cs in ToasterComponent.cs in modo che corrisponda al nome del progetto.In Solution Explorer, rename class1.cs to ToasterComponent.cs so that it matches the name of the project. Visual Studio rinomina automaticamente la classe nel file in modo che corrisponda al nuovo nome file.Visual Studio automatically renames the class in the file to match the new file name.

Nel file CS aggiungi una direttiva using per lo spazio dei nomi Windows.Foundation per inserire TypedEventHandler nell'ambito.In the .cs file, add a using directive for the Windows.Foundation namespace to bring TypedEventHandler into scope.

Quando sono necessari proxy e stub, il componente deve usare interfacce per esporre i membri pubblici.When you require proxies and stubs, your component must use interfaces to expose its public members. In ToasterComponent.cs definisci un'interfaccia per il componente Toaster e un'altra per l'oggetto Toast prodotto dal componente.In ToasterComponent.cs, define an interface for the toaster, and another one for the Toast that the toaster produces.

Nota   In C# è possibile ignorare questo passaggio.Note In C# you can skip this step. Al suo posto, crea prima di tutto una classe e quindi apri il menu di scelta rapida corrispondente e scegli Refactoring > Estrai interfaccia.Instead, first create a class, and then open its shortcut menu and choose Refactor > Extract Interface. Nel codice generato fornisci manualmente accessibilità pubblica alle interfacce.In the code that's generated, manually give the interfaces public accessibility.

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

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

L'interfaccia IToast ha una stringa che può essere recuperata per descrivere il tipo dell'oggetto Toast.The IToast interface has a string that can be retrieved to describe the type of toast. L'interfaccia IToaster ha un metodo per creare l'oggetto Toast e un evento per indicare che l'oggetto è stato creato.The IToaster interface has a method to make toast, and an event to indicate that the toast is made. Poiché questo evento restituisce la parte specifica, ovvero il tipo, dell'oggetto Toast, è chiamato evento tipizzato.Because this event returns the particular piece (that is, type) of toast, it's known as a typed event.

Quindi, abbiamo bisogno di classi che implementino queste interfacce e che siano pubbliche e sealed in modo da essere accessibili dall'app JavaScript che programmerai successivamente.Next, we need classes that implement these interfaces, and are public and sealed so that they are accessible from the JavaScript app that you'll program later.

    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 l'oggetto Toast e quindi abbiamo accelerato l'elemento di lavoro del pool di thread per generare la notifica.In the preceding code, we create the toast and then spin up a thread-pool work item to fire the notification. 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 attività che dipende dai risultati dell'operazione.Although the IDE might suggest that you apply the await keyword to the async call, it isn’t necessary in this case because the method doesn’t do any work that depends on the results of the operation.

Nota   La chiamata asincrona nel codice precedente USA ThreadPool. RunAsync esclusivamente per dimostrare un modo semplice di generare l'evento in un thread in background.Note The async call in the preceding code uses ThreadPool.RunAsync solely to demonstrate a simple way to fire the event on a background thread. Potresti scrivere questo metodo particolare come mostrato nell'esempio seguente e il metodo funzionerebbe nel modo corretto perché l'utilità di pianificazione .NET esegue automaticamente il marshalling di chiamate asincrone/await di nuovo al thread dell'interfaccia utente.You could write this particular method as shown in the following example, and it would work fine because the .NET Task scheduler automatically marshals async/await calls back to the UI thread.  

    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.If you build the project now, it should build cleanly.

Per programmare l'app JavaScriptTo program the JavaScript app

A questo punto possiamo aggiungere un pulsante all'app JavaScript per indurla a utilizzare la classe definita per la creazione del toast.Now we can add a button to the JavaScript app to cause it to use the class we just defined to make toast. Prima però dobbiamo aggiungere un riferimento al progetto ToasterComponent che abbiamo appena creato.Before we do this, we must add a reference to the ToasterComponent project we just created. In Esplora soluzioni aprire il menu di scelta rapida per il progetto ToasterApplication, scegliere Aggiungi > riferimenti, quindi scegliere il pulsante Aggiungi nuovo riferimento .In Solution Explorer, open the shortcut menu for the ToasterApplication project, choose Add > References, and then choose the Add New Reference button. Nella finestra di dialogo Aggiungi riferimento, nel riquadro sinistro sotto Soluzione, seleziona il progetto del componente, quindi, nel riquadro centrale, seleziona ToasterComponent.In the Add Reference dialog box, in the left pane under Solution, select the component project, and then in the middle pane, select ToasterComponent. Fare clic su OK .Choose the OK button.

In Esplora soluzioni aprire il menu di scelta rapida per il progetto ToasterApplication, quindi scegliere Imposta come progetto di avvio.In Solution Explorer, open the shortcut menu for the ToasterApplication project and then choose Set as Startup Project.

Alla fine del file default.js aggiungi uno spazio dei nomi per includere le funzioni chiamanti e chiamate dal componente.At the end of the default.js file, add a namespace to contain the functions to call the component and be called back by it. Lo spazio dei nomi avrà due funzioni: generare il toast e gestire l'evento di completamento del toast.The namespace will have two functions, one to make toast and one to handle the toast-complete event. L'implementazione di makeToast crea un oggetto toaster, registra il gestore dell'evento e crea il popup.The implementation of makeToast creates a Toaster object, registers the event handler, and makes the toast. Finora il gestore eventi non serve a molto, come illustrato di seguito:So far, the event handler doesn’t do much, as shown here:

    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.The makeToast function must be hooked up to a button. Aggiorna il file default.html per includere un pulsante e dello spazio per restituire il risultato della creazione del toast:Update default.html to include a button and some space to output the result of making 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 usa un TypedEventHandler, è ora possibile eseguire l'app nel computer locale e fare clic sul pulsante per creare un avviso popup.If we weren’t using a TypedEventHandler, we would now be able to run the app on the local machine and click the button to make toast. Ma nella nostra app non accade nulla.But in our app, nothing happens. Per scoprirne il motivo, eseguiamo il debug del codice gestito che genera l'ToastCompletedEvent.To find out why, let’s debug the managed code that fires the ToastCompletedEvent. Arrestare il progetto, quindi sulla barra dei menu scegliere debug > Proprietà applicazione.Stop the project, and then on the menu bar, choose Debug > Toaster Application properties. Modificare il tipo di debugger in solo gestito.Change Debugger Type to Managed Only. Nuovamente nella barra dei menu scegliere debug > eccezioni, quindi selezionare eccezioni Common Language Runtime.Again on the menu bar, choose Debug > Exceptions, and then select Common Language Runtime Exceptions.

Esegui l'app e fai clic sul pulsante per la generazione del toast.Now run the app and click the make-toast button. Il debugger rileva un'eccezione di cast non valido.The debugger catches an invalid cast exception. Sebbene non sia evidente dal messaggio, questa eccezione si verifica perché ai proxy manca l'interfaccia.Although it’s not obvious from its message, this exception is occurring because proxies are missing for that interface.

proxy mancante

Il primo passaggio per creare un proxy e uno stub per un componente consiste nell'aggiungere un ID o un GUID univoco alle interfacce.The first step in creating a proxy and stub for a component is to add a unique ID or GUID to the interfaces. 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++.However, the GUID format to use differs depending on whether you're coding in C#, Visual Basic, or another .NET language, or in C++.

Per generare GUID per le interfacce del componente (C# e altri linguaggi .NET)To generate GUIDs for the component's interfaces (C# and other .NET languages)

Sulla barra dei menu scegliere strumenti > Crea GUID.On the menu bar, choose Tools > Create GUID. Nella finestra di dialogo selezionare 5.In the dialog box, select 5. [GUID ("xxxxxxxx-xxxx... xxxx ") ] .[Guid("xxxxxxxx-xxxx...xxxx")]. Scegli il pulsante Nuovo GUID, quindi il pulsante Copia.Choose the New GUID button and then choose the Copy button.

strumento generatore di GUID

Tornare alla definizione dell'interfaccia e incollare il nuovo GUID appena prima dell'interfaccia IToaster, come illustrato nell'esempio seguente.Go back to the interface definition, and then paste the new GUID just before the IToaster interface, as shown in the following example. Non utilizzare il GUID nell'esempio.(Don't use the GUID in the example. Ogni interfaccia univoca deve avere un proprio GUID.Every unique interface should have its own GUID.)

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

Aggiungere una direttiva using per lo spazio dei nomi System. Runtime. InteropServices.Add a using directive for the System.Runtime.InteropServices namespace.

Ripetere questi passaggi per l'interfaccia IToast.Repeat these steps for the IToast interface.

Per generare GUID per le interfacce del componente (C++)To generate GUIDs for the component's interfaces (C++)

Sulla barra dei menu scegliere strumenti > Crea GUID.On the menu bar, choose Tools > Create GUID. Nella finestra di dialogo selezionare 3.In the dialog box, select 3. GUID dello struct const statico = {...}.static const struct GUID = {...}. Scegli il pulsante Nuovo GUID, quindi il pulsante Copia.Choose the New GUID button and then choose the Copy button.

Incollare il GUID appena prima della definizione dell'interfaccia IToaster.Paste the GUID just before the IToaster interface definition. Il GUID incollato dovrebbe essere come nell'esempio seguente.After you paste, the GUID should resemble the following example. Non utilizzare il GUID nell'esempio.(Don't use the GUID in the example. Ogni interfaccia univoca deve avere un proprio GUID.Every unique interface should have its own 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 portare GuidAttribute nell'ambito.Add a using directive for Windows.Foundation.Metadata to bring GuidAttribute into scope.

A questo punto converti manualmente il GUID del costruttore in GuidAttribute in modo da formattarlo come illustrato nell'esempio seguente.Now manually convert the const GUID to a GuidAttribute so that it's formatted as shown in the following example. Nota che le parentesi graffe vengono sostituite con le parentesi quadre e tonde e il punto e virgola finale viene rimosso.Notice that the curly braces are replaced with brackets and parentheses, and the trailing semicolon is removed.

// {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.Repeat these steps for the IToast interface.

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 generando il codice sorgente C per il proxy e lo stub inserendo il file IDL nello strumento da riga di comando MIDL.Now that the interfaces have unique IDs, we can create an IDL file by feeding the .winmd file into the winmdidl command-line tool, and then generate the C source code for the proxy and stub by feeding that IDL file into the MIDL command-line tool. In Visual Studio questa operazione viene eseguita automaticamente se crei degli eventi post-compilazione come illustrato di seguito.Visual Studio do this for us if we create post-build events as shown in the following steps.

Per generare il codice sorgente del proxy e dello stubTo generate the proxy and stub source code

Per aggiungere un evento di post-compilazione personalizzato, in Esplora soluzioni apri il menu di scelta rapida del progetto ToasterComponent, quindi scegli Proprietà.To add a custom post-build event, in Solution Explorer, open the shortcut menu for the ToasterComponent project and then choose Properties. Nel riquadro sinistro delle pagine delle proprietà seleziona Eventi di compilazione, quindi scegli il pulsante Modifica post-compilazione.In the left pane of the property pages, select Build Events, and then choose the Edit Post-build button. Aggiungi i seguenti comandi alla riga di comando di post-compilazione.Add the following commands to the post-build command line. (Il file batch deve essere chiamato per primo per impostare le variabili di ambiente per trovare lo strumento winmdidl).(The batch file must be called first to set the environment variables to find the winmdidl tool.)

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, impostare il parametro MIDL/ENV su x64 o ARM32.Important  For an ARM or x64 project configuration, change the MIDL /env parameter to x64 or arm32.

Per assicurarsi che il file IDL venga rigenerato ogni volta che viene modificato il file con estensione WinMD, modificare eseguire l'evento di post-compilazione in quando la compilazione aggiorna l'output del progetto.To make sure the IDL file is regenerated every time the .winmd file is changed, change Run the post-build event to When the build updates the project output. La pagina delle proprietà eventi di compilazione dovrebbe essere simile alla seguente:  eventi di compilazioneThe Build Events property page should resemble this: build events

Ricompila la soluzione per generare e compilare il file IDL.Rebuild the solution to generate and compile the 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.You can verify that MIDL correctly compiled the solution by looking for ToasterComponent.h, ToasterComponent_i.c, ToasterComponent_p.c, and dlldata.c in the ToasterComponent project directory.

Per compilare il codice del proxy e dello stub in una DLLTo compile the proxy and stub code into a DLL

Dopo avere creato i file necessari, puoi compilarli per produrre una DLL, che è un file C++.Now that you have the required files, you can compile them to produce a DLL, which is a C++ file. Per semplificare il più possibile questa attività, aggiungi un nuovo progetto per supportare la compilazione dei proxy.To make this as easy as possible, add a new project to support building the proxies. Aprire il menu di scelta rapida per la soluzione ToasterApplication, quindi scegliere aggiungi > nuovo progetto.Open the shortcut menu for the ToasterApplication solution and then choose Add > New Project. Nel riquadro sinistro della finestra di dialogo nuovo progetto espandere Visual C++ > > Windows Univeral, quindi nel riquadro centrale selezionare dll (app UWP).In the left pane of the New Project dialog box, expand Visual C++ > Windows > Univeral Windows, and then in the middle pane, select DLL (UWP apps). (Si noti che questo non è un progetto di componente Windows Runtime C++). Assegnare al progetto il nome proxy, quindi scegliere il pulsante OK .(Notice that this is NOT a C++ Windows Runtime Component project.) Name the project Proxies and then choose the OK button. Questi file verranno aggiornati dagli eventi post-compilazione quando vengono apportate modifiche nella classe C#.These files will be updated by the post-build events when something changes in the C# class.

Per impostazione predefinita, il progetto Proxy genera file di intestazione .h e file .cpp di C++.By default, the Proxies project generates header .h files and C++ .cpp files. Poiché la DLL viene compilata dai file scritti da MIDL, i file con estensione .h e . cpp non sono necessari.Because the DLL is built from the files produced from MIDL, the .h and .cpp files are not required. In Esplora soluzioni aprire il menu di scelta rapida, scegliere Rimuovi, quindi confermare l'eliminazione.In Solution Explorer, open the shortcut menu for them, choose Remove, and then confirm the deletion.

Ora che il progetto è vuoto, puoi aggiungere di nuovo i file generati da MIDL.Now that the project is empty, you can add back the MIDL-generated files. Aprire il menu di scelta rapida per il progetto proxy, quindi scegliere aggiungi > elemento esistente.Open the shortcut menu for the Proxies project, and then choose Add > Existing Item. 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.In the dialog box, navigate to the ToasterComponent project directory and select these files: ToasterComponent.h, ToasterComponent_i.c, ToasterComponent_p.c, and dlldata.c files. Fare clic sul pulsante Aggiungi.Choose the Add button.

Nel progetto Proxy crea un file con estensione .def per definire le esportazioni di DLL descritte in dlldata.c.In the Proxies project, create a .def file to define the DLL exports described in dlldata.c. Aprire il menu di scelta rapida per il progetto, quindi scegliere aggiungi > nuovo elemento.Open the shortcut menu for the project, and then choose Add > New Item. Nel riquadro sinistro della finestra di dialogo seleziona Codice, quindi, nel riquadro centrale, seleziona File di definizione moduli.In the left pane of the dialog box, select Code and then in the middle pane, select Module-Definition File. Denominare il file Proxys. def, quindi scegliere il pulsante Aggiungi .Name the file proxies.def and then choose the Add button. Apri il file .def e modificalo per includere le esportazioni definite nel file dlldata.c:Open this .def file and modify it to include the EXPORTS that are defined in dlldata.c:

EXPORTS
    DllCanUnloadNow         PRIVATE
    DllGetClassObject       PRIVATE

Se compili il progetto a questo punto, la compilazione non riuscirà.If you build the project now, it will fail. Per poter compilare il progetto, devi modificare il modo in cui il progetto viene compilato e collegato.To correctly compile this project, you have to change how the project is compiled and linked. In Esplora soluzioni aprire il menu di scelta rapida per il progetto proxy, quindi scegliere Proprietà.In Solution Explorer, open the shortcut menu for the Proxies project and then choose Properties. Modificare le pagine delle proprietà come indicato di seguito.Change the property pages as follows.

Nel riquadro sinistro selezionare C/C++ > preprocessore, quindi nel riquadro destro selezionare definizioni preprocessore, fare clic sul pulsante freccia giù e quindi scegliere modifica.In the left pane, select C/C++ > Preprocessor, and then in the right pane, select Preprocessor Definitions, choose the down-arrow button, and then select Edit. Aggiungi le definizioni nella casella:Add these definitions in the box:

WIN32;_WINDOWS

In C/C++ > le intestazioni precompilate, modificare l' intestazione precompilata in non usando le intestazioniprecompilate, quindi scegliere il pulsante applica .Under C/C++ > Precompiled Headers, change Precompiled Header to Not Using Precompiled Headers, and then choose the Apply button.

In linker > generalemodificare Ignora la libreria di importazione in Yes, quindi scegliere il pulsante applica .Under Linker > General, change Ignore Import Library to Yes, and then choose the Apply button.

In linker > inputselezionare dipendenze aggiuntive, fare clic sul pulsante freccia giù e quindi selezionare modifica.Under Linker > Input, select Additional Dependencies, choose the down-arrow button, and then select Edit. Aggiungi questo testo nella casella:Add this text in the box:

rpcrt4.lib;runtimeobject.lib

Non inserire queste librerie direttamente nella riga dell'elenco.Do not paste these libs directly into the list row. Utilizzare la casella di modifica per assicurarsi che MSBuild in Visual Studio mantenga le dipendenze aggiuntive corrette.Use the Edit box to ensure that MSBuild in Visual Studio will maintain the correct additional dependencies.

Dopo aver apportato queste modifiche, scegliere il pulsante OK nella finestra di dialogo pagine delle proprietà .When you have made these changes, choose the OK button in the Property Pages dialog box.

Successivamente, inserisci una dipendenza nel progetto ToasterComponent.Next, take a dependency on the ToasterComponent project. In questo modo, Toaster verrà compilato prima del progetto Proxy.This ensures that the Toaster will build before the proxy project builds. Ciò è fondamentale perché il progetto Toaster è responsabile della generazione dei file necessari a compilare il proxy.This is required because the Toaster project is responsible for generating the files to build the proxy.

Apri il menu di scelta rapida del progetto Proxy e scegli Dipendenze progetto.Open the shortcut menu for the Proxies project and then choose Project Dependencies. 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.Select the check boxes to indicate that the Proxies project depends on the ToasterComponent project, to ensure that Visual Studio builds them in the correct order.

Verificare che la soluzione venga compilata correttamente scegliendo compila > Ricompila soluzione sulla barra dei menu di Visual Studio.Verify that the solution builds correctly by choosing Build > Rebuild Solution on the Visual Studio menu bar.

Per registrare il proxy e lo stubTo register the proxy and stub

Nel progetto ToasterApplication aprire il menu di scelta rapida per Package. appxmanifest, quindi scegliere Apri con.In the ToasterApplication project, open the shortcut menu for package.appxmanifest and then choose Open With. Nella finestra di dialogo Apri con selezionare editor di testo XML , quindi scegliere il pulsante OK .In the Open With dialog box, select XML Text Editor and then choose the OK button. In questo modo verrà incollato un codice XML che fornisce una registrazione dell'estensione Windows. activatableClass. proxyStub e che si basano sui GUID del proxy.We're going to paste in some XML that provides a windows.activatableClass.proxyStub extension registration and which are based on the GUIDs in the proxy. Per individuare i GUID da utilizzare nel file .appxmanifest, apri il file ToasterComponent_i.c.To find the GUIDs to use in the .appxmanifest file, open ToasterComponent_i.c. Cerca le voci simili a quelle nell'esempio seguente.Find entries that resemble the ones in the following example. Si notino inoltre le definizioni per IToast, IToaster e una terza interfaccia, ovvero un gestore eventi tipizzato che presenta due parametri: un tostapane e un avviso popup.Also notice the definitions for IToast, IToaster, and a third interface—a typed event handler that has two parameters: a Toaster and Toast. Corrisponde all'evento definito nella classe del tostapane.This matches the event that's defined in the Toaster class. Si noti che i GUID per IToast e IToaster corrispondono ai GUID definiti nelle interfacce nel file C#.Notice that the GUIDs for IToast and IToaster match the GUIDs that are defined on the interfaces in the C# file. Poiché l'interfaccia del gestore eventi tipizzato viene generata automaticamente, anche il GUID corrispondente viene generato automaticamente.Because the typed event handler interface is autogenerated, the GUID for this interface is also autogenerated.

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, li incolliamo in Package. appxmanifest in un nodo che aggiungiamo e nomiamo Extensions, quindi li riformatco.Now we copy the GUIDs, paste them in package.appxmanifest in a node that we add and name Extensions, and then reformat them. La voce del manifesto è simile al seguente esempio, ma anche in questo caso è necessario utilizzare i propri GUID.The manifest entry resembles the following example—but again, remember to use your own GUIDs. Nota che il GUID di ClassId in XML è lo stesso di ITypedEventHandler2.Notice that the ClassId GUID in the XML is the same as ITypedEventHandler2. Questo perché il GUID è il primo elencato in ToasterComponent_i.c.This is because that GUID is the first one that's listed in ToasterComponent_i.c. I GUID sono senza distinzione tra maiuscole e minuscole.The GUIDs here are case-insensitive. Anziché riformattare manualmente i GUID per IToast e IToaster, è possibile tornare alle definizioni dell'interfaccia e ottenere il valore GuidAttribute, che ha il formato corretto.Instead of manually reformatting the GUIDs for IToast and IToaster, you can go back into the interface definitions and get the GuidAttribute value, which has the correct format. In C++, nel commento è presente un GUID formattato correttamente.In C++, there is a correctly-formatted GUID in the comment. Ad ogni modo, è necessario riformattare il GUID usato sia per ClassId che per il gestore dell'evento.In any case, you must manually reformat the GUID that's used for both the ClassId and the event handler.

      <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 extensions come figlio diretto del nodo del pacchetto e un peer di, ad esempio, il nodo resources.Paste the Extensions XML node as a direct child of the Package node, and a peer of, for example, the Resources node.

Prima di proseguire assicurati che:Before moving on, it’s important to ensure that:

  • Il ProxyStub ClassID è impostato sul primo GUID nel file ToasterComponent _ i. c.The ProxyStub ClassId is set to the first GUID in the ToasterComponent_i.c file. Utilizza il primo GUID definito in questo file per il classId,Use the first GUID that's defined in this file for the classId. che potrebbe essere lo stesso GUID di ITypedEventHandler2.(This might be the same as the GUID for ITypedEventHandler2.)
  • Il percorso è il percorso relativo del pacchetto del file binario del proxy.The Path is the package relative path of the proxy binary. In questa procedura dettagliata, il file proxies.dll si trova nella stessa cartella di ToasterApplication.winmd.(In this walkthrough, proxies.dll is in the same folder as ToasterApplication.winmd.)
  • I GUID siano in formato corretto,The GUIDs are in the correct format. dal momento che è facile che sia errato.(This is easy to get wrong.)
  • Gli ID di interfaccia nel manifesto corrispondono a IID nel _ file ToasterComponent i. c.The interface IDs in the manifest match the IIDs in ToasterComponent_i.c file.
  • I nomi di interfaccia siano univoci nel manifesto.The interface names are unique in the manifest. Poiché questi non vengono utilizzati dal sistema, puoi scegliere i valori.Because these are not used by the system, you can choose the values. È consigliabile scegliere nomi di interfaccia che corrispondano chiaramente alle interfacce definite.It is a good practice to choose interface names that clearly match interfaces that you have defined. Per le interfacce generate, i nomi devono essere indicativi delle interfacce generate.For generated interfaces, the names should be indicative of the generated interfaces. È possibile usare il _ file ToasterComponent i. c per generare nomi di interfaccia.You can use the ToasterComponent_i.c file to help you generate interface names.

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.If you try to run the solution now, you will get an error that proxies.dll is not part of the payload. Aprire il menu di scelta rapida per la cartella riferimenti nel progetto ToasterApplication, quindi scegliere Aggiungi riferimento.Open the shortcut menu for the References folder in the ToasterApplication project and then choose Add Reference. Seleziona la casella di controllo accanto al progetto Proxy.Select the check box next to the Proxies project. Assicurati che anche la casella di controllo accanto a ToasterComponent sia selezionata.Also, make sure that the check box next to ToasterComponent is also selected. Fare clic su OK .Choose the OK button.

La compilazione del progetto dovrebbe avvenire senza problemi.The project should now build. Esegui il progetto e verifica di poter generare il toast.Run the project and verify that you can make toast.