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

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

Rate This
  • Comments 65

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:

  • @jalf:  It looks like other Intellisense features (e.g., Go to Definition) do not work with identifiers like "interface."  I'll talk with our IDE team to see whether that's a known issue and will open a bug if required.

    @atch666:  A comment in reply to your comment from 5 Sep 2012 1:07 AM:  Windows Runtime does not support multiple inheritance (and hierarchies of public types are only permitted in a small set of scenarios); this is a restriction imposed by the runtime (and, in a sense, the metadata format), not one imposed by the C++/CX language extensions.  A T^ may be reinterpreted as a T*, which makes interoperation of hats and ComPtr smart pointers fairly straightforward.

    @Krzysztof Kawa:  I'm curious about your statement that "WRL is not an answer, it's just horrible."  Are there particular features (or lack-of-features) that you dislike?  Do you have any suggestions on what would make it more usable?  (I've written quite a bit of code that uses WRL--more than I've written using C++/CX--and while the code is often fairly verbose, I've found it to be quite usable.  I'm curious what problems you've run into in using it.  Feel free to drop me an e-mail if you'd prefer:  james.mcnellis@microsoft.com.)

    @S. Colcord:  There is a compiler option:  a translation unit that makes use of C++/CX must be compiled with /ZW.  If you attempt to compile a C++/CX program without that option, the compiler will balk at the C++/CX extensions.  You can name your source files with any extension you'd like (and use the /TC option to notify the compiler that it's a source file).

    I'm curious about why you think this makes it harder to use C++/CX solely at the boundary:  I would have assumed that it would be more confusing if a different file extension was used by default.  A C++/CX translation unit can make use of any C++ code.  Currently, the .cpp extension already doesn't say much about the source code:  much C++ code already relies on nonstandard extensions (or, perhaps more commonly, mostly-standard C++ code often relies on quirks or bugs in a particular set of compilers that have been used to test it).

    If one wants absolute separation between code written in standard C++ and code written using C++/CX, I would recommend building the standard C++ code as a library and linking it with the C++/CX component:  this allows verification that the library can be built without C++/CX support.  (Actually, I'd recommend doing this regardless--it makes code easier to test and verify, and code portability is A Good Thing.)

    @atch666:  In reply to your last comment, on 6 Sep 2012 10:58 PM:  @Diegum states that "it's still a desktop app," so "it doesn't do Metro" means that it doesn't produce a Windows Store app and thus it doesn't run in the new Windows 8 UI environment.

    [I've been on vacation for the last week, hence my delayed replies.]

  • @James thank you for your reply.

    >new Windows 8 UI environment

    Correct me if I'm wrong, but there isn't such thing as windows 8 ui environment only Windows 8 environment, right? What do you mean when you say that app produced in XE3 doesn't run in Windows 8 UI environement? That it doesn't have Windows UI look&feel? You're wrong because it does have. Do you mean that it cannot be run in windows 8 OS? You're wrong because it can precisely do it. So what you seem to imply is that the only constraint on it, will be that it will not be able to be available through Win8 app store? As I've already said, if someone's app is good no win app store is needed to sell it. If on the other hand someone produced craappy app, win app store will be of no help to him. Ok, that's dealt with. Now your argument with Colcord et al. James I suspect that you are intelligent person and I cannot possibly imagine that you really cannot see their points, and also cannot possibly imagine that you actually believe in the argument you've presented. If on the other hands you need any suggestions, as you ask K.Kawa, go to link I've provided and watch discussion between PleaseFixYourBugs and Jim Springfield. blogs.msdn.com/.../10228473.aspx

    Regards

  • @James

    > Windows Runtime does not support multiple inheritance (and hierarchies of public types are only permitted in a small set of scenarios); this is a restriction imposed by the runtime (and, in a sense, the metadata format), not one imposed by the C++/CX language extensions

    James, I don't care "what" does not allow me to use multiple inheritance, be it run time, be it CX, be it some other thing. The point what matters is that I cannot use multiple inheritance. Second point is, that I am not even convinced (I have no expertise in this area) that Windows Runtime doesn't support multiple inheritance. If those Metro apps can be made out of Cx (at the boundary only) and C++ at it's core, so if I follow that Metro app is running on Windows Runtime and is made out of CX and C++ this means that Windows Runtime supports multiple inheritance when C++ is concerned. If so, then what you're saying is incorrect. Windows runtime supports multiple inheritance, it just doesn't do it (laugh) when Cx is concerned.

    Another argument: ok, as you said yourself, we (developers) do not have to use Cx at all to write metro apps, right? Right, ok, then we can write our apps in WRL which is horrible but this is different story. If, we can write our metro apps in WRL and we use multiple inheritance in our apps (because we are not constrained by Cx) and we can run it as metro apps, then it follows that Windows runtime support multiple inheritance, it is just Cx doesn't support it. As simple as that.

    Having said that, let's forget those silly Metro apps or whatever you are now told to call them. What about desktop apps? If they can be run on Windows 8, and they are written using C++, then it follows that Windows runtime supports multiple inheritance, why wouldn't it? Cx doesn't support inheritance, and that the whole point.

    Regards

  • @atch666:  Windows Store apps are the new class of apps, built using the Windows Runtime, designed for Windows 8.  They are fundamentally different from ordinary desktop apps.  If you've used Windows 8, it's pretty obvious which apps are Windows Store apps (formerly called "Metro style apps") and which are desktop ("classic") apps.

    Unlike desktop apps, these apps can only be distributed via the Windows Store (there's an exception to this rule that applies in enterprise environments).  I am not an expert on building apps, and I am not familiar with the Windows Store rules; for more information on those subjects, I'd recommend the many posts on the Windows 8 app developer blog (blogs.msdn.com/.../windowsappdev) and the MSDN documentation for Windows Store apps (msdn.microsoft.com/.../apps).

    I'm not sure what leads you to think that my last comment was insincere.  I understand that people have concerns, and I'd like to help find ways to mitigate those concerns.  I've spent quite a bit of time writing Windows Runtime components over the last year, using both C++/CX and WRL, and have not had much difficulty using C++/CX (or WRL) only on the boundary, which is the recommendation that we've made ever since C++/CX was announced last year.

    As has been explained--both in this thread of comments and in threads elsewhere on this blog, on MSDN Forums, and in Channel 9 discussion--you don't have to use C++/CX if you don't want to.  You are free to write your code however you like.  C++/CX is just one option, and I think that many people are going to find it a compelling tool when writing native Windows Runtime components and Windows Store apps.

    In reply to your second comment:  one must distinguish between Windows Runtime types (types that can be used across the Windows Runtime ABI boundary) and arbitrary C++ types.  Some features of the C++ type system (like multiple inheritance) have no equivalent in the Windows Runtime type system.  C++/CX is not designed for building general C++ code, it's designed for creating and using Windows Runtime components, which are necessarily constrained by the rules of the Windows Runtime type system.

    You have said several times in this thread that WRL is "horrible."  Have you used it for building Windows Runtime components?  Do you have any specific feedback concerning which features of WRL you consider horrible, or suggestions for improvement?

  • @James

    Well, on several occasions MS guys hinted that WRL is a bit more verbose than C++/CX. The problem I have with this is that it's not a bit more verbose. It's massively, horribly over-verbose.

    I admit that I don't have that much experience with it, but I followed several presentations and examples, than tried to write few components myself. The amount of code I got to achieve simple things, like a class with just a handful of methods.. this is the horrible part for me. I just honestly can't imagine using it for anything more than short examples without making it unmaintainable. I showed an example to my friend(also a professional C++ programmer for some years now) and he couldn't believe the amount of machinery used to make a method that returns 42.

    I know I sound negative about this but it's not without a cause. Few times now I've mentioned Qt library on this board. That's because I use it in my work and private projects every day and I absolutely love its simplicity. Complex tasks like networking, threading, graphics, COM etc. can be grasped with just a few lines of very simple, readable code. I can't even think how much WRL code I would have to write to achieve the same goals Qt one-liners solve for me.

    To back up my words - take a look at the example in "C++/CX Part 1 of [n]" post - 109(I removed empty lines and comments!!!) lines of code in 4 files (3 .cpp and an .idl) to get a component with getter/setter for an int??? Not to mention the "override" extension keyword that got its way there. Come on... there HAS GOT TO BE a better way to write a library... thank god for "auto" at least...

    This all is not cause I'm lazy and don't like to write code :) I just believe WRL could have been much much cleaner and leaner and I just value my time too much to deal with it in this present form.

  • As for the features I'd like for WRL...

    This is the C++/CX code from the part 1 example:

    namespace CxxCXNumberComponent

    {

       public ref class Number sealed

       {

       public:

           Number() : _value(0) { }

           int GetValue()           { return _value;  }

           void SetValue(int value) { _value = value; }

       private:

           int _value;

       };

    }

    I'd like WRL to look as closely as possible to this:

    namespace CxxWRLNumberComponent

    {

       class Number : public WRLClass

       {

       public:

           Number(): _value(0) { }

           int GetValue()           { return _value;  }

           void SetValue(int value) { _value = value; }

       private:

           int _value;

       };

    }

    I understand it can't be THAT simple cause of COM and metadata so throw an iso c++ conformant macro in there if you will or even a #pragma if you can't help it but don't make it 109 lines in 4 files long!

  • @James thank you for your reply.

    To answer your question, yes, I did try to use it and also I did try to do same task with cx. Guess what? WRL is horrible. Even look at the examples you've provided and how much more and unreadable/unmaintainable stuff there is compared to Cx!

    The truth is that Cx was designed to suit .Net crowd (even comments from Ms suggest this) and we, C++ devs are left with if you please "second class" alternative. Oh yes, we can just not use Cx, but then we have to go through hell in order to achieve what is quite easily achievable with Cx. And that's the whole point. There was absolutely NO NECESSITY (Jim Springfield confirms) to go with Cx - C++ could be as easily (or easier) used. The problem is that MS had milions of devs enticed with C# and .NET and they (MS) just couldn't abandon them, so they've created .NET-ish language. As simple as this. Nobody thought about C++ devs for more than 5 minutes. That's why I concur with Knowing me, knowing you, a-ha, and agree that herb sutter is a traitor to C++.

  • @Krzysztof Kawa:  Thanks for your feedback.  Yes, WRL code is more verbose than equivalent C++/CX code, and it's much more tedious to write and more difficult to write correctly.  It's more flexible and offers much more control over practically everything, but that flexibility comes at a cost of higher complexity.

    To address two specific points that you made:  first, 'override' is not an extension, it's a feature of C++11.  It's optional in standard C++ code, but it is very useful and I'd recommend using it if possible.  Second, with respect to the 109 lines of code in the WRL component from Part 1:  to be fair, about 40% of that code is in the module.cpp file, which is all boilerplate and is per-module, not per-type (actually, I copied that code directly from the WRL project template).  This code looks worse (i.e. more verbose) than it really is because the project itself is so small:  in a larger project, the relative size of that code would be insignificant.

    The remaining code (the IDL and C++ definitions of the Number type and its interface) is still verbose, absolutely, but everything that is there is required.  Any other library or set of compiler extensions would somehow need to be able to generate that code somehow:  via language extensions like C++/CX, by using macros to generate the boilerplate, or perhaps through some sort of preprocessing step (that's not an exhaustive list of options--just some examples).

    The closer you want to get to your "target" code (so far as I can tell, it's just ordinary C++ code), the more work you need the compiler (or some sort of preprocessor) to do for you.  There's only so much that a library can do.  WRL encapsulates a lot of the boilerplate code, but to be able to build or consume Windows Runtime types using clean, simple code that is easy to write correctly, language extensions like C++/CX are a preferable solution.  Future posts in this series will cover additional transformations that are done and why compiler support is required.

    @atch666:  Ad hominem attacks do not in any way help your argument and are not welcome here.  If you'd like to make such comments, I would request that you find some other venue.

  • @James

    > first, 'override' is not an extension, it's a feature of C++11.

    Ah, my bad. There's so much new things in C++11 it's hard to remember everything :)

    > to be fair, about 40% of that code is in the module.cpp file

    Yup, true again. But why don't I see it in the /cx version then? If /cx can hide it from me why can't WRL do it too? The answer is - it could. But instead it just has this "naaah, just use our proprietary /cx extension" feeling all over the place.

    > The remaining code (the IDL and C++ definitions of the Number type and its interface) is still verbose, absolutely, but everything that is there is required.

    Yes, this is understandable.

    > Any other library or set of compiler extensions would somehow need to be able to generate that code somehow

    Yes, so why is it left to programmer to do it manually unlike with /cx? I see no uuids or [activatable] thingies in /cx code and yet the underlying machinery is still generated automagically and correctly by the compiler. This could be done perfectly well within a library with plain c++ or, in worst case, with some "not-that-ugly" macros.

    > There's only so much that a library can do.

    Take a look at boost or (again) Qt. Or even the stl! If we can have threads as a library I honestly don't see a problem with a little reflection or COM. There is very very much that a well written library can do and efficiently at that.

    > WRL encapsulates a lot of the boilerplate code, but to be able to build or consume Windows Runtime types using clean, simple code that is easy to write correctly, language extensions like C++/CX are a preferable solution.  

    Not preferred by me and, judging by the comments on this board, not by many others too. Certainly not by people who for any reason would like to use another compiler and at the same time target new windows runtime.

    You guys always say you listen to us but somehow you don't seem to hear. You talk about c++ renaissance and than pull a /cx on us. This creation of new c++ish languages and yet another compiler extensions with each new VS version has to stop at some point. It's madness (not to sound too Spartish). But yeah, this argument was raised way too many times already so I'll just leave it at that.

    > Future posts in this series will cover additional transformations that are done and why compiler support is required.

    I'm honestly looking forward to that and wish for the best. I would love to think to myself at some point: "yup, this is the right way to do it", but so far this just seems like another c++/cli (compiled to native code this time) misunderstanding and I fear it will end up the same - as something replaced by c++/whatever in VC.next. I know c++/cli is not technically removed yet, but lets be honest - it was a bad idea, dying the slow death it deserves.

    @atch666

    To be honest the thing that XE3 does seems to me just plain bad too and I can't see it catching on. It's like when people installed all kind of crap on Windows XP to make it look and behave like Windows 7 when it came out. To some extent it worked, but not always, not that well and caused more problems than it solved. Pointless. Desktop apps (what XE3 does) don't follow the same life-cycle, power and memory management rules, task switching patterns etc. etc. The look and feel can be simulated to some extent but it's just not the real deal and never will be.

  • @James I'm not attacking anobody, let's be honest, the only thing I've said is that I agree with someone's opinion and this surely cannot be seen as an attack. I'm here not to cause disturbance of any kind. Argue? Yes, I argue, but I believe that I am right in what I'm saying and judging by other's comments I see that lots of people feel exactly the same.

  • @Kawa my main point with XE3 was that so called Metro apps CAN be made using C++ only. Another story is if this will take off or not. But the point is still valid - no Cx is required, no complicated, unmaintainable code is required to do Metro.

  • @atch666 You called Herb Sutter a traitor to C++.  I don't know how you can say that's not attacking someone.  That was really uncalled for.

  • @GregM Cx was the cause that he was first called a traitor. So I disagree that it was uncalled for. The call was made as soon as last year's presentation of //build was over and every folks saw what MS meant by C++ Renaissance, which herb sutter was so enthusiastic about. That's why I said that I agree with Knowing me, knowing you, a-ha.

  • @atch666: People don't insult others just because their opinion is different. Grow up.

  • @atch666 The fact that other people did it first doesn't change the fact that you were attacking him and it was uncalled for.  Stay away from personal attacks and people will be more likely to accept your arguments.

Page 4 of 5 (65 items) 12345