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.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s