C++/WinRT: Understanding Async

Previous: Working with Strings

The Windows Runtime has a relatively simple async model in the sense that, like everything else in the Windows Runtime, it is focused on allowing components to expose async methods and making it simple for apps to call those async methods. It does not in itself provide a concurrency runtime or even anything in the way of building blocks for producing or consuming async methods. Instead, all of that is left up to the individual language projections. This is as it should be and is not meant to trivialize the Windows Runtime’s async pattern. It is no small feat to implement this pattern correctly. Of course, it also means that a developer’s perception of async in the Windows Runtime is very heavily influenced by their language of choice. A developer that has only ever used C++/CX might for example wrongly, but understandably, assume that async is a hot mess.

The ideal concurrency framework for the C# developer will be different to the ideal concurrency library for the C++ developer. The role of the language projection then is to take care of the mechanics of the async pattern and provide a natural bridge to a language-specific implementation.

Coroutines are the preferred abstraction for both implementing and calling async methods in C++, but first let’s make sure we understand how the async model works. Consider a class with a single static method that looks something like this:

struct Sample
{
    Sample() = delete;

    static Windows::Foundation::IAsyncAction CopyAsync();
};

Async methods end with “Async” by convention, so you might think of this as the Copy async method. There might be a blocking or synchronous alternative that is simply called Copy. It is conceivable that a caller might want a blocking Copy method for use by a background thread and a non-blocking, or asynchronous, method for use by a UI thread that cannot afford to block for fear of appearing unresponsive.

At first, the CopyAsync method may seem quite simple to call. I might write the following C++ code:

IAsyncAction async = Sample::CopyAsync();

As you might imagine, the resulting IAsyncAction is not actually the ultimate result of the async method, even as it is the result of calling the CopyAsync method in a traditional procedural manner. The IAsyncAction is the object that a caller may use to wait upon the result synchronously or asynchronously, depending on the situation. Along with IAsyncAction, there are three other well-known interfaces that follow a similar pattern and offer different features for the callee to communicate information back to the caller. The following table provides a comparison of the four async interfaces.

In C++ terms, the interfaces can be expressed as follows:

namespace Windows::Foundation
{
    struct IAsyncAction;

    template <typename Progress>
    struct IAsyncActionWithProgress;

    template <typename Result>
    struct IAsyncOperation;

    template <typename Result, typename Progress>
    struct IAsyncOperationWithProgress;
}

IAsyncAction and IAsyncActionWithProgress can be waited upon to determine when the async method completes, but these interfaces do not offer any observable result or return value directly. IAsyncOperation and IAsyncOperationWithProgress, on the other hand, expect the Result type parameter to indicate the type of result that can be expected when the async method completes successfully. Finally, IAsyncActionWithProgress and IAsyncOperationWithProgress expect the Progress type parameter to indicate the type of progress information that can be expected periodically for long-running operations up until the async method completes.

There are a few ways to wait upon the result of an async method. I won’t describe them all here since that would turn this into a very long article. Instead, I’ll save those for next time so that I can give them each the attention they deserve. While there are a variety of ways to handle async completion, there are only two that I recommend. Those two are the async.get() method, which performs a blocking wait, and the co_await async expression, which performs a cooperative wait in the context of a coroutine. Neither is better than the other as they simply serve different purposes. Let’s look at blocking wait today.

As I mentioned, a blocking wait can be achieved using the get() method as follows:

IAsyncAction async = Sample::CopyAsync();

async.get();

There’s seldom any value in holding on to the async object and the following form is thus preferred:

Sample::CopyAsync().get();

It’s important to keep in mind that the get method will block the calling thread until the async method completes. As such, it is not appropriate to use the get method on a UI thread since it may cause the app to become unresponsive. An assertion will fire in unoptimized builds if you attempt to do so. The get method is ideal for console apps or background threads where you may not want to use a coroutine for whatever reason.

Once the async method completes, the get method will return any result directly to the caller. In the case of IAsyncAction and IAsyncActionWithProgress, the return type is void. That might be useful for an async method that initiates a file copy operation, but less so for something like an async method that reads the contents of a file. Let’s add another async method to our example:

struct Sample
{
    Sample() = delete;

    static Windows::Foundation::IAsyncAction CopyAsync();
    static Windows::Foundation::IAsyncOperation<hstring> ReadAsync();
};

In the case of ReadAsync, the get method will properly forward the hstring result to the caller once the operation completes:

Sample::CopyAsync().get();

hstring result = Sample::ReadAsync().get();

Assuming execution returns from the get method, the resulting string will hold whatever value was returned by the async method upon its successful completion. Execution may not return, for example, if an error occurred but we’ll talk more about error handling later.

The get method is limited in the sense that it cannot be used from a UI thread, nor does it exploit the full potential of the machine’s concurrency, since it holds the calling thread hostage until the async method completes. Using a coroutine allows the async method to complete without holding such a precious resource captive for some indeterminate amount of time.

Join me next time as we explore more about async in the Windows Runtime.

C++/WinRT: Working with Strings

I think it’s high time I restarted the series on C++/WinRT, providing short “how to” and “how it works” articles to help developers understand some of the fundamental principles of the C++ language projection for the Windows Runtime. As a recap, here’s what I covered thus far:

Consumption and Production

Working with Implementations

Fun with Agility

Optimizing Activation

Working with Namespaces

C++/WinRT in the Windows SDK

cppwinrt.exe in the Windows SDK

C++/WinRT now ships in the Windows SDK and the cppwinrt compiler is also available. Visual Studio 2017 even provides tentative support, so there’s a lot to talk about. The original Getting Started assumed that you had to get the C++/WinRT headers from GitHub. That’s no longer the case, so let’s get started again but this time with Visual Studio and go from there. This guide will assume that you have installed Visual Studio 2017 15.6 or later as well as the Windows SDK for RS4 or later. The 15.6 update of Visual Studio 2017 provides command line support for C++/WinRT. While the Window SDK will ensure that cppwinrt.exe is available from a developer command prompt, it’s Visual Studio that ensures that the headers are in the include path.

The C++ language has a bad reputation when it comes to strings. Unlike many other languages, C++ doesn’t have a built-in type representing a string of text. Rather, the C++ library fills that gap by providing std::string and its variants. Inevitably, std::string doesn’t work for everyone and thus we land up with a myriad of string types to contend with. C++17 attempts to alleviate some of this pain with the introduction of string conversion utilities and the loveable but contentious std::string_view class. Of course, if that were the end of the story it would certainly have a happy ending.

Sadly, std::string is just one option. There’s also std::wstring, largely for Windows developers where wchar_t dominates. The trouble is that wchar_t is 2 bytes on Windows and represents UTF-16 characters whereas wchar_t is typically 4 bytes on most other platforms and represents UTF-32 characters. Then there’s the more explicit std::u16string and std::u32string. And on it goes.

So what’s the solution? We need another string type! Seriously, the idea of a universal string type for C++ is unrealistic today. Perhaps one day we’ll get there. Until then, we have a partial solution and that is the std::string_view to bridge the gap between different libraries and their unique requirements. While C++/WinRT has its own string type, it provides convertibility with std::wstring_view specifically to address this problem.

C++/WinRT requires its own string type because while WinRT uses wchar_t characters, the ABI itself is not a subset of what either std::wstring or std::wstring_view provides and using those would lead to significant inefficiency. Instead, C++/WinRT provides the winrt::hstring that represents an immutable string consistent with the underlying HSTRING, but in such a way that C++ developers can largely ignore the specifics of WinRT string management and just work with what they know and love about C++. Consider the following example:

using namespace Windows::Networking::Connectivity;

int main()
{
    for (auto&& host : NetworkInformation::GetHostNames())
    {
        hstring name = host.DisplayName();

        printf("%ls\n", name.c_str());
    }
}

GetHostNames returns a collection of HostName objects representing the various network names associated with the computer. I can then call DisplayName to get a string representation. Since DisplayName is a WinRT API it naturally returns an hstring, but notice that I could just as easily have used auto:

auto name = host.DisplayName();

printf("%ls\n", name.c_str());

Suddenly, this looks very much like std::wstring. Indeed, there’s no reason to have a named local. I can more concisely express it as follows:

printf("%ls\n", host.DisplayName().c_str());

As you can see, it looks and feels like std::wstring and provides many of the same type aliases and functions. We could have changed the cppwinrt compiler to generate API strings using std::wstring directly, but that would have been inefficient. Still, we aim to make it as transparent as possible. You can for example, pass an hstring to a function expecting a std::wstring_view:

void print(std::wstring_view text);

int main()
{
    for (auto&& host : NetworkInformation::GetHostNames())
    {
        print(host.DisplayName());
    }
}

Notice that I’m not calling c_str or any other conversion helper. Since the hstring is convertible to std::wstring_view – and at no cost – this just works. It works the other way as well. I can create a HostName object directly, perhaps in anticipation of creating a socket connection:

using namespace Windows::Networking;

int main()
{
    HostName host(L"moderncpp.com");
}

While the HostHame constructor technically expects an hstring, it’s quite happy if you pass it a string literal. In fact, this is often more efficient than creating an hstring yourself. You might instead have a std::wstring or just a std::wstring_view and that will work just as well:

int main()
{
    std::wstring name = L"moderncpp.com";

    HostName host(name);
}

What about a std::wstring_view literal? No problem:

using namespace std::literals;

int main()
{
    HostName host(L"moderncpp.com"sv);
}

If you’re really curious, you’ll notice that all of the input parameters that should logically accept a winrt::hstring really expect a winrt::param::hstring. The param namespace has a set of types that are used exclusively for optimizing input parameters to naturally bind to STL types and avoid copies as well as other inefficiencies. You should never use those types directly, but that’s where the magic happens to make this work efficiently for input. Again, you should never use those param types yourself. Don’t use them as an optimization for your own functions – just use std::wstring_view.

The hstring also provides all of the comparison operators so that you can naturally and efficiently compare against its counterparts in the C++ standard library. It also includes everything you need to use hstring as a key for associative containers if need be. We also recognize that many C++ libraries use std::string and work exclusively with UTF-8 text. As a convenience, we provide helpers for converting back and forth as well:

hstring w = L"hello world";

std::string c = to_string(w);
assert(c == "hello world");

w = to_hstring(c);
assert(w == L"hello world");

As a team, we spend a lot of time focusing on performance. That includes machine instructions, but it also includes binary size. All of that comes into play when we talk about strings because of how heavily strings are used in the Windows Runtime. There are many other optimizations and affordances we provide for strings, but hopefully this gives you a good idea of how to make use of strings with C++/WinRT.

Variadic generators in C++

Coroutines allow us to write generators that yield values such that a function can effectively return multiple values. The coroutine return type can then provide begin and end functions and thus behave like an STL container or range expression. If you have Visual C++ handy, you can follow along using its simple experimental generator:

#include <experimental/generator>
using namespace std::experimental;

We can write a function that will produce a sequence of values as follows:

generator<int> get_values()
{
    co_yield 1;
    co_yield 2;
    co_yield 3;
}

From the caller’s perspective, it behaves much the same as if the get_values function had been written as follows:

std::vector<int> get_values()
{
    return { 1, 2, 3 };
}

The difference is that the coroutine does not require the container to be prepared in advance (or even allocated), but the caller can simply rely on the resulting range expression and write the same range-based for loop regardless:

int main()
{
    for (int value : get_values())
    {
        printf("%d\n", value);
    }
}

As you might expect, the results are staggering:

1
2
3
Press any key to continue . . .

But that’s not very interesting. Let’s imagine we have two (or more) containers with numbers as follows:

std::vector<int> a{ 1, 2, 3 };
std::vector<int> b{ 4, 5, 6 };

And we’d like to use the same simple range-based for loop to print out all their values:

for (int value : get_container_values(a, b))
{
    printf("%d\n", value);
}

How might we achieve that? With variadics of course. First we need to write a generalized get_values function that can effectively turn a parameter pack into a range:

template <typename First, typename ... Rest>
generator<First> get_values(First const& first, Rest const& ... rest)
{
    int ignored[] = { (co_yield first, 0), (co_yield rest, 0) ... }; ignored;
}

We need to separate out the first template argument from the parameter pack so that we can identify the type of the resulting generator. We then simply expand the function arguments and yield up each value in turn.

With this version of get_values, we can now write a more generalized version of the original example as follows:

for (int value : get_values(1, 2, 3))
{
    printf("%d\n", value);
}

No longer does the get_values function need to hardcode the values to yield to the caller and it works with types other than int. Using get_values as a building block, we can then write the get_container_values function that will iterate over its arguments and then iterate over each container’s values, yielding each in turn:

template <typename First, typename ... Rest, typename Value = First::value_type>
generator<Value> get_container_values(First const& first, Rest const& ... rest)
{
    for (First const& current : get_values(first, rest ...))
    {
        for (Value const& value : current)
        {
            co_yield value;
        }
    }
}

Again, the first template argument must be separated to determine the type of the resulting generator. The get_values function is used to produce a range from the get_container_values arguments. Could this be implemented without coroutines? Sure, but not nearly as simply and most likely involving copies of containers and elements. The get_container_values function will not make a copy of a single element.

We can now write the following simple program:

int main()
{
    std::vector<int> a{ 1, 2, 3 };
    std::vector<int> b{ 4, 5, 6 };

    for (int value : get_container_values(a, b))
    {
        printf("%d\n", value);
    }
}

The results are beautifully simple:

1
2
3
4
5
6
Press any key to continue . . .

C++/WinRT: Working with Namespaces

Previous: Optimizing Activation

The Windows Runtime adopted namespaces as part of its type system. This works rather well since most languages targeting the Windows Runtime support namespaces in a fairly uniform way. Unfortunately, C++ has a bit more history than most languages and that is certainly true when it comes to the Windows platform. The problem is that C++/WinRT was not the first language projection for C++. C++/CX may not have been standard C++, but it exists within the Visual C++ compiler such that it causes problems when porting a project from C++/CX to C++/WinRT and especially when gradually migrating from one to the other. Then there’s the Windows SDK with its own historical complications.

Fortunately, C++/WinRT was designed with all of this in mind. The Windows SDK ships with headers describing the Windows Runtime APIs in standard C++. This is known as an ABI rather than a language projection since its really just a bunch of COM interface declarations and no attempt is made to “project” it into modern C++. I might use the IStringable type as follows:

#include <windows.foundation.h>
using namespace ABI::Windows::Foundation;

IStringable * stringable = ...

HSTRING value = nullptr;
HRESULT hr = stringable->ToString(&value);

Naturally you might want to use smart pointers and handle wrappers here, but that’s not part of the ABI. Notice that the windows.foundation.h header introduces a root ABI namespace in which the “Windows.Foundation.IStringable” type is declared. This is a good thing for the SDK to do. Technically, it’s the MIDL compiler that prepends this lovely disambiguator. C++/WinRT takes much the same approach to namespaces:

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

IStringable stringable = ...

winrt::hstring value = stringable.ToString();

Notice that instead of the ABI root namespace, I’m now using the winrt root namespace. The Windows namespace, or any other namespace found in a Windows Metadata (.winmd) file, will be safely nested within the respective root namespaces. This is significant because it means that you can use the two together in the same project. There’s a way to disambiguate type names.

And then comes C++/CX and it blissfully thinks it lives on an island all on its own:

using namespace Windows::Foundation;

IStringable ^ stringable = ...

Platform::String ^ value = stringable->ToString();

Notice that there’s no root namespace clearly identifying this “Windows” from any other. Here “Windows” is the root namespace. That’s a bit of a drag. There are also various culprits in the Windows SDK, headers that inexplicably chose not to use the ABI root namespace. What to do?

All is not lost. Naturally, if you’re starting a new project then you can just ignore the ABI from the Windows SDK and you can just avoid C++/CX entirely:

using namespace winrt;
using namespace Windows::Foundation;

IStringable stringable = ...

hstring value = stringable.ToString();

Here I start with a using directive, allowing unqualified name lookup for anything in the winrt namespace. This is the simplest and most convenient route. You might still need to include the ABI headers from the Windows SDK. Perhaps to access an interop API not described in Windows metadata. But you must be explicit about it. Simply adding a using directive will not work:

using namespace winrt;
using namespace Windows::Foundation;
using namespace ABI::Windows::Foundation; // error!

The compiler will tell you that the ABI namespace is ambiguous. That’s because the winrt namespace itself includes its own ABI representation in the winrt::ABI namespace. You might try to be explicit as follows:

using namespace winrt;
using namespace Windows::Foundation;
using namespace ::ABI::Windows::Foundation;

IStringable stringable = ... // error!

But that won’t work either. Now the IStringable type name is ambiguous since that name could refer to either winrt::Windows::Foundation::IStringable or ABI::Windows::Foundation::IStringable.

The same problem occurs when mixing C++/CX with C++/WinRT or the Windows SDK for that matter. This is certainly not a problem that C++/WinRT introduced. One solution is just to be explicit:

winrt::Windows::Foundation::IStringable stringable = ...

While that works, it’s far from convenient. Another solution is to create namespace aliases for the different islands and use those instead:

namespace cx
{
    using namespace ::Windows::Foundation;
}

namespace sdk
{
    using namespace ::ABI::Windows::Foundation;
}

namespace winrt
{
    using namespace Windows::Foundation;
}

I can now unambiguously refer to the IStringable representation from all three type systems in a single program quite conveniently:

int main()
{
    cx::IStringable ^ hat = ...
    sdk::IStringable * pointer = ...
    winrt::IStringable value = ...
}

Any additional namespaces can easily be added as required:

namespace winrt
{
    using namespace Windows::Foundation;
    using namespace Windows::Web::Syndication;
}

Again, this is only required for backward compatibility and in a few other relatively rare cases where you might need to interop between these disparate manifestations of the Windows Runtime APIs.

Join me next time as we continue to explore C++/WinRT. Give C++/WinRT a try today. Got a question? Post it here and we’ll do our best to help.

C++/WinRT: Optimizing Activation

Previous: Fun with Agility

Activation and agility have a strange relationship. In the last installment, I talked about agility, but agility also has an impact on activation. When I talk about activation I mean those things that the language projection (any language projection) must do in order to interact with runtime classes. This might be calling some constructor like this:

using namespace Windows::UI::Xaml::Media;

FontFamily font(L"Consolas");

Or it might be calling some static method like this:

using namespace Windows::UI::Xaml;

Window window = Window::Current();

In either case, activation is at play. That’s because in both cases, the activation factory for the runtime class must be retrieved. In the first example, the “Windows.UI.Xaml.Media.FontFamily” activation factory is what actually creates the FontFamily object under the hood. In the second example, it is the “Windows.UI.Xaml.Window” activation factory that actually implements the “Current” property.

Optimizing activation is all about making the retrieval of the activation factory as efficient as possible. James and I talked about how this is done in this presentation at CppCon 2016. The gist of it is that if the activation factory is agile then it can simply be cached via a magic static. Of course, if the activation factory is not agile then it would not be safe to do so since that would allow the factory object to be accessed from a different apartment to the one in which it was created.

Activation factories should be agile, but sadly some are not. Caching agile activation factories is safe since the cached pointer may be used by any thread from any apartment. Non-agile activation factories may only be used by threads from the same apartment and the overhead of managing a per-apartment cache is prohibitive. Non-agile activation factories are also the source of a variety of bugs. We are moving to a world where all activation factories will be agile. This is the most reliable and efficient model, but we need this fallback in C++/WinRT to deal with existing non-agile factories.

One of the nice things about C++/WinRT is that it is a header-only library. That means you can step into those constructors and static methods above and see how they map to the underlying WinRT plumbing. In both cases, you’ll see that they eventually call this function:

template <typename Class, typename Interface = Windows::Foundation::IActivationFactory>
Interface get_activation_factory()
{
    static Interface factory = impl::get_agile_activation_factory<Class, Interface>();

    if (!factory)
    {
        return impl::get_activation_factory<Class, Interface>();
    }

    return factory;
}

How this function is implemented is an implementation detail but you can clearly see what’s going on. The internal get_agile_activation_factory function will only return a valid factory object if the factory implements the IAgileObject interface. This check is done on demand and once per process. Due to the proliferation of required interfaces and static members in the Windows Runtime, the ability to optimize activation factory access is vital in building high-performance apps and components. As we illustrated at CppCon, the approach taken by C++/WinRT performs substantially better than C++/CX. I have also successfully campaigned within Microsoft to have all activation factories eventually becoming agile. This will provide significant performance wins for both existing and new apps targeting the Windows platform. The good news is that there’s nothing you need to do to opt in to this performance. C++/WinRT will give you the best possible performance today and your apps will only get faster as more of the Windows Runtime switches to agile activation factories.

Join me next time as we continue to explore C++/WinRT. Give C++/WinRT a try today. Got a question? Post it here and we’ll do our best to help.

Next: Working with Namespaces

C++/WinRT: Fun with Agility

Previous: Working with Implementations

For the most part, every COM and WinRT object should be agile. This is a good default unless you have a compelling reason to require an object to reside in a given single-threaded apartment. This typically has to do with reentrancy requirements. Increasingly, APIs that provide services for building user experiences are offering objects that are agile. This tends to provides the best performance and avoids all kinds of problems. Certainly, if you’re implementing an activation factory you must ensure that it is agile even if the runtime class is not. So how does C++/WinRT help or support working with agility?

Here’s a simple example of an implementation:

using namespace Windows::Foundation;

struct Sample : implements<Sample, IStringable>
{
    hstring ToString()
    {
        return L"Sample";
    }
};

This implementation is agile by default. What that means is that unless you say otherwise, the implements class template will implement both IAgileObject and IMarshal. The latter simply uses CoCreateFreeThreadedMarshaler to do the right thing for legacy code that doesn’t know about IAgileObject. So how does one check for agility?

com_ptr<IAgileObject> agile = sample.as<IAgileObject>();

The as method will throw an exception if the sample object is not agile (the query for IAgileObject failed). To avoid the exception, you can use try_as instead:

com_ptr<IAgileObject> maybe = sample.try_as<IAgileObject>();

if (maybe)
{
    // yep, sample is agile!
}

Of course, the IAgileObject interface has no methods beyond those inherited from IUnknown. So, it’s more typical that you might write code like this:

if (sample.try_as<IAgileObject>())
{
    // yep, sample is agile!
}

You see, the IAgileObject interface is just a “marker” interface. The success or failure of the query tells you something. The interface itself is useless. What if you really don’t want an agile implementation? No problem, you can simply request that when you define your implementation:

struct Sample : implements<Sample, non_agile, IStringable>
{
    ...
};

Now, if you run the following check it will report that the object is not agile:

if (sample.try_as<IAgileObject>())
{
    printf("I'm agile :)\n");
}
else
{
    printf("I'm not agile :(\n");
}

And it doesn’t matter where in the variadic parameter pack non_agile appears:

struct Sample : implements<Sample, IStringable, IClosable, non_agile>
{
    ...
};

Of course, this doesn’t preclude you from implementing IMarshal yourself. You might use non_agile to avoid the default agility implementation and then go and implement IMarshal yourself, perhaps to support marhal-by-value semantics.

Now what if you have some poor object that’s not agile but you need to pass it around in some potentially agile context? No problem, the agile_ref helpers comes to the rescue:

IStringable sample = make<Sample>();

You can wrap it inside an agile_ref as follows:

agile_ref<IStringable> ref = sample;

The ref object may be freely passed to a thread in a different apartment:

co_await resume_background();

IStringable local = ref.get();

hstring value = local.ToString();

The get method returns a proxy that may safely be used within the thread context in which the get method was called.

I hope that helps. Join me next time as we continue to explore C++/WinRT. Give C++/WinRT a try today. Got a question? Post it here and we’ll do our best to help.

Next: Optimizing Activation

C++/WinRT: Working with Implementations

Previous: Consumption and Production

Consider the following simple class that implements both the IStringable interface and the IClosable interface. These interfaces were chosen for their simplicity and don’t hold any special status in C++/WinRT (unlike C++/CX).

using namespace Windows::Foundation;

struct Sample : implements<Sample, IStringable, IClosable>
{
    hstring ToString()
    {
        return L"Sample";
    }

    void Close()
    {
    }
};

Clearly this class implements IStringable and IClosable but how do I go from an implementation to an IStringable or IClosable object that I can use or return as part of the projection? There are actually a few options. I alluded to the make function template in the previous installment. The make function returns the first interface implemented by Sample:

IStringable a = make<Sample>();

This is most useful if I’m passing the result directly to a caller. Alternatively, I can specify another interface that the implementation provides:

IClosable b = make<Sample, IClosable>();

Sometimes I might need to get the implementation right away and only later return an interface to some caller. In that case, the make_self function template is what I need:

com_ptr<Sample> c = make_self<Sample>();

Notice that I’ve effectively stepped out of the projection. The Sample class is not part of the projection. It’s my implementation, but I can certainly call its implementation methods directly (without the overhead of a virtual function call):

com_ptr<Sample> c = make_self<Sample>();
hstring h = c->ToString();

Even though the ToString method uses the same signature as the projected IStringable method, here I’m calling that non virtual method directly without crossing the ABI. Since the com_ptr simply holds a pointer to the Sample class, I can also access any other internal details of the implementation.

Finally, if I have an interface and I happen to know that it’s my implementation then I can get back to the implementation using the get_self function template:

IStringable a = make<Sample>();

Sample * impl = get_self<Sample>(a);

hstring h = impl->ToString();

Again, this can be used to avoid vcalls and get directly at the implementation but the original object still holds the reference. So if I want to hold on to it I might want to do something like this:

com_ptr<Sample> impl;
impl.copy_from(get_self<Sample>(a));

The copy_from function will ensure that AddRef is called.

This is just a few of the ways you can interact with and manage implementations. Join me next time as we continue to explore C++/WinRT. Give C++/WinRT a try today. Got a question? Post it here and we’ll do our best to help.

Next: Fun with Agility