Consume APIs with C++/WinRT

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.

If the API is in a Windows namespace

This is the most common case in which you'll consume a Windows Runtime API. For every type in a Windows namespace defined in metadata, C++/WinRT defines a C++-friendly equivalent (called the projected type). 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. For example, Windows::Foundation::Uri is projected into C++/WinRT as winrt::Windows::Foundation::Uri.

Here's a simple code example. 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");
}

The included header winrt/Windows.Foundation.h is part of the SDK, found inside the folder %WindowsSdkDir%Include<WindowsTargetPlatformVersion>\cppwinrt\winrt\. The headers in that folder contain Windows namespace types projected into C++/WinRT. In this example, winrt/Windows.Foundation.h contains winrt::Windows::Foundation::Uri, which is the projected type for the runtime class Windows::Foundation::Uri.

Tip

Whenever you want to use a type from a Windows namespace, include the C++/WinRT header corresponding to that namespace. The using namespace directives are optional, but convenient.

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). For this, the most common use case, that's typically all you have to do. 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.

In fact, that projected value is a proxy; it's essentially just a smart pointer to a backing object. 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. 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.

The projected Windows::Foundation::Uri type

When the contosoUri value falls out of scope, it destructs, and releases its reference to the default interface. If that reference is the last reference to the backing Windows Runtime Windows.Foundation.Uri object, the backing object destructs as well.

Tip

A projected type is a wrapper over a runtime class for purposes of consuming its APIs. A projected interface is a wrapper over a Windows Runtime interface.

C++/WinRT projection headers

To consume Windows namespace APIs from C++/WinRT, you include headers from the %WindowsSdkDir%Include<WindowsTargetPlatformVersion>\cppwinrt\winrt folder. It's common for a type in a subordinate namespace to reference types in its immediate parent namespace. Consequently, each C++/WinRT projection header automatically includes its parent namespace header file; so you don't need to explicitly include it. Although, if you do, there will be no error.

For example, for the Windows::Security::Cryptography::Certificates namespace, the equivalent C++/WinRT type definitions reside in winrt/Windows.Security.Cryptography.Certificates.h. 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.

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. That's where the trail stops, since there is no winrt/Windows.h. This transitive inclusion process stops at the second-level namespace.

This process transitively includes the header files that provide the necessary declarations and implementations for the classes defined in parent namespaces.

A member of a type in one namespace can reference one or more types in other, unrelated, namespaces. 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. Consequently, each C++/WinRT projection header includes the namespace headers it needs to declare any dependent types. Unlike for parent namespaces, this process does not pull in the implementations for referenced types.

Important

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. Only declarations, not implementations, are automatically included.

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.Foundation
  • Windows.Foundation.Collections
  • Windows.Networking
  • Windows.Storage.Streams
  • Windows.Security.Cryptography

In other words, some APIs are forward-declared in a header that you've included. But their definitions are in a header that you haven't yet included. So, if you then call Windows::Foundation::Uri::RawUri, then you'll receive a linker error indicating that the member is undefined. The solution is to explicitly #include <winrt/Windows.Foundation.h>. In general, when you see a linker error such as this, include the header named for the API's namespace, and rebuild.

Accessing members via the object, via an interface, or via the ABI

With the C++/WinRT projection, the runtime representation of a Windows Runtime class is no more than the underlying ABI interfaces. But, for your convenience, you can code against classes in the way that their author intended. 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 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.

This convenience is achieved via a query for the appropriate interface. But you're always in control. 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. In the code example below, you obtain an actual IStringable interface pointer at run time (via a one-time query). 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/");

You might choose this technique if you know you'll be calling several methods on the same interface.

Incidentally, if you do want to access members at the ABI level then you can. 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.
}

Delayed initialization

In C++/WinRT, each projected type has a special C++/WinRT std::nullptr_t constructor. 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. So, that rule applies anywhere that the default constructor is used, such as uninitialized local variables, uninitialized global variables, and uninitialized member variables.

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 your variable or field using that special C++/WinRT std::nullptr_t constructor (which the C++/WinRT projection injects into every runtime class). 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();
}

All constructors on the projected type except the std::nullptr_t constructor cause a backing Windows Runtime object to be created. The std::nullptr_t constructor is essentially a no-op. It expects the projected object to be initialized at a subsequent time. So, whether a runtime class has a default constructor or not, you can use this technique for efficient delayed initialization.

This consideration affects other places where you're invoking the default constructor, such as in vectors and maps. Consider this code example, for which you'll need a Blank App (C++/WinRT) project.

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

The assignment creates a new TextBlock, and then immediately overwrites it with value. Here's the remedy.

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

Also see How the default constructor affects collections.

Don't delay-initialize by mistake

Be careful that you don't invoke the std::nullptr_t constructor by mistake. The compiler's conflict resolution favors it over the factory constructors. 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.
}

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). First, let's look at the wrong way to do that. We know that there'a Gift constructor that takes a GiftBox. 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) };

What you get here is an uninitialized Gift. You don't get a Gift with an uninitialized GiftBox. 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 }) };

In the incorrect example, passing a nullptr literal resolves in favor of the delay-initializing constructor. To resolve in favor of the factory constructor, the type of the parameter must be a GiftBox. You still have the option to pass an explicitly delay-initializing GiftBox, as shown in the correct example.

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.

It's only when you pass a nullptr literal that the ambiguity arises.

Don't copy-construct by mistake.

This caution is similar to the one described in the Don't delay-initialize by mistake section above.

In addition to the delay-initializing constructor, the C++/WinRT projection also injects a copy constructor into every runtime class. It's a single-parameter constructor that accepts the same type as the object being constructed. The resulting smart pointer points to the same backing Windows Runtime object as that pointed to by its constructor parameter. The result is two smart pointer objects pointing to the same backing object.

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.
}

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) };

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) };

If the API is implemented in a Windows Runtime component

This section applies whether you authored the component yourself, or it came from a vendor.

Note

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.

In your application project, reference the Windows Runtime component's Windows Runtime metadata (.winmd) file, and build. During the build, the cppwinrt.exe tool generates a standard C++ library that fully describes—or projects—the API surface for the component. In other words, the generated library contains the projected types for the component.

Then, just as for a Windows namespace type, you include a header and construct the projected type via one of its constructors. 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/BankAccountWRC.h>

struct App : implements<App, IFrameworkViewSource, IFrameworkView>
{
    BankAccountWRC::BankAccount bankAccount;
    ...
};

For more details, code, and a walkthrough of consuming APIs implemented in a Windows Runtime component, see Author events in C++/WinRT.

If the API is implemented in the consuming project

A type that's consumed from XAML UI must be a runtime class, even if it's in the same project as the XAML.

For this scenario, you generate a projected type from the runtime class's Windows Runtime metadata (.winmd). Again, you include a header, but this time you construct the projected type via its std::nullptr_t constructor. 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. 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.

You'll need a Blank App (C++/WinRT) project for this code example.

// 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>();
    ...
}

For more details, code, and a walkthrough of consuming a runtime class implemented in the consuming project, see XAML controls; bind to a C++/WinRT property.

Instantiating and returning projected types and interfaces

Here's an example of what projected types and interfaces might look like in your consuming project. 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 is a projected type; projected interfaces include IMyRuntimeClass, IStringable, and IClosable. This topic has shown the different ways in which you can instantiate a projected type. 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>();
  • You can access the members of all of the interfaces of a projected type.
  • You can return a projected type to a caller.
  • Projected types and interfaces derive from winrt::Windows::Foundation::IUnknown. 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. The as member function works like QueryInterface.
void f(MyProject::MyRuntimeClass const& myrc)
{
    myrc.ToString();
    myrc.Close();
    IClosable iclosable = myrc.as<IClosable>();
    iclosable.Close();
}

Activation factories

The convenient, direct way to create a C++/WinRT object is as follows.

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

But there may be times that you'll want to create the activation factory yourself, and then create objects from it at your convenience. 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 account = factory.CreateUri(L"http://www.contoso.com");

The classes in the two examples above are types from a Windows namespace. In this next example, BankAccountWRC::BankAccount is a custom type implemented in a Windows Runtime Component.

auto factory = winrt::get_activation_factory<BankAccountWRC::BankAccount>();
BankAccountWRC::BankAccount account = factory.ActivateInstance<BankAccountWRC::BankAccount>();

Member/Type ambiguities

When a member function has the same name as a type, there's ambiguity. The rules for C++ unqualified name lookup in member functions cause it to search the class before searching in namespaces. The substitution failure is not an error (SFINAE) rule doesn't apply (it applies during overload resolution of function templates). 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>() };
    }
}

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. 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>();
    }
}

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. This allows you to do things like this.

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

The call to Visibility() resolves to the UIElement.Visibility member function name. But the parameter Visibility::Collapsed follows the word Visibility with ::, and so the method name is ignored, and the compiler finds the enum class.

Important APIs