cppwinrt.exe in the Windows SDK

C++/WinRT shipped inside the Windows SDK (17025) for the first time at the beginning of November. The SDK included the C++/WinRT headers, so you don’t have to first get them from GitHub. Instead, you can simply include the appropriate headers from within any C++ project and start writing modern C++ code using the Windows API.

I’m happy to announce that today’s update to the Windows SDK (17035) now also includes the C++/WinRT compiler (cppwinrt.exe). While you don’t need to run the compiler yourself for most scenarios, it can come in handy if you need to use a third-party WinRT component and is needed for authoring your own WinRT components with C++/WinRT. You can also use it to produce custom projections for your own set of .winmd files.

Scott Jones first demonstrated this at CppCon earlier this year. You can watch our whole CppCon 2017 talk here:

Eventually we will have C++/WinRT fully integrated into Visual Studio, but until then you must do a little bit of work to get it all integrated smoothly. Last time I showed you how to start using the C++/WinRT headers from with Visual C++ 2017 projects. I have also prepared a set of sample projects that you can use as a starting point. You can find them here:

https://github.com/kennykerr/cppwinrt

These samples work with today’s update of the Windows SDK and there are a variety of samples that will get you going with desktop as well as store apps. There are samples that illustrate various interop scenarios and there’s even a complete example of authoring a WinRT component.

Still, I know a lot of developers are anxious to try out the C++/WinRT compiler itself. Let me show you how to get started, but keep in mind that this is still considered experimental and subject to change. We are however more than happy to answer any questions you have over on the GitHub issues page. If you’d like to follow along, open a developer command prompt. I usually use the x86 Native Tools Command Prompt for VS 2017. Assuming you’ve installed the Windows SDK, you should find cppwinrt.exe in the path. You can double check by using the where command. It should look something like this:

> where cppwinrt

C:\Program Files (x86)\Windows Kits\10\bin\10.0.17035.0\x86\cppwinrt.exe

You can also run the cppwinrt command itself to explore some of the available features and options.

> cppwinrt

C++/WinRT v1.0.170906.1
Copyright (c) 2017 Microsoft Corporation. All rights reserved.

  cppwinrt.exe [options...]

Options:

  -in     <spec>      Winmd files to include in projection
  -ref    <spec>      Winmd files to reference from projection
  -out    <path>      Location of generated projection files
  -component          Generate component implementation source files
  -filter <prefix>    One or more prefixes to include in component
  -name   <name>      Assume this component name to shorten file names
  -natvis             Generate a natvis script for debug visualization
  -verbose            Show detailed progress information
  -overwrite          Overwrite existing component projection files
  -help               Show detailed help with examples
  @<path>             Response file containing command line options

Where <spec> is one or more of:

  path                Path to winmd file or recursively scanned folder
  local               Local %WinDir%\System32\WinMetadata folder
  10.0.15063.0        Specific version of Windows SDK

As you might imagine from looking at the options, I often call cppwinrt a compiler because it reads some set of input files and writes a corresponding set of output files. Let’s begin with a concrete example tailored to developers using Windows Insider builds. Let’s imagine you get a new build and immediately want to try some new functionality, but the matching Windows SDK build is inexplicably delayed. I know that never happens, but play along. No problem, you can use the local option and produce a projection for the build of Windows you happen to be running on:

> cppwinrt -in local

You should find that a local folder called winrt was just created and it includes quite a few headers. You can get a bit more visibility into what’s happening by using the verbose option:

> cppwinrt -in local -verbose

 in:   C:\WINDOWS\System32\WinMetadata\Windows.ApplicationModel.winmd
 in:   C:\WINDOWS\System32\WinMetadata\Windows.Data.winmd
 in:   C:\WINDOWS\System32\WinMetadata\Windows.Devices.winmd
 in:   C:\WINDOWS\System32\WinMetadata\Windows.Foundation.winmd
 in:   C:\WINDOWS\System32\WinMetadata\Windows.Gaming.winmd
 in:   C:\WINDOWS\System32\WinMetadata\Windows.Globalization.winmd
 in:   C:\WINDOWS\System32\WinMetadata\Windows.Graphics.winmd
 in:   C:\WINDOWS\System32\WinMetadata\Windows.Management.winmd
 in:   C:\WINDOWS\System32\WinMetadata\Windows.Media.winmd
 in:   C:\WINDOWS\System32\WinMetadata\Windows.Networking.winmd
 in:   C:\WINDOWS\System32\WinMetadata\Windows.Perception.winmd
 in:   C:\WINDOWS\System32\WinMetadata\Windows.Security.winmd
 in:   C:\WINDOWS\System32\WinMetadata\Windows.Services.winmd
 in:   C:\WINDOWS\System32\WinMetadata\Windows.Storage.winmd
 in:   C:\WINDOWS\System32\WinMetadata\Windows.System.winmd
 in:   C:\WINDOWS\System32\WinMetadata\Windows.UI.Xaml.winmd
 in:   C:\WINDOWS\System32\WinMetadata\Windows.UI.winmd
 in:   C:\WINDOWS\System32\WinMetadata\Windows.Web.winmd
 out:  C:\sample
 time: 2890ms

Now you can see clearly what the local input represents and where the output was written, in this case into the local folder. Unfortunately, the version of cppwinrt.exe that ships in the SDK is a few weeks behind our internals builds. More recent builds of the compiler complete in about a third of the time (due to a coroutine optimizer bug). It also means that there are a few known bugs in this version of the compiler, but do let us know if you run into any difficulties.

Now that you’ve created a projection, you can use it just as you would the one included with the Windows SDK. Of course, keep in mind that you now have access to various APIs that may be subject to change. Still, you can quickly test that it works with a simple console app:

> type sample.cpp

#pragma comment(lib, "windowsapp")
#include "winrt/Windows.Foundation.Metadata.h"

using namespace winrt;
using namespace Windows::Foundation::Metadata;

int main()
{
    init_apartment();

    bool const rs4 = ApiInformation::IsApiContractPresent(L"Windows.Foundation.UniversalApiContract", 6);

    printf("Am I running on Redstone 4? %s\n", rs4 ? "Yes!" : "No. :(");
}

Then simply use the C++ compiler with exception handling and C++17 support:

C:\sdk>cl /EHsc /std:c++17 sample.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 19.11.25547 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

sample.cpp
Microsoft (R) Incremental Linker Version 14.11.25547.0
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:sample.exe
sample.obj

The sample app will then tell you whether you’re running on a Redstone 4 build of Windows:

> sample.exe

Am I running on Redstone 4? Yes!

Naturally, you can use cppwinrt to target more than just the local machine. It is more typical that you would need a projection for a specific version of the Windows SDK. For example, here’s how you can create projection for the Fall Creators Update (Redstone 3):

> cppwinrt -in 10.0.16299.0 -verbose

This of course presupposes that you have the 16299 build of the Windows SDK installed. I’ll save you the output, but it should be evident from the verbose output which set of .winmd files it used to create the projection.

What about a third-party component? Imagine some developer sent you a DLL as well as a .winmd file describing a component that you would like to make use of. And I know you’re going to ask and the answer is no, this won’t work with Win2D today because the version of cppwinrt.exe that ships with the Windows SDK has a bug that gets in the way. Our internal builds have supported Win2D for some time and I’m told the next Windows SDK will have the fixes, hopefully later this month. Now consider a different component:

> dir /b Component.*

Component.dll
Component.winmd

That’s all you need from the author of the component. You can now create a projection for this component as follows:

> cppwinrt -in Component.winmd -ref local -out Component

In the previous example the input was some version of the Windows SDK. Now the input is the particular .winmd representing the WinRT component. The ref option tells the compiler which underlying set of .winmds represent the platform that this component refers to. It might for example have a parameter of some type defined by Windows itself or perhaps implement a common interface like Windows.Foundation.IStringable. The cppwinrt compiler needs to know how to resolve those types and that’s what the ref option is for. Finally, the headers for the component should reside in their own folder and the C++ project can simply include the various folders as necessary.

Let’s now switch gears and look at a more concrete example inside Visual Studio. You can start by opening the Component solution in Visual Studio. It includes two projects, a store app written in C++/WinRT as well as a WinRT component also written in C++/WinRT. Naturally, you can also consume the component from a C# app if you wish. You can also use a desktop application with the help of Desktop Bridge if needed.

If you have a look at the components IDL file, you’ll notice the definition of a simple WinRT runtime class. The C++ project invokes the MIDL compiler to produce the aforementioned .winmd file. It then also invokes cppwinrt to create the headers representing the component in C++/WinRT, but it goes a step further and uses the component option to also produce any needed scaffolding to implement the runtime class with modern C++. Let’s change the IDL to see this in action. I’m going to add a method called Hide to the IButton2 interface:

[version(2.0), uuid(d3235252-4081-4cc8-b0e0-8c7691813845), exclusiveto(Button)]
interface IButton2 : IInspectable
{
    HRESULT Show();
    HRESULT Hide(); // <-- add this!
};

Building the project will cause MIDL to generate a new .winmd file, which will cause cppwinrt to update the headers and implementation scaffolding. All you’re left with is having to add the Hide method to the Button class. Inside the Button.h file you can add the declaration for the Hide method:

struct Button : ButtonT<Button>
{
    Button() = default;

    hstring Text();
    void Show();
    hstring ToString();

    void Hide(); // <-- add this!
};

It’s that ButtonT class template that cppwinrt updated with the expectation of the Hide method. Then inside the Button.cpp file you can add the definition:

void Button::Hide()
{
}

And that’s all it takes. Behind the scenes, C++/WinRT is doing a lot of work making sure this modern C++ translates into an efficient implementation of the ABI required by the Windows Runtime, but ensures that you can stick to modern or idiomatic C++ as part of your implementation.

C++/WinRT makes a clear distinction between your code and generated code. For example, the Button.h file may initially be generated by cppwinrt but is now your code to maintain and extend. On other hand, the Button.g.h file that it includes is always regenerated by cppwinrt and a warning at the top of the file reminds you of that. Of course, if you define a brand new runtime class in IDL for which there does not exist a .h and .cpp file to begin with, cppwinrt will go ahead and create those files to help you get started.

As I mentioned, we’re very busy improving C++/WinRT and you should expect regular updates and improvements over the next few months. Until next time, I hope you enjoy using C++/WinRT and the cppwinrt compiler.

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