August 29th, 2012

C++/CX Part 0 of [n]: An Introduction

Hello; I’m James McNellis, and I’ve recently joined the Visual C++ team as a libraries developer. My first encounter with the C++/CX language extensions was early last year, while implementing some code generation features for the Visual Studio 2012 XAML designer. I started off by hunting for some example code, and it suffices to say that I was a bit surprised with what I first saw. My initial reaction was along the lines of:

“What the heck are these hats doing in this C++ code?”

Actually, I was quite worried; because I thought it was C++/CLI—managed code. Not that managed code is bad, per se, but I’m a C++ programmer, and I had been promised native code.

Thankfully, my initial impression was uninformed and wrong: while C++/CX is syntactically similar to C++/CLI and thus looks almost the same in many ways, it is semantically quite different. C++/CX code is native code, no CLR required. Programming in C++/CLI can be very challenging, as one must deftly juggle two very different object models at the same time: the C++ object model with its deterministic object lifetimes, and the garbage-collected CLI object model. C++/CX is much simpler to work with, because the Windows Runtime, which is based on COM, maps very well to the C++ programming language.

Windows Runtime defines a relatively simple, low-level Application Binary Interface (ABI), and mandates that components define their types using a common metadata format. C++/CX is not strictly required to write a native Windows Runtime component: it is quite possible to write Windows Runtime components using C++ without using the C++/CX language extensions, and Visual C++ 2012 includes a library, the Windows Runtime C++ Template Library (WRL), to help make this easier. Many of the Windows Runtime components that ship as part of Windows (in the Windows namespace) are written using WRL. There’s no magic in C++/CX: it just makes writing Windows Runtime components in C++ much, much simpler and helps to cut the amount of repetitive and verbose code that you would have to write when using a library-based solution like WRL.

The intent of this series of articles is to discuss the Windows Runtime ABI and to explain what really happens under the hood when you use the C++/CX language constructs, by demonstrating equivalent Windows Runtime components written in C++ both with and without C++/CX, and by showing how the C++ compiler actually transforms C++/CX code for compilation.

Recommended Resources

There are already quite a few great sources of information about C++/CX, and I certainly don’t intend for a simple series of blog articles to replace them, so before we begin digging into C++/CX, I wanted to start with a roundup of those resources.

First, if you’re interested in the rationale behind why the C++/CX language extension were developed and how the C++/CLI syntax ended up being selected for reuse, I’d recommend Jim Springfield’s post on this blog from last year, “Inside the C++/CX Design”. Also of note is episode 3 of GoingNative, in which Marian Luparu discusses C++/CX.

If you’re new to C++/CX (or Windows Store app and Windows Runtime component development in general), and are looking for an introduction to building software with C++/CX, or if you’re building something using C++/CX and are trying to figure out how to accomplish a particular task, I’d recommend the following resources as starting points:

  • Visual C++ Language Reference (C++/CX): The language reference includes a lot of useful information, including a C++/CX syntax reference with many short examples demonstrating its use. There’s also a useful walkthrough of how to build a Windows Store app using C++/CX and XAML. If you’re just starting out, this would be a great place to start.

  • C++ Metro style app samples: Most of the C++ sample applications and components make use of C++/CX and many demonstrate interoperation with XAML.

  • Component Extensions for Runtime Platforms: This used to be the documentation for C++/CLI, but it has since been updated to include documentation for C++/CX, with comparisons of what each syntactic feature does in each set of language extensions.

  • Hilo is an example application, written using C++, C++/CX, and XAML, and is a great resource from which to observe good coding practices—both for modern C++ and for mixing ordinary C++ code with C++/CX.

  • Building Metro style apps with C++ on MSDN Forums is a great place to ask questions if you are stuck.

Tools for Exploration

Often, the best way to learn about how the compiler handles code is to take a look at what the compiler outputs. For C++/CX, there are two outputs that are useful to look at: the metadata for the component, and the generated C++ transformation of the C++/CX code.

Metadata: As noted above, Windows Runtime requires each component to include metadata containing information about any public types defined by the component and any public or protected members of those types. This metadata is stored in a Windows Metadata (WinMD) file with a .winmd extension. When you build a Windows Runtime component using C++/CX, the WinMD file is generated by the C++ compiler; when you build a component using C++ (without C++/CX), the WinMD file is generated from IDL. WinMD files use the same metadata format as .NET assemblies.

If you want to know what types have been fabricated by the C++ compiler to support your C++/CX code, or how different C++/CX language constructs appear in metadata, it is useful to start by inspecting the generated WinMD file. Because WinMD files use the .NET metadata format, you can use the ildasm tool from the .NET Framework SDK to view the contents of a WinMD file. This tool doesn’t do much interpretation of the data, so it can take some getting used to how it presents data, but it’s very helpful nonetheless.

Generated Code: When compiling C++/CX code, the Visual C++ compiler transforms most C++/CX constructs into equivalent C++ code. If you’re curious about what a particular snippet of C++/CX code really does, it’s useful to take a look at this transformation.

There is a top-secret compiler option, /d1ZWtokens, which causes the compiler to print the generated C++ code that it generated from your C++/CX source. (Ok, this compiler option isn’t really top secret: Deon Brewis mentioned it in his excellent //BUILD/ 2011 presentation, “Under the covers with C++ for Metro style apps.” However, do note that this option is undocumented, and thus it is unsupported and its behavior may change at any time.)

The output is intended for diagnostic purposes only, so you won’t be able to just copy and paste the output and expect it to be compilable as-is, but it’s good enough to demonstrate how the compiler treats C++/CX code during compilation, and that makes this option invaluable. The output is quite verbose, so it is best to use this option with as small a source file as possible. The output includes any generated headers, including the implicitly included <vccorlib.h>. I find it’s often best to use types and members with distinctive names so you can easily search for the parts that correspond to your code.

There are two other useful compiler options, also mentioned in Deon’s presentation, which can be useful if you want to figure out how class hierarchies and virtual function tables (vtables) are laid out. The first is /d1reportAllClassLayout, which will cause the compiler to print out the class and vtable layouts for all classes and functions in the translation unit. The other is /d1reportSingleClassLayoutClyde which will cause the compiler to print out the class and vtable layouts for any class whose name contains “Clyde” (substitute “Clyde” for your own type name). These options are also undocumented and unsupported, and they too should only be used for diagnostic purposes.

Next Up…

In our next article (which will be the first “real” article), we’ll introduce a simple C++/CX class and discuss how it maps to the Windows Runtime ABI.  The following is a list of all of the articles in this series that have been published so far:

0 comments

Discussion are closed.