Compartilhar via


Componentes do Windows Runtime com C++/WinRT

Este tópico mostra como usar o C++/WinRT para criar e consumir um componente do Tempo de Execução do Windows, um componente que pode ser chamado de um aplicativo Universal do Windows criado usando qualquer linguagem do Tempo de Execução do Windows.

Há vários motivos para criar um componente do Tempo de Execução do Windows em C++/WinRT.

  • Para aproveitar a vantagem de desempenho do C++ em operações complexas ou com uso intensivo de computação.
  • Para reutilizar o código C++ padrão que já foi escrito e testado.
  • Para expor a funcionalidade Win32 a um aplicativo UWP (Plataforma Universal do Windows) escrito, por exemplo, em C#.

Em geral, ao criar seu componente C++/WinRT, você pode usar tipos da biblioteca C++ padrão e tipos internos, exceto no limite da ABI (interface binária do aplicativo) em que você está passando dados de e para o código em outro .winmd pacote. Na ABI, use tipos do Tempo de Execução do Windows. Além disso, em seu código C++/WinRT, use tipos como delegate e event para implementar eventos que podem ser gerados do componente e manipulados em outra linguagem. Consulte C++/WinRT para obter mais informações sobre C++/WinRT.

O restante deste tópico explica como criar um componente do Tempo de Execução do Windows em C++/WinRT e, em seguida, como consumi-lo de um aplicativo.

O componente do Tempo de Execução do Windows que você criará neste tópico contém uma classe de tempo de execução que representa um termômetro. O tópico também demonstra um aplicativo principal que consome a classe de runtime do termômetro e chama uma função para ajustar a temperatura.

Observação

Para saber mais sobre como instalar e usar a VSIX (Extensão do Visual Studio) para C++/WinRT e o pacote NuGet (que juntos fornecem um modelo de projeto e suporte ao build), confira Suporte ao Visual Studio para C++/WinRT.

Importante

Para ver conceitos e termos essenciais que ajudam a entender como utilizar e criar classes de runtime com C++/WinRT, confira Utilizar APIs com C++/WinRT e Criar APIs com C++/WinRT.

Práticas recomendadas de nomenclatura para dlls de componentes do Tempo de Execução do Windows

Importante

Esta seção descreve a convenção de nomenclatura que recomendamos que você use para o .dll arquivo (DLL) no qual você cria seu componente do Tempo de Execução do Windows. É tudo sobre a sequência de ativação que o C++/WinRT segue quando você consome uma classe de runtime de um componente do Windows Runtime.

Ao ativar uma fábrica de classes, o C++/WinRT primeiro tenta uma chamada para RoGetActivationFactory. Se isso falhar, o C++/WinRT tentará encontrar uma DLL para carregar diretamente. A ativação do Tempo de Execução do Windows é sempre baseada em um nome de classe totalmente qualificado. A lógica é remover o nome da classe (desse nome de classe totalmente qualificado) e, em seguida, procurar uma DLL nomeada para o namespace completo que permanece. Se isso não for encontrado, remova o nome do segmento mais específico e repita.

Portanto, por exemplo, se a classe que está sendo ativada tiver um nome totalmente qualificado de Contoso.Instruments.ThermometerWRC.Thermometer e RoGetActivationFactory falhar, primeiro procuraremos um Contoso.Instruments.ThermometerWRC.dll. Se isso não for encontrado, procuraremos por Contoso.Instruments.dll, e depois por Contoso.dll.

Quando uma DLL for encontrada (nessa sequência), usaremos o ponto de entrada DllGetActivationFactory dessa DLL para tentar obter a fábrica diretamente (em vez de indiretamente por meio da função RoGetActivationFactory que tentamos pela primeira vez). Mesmo assim, o resultado final é indistinguível para o chamador e para a DLL.

Esse processo é totalmente automático - nenhum registro ou ferramenta é necessário. Se você estiver criando um componente do Tempo de Execução do Windows, precisará apenas usar uma convenção de nomenclatura para suas DLLs que funcione com o processo que acabamos de descrever. E se você estiver consumindo um componente do Tempo de Execução do Windows e ele não estiver nomeado corretamente, você terá a opção de renomeá-lo conforme descrito.

Criar um componente do Tempo de Execução do Windows (ThermometerWRC)

Comece criando um novo projeto no Microsoft Visual Studio. Crie um projeto de Componente do Tempo de Execução do Windows (C++/WinRT) e nomeie-o como ThermometerWRC (para "componente do Tempo de Execução do Windows do termômetro"). Verifique se a opção Colocar a solução e o projeto no mesmo diretório está desmarcada. Direcione a versão mais recente em disponibilidade geral (ou seja, que não esteja em versão prévia) do SDK do Windows. Nomear o projeto ThermometerWRC lhe dará a experiência mais fácil com o restante das etapas deste tópico.

Não crie o projeto ainda.

O projeto recém-criado contém um arquivo chamado Class.idl. No Gerenciador de Soluções, renomeie esse arquivo para Thermometer.idl (renomear o arquivo .idl também renomeia automaticamente os arquivos dependentes .h e .cpp). Substitua o conteúdo de Thermometer.idl pela listagem a seguir.

// Thermometer.idl
namespace ThermometerWRC
{
    runtimeclass Thermometer
    {
        Thermometer();
        void AdjustTemperature(Single deltaFahrenheit);
    };
}

Salve o arquivo. O projeto não será compilado até a conclusão no momento, mas compilar agora é uma coisa útil a se fazer porque ele gera os arquivos de código-fonte nos quais você implementará a classe de tempo de execução Thermometer . Portanto, vá em frente e compile agora (os erros de compilação que você espera ver neste estágio têm a ver com Class.h e Class.g.h que não foram encontrados).

Durante o processo de compilação, a ferramenta midl.exe é executada para criar o arquivo de metadados do componente do Windows Runtime (que é \ThermometerWRC\Debug\ThermometerWRC\ThermometerWRC.winmd). Em seguida, a ferramenta cppwinrt.exe é executada (com a opção -component) para gerar arquivos de código fonte que dão suporte na criação do componente. Esses arquivos incluem stubs para você começar a implementar a classe de runtime do Termômetro que você declarou em sua IDL. Esses stubs são \ThermometerWRC\ThermometerWRC\Generated Files\sources\Thermometer.h e Thermometer.cpp.

Clique com o botão direito do mouse no nó do projeto e clique em Abrir Pasta no Explorador de Arquivos. A pasta do projeto abre no Explorador de Arquivos. Copie os arquivos de stub Thermometer.h e Thermometer.cpp da pasta \ThermometerWRC\ThermometerWRC\Generated Files\sources\ para a pasta que contém os arquivos de projeto, que é \ThermometerWRC\ThermometerWRC\, e substitua os arquivos no destino. Agora vamos abrir Thermometer.h e Thermometer.cpp, e implementar nossa classe de runtime. No Thermometer.h, adicione um novo membro privado à implementação (não à implementação de fábrica) do Termômetro.

// Thermometer.h
...
namespace winrt::ThermometerWRC::implementation
{
    struct Thermometer : ThermometerT<Thermometer>
    {
        ...

    private:
        float m_temperatureFahrenheit { 0.f };
    };
}
...

No Thermometer.cpp, implemente o método AdjustTemperature conforme mostrado na lista abaixo.

// Thermometer.cpp
...
namespace winrt::ThermometerWRC::implementation
{
    void Thermometer::AdjustTemperature(float deltaFahrenheit)
    {
        m_temperatureFahrenheit += deltaFahrenheit;
    }
}

Você verá um static_assert na parte superior de Thermometer.h e Thermometer.cpp, que você precisará remover. Agora o projeto será criado.

Se um aviso impedir a compilação, resolva-o ou defina a propriedade de projeto C/C++>Geral>Tratar avisos como erros como Não (/WX-), e compile o projeto novamente.

Criar um aplicativo principal (ThermometerCoreApp) para testar o componente do Tempo de Execução do Windows

Agora crie um novo projeto (seja em sua solução ThermometerWRC ou em uma nova). Crie um projeto de Aplicativo Principal (C++/WinRT) e nomeie-o como ThermometerCoreApp. Defina ThermometerCoreApp como o projeto de inicialização se os dois projetos estiverem na mesma solução.

Observação

Conforme mencionado anteriormente, o arquivo de metadados do Tempo de Execução do Windows para o componente do Tempo de Execução do Windows (cujo projeto você chamou de ThermometerWRC) é criado na pasta \ThermometerWRC\Debug\ThermometerWRC\. O primeiro segmento desse caminho é o nome da pasta que contém o arquivo de solução. O próximo segmento é o subdiretório dela, chamado Debug. O último segmento é o subdiretório dele, nomeado para o componente do Windows Runtime. Se você não nomeou seu projeto como ThermometerWRC, seu arquivo de metadados estará na pasta \<YourProjectName>\Debug\<YourProjectName>\.

Agora, em seu projeto de Aplicativo Principal (ThermometerCoreApp), adicione uma referência e navegue até \ThermometerWRC\Debug\ThermometerWRC\ThermometerWRC.winmd (ou adicione uma referência de projeto a projeto, se os dois projetos estiverem na mesma solução). Clique em Adicionar e em OK. Agora crie o ThermometerCoreApp. No caso improvável de você ver um erro informando que o arquivo readme.txt de carga não existe, exclua esse arquivo do projeto de componente do Tempo de Execução do Windows, recompile-o e recompile ThermometerCoreApp.

Durante o processo de compilação, a ferramenta cppwinrt.exe é executada para processar o arquivo .winmd mencionado nos arquivos de código-fonte que contêm os tipos projetados para ajudá-lo a utilizar o componente. O cabeçalho dos tipos projetados para as classes de tempo de execução do componente, denominado ThermometerWRC.h—, é gerado na pasta \ThermometerCoreApp\ThermometerCoreApp\Generated Files\winrt\.

Inclua esse cabeçalho em App.cpp.

// App.cpp
...
#include <winrt/ThermometerWRC.h>
...

Também em App.cpp, adicione o código a seguir para instanciar um objeto Thermometer (usando o construtor padrão do tipo projetado) e chame um método no objeto thermometer.

struct App : implements<App, IFrameworkViewSource, IFrameworkView>
{
    ThermometerWRC::Thermometer m_thermometer;
    ...
    
    void OnPointerPressed(IInspectable const &, PointerEventArgs const & args)
    {
        m_thermometer.AdjustTemperature(1.f);
        ...
    }
    ...
};

Cada vez que você clica na janela, você incrementa a temperatura do objeto do termômetro. Você pode definir pontos de interrupção se quiser percorrer o código para confirmar se o aplicativo realmente está chamando o componente do Tempo de Execução do Windows.

Próximas etapas

Para adicionar ainda mais funcionalidades ou novos tipos de Tempo de Execução do Windows ao componente C++/WinRT do Tempo de Execução do Windows, você pode seguir os mesmos padrões mostrados acima. Primeiro, use o IDL para definir a funcionalidade que você deseja expor. Em seguida, crie o projeto no Visual Studio para gerar uma implementação de stub. Em seguida, conclua a implementação conforme apropriado. Todos os métodos, propriedades e eventos definidos na IDL são visíveis para o aplicativo que consome o componente do Tempo de Execução do Windows. Para obter mais informações sobre IDL, consulte Introdução à Linguagem de Definição de Interface da Microsoft 3.0.

Para obter um exemplo de como adicionar um evento ao componente do Tempo de Execução do Windows, consulte Criar eventos em C++/WinRT.

Solução de problemas

Sintoma Medida
Em um aplicativo C++/WinRT, ao consumir um componente do Windows Runtime com C# que usa o XAML, o compilador produz um erro no formato "'MyNamespace_XamlTypeInfo': não é um membro de 'winrt::MyNamespace'", em que MyNamespace é o nome do namespace do componente do Windows Runtime. Em pch.h no aplicativo C++/WinRT de consumo, adicione #include <winrt/MyNamespace.MyNamespace_XamlTypeInfo.h>substituindo MyNamespace conforme apropriado.