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

Puedes utilizar las funciones de la biblioteca C++/WinRT para consumir los componentes COM, como los gráficos 2D y 3D de alto rendimiento de las API de 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. C++/WinRT es la manera más sencilla de usar DirectX sin comprometer el rendimiento.C++/WinRT is the simplest way to use DirectX without compromising performance. En este tema se usa un ejemplo de código completo de Direct2D para mostrar cómo utilizar C++/WinRT para consumir clases e interfaces COM.This topic uses a Direct2D code example to show how to use C++/WinRT to consume COM classes and interfaces. Por supuesto, puedes combinar la programación en COM y Windows Runtime dentro del mismo proyecto de C++/WinRT.You can, of course, mix COM and Windows Runtime programming within the same C++/WinRT project.

Al final de este tema, encontrarás una lista del código fuente completo de una aplicación de Direct2D mínima.At the end of this topic, you'll find a full source code listing of a minimal Direct2D application. Extraeremos partes de ese código y las usaremos para ilustrar cómo consumir componentes COM mediante C++/WinRT con varias facilidades de la biblioteca 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.

Punteros inteligentes de COM (winrt::com_ptr)COM smart pointers (winrt::com_ptr)

Cuando se programa con COM, se trabaja directamente con interfaces en lugar de con objetos (esto también se puede aplicar para las API de Windows Runtime, que son una evolución de 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 llamar a una función en una clase COM, por ejemplo, tienes que activar la clase, volver a obtener una interfaz y, después, llamar a las funciones en esa interfaz.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 acceder al estado de un objeto, no se accede directamente a sus miembros de datos, sino que se llaman a las funciones de acceso y mutador en una interfaz.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 más específico, hablamos de la interacción con los punteros de la interfaz.To be more specific, we're talking about interacting with interface pointers. Y para ello, nos beneficiamos de la existencia del tipo de puntero inteligente de COM en C++/WinRT: el 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;

En el código anterior se muestra cómo declarar un puntero inteligente no inicializado a una interfaz COM ID2D1Factory1.The code above shows how to declare an uninitialized smart pointer to a ID2D1Factory1 COM interface. El puntero inteligente no está inicializado, por lo que aún no apunta a una interfaz ID2D1D1Factory1 que pertenezca a un objeto real (no apunta a ninguna interfaz).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). Pero tienes la posibilidad de hacerlo; y, al ser un puntero inteligente, tienes la capacidad mediante un recuento de referencias COM de administrar el tiempo de vida del objeto propietario de la interfaz a la que apunta, y de ser el medio por el cual llamas a las funciones en esa interfaz.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.

Funciones COM que devuelven un puntero de interfaz como voidCOM functions that return an interface pointer as void

Puede llamar a la función com_ptr::put_void para escribir en un puntero inteligente sin inicializar subyacente del puntero básico.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()
);

El código anterior llama a la función D2D1CreateFactory, que devuelve un puntero de interfaz ID2D1Factory1 mediante su último parámetro, que tiene el tipo void** .The code above calls the D2D1CreateFactory function, which returns an ID2D1Factory1 interface pointer via its last parameter, which has void** type. Muchas funciones COM devuelven un tipo void** .Many COM functions return a void**. Para esas funciones, utiliza com_ptr::put_void tal como se muestra.For such functions, use com_ptr::put_void as shown.

Funciones COM que devuelven un puntero de interfaz específicoCOM functions that return a specific interface pointer

La función D3D11CreateDevice devuelve un puntero de interfaz ID3D11Device mediante su tercer parámetro desde el último, que tiene el tipo ID3D11Device** .The D3D11CreateDevice function returns an ID3D11Device interface pointer via its third-from-last parameter, which has ID3D11Device** type. Para las funciones que devuelven un puntero de interfaz específico como este, utiliza 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(),
    ...);

En el ejemplo de código de la sección anterior, se muestra cómo llamar a la función D2D1CreateFactory básica.The code example in the section before this one shows how to call the raw D2D1CreateFactory function. Pero de hecho, cuando el ejemplo de código para este tema llama a D2D1CreateFactory, utiliza una plantilla de asistente que envuelve la API básica, de modo que el ejemplo de código realmente utiliza 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());

Funciones COM que devuelven un puntero de interfaz como IUnknownCOM functions that return an interface pointer as IUnknown

La función DWriteCreateFactory devuelve un puntero de interfaz del generador de DirectWrite mediante su último parámetro, que tiene el tipo IUnknown.The DWriteCreateFactory function returns a DirectWrite factory interface pointer via its last parameter, which has IUnknown type. Para usar dicha función, utiliza com_ptr::put, pero reinterpreta su conversión en 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()));

Volver a sentar un winrt::com_ptrRe-seat a winrt::com_ptr

Importante

Si tienes una función winrt::com_ptr que ya se ha sentado (el puntero básico interno ya tiene un destino) y quieres volver a sentarla para que señale a un objeto distinto, en primer lugar deberás asignar nullptr en esta, tal como se muestra en el ejemplo de código siguiente.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. Si no lo haces, una función com_ptr ya sentada llamará la atención sobre el problema (cuando llames a com_ptr::put o com_ptr:: put_void) mediante la declaración de que el puntero interno no es null.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()));

Control de los códigos de error HRESULTHandle HRESULT error codes

Para comprobar el valor de un HRESULT devuelto desde una función COM e iniciar una excepción en el caso de que represente un código de error, llama a 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()));

Funciones COM que toman un puntero de interfaz específicoCOM functions that take a specific interface pointer

Puedes llamar a la función com_ptr::get para pasar com_ptr a una función que toma un puntero de interfaz específico del mismo 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(), ...));
    ...
}

Funciones COM que toman un puntero de interfaz IUnknownCOM functions that take an IUnknown interface pointer

Puedes usar com_ptr::get para pasar com_ptr a una función que toma un puntero de interfaz IUnknown.You can use com_ptr::get to pass your com_ptr to a function that takes an IUnknown interface pointer.

Puedes usar la función gratuita winrt::get_unknown para devolver la dirección de (es decir, un puntero a) la interfaz IUnknown subyacente sin procesar de un objeto de un tipo proyectado.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. Después, puedes pasar esa dirección a una función que tome un puntero de interfaz IUnknown.You can then pass that address to a function that takes an IUnknown interface pointer.

Para obtener información sobre los tipos proyectados, consulta Consumo de API con C++/WinRT.For info about projected types, see Consume APIs with C++/WinRT.

Para obtener un ejemplo de código de get_unknown, consulta winrt::get_unknown o la lista de código fuente completa de una aplicación Direct2D mínima en este tema.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.

Paso y devolución de punteros inteligentes COMPassing and returning COM smart pointers

Una función que tome un puntero inteligente COM en forma de winrt::com_ptr debería hacerlo por referencia constante, o por referencia.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) ...

Una función que devuelve winrt::com_ptr debería hacerlo por valor.A function that returns a winrt::com_ptr should do so by value.

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

Consulta de un puntero inteligente COM para otra interfazQuery a COM smart pointer for a different interface

Puede usar la función com_ptr::as para consultar un puntero inteligente COM para otra interfaz.You can use the com_ptr::as function to query a COM smart pointer for a different interface. La función inicia una excepción si la consulta no se realiza correctamente.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>() };
    ...
}

Además, utiliza com_ptr::try_as, que devuelve un valor que puedes comparar con nullptr para ver si la consulta se ha realizado correctamente.Alternatively, use com_ptr::try_as, which returns a value that you can check against nullptr to see whether the query succeeded.

Lista del código fuente completo de una aplicación de Direct2D mínimaFull source code listing of a minimal Direct2D application

Nota

Para más información sobre cómo instalar Visual Studio para la implementación de C++/WinRT —incluida la instalación y el uso de la Extensión de Visual Studio (VSIX) para C++/WinRT y el paquete NuGet (que juntos proporcionan la plantilla de proyecto y compatibilidad de la compilación)—, consulta Compatibilidad de 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.

Si desea compilar y ejecutar este ejemplo de código fuente, primero instale (o actualice a) la versión más reciente de la extensión de Visual Studio (VSIX) de C++/WinRT (consulte la nota anterior).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. A continuación, en Visual Studio, cree una nueva Aplicación principal (C++/WinRT) .Then, in Visual Studio, create a new Core App (C++/WinRT). Direct2D es un nombre razonable para el proyecto, pero puedes darle el nombre que quieras.Direct2D is a reasonable name for the project, but you can name it anything you like. Elija como destino la versión más reciente disponible de manera general (es decir, no en versión preliminar) de Windows SDK.Target the latest generally-available (that is, not preview) version of the Windows SDK.

Paso 1.Step 1. Edita pch.h.Edit pch.h

Abre pch.h y agrega #include <unknwn.h> inmediatamente después de incluir windows.h.Open pch.h, and add #include <unknwn.h> immediately after including windows.h. Esto se debe a que estamos usando winrt::get_unknown.This is because we're using winrt::get_unknown. Es una buena idea usar #include <unknwn.h> de forma explícita cada vez que utilices winrt::get_unknown, aunque otro encabezado haya incluido dicho encabezado.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.

Nota

Si omite este paso, verá el error de compilación 'get_unknown': no se encontró el identificador.If you omit this step then you'll see the build error 'get_unknown': identifier not found.

Paso 2.Step 2. Edita App.cpp.Edit App.cpp

Abre App.cpp, elimina todo su contenido y pega en la lista siguiente.Open App.cpp, delete its entire contents, and paste in the listing below.

El código siguiente usa la función winrt::com_ptr::capture siempre que sea posible.The code below uses the winrt::com_ptr::capture function where possible. WINRT_ASSERT es una definición de macro y se expande a _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>());
}

Trabajo con tipos COM, como BSTR y VARIANTWorking with COM types, such as BSTR and VARIANT

Como puede ver, C++/WinRT proporciona compatibilidad tanto para implementar como para llamar interfaces COM.As you can see, C++/WinRT provides support for both implementing and calling COM interfaces. Para utilizar tipos COM, como BSTR y VARIANT, recomendamos que utilices los contenedores proporcionados por las Bibliotecas de implementación de Windows (WIL), como wil::unique_bstr y wil::unique_variant (que administran la vigencia de los 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).

WIL reemplaza a plataformas como Active Template Library (ATL) y la compatibilidad de COM con el compilador de Visual C++.WIL supersedes frameworks such as the Active Template Library (ATL), and the Visual C++ compiler's COM Support. Y recomendamos sobrescribir sus propios contenedores, o el uso de tipos COM como BSTR y VARIANT en su forma básica (junto con las API apropiadas).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 conflictos de espacio de nombresAvoiding namespace collisions

Es una práctica común en C++/WinRT —como se muestra en el listado de código de este tema— utilizar las directivas "using" libremente.It's common practice in C++/WinRT—as the code listing in this topic demonstrates—to use using-directives liberally. Sin embargo, en algunos casos eso puede provocar el problema de importación de nombres en conflicto en el espacio de nombres global.In some cases, though, that can lead to the problem of importing colliding names into the global namespace. A continuación se muestra un ejemplo.Here's an example.

C++/WinRT contiene un tipo denominado winrt::Windows::Foundation::IUnknown; mientras que COM define un tipo denominado ::IUnknown.C++/WinRT contains a type named winrt::Windows::Foundation::IUnknown; while COM defines a type named ::IUnknown. Por tanto, ten en cuenta el código siguiente, en un proyecto de C++/WinRT que consume encabezados de 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

El nombre no completo IUnknown entra en conflicto en el espacio de nombres global, de ahí el error de compilador ambiguous symbol.The unqualified name IUnknown collides in the global namespace, hence the ambiguous symbol compiler error. En su lugar, puedes aislar la versión de C++/WinRT del nombre en el espacio de nombres winrt, como se muestra a continuación.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.

O bien, si prefieres la comodidad de using namespace winrt, puedes usarlo.Or, if you want the convenience of using namespace winrt, then you can. Basta calificar la versión global de IUnknown, como en este ejemplo.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, esto funciona con cualquier espacio de nombres de C++/WinRT.Naturally, this works with any C++/WinRT namespace.

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

A continuación, puedes hacer referencia a winrt::Windows::Storage::StorageFile, por ejemplo, simplemente como winrt::StorageFile.You can then refer to winrt::Windows::Storage::StorageFile, for example, as just winrt::StorageFile.

API importantesImportant APIs