Partilhar via


Levantar eventos em componentes do Tempo de Execução do Windows

Observação

Para saber mais sobre como gerar eventos em um C++/WinRT Componente de Tempo de Execução do Windows, veja Criar eventos em C++/WinRT.

Se o componente do Tempo de Execução do Windows gerar um evento de um tipo de delegado definido pelo usuário em um thread em segundo plano (thread de trabalho) e você quiser que o JavaScript possa receber o evento, poderá implementá-lo e/ou gerá-lo de qualquer uma dessas maneiras.

  • (Opção 1) Levante o evento por meio do Windows.UI.Core.CoreDispatcher para encaminhar o evento para o contexto de thread JavaScript. Embora normalmente esta seja a melhor opção, em alguns cenários pode não fornecer o desempenho mais rápido.
  • (Opção 2) Use Windows.Foundation.EventHandler<Object> (mas perde a informação sobre o tipo de evento). Se a opção 1 não for viável, ou se o seu desempenho não for adequado, esta é uma boa segunda opção, desde que a perda de informações de tipo seja aceitável. Se estiver a criar um Componente de Tempo de Execução do Windows em C#, o tipo Windows.Foundation.EventHandler<> não estará disponível; este tipo será projetado como System.EventHandler, e deve usá-lo.
  • (Opção 3) Crie seu próprio proxy e stub para o componente. Esta opção é a mais difícil de implementar, mas preserva as informações de tipo e pode fornecer um melhor desempenho em comparação com a Opção 1 em cenários exigentes.

Se você apenas gerar um evento em um thread em segundo plano sem usar uma dessas opções, um cliente JavaScript não receberá o evento.

Contexto geral

Todos os componentes e aplicativos do Tempo de Execução do Windows são fundamentalmente objetos COM, independentemente da linguagem usada para criá-los. Na API do Windows, a maioria dos componentes são objetos COM ágeis que podem se comunicar igualmente bem com objetos no thread em segundo plano e no thread da interface do usuário. Se um objeto COM não puder ser tornado ágil, ele exigirá objetos auxiliares conhecidos como proxies e stubs para se comunicar com outros objetos COM através da fronteira entre a thread da interface do utilizador e a thread de plano de fundo. (Em termos de COM, isto é conhecido como comunicação entre compartimentos de threads.)

A maioria dos objetos na API do Windows é ágil ou tem proxies e stubs integrados. No entanto, proxies e stubs não podem ser criados para tipos genéricos, como Windows.Foundation.TypedEventHandler<TSender, TResult> porque eles não são tipos completos até que você forneça o argumento type. É apenas com clientes JavaScript que a falta de proxies ou stubs se torna um problema, mas se você quiser que seu componente seja utilizável a partir de JavaScript, bem como de C++ ou uma linguagem .NET, então você deve usar uma das três opções a seguir.

(Opção 1) Gere o evento através do CoreDispatcher

Você pode enviar eventos de qualquer tipo de delegado definido pelo usuário usando o Windows.UI.Core.CoreDispatchere o JavaScript poderá recebê-los. Se você não tiver certeza de qual opção usar, tente esta primeiro. Se a latência entre o disparo do evento e o processamento do evento se tornar um problema, tente uma das outras opções.

O exemplo a seguir mostra como usar o CoreDispatcher para levantar um evento de tipo forte. Observe que o argumento type é Toast, não 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 de tipo

Observação

Se estiver a criar um Componente de Tempo de Execução do Windows em C#, o tipo Windows.Foundation.EventHandler<> não estará disponível; este tipo será projetado como System.EventHandler, e deve usá-lo.

Outra maneira de enviar um evento de um thread em segundo plano é usar Windows.Foundation.EventHandler<Object> como o tipo do evento. O Windows fornece essa instanciação concreta do tipo genérico e fornece um proxy e stub para ela. A desvantagem é que as informações de tipo do seu evento args e remetente são perdidas. Os clientes C++ e .NET devem saber, através da documentação, para que tipo retransmitir quando o evento for recebido. Os clientes JavaScript não precisam das informações de tipo originais. Eles encontram as propriedades arg, baseando-se nos seus nomes nos metadados.

Este exemplo mostra como usar Windows.Foundation.EventHandler<Object> em 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 JavaScript da seguinte forma:

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

(Opção 3) Crie os seus próprios proxy e stub

Para obter possíveis ganhos de desempenho em tipos de evento definidos pelo usuário que tenham informações de tipo totalmente preservadas, você precisa criar seus próprios objetos de proxy e stub e incorporá-los ao pacote do aplicativo. Normalmente, você tem que usar essa opção apenas em raras situações em que nenhuma das outras duas opções é adequada. Além disso, não há garantia de que esta opção proporcione um melhor desempenho do que as outras duas opções. O desempenho real depende de muitos fatores. Utilize o analisador de desempenho do Visual Studio ou outras ferramentas de análise de desempenho para medir o desempenho real no seu aplicativo e determinar se o evento é de facto um gargalo.

O restante deste artigo mostra como usar C# para criar um componente básico do Tempo de Execução do Windows e, em seguida, usar C++ para criar uma DLL para o proxy e stub que permitirá que o JavaScript consuma um evento Windows.Foundation.TypedEventHandler<TSender, TResult> gerado pelo componente em uma operação assíncrona. (Você também pode usar C++ ou Visual Basic para criar o componente. As etapas relacionadas à criação de proxies e stubs são as mesmas.) Este passo a passo é baseado em Criando um exemplo de componente em processo do Tempo de Execução do Windows (C++/CX) e ajuda a explicar suas finalidades.

Este passo a passo tem essas partes.

  • Aqui você criará duas classes básicas do Tempo de Execução do Windows. Uma classe expõe um evento do tipo Windows.Foundation.TypedEventHandler<TSender, TResult> e a outra classe é o tipo que é retornado ao JavaScript como argumento para TValue. Essas classes não podem se comunicar com JavaScript até que você conclua as etapas posteriores.
  • Este aplicativo ativa o objeto de classe principal, chama um método e manipula um evento gerado pelo componente do Tempo de Execução do Windows.
  • Eles são exigidos pelas ferramentas que geram as classes proxy e stub.
  • Em seguida, use o arquivo IDL para gerar o código-fonte C para o proxy e o stub.
  • Registre os objetos proxy-stub para que o tempo de execução COM possa localizá-los e faça referência à DLL proxy-stub no projeto do aplicativo.

Para criar o componente Runtime do Windows

No Visual Studio, na barra de menus, escolha Arquivo > Novo Projeto. Na caixa de diálogo Novo Projeto, expanda > Universal Windows e, em seguida, selecione Aplicativo em Branco. Nomeie o projeto ToasterApplication e, em seguida, escolha o botão OK.

Adicione um componente do Tempo de Execução do Windows em C# à solução: no Gerenciador de Soluções, abra o menu de atalho da solução e escolha Adicionar > Novo Projeto. Expanda Visual C# > Microsoft Store e selecione Componente do Tempo de Execução do Windows. Nomeie o projeto ToasterComponent e escolha o botão OK. ToasterComponent será o namespace raiz para os componentes que você criará em etapas posteriores.

No Gerenciador de Soluções, abra o menu de atalho para a solução e escolha Propriedades. 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 a Configuração para Depuração e a Plataforma para x86, x64 ou ARM. Escolha o botão OK.

Importante Platform = Qualquer CPU não funcionará porque não é válida para a DLL Win32 de código nativo que será adicionada à solução mais tarde.

No Gerenciador de Soluções, renomeie class1.cs para ToasterComponent.cs para que corresponda ao nome do projeto. O Visual Studio renomeia automaticamente a classe no arquivo para corresponder ao novo nome de arquivo.

No arquivo .cs, adicione uma diretiva using para o namespace Windows.Foundation, para que TypedEventHandler fique no escopo.

Quando você precisa de proxies e stubs, seu componente deve usar interfaces para expor seus membros públicos. Em ToasterComponent.cs, defina uma interface para a torradeira e outra para a torrada que a torradeira produz.

Observação Em C#, você pode pular esta etapa. Em vez disso, primeiro crie uma classe e, em seguida, abra o respetivo menu de atalho e escolha Refatorar > Extrair Interface. No código gerado, dê manualmente às interfaces acessibilidade pública.

	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 toast. A interface IToaster tem um método para fazer torrada e um evento para indicar que a torrada está pronta. Como este evento retorna a parte específica (ou seja, tipo) do "toast", é conhecido como um evento tipificado.

Em seguida, precisamos de classes que implementem essas interfaces e sejam públicas e seladas para que sejam acessíveis a partir do aplicativo JavaScript que você programará mais tarde.

	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 o toast e, em seguida, iniciamos um item de trabalho no grupo de threads para disparar a notificação. 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.

Observação A chamada assíncrona no código anterior usa ThreadPool.RunAsync apenas para demonstrar uma maneira simples de disparar o evento em um thread em segundo plano. Você poderia escrever este método específico, conforme mostrado no exemplo a seguir, e ele funcionaria bem porque o agendador de tarefas do .NET automaticamente encaminha chamadas async/await de volta para o fio da interface do utilizador.  

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

Se você compilar o projeto agora, ele deve compilar sem erros.

Para programar o aplicativo JavaScript

Agora podemos adicionar um botão à app JavaScript para que use a classe que acabámos de definir para executar a operação. Antes de fazermos isso, devemos adicionar uma referência ao projeto ToasterComponent que acabamos de criar. No Gerenciador de Soluções, abra o menu de atalho para o projeto ToasterApplication, escolha Adicionar > Referênciase, em seguida, escolha o botão Adicionar Nova Referência. Na caixa de diálogo Adicionar Referência, no painel esquerdo em Solução, selecione o projeto do componente e, no painel central, selecione ToasterComponent. Escolha o botão OK.

No Explorador de Soluções, abra o menu de atalho para o projeto ToasterApplication e escolha Definir como Projeto de Arranque.

No final do arquivo default.js, adicione um namespace para conter as funções para chamar o componente e ser chamado de volta por ele. O namespace terá duas funções, uma para fazer um toast e outra para manipular o evento toast-complete. A implementação de makeToast cria um objeto Toaster, regista o manipulador de eventos e faz a torrada. Até agora, o manipulador de eventos não faz muito, como mostrado aqui:

	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. Atualize default.html para incluir um botão e algum espaço para apresentar o resultado de fazer torradas:

    <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 a usar um TypedEventHandler, agora poderíamos executar a aplicação na máquina local e clicar no botão para fazer torradas. Mas no nosso aplicativo, nada acontece. Para descobrir por quê, vamos depurar o código gerenciado que dispara o ToastCompletedEvent. Pare o projeto e, na barra de menus, escolha Depurar > propriedades do aplicativo Toaster. Altere Tipo de Depurador para Managed Only. Novamente na barra de menus, escolha Depurar > Exceçõese, em seguida, selecione Common Language Runtime Exceptions.

Agora execute a aplicação e clique no botão fazer torradas. O depurador captura uma exceção de conversão inválida. Embora não seja óbvio em sua mensagem, essa exceção está ocorrendo porque proxies estão faltando para essa interface.

proxy ausente

A primeira etapa na criação de um proxy e stub para um componente é adicionar um ID ou GUID exclusivo às interfaces. No entanto, o formato GUID a ser usado difere dependendo se você está codificando em C#, Visual Basic ou outra linguagem .NET, ou em C++.

Para gerar GUIDs para as interfaces do componente (C# e outras linguagens .NET)

Na barra de menu, escolha Ferramentas > Criar GUID. Na caixa de diálogo, selecione 5. [Guid("xxxxxxxx-xxxx... xxxx")]. Escolha o botão Novo GUID e, em seguida, escolha o botão Copiar.

ferramenta gerador de guid

Volte para a definição de interface e, em seguida, cole o novo GUID imediatamente antes da interface IToaster, conforme mostrado no exemplo a seguir. (Não use o GUID no exemplo. Cada interface exclusiva deve ter seu próprio GUID.)

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

Adicione uma diretiva using para o namespace System.Runtime.InteropServices.

Repita estas etapas para a interface IToast.

Para gerar GUIDs para as interfaces do componente (C++)

Na barra de menu, escolha Ferramentas > Criar GUID. Na caixa de diálogo, selecione 3. static const struct GUID = {...}. Escolha o botão Novo GUID e, em seguida, escolha o botão Copiar.

Cole o GUID imediatamente antes da definição da interface IToaster. Depois de colar, o GUID deve ser semelhante ao exemplo a seguir. (Não use o GUID no exemplo. Cada interface exclusiva deve ter seu próprio 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 para trazer GuidAttribute para o escopo.

Agora, converta manualmente o GUID const em um GuidAttribute para que ele seja formatado como mostrado no exemplo a seguir. Observe que as chaves são substituídas por colchetes e parênteses, e o ponto-e-vírgula à direita é removido.

// {E976784C-AADE-4EA4-A4C0-B0C2FD1307C3}
    [GuidAttribute(0xe976784c, 0xaade, 0x4ea4, 0xa4, 0xc0, 0xb0, 0xc2, 0xfd, 0x13, 0x7, 0xc3)]
    public interface IToaster
    {...

Repita estas etapas para a interface IToast.

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, em seguida, gerar o código-fonte C para o proxy e stub alimentando esse arquivo IDL na ferramenta de linha de comando MIDL. O Visual Studio faz isso por nós se criarmos eventos pós-compilação, conforme mostrado nas etapas a seguir.

Para gerar o proxy e o código-fonte do stub

Para adicionar um evento pós-compilação personalizado, no Gerenciador de Soluções, abra o menu de atalho para o projeto ToasterComponent e escolha Propriedades. No painel esquerdo das páginas de propriedades, selecione Criar eventos e, em seguida, escolha o botão Editar pós-compilação. Adicione os seguintes comandos à linha de comando pós-compilação. (O arquivo em lotes deve ser chamado primeiro para definir as variáveis de ambiente para encontrar a ferramenta winmdidl.)

call "$(DevEnvDir)..\..\vc\vcvarsall.bat" $(PlatformName)
winmdidl /outdir:output "$(TargetPath)"
midl /metadata_dir "%WindowsSdkDir%References\CommonConfiguration\Neutral" /iid "$(ProjectDir)$(TargetName)_i.c" /env win32 /h "$(ProjectDir)$(TargetName).h" /winmd "Output\$(TargetName).winmd" /W1 /char signed /nologo /winrt /dlldata "$(ProjectDir)dlldata.c" /proxy "$(ProjectDir)$(TargetName)_p.c" "Output\$(TargetName).idl"

importante Para uma configuração de projeto ARM ou x64, altere o parâmetro MIDL /env para x64 ou arm32.

Para garantir que o arquivo IDL seja regenerado sempre que o arquivo .winmd for alterado, altere Execute o evento pós-compilação para Quando a compilação atualiza a saída do projeto. A página de propriedades Build Events deve ser semelhante a esta: criar eventos

Reconstrua a solução para gerar e compilar o IDL.

Você pode verificar se o MIDL compilou corretamente a solução procurando ToasterComponent.h, ToasterComponent_i.c, ToasterComponent_p.c e dlldata.c no diretório do projeto ToasterComponent.

Para compilar o proxy e o código de stub em uma DLL

Agora que você tem os arquivos necessários, você pode compilá-los para produzir uma DLL, que é um arquivo C++. Para tornar isso o mais fácil possível, adicione um novo projeto para apoiar a construção dos proxies. Abra o menu de atalho para a solução ToasterApplication e, em seguida, escolha Adicionar > Novo Projeto. No painel esquerdo da caixa de diálogo Novo Projeto, expanda Visual C++ > Windows > Universal Windows e, no painel central, selecione DLL (aplicativos UWP). (Observe que este NÃO é um projeto de componente do Tempo de Execução do Windows C++.) Nomeie os proxies do projeto e escolha o botão OK. Esses arquivos serão atualizados pelos eventos pós-compilação quando algo mudar na classe C#.

Por padrão, o projeto Proxies gera arquivos .h de cabeçalho e arquivos .cpp C++. Como a DLL é criada a partir dos arquivos produzidos a partir de MIDL, os arquivos .h e .cpp não são necessários. No Gerenciador de Soluções, abra o menu de atalho para eles, escolha Removere confirme a exclusão.

Agora que o projeto está vazio, você pode adicionar de volta os arquivos gerados pelo MIDL. Abra o menu de atalho para o projeto Proxies e escolha Adicionar > Item Existente. Na caixa de diálogo, navegue até o diretório do projeto ToasterComponent e selecione estes arquivos: arquivos ToasterComponent.h, ToasterComponent_i.c, ToasterComponent_p.c e dlldata.c. Escolha o botão Adicionar.

No projeto Proxies, crie um arquivo .def para definir as exportações de DLL descritas em dlldata.c. Abra o menu de atalho para o projeto e, em seguida, escolha Adicionar > Novo Item. No painel esquerdo da caixa de diálogo, selecione Código e, no painel central, selecione Module-Definition File. Nomeie o arquivo proxies.def e escolha o botão Adicionar. Abra este arquivo .def e modifique-o para incluir as EXPORTAÇÕES definidas em dlldata.c:

EXPORTS
    DllCanUnloadNow         PRIVATE
    DllGetClassObject       PRIVATE

Se você construir o projeto agora, ele falhará. Para compilar corretamente este projeto, você tem que alterar como o projeto é compilado e vinculado. No Explorador de Soluções, abra o menu de atalho para o projeto Proxies e depois escolha Propriedades. Altere as páginas de propriedades da seguinte maneira.

No painel esquerdo, selecione Pré-processador C/C++ >e, em seguida, no painel direito, selecione Definições de Pré-processador, escolha o botão de seta para baixo e, em seguida, selecione Editar. Adicione estas definições na caixa:

WIN32;_WINDOWS

Em C/C++ > Cabeçalhos Pré-compilados, altere Cabeçalho Pré-Compilado para Não Utilizar Cabeçalhos Pré-Compiladose, em seguida, escolha o botão Aplicar.

Em Vinculador > Geral, altere Ignorar Biblioteca de Importação para Sim, e depois escolha o botão Aplicar.

Em Vinculador >de Entrada, selecione Dependências Adicionais, escolha a seta para baixo e selecione Editar. Adicione este texto na caixa:

rpcrt4.lib;runtimeobject.lib

Não cole essas libs diretamente na linha da lista. Use a caixa Editar para garantir que o MSBuild no Visual Studio manterá as dependências adicionais corretas.

Quando tiver feito essas alterações, escolha o botão OK na caixa de diálogo Property Pages.

Em seguida, adicione uma dependência ao projeto ToasterComponent. Isso garante que o Toaster compilará antes que o projeto proxy seja compilado. Isso é necessário porque o projeto Toaster é responsável por gerar os arquivos para construir o proxy.

Abra o menu de atalho para o projeto Proxies e escolha Dependências do projeto. 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.

Verifique se a solução é compilada corretamente escolhendo na barra de menus do Visual Studio a opção Build > Rebuild Solution.

Para registar o proxy e o stub

No projeto ToasterApplication, abra o menu de atalho para package.appxmanifest e escolha Abrir com. Na caixa de diálogo Abrir com, selecione o Editor de Texto XML e, em seguida, escolha o botão OK. Vamos colar algum código XML que fornece um registo de extensão windows.activatableClass.proxyStub, baseado nos GUIDs do proxy. Para localizar os GUIDs a serem usados no arquivo .appxmanifest, abra o ToasterComponent_i.c. Encontre entradas que se assemelham às do exemplo a seguir. Observe também as definições para IToast, IToaster, e uma terceira interface — um manipulador de eventos tipado que tem dois parâmetros: um Toaster e um Toast. Isso corresponde ao evento definido na classe Toaster. Observe que os GUIDs para IToast e IToaster correspondem aos GUIDs definidos nas interfaces no arquivo C#. Como a interface do manipulador de eventos digitada é gerada automaticamente, o GUID dessa interface também é gerado automaticamente.

MIDL_DEFINE_GUID(IID, IID___FITypedEventHandler_2_ToasterComponent__CToaster_ToasterComponent__CToast,0x1ecafeff,0x1ee1,0x504a,0x9a,0xf5,0xa6,0x8c,0x6f,0xb2,0xb4,0x7d);

MIDL_DEFINE_GUID(IID, IID___x_ToasterComponent_CIToast,0xF8D30778,0x9EAF,0x409C,0xBC,0xCD,0xC8,0xB2,0x44,0x42,0xB0,0x9B);

MIDL_DEFINE_GUID(IID, IID___x_ToasterComponent_CIToaster,0xE976784C,0xAADE,0x4EA4,0xA4,0xC0,0xB0,0xC2,0xFD,0x13,0x07,0xC3);

Agora copiamos os GUIDs, colamo-los no package.appxmanifest num nó que adicionamos e ao qual damos o nome de Extensões, e, em seguida, reformatamo-los. A entrada de manifesto é semelhante ao exemplo seguinte, mas, novamente, lembre-se de usar os seus próprios GUIDs. Observe que o GUID ClassId no XML é o mesmo que ITypedEventHandler2. Isso ocorre porque esse GUID é o primeiro listado em ToasterComponent_i.c. Os GUIDs aqui são insensíveis a maiúsculas e minúsculas. Em vez de reformatar manualmente os GUIDs para IToast e IToaster, você pode voltar para as definições de interface e obter o valor GuidAttribute, que tem o formato correto. Em C++, há um GUID formatado corretamente no comentário. Em qualquer caso, você deve reformatar manualmente o GUID usado para o ClassId e o manipulador de eventos.

	  <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ó de Extensões como um filho direto do nó de Pacote e um par, por exemplo, do nó de Recursos.

Antes de seguir em frente, é importante garantir que:

  • O ProxyStub ClassId é definido como o primeiro GUID no arquivo ToasterComponent_i.c. Utilize o primeiro GUID definido neste ficheiro para o classId. (Isso pode ser o mesmo que o GUID para ITypedEventHandler2.)
  • O Caminho é o caminho relativo ao pacote do binário de proxy. (Neste passo a passo, proxies.dll está na mesma pasta que ToasterApplication.winmd.)
  • Os GUIDs estão no formato correto. (Isso é fácil de errar.)
  • Os IDs de interface no manifesto correspondem aos IIDs no arquivo ToasterComponent_i.c.
  • Os nomes de interface são exclusivos no manifesto. Como estes não são usados pelo sistema, você pode escolher os valores. É uma boa prática escolher nomes de interface que correspondam claramente às interfaces que você definiu. Para interfaces geradas, os nomes devem ser indicativos das interfaces geradas. Você pode usar o arquivo ToasterComponent_i.c para ajudá-lo a gerar nomes de interface.

Se você tentar executar a solução agora, receberá um erro informando que proxies.dll não faz parte da carga útil. Abra o menu de atalho para a pasta References no projeto ToasterApplication e escolha Add Reference. Marque a caixa de seleção ao lado do projeto Proxies. Além disso, certifique-se de que a caixa de seleção ao lado de ToasterComponent também está marcada. Escolha o botão OK.

O projeto deve agora ser construído. Execute o projeto e verifique se consegue fazer torradas.