Acionando eventos em componentes do Windows RuntimeRaising events in Windows Runtime components

Observação

Para obter mais informações sobre como gerar eventos em um componente Windows Runtime do c++/WinRT , consulte criar eventos em c++/WinRT.For more info about raising events in a C++/WinRT Windows Runtime Component, see Author events in C++/WinRT.

Se o componente de Windows Runtime gerar um evento de um tipo delegado definido pelo usuário em um thread em segundo plano (thread de trabalho) e você quiser que o JavaScript possa receber o evento, você poderá implementá-lo e/ou procebê-lo de qualquer uma dessas maneiras.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.

  • (Opção 1) Gere o evento por meio do Windows. UI. Core. CoreDispatcher para realizar marshaling do evento para o contexto do thread JavaScript.(Option 1) Raise the event through the Windows.UI.Core.CoreDispatcher to marshal the event to the JavaScript thread context. Embora normalmente essa seja a melhor opção, em alguns cenários ela talvez não ofereça o desempenho mais rápido.Although typically this is the best option, in some scenarios it might not provide the fastest performance.
  • (Opção 2) Use ** Windows. Foundation. EventHandler <Object> ** (Mas perca as informações do tipo de evento).(Option 2) Use Windows.Foundation.EventHandler<Object> (but lose the event type information). Se a opção 1 não for viável, ou se seu desempenho não for adequado, essa é uma boa opção de segunda escolha que a perda de informações de tipo é aceitável.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 você estiver criando um componente de Windows Runtime do C#, o tipo Windows. Foundation. <Object> EventHandler não estará disponível; em vez disso, esse tipo é projetado para System. EventHandler, portanto, você deve usá-lo em vez disso.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.
  • (Opção 3) Crie os próprios proxy e stub do componente.(Option 3) Create your own proxy and stub for the component. Essa opção é mais difícil de implementar, mas preserva informações sobre o tipo e pode fornecer um desempenho melhor em comparação com a Opção 1 em cenários exigentes.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 você simplesmente acionar um evento em um thread em segundo plano sem usar uma dessas opções, um cliente JavaScript não receberá o 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.

Segundo planoBackground

Todos os componentes do Tempo de Execução do Windows e aplicativos são fundamentalmente objetos COM, independentemente da linguagem que você usa para criá-los.All Windows Runtime components and apps are fundamentally COM objects, no matter what language you use to create them. Na API do Windows, a maioria dos componentes é de objetos COM Agile que podem se comunicar igualmente bem com objetos no thread em segundo plano e no thread da interface do usuário.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. Caso um objeto COM não possa ser Agile, isso requer que objetos auxiliares conhecidos como proxies e stubs se comuniquem com outros objetos COM em todo o limite de thread em segundo plano do thread de interface do usuário.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. (Em termos de COM, isso é conhecido como comunicação entre apartments de thread.)(In COM terms, this is known as communication between thread apartments.)

A maioria dos objetos na API do Windows é Agile ou tem proxies e stubs integrados.Most of the objects in the Windows API are either agile or have proxies and stubs built in. No entanto, proxies e stubs não podem ser criados para tipos genéricos, como Windows.Foundation.TypedEventHandler<TSender, TResult> porque eles só serão tipos completos quando você fornecer o argumento de 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. É apenas com clientes JavaScript que a falta de proxies ou stubs se torna um problema, mas caso queira que o componente seja utilizável em JavaScript, bem como em C++ ou em uma linguagem .NET, você deve usar uma das três opções a seguir.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.

(Opção 1) Acionar o evento por meio de CoreDispatcher(Option 1) Raise the event through the CoreDispatcher

Você pode enviar eventos de qualquer tipo de representante definido pelo usuário usando o Windows.UI.Core.CoreDispatcher, e o JavaScript poderá recebê-los.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. Caso você não tenha certeza de qual opção usar, tente esta primeiro.If you are unsure which option to use, try this one first. Caso a latência entre o acionamento do evento e a manipulação do evento se torne um problema, tente uma das outras opções.If latency between the event firing and the event handling becomes an issue, then try one of the other options.

O exemplo a seguir mostra como usar o CoreDispatcher para acionar um evento fortemente tipado.The following example shows how to use the CoreDispatcher to raise a strongly-typed event. O argumento do tipo é Toast, e não 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
}

(Opção 2) Usar EventHandler <Object>, mas perder informações sobre o tipo(Option 2) Use EventHandler<Object> but lose type information

Observação

Se você estiver criando um componente de Windows Runtime do C#, o tipo Windows. Foundation. <Object> EventHandler não estará disponível; em vez disso, esse tipo é projetado para System. EventHandler, portanto, você deve usá-lo em vez disso.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.

Outra maneira de enviar um evento de um thread em segundo plano é usar o objeto Windows. Foundation. EventHandler < > como o tipo do evento.Another way to send an event from a background thread is to use Windows.Foundation.EventHandler<Object> as the type of the event. O Windows oferece essa instanciação concreta do tipo genérico e fornece um proxy e um stub para ele.Windows provides this concrete instantiation of the generic type and provides a proxy and stub for it. A desvantagem é que as informações de tipo dos argumentos de evento e remetente são perdidas.The downside is that the type information of your event args and sender is lost. Os clientes C++ e .NET devem saber pela documentação para qual tipo reconverter quando o evento é recebido.C++ and .NET clients must know through documentation what type to cast back to when the event is received. Os clientes JavaScript não precisam das informações sobre o tipo original.JavaScript clients don’t need the original type information. Eles encontram as propriedades arg, com base nos nomes nos metadados.They find the arg properties, based on their names in the metadata.

Este exemplo mostra como usar Windows.Foundation.EventHandler<Object> em 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);
        }
    }
}

Você consome esse evento no lado do JavaScript desta forma: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>";
}

(Opção 3) Criar os próprios proxy e stub(Option 3) Create your own proxy and stub

Para ganhos de desempenho potenciais em tipos de eventos definidos pelo usuário que tenham informações de tipo totalmente preservadas, você precisa criar os próprios objetos de proxy e stub e incorporá-los ao pacote do aplicativo.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. Normalmente, você só precisa usar essa opção em situações raras nas quais nenhuma das outras duas opções são adequadas.Typically, you have to use this option only in rare situations where neither of the other two options are adequate. Além disso, não há garantia de que essa opção fornecerá desempenho melhor do que as outras duas opções.Also, there is no guarantee that this option will provide better performance than the other two options. O desempenho real depende de muitos fatores.Actual performance depends on many factors. Use o criador de perfil do Visual Studio ou outras ferramentas de criação de perfil para avaliar o desempenho real no aplicativo e determinar se o evento é, na verdade, um afunilamento.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.

O restante deste artigo mostra como usar C# para criar um componente do Tempo de Execução do Windows básico e usar C++ para criar uma DLL para o proxy e o stub que permitirão que o JavaScript consuma um evento Windows.Foundation.TypedEventHandler<TSender, TResult> acionado pelo componente em uma operação assíncrona.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. (Também é possível usar C++ ou Visual Basic para criar o componente.(You can also use C++ or Visual Basic to create the component. As etapas relacionadas à criação de proxies e stubs são as mesmas.) Este procedimento passo a passo se baseia na criação de uma amostra de componente no processo de Windows Runtime (C++/CX) e ajuda a explicar as finalidades.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.

Este tutorial tem essas partes.This walkthrough has these parts.

  • Aqui, você criará duas classes de Tempo de Execução do Windows básicas.Here you will create two basic Windows Runtime classes. Uma classe expõe um evento do tipo Windows.Foundation.TypedEventHandler<TSender, TResult> e a outra classe é o tipo retornado para o JavaScript como o argumento de 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. Essas classes não podem se comunicar com JavaScript até você concluir as etapas posteriores.These classes can't communicate with JavaScript until you complete the later steps.
  • Este aplicativo ativa o objeto de classe principal, chama um método e manipula um evento acionado pelo componente do Tempo de Execução do Windows.This app activates the main class object, calls a method, and handles an event that's raised by the Windows Runtime component.
  • Elas são exigidas pelas ferramentas para gerar as classes de proxy e stub.These are required by the tools that generate the proxy and stub classes.
  • Em seguida, você usa o arquivo IDL para gerar o código-fonte C para o proxy e o stub.You then use the IDL file to generate the C source code for the proxy and stub.
  • Registre os objetos proxy-stub de maneira que o tempo de execução COM possa encontrá-los e faça referência à DLL proxy-stub no projeto do aplicativo.Register the proxy-stub objects so that the COM runtime can find them, and reference the proxy-stub DLL in the app project.

Para criar o componente do Tempo de Execução do WindowsTo create the Windows Runtime component

No Visual Studio, na barra de menus, escolha arquivo > novo projeto.In Visual Studio, on the menu bar, choose File > New Project. Na caixa de diálogo Novo Projeto, expanda JavaScript > Universal Windows e selecione Aplicativo em Branco.In the New Project dialog box, expand JavaScript > Universal Windows and then select Blank App. Nomeie o projeto ToasterApplication e escolha o botão OK.Name the project ToasterApplication and then choose the OK button.

Adicione um componente do Tempo de Execução do Windows C# à solução: no Gerenciador de Soluções, abra o menu de atalho da solução e escolha Adicionar> Novo Projeto.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. Expanda Visual C# > Microsoft Store e, em seguida, selecione Windows Runtime componente.Expand Visual C# > Microsoft Store and then select Windows Runtime Component. Nomeie o projeto ToasterComponent e escolha o botão OK.Name the project ToasterComponent and then choose the OK button. ToasterComponent será o namespace raiz dos componentes que você criará em etapas posteriores.ToasterComponent will be the root namespace for the components you will create in later steps.

No Gerenciador de Soluções, abra o menu de atalho da solução e escolha Propriedades.In Solution Explorer, open the shortcut menu for the solution and then choose Properties. Na caixa de diálogo Páginas de Propriedades, selecione Propriedades de Configuração no painel esquerdo e, na parte superior da caixa de diálogo, defina Configuração como Depurar e Plataforma como x86, x64 ou 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. Clique no botão OK.Choose the OK button.

Importante   Plataforma = qualquer CPU não funcionará porque não é válido para a DLL Win32 de código nativo que você adicionará à solução mais tarde.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.

No Gerenciador de Soluções, renomeie class1.cs para ToasterComponent.cs de maneira que ele corresponda ao nome do projeto.In Solution Explorer, rename class1.cs to ToasterComponent.cs so that it matches the name of the project. O Visual Studio renomeia automaticamente a classe no arquivo para coincidir com o novo nome de arquivo.Visual Studio automatically renames the class in the file to match the new file name.

No arquivo .cs, adicione uma diretiva using para o namespace Windows.Foundation a fim de colocar TypedEventHandler em escopo.In the .cs file, add a using directive for the Windows.Foundation namespace to bring TypedEventHandler into scope.

Quando você precisa de proxies e stubs, o componente deve usar interfaces para expor os membros públicos.When you require proxies and stubs, your component must use interfaces to expose its public members. Em ToasterComponent.cs, defina uma interface para o notificador do sistema (toaster) e outra para a notificação (Toast) que o notificador produz.In ToasterComponent.cs, define an interface for the toaster, and another one for the Toast that the toaster produces.

Observação   Em C#, você pode ignorar esta etapa.Note In C# you can skip this step. Em vez disso, primeiro crie uma classe e, em seguida, abra o menu de atalho e escolha refatorar a > interface de extração.Instead, first create a class, and then open its shortcut menu and choose Refactor > Extract Interface. No código gerado, dê manualmente às interfaces acessibilidade pública.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; }
        }

A interface IToast tem uma cadeia de caracteres que pode ser recuperada para descrever o tipo de notificação do sistema.The IToast interface has a string that can be retrieved to describe the type of toast. A interface IToaster tem um método para criar a notificação do sistema e um evento para indicar que a notificação do sistema foi feita.The IToaster interface has a method to make toast, and an event to indicate that the toast is made. Como retorna a parte específica (ou seja, tipo) da notificação do sistema, esse evento é conhecido como um evento tipado.Because this event returns the particular piece (that is, type) of toast, it's known as a typed event.

Em seguida, precisamos de classes que implementem essas interfaces e sejam públicas e seladas de maneira que permaneçam acessíveis no aplicativo JavaScript que você programará depois.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);
                    }
                });
           }
        }

No código anterior, criamos a notificação do sistema e giramos um item de trabalho do pool de threads para acionar a notificação.In the preceding code, we create the toast and then spin up a thread-pool work item to fire the notification. Embora o IDE possa sugerir que você aplique a palavra-chave await à chamada assíncrona, isso não é necessário neste caso porque o método não faz nenhum trabalho que dependa dos resultados da operação.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.

Observação   A chamada assíncrona no código anterior usa ThreadPool. RunAsync unicamente para demonstrar uma maneira simples de acionar o evento em um thread em segundo plano.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. Você pode escrever esse método em particular, conforme mostrado no exemplo a seguir, e ele funcionaria bem porque o agendador de tarefas .NET realiza marshaling automaticamente de chamadas async/await de volta para o thread da interface do usuário.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);
    }

Caso você compile o projeto agora, ele deve ser compilado tranquilamente.If you build the project now, it should build cleanly.

Para programar o aplicativo em JavaScriptTo program the JavaScript app

Agora podemos adicionar um botão ao aplicativo JavaScript para fazê-lo usar a classe que acabamos de definir para criar a notificação do sistema.Now we can add a button to the JavaScript app to cause it to use the class we just defined to make toast. Antes de fazer isso, devemos adicionar uma referência ao projeto ToasterComponent que acabamos de criar.Before we do this, we must add a reference to the ToasterComponent project we just created. No Gerenciador de Soluções, abra o menu de atalho para o projeto ToasterApplication, selecione Adicionar > Referências e, em seguida, clique no botão Adicionar Nova Referência.In Solution Explorer, open the shortcut menu for the ToasterApplication project, choose Add > References, and then choose the Add New Reference button. Na caixa de diálogo Adicionar referência, no painel esquerdo em Solução, selecione o projeto do componente e, em seguida, no painel do meio, selecione 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. Clique no botão OK.Choose the OK button.

No Gerenciador de Soluções, abra o menu de atalho do projeto ToasterApplication e escolha Definir como Projeto de Inicialização.In Solution Explorer, open the shortcut menu for the ToasterApplication project and then choose Set as Startup Project.

Ao final do arquivo default.js, adicione um namespace para conter as funções para chamar o componente e ser chamado por ele.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. O namespace terá duas funções, uma para criar a notificação do sistema e outra para manipular o evento toast-complete.The namespace will have two functions, one to make toast and one to handle the toast-complete event. A implementação de makeToast cria um objeto Toaster, registra o manipulador de eventos e cria a notificação do sistema.The implementation of makeToast creates a Toaster object, registers the event handler, and makes the toast. Até agora, o manipulador de eventos não faz muito, conforme mostrado aqui: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>";
        },
    });

A função makeToast deve ser conectada a um botão.The makeToast function must be hooked up to a button. Atualize default.html para incluir um botão e um espaço para gerar o resultado da notificação do sistema: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 não estivéssemos usando um TypedEventHandler, poderíamos agora executar o aplicativo na máquina local e clicar no botão para criar a notificação do sistema.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. Mas, em nosso aplicativo, nada acontece.But in our app, nothing happens. Para descobrir o motivo, vamos depurar o código gerenciado que dispara o ToastCompletedEvent.To find out why, let’s debug the managed code that fires the ToastCompletedEvent. Pare o projeto e, em seguida, na barra de menu, selecione Depurar > propriedades do Toaster Application.Stop the project, and then on the menu bar, choose Debug > Toaster Application properties. Altere o Tipo de depurador para Somente gerenciado.Change Debugger Type to Managed Only. Novamente na barra de menu, selecione Depurar > Exceções e, em seguida, selecione Exceções de tempo de execução de linguagem comum.Again on the menu bar, choose Debug > Exceptions, and then select Common Language Runtime Exceptions.

Agora execute o aplicativo e clique no botão para criar notificações do sistema.Now run the app and click the make-toast button. O depurador detecta uma exceção de conversão inválida.The debugger catches an invalid cast exception. Embora não seja óbvio por sua mensagem, esta exceção está ocorrendo porque os proxies estão faltando para essa interface.Although it’s not obvious from its message, this exception is occurring because proxies are missing for that interface.

proxy ausente

O primeiro passo na criação de um proxy e um talão para um componente é adicionar um ID ou GUID exclusivo às interfaces.The first step in creating a proxy and stub for a component is to add a unique ID or GUID to the interfaces. No entanto, o formato GUID a ser usado muda dependendo se você estiver codificando em C#, Visual Basic ou outra linguagem .NET ou em 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++.

Para gerar GUIDs para as interfaces do componente (C# e outras linguagens .NET)To generate GUIDs for the component's interfaces (C# and other .NET languages)

Na barra de menus, selecione Ferramentas > Criar GUID.On the menu bar, choose Tools > Create GUID. Na caixa de diálogo, selecione 5.In the dialog box, select 5. [GUID ("xxxxxxxx-xxxx... xxxx ") ] .[Guid("xxxxxxxx-xxxx...xxxx")]. Escolha o botão Novo GUID e o botão Copiar.Choose the New GUID button and then choose the Copy button.

ferramenta geradora de GUIDs

Volte para a definição da interface e cole o novo GUID antes da interface IToaster, conforme mostrado no exemplo a seguir.Go back to the interface definition, and then paste the new GUID just before the IToaster interface, as shown in the following example. (Não use o GUID no exemplo.(Don't use the GUID in the example. Cada interface exclusiva deve ter o próprio GUID.)Every unique interface should have its own GUID.)

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

Adicione uma diretiva using para o namespace System.Runtime.InteropServices.Add a using directive for the System.Runtime.InteropServices namespace.

Repita essas etapas para a interface IToast.Repeat these steps for the IToast interface.

Para gerar GUIDs para as interfaces do componente (C ++)To generate GUIDs for the component's interfaces (C++)

Na barra de menus, selecione Ferramentas > Criar GUID.On the menu bar, choose Tools > Create GUID. Na caixa de diálogo, selecione 3.In the dialog box, select 3. estrutura estática const GUID = {...}.static const struct GUID = {...}. Escolha o botão Novo GUID e o botão Copiar.Choose the New GUID button and then choose the Copy button.

Cole o GUID pouco antes da definição da interface IToaster.Paste the GUID just before the IToaster interface definition. Após a colagem, o GUID deve ser parecido com o exemplo a seguir.After you paste, the GUID should resemble the following example. (Não use o GUID no exemplo.(Don't use the GUID in the example. Cada interface exclusiva deve ter o próprio 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 } };

Adicione uma diretiva using para Windows.Foundation.Metadata a fim de colocar GuidAttribute em escopo.Add a using directive for Windows.Foundation.Metadata to bring GuidAttribute into scope.

Agora converta manualmente o GUID const em um GuidAttribute, de maneira que ele seja formatado conforme mostrado no exemplo a seguir.Now manually convert the const GUID to a GuidAttribute so that it's formatted as shown in the following example. As chaves são substituídas por colchetes e parênteses, e o ponto-e-vírgula à direita é removido.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
    {...

Repita essas etapas para a interface IToast.Repeat these steps for the IToast interface.

Agora que as interfaces têm IDs exclusivas, podemos criar um arquivo IDL alimentando o arquivo .winmd na ferramenta de linha de comando winmdidl e gerar o código-fonte C do proxy e do stub alimentando esse arquivo IDL na ferramenta de linha de 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. O Visual Studio faz isso para caso criemos eventos de pós-compilação conforme mostrado nas etapas a seguir.Visual Studio do this for us if we create post-build events as shown in the following steps.

Para gerar o código-fonte de proxy e stubTo generate the proxy and stub source code

Para adicionar um evento de pós-compilação personalizado, no Gerenciador de Soluções, abra o menu de atalho do projeto ToasterComponent e escolha Propriedades.To add a custom post-build event, in Solution Explorer, open the shortcut menu for the ToasterComponent project and then choose Properties. No painel esquerdo das páginas de propriedades, selecione Compilar Eventos e escolha o botão Editar Pós-compilação.In the left pane of the property pages, select Build Events, and then choose the Edit Post-build button. Adicione os seguintes comandos à linha de comando de pós-compilação.Add the following commands to the post-build command line. (O arquivo em lote deve ser chamado primeiro para definir as variáveis de ambiente para encontrar a ferramenta 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    Para uma configuração de projeto ARM ou x64, altere o parâmetro MIDL/Env para x64 ou arm32.Important  For an ARM or x64 project configuration, change the MIDL /env parameter to x64 or arm32.

Para garantir que o arquivo IDL seja regenerado sempre que o arquivo .winmd for alterado, mude Execute o evento pós-compilação para Quando a compilação atualiza a saída do projeto.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. A página de propriedades compilar eventos deve ser semelhante a esta:  eventos de compilaçãoThe Build Events property page should resemble this: build events

Recompile a solução para gerar e compilar IDL.Rebuild the solution to generate and compile the IDL.

É possível verificar que MIDL compilou corretamente a solução procurando ToasterComponent.h, ToasterComponent_i.c, ToasterComponent_p.c, e dlldata.c no diretório do projeto 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.

Para compilar o código de proxy e stub em uma DLLTo compile the proxy and stub code into a DLL

Agora que tem os arquivos necessários, você pode compilá-los para produzir uma DLL, que é um arquivo em C++.Now that you have the required files, you can compile them to produce a DLL, which is a C++ file. Para que isso seja o mais fácil possível, adicione um novo projeto para dar suporte à compilação dos proxies.To make this as easy as possible, add a new project to support building the proxies. Abra o menu de atalho da solução ToasterApplication e escolha Adicionar > Novo Projeto.Open the shortcut menu for the ToasterApplication solution and then choose Add > New Project. No painel esquerdo da caixa de diálogo novo projeto , expanda Visual C++ > Windows > UniversalWindows e, no painel central, selecione dll (aplicativos 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). (Observe que este NÃO é um projeto do componente do Tempo de Execução do Windows do C ++.) Nomeie o projeto Proxies e clique no botão OK.(Notice that this is NOT a C++ Windows Runtime Component project.) Name the project Proxies and then choose the OK button. Esses arquivos serão atualizados pelos eventos de pós-compilação quando algo mudar na classe C#.These files will be updated by the post-build events when something changes in the C# class.

Por padrão, o projeto Proxies gera arquivos .h de cabeçalho e arquivos .cpp em C++.By default, the Proxies project generates header .h files and C++ .cpp files. Como a DLL é compilada com base nos arquivos produzidos no MIDL, os arquivos .h e .cpp não são necessários.Because the DLL is built from the files produced from MIDL, the .h and .cpp files are not required. No Gerenciador de Soluções, abra o menu de atalho deles, escolha Remover e confirme a exclusão.In Solution Explorer, open the shortcut menu for them, choose Remove, and then confirm the deletion.

Agora que o projeto está vazio, é possível readicionar os arquivos gerados por MIDL.Now that the project is empty, you can add back the MIDL-generated files. Abra o menu de atalho para o projeto Proxies e clique em Adicionar > Item Existente.Open the shortcut menu for the Proxies project, and then choose Add > Existing Item. Na caixa de diálogo, navegue até o diretório do projeto ToasterComponent e selecione estes arquivos: 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. Clique no botão Adicionar.Choose the Add button.

No projeto Proxies, crie um arquivo .def para definir as exportações DLL descritas em dlldata.c.In the Proxies project, create a .def file to define the DLL exports described in dlldata.c. Abra o menu de atalho do projeto e escolha Adicionar > Novo Item.Open the shortcut menu for the project, and then choose Add > New Item. No painel à esquerda da caixa de diálogo, selecione Código e, no painel intermediário, selecione Arquivo de Definição de Módulo.In the left pane of the dialog box, select Code and then in the middle pane, select Module-Definition File. Nomeie o arquivo proxies.def e escolha o botão Adicionar.Name the file proxies.def and then choose the Add button. Abra esse arquivo .def e o modifique para incluir as EXPORTS definidas em 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 você compilar o projeto agora, ele falhará.If you build the project now, it will fail. Para compilar corretamente o projeto, você precisa alterar a maneira como o projeto é compilado e vinculado.To correctly compile this project, you have to change how the project is compiled and linked. No Gerenciador de soluções, abra o menu de atalho para o projeto Proxies e selecione Propriedades.In Solution Explorer, open the shortcut menu for the Proxies project and then choose Properties. Mude as páginas de propriedades da seguinte forma.Change the property pages as follows.

No painel esquerdo, selecione C/C++ > Pré-processador e, em seguida, no painel direito, selecione Definições de pré-processador, escolha o botão de seta para baixo e selecione Editar.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. Adicione estas definições na caixa:Add these definitions in the box:

WIN32;_WINDOWS

Em C/C++ > Cabeçalhos Pré-compilados, altere Cabeçalho Pré-compilado para Não Usar Cabeçalhos Pré-Compilados e escolha o botão Aplicar.Under C/C++ > Precompiled Headers, change Precompiled Header to Not Using Precompiled Headers, and then choose the Apply button.

Em Linker > Geral, altere Ignorar Biblioteca de Importação para Sim e, em seguida, clique no botão Aplicar.Under Linker > General, change Ignore Import Library to Yes, and then choose the Apply button.

Em Vinculador > Entrada, selecione Dependências Adicionais, escolha o botão de seta para baixo e selecione Editar.Under Linker > Input, select Additional Dependencies, choose the down-arrow button, and then select Edit. Adicione este texto na caixa:Add this text in the box:

rpcrt4.lib;runtimeobject.lib

Não cole essas bibliotecas diretamente na linha da lista.Do not paste these libs directly into the list row. Use a caixa Editar para garantir que MSBuild no Visual Studio mantenha as dependências adicionais corretas.Use the Edit box to ensure that MSBuild in Visual Studio will maintain the correct additional dependencies.

Ao fazer essas alterações, escolha o botão OK na caixa de diálogo Páginas de Propriedades.When you have made these changes, choose the OK button in the Property Pages dialog box.

Em seguida, utilize uma dependência no projeto ToasterComponent.Next, take a dependency on the ToasterComponent project. Isso garante que o Toaster será compilado antes da compilação do projeto de proxy.This ensures that the Toaster will build before the proxy project builds. Isso é necessário porque o projeto Toaster é responsável por gerar os arquivos para compilar o proxy.This is required because the Toaster project is responsible for generating the files to build the proxy.

Abra o menu de atalho do projeto Proxies e escolha Dependências do Projeto.Open the shortcut menu for the Proxies project and then choose Project Dependencies. Marque as caixas de seleção para indicar que o projeto Proxies depende do projeto ToasterComponent, para garantir que o Visual Studio os compile na ordem correta.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.

Verifique se que a solução é compilada corretamente escolhendo Compilar > Recompilar Solução na barra de menus do Visual Studio.Verify that the solution builds correctly by choosing Build > Rebuild Solution on the Visual Studio menu bar.

Para registrar o proxy e o stubTo register the proxy and stub

No projeto ToasterApplication, abra o menu de atalho de package.appxmanifest e escolha Abrir Com.In the ToasterApplication project, open the shortcut menu for package.appxmanifest and then choose Open With. Na caixa de diálogo Abrir Com, selecione Editor de texto XML e, em seguida, clique no botão OK.In the Open With dialog box, select XML Text Editor and then choose the OK button. Colemos em um XML que forneça um registro de extensão windows.activatableClass.proxyStub e que se baseie nos GUIDs no 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. Para encontrar os GUIDs a serem usados no arquivo .appxmanifest, abra ToasterComponent_i.c.To find the GUIDs to use in the .appxmanifest file, open ToasterComponent_i.c. Encontre entradas semelhantes às do exemplo a seguir.Find entries that resemble the ones in the following example. Observe também que as definições de IToast, IToaster e uma terceiro interface – um manipulador de eventos tipado com dois parâmetros: Toaster e Toast.Also notice the definitions for IToast, IToaster, and a third interface—a typed event handler that has two parameters: a Toaster and Toast. Isso corresponde ao evento definido na classe Toaster.This matches the event that's defined in the Toaster class. Observe os GUIDs de IToast e IToaster correspondem aos GUIDs definidos nas interfaces no arquivo C#.Notice that the GUIDs for IToast and IToaster match the GUIDs that are defined on the interfaces in the C# file. Como a interface do manipulador de eventos tipados é gerada automaticamente, o GUID dessa interface também é gerado 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);

Agora copiamos os GUIDs, os colamos em appxmanifest em um nó que adicionamos, damos o nome de Extensões e os reformatamos.Now we copy the GUIDs, paste them in package.appxmanifest in a node that we add and name Extensions, and then reformat them. A entrada de manifesto se parece com o exemplo a seguir – mas, novamente, lembre-se de usar os próprios GUIDs.The manifest entry resembles the following example—but again, remember to use your own GUIDs. O GUID ClassId no XML é o mesmo de ITypedEventHandler2.Notice that the ClassId GUID in the XML is the same as ITypedEventHandler2. Isso porque esse GUID é o primeiro listado em ToasterComponent_i.c.This is because that GUID is the first one that's listed in ToasterComponent_i.c. Os GUIDs aqui diferenciam maiúsculas de minúsculas.The GUIDs here are case-insensitive. Em vez de reformatar manualmente os GUIDs de IToast e IToaster, você pode voltar para as definições de interface e obter o valor GuidAttribute, que tem o formato correto.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. Em C++, existe um GUID formatado corretamente no comentário.In C++, there is a correctly-formatted GUID in the comment. Em qualquer caso, você deve reformatar manualmente o GUID usado para a ClassId e o manipulador de eventos.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>

Cole o nó XML de extensões como um filho direto do nó Pacote e um par de, por exemplo, o nó Recursos.Paste the Extensions XML node as a direct child of the Package node, and a peer of, for example, the Resources node.

Antes de continuar, é importante garantir que:Before moving on, it’s important to ensure that:

  • O ProxyStub ClassID é definido como o primeiro GUID no _ arquivo ToasterComponent i. c.The ProxyStub ClassId is set to the first GUID in the ToasterComponent_i.c file. Use o primeiro GUID que está definido neste arquivo para o classId.Use the first GUID that's defined in this file for the classId. (Ele pode ser o mesmo que o GUID de ITypedEventHandler2.)(This might be the same as the GUID for ITypedEventHandler2.)
  • Path é o caminho relativo do pacote do proxy binário.The Path is the package relative path of the proxy binary. (Neste procedimento passo a passo, proxies.dll está na mesma pasta de ToasterApplication.winmd.)(In this walkthrough, proxies.dll is in the same folder as ToasterApplication.winmd.)
  • Os GUIDs estão no formato correto.The GUIDs are in the correct format. (É fácil errar.)(This is easy to get wrong.)
  • As IDs de interface no manifesto correspondem ao IIDs no _ arquivo ToasterComponent i. c.The interface IDs in the manifest match the IIDs in ToasterComponent_i.c file.
  • Os nomes das interfaces são únicos no manifesto.The interface names are unique in the manifest. Porque elas não são usadas pelo sistema, você pode escolher os valores.Because these are not used by the system, you can choose the values. É uma boa prática escolher nomes de interface claramente correspondentes a interfaces que você definiu.It is a good practice to choose interface names that clearly match interfaces that you have defined. Para interfaces geradas, os nomes devem ser indicativos das interfaces geradas.For generated interfaces, the names should be indicative of the generated interfaces. Você pode usar o _ arquivo ToasterComponent i. c para ajudá-lo a gerar nomes de interface.You can use the ToasterComponent_i.c file to help you generate interface names.

Se você tentar executar a solução agora, você receberá um erro que proxies.dll não faz parte da carga útil.If you try to run the solution now, you will get an error that proxies.dll is not part of the payload. Abra o menu de atalho da pasta Referências no projeto ToasterApplication e escolha Adicionar Referência.Open the shortcut menu for the References folder in the ToasterApplication project and then choose Add Reference. Marque a caixa de seleção próxima do projeto Proxies.Select the check box next to the Proxies project. Além disso, assegure-se de que a caixa de seleção próxima de ToasterComponent também esteja selecionada.Also, make sure that the check box next to ToasterComponent is also selected. Clique no botão OK.Choose the OK button.

O projeto agora deve ser compilado.The project should now build. Execute o projeto e verifique se você pode fazer torradas.Run the project and verify that you can make toast.