Compartilhar via


Acionando eventos em componentes do Windows Runtime

Observação

Para obter mais informações sobre como gerar eventos em um componente do Tempo de Execução do Windows C++/WinRT , consulte Criar eventos em C++/WinRT.

Se o componente do Tempo de Execução do Windows 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, poderá implementá-lo e/ou gerá-lo de qualquer uma dessas maneiras.

  • (Opção 1) Gere o evento por meio do Windows.UI.Core.CoreDispatcher para empacotar o evento para o contexto de thread JavaScript. Embora normalmente essa seja a melhor opção, em alguns cenários ela pode não fornecer o desempenho mais rápido.
  • (Opção 2) Use o objeto> Windows.Foundation.EventHandler<(mas perca as informações de tipo de evento). Se a opção 1 não for viável ou se seu desempenho não for adequado, essa é uma boa segunda opção, desde que a perda de informações de tipo seja aceitável. Se você estiver criando um componente do Tempo de Execução do Windows em C#, o tipo de objeto> Windows.Foundation.EventHandler<não estará disponível; em vez disso, esse tipo será projetado para System.EventHandler, portanto, você deve usá-lo.
  • (Opção 3) Crie seu próprio proxy e stub para o componente. Essa opção é a mais difícil de implementar, mas preserva as informações de tipo e pode fornecer 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.

Tela de fundo

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 do limite do thread em segundo plano do thread da interface do usuário. (Em termos COM, isso é conhecido como comunicação entre apartamentos de thread.)

A maioria dos objetos na API do Windows é ágil ou tem proxies e stubs internos. 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, você deve usar uma das três opções a seguir.

(Opção 1) Gerar o evento por meio do CoreDispatcher

Você pode enviar eventos de qualquer tipo de delegado definido pelo usuário usando o Windows.UI.Core.CoreDispatcher, e 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 acionamento do evento e a manipulação do evento se tornar um problema, tente uma das outras opções.

O exemplo a seguir mostra como usar o CoreDispatcher para gerar um evento fortemente tipado. 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 o objeto> EventHandler<, mas perder informações de tipo

Observação

Se você estiver criando um componente do Tempo de Execução do Windows em C#, o tipo de objeto> Windows.Foundation.EventHandler<não estará disponível; em vez disso, esse tipo será projetado para System.EventHandler, portanto, você deve usá-lo.

Outra maneira de enviar um evento de um thread em segundo plano é usar o objeto> Windows.Foundation.EventHandler<como o tipo do evento. O Windows fornece essa instanciação concreta do tipo genérico e fornece um proxy e um stub para ele. A desvantagem é que as informações de tipo de seus argumentos de evento e remetente são perdidas. Os clientes C++ e .NET devem saber por meio da documentação para qual tipo converter de volta quando o evento for recebido. Os clientes JavaScript não precisam das informações de tipo original. Eles encontram as propriedades arg, com base em seus nomes nos metadados.

Este exemplo mostra como usar o objeto> Windows.Foundation.EventHandler<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 do 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 seu próprio proxy e stub

Para obter ganhos potenciais de desempenho em tipos de evento definidos pelo usuário que têm informações de tipo totalmente preservadas, você precisa criar seus próprios objetos proxy e stub e inseri-los no pacote do aplicativo. Normalmente, você precisa 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 essa opção fornecerá melhor desempenho do que as outras duas opções. O desempenho real depende de muitos fatores. Use o criador de perfil do Visual Studio ou outras ferramentas de criação de perfil para medir o desempenho real em seu aplicativo e determinar se o evento é de fato um gargalo.

O restante deste artigo mostra como usar o C# para criar um componente básico do Tempo de Execução do Windows e, em seguida, usar o 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> 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 se baseia na criação de 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 o argumento para TValue. Essas classes não podem se comunicar com JavaScript até que você conclua as etapas posteriores.
  • Esse 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 runtime COM possa encontrá-los e faça referência à DLL proxy-stub no projeto do aplicativo.

Para criar o componente do Tempo de Execução do Windows

No Visual Studio, na barra de menus, escolha Arquivo > Novo Projeto. Na caixa de diálogo Novo Projeto , expanda JavaScript > Universal Windows e selecione Aplicativo em Branco. Nomeie o projeto ToasterApplication e 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 da 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 Configuração como Depurar e Plataforma como x86, x64 ou ARM. Clique no botão OK.

Plataforma importante = Qualquer CPU não funcionará porque não é válida para a DLL Win32 de código nativo que você adicionará à solução posteriormente.

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

No arquivo .cs, adicione uma diretiva using para o namespace Windows.Foundation para colocar TypedEventHandler 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 torradeira que a torradeira produz.

Observação Em C#, você pode ignorar esta etapa. Em vez disso, primeiro crie uma classe e, em seguida, abra seu menu de atalho e escolha Refatorar > interface de extração. No código gerado, forneça manualmente acessibilidade pública às interfaces.

	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. A interface IToaster tem um método para fazer uma notificação do sistema e um evento para indicar que a notificação do sistema foi feita. Como esse evento retorna a parte específica (ou seja, tipo) da notificação do sistema, ele é conhecido como um evento tipado.

Em seguida, precisamos de classes que implementem essas interfaces e sejam públicas e lacradas para que possam ser acessadas a partir do aplicativo JavaScript que você programará posteriormente.

	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, em seguida, criamos um item de trabalho do pool 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 nesse 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ê pode escrever esse método específico, conforme mostrado no exemplo a seguir, e ele funcionaria bem porque o agendador de tarefas do .NET realiza marshaling automaticamente as chamadas assíncronas/await de volta para o thread da interface do usuário.  

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

Se você construir o projeto agora, ele deve ser construído de forma limpa.

Para programar o aplicativo JavaScript

Agora podemos adicionar um botão ao aplicativo JavaScript para fazer com que ele use a classe que acabamos de definir para fazer o brinde. 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 do projeto ToasterApplication, escolha Adicionar Referências e, 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 de componente e, no painel do meio, selecione TorradeiraComponente. Clique no botão OK.

No Gerenciador de Soluções, abra o menu de atalho do projeto ToasterApplication e escolha Definir como Projeto de Inicialização.

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 toast e outra para manipular o evento toast-complete. A implementação de makeToast cria um objeto Toaster, registra o manipulador de eventos e faz a notificação do sistema. 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 gerar o resultado de fazer uma notificação do sistema:

    <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, agora poderíamos executar o aplicativo no computador local e clicar no botão para fazer uma notificação do sistema. Mas em nosso aplicativo, nada acontece. Para descobrir o motivo, vamos depurar o código gerenciado que aciona o ToastCompletedEvent. Pare o projeto e, na barra de menus, escolha Depurar > propriedades do Aplicativo Torradeira. Altere o tipo de depurador para Somente gerenciado. Novamente na barra de menus, escolha Depurar > Exceções e, em seguida, selecione Exceções do Common Language Runtime.

Agora execute o aplicativo e clique no botão make-toast. 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 os proxies estão ausentes para essa interface.

proxy ausente

A primeira etapa na criação de um proxy e stub para um componente é adicionar uma 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 menus, 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 geradora de GUID

Volte para a definição da interface e cole o novo GUID 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 essas etapas para a interface IToast.

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

Na barra de menus, 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 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 colocar GuidAttribute no escopo.

Agora, converta manualmente o const GUID em um GuidAttribute para que ele seja formatado conforme 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 essas 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 o stub alimentando esse arquivo IDL na ferramenta de linha de comando MIDL. O Visual Studio fará isso por nós se criarmos eventos de pós-compilação, conforme mostrado nas etapas a seguir.

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

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. No painel esquerdo das páginas de propriedades, selecione Eventos de Compilação 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 localizar 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 Executar o evento pós-build para Quando o build atualizar a saída do projeto. A página de propriedades Eventos de Build deve ser semelhante a esta: Eventos de compilação

Recompile a solução para gerar e compilar a 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, 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 dar suporte à criação dos proxies. Abra o menu de atalho da solução ToasterApplication e escolha Adicionar > Novo Projeto. No painel esquerdo da caixa de diálogo Novo Projeto, expanda Visual C++ > Windows > Universal Windows e, no painel do meio, selecione DLL (aplicativos UWP). (Observe que este NÃO é um projeto de componente do Windows Runtime C++.) Nomeie o projeto como Proxies e escolha o botão OK . Esses arquivos serão atualizados pelos eventos de pós-compilação quando algo for alterado 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 do 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 Remover e confirme a exclusão.

Agora que o projeto está vazio, você pode adicionar novamente os arquivos gerados por MIDL. Abra o menu de atalho do 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. Clique no 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 do projeto e escolha Adicionar > Novo Item. No painel esquerdo da caixa de diálogo, selecione Código e, no painel do meio, selecione Arquivo de Definição de Módulo. 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ê precisa alterar a forma como o projeto é compilado e vinculado. No Gerenciador de Soluções, abra o menu de atalho do projeto Proxies e 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 selecione Editar. Adicione estas definições na caixa:

WIN32;_WINDOWS

Em Cabeçalhos Pré-compilados C/C++>, altere Cabeçalho Pré-compilado para Não Usando Cabeçalhos Pré-compilados e escolha o botão Aplicar.

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

Em Entrada do Vinculador>, selecione Dependências Adicionais, escolha o botão de 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 mantenha as dependências adicionais corretas.

Depois de fazer essas alterações, escolha o botão OK na caixa de diálogo Páginas de Propriedades .

Em seguida, use uma dependência no projeto ToasterComponent. Isso garante que o Toaster será compilado antes que o projeto de proxy seja compilado. Isso é necessário porque o projeto Toaster é responsável por gerar os arquivos para criar o proxy.

Abra o menu de atalho do 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 Compilar > Solução de Recompilação na barra de menus do Visual Studio.

Para registrar 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 Editor de Texto XML e escolha o botão OK . Vamos colar um XML que fornece um registro de extensão windows.activatableClass.proxyStub e que se baseia nos GUIDs no proxy. Para localizar os GUIDs a serem usados no arquivo .appxmanifest, abra ToasterComponent_i.c. Encontre entradas semelhantes às do exemplo a seguir. Observe também as definições de 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 Toraster. Observe que os GUIDs para IToast e IToaster correspondem aos GUIDs definidos nas interfaces no arquivo C#. Como a interface do manipulador de eventos tipado é 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, colamos em package.appxmanifest em um nó que adicionamos e nomeamos Extensões e, em seguida, reformatá-los. A entrada do manifesto é semelhante ao exemplo a seguir, mas, novamente, lembre-se de usar seus próprios GUIDs. Observe que o GUID ClassId no XML é o mesmo que ITypedEventHandler2. Isso ocorre porque esse GUID é o primeiro listado no ToasterComponent_i.c. Os GUIDs aqui não diferenciam maiúsculas de 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. De qualquer forma, 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ó XML de Extensões como um filho direto do nó Pacote e um par de, por exemplo, o nó Recursos.

Antes de prosseguir, é importante garantir que:

  • O ProxyStub ClassId é definido como o primeiro GUID no arquivo ToasterComponent_i.c. Use o primeiro GUID definido neste arquivo para o classId. (Isso pode ser o mesmo que o GUID para ITypedEventHandler2.)
  • O caminho é o caminho relativo do pacote do binário do 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.)
  • As IDs de interface no manifesto correspondem aos IIDs no arquivo ToasterComponent_i.c.
  • Os nomes de interface são exclusivos no manifesto. Como eles 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. Abra o menu de atalho da pasta Referências no projeto ToasterApplication e escolha Adicionar Referência. 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 esteja marcada. Clique no botão OK.

O projeto agora deve ser construído. Execute o projeto e verifique se você pode fazer uma notificação do sistema.