Partilhar via


O que há de novo no C++/WinRT

À medida que as versões subsequentes do C++/WinRT são lançadas, este tópico descreve as novidades e as alterações.

Compilação de melhorias/adições recentes até março de 2020

Tempos de construção até 23% mais curtos

As equipes de compiladores C++/WinRT e C++ colaboraram para fazer todo o possível para reduzir os tempos de compilação. Nós nos debruçamos sobre a análise do compilador para descobrir como os internos do C++/WinRT podem ser reestruturados para ajudar o compilador C++ a eliminar a sobrecarga em tempo de compilação, bem como como o próprio compilador C++ pode ser melhorado para lidar com a biblioteca C++/WinRT. C++/WinRT foi otimizado para o compilador; e o compilador foi otimizado para C++/WinRT.

Tomemos como exemplo o pior cenário de criação de um cabeçalho pré-compilado (PCH) que contenha todos os cabeçalhos de namespace de projeção C++/WinRT.

Versão Tamanho da PCH (bytes) Tempo (s)
C++/WinRT de julho, com Visual C++ 16.3 3,004,104,632 31
versão 2.0.200316.3 do C++/WinRT, com Visual C++ 16.5 2,393,515,336 24

Uma redução de 20% no tamanho e uma redução de 23% no tempo de construção.

Suporte melhorado ao MSBuild

Investimos muito trabalho para melhorar o suporte do MSBuild para vários cenários.

Cache de fábrica ainda mais rápido

Melhorámos a integração do cache da fábrica para melhorar o desempenho dos caminhos críticos, resultando em uma execução mais rápida.

Essa melhoria não afeta o tamanho do código — conforme descrito abaixo em Optimized EH code-gen, se seu aplicativo usa muito o tratamento de exceções C++, você pode reduzir seu binário usando a opção, que está ativada por padrão em novos projetos criados com o /d2FH4 Visual Studio 2019 16.3 e posterior.

Boxe mais eficiente

Quando usado numa aplicação XAML, winrt::box_value é agora mais eficiente (ver Embalagem e desembalagem). Aplicativos que fazem muito boxe também notarão uma redução no tamanho do código.

Suporte para implementação de interfaces COM que implementam IInspectable

Se você precisar implementar uma interface COM (nãoWindows-Runtime) que por acaso implemente IInspectable, agora você pode fazê-lo com C++/WinRT. Veja as interfaces COM que implementam IInspectable.

Melhorias no bloqueio de módulos

O controle sobre o bloqueio de módulo agora permite cenários de hospedagem personalizados e a eliminação total do bloqueio no nível do módulo. Consulte Aprimoramentos de bloqueio de módulo.

Suporte para informações de erro diferentes deWindows-Runtime

Algumas APIs (até mesmo algumas APIs do Runtime do Windows) relatam erros sem usar as APIs de originação de erros do Runtime do Windows. Em casos como esse, C++/WinRT agora volta a usar informações de erro COM. Consulte suporte a C++/WinRT para obter informações de erro que não sejam do WinRT.

Habilite o suporte ao módulo C++

O suporte ao módulo C++ está de volta, mas apenas de forma experimental. O recurso ainda não está completo no compilador C++.

A retomada de corrotina mais eficiente

As co-rotinas C++/WinRT já têm um bom desempenho, mas continuamos a procurar formas de melhorá-las. Veja para melhorar a escalabilidade da retomada de corrotinas.

Novos auxiliares assíncronos when_all e when_any

A função auxiliar when_all cria um objeto IAsyncAction que é concluído quando todos os objetos aguardáveis fornecidos tiverem sido concluídos. O helper when_any cria uma IAsyncAction que é concluída quando qualquer uma das tarefas assíncronas fornecidas foram concluídas.

Consulte Adicionar o auxiliar assíncrono when_any e Adicionar o auxiliar assíncrono when_all.

Outras otimizações e adições

Além disso, muitas correções de bugs e pequenas otimizações e adições foram introduzidas, incluindo várias melhorias para simplificar a depuração e otimizar os componentes internos e as implementações padrão. Siga este link para uma lista exaustiva: https://github.com/microsoft/xlang/pulls?q=is%3Apr+is%3Aclosed.

Notícias e alterações em C++/WinRT 2.0

Para obter mais informações sobre a Extensão Visual Studio C++/WinRT (VSIX) , o pacote NuGet Microsoft.Windows.CppWinRT e a ferramenta cppwinrt.exe — incluindo como adquiri-los e instalá-los — consulte o suporte do Visual Studio ao C++/WinRT, XAML, a extensão VSIX e o pacote NuGet .

Alterações no C++/WinRT Visual Studio Extension (VSIX) para a versão 2.0

  • O visualizador de depuração agora oferece suporte ao Visual Studio 2019, bem como continua a oferecer suporte ao Visual Studio 2017.
  • Inúmeras correções de bugs foram feitas.

Alterações no pacote NuGet Microsoft.Windows.CppWinRT para versão 2.0

  • A ferramenta cppwinrt.exe agora está incluída no pacote NuGet Microsoft.Windows.CppWinRT e gera cabeçalhos de projeção platfom para cada projeto sob demanda. Consequentemente, a cppwinrt.exe ferramenta não depende mais do SDK do Windows (embora, a ferramenta ainda seja fornecida com o SDK por motivos de compatibilidade).
  • cppwinrt.exe agora gera cabeçalhos de projeção em cada pasta intermediária ($IntDir) específica da plataforma/configuração para permitir compilações paralelas.
  • O suporte à compilação C++/WinRT (props/targets) agora está totalmente documentado, caso você queira personalizar manualmente seus arquivos de projeto. Consulte o pacote Microsoft.Windows.CppWinRT NuGet Leiame.
  • Inúmeras correções de bugs foram feitas.

Alterações no C++/WinRT para a versão 2.0

Código aberto

A ferramenta cppwinrt.exe usa um arquivo de metadados do Tempo de Execução do Windows (.winmd) e gera a partir dele uma biblioteca C++ padrão baseada em arquivo de cabeçalho que projetos APIs descritas nos metadados. Dessa forma, você pode consumir essas APIs do seu código C++/WinRT.

Esta ferramenta é agora um projeto totalmente de código aberto, disponível no GitHub. Visite Microsoft/cppwinrt.

Bibliotecas Xlang

Uma biblioteca apenas de cabeçalho completamente portátil (para analisar o formato de metadados ECMA-335 usado pelo Windows Runtime) forma a base de todas as ferramentas do Windows Runtime e xlang no desenvolvimento futuro. Notavelmente, também reescrevemos a cppwinrt.exe ferramenta do zero usando as bibliotecas xlang. Isso fornece consultas de metadados muito mais precisas, resolvendo alguns problemas de longa data com a projeção da linguagem C++/WinRT.

Menos dependências

Devido ao leitor de metadados xlang, a cppwinrt.exe ferramenta em si tem menos dependências. Isso o torna muito mais flexível, além de ser utilizável em mais cenários, especialmente em ambientes de compilação restritos. Notavelmente, ele não depende mais de RoMetadata.dll.   Estas são as dependências do cppwinrt.exe 2.0.  

  • ADVAPI32.dll
  • KERNEL32.dll
  • SHLWAPI.dll
  • XmlLite.dll

Todas essas DLLs estão disponíveis não apenas no Windows 10, mas até mesmo no Windows 7 e até mesmo no Windows Vista. Se quiser, o seu antigo servidor de compilação que executa Windows 7 pode agora executar cppwinrt.exe para gerar cabeçalhos C++ para o seu projeto. Com um pouco de trabalho, você pode até executar C++ / WinRT no Windows 7, se isso lhe interessar.

Compare a lista acima com essas dependências, que cppwinrt.exe o 1.0 tem.

  • ADVAPI32.dll
  • SHELL32.dll
  • api-ms-win-core-file-l1-1-0.dll
  • XmlLite.dll
  • api-ms-win-core-libraryloader-l1-2-0.dll
  • api-ms-win-core-processenvironment-l1-1-0.dll
  • RoMetadata.dll
  • SHLWAPI.dll
  • KERNEL32.dll
  • api-ms-win-core-rtlsupport-l1-1-0.dll
  • api-ms-win-core-heap-l1-1-0.dll
  • api-ms-win-core-timezone-l1-1-0.dll
  • api-ms-win-core-console-l1-1-0.dll
  • api-ms-win-core-localization-l1-2-0.dll
  • OLEAUT32.dll
  • api-ms-win-core-winrt-error-l1-1-0.dll
  • api-ms-win-core-winrt-error-l1-1-1.dll
  • api-ms-win-core-winrt-l1-1-0.dll
  • api-ms-win-core-winrt-string-l1-1-0.dll
  • api-ms-win-core-synch-l1-1-0.dll
  • api-ms-win-core-threadpool-l1-2-0.dll
  • api-ms-win-core-com-l1-1-0.dll
  • api-ms-win-core-com-l1-1-1.dll
  • api-ms-win-core-synch-l1-2-0.dll

O atributo noexcept do Tempo de Execução do Windows

O Tempo de Execução do Windows tem um novo atributo [noexcept], que você pode usar para decorar seus métodos e propriedades em MIDL 3.0. A presença do atributo indica às ferramentas de suporte que sua implementação não gera uma exceção (nem retorna um HRESULT com falha). Isso permite que as projeções de linguagem otimizem a geração de código, evitando a sobrecarga de tratamento de exceções necessária para dar suporte a chamadas de interface binária de aplicativo (ABI) que podem falhar.

C++/WinRT aproveita isso para produzir implementações em C++ noexcept para ambos os códigos de consumo e de criação. Se você tiver métodos de API ou propriedades livres de falhas e estiver preocupado com o tamanho do código, poderá investigar esse atributo.

Geração de código otimizada

C++/WinRT agora gera código fonte C++ ainda mais eficiente (nos bastidores) para que o compilador C++ possa produzir o menor e mais eficiente código binário possível. Muitas das melhorias visam reduzir o custo do tratamento de exceções, evitando informações de desenrolamento desnecessárias. Os binários que usam grandes quantidades de código C++/WinRT terão uma redução de aproximadamente 4% no tamanho do código. O código também é mais eficiente (é executado mais rápido) devido à contagem reduzida de instruções.

Essas melhorias dependem de um novo recurso de interoperabilidade que também está disponível para você. Todos os tipos de C++/WinRT que são proprietários de recursos agora incluem um construtor para assumirem a propriedade diretamente, evitando a abordagem de duas etapas anterior.

ABI::Windows::Foundation::IStringable* raw = ...

IStringable projected(raw, take_ownership_from_abi);

printf("%ls\n", projected.ToString().c_str());

Geração otimizada de código de tratamento de exceções (EH)

Essa alteração complementa o trabalho que foi feito pela equipe do otimizador do Microsoft C++ para reduzir o custo do tratamento de exceções. Se você usar interfaces binárias de aplicativos (ABIs) (como COM) fortemente em seu código, então você observará um monte de código seguindo esse padrão.

int32_t Function() noexcept
{
    try
    {
        // code here constitutes unique value.
    }
    catch (...)
    {
        // code here is always duplicated.
    }
}

O próprio C++/WinRT gera esse padrão para cada API implementada. Com milhares de funções de API, qualquer otimização aqui pode ser significativa. No passado, o otimizador não detetava que esses blocos de captura são todos idênticos, então estava duplicando muito código em torno de cada ABI (o que, por sua vez, contribuiu para a crença de que o uso de exceções no código do sistema produz grandes binários). No entanto, a partir do Visual Studio 2019, o compilador C++ agrupa todos esses funclets catch e armazena apenas aqueles que são únicos. O resultado é uma redução adicional e geral de 18% no tamanho do código para binários que dependem fortemente desse padrão. Não só o código EH agora é mais eficiente do que usar códigos de retorno, mas também a preocupação com binários maiores é agora uma coisa do passado.

Melhorias incrementais na construção

A cppwinrt.exe ferramenta agora compara a saída de um arquivo de cabeçalho/origem gerado com o conteúdo de qualquer arquivo existente no disco e só grava o arquivo se o arquivo tiver sido de fato alterado. Isso economiza tempo considerável com E/S de disco e garante que os arquivos não sejam considerados "sujos" pelo compilador C++. O resultado é que a recompilação é evitada, ou reduzida, em muitos casos.

As interfaces genéricas são agora todas geradas

Devido ao leitor de metadados xlang, o C++/WinRT agora gera todas as interfaces parametrizadas, ou genéricas, a partir de metadados. Interfaces como Windows::Foundation::Collections::IVector<T> agora são geradas a partir de metadados em vez de escritas à mão em winrt/base.h. O resultado é que o tamanho do winrt/base.h foi reduzido para metade, e que as optimizações são geradas diretamente no código (o que era complicado de fazer com a abordagem manual).

Importante

Interfaces como o exemplo dado agora aparecem em seus respetivos cabeçalhos de namespace, em vez de em winrt/base.h. Portanto, se você ainda não tiver feito isso, terá que incluir o cabeçalho de namespace apropriado para usar a interface.

Otimizações de componentes

Esta atualização adiciona suporte para várias otimizações de aceitação adicionais para C++/WinRT, descritas nas seções abaixo. Como essas otimizações constituem mudanças significativas (exigindo que você faça pequenas alterações para suporte), será necessário ativá-las explicitamente. No Visual Studio, defina a propriedade do projeto Common Properties>C++/WinRT>Optimized para Yes. Isso tem o efeito de adicionar <CppWinRTOptimized>true</CppWinRTOptimized> ao seu arquivo de projeto. E tem o mesmo efeito que adicionar o switch -opt[imize] ao invocar cppwinrt.exe da linha de comando.

Um novo projeto (de um modelo de projeto) usará -opt por defeito.

Construção uniforme e acesso direto à implementação

Essas duas otimizações permitem que seu componente tenha acesso direto aos seus próprios tipos de implementação, mesmo quando ele está usando apenas os tipos projetados. Não há necessidade de usar fazer, make_self, nem get_self se você simplesmente quiser usar a superfície de API pública. Suas chamadas serão compiladas em chamadas diretas na implementação, e elas podem até ser totalmente inseridas.

Para obter mais informações e exemplos de código, consulte Adesão à construção uniforme e acesso direto à implementação.

Fábricas apagadas por tipo

Esta otimização evita as dependências de #include em module.g.cpp, de modo que não seja necessário recompilar toda vez que uma única classe de implementação sofrer alterações. O resultado é um melhor desempenho de construção.

Mais inteligentes e eficientes module.g.cpp para grandes projetos com várias bibliotecas

O arquivo module.g.cpp agora também contém dois auxiliares compôiveis adicionais, winrt_can_unload_nowe winrt_get_activation_factory. Eles foram projetados para projetos maiores, onde uma DLL é composta por um número de libs, cada uma com suas próprias classes de tempo de execução. Nessa situação, precisa juntar manualmente o da DLL DllGetActivationFactory e o DllCanUnloadNow. Esses auxiliares tornam muito mais fácil para você fazer isso, evitando erros de originação espúrios. A flag da cppwinrt.exe ferramenta -lib também pode ser usada para dar a cada lib seu próprio preâmbulo (em vez de winrt_xxx) para que as funções de cada lib possam ser nomeadas individualmente e, assim, combinadas inequivocamente.

Suporte de corrotina

O suporte de co-rotina é incluído automaticamente. Anteriormente, o apoio residia em vários lugares, o que considerávamos demasiado limitador. E então, temporariamente, para a v2.0, um winrt/coroutine.h arquivo de cabeçalho era necessário, mas isso não é mais necessário. Como as interfaces assíncronas do Tempo de Execução do Windows agora são geradas, em vez de escritas à mão, elas agora residem em winrt/Windows.Foundation.h. Além de ser mais fácil de manter e suportar, isso significa que os auxiliares de co-rotina, como resume_foreground não precisam mais ser anexados ao final de um cabeçalho de namespace. Em vez disso, eles podem incluir mais naturalmente suas dependências. Isso ainda permite que resume_foreground suporte não apenas a retomada em uma determinada Windows::UI::Core::CoreDispatcher, mas agora também pode suportar a retomada em uma determinada Windows::System::DispatcherQueue. Anteriormente, apenas um podia ser suportado; mas não ambos, uma vez que a definição só poderia residir em um namespace.

Aqui está um exemplo do suporte DispatcherQueue.

...
#include <winrt/Windows.System.h>
using namespace Windows::System;
...
fire_and_forget Async(DispatcherQueueController controller)
{
    bool queued = co_await resume_foreground(controller.DispatcherQueue());
    assert(queued);

    // This is just to simulate queue failure...
    co_await controller.ShutdownQueueAsync();

    queued = co_await resume_foreground(controller.DispatcherQueue());
    assert(!queued);
}

Os ajudantes de co-rotina agora também são decorados com [[nodiscard]], melhorando assim sua usabilidade. Se você esquecer (ou não perceber que precisa) co_await-los para que eles funcionem, então, devido a [[nodiscard]], esses erros agora produzem um aviso de compilador.

Ajuda no diagnóstico de alocações diretas (pilha)

Como os nomes de classe projetados e de implementação são (por padrão) os mesmos e diferem apenas pelo namespace, é possível confundir um pelo outro e acidentalmente criar uma implementação na pilha, em vez de usar a família de auxiliares do tipo . Isso pode ser difícil de diagnosticar em alguns casos, porque o objeto pode ser destruído enquanto as referências pendentes ainda estão em voo. Uma asserção agora captura isso durante compilações de depuração. Embora a asserção não detete a alocação de pilha dentro de uma coroutine, é, no entanto, útil para apanhar a maior parte desses erros.

Para obter mais informações, consulte Diagnóstico das alocações diretas.

Ajudantes de captura aprimorados e delegados variáveis

Esta atualização corrige a limitação com os auxiliares de captura, suportando também os tipos projetados. Isto ocorre ocasionalmente com as APIs de interoperabilidade do Tempo de Execução do Windows, quando elas retornam um tipo previsto.

Esta atualização também adiciona suporte para get_strong e get_weak quando se cria um delegado variádico (não do Tempo de Execução do Windows).

Suporte para destruição diferida e QI seguro durante a destruição

Não é incomum no destrutor de um objeto de uma classe em tempo de execução chamar um método que aumenta temporariamente a contagem de referência. Quando a contagem de referência retorna a zero, o objeto é destruído uma segunda vez. Em uma aplicação XAML, pode ser necessário executar um QueryInterface (QI) em um destrutor, para chamar alguma tarefa de limpeza ao longo da hierarquia. Mas a contagem de referência do objeto já atingiu zero, de modo que o QI também constitui um salto de contagem de referência.

Esta atualização adiciona suporte para debouncing a contagem de referência, garantindo que, uma vez que atinge zero, nunca poderá ser ressuscitado; enquanto ainda permite que você QI para qualquer temporário que você precisa durante a destruição. Esse procedimento é inevitável em determinados aplicativos/controles XAML, e o C++/WinRT agora é resiliente a ele.

Você pode adiar a destruição, fornecendo uma função estática de final_release no seu tipo de implementação. O último ponteiro restante para o objeto, na forma de um std::unique_ptr, é passado para o seu final_release. A seguir, podes optar por transferir a propriedade desse ponteiro para outro contexto. É seguro para você QI o ponteiro sem desencadear uma dupla destruição. Mas a alteração líquida na contagem de referência deve ser zero no ponto em que você destrói o objeto.

O valor de retorno de final_release pode ser void, um objeto de operação assíncrona, como IAsyncAction, ou winrt::fire_and_forget.

struct Sample : implements<Sample, IStringable>
{
    hstring ToString()
    {
        return L"Sample";
    }

    ~Sample()
    {
        // Called when the unique_ptr below is reset.
    }

    static void final_release(std::unique_ptr<Sample> self) noexcept
    {
        // Move 'self' as needed to delay destruction.
    }
};

No exemplo abaixo, uma vez que o MainPage é lançado (pela última vez), final_release é chamado. Essa função passa cinco segundos a aguardar (no pool de threads) e, em seguida, retoma usando o Dispatcher da página (que requer QI/AddRef/Release para funcionar). Em seguida, ele limpa um recurso nesse thread da interface do usuário. E, finalmente, limpa o unique_ptr, o que faz com que o destrutor de MainPage seja realmente chamado. Mesmo nesse destrutor, o DataContext é chamado, o que requer um QI para IFrameworkElement.

Você não precisa implementar seu final_release como uma corotina. Mas isso funciona, e torna muito simples mover a destruição para um segmento diferente, que é o que está acontecendo neste exemplo.

struct MainPage : PageT<MainPage>
{
    MainPage()
    {
    }

    ~MainPage()
    {
        DataContext(nullptr);
    }

    static IAsyncAction final_release(std::unique_ptr<MainPage> self)
    {
        co_await 5s;

        co_await resume_foreground(self->Dispatcher());
        co_await self->resource.CloseAsync();

        // The object is destructed normally at the end of final_release,
        // when the std::unique_ptr<MyClass> destructs. If you want to destruct
        // the object earlier than that, then you can set *self* to `nullptr`.
        self = nullptr;
    }
};

Para obter mais informações, consulte Destruição adiada.

Suporte melhorado para herança de interface única no estilo COM

Assim como para a programação do Runtime do Windows, o C++/WinRT também é usado para criar e consumir APIs exclusivas COM. Esta atualização torna possível implementar um servidor COM onde existe uma hierarquia de interface. Isso não é necessário para o Tempo de Execução do Windows; mas é necessário para algumas implementações COM.

Manuseio correto dos parâmetros de out

Pode ser complicado trabalhar com out parâmetros; particularmente matrizes do Tempo de Execução do Windows. Com esta atualização, o C++/WinRT é consideravelmente mais robusto e resiliente a erros quando se trata de out parâmetros e arrays, quer esses parâmetros cheguem através de uma projeção de linguagem, quer de um desenvolvedor COM que está usando a ABI bruta e que está cometendo o erro de não inicializar variáveis de forma consistente. Em ambos os casos, o C++/WinRT agora faz a coisa certa quando se trata de entregar tipos projetados para a ABI (lembrando-se de liberar quaisquer recursos) e quando se trata de zerar ou limpar parâmetros que chegam através da ABI.

Os eventos agora lidam com tokens inválidos de forma confiável

A implementação winrt::event agora lida graciosamente com o caso em que seu método remove é chamado com um valor de token inválido (um valor que não está presente na matriz).

As variáveis locais de corrotina são agora destruídas antes que a corrotina retorne

A maneira tradicional de implementar um tipo de co-rotina pode permitir que variáveis locais dentro da co-rotina sejam destruídas após a a co-rotina retornar/completar (em vez de antes da suspensão final). A retomada de qualquer garçom agora é adiada até a suspensão final, a fim de evitar esse problema e acumular outros benefícios.

Notícias e alterações no Windows SDK versão 10.0.17763.0 (Windows 10, versão 1809)

A tabela abaixo contém notícias e alterações para C++/WinRT no SDK do Windows versão 10.0.17763.0 (Windows 10, versão 1809).

Funcionalidade nova ou alterada Mais informações
Quebrando a mudança. Para compilar, o C++/WinRT não depende de cabeçalhos do SDK do Windows. Ver abaixo Isolamento dos ficheiros de cabeçalho do SDK do Windows
O formato do sistema de projeto do Visual Studio foi alterado. Consulte Como redirecionar seu projeto C++/WinRT para uma versão posterior do SDK do Windows, abaixo.
Há novas funções e classes base para ajudá-lo a passar um objeto de coleção para uma função do Tempo de Execução do Windows ou para implementar suas próprias propriedades e tipos de coleção. Consulte coleções com C++/WinRT.
Você pode usar a extensão de marcação {Binding} com as suas classes runtime C++/WinRT. Para obter mais informações e exemplos de código, consulte Visão geral da vinculação de dados.
O suporte para cancelar uma corotina permite registrar um retorno de chamada de cancelamento. Para mais informações e exemplos de código, consulte Cancelamento de uma operação assíncrona e callbacks de cancelamento.
Ao criar um delegado apontando para uma função de membro, você pode estabelecer uma referência forte ou fraca ao objeto atual (em vez de uma bruta esse ponteiro) no ponto em que o manipulador está registrado. Para obter mais informações e exemplos de código, consulte a subseção Se você usar uma função de membro como um delegado na seção Acessando com segurança o esta ponteiro com um delegado de manipulação de eventos.
Foram corrigidos bugs que foram descobertos pela conformidade melhorada do Visual Studio com o padrão C++. A cadeia de ferramentas LLVM e Clang também é melhor aproveitada para validar a conformidade dos padrões C++/WinRT. Você não encontrará mais o problema descrito em Por que meu novo projeto não será compilado? Estou usando o Visual Studio 2017 (versão 15.8.0 ou posterior) e o SDK versão 17134

Outras alterações.

  • Quebrando a mudança. winrt::get_abi(winrt::hstring const&) agora retorna void* em vez de HSTRING. Você pode usar static_cast<HSTRING>(get_abi(my_hstring)); para obter um HSTRING. Veja Interoperando com o HSTRING da ABI.
  • Quebrando a mudança. winrt::put_abi(winrt::hstring&) agora retorna void** em vez de HSTRING*. Você pode usar reinterpret_cast<HSTRING*>(put_abi(my_hstring)); para obter um HSTRING*. Veja Interoperando com o HSTRING da ABI.
  • Quebrando a mudança. HRESULT agora é projetado como winrt::hresult. Se você precisar de um HRESULT (para fazer verificação de tipo, ou para suportar características de tipo), então você pode static_cast um winrt::hresult. Caso contrário, winrt::hresult converte em HRESULT, desde que você inclua unknwn.h antes de incluir qualquer cabeçalho C++/WinRT.
  • Quebrando a mudança. GUID agora é projetado como winrt::guid. Para APIs implementadas, você deve usar winrt::guid para parâmetros GUID. Caso contrário, winrt::guid converte em GUID, desde que você inclua unknwn.h antes de incluir qualquer cabeçalho C++/WinRT. Consulte Interoperando com o GUID structda ABI .
  • Quebrando a mudança. O construtor winrt::handle_type foi endurecido tornando-o explícito (agora é mais difícil escrever código incorreto com ele). Se você precisar atribuir um valor de identificador bruto, chame a função handle_type::attach em vez disso.
  • Quebrando a mudança. As assinaturas de WINRT_CanUnloadNow e WINRT_GetActivationFactory têm mudado. Você não deve de forma alguma declarar essas funções. Em vez disso, inclua winrt/base.h (que é incluído automaticamente se você incluir qualquer arquivo de cabeçalho de namespace do Windows C++/WinRT) para incluir as declarações dessas funções.
  • Para o winrt::clock struct, from_FILETIME/to_FILETIME são preteridos em favor de from_file_time/to_file_time.
  • APIs simplificadas que esperam parâmetros IBuffer. A maioria das APIs prefere coleções ou matrizes. Mas sentimos que deveríamos tornar mais fácil chamar APIs que dependem do IBuffer. Esta atualização fornece acesso direto aos dados por trás de uma implementação do IBuffer . Ele usa a mesma convenção de nomenclatura de dados usada pelos contêineres da Biblioteca Padrão C++. Essa convenção também evita colisões com nomes de metadados que convencionalmente começam com uma letra maiúscula.
  • Geração de código aprimorada: várias melhorias para reduzir o tamanho do código, melhorar o inlining e otimizar o cache de fábrica.
  • Removida a recursão desnecessária. Quando a linha de comando se refere a uma pasta em vez de um .winmd específico, a ferramenta cppwinrt.exe deixa de pesquisar arquivos .winmd de forma recursiva. A cppwinrt.exe ferramenta agora também lida com duplicatas de forma mais inteligente, tornando-a mais resiliente a erros do usuário e a arquivos mal formados .winmd .
  • Ponteiros inteligentes reforçados. Anteriormente, os revogadores de eventos não conseguiam revogar quando moviam um novo valor. Isso ajudou a descobrir um problema em que as classes de ponteiro inteligentes não estavam a lidar de forma confiável com a autoatribuição, o qual estava enraizado no modelo de estrutura winrt::com_ptr . winrt::com_ptr foi corrigido e os revogadores de eventos foram ajustados para manipular corretamente a semântica de movimento, permitindo que sejam revogados após a atribuição.

Importante

Alterações importantes foram feitas no C++/WinRT Visual Studio Extension (VSIX), tanto na versão 1.0.181002.2 quanto posteriormente na versão 1.0.190128.4. Para obter detalhes dessas alterações e como elas afetam seus projetos existentes, suporte do Visual Studio para C++/WinRT e versões anteriores da extensão VSIX.

Isolamento dos arquivos de cabeçalho do SDK do Windows

Esta é potencialmente uma alteração significativa para o seu código.

Para compilar, o C++/WinRT não depende mais de arquivos de cabeçalho do SDK do Windows. Os arquivos de cabeçalho na CRT (biblioteca de tempo de execução) C e na STL (C++ Standard Template Library) também não incluem cabeçalhos do SDK do Windows. E isso melhora a conformidade com os padrões, evita dependências inadvertidas e reduz consideravelmente o número de macros contra as quais você precisa se proteger.

Essa independência significa que o C++/WinRT agora é mais portátil e compatível com os padrões, além de aumentar a possibilidade de se tornar uma biblioteca multicompilador e multiplataforma. Isso também significa que as macros não afetam negativamente os cabeçalhos C++/WinRT.

Se anteriormente deixaste que o C++/WinRT incluísse os cabeçalhos do Windows no teu projeto, agora terás de incluí-los tu mesmo. Em qualquer caso, é sempre uma boa prática incluir explicitamente os cabeçalhos dos quais você depende e não deixar para outra biblioteca incluí-los para você.

Atualmente, as únicas exceções ao isolamento do arquivo de cabeçalho do SDK do Windows são para intrínsecos e numéricos. Não há problemas conhecidos com essas últimas dependências restantes.

Em seu projeto, você pode reativar a interoperabilidade com os cabeçalhos do SDK do Windows, se necessário. Você pode, por exemplo, querer implementar uma interface COM (enraizada em IUnknown). Para esse exemplo, inclua unknwn.h antes de incluir qualquer cabeçalho C++/WinRT. Isso faz com que a biblioteca base C++/WinRT habilite vários ganchos para oferecer suporte a interfaces COM clássicas. Para obter um exemplo de código, consulte Criar componentes COM com C++/WinRT. Da mesma forma, inclua explicitamente quaisquer outros cabeçalhos do SDK do Windows que declarem tipos e/ou funções que você deseja chamar.

Como redirecionar seu projeto C++/WinRT para uma versão posterior do SDK do Windows

O método para redirecionar seu projeto que provavelmente resultará no menor problema de compilador e vinculador também é o mais trabalhoso. Esse método envolve a criação de um novo projeto (visando a versão do SDK do Windows de sua escolha) e, em seguida, a cópia de arquivos para o novo projeto do antigo. Existirão secções dos seus arquivos antigos .vcxproj e .vcxproj.filters que poderá simplesmente transferir para evitar ter de adicionar arquivos no Visual Studio.

No entanto, há duas outras maneiras de redirecionar seu projeto no Visual Studio.

  • Vá para a propriedade do projeto Geral>Versão do Windows SDKe selecione Todas as Configurações e Todas as Plataformas. Defina Versão do SDK do Windows para a versão que você deseja segmentar.
  • No Gerenciador de Soluções, clique com o botão direito do mouse no nó do projeto, clique em Redirecionar Projetos, escolha a(s) versão(ões) que deseja direcionar e clique em OK.

Se você encontrar algum erro de compilador ou vinculador depois de usar qualquer um desses dois métodos, tente limpar a solução (Build>Clean Solution e/ou excluir manualmente todas as pastas e arquivos temporários) antes de tentar compilar novamente.

Se o compilador C++ produzir o "erroC2039: 'IUnknown': não é um membro de '`global namespace''", então adicione #include <unknwn.h> à parte superior do arquivo pch.h (antes de incluir qualquer cabeçalho C++/WinRT).

Você também pode precisar adicionar #include <hstring.h> depois disso.

Se o vinculador C++ produzir "erro LNK2019: símbolo externo não resolvido _WINRT_CanUnloadNow@0 referenciado na função _VSDesignerCanUnloadNow@0", então você pode resolver isso adicionando #define _VSDESIGNER_DONT_LOAD_AS_DLL ao seu arquivo pch.h.