Consumir componentes COM com C++/WinRTConsume COM components with C++/WinRT

Você pode usar as instalações da biblioteca do C++/WinRT para consumir componentes COM, como gráficos 2D e 3D de alto desempenho das APIs do DirectX.You can use the facilities of the C++/WinRT library to consume COM components, such as the high-performance 2-D and 3-D graphics of the DirectX APIs. O C++/ WinRT é a maneira mais simples de usar o DirectX sem comprometer o desempenho.C++/WinRT is the simplest way to use DirectX without compromising performance. Este tópico usa um exemplo de código do Direct2D para mostrar como usar C++/WinRT para consumir classes e interfaces COM.This topic uses a Direct2D code example to show how to use C++/WinRT to consume COM classes and interfaces. Obviamente, você pode misturar a programação do Windows Runtime e COM no mesmo projeto de C++/WinRT.You can, of course, mix COM and Windows Runtime programming within the same C++/WinRT project.

No final deste tópico, você encontrará uma listagem completa de código-fonte de um aplicativo mínimo do Direct2D.At the end of this topic, you'll find a full source code listing of a minimal Direct2D application. Vamos ressaltar extratos desse código e usá-los para ilustrar como consumir componentes COM usando C++/WinRT com várias instalações da biblioteca do C++/WinRT.We'll lift excerpts from that code and use them to illustrate how to consume COM components using C++/WinRT using various facilities of the C++/WinRT library.

Ponteiros inteligentes COM (winrt::com_ptr)COM smart pointers (winrt::com_ptr)

Ao programar usando COM, você trabalha diretamente com interfaces, em vez de projetos (isso também se aplica aos bastidores para APIs do Windows Runtime, que são uma evolução do COM).When you program with COM, you work directly with interfaces rather than with objects (that's also true behind the scenes for Windows Runtime APIs, which are an evolution of COM). Para chamar uma função em uma classe COM, por exemplo, ative a classe, obtenha de volta uma interface e, em seguida, chame funções nessa interface.To call a function on a COM class, for example, you activate the class, get an interface back, and then you call functions on that interface. Para acessar o estado de um objeto, não acesse seus membros de dados diretamente; em vez disso, chame as funções de acessador e modificador em uma interface.To access the state of an object, you don't access its data members directly; instead, you call accessor and mutator functions on an interface.

Para ser mais específico, estamos falando sobre como interagir com os ponteiros da interface.To be more specific, we're talking about interacting with interface pointers. E para fazer isso, aproveitamos a existência do tipo de ponteiro inteligente COM em C++/WinRT—o tipo winrt::com_ptr.And for that, we benefit from the existence of the COM smart pointer type in C++/WinRT—the winrt::com_ptr type.

#include <d2d1_1.h>
...
winrt::com_ptr<ID2D1Factory1> factory;

O código acima mostra como declarar um ponteiro inteligente não inicializado para uma interface COM ID2D1Factory1.The code above shows how to declare an uninitialized smart pointer to a ID2D1Factory1 COM interface. O ponteiro inteligente não foi inicializado, portanto, ele ainda não está apontando para uma interface ID2D1Factory1 pertencendo a qualquer objeto real (não está apontando para uma interface).The smart pointer is uninitialized, so it's not yet pointing to a ID2D1Factory1 interface belonging to any actual object (it's not pointing to an interface at all). Mas ele tem potencial para isso; e (sendo um ponteiro inteligente) tem a capacidade por meio da contagem de referência COM de gerenciar o tempo de vida do objeto proprietário da interface para o qual ele aponta, assim como para ser o meio pelo qual você chama funções nessa interface.But it has the potential to do so; and (being a smart pointer) it has the ability via COM reference counting to manage the lifetime of the owning object of the interface that it points to, and to be the medium by which you call functions on that interface.

Funções COM que retornam um ponteiro de interface como voidCOM functions that return an interface pointer as void

Você pode chamar a função com_ptr::put_void para gravar em um ponteiro bruto subjacente do ponteiro inteligente não inicializado.You can call the com_ptr::put_void function to write to an uninitialized smart pointer's underlying raw pointer.

D2D1_FACTORY_OPTIONS options{ D2D1_DEBUG_LEVEL_NONE };
D2D1CreateFactory(
    D2D1_FACTORY_TYPE_SINGLE_THREADED,
    __uuidof(factory),
    &options,
    factory.put_void()
);

O código acima chama a função D2D1CreateFactory, que retorna um ponteiro de interface ID2D1Factory1 por meio de seu último parâmetro, que tem o tipo void** .The code above calls the D2D1CreateFactory function, which returns an ID2D1Factory1 interface pointer via its last parameter, which has void** type. Muitas funções COM retornam um void** .Many COM functions return a void**. Para essas funções, use com_ptr::put_void, conforme mostrado.For such functions, use com_ptr::put_void as shown.

Funções COM que retornam um ponteiro de interface específicoCOM functions that return a specific interface pointer

A função D3D11CreateDevice retorna um ponteiro de interface ID3D11Device por meio de seu terceiro parâmetro, a contar do fim, que tem o tipo ID3D11Device** .The D3D11CreateDevice function returns an ID3D11Device interface pointer via its third-from-last parameter, which has ID3D11Device** type. Para funções que retornam um ponteiro de interface específico como esse, use com_ptr::put.For functions that return a specific interface pointer like that, use com_ptr::put.

winrt::com_ptr<ID3D11Device> device;
D3D11CreateDevice(
    ...
    device.put(),
    ...);

O exemplo de código na seção anterior mostra como chamar a função D2D1CreateFactory bruta.The code example in the section before this one shows how to call the raw D2D1CreateFactory function. Mas, na verdade, quando o exemplo de código para este tópico chama D2D1CreateFactory, ele usa um modelo de função auxiliar que encapsula a API bruta, assim, o exemplo de código, de fato, usa com_ptr::put.But in fact, when the code example for this topic calls D2D1CreateFactory, it uses a helper function template that wraps the raw API, and so the code example actually uses com_ptr::put.

winrt::com_ptr<ID2D1Factory1> factory;
D2D1CreateFactory(
    D2D1_FACTORY_TYPE_SINGLE_THREADED,
    options,
    factory.put());

Funções COM que retornam um ponteiro de interface como IUnknownCOM functions that return an interface pointer as IUnknown

A função DWriteCreateFactory retorna um ponteiro de interface de fábrica DirectWrite por meio de seu último parâmetro, que tem o tipo IUnknown.The DWriteCreateFactory function returns a DirectWrite factory interface pointer via its last parameter, which has IUnknown type. Para essa função, use com_ptr::put, mas reinterprete a transmissão disso para IUnknown.For such a function, use com_ptr::put, but reinterpret cast that to IUnknown.

DWriteCreateFactory(
    DWRITE_FACTORY_TYPE_SHARED,
    __uuidof(dwriteFactory2),
    reinterpret_cast<IUnknown**>(dwriteFactory2.put()));

Restabelecer um winrt::com_ptrRe-seat a winrt::com_ptr

Importante

Se você tiver um winrt::com_ptr que já esteja estabelecido (seu ponteiro bruto interno já tem um destino) e deseja restabelecê-lo para apontar para outro objeto, primeiramente, é preciso atribuir nullptr a ele— conforme mostrado no exemplo de código abaixo.If you have a winrt::com_ptr that's already seated (its internal raw pointer already has a target) and you want to re-seat it to point to a different object, then you first need to assign nullptr to it—as shown in the code example below. Se não o fizer, um com_ptr já estabelecido chamará sua atenção para o problema (quando você chamar com_ptr::put ou com_ptr::put_void) afirmando que seu ponteiro interno não é nulo.If you don't, then an already-seated com_ptr will draw the issue to your attention (when you call com_ptr::put or com_ptr::put_void) by asserting that its internal pointer is not null.

winrt::com_ptr<ID2D1SolidColorBrush> brush;
...
    brush.put()
...
brush = nullptr; // Important because we're about to re-seat
target->CreateSolidColorBrush(
    color_orange,
    D2D1::BrushProperties(0.8f),
    brush.put()));

Tratar códigos de erro HRESULTHandle HRESULT error codes

Para verificar o valor de um HRESULT retornado de uma função COM e lançar uma exceção no caso em que ele representar um código de erro, chame winrt::check_hresult.To check the value of a HRESULT returned from a COM function, and throw an exception in the event that it represents an error code, call winrt::check_hresult.

winrt::check_hresult(D2D1CreateFactory(
    D2D1_FACTORY_TYPE_SINGLE_THREADED,
    __uuidof(factory),
    options,
    factory.put_void()));

Funções COM que adotam um ponteiro de interface específicoCOM functions that take a specific interface pointer

Você pode chamar a função com_ptr::get para passar seu com_ptr para uma função que usa um ponteiro de interface específico do mesmo tipo.You can call the com_ptr::get function to pass your com_ptr to a function that takes a specific interface pointer of the same type.

... ExampleFunction(
    winrt::com_ptr<ID2D1Factory1> const& factory,
    winrt::com_ptr<IDXGIDevice> const& dxdevice)
{
    ...
    winrt::check_hresult(factory->CreateDevice(dxdevice.get(), ...));
    ...
}

Funções COM que adotam um ponteiro de interface IUnknownCOM functions that take an IUnknown interface pointer

É possível usar com_ptr::get para passar seu com_ptr para uma função que usa um ponteiro de interface IUnknown.You can use com_ptr::get to pass your com_ptr to a function that takes an IUnknown interface pointer.

É possível usar a função free winrt::get_unknown para retornar o endereço da interface IUnknown bruta subjacente (em outras palavras, um ponteiro para ela) de um objeto de um tipo projetado.You can use the winrt::get_unknown free function to return the address of (in other words, a pointer to) the underlying raw IUnknown interface of an object of a projected type. Em seguida, é possível passar esse endereço para uma função que usa um ponteiro de interface IUnknown.You can then pass that address to a function that takes an IUnknown interface pointer.

Para obter informações sobre tipos projetados, confira Consumir APIs com C++/WinRT.For info about projected types, see Consume APIs with C++/WinRT.

Para obter um exemplo de código de get_unknown, confira winrt::get_unknown ou Listagem completa de código-fonte de um aplicativo Direct2D mínimo neste tópico.For a code example of get_unknown, see winrt::get_unknown, or the Full source code listing of a minimal Direct2D application in this topic.

Passando e retornando ponteiros inteligentes COMPassing and returning COM smart pointers

Uma função usando um ponteiro inteligente COM na forma de um winrt::com_ptr deve fazer isso por referência de constante, ou por referência.A function taking a COM smart pointer in the form of a winrt::com_ptr should do so by constant reference, or by reference.

... GetDxgiFactory(winrt::com_ptr<ID3D11Device> const& device) ...

... CreateDevice(..., winrt::com_ptr<ID3D11Device>& device) ...

Uma função que retorna um winrt::com_ptr deve fazer isso por valor.A function that returns a winrt::com_ptr should do so by value.

winrt::com_ptr<ID2D1Factory1> CreateFactory() ...

Consultar um ponteiro inteligente COM para uma interface diferenteQuery a COM smart pointer for a different interface

Você pode usar a função com_ptr::as para consultar um ponteiro inteligente COM para uma interface diferente.You can use the com_ptr::as function to query a COM smart pointer for a different interface. A função vai gerar uma exceção se a consulta não tiver êxito.The function throws an exception if the query doesn't succeed.

void ExampleFunction(winrt::com_ptr<ID3D11Device> const& device)
{
    ...
    winrt::com_ptr<IDXGIDevice> const dxdevice{ device.as<IDXGIDevice>() };
    ...
}

Como alternativa, use com_ptr::try_as, que retorna um valor que você pode verificar em relação a nullptr para saber se a consulta foi bem-sucedida.Alternatively, use com_ptr::try_as, which returns a value that you can check against nullptr to see whether the query succeeded.

Listagem completa de código-fonte de um aplicativo Direct2D mínimoFull source code listing of a minimal Direct2D application

Observação

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 ao Visual Studio para C++/WinRT.For info about setting up Visual Studio for C++/WinRT development—including 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.

Se você quiser compilar e executar esse exemplo de código-fonte, primeiramente instale (ou atualize para) a versão mais recente da VSIX (Extensão do Visual Studio) para C++/WinRT; confira a anotação acima.If you want to build and run this source code example then first install (or update to) the latest version of the C++/WinRT Visual Studio Extension (VSIX); see the note above. Em seguida, no Visual Studio, crie um App Core (C++/WinRT) .Then, in Visual Studio, create a new Core App (C++/WinRT). Direct2D é um nome razoável para o projeto, mas você pode nomeá-lo como desejar.Direct2D is a reasonable name for the project, but you can name it anything you like. Direcione a versão mais recente em disponibilidade geral (ou seja, que não esteja em versão prévia) do SDK do Windows.Target the latest generally-available (that is, not preview) version of the Windows SDK.

Etapa 1.Step 1. Editar pch.hEdit pch.h

Abra pch.h e adicione #include <unknwn.h> imediatamente após a inclusão de windows.h.Open pch.h, and add #include <unknwn.h> immediately after including windows.h. Isso ocorre porque estamos usando winrt::get_unknown.This is because we're using winrt::get_unknown. É uma boa ideia explicitar #include <unknwn.h> sempre que você usar winrt ::get_unknown, mesmo que esse cabeçalho tenha sido incluído por outro cabeçalho.It's a good idea to #include <unknwn.h> explicity whenever you use winrt::get_unknown, even if that header has been included by another header.

Observação

Se você omitir essa etapa, verá o erro de build 'get_unknown': identificador não encontrado.If you omit this step then you'll see the build error 'get_unknown': identifier not found.

Etapa 2.Step 2. Editar App.cppEdit App.cpp

Abra App.cpp, exclua todo o seu conteúdo e cole na lista abaixo.Open App.cpp, delete its entire contents, and paste in the listing below.

O código a seguir usa a função winrt::com_ptr::capture sempre que possível.The code below uses the winrt::com_ptr::capture function where possible. WINRT_ASSERT é uma definição de macro e se expande para _ASSERTE.WINRT_ASSERT is a macro definition, and it expands to _ASSERTE.

#include "pch.h"
#include <d2d1_1.h>
#include <d3d11.h>
#include <dxgi1_2.h>
#include <winrt/Windows.Graphics.Display.h>

using namespace winrt;

using namespace Windows;
using namespace Windows::ApplicationModel::Core;
using namespace Windows::UI;
using namespace Windows::UI::Core;
using namespace Windows::Graphics::Display;

namespace
{
    winrt::com_ptr<ID2D1Factory1> CreateFactory()
    {
        D2D1_FACTORY_OPTIONS options{};

#ifdef _DEBUG
        options.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION;
#endif

        winrt::com_ptr<ID2D1Factory1> factory;

        winrt::check_hresult(D2D1CreateFactory(
            D2D1_FACTORY_TYPE_SINGLE_THREADED,
            options,
            factory.put()));

        return factory;
    }

    HRESULT CreateDevice(D3D_DRIVER_TYPE const type, winrt::com_ptr<ID3D11Device>& device)
    {
        WINRT_ASSERT(!device);

        return D3D11CreateDevice(
            nullptr,
            type,
            nullptr,
            D3D11_CREATE_DEVICE_BGRA_SUPPORT,
            nullptr, 0,
            D3D11_SDK_VERSION,
            device.put(),
            nullptr,
            nullptr);
    }

    winrt::com_ptr<ID3D11Device> CreateDevice()
    {
        winrt::com_ptr<ID3D11Device> device;
        HRESULT hr{ CreateDevice(D3D_DRIVER_TYPE_HARDWARE, device) };

        if (DXGI_ERROR_UNSUPPORTED == hr)
        {
            hr = CreateDevice(D3D_DRIVER_TYPE_WARP, device);
        }

        winrt::check_hresult(hr);
        return device;
    }

    winrt::com_ptr<ID2D1DeviceContext> CreateRenderTarget(
        winrt::com_ptr<ID2D1Factory1> const& factory,
        winrt::com_ptr<ID3D11Device> const& device)
    {
        WINRT_ASSERT(factory);
        WINRT_ASSERT(device);

        winrt::com_ptr<IDXGIDevice> const dxdevice{ device.as<IDXGIDevice>() };

        winrt::com_ptr<ID2D1Device> d2device;
        winrt::check_hresult(factory->CreateDevice(dxdevice.get(), d2device.put()));

        winrt::com_ptr<ID2D1DeviceContext> target;
        winrt::check_hresult(d2device->CreateDeviceContext(D2D1_DEVICE_CONTEXT_OPTIONS_NONE, target.put()));
        return target;
    }

    winrt::com_ptr<IDXGIFactory2> GetDxgiFactory(winrt::com_ptr<ID3D11Device> const& device)
    {
        WINRT_ASSERT(device);

        winrt::com_ptr<IDXGIDevice> const dxdevice{ device.as<IDXGIDevice>() };

        winrt::com_ptr<IDXGIAdapter> adapter;
        winrt::check_hresult(dxdevice->GetAdapter(adapter.put()));

        winrt::com_ptr<IDXGIFactory2> factory;
        factory.capture(adapter, &IDXGIAdapter::GetParent);
        return factory;
    }

    void CreateDeviceSwapChainBitmap(
        winrt::com_ptr<IDXGISwapChain1> const& swapchain,
        winrt::com_ptr<ID2D1DeviceContext> const& target)
    {
        WINRT_ASSERT(swapchain);
        WINRT_ASSERT(target);

        winrt::com_ptr<IDXGISurface> surface;
        surface.capture(swapchain, &IDXGISwapChain1::GetBuffer, 0);

        D2D1_BITMAP_PROPERTIES1 const props{ D2D1::BitmapProperties1(
            D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW,
            D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE)) };

        winrt::com_ptr<ID2D1Bitmap1> bitmap;

        winrt::check_hresult(target->CreateBitmapFromDxgiSurface(surface.get(),
            props,
            bitmap.put()));

        target->SetTarget(bitmap.get());
    }

    winrt::com_ptr<IDXGISwapChain1> CreateSwapChainForCoreWindow(winrt::com_ptr<ID3D11Device> const& device)
    {
        WINRT_ASSERT(device);

        winrt::com_ptr<IDXGIFactory2> const factory{ GetDxgiFactory(device) };

        DXGI_SWAP_CHAIN_DESC1 props{};
        props.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
        props.SampleDesc.Count = 1;
        props.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
        props.BufferCount = 2;
        props.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;

        winrt::com_ptr<IDXGISwapChain1> swapChain;

        winrt::check_hresult(factory->CreateSwapChainForCoreWindow(
            device.get(),
            winrt::get_unknown(CoreWindow::GetForCurrentThread()),
            &props,
            nullptr, // all or nothing
            swapChain.put()));

        return swapChain;
    }

    constexpr D2D1_COLOR_F color_white{ 1.0f,  1.0f,  1.0f,  1.0f };
    constexpr D2D1_COLOR_F color_orange{ 0.92f,  0.38f,  0.208f,  1.0f };
}

struct App : implements<App, IFrameworkViewSource, IFrameworkView>
{
    winrt::com_ptr<ID2D1Factory1> m_factory;
    winrt::com_ptr<ID2D1DeviceContext> m_target;
    winrt::com_ptr<IDXGISwapChain1> m_swapChain;
    winrt::com_ptr<ID2D1SolidColorBrush> m_brush;
    float m_dpi{};

    IFrameworkView CreateView()
    {
        return *this;
    }

    void Initialize(CoreApplicationView const&)
    {
    }

    void Load(hstring const&)
    {
        CoreWindow const window{ CoreWindow::GetForCurrentThread() };

        window.SizeChanged([&](auto&&...)
        {
            if (m_target)
            {
                ResizeSwapChainBitmap();
                Render();
            }
        });

        DisplayInformation const display{ DisplayInformation::GetForCurrentView() };
        m_dpi = display.LogicalDpi();

        display.DpiChanged([&](DisplayInformation const& display, IInspectable const&)
        {
            if (m_target)
            {
                m_dpi = display.LogicalDpi();
                m_target->SetDpi(m_dpi, m_dpi);
                CreateDeviceSizeResources();
                Render();
            }
        });

        m_factory = CreateFactory();
        CreateDeviceIndependentResources();
    }

    void Uninitialize()
    {
    }

    void Run()
    {
        CoreWindow const window{ CoreWindow::GetForCurrentThread() };
        window.Activate();

        Render();
        CoreDispatcher const dispatcher{ window.Dispatcher() };
        dispatcher.ProcessEvents(CoreProcessEventsOption::ProcessUntilQuit);
    }

    void SetWindow(CoreWindow const&) {}

    void Draw()
    {
        m_target->Clear(color_white);

        D2D1_SIZE_F const size{ m_target->GetSize() };
        D2D1_RECT_F const rect{ 100.0f, 100.0f, size.width - 100.0f, size.height - 100.0f };
        m_target->DrawRectangle(rect, m_brush.get(), 100.0f);

        char buffer[1024];
        (void)snprintf(buffer, sizeof(buffer), "Draw %.2f x %.2f @ %.2f\n", size.width, size.height, m_dpi);
        ::OutputDebugStringA(buffer);
    }

    void Render()
    {
        if (!m_target)
        {
            winrt::com_ptr<ID3D11Device> const device{ CreateDevice() };
            m_target = CreateRenderTarget(m_factory, device);
            m_swapChain = CreateSwapChainForCoreWindow(device);

            CreateDeviceSwapChainBitmap(m_swapChain, m_target);

            m_target->SetDpi(m_dpi, m_dpi);

            CreateDeviceResources();
            CreateDeviceSizeResources();
        }

        m_target->BeginDraw();
        Draw();
        m_target->EndDraw();

        HRESULT const hr{ m_swapChain->Present(1, 0) };

        if (S_OK != hr && DXGI_STATUS_OCCLUDED != hr)
        {
            ReleaseDevice();
        }
    }

    void ReleaseDevice()
    {
        m_target = nullptr;
        m_swapChain = nullptr;

        ReleaseDeviceResources();
    }

    void ResizeSwapChainBitmap()
    {
        WINRT_ASSERT(m_target);
        WINRT_ASSERT(m_swapChain);

        m_target->SetTarget(nullptr);

        if (S_OK == m_swapChain->ResizeBuffers(0, // all buffers
            0, 0, // client area
            DXGI_FORMAT_UNKNOWN, // preserve format
            0)) // flags
        {
            CreateDeviceSwapChainBitmap(m_swapChain, m_target);
            CreateDeviceSizeResources();
        }
        else
        {
            ReleaseDevice();
        }
    }

    void CreateDeviceIndependentResources()
    {
    }

    void CreateDeviceResources()
    {
        winrt::check_hresult(m_target->CreateSolidColorBrush(
            color_orange,
            D2D1::BrushProperties(0.8f),
            m_brush.put()));
    }

    void CreateDeviceSizeResources()
    {
    }

    void ReleaseDeviceResources()
    {
        m_brush = nullptr;
    }
};

int __stdcall wWinMain(HINSTANCE, HINSTANCE, PWSTR, int)
{
    CoreApplication::Run(winrt::make<App>());
}

Trabalhando com os tipos de COM, como BSTR e VARIANTWorking with COM types, such as BSTR and VARIANT

Como você pode ver, C++/WinRT fornece suporte para implementar e chamar interfaces COM.As you can see, C++/WinRT provides support for both implementing and calling COM interfaces. Para usar tipos de COM, como BSTR e VARIANT, é recomendável usar wrappers fornecidos pelas WILs (Bibliotecas de Implementação do Windows), como wil::unique_bstr e wil::unique_variant (que gerenciam os tempos de vida dos recursos).For using COM types, such as BSTR and VARIANT, we recommend that you use wrappers provided by the Windows Implementation Libraries (WIL), such as wil::unique_bstr and wil::unique_variant (which manage resources lifetimes).

A WIL substitui estruturas como a ATL (Active Template Library) e o suporte COM do compilador do Visual C++.WIL supersedes frameworks such as the Active Template Library (ATL), and the Visual C++ compiler's COM Support. E é recomendável substituir seus próprios wrappers ou usar tipos de COM como BSTR e VARIANT na respectiva forma bruta (com as APIs apropriadas).And we recommend it over writing your own wrappers, or using COM types such as BSTR and VARIANT in their raw form (together with the appropriate APIs).

Evitar conflitos de namespaceAvoiding namespace collisions

É prática comum em C++/WinRT, —como a listagem de código neste tópico demonstra—, usar diretivas de uso livremente.It's common practice in C++/WinRT—as the code listing in this topic demonstrates—to use using-directives liberally. Em alguns casos, no entanto, isso pode levar ao problema de importar nomes conflitantes para o namespace global.In some cases, though, that can lead to the problem of importing colliding names into the global namespace. Aqui está um exemplo.Here's an example.

C++/WinRT contém um tipo denominado winrt::Windows::Foundation::IUnknown; enquanto COM define um tipo denominado ::IUnknown.C++/WinRT contains a type named winrt::Windows::Foundation::IUnknown; while COM defines a type named ::IUnknown. Sendo assim, considere o código a seguir, em um projeto de C++/WinRT que consome cabeçalhos COM.So consider the following code, in a C++/WinRT project that consumes COM headers.

using namespace winrt::Windows::Foundation;
...
void MyFunction(IUnknown*); // error C2872:  'IUnknown': ambiguous symbol

O nome não qualificado IUnknown entra em conflito com o namespace global, daí o erro do compilador de símbolo ambíguo.The unqualified name IUnknown collides in the global namespace, hence the ambiguous symbol compiler error. Em vez disso, você pode isolar a versão C++/WinRT do nome no namespace winrt, dessa forma.Instead, you can isolate the C++/WinRT version of the name into the winrt namespace, like this.

namespace winrt
{
    using namespace Windows::Foundation;
}
...
void MyFunctionA(IUnknown*); // Ok.
void MyFunctionB(winrt::IUnknown const&); // Ok.

Ou, se quiser a conveniência de using namespace winrt, você pode.Or, if you want the convenience of using namespace winrt, then you can. Você só precisa qualificar a versão global de IUnknown, dessa forma.You just need to qualify the global version of IUnknown, like this.

using namespace winrt;
namespace winrt
{
    using namespace Windows::Foundation;
}
...
void MyFunctionA(::IUnknown*); // Ok.
void MyFunctionB(winrt::IUnknown const&); // Ok.

Naturalmente, isso funciona com qualquer namespace de C++/WinRT.Naturally, this works with any C++/WinRT namespace.

namespace winrt
{
    using namespace Windows::Storage;
    using namespace Windows::System;
}

Você pode, em seguida, fazer referência a winrt::Windows::Storage::StorageFile, por exemplo, apenas como winrt::StorageFile.You can then refer to winrt::Windows::Storage::StorageFile, for example, as just winrt::StorageFile.

APIs importantesImportant APIs