Introdução ao C++/WinRT

Importante

Para saber mais sobre como configurar o Visual Studio para desenvolvimento em C++/WinRT, incluindo instalação e uso da 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 do Visual Studio para C++/WinRT.

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

Observação

Embora a recomendação seja realizar o desenvolvimento usando as últimas versões do Visual Studio e do SDK do Windows, se você estiver usando o Visual Studio 2017 (15.8.0 ou superior) e visando o SDK do Windows 10.0.17134.0 (Windows 10, versão 1803), poderá ocorrer uma falha de compilação em um projeto do C++/WinRT recentemente criado com o erro "erro C3861 ─ 'from_abi': identificador não encontrado" e com outros erros originados em base.h. A solução é visar uma versão posterior (mais compatível) do SDK do Windows ou definir a propriedade do projeto C/C++>Language>Conformance mode: No (além disso, se /permissive- for exibido na propriedade do projeto C/C++>Language>Command Line em Additional Options, exclua-o).

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

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

Edite pch.h e main.cpp para que tenha a aparência a seguir.

// 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 acima detalhadamente 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 padrão do projeto, os cabeçalhos incluídos vêm do SDK do Windows, dentro da pasta %WindowsSdkDir%Include<WindowsTargetPlatformVersion>\cppwinrt\winrt. O Visual Studio inclui esse caminho em sua macro IncludePath. Mas não há dependência estrita sobre o SDK do Windows, pois seu projeto (por meio da ferramenta cppwinrt.exe) gera os 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 em C++/WinRT. Em outras palavras, para cada tipo de Windows, o C++/WinRT define um equivalente amigável de C++ (chamado de tipo projetado). Um tipo projetado tem o mesmo nome totalmente qualificado do tipo do Windows, mas ele é colocado no namespace winrt de C++. Colocar essas inclusões no cabeçalho pré-compilado reduz os tempos incrementais da compilação.

Importante

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

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

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

As diretivas using namespace são opcionais, mas convenientes. O padrão mostrado acima para essas diretivas (permitindo a pesquisa de nome não qualificado para qualquer item no namespace winrt) é adequado para quando você estiver iniciando um novo projeto e C++/WinRT for a única projeção de linguagem que está sendo usada dentro desse projeto. Por outro lado, se você estiver misturando código de C++/WinRT com C++/CX e/ou código ABI (interface binária de aplicativo) do SDK (você está fazendo a portabilidade de ou a interoperabilidade com um ou ambos os modelos), veja os tópicos Interoperabilidade entre C++/WinRT e C++/CX, Mover do C++/CX para C++/WinRT e Interoperabilidade entre C++/WinRT e ABI.

winrt::init_apartment();

A chamada a winrt::init_apartment inicializa o thread no Windows Runtime; por padrão, em um apartment multi-threaded. A chamada também inicializa o COM.

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

Aloque dois objetos em pilha: eles representam o uri do blog do Windows e um cliente de sindicalização. Construímos o uri com um literal de cadeia de caracteres simples (veja Processamento da cadeia de caracteres em C++/WinRT para ver outras formas de trabalhar com cadeias de caracteres).

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

SyndicationClient::RetrieveFeedAsync é um exemplo de uma função assíncrona do Windows Runtime. O exemplo de código recebe um objeto de operação assíncrona do RetrieveFeedAsync e chama get nesse objeto para bloquear o thread de chamada e aguardar os resultados (no caso, um feed de sindicalização). Para saber mais sobre simultaneidade e técnicas de não bloqueio, confira Simultaneidade e operações assíncronas com C++/WinRT.

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

SyndicationFeed.Items é um intervalo, definido pelos iteradores retornados pelas funções begin e end (ou por suas variantes constantes, reversas e constante-reversas). Por isso, você pode enumerar itens com uma instrução for baseada em intervalo ou com a função de modelo std::for_each. Sempre que você iterar em uma coleção do Windows Runtime como essa, você precisará #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;

Veja o texto do título do feed como um objeto winrt::hstring (mais detalhes em Processamento de cadeia de caracteres em C++/WinRT). Em seguida, hstring é enviado pela função c_str, que reflete o padrão usado com cadeias de caracteres da biblioteca padrão C++.

Como você pode ver, o C++/WinRT incentiva o uso de expressões C++ modernas e semelhantes a classes, como syndicationItem.Title().Text(). Esse é um estilo de programação diferente e mais limpo em contraposição à programação COM tradicional. Não é necessário inicializar diretamente o COM nem trabalhar com ponteiros do COM.

Nem tampouco é necessário processar os códigos de retorno de HRESULT. O C++/WinRT converte os HRESULTs de erro em exceções, como winrt::hresult-error para oferecer um estilo de programação moderno e natural. Para saber mais sobre o processamento de erros e ver exemplos de código, confira Processamento de erros com C++/WinRT.

Modificar um projeto de aplicativo de Área de Trabalho do Windows para adicionar suporte ao C++/WinRT

Alguns projetos de área de trabalho (por exemplo, os modelos da WinUI 3 no Visual Studio) contam com suporte interno a C++/WinRT.

Mas esta seção mostra como você pode adicionar o suporte ao C++/WinRT a qualquer projeto de aplicativo da área de trabalho do Windows. Se você não tiver um projeto de aplicativo de Área de Trabalho do Windows existente, siga estas etapas para criar um. Por exemplo, abra o Visual Studio e crie um projeto Visual C++>Área de Trabalho do Windows>Aplicativo de Área de Trabalho do Windows.

Se desejar, você pode instalar a VSIX (Extensão do Visual Studio) para C++/WinRT e o pacote NuGet. Para obter detalhes, confira Suporte ao Visual Studio para C++/WinRT.

Definir propriedades do projeto

Vá para a propriedade do projeto Geral>Versão do SDK do Windows e selecione Todas as Configurações e Todas as Plataformas. Certifique-se de que a Versão do SDK do Windows esteja definida para 10.0.17134.0 (Windows 10, versão 1803) ou superior.

Confirme que você não será 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 do projeto C/C++>Linguagem>Padrão da Linguagem C++ para Padrão ISO C++17 (/std:c++17) .

O cabeçalho pré-compilado

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

Localize e substitua todo o #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 de C++/WinRT depende de determinadas funções livres (não membros) do Windows Runtime, que exigem vinculação à biblioteca WindowsApp.lib. Esta seção descreve três maneiras de atender ao vinculador.

A primeira opção é adicionar ao seu projeto do Visual Studio todos os destinos e propriedades MSBuild de C++/WinRT. Para isso, instale o pacote NuGet Microsoft.Windows.CppWinRT em seu projeto. Abra o projeto no Visual Studio, clique em Projeto>Gerenciar Pacotes NuGet...>Procurar, digite ou cole Microsoft.Windows.CppWinRT na caixa de pesquisa, selecione o item nos resultados da pesquisa e, em seguida, clique em Instalar para instalar o pacote para esse projeto.

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) como se segue.

#pragma comment(lib, "windowsapp")

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

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

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

Como consumir APIs e tipos do 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-se ao shell do Windows; e assim por diante. O C++/WinRT dá suporte total e inflexível a essa categoria de cenário. Para saber mais, confira Consumir APIs com C++/WinRT.

Como criar APIs e tipos do Windows

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

Criar APIs com o C++/WinRT é um pouco mais complicado do que consumi-las, porque você deve usar o IDL para definir a forma da API antes de poder implementá-la. Há um passo a passo para fazer isso nos Controles XAML; associar a uma propriedade de C++/WinRT.

Aplicativos XAML

Esse cenário trata-se de compilar aplicativos e controles na estrutura de interface do usuário XAML. Trabalhar em um aplicativo XAML resulta em uma combinação de consumo e criação. Mas como o XAML é a estrutura de interface do usuário dominante no Windows atualmente e sua influência sobre o Windows Runtime é proporcional a isso, ele 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 ter um pouco mais de trabalho para interoperar com a estrutura XAML. Todos esses casos são abordados na documentação. Bons locais para começar são Controles XAML; associar a uma propriedade de C++/WinRT e controles personalizados XAML (com modelo) com o C++/WinRT.

Aplicativos de exemplo escritos em C++/WinRT

Confira Onde posso encontrar aplicativos de exemplo do C++/WinRT?.

APIs importantes