Utilizar APIs com C++/WinRTConsume APIs with C++/WinRT

Este tópico mostra como utilizar as APIs do C++/WinRT, sejam elas parte do Windows, implementadas por um fornecedor de componentes de terceiros, ou implementada por você mesmo.This topic shows how to consume C++/WinRT APIs, whether they're part of Windows, implemented by a third-party component vendor, or implemented by yourself.

Se a API estiver em um namespace do WindowsIf the API is in a Windows namespace

Esse é o caso mais comum de utilização de uma API do Windows Runtime.This is the most common case in which you'll consume a Windows Runtime API. Para cada tipo em um namespace do Windows definido nos metadados, C ++/WinRT define um equivalente C++ amigável (chamado de tipo projetado).For every type in a Windows namespace defined in metadata, C++/WinRT defines a C++-friendly equivalent (called the projected type). Um tipo projetado tem o mesmo nome totalmente qualificado do tipo do Windows, mas é colocado no namespace C++ winrt usando a sintaxe do C++.A projected type has the same fully-qualified name as the Windows type, but it's placed in the C++ winrt namespace using C++ syntax. Por exemplo, Windows::Foundation::Uri é projetado no C++/WinRT como winrt::Windows::Foundation::Uri.For example, Windows::Foundation::Uri is projected into C++/WinRT as winrt::Windows::Foundation::Uri.

A seguir apresentamos um exemplo de código simples.Here's a simple code example. Se quiser copiar e colar os exemplos de código a seguir diretamente no arquivo de código-fonte principal de um projeto de Aplicativo de Console do Windows (C++/WinRT) , primeiro defina Não usar Cabeçalhos Pré-compilados nas propriedades do projeto.If you want to copy-paste the following code examples directly into the main source code file of a Windows Console Application (C++/WinRT) project, then first set Not Using Precompiled Headers in project properties.

// main.cpp
#include <winrt/Windows.Foundation.h>

using namespace winrt;
using namespace Windows::Foundation;

int main()
{
    winrt::init_apartment();
    Uri contosoUri{ L"http://www.contoso.com" };
    Uri combinedUri = contosoUri.CombineUri(L"products");
}

O cabeçalho winrt/Windows.Foundation.h incluído faz parte do SDK, e pode ser encontrado dentro da pasta %WindowsSdkDir%Include<WindowsTargetPlatformVersion>\cppwinrt\winrt\.The included header winrt/Windows.Foundation.h is part of the SDK, found inside the folder %WindowsSdkDir%Include<WindowsTargetPlatformVersion>\cppwinrt\winrt\. Os cabeçalhos nessa pasta contêm tipos de namespace do Windows projetados em C++/WinRT.The headers in that folder contain Windows namespace types projected into C++/WinRT. Neste exemplo, winrt/Windows.Foundation.h contém winrt::Windows::Foundation::Uri, que é o tipo projetado para a classe de runtime Windows::Foundation::Uri.In this example, winrt/Windows.Foundation.h contains winrt::Windows::Foundation::Uri, which is the projected type for the runtime class Windows::Foundation::Uri.

Dica

Sempre que desejar usar um tipo de namespace do Windows, inclua o cabeçalho do C++/WinRT correspondente a esse namespace.Whenever you want to use a type from a Windows namespace, include the C++/WinRT header corresponding to that namespace. As diretivas using namespace são opcionais, mas convenientes.The using namespace directives are optional, but convenient.

No exemplo de código acima, após iniciar o C++/WinRT, alocamos em pilhas um valor do tipo projetado winrt::Windows::Foundation::Uri por meio de um de seus construtores documentados publicamente (Uri(String) , neste exemplo).In the code example above, after initializing C++/WinRT, we stack-allocate a value of the winrt::Windows::Foundation::Uri projected type via one of its publicly documented constructors (Uri(String), in this example). Este é o caso de uso mais comum, e normalmente é tudo o que você precisa fazer.For this, the most common use case, that's typically all you have to do. Quando tiver um valor de tipo projetado do C++/WinRT, é possível tratá-lo como se fosse uma instância do tipo real do Windows Runtime, pois já tem todos os mesmos membros.Once you have a C++/WinRT projected type value, you can treat it as if it were an instance of the actual Windows Runtime type, since it has all the same members.

Na verdade, esse valor projetado é um proxy; essencialmente, é apenas um ponteiro inteligente de um objeto existente.In fact, that projected value is a proxy; it's essentially just a smart pointer to a backing object. A chamada de construtores do valor projetado RoActivateInstance para criar uma instância da classe existente do Windows Runtime (Windows.Foundation.Uri, neste caso) e armazenar a interface padrão do objeto no novo valor projetado.The projected value's constructor(s) call RoActivateInstance to create an instance of the backing Windows Runtime class (Windows.Foundation.Uri, in this case), and store that object's default interface inside the new projected value. Como mostrado abaixo, suas chamadas para os membros do valor projetado na verdade delegam, por meio do ponteiro inteligente, para o objeto existente, que é onde ocorrem alterações de estado.As illustrated below, your calls to the projected value's members actually delegate, via the smart pointer, to the backing object; which is where state changes occur.

O tipo projetado Windows::Foundation::Uri

Quando o valor contosoUri não está mais no escopo, ele destrói e libera a referência à interface padrão.When the contosoUri value falls out of scope, it destructs, and releases its reference to the default interface. Se essa é a última referência ao objeto existente Windows.Foundation.Uri do Windows Runtime, o objeto existente também é destruído.If that reference is the last reference to the backing Windows Runtime Windows.Foundation.Uri object, the backing object destructs as well.

Dica

Um tipo projetado é um wrapper ao longo de uma classe de runtime para utilizar suas APIs.A projected type is a wrapper over a runtime class for purposes of consuming its APIs. Uma interface projetada é um wrapper sobre uma interface do Windows Runtime.A projected interface is a wrapper over a Windows Runtime interface.

Cabeçalhos de projeção do C++/WinRTC++/WinRT projection headers

Para utilizar APIs de namespace do Windows a partir do C++/WinRT, é preciso incluir os cabeçalhos da pasta %WindowsSdkDir%Include<WindowsTargetPlatformVersion>\cppwinrt\winrt.To consume Windows namespace APIs from C++/WinRT, you include headers from the %WindowsSdkDir%Include<WindowsTargetPlatformVersion>\cppwinrt\winrt folder. É comum que um tipo em um namespace subordinado faça referência aos tipos no namespace pai imediato.It's common for a type in a subordinate namespace to reference types in its immediate parent namespace. Consequentemente, cada cabeçalho de projeção do C++/WinRT inclui automaticamente o arquivo de cabeçalho do namespace pai para que você não precise incluí-lo explicitamente.Consequently, each C++/WinRT projection header automatically includes its parent namespace header file; so you don't need to explicitly include it. No entanto, se você fizer isso, não haverá nenhum erro.Although, if you do, there will be no error.

Por exemplo, para o namespace Windows::Security::Cryptography::Certificates, as definições de tipo do C++/WinRT equivalentes estão em winrt/Windows.Security.Cryptography.Certificates.h.For example, for the Windows::Security::Cryptography::Certificates namespace, the equivalent C++/WinRT type definitions reside in winrt/Windows.Security.Cryptography.Certificates.h. Os tipos em Windows::Security::Cryptography::Certificates exigem tipos no namespace pai Windows::Security::Cryptography e os tipos nesse namespace podem exigir tipos no próprio pai, Windows::Security.Types in Windows::Security::Cryptography::Certificates require types in the parent Windows::Security::Cryptography namespace; and types in that namespace could require types in its own parent, Windows::Security.

Então, ao incluir winrt/Windows.Security.Cryptography.Certificates.h, esse arquivo inclui winrt/Windows.Security.Cryptography.h; e winrt/Windows.Security.Cryptography.h inclui winrt/Windows.Security.h.So, when you include winrt/Windows.Security.Cryptography.Certificates.h, that file in turn includes winrt/Windows.Security.Cryptography.h; and winrt/Windows.Security.Cryptography.h includes winrt/Windows.Security.h. E é aqui que a trilha acaba, pois não há um winrt/Windows.h.That's where the trail stops, since there is no winrt/Windows.h. Esse processo de inclusão transitiva para no namespace de segundo nível.This transitive inclusion process stops at the second-level namespace.

Esse processo inclui transitivamente os arquivos de cabeçalho que fornecem as declarações e implementações necessárias para as classes definidas nos namespaces pai.This process transitively includes the header files that provide the necessary declarations and implementations for the classes defined in parent namespaces.

Um membro de um tipo em um namespace pode fazer referência a um ou mais tipos de outros namespaces não relacionados.A member of a type in one namespace can reference one or more types in other, unrelated, namespaces. Para que o compilador faça a compilação dessa definições de membros, deve ver as declarações de tipo para o fechamento de todos esses tipos.In order for the compiler to compile these member definitions successfully, the compiler needs to see the type declarations for the closure of all these types. Consequentemente, cada cabeçalho de projeção do C++/WinRT inclui os cabeçalhos de namespace necessários para declarar quaisquer tipos dependentes.Consequently, each C++/WinRT projection header includes the namespace headers it needs to declare any dependent types. Ao contrário do namespaces pai, esse processo não usa as implementações para tipos mencionados.Unlike for parent namespaces, this process does not pull in the implementations for referenced types.

Importante

Quando você realmente deseja usar um tipo (instanciar, chamar métodos, etc.) declarado em um namespace não relacionado, deve incluir o arquivo de cabeçalho de namespace apropriado para o tipo.When you want to actually use a type (instantiate, call methods, etc.) declared in an unrelated namespace, you must include the appropriate namespace header file for that type. Somente declarações, e não implementações, são incluídas automaticamente.Only declarations, not implementations, are automatically included.

Por exemplo, se você incluir somente winrt/Windows.Security.Cryptography.Certificates.h, isso fará com que as declarações sejam obtidas desses namespaces (e assim por diante, transitivamente).For example, if you only include winrt/Windows.Security.Cryptography.Certificates.h, then that causes declarations to be pulled in from these namespaces (and so on, transitively).

  • Windows.FoundationWindows.Foundation
  • Windows.Foundation.CollectionsWindows.Foundation.Collections
  • Windows.NetworkingWindows.Networking
  • Windows.Storage.StreamsWindows.Storage.Streams
  • Windows.Security.CryptographyWindows.Security.Cryptography

Ou seja, algumas APIs têm encaminhamento declarado em um cabeçalho que você incluiu.In other words, some APIs are forward-declared in a header that you've included. Entretanto, suas definições estão em um cabeçalho ainda não incluído.But their definitions are in a header that you haven't yet included. Portanto, ao chamar Windows::Foundation::Uri::RawUri, você receberá um erro de vinculador indicando que o membro não está definido.So, if you then call Windows::Foundation::Uri::RawUri, then you'll receive a linker error indicating that the member is undefined. A solução é usar #include <winrt/Windows.Foundation.h> explicitamente.The solution is to explicitly #include <winrt/Windows.Foundation.h>. Em geral, ao ver um erro de vinculador assim, inclua o cabeçalho nomeado para o namespace da API e recompile.In general, when you see a linker error such as this, include the header named for the API's namespace, and rebuild.

Acessar membros pelo objeto, por uma interface ou pela ABIAccessing members via the object, via an interface, or via the ABI

Com a projeção do C++/WinRT, a representação do tempo de execução de uma classe do Windows Runtime é somente uma interface ABI subjacente.With the C++/WinRT projection, the runtime representation of a Windows Runtime class is no more than the underlying ABI interfaces. No entanto, para sua conveniência, é possível codificar em relação às classes da maneira que o autor pretendia.But, for your convenience, you can code against classes in the way that their author intended. Por exemplo, chame o método ToString de um Uri como se fosse um método da classe (na verdade, por baixo dos panos, é um método na interface IStringable separada).For example, you can call the ToString method of a Uri as if that were a method of the class (in fact, under the covers, it's a method on the separate IStringable interface).

WINRT_ASSERT é uma definição de macro e se expande para _ASSERTE.WINRT_ASSERT is a macro definition, and it expands to _ASSERTE.

Uri contosoUri{ L"http://www.contoso.com" };
WINRT_ASSERT(contosoUri.ToString() == L"http://www.contoso.com/"); // QueryInterface is called at this point.

Essa conveniência é obtida por meio de uma consulta na interface apropriada.This convenience is achieved via a query for the appropriate interface. Entretanto, você está sempre no controle.But you're always in control. É possível optar por trocar um pouco dessa conveniência por desempenho ao recuperar a interface IStringable por conta própria e usando-a diretamente.You can opt to give away a little of that convenience for a little performance by retrieving the IStringable interface yourself and using it directly. No exemplo de código abaixo, obtém-se um ponteiro de interface IStringable real no tempo de execução (por meio de uma consulta única).In the code example below, you obtain an actual IStringable interface pointer at run time (via a one-time query). Depois disso, a chamada para ToString é direta e evita qualquer chamada para QueryInterface.After that, your call to ToString is direct, and avoids any further call to QueryInterface.

...
IStringable stringable = contosoUri; // One-off QueryInterface.
WINRT_ASSERT(stringable.ToString() == L"http://www.contoso.com/");

Escolha essa técnica se souber que chamará vários métodos na mesma interface.You might choose this technique if you know you'll be calling several methods on the same interface.

A propósito, é possível acessar membros no nível da ABI, se quiser.Incidentally, if you do want to access members at the ABI level then you can. O exemplo de código abaixo mostra como fazer isso, e é possível saber mais e obter exemplos de código em Interoperabilidade entre C++/WinRT e ABI.The code example below shows how, and there are more details and code examples in Interop between C++/WinRT and the ABI.

#include <Windows.Foundation.h>
#include <unknwn.h>
#include <winrt/Windows.Foundation.h>
using namespace winrt::Windows::Foundation;

int main()
{
    winrt::init_apartment();
    Uri contosoUri{ L"http://www.contoso.com" };

    int port{ contosoUri.Port() }; // Access the Port "property" accessor via C++/WinRT.

    winrt::com_ptr<ABI::Windows::Foundation::IUriRuntimeClass> abiUri{
        contosoUri.as<ABI::Windows::Foundation::IUriRuntimeClass>() };
    HRESULT hr = abiUri->get_Port(&port); // Access the get_Port ABI function.
}

Inicialização atrasadaDelayed initialization

No C++/WinRT, cada tipo projetado tem um construtor std::nullptr_t especial do C++/WinRT.In C++/WinRT, each projected type has a special C++/WinRT std::nullptr_t constructor. Com exceção desse, todos os construtores de tipo projetado—incluindo o construtor padrão—fazem com que um objeto de suporte do Windows Runtime seja criado e fornecem um ponteiro inteligente para ele.With the exception of that one, all projected-type constructors—including the default constructor—cause a backing Windows Runtime object to be created, and give you a smart pointer to it. Portanto, essa regra se aplica em qualquer lugar em que o construtor padrão é usado, como variáveis locais não inicializadas, variáveis globais não inicializadas e variáveis de membro não inicializadas.So, that rule applies anywhere that the default constructor is used, such as uninitialized local variables, uninitialized global variables, and uninitialized member variables.

Se, por outro lado, você desejar construir uma variável de um tipo projetado sem construir um objeto do Windows Runtime (para atrasar esse trabalho até um momento posterior), poderá fazer isso.If, on the other hand, you want to construct a variable of a projected type without it in turn constructing a backing Windows Runtime object (so that you can delay that work until later), then you can do that. Declare a variável ou o campo usando o construtor std::nullptr_t especial do C++/WinRT (que a projeção do C++/WinRT injeta em toda classe de runtime).Declare your variable or field using that special C++/WinRT std::nullptr_t constructor (which the C++/WinRT projection injects into every runtime class). Usamos esse construtor especial com m_gamerPicBuffer no exemplo de código abaixo.We use that special constructor with m_gamerPicBuffer in the code example below.

#include <winrt/Windows.Storage.Streams.h>
using namespace winrt::Windows::Storage::Streams;

#define MAX_IMAGE_SIZE 1024

struct Sample
{
    void DelayedInit()
    {
        // Allocate the actual buffer.
        m_gamerPicBuffer = Buffer(MAX_IMAGE_SIZE);
    }

private:
    Buffer m_gamerPicBuffer{ nullptr };
};

int main()
{
    winrt::init_apartment();
    Sample s;
    // ...
    s.DelayedInit();
}

Todos os construtores no tipo projetado, exceto pelo construtor std::nullptr_t, resultam na criação do objeto existente do Windows Runtime.All constructors on the projected type except the std::nullptr_t constructor cause a backing Windows Runtime object to be created. O construtor std::nullptr_t é, essencialmente, inoperante.The std::nullptr_t constructor is essentially a no-op. Ele espera que o objeto projetado seja iniciado posteriormente.It expects the projected object to be initialized at a subsequent time. Portanto, se uma classe de runtime tem ou não um construtor padrão, use essa técnica para uma inicialização atrasada eficiente.So, whether a runtime class has a default constructor or not, you can use this technique for efficient delayed initialization.

Essa consideração afeta outros lugares em que se chama o construtor padrão, como em vetores e mapas.This consideration affects other places where you're invoking the default constructor, such as in vectors and maps. Considere este exemplo de código, para o qual será necessário um projeto Aplicativo em Branco (C++/WinRT) .Consider this code example, for which you'll need a Blank App (C++/WinRT) project.

std::map<int, TextBlock> lookup;
lookup[2] = value;

A atribuição cria um novo TextBlock e o substitui imediatamente por value.The assignment creates a new TextBlock, and then immediately overwrites it with value. A solução é a seguinte.Here's the remedy.

std::map<int, TextBlock> lookup;
lookup.insert_or_assign(2, value);

Confira também Como o construtor padrão afeta as coleções.Also see How the default constructor affects collections.

Não inicializar com atraso por enganoDon't delay-initialize by mistake

Tenha cuidado para não invocar o construtor std::nullptr_t por engano.Be careful that you don't invoke the std::nullptr_t constructor by mistake. A resolução de conflitos do compilador o favorece em detrimento dos construtores de fábrica.The compiler's conflict resolution favors it over the factory constructors. Por exemplo, considere estas duas definições de classe de runtime.For example, consider these two runtime class definitions.

// GiftBox.idl
runtimeclass GiftBox
{
    GiftBox();
}

// Gift.idl
runtimeclass Gift
{
    Gift(GiftBox giftBox); // You can create a gift inside a box.
}

Digamos que queremos construir um Gift que não está dentro de uma caixa (um Gift construído com um GiftBox não inicializado).Let's say that we want to construct a Gift that isn't inside a box (a Gift that's constructed with an uninitialized GiftBox). Primeiro, vamos ver a maneira errada de fazer isso.First, let's look at the wrong way to do that. Sabemos que há um construtor Gift que usa um GiftBox.We know that there'a Gift constructor that takes a GiftBox. Mas, se estivermos tentados a passar um GiftBox nulo (invocando o construtor Gift por meio da inicialização uniforme, como fazemos abaixo), não teremos o resultado desejado.But if we're tempted to pass a null GiftBox (invoking the Gift constructor via uniform initialization, as we do below), then we won't get the result we want.

// These are *not* what you intended. Doing it in one of these two ways
// actually *doesn't* create the intended backing Windows Runtime Gift object;
// only an empty smart pointer.

Gift gift{ nullptr };
auto gift{ Gift(nullptr) };

O que você terá aqui é um Gift não inicializado.What you get here is an uninitialized Gift. Você não recebe um Gift com um GiftBox não inicializado.You don't get a Gift with an uninitialized GiftBox. Esta é a forma correta de fazer isso.Here's the correct way to do that.

// Doing it in one of these two ways creates an initialized
// Gift with an uninitialized GiftBox.

Gift gift{ GiftBox{ nullptr } };
auto gift{ Gift(GiftBox{ nullptr }) };

No exemplo incorreto, passar um literal nullptr resolve em favor do construtor de inicialização com atraso.In the incorrect example, passing a nullptr literal resolves in favor of the delay-initializing constructor. Para resolver em favor do construtor de fábrica, o tipo do parâmetro deve ser GiftBox.To resolve in favor of the factory constructor, the type of the parameter must be a GiftBox. Você ainda terá a opção de passar explicitamente um GiftBox com inicialização com atraso, conforme mostrado no exemplo correto.You still have the option to pass an explicitly delay-initializing GiftBox, as shown in the correct example.

O exemplo a seguir também está correto, pois o parâmetro tem o tipo GiftBox e não std::nullptr_t.This next example is also correct, because the parameter has type GiftBox, and not std::nullptr_t.

GiftBox giftBox{ nullptr };
Gift gift{ giftBox }; // Calls factory constructor.

A ambiguidade surge apenas quando você passa um literal nullptr.It's only when you pass a nullptr literal that the ambiguity arises.

Não construir por cópia por engano.Don't copy-construct by mistake.

Este aviso é semelhante ao descrito na seção Não inicializar com atraso por engano acima.This caution is similar to the one described in the Don't delay-initialize by mistake section above.

Além do construtor de inicialização com atraso, a projeção de C++/WinRT também injeta um construtor de cópia em cada classe de runtime.In addition to the delay-initializing constructor, the C++/WinRT projection also injects a copy constructor into every runtime class. Trata-se de um construtor de parâmetro único que aceita o mesmo tipo que o objeto que está sendo construído.It's a single-parameter constructor that accepts the same type as the object being constructed. Os ponteiro inteligente resultante aponta para o mesmo objeto do Windows Runtime que é apontado pelo seu parâmetro de construtor.The resulting smart pointer points to the same backing Windows Runtime object as that pointed to by its constructor parameter. O resultado são dois objetos de ponteiro inteligente apontando para o mesmo objeto.The result is two smart pointer objects pointing to the same backing object.

Esta é uma definição de classe de runtime que usaremos nos exemplos de código.Here's a runtime class definition that we'll use in the code examples.

// GiftBox.idl
runtimeclass GiftBox
{
    GiftBox(GiftBox biggerBox); // You can place a box inside a bigger box.
}

Vamos supor que queremos construir um GiftBox dentro de um GiftBox maior.Let's say that we want to construct a GiftBox inside a larger GiftBox.

GiftBox bigBox{ ... };

// These are *not* what you intended. Doing it in one of these two ways
// copies bigBox's backing-object-pointer into smallBox.
// The result is that smallBox == bigBox.

GiftBox smallBox{ bigBox };
auto smallBox{ GiftBox(bigBox) };

A forma correta de fazer isso é chamar a fábrica de ativação explicitamente.The correct way to do it is to call the activation factory explicitly.

GiftBox bigBox{ ... };

// These two ways call the activation factory explicitly.

GiftBox smallBox{
    winrt::get_activation_factory<GiftBox, IGiftBoxFactory>().CreateInstance(bigBox) };
auto smallBox{
    winrt::get_activation_factory<GiftBox, IGiftBoxFactory>().CreateInstance(bigBox) };

Se a API é implementada em um componente do Windows RuntimeIf the API is implemented in a Windows Runtime component

Esta seção se aplica se você criou o componente por conta própria ou se ele veio por meio de um fornecedor.This section applies whether you authored the component yourself, or it came from a vendor.

Observação

Para obter informações sobre como instalar e usar o C++/WinRT Visual Studio Extension (VSIX) e o pacote NuGet (que juntos fornecem um modelo de projeto e suporte ao build), confira as informações de suporte do Visual Studio para C++/WinRT.For info about installing and using the C++/WinRT Visual Studio Extension (VSIX) and the NuGet package (which together provide project template and build support), see Visual Studio support for C++/WinRT.

No seu projeto de aplicativo, faça referência ao arquivo de metadados do Windows Runtime do componente do Windows Runtime (.winmd) e compile.In your application project, reference the Windows Runtime component's Windows Runtime metadata (.winmd) file, and build. Durante a compilação, a ferramenta cppwinrt.exe gera uma biblioteca C++ padrão que descreve completamente, ou projeta, a superfície de API do componente.During the build, the cppwinrt.exe tool generates a standard C++ library that fully describes—or projects—the API surface for the component. Em outras palavras, a biblioteca gerada contém os tipos projetados para o componente.In other words, the generated library contains the projected types for the component.

Em seguida, assim como acontece com um tipo de namespace do Windows, inclua um cabeçalho e construa o tipo projetado por meio de um de seus construtores.Then, just as for a Windows namespace type, you include a header and construct the projected type via one of its constructors. O código de inicialização do seu projeto de aplicativo registra a classe de runtime, e o construtor do tipo projetado chama RoActivateInstance para ativar a classe de runtime do componente mencionado.Your application project's startup code registers the runtime class, and the projected type's constructor calls RoActivateInstance to activate the runtime class from the referenced component.

#include <winrt/ThermometerWRC.h>

struct App : implements<App, IFrameworkViewSource, IFrameworkView>
{
    ThermometerWRC::Thermometer thermometer;
    ...
};

Para saber mais, obter códigos e ver um passo a passo do consumo de APIs implementadas em um componente do Windows Runtime, confira Componentes do Windows Runtime com C++/WinRT e Criar eventos em C++/WinRT.For more details, code, and a walkthrough of consuming APIs implemented in a Windows Runtime component, see Windows Runtime components with C++/WinRT and Author events in C++/WinRT.

Se a API é implementada no projeto utilizadoIf the API is implemented in the consuming project

O exemplo de código nesta seção é extraído do tópico Controles XAML; fazer a associação com uma propriedade C++/WinRT.The code example in this section is taken from the topic XAML controls; bind to a C++/WinRT property. Confira esse tópico para obter mais detalhes, código e um guia passo a passo de como consumir uma classe de runtime implementada no mesmo projeto que a consome.See that topic for more details, code, and a walkthrough of consuming a runtime class that's implemented in the same project that consumes it.

Um tipo utilizado a partir da interface de usuário do XAML deve ser uma classe de runtime, mesmo que esteja no mesmo projeto do XAML.A type that's consumed from XAML UI must be a runtime class, even if it's in the same project as the XAML. Para esse cenário, gere um tipo projetado a partir de metadados do Windows Runtime da classe de tempo de execução (.winmd).For this scenario, you generate a projected type from the runtime class's Windows Runtime metadata (.winmd). Novamente, você incluirá um cabeçalho, mas terá uma opção entre as maneiras do C++/WinRT versão 1.0 ou 2.0 de construir a instância da classe de runtime.Again, you include a header, but then you have a choice between the C++/WinRT version 1.0 or version 2.0 ways of constructing the instance of the runtime class. O método da versão 1.0 usa winrt::make; o método da versão 2.0 é conhecido como construção uniforme.The version 1.0 method uses winrt::make; the version 2.0 method is known as uniform construction. Vamos examinar cada um deles separadamente.Let's look at each in turn.

Como construir usando winrt::makeConstructing by using winrt::make

Vamos começar com o método padrão (C++/WinRT versão 1.0), pois é uma boa ideia ter, pelo menos, familiaridade com esse padrão.Let's start with the default (C++/WinRT version 1.0) method, because it's a good idea to be at least familiar with that pattern. Construa o tipo projetado por meio do construtor std::nullptr_t.You construct the projected type via its std::nullptr_t constructor. Esse construtor não realiza qualquer inicialização, portanto, em seguida é preciso atribuir um valor para a instância por meio da função auxiliar winrt::make, passando quaisquer argumentos de construtor necessários.That constructor doesn't perform any initialization, so you must next assign a value to the instance via the winrt::make helper function, passing any necessary constructor arguments. Uma classe de tempo de execução implementada no mesmo projeto que o código utilizado não precisa ser registrada, nem instanciada por meio de ativação do Windows Runtime/COM.A runtime class implemented in the same project as the consuming code doesn't need to be registered, nor instantiated via Windows Runtime/COM activation.

Para obter um guia passo a passo completo, confira Controles XAML; fazer a associação com uma propriedade C++/WinRT.See XAML controls; bind to a C++/WinRT property for a full walkthrough. Esta seção mostra os extratos desse guia passo a passo.This section shows extracts from that walkthrough.

// MainPage.idl
import "BookstoreViewModel.idl";
namespace Bookstore
{
    runtimeclass MainPage : Windows.UI.Xaml.Controls.Page
    {
        BookstoreViewModel MainViewModel{ get; };
    }
}

// MainPage.h
...
struct MainPage : MainPageT<MainPage>
{
    ...
    private:
        Bookstore::BookstoreViewModel m_mainViewModel{ nullptr };
};
...

// MainPage.cpp
...
#include "BookstoreViewModel.h"

MainPage::MainPage()
{
    m_mainViewModel = winrt::make<Bookstore::implementation::BookstoreViewModel>();
    ...
}

Construção uniformeUniform construction

Com o C++/WinRT versão 2.0 e posterior, há uma forma de construção otimizada disponível para você, conhecida como construção uniforme (confira Novidades e alterações em C++ /WinRT 2.0).With C++/WinRT version 2.0 and later, there's an optimized form of construction available to you known as uniform construction (see News, and changes, in C++/WinRT 2.0).

Para obter um guia passo a passo completo, confira Controles XAML; fazer a associação com uma propriedade C++/WinRT.See XAML controls; bind to a C++/WinRT property for a full walkthrough. Esta seção mostra os extratos desse guia passo a passo.This section shows extracts from that walkthrough.

Para usar a construção uniforme em vez de winrt::make, você precisará de uma fábrica de ativação.To use uniform construction instead of winrt::make, you'll need an activation factory. Uma boa maneira de gerar uma é adicionar um construtor à sua IDL.A good way to generate one is to add a constructor to your IDL.

// MainPage.idl
import "BookstoreViewModel.idl";
namespace Bookstore
{
    runtimeclass MainPage : Windows.UI.Xaml.Controls.Page
    {
        MainPage();
        BookstoreViewModel MainViewModel{ get; };
    }
}

Em seguida, em MainPage.h, declare e inicialize m_mainViewModel em apenas uma etapa, conforme mostrado abaixo.Then, in MainPage.h declare and initialize m_mainViewModel in just one step, as shown below.

// MainPage.h
...
struct MainPage : MainPageT<MainPage>
{
    ...
    private:
        Bookstore::BookstoreViewModel m_mainViewModel;
        ...
    };
}
...

E, em seguida, no construtor MainPage no MainPage.cpp, não há necessidade do código m_mainViewModel = winrt::make<Bookstore::implementation::BookstoreViewModel>();.And then, in the MainPage constructor in MainPage.cpp, there's no need for the code m_mainViewModel = winrt::make<Bookstore::implementation::BookstoreViewModel>();.

Para obter mais informações sobre a construção uniforme, confira Aceitar a construção uniforme e o acesso direto de implementação.For more info about uniform construction, and code examples, see Opt in to uniform construction, and direct implementation access.

Instanciar e retornar tipos e interfaces projetadosInstantiating and returning projected types and interfaces

Veja um exemplo da aparência dos tipos projetados e interfaces ao utilizar seu projeto.Here's an example of what projected types and interfaces might look like in your consuming project. Lembre-se de que um tipo projetado (como o deste exemplo), é gerado por ferramenta e não é algo que você pode criar por conta própria.Remember that a projected type (such as the one in this example), is tool-generated, and is not something that you'd author yourself.

struct MyRuntimeClass : MyProject::IMyRuntimeClass, impl::require<MyRuntimeClass,
    Windows::Foundation::IStringable, Windows::Foundation::IClosable>

MyRuntimeClass é um tipo projetado; as interfaces projetadas incluem IMyRuntimeClass, IStringable e IClosable.MyRuntimeClass is a projected type; projected interfaces include IMyRuntimeClass, IStringable, and IClosable. Este tópico mostra as diferentes maneiras de como instanciar um tipo projetado.This topic has shown the different ways in which you can instantiate a projected type. Este é um lembrete e um resumo, usando MyRuntimeClass como exemplo.Here's a reminder and summary, using MyRuntimeClass as an example.

// The runtime class is implemented in another compilation unit (it's either a Windows API,
// or it's implemented in a second- or third-party component).
MyProject::MyRuntimeClass myrc1;

// The runtime class is implemented in the same compilation unit.
MyProject::MyRuntimeClass myrc2{ nullptr };
myrc2 = winrt::make<MyProject::implementation::MyRuntimeClass>();
  • É possível acessar os membros de todas as interfaces de um tipo projetado.You can access the members of all of the interfaces of a projected type.
  • E retornar um tipo projetado para um chamador.You can return a projected type to a caller.
  • Tipos projetados e interfaces derivam de winrt::Windows::Foundation::IUnknown.Projected types and interfaces derive from winrt::Windows::Foundation::IUnknown. Assim, chame IUnknown::as em um tipo projetado ou interface para consultar outras interfaces projetadas, que também podem ser usadas ou retornadas para um chamador.So, you can call IUnknown::as on a projected type or interface to query for other projected interfaces, which you can also either use or return to a caller. A função de membro as funciona como QueryInterface.The as member function works like QueryInterface.
void f(MyProject::MyRuntimeClass const& myrc)
{
    myrc.ToString();
    myrc.Close();
    IClosable iclosable = myrc.as<IClosable>();
    iclosable.Close();
}

Alocadores de ativaçãoActivation factories

A maneira conveniente e direta de criar um objeto de C++/WinRT é a seguinte.The convenient, direct way to create a C++/WinRT object is as follows.

using namespace winrt::Windows::Globalization::NumberFormatting;
...
CurrencyFormatter currency{ L"USD" };

Pode haver momentos em que se deseja criar o alocador de ativação por conta própria e, em seguida, criar objetos a partir dele para sua conveniência.But there may be times that you'll want to create the activation factory yourself, and then create objects from it at your convenience. Veja alguns exemplos mostrando como fazer isso usando o modelo de função winrt::get_activation_factory.Here are some examples showing you how, using the winrt::get_activation_factory function template.

using namespace winrt::Windows::Globalization::NumberFormatting;
...
auto factory = winrt::get_activation_factory<CurrencyFormatter, ICurrencyFormatterFactory>();
CurrencyFormatter currency = factory.CreateCurrencyFormatterCode(L"USD");
using namespace winrt::Windows::Foundation;
...
auto factory = winrt::get_activation_factory<Uri, IUriRuntimeClassFactory>();
Uri uri = factory.CreateUri(L"http://www.contoso.com");

As classes nos dois exemplos acima são tipos de um namespace do Windows.The classes in the two examples above are types from a Windows namespace. No exemplo a seguir, ThermometerWRC::Thermometer é um tipo personalizado implementado em um componente do Windows Runtime.In this next example, ThermometerWRC::Thermometer is a custom type implemented in a Windows Runtime component.

auto factory = winrt::get_activation_factory<ThermometerWRC::Thermometer>();
ThermometerWRC::Thermometer thermometer = factory.ActivateInstance<ThermometerWRC::Thermometer>();

Ambiguidades de membro/tipoMember/Type ambiguities

Quando uma função de membro tem o mesmo nome de um tipo, há ambiguidade.When a member function has the same name as a type, there's ambiguity. As regras para a pesquisa de nome não qualificado do C++ em funções de membro fazem com que ele pesquise a classe antes de fazer a pesquisa em namespaces.The rules for C++ unqualified name lookup in member functions cause it to search the class before searching in namespaces. A regra a falha de substituição não é um erro (SFINAE) não se aplica (ela se aplica durante a resolução de sobrecarga dos modelos de função).The substitution failure is not an error (SFINAE) rule doesn't apply (it applies during overload resolution of function templates). Portanto, se o nome dentro da classe não fizer sentido, o compilador não continuará procurando uma correspondência melhor—ele simplesmente relatará um erro.So if the name inside the class doesn't make sense, then the compiler doesn't keep looking for a better match—it simply reports an error.

struct MyPage : Page
{
    void DoWork()
    {
        // This doesn't compile. You get the error
        // "'winrt::Windows::Foundation::IUnknown::as':
        // no matching overloaded function found".
        auto style{ Application::Current().Resources().
            Lookup(L"MyStyle").as<Style>() };
    }
}

Acima, o compilador pensa que você está passando FrameworkElement.Style() (que, no C++/WinRT, é uma função membro) como o parâmetro de modelo para IUnknown::as.Above, the compiler thinks that you're passing FrameworkElement.Style() (which, in C++/WinRT, is a member function) as the template parameter to IUnknown::as. A solução é forçar o nome Style a ser interpretado como o tipo Windows::UI::Xaml::Style.The solution is to force the name Style to be interpreted as the type Windows::UI::Xaml::Style.

struct MyPage : Page
{
    void DoWork()
    {
        // One option is to fully-qualify it.
        auto style{ Application::Current().Resources().
            Lookup(L"MyStyle").as<Windows::UI::Xaml::Style>() };

        // Another is to force it to be interpreted as a struct name.
        auto style{ Application::Current().Resources().
            Lookup(L"MyStyle").as<struct Style>() };

        // If you have "using namespace Windows::UI;", then this is sufficient.
        auto style{ Application::Current().Resources().
            Lookup(L"MyStyle").as<Xaml::Style>() };

        // Or you can force it to be resolved in the global namespace (into which
        // you imported the Windows::UI::Xaml namespace when you did
        // "using namespace Windows::UI::Xaml;".
        auto style = Application::Current().Resources().
            Lookup(L"MyStyle").as<::Style>();
    }
}

A pesquisa de nome não qualificado tem uma exceção especial no caso de o nome ser seguido por ::; nesse caso, ele ignora funções, variáveis e valores de enumeração.Unqualified name lookup has a special exception in the case that the name is followed by ::, in which case it ignores functions, variables, and enum values. Isso permite realizar ações semelhantes às mostradas a seguir.This allows you to do things like this.

struct MyPage : Page
{
    void DoSomething()
    {
        Visibility(Visibility::Collapsed); // No ambiguity here (special exception).
    }
}

A chamada a Visibility() é resolvida para o nome da função de membro UIElement.Visibility.The call to Visibility() resolves to the UIElement.Visibility member function name. Mas o parâmetro Visibility::Collapsed segue a palavra Visibility com :: e, portanto, o nome do método é ignorado e o compilador localiza a classe de enumeração.But the parameter Visibility::Collapsed follows the word Visibility with ::, and so the method name is ignored, and the compiler finds the enum class.

APIs importantesImportant APIs