Introdução ao C++/WinRT

Important

Para obter informações sobre como configurar Visual Studio para o desenvolvimento do C++/WinRT, incluindo a instalação e o uso da VSIX (Extensão de Visual Studio) do C++/WinRT e do pacote NuGet (que, juntos, fornecem modelo de projeto e suporte de build)— consulte Visual Studio suporte para C++/WinRT.

Para acelerar o uso do C++/WinRT, este tópico apresenta um exemplo de código simples com base em um novo projeto do C++/WinRT (Aplicativo de Console do Windows). Este tópico também mostra como adicionar suporte do C++/WinRT a um projeto de aplicativo do Windows Desktop.

Note

Embora seja recomendável desenvolver com as versões mais recentes do Visual Studio e do SDK do Windows, se você estiver usando Visual Studio 2017 (versão 15.8.0 ou posterior) e direcionando o SDK Windows versão 10.0.17134.0 (Windows 10, versão 1803), um projeto C++/WinRT recém-criado pode falhar ao compilar com o erro "erro C3861: 'from_abi': identificador não encontrado" e com outros erros originados em base.h. A solução é usar como destino uma versão posterior (mais compatível com o padrão) do SDK do Windows ou definir a propriedade do projeto C/C++>Linguagem>Modo de conformidade: Não (além disso, se /permissive- aparecer na propriedade do projeto C/C++>Linguagem>Linha de Comando, em Opções Adicionais, exclua-o).

Um início rápido do C++/WinRT

Crie um novo projeto Windows Aplicativo de Console (C++/WinRT).

Edite pch.h e main.cpp para ficarem assim.

// pch.h
#pragma once
#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.Web.Syndication.h>
#include <iostream>
// main.cpp
#include "pch.h"

using namespace winrt;
using namespace Windows::Foundation;
using namespace Windows::Web::Syndication;

int main()
{
    winrt::init_apartment();

    Uri rssFeedUri{ L"https://blogs.windows.com/feed" };
    SyndicationClient syndicationClient;
    syndicationClient.SetRequestHeader(L"User-Agent", L"Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)");
    SyndicationFeed syndicationFeed = syndicationClient.RetrieveFeedAsync(rssFeedUri).get();
    for (const SyndicationItem syndicationItem : syndicationFeed.Items())
    {
        winrt::hstring titleAsHstring = syndicationItem.Title().Text();
        
        // A workaround to remove the trademark symbol from the title string, because it causes issues in this case.
        std::wstring titleAsStdWstring{ titleAsHstring.c_str() };
        titleAsStdWstring.erase(remove(titleAsStdWstring.begin(), titleAsStdWstring.end(), L'™'), titleAsStdWstring.end());
        titleAsHstring = titleAsStdWstring;

        std::wcout << titleAsHstring.c_str() << std::endl;
    }
}

Vamos usar o exemplo de código curto acima, peça por peça, e explicar o que está acontecendo em cada parte.

#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.Web.Syndication.h>

Com as configurações de projeto padrão, os cabeçalhos incluídos vêm do SDK do Windows, dentro da pasta%WindowsSdkDir%Include<WindowsTargetPlatformVersion>\cppwinrt\winrt. Visual Studio inclui esse caminho em sua macro IncludePath. Mas não há nenhuma dependência estrita no SDK do Windows, pois seu projeto (por meio da cppwinrt.exe ferramenta) gera esses mesmos cabeçalhos na pasta $(GeneratedFilesDir) do seu projeto. Eles serão carregados dessa pasta se não puderem ser encontrados em outro lugar ou se você alterar as configurações do projeto.

Os cabeçalhos contêm APIs do Windows projetadas para C++/WinRT. Em outras palavras, para cada tipo de Windows, C++/WinRT define um equivalente C++amigável (chamado de tipo projetado). Um tipo projetado tem o mesmo nome totalmente qualificado que o tipo de Windows, mas é colocado no namespace do winrt do C++. Colocar essas diretivas de inclusão no seu cabeçalho pré-compilado reduz os tempos de compilação incremental.

Important

Sempre que você quiser usar um tipo de um namespace do Windows, você deve #include o arquivo de cabeçalho do namespace do Windows correspondente do C++/WinRT, conforme mostrado acima. O cabeçalho correspondente é aquele com o mesmo nome do namespace do tipo. Por exemplo, para usar a projeção C++/WinRT para a classe de tempo de execução Windows::Foundation::Collections::PropertySet, inclua o cabeçalho winrt/Windows.Foundation.Collections.h.

É comum que um cabeçalho de projeção C++/WinRT inclua automaticamente arquivos de cabeçalho de namespace relacionados. Por exemplo, winrt/Windows.Foundation.Collections.h inclui winrt/Windows.Foundation.h. Mas você não deve confiar nesse comportamento, pois é um detalhe de implementação que muda ao longo do tempo. Você deve incluir explicitamente todos os cabeçalhos necessários.

using namespace winrt;
using namespace Windows::Foundation;
using namespace Windows::Web::Syndication;

As using namespace diretivas são opcionais, mas convenientes. O padrão mostrado acima para essas diretivas (permitindo a pesquisa de nomes não qualificados para qualquer coisa no namespace winrt ) é adequado para quando você está iniciando um novo projeto e C++/WinRT é a única projeção de linguagem que você está usando dentro desse projeto. Se, por outro lado, você estiver misturando código C++/WinRT com código C++/CX e/ou ABI (interface binária do aplicativo SDK) (você está portando, ou interoperando com, um ou ambos os modelos), em seguida, consulte os tópicos Interoperabilidade entre C++/WinRT e C++/CX, Mover para C++/WinRT de C++/CX e Interoperabilidade entre C++/WinRT e a ABI.

winrt::init_apartment();

A chamada para winrt::init_apartment inicializa a thread no Windows Runtime; por padrão, em um apartamento multithreaded. A chamada também inicializa COM.

Uri rssFeedUri{ L"https://blogs.windows.com/feed" };
SyndicationClient syndicationClient;

Aloque na pilha dois objetos: eles representam a URI do blog do Windows e um cliente de sindicalização. Criamos o uri com um literal de cadeia de caracteres largo simples (consulte Tratamento de cadeia de caracteres em C++/WinRT para obter mais maneiras de trabalhar com cadeias de caracteres).

SyndicationFeed syndicationFeed = syndicationClient.RetrieveFeedAsync(rssFeedUri).get();

SyndicationClient::RetrieveFeedAsync é um exemplo de uma função de Windows Runtime assíncrona. O exemplo de código recebe um objeto de operação assíncrona de RetrieveFeedAsync e chama get nesse objeto para bloquear a thread chamadora e aguardar o resultado (que, neste caso, é um feed de sindicalização). Para obter mais informações sobre simultaneidade e técnicas de não bloqueio, consulte Simultaneidade e operações assíncronas com C++/WinRT.

for (const SyndicationItem syndicationItem : syndicationFeed.Items()) { ... }

SyndicationFeed.Items é um intervalo definido pelos iteradores retornados das funções de início e de término (ou suas variantes constantes, inversas e constantes-inversas). Por isso, você pode enumerar Itens com uma instrução baseada em for intervalo ou com a função de modelo std::for_each . Sempre que você iterar por uma coleção do Windows Runtime como essa, será necessário #include <winrt/Windows.Foundation.Collections.h>.

winrt::hstring titleAsHstring = syndicationItem.Title().Text();

// Omitted: there's a little bit of extra work here to remove the trademark symbol from the title text.

std::wcout << titleAsHstring.c_str() << std::endl;

Obtém o texto do título do feed, como um objeto winrt::hstring (mais detalhes sobre o tratamento de cadeia de caracteres em C++/WinRT). A hstring é então retornada, por meio da função c_str, que reflete o padrão usado com cadeias de caracteres da Biblioteca Padrão do C++.

Como você pode ver, O C++/WinRT incentiva expressões C++ modernas e semelhantes a classes, como syndicationItem.Title().Text(). Esse é um estilo de programação diferente e mais limpo da programação COM tradicional. Você não precisa inicializar diretamente o COM nem trabalhar com ponteiros COM.

Também não é necessário lidar com códigos de retorno HRESULT. O C++/WinRT converte os HRESULTs de erro em exceções como winrt::hresult-error para um estilo de programação natural e moderno. Para obter mais informações sobre tratamento de erros e exemplos de código, consulte Tratamento de erros com C++/WinRT.

Modificar um projeto de aplicativo da área de trabalho Windows para adicionar suporte ao C++/WinRT

Alguns projetos para desktop (por exemplo, os modelos do WinUI 3 no Visual Studio) têm suporte interno a C++/WinRT.

Mas esta seção mostra como você pode adicionar suporte do C++/WinRT a qualquer projeto de aplicativo da área de trabalho Windows que você possa ter. Se você não tiver um projeto de aplicativo da área de trabalho Windows existente, poderá acompanhar essas etapas criando primeiro uma. Por exemplo, abra o Visual Studio e crie um projeto Visual C++>Windows Desktop>Aplicativo da Área de Trabalho do Windows.

Você pode instalar opcionalmente a Extensão do Visual Studio C++/WinRT (VSIX) e o pacote NuGet. Para obter detalhes, consulte Visual Studio suporte para C++/WinRT.

Definir propriedades do projeto

Vá para a propriedade de projeto General>Windows Versão do SDK e selecione Todas as Configurações e Todas as Plataformas. Verifique se Windows versão do SDK está definida como 10.0.17134.0 (Windows 10, versão 1803) ou superior.

Confirme se você não foi afetado por Por que meu novo projeto não será compilado?.

Como o C++/WinRT usa recursos do padrão C++17, defina a propriedade de projeto C/C++>Language>C++ Language Language Standard como ISO C++17 Standard (/std:c++17).

O cabeçalho pré-compilado

O modelo de projeto padrão cria um cabeçalho pré-compilado para você, chamado de framework.h ou stdafx.h. Renomeie-o para pch.h. Se você tiver um stdafx.cpp arquivo, renomeie-o para pch.cpp. Defina a propriedade do projeto C/C++>Cabeçalhos pré-compilados>Cabeçalho pré-compilado como Criar (/Yc) e Arquivo de cabeçalho pré-compilado como pch.h.

Localizar e substituir tudo #include "framework.h" (ou #include "stdafx.h") por #include "pch.h".

Em pch.h, inclua winrt/base.h.

// pch.h
...
#include <winrt/base.h>

Vinculação

A projeção de linguagem C++/WinRT depende de determinadas funções livres do Windows Runtime (funções não membro) e de pontos de entrada que exigem vinculação com a biblioteca agregadora WindowsApp.lib. Esta seção descreve três maneiras de satisfazer o vinculador.

A primeira opção é adicionar ao projeto do Visual Studio todas as propriedades e os alvos do MSBuild do C++/WinRT. Para fazer isso, instale o pacote NuGet Microsoft.Windows.CppWinRT no seu projeto. Abra o project em Visual Studio, clique em Project>Manage NuGet Packages...>Navegue, digite ou cole Microsoft.Windows. CppWinRT na caixa de pesquisa, selecione o item nos resultados da pesquisa e clique em Instalar para instalar o pacote para esse project.

Você também pode usar as configurações de link do projeto para vincular WindowsApp.lib explicitamente. Ou, você pode fazê-lo no código-fonte (em pch.h, por exemplo) assim.

#pragma comment(lib, "windowsapp")

Agora você pode compilar e vincular e adicionar código C++/WinRT ao seu projeto (por exemplo, código semelhante ao mostrado na seção de início rápido do A C++/WinRT , acima).

Os três principais cenários para C++/WinRT

Conforme você usa e se familiariza com o C++/WinRT e trabalha com o restante da documentação aqui, você provavelmente observará que há três cenários principais, conforme descrito nas seções a seguir.

Consumindo APIs e tipos de Windows

Em outras palavras, usar ou chamar APIs. Por exemplo, fazer chamadas à API para se comunicar usando Bluetooth; para transmitir e apresentar vídeo; para integrar com o shell Windows; e assim por diante. O C++/WinRT dá suporte total e intransigente a essa categoria de cenário. Para obter mais informações, consulte Consumir APIs com C++/WinRT.

Criando APIs e tipos de Windows

Em outras palavras, produzindo APIs e tipos. Por exemplo, produzir os tipos de APIs descritos na seção acima; ou as APIs gráficas; as APIs do sistema de arquivos e armazenamento; as APIs de rede e assim por diante. Para obter mais informações, consulte Criação de APIs com C++/WinRT.

A criação de APIs com C++/WinRT é um pouco mais envolvida do que consumi-las, pois você deve usar a IDL para definir a forma da API antes de poder implementá-la. Há um passo a passo para fazer isso em controles XAML; vincular a uma propriedade C++/WinRT.

Aplicativos XAML

Esse cenário é sobre a criação de aplicativos e controles na estrutura da interface do usuário XAML. Trabalhar em um aplicativo XAML equivale a uma combinação de consumo e criação. Mas como o XAML é a estrutura dominante da interface do usuário no Windows hoje, e sua influência sobre a Windows Runtime é proporcional a isso, ela merece sua própria categoria de cenário.

Lembre-se de que o XAML funciona melhor com linguagens de programação que oferecem reflexão. No C++/WinRT, às vezes você precisa fazer um trabalho extra para interoperar com a estrutura XAML. Todos esses casos são abordados na documentação. Bons pontos de partida são controles XAML; associação a uma propriedade C++/WinRT e controles XAML personalizados com modelo no C++/WinRT.

Aplicativos de exemplo escritos em C++/WinRT

Veja onde posso encontrar aplicativos de exemplo do C++/WinRT?.

APIs importantes