Utilizzare componenti COM con C++/WinRTConsume COM components with C++/WinRT

Puoi usare le funzionalità della libreria C++/WinRT per utilizzare componenti COM, ad esempio la grafica 2D e 3D ad alte prestazioni delle API 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 è il modo più semplice per usare DirectX senza compromettere le prestazioni.C++/WinRT is the simplest way to use DirectX without compromising performance. Questo argomento usa un esempio di codice Direct2D per illustrare l'uso di C++/WinRT per utilizzare classi e interfacce COM.This topic uses a Direct2D code example to show how to use C++/WinRT to consume COM classes and interfaces. Naturalmente, puoi combinare elementi di programmazione COM e Windows Runtime all'interno dello stesso progetto C++/WinRT.You can, of course, mix COM and Windows Runtime programming within the same C++/WinRT project.

Alla fine di questo argomento, troverai un listato di codice sorgente completo di un'applicazione Direct2D minima.At the end of this topic, you'll find a full source code listing of a minimal Direct2D application. Alcuni estratti di tale codice verranno usati per illustrare come utilizzare i componenti COM con C++/WinRT sfruttando diverse funzionalità della libreria 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.

Puntatori intelligenti COM (winrt::com_ptr)COM smart pointers (winrt::com_ptr)

Nella programmazione con COM si lavora direttamente con le interfacce anziché con gli oggetti. Ciò è vero anche dietro le quinte per le API Windows Runtime, che sono un'evoluzione di 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). Per chiamare una funzione per una classe COM, ad esempio, si attiva la classe, si ottiene un'interfaccia e quindi si chiamano funzioni su tale interfaccia.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. Per accedere allo stato di un oggetto, non devi accedere direttamente ai relativi membri dati, ma chiamare funzioni di accesso e mutatore su un'interfaccia.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.

Per essere più specifici, si tratta di interagire con puntatori di interfaccia.To be more specific, we're talking about interacting with interface pointers. A tale scopo possiamo sfruttare il vantaggio dell'esistenza del tipo di puntatore intelligente COM in C++/WinRT, ovvero il 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;

Il codice sopra riportato mostra come dichiarare un puntatore intelligente non inizializzato a un'interfaccia COM ID2D1Factory1.The code above shows how to declare an uninitialized smart pointer to a ID2D1Factory1 COM interface. Il puntatore intelligente non è inizializzato, quindi non punta ancora a un'interfaccia ID2D1Factory1 appartenente a qualsiasi oggetto effettivo (in effetti non punta ad alcuna interfaccia).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). Però può farlo potenzialmente e trattandosi di un puntatore intelligente ha la capacità (tramite conteggio dei riferimenti COM) di gestire la durata dell'oggetto dell'interfaccia a cui punta e di essere il mezzo tramite il quale puoi chiamare le funzioni su tale interfaccia.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.

Funzioni COM che restituiscono un puntatore di interfaccia come voidCOM functions that return an interface pointer as void

Puoi chiamare la funzione com_ptr::put_void per scrivere nel puntatore non elaborato sottostante di un puntatore intelligente non inizializzato.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()
);

Il codice precedente chiama la funzione D2D1CreateFactory, che restituisce un puntatore di interfaccia ID2D1Factory1 tramite l'ultimo parametro, con il tipo void ** .The code above calls the D2D1CreateFactory function, which returns an ID2D1Factory1 interface pointer via its last parameter, which has void** type. Molte funzioni COM restituiscono void** .Many COM functions return a void**. Per tali funzioni, usa com_ptr::put_void come illustrato.For such functions, use com_ptr::put_void as shown.

Funzioni COM che restituiscono un puntatore di interfaccia specificoCOM functions that return a specific interface pointer

La funzione D3D11CreateDevice restituisce un puntatore di interfaccia ID3D11Device tramite il terzultimo parametro, con tipo ID3D11Device** .The D3D11CreateDevice function returns an ID3D11Device interface pointer via its third-from-last parameter, which has ID3D11Device** type. Per le funzioni che restituiscono un puntatore di interfaccia specifico in questo modo, usa 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(),
    ...);

L'esempio di codice nella sezione prima di questa mostra come chiamare la funzione D2D1CreateFactory non elaborata.The code example in the section before this one shows how to call the raw D2D1CreateFactory function. Ma in realtà, quando l'esempio di codice in questo argomento chiama D2D1CreateFactory usa un modello di funzione helper che esegue il wrapping dell'API non elaborata e quindi l'esempio di codice usa effettivamente 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());

Funzioni COM che restituiscono un puntatore di interfaccia come IUnknownCOM functions that return an interface pointer as IUnknown

La funzione DWriteCreateFactory restituisce un puntatore di interfaccia factory DirectWrite tramite l'ultimo parametro, con tipo IUnknown.The DWriteCreateFactory function returns a DirectWrite factory interface pointer via its last parameter, which has IUnknown type. Per una funzione di questo tipo, usa com_ptr::put, ma eseguine il cast su 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()));

Ridestinare un puntatore winrt::com_ptrRe-seat a winrt::com_ptr

Importante

Se hai un puntatore winrt::com_ptr già collocato (il relativo puntatore non elaborato interno ha già una destinazione) e voi ridestinarlo in modo che punti a un oggetto diverso, devi prima di tutto assegnare nullptr al puntatore, come illustrato nell'esempio di codice seguente.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. In caso contrario, un com_ptr già collocato porterà il problema alla tua attenzione (quando chiami com_ptr::put oppure com_ptr:: put_void) indicando che il relativo puntatore interno non è 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()));

Gestire i codici di errore HRESULTHandle HRESULT error codes

Per controllare il valore di un HRESULT restituito da una funzione COM e generare un'eccezione nel caso in cui rappresenti un codice di errore, chiama 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()));

Funzioni COM che accettano un puntatore di interfaccia specificoCOM functions that take a specific interface pointer

Puoi chiamare la funzione com_ptr::get per passare com_ptr a una funzione che accetta un puntatore di interfaccia specifico dello stesso 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(), ...));
    ...
}

Funzioni COM che accettano un puntatore di interfaccia IUnknownCOM functions that take an IUnknown interface pointer

Puoi usare com_ptr::get per passare com_ptr a una funzione che accetta un puntatore di interfaccia IUnknown.You can use com_ptr::get to pass your com_ptr to a function that takes an IUnknown interface pointer.

Puoi usare la funzione libera winrt::get_unknown per restituire l'indirizzo dell'interfaccia IUnknown sottostante non elaborata (in altre parole, un puntatore a tale interfaccia) di un oggetto di un tipo proiettato.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. Puoi quindi passare tale indirizzo a una funzione che accetta un puntatore di interfaccia IUnknown.You can then pass that address to a function that takes an IUnknown interface pointer.

Per informazioni sui tipi proiettati, vedi Utilizzare API con C++/WinRT.For info about projected types, see Consume APIs with C++/WinRT.

Per un esempio di codice di get_unknown, vedi winrt::get_unknown o la sezione Listato di codice sorgente completo di un'applicazione Direct2D minima in questo argomento.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.

Passaggio e restituzione di puntatori intelligenti COMPassing and returning COM smart pointers

Una funzione che accetta un puntatore intelligente COM in forma di winrt::com_ptr deve farlo tramite un riferimento costante o per riferimento.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 funzione che restituisce un winrt::com_ptr deve farlo per valore.A function that returns a winrt::com_ptr should do so by value.

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

Richiedere un puntatore intelligente COM per un'altra interfacciaQuery a COM smart pointer for a different interface

Puoi usare la funzione com_ptr::as per richiedere un puntatore intelligente COM per un'interfaccia diversa.You can use the com_ptr::as function to query a COM smart pointer for a different interface. La funzione genera un'eccezione se la query ha esito negativo.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>() };
    ...
}

In alternativa, usa com_ptr::try_as, che restituisce un valore che puoi confrontare con nullptr per vedere se la query è stata completata.Alternatively, use com_ptr::try_as, which returns a value that you can check against nullptr to see whether the query succeeded.

Listato di codice sorgente completo di un'applicazione Direct2D minimaFull source code listing of a minimal Direct2D application

Nota

Per informazioni sulla configurazione di Visual Studio per lo sviluppo in C++/WinRT, compresi l'installazione e l'uso dell'estensione C++/WinRT per Visual Studio (VSIX) e del pacchetto NuGet, che insieme forniscono il modello di progetto e il supporto della compilazione, vedi Supporto di Visual Studio per 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.

Per compilare ed eseguire questo esempio di codice sorgente, installare prima o eseguire l'aggiornamento alla versione più recente di C++/WinRT Visual Studio Extension (VSIX). Vedere la nota sopra.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. Quindi, in Visual Studio, creare una nuova App Core (C++/WinRT) .Then, in Visual Studio, create a new Core App (C++/WinRT). Direct2D è un nome adeguato per il progetto, ma puoi scegliere un nome qualsiasi.Direct2D is a reasonable name for the project, but you can name it anything you like. Specificare come destinazione la versione più recente disponibile a livello generale, ovvero non l'anteprima, di Windows SDK.Target the latest generally-available (that is, not preview) version of the Windows SDK.

Passaggio 1.Step 1. Modifica pch.hEdit pch.h

Apri pch.h e aggiungi #include <unknwn.h> subito dopo aver incluso windows.h.Open pch.h, and add #include <unknwn.h> immediately after including windows.h. Questa operazione è necessaria perché stiamo usando winrt::get_unknown.This is because we're using winrt::get_unknown. È consigliabile eseguire #include <unknwn.h> in modo esplicito ogni volta che usi winrt::get_unknown, anche se tale intestazione è stata inclusa da un'altra intestazione.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

Se si omette questo passaggio, verrà visualizzato l'errore di compilazione 'get_unknown': identificatore non trovato.If you omit this step then you'll see the build error 'get_unknown': identifier not found.

Passaggio 2.Step 2. Modifica App.cppEdit App.cpp

Apri App.cpp, elimina l'intero contenuto e incolla il listato riportato di seguito.Open App.cpp, delete its entire contents, and paste in the listing below.

Il codice seguente usa la funzione winrt::com_ptr::capture laddove possibile.The code below uses the winrt::com_ptr::capture function where possible. WINRT_ASSERT è una definizione di macro e si espande in 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>());
}

Utilizzo di tipi COM, quali BSTR e VARIANTWorking with COM types, such as BSTR and VARIANT

Come puoi notare, C++/WinRT offre supporto sia per l'implementazione che per la chiamata di interfacce COM.As you can see, C++/WinRT provides support for both implementing and calling COM interfaces. Per usare i tipi COM, quali BSTR e VARIANT, è consigliabile usare i wrapper forniti dalle librerie di implementazione di Windows (WIL), come wil::unique_bstr e wil::unique_variant (che gestiscono la durata delle risorse).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).

Le librerie WIL sostituiscono framework come ATL (Active Template Library) e il supporto COM del compilatore Visual C++.WIL supersedes frameworks such as the Active Template Library (ATL), and the Visual C++ compiler's COM Support. Consigliamo l'uso di queste librerie rispetto alla scrittura di wrapper personalizzati oppure l'uso di tipi COM, ad esempio BSTR e VARIANT nel loro formato non elaborato (insieme alle API appropriate).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).

Come evitare conflitti di spazio dei nomiAvoiding namespace collisions

In C++/WinRT è prassi comune, come illustrato nel listato di codice di questo argomento, usare numerose direttive using.It's common practice in C++/WinRT—as the code listing in this topic demonstrates—to use using-directives liberally. In alcuni casi, tuttavia, ciò può causare un problema di importazione di nomi in conflitto nello spazio dei nomi globale.In some cases, though, that can lead to the problem of importing colliding names into the global namespace. Ecco un esempio.Here's an example.

C++/WinRT contiene un tipo denominato winrt::Windows::Foundation::IUnknown, mentre COM definisce un tipo denominato ::IUnknown.C++/WinRT contains a type named winrt::Windows::Foundation::IUnknown; while COM defines a type named ::IUnknown. Considera ora il codice seguente, in un progetto C++/WinRT che utilizza intestazioni 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

Il nome non qualificato IUnknown è in conflitto nella spazio dei nomi globale e pertanto il compilatore restituisce un errore di simbolo ambiguo.The unqualified name IUnknown collides in the global namespace, hence the ambiguous symbol compiler error. In alternativa, puoi isolare la versione C++/WinRT del nome nello spazio dei nomi winrt, come nel codice seguente.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.

Oppure puoi anche sfruttare la comodità di using namespace winrt.Or, if you want the convenience of using namespace winrt, then you can. Devi semplicemente qualificare la versione globale di IUnknown, come nel codice seguente.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, questo funziona con qualsiasi spazio dei nomi C++/WinRT.Naturally, this works with any C++/WinRT namespace.

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

Puoi quindi fare riferimento a winrt::Windows::Storage::StorageFile, ad esempio, usando semplicemente winrt::StorageFile.You can then refer to winrt::Windows::Storage::StorageFile, for example, as just winrt::StorageFile.

API importantiImportant APIs