IanG on Tap

Ian Griffiths in Weblog Form (RSS 2.0)

Blog Navigation

August (2014)

(1 item)

July (2014)

(5 items)

April (2014)

(1 item)

March (2014)

(1 item)

January (2014)

(2 items)

November (2013)

(2 items)

July (2013)

(4 items)

April (2013)

(1 item)

February (2013)

(6 items)

September (2011)

(2 items)

November (2010)

(4 items)

September (2010)

(1 item)

August (2010)

(4 items)

July (2010)

(2 items)

September (2009)

(1 item)

June (2009)

(1 item)

April (2009)

(1 item)

November (2008)

(1 item)

October (2008)

(1 item)

September (2008)

(1 item)

July (2008)

(1 item)

June (2008)

(1 item)

May (2008)

(2 items)

April (2008)

(2 items)

March (2008)

(5 items)

January (2008)

(3 items)

December (2007)

(1 item)

November (2007)

(1 item)

October (2007)

(1 item)

September (2007)

(3 items)

August (2007)

(1 item)

July (2007)

(1 item)

June (2007)

(2 items)

May (2007)

(8 items)

April (2007)

(2 items)

March (2007)

(7 items)

February (2007)

(2 items)

January (2007)

(2 items)

November (2006)

(1 item)

October (2006)

(2 items)

September (2006)

(1 item)

June (2006)

(2 items)

May (2006)

(4 items)

April (2006)

(1 item)

March (2006)

(5 items)

January (2006)

(1 item)

December (2005)

(3 items)

November (2005)

(2 items)

October (2005)

(2 items)

September (2005)

(8 items)

August (2005)

(7 items)

June (2005)

(3 items)

May (2005)

(7 items)

April (2005)

(6 items)

March (2005)

(1 item)

February (2005)

(2 items)

January (2005)

(5 items)

December (2004)

(5 items)

November (2004)

(7 items)

October (2004)

(3 items)

September (2004)

(7 items)

August (2004)

(16 items)

July (2004)

(10 items)

June (2004)

(27 items)

May (2004)

(15 items)

April (2004)

(15 items)

March (2004)

(13 items)

February (2004)

(16 items)

January (2004)

(15 items)

Blog Home

RSS 2.0

Writing

Programming C# 5.0

Programming WPF

Other Sites

Interact Software

Real Native WinRT Development

Friday 16 September, 2011, 04:05 PM

I’ve been at Microsoft’s //build/ conference this week, where they announced WinRT. WinRT is a new API for building Windows applications that use the new ‘Metro’ style. Under the covers this uses a lot of COM-based technology. However, we’ve seen very little of that COM layer.

The various languages that support WinRT (C#, VB, JavaScript, and C++) all define “projections” to make the new WinRT-based objects easier to work with. After all, who really wants to use COM if they can help it? Even the vast majority of the C++ examples we've been shown have used the C++ projection. Slightly confusingly, this hasn’t always been made very clear—some presenters have shown C++ examples and talked about native code and COM while showing us things that are actually the C++ projection.

If you want to crow about how C++ lets you do native development (and apparently some people seem very excited by this) you don’t get full bragging rights if you’re using the projection. The C++ Metro project templates in the Visual Studio 11 preview are all working at a level removed from the true native experience.

That’s a good thing, by the way (for much the same reasons that managed code is a good thing). Without the various language projections, WinRT would be a clear reminder of why so many of us walked away from COM a decade ago. There will rarely be any good reason to work directly with WinRT at the native level. (Adopting a boastful “more native than thou” attitude may be a reason of sorts, but it’s certainly not a good one.) But I like to know how things work, so I thought it’d be fun to try out some real native WinRT development. This means eschewing the projections, and getting down to the level where you will see an actual vtbl call. (We didn’t see any such thing in the ‘big picture’ talks on the first day of the conference, despite what some presenters claimed.)

Raw Native WinRT Client Projects

The first challenge is to create a C++ project capable of working in the WinRT environment, but without opting into the projected world. None of the templates supplied with the Visual Studio preview seem to do this—the Metro projects all turn on the projection features, but the classic C++ templates produce programs which won’t run in the new WinRT world. (If you saw any of the //build/ presentations on WinRT, you may remember the green and blue boxes—the green boxes are the new Metroid world, while the blue boxes represent the classic pre-Win8 world.)

You need your project file to contain a combination of settings which, as far as I can tell, can’t actually be configured in Visual Studio’s UI, so some manual project file editing is required. In particular, you need an <Immersive>true/</Immersive> element in a property group to enable the deploy step that builds a new appx package for your app—if I’ve understood correctly, you won’t get into the green box without this. (This property is present in all the new Metro templates, but as far as I can see, there’s no UI for turning this on in an existing C++ project.) However, that setting also turns on all the projection stuff, so you need to turn that back off again. You need a <CompileAsWinRT>false</CompileAsWinRT> inside the <ClCompile> section for each configuration, and also <GenerateWindowsMetadata>false</GenerateWindowsMetadata> and <WindowsMetadataFile /> inside each configuration’s <Link> section.

If you don’t turn those off, you’ll get a load of errors when you try to include the header files that define the native versions of all the WinRT types and interfaces—the C++ compiler will complain that it has already seen all these types (because it imports them automatically when you’re using the C++ WinRT projection), and that they all look different (because the C++ projection represents many these types differently from the native versions).

So, we now have a project that builds genuine native C++ code with none of the projection features switched on, but which puts the result into the new appx packaging format. This will also use the appx-aware debugger. (You can turn that on with <DebuggerFlavour>ImmersiveLocalDebugger</DebuggerFlavor>, but that setting will be in effect as a result of turning on the immersive setting for the build system.)

Next, we need some code.

Ruh Roh!

First, let’s initialize the runtime:

HRESULT hr = ::RoInitialize(RO_INIT_SINGLETHREADED);

[Update (2011/09/20): it turns out that this should be RO_INIT_MULTITHREADED if you want it to work.]

That should look hauntingly familiar to anyone who’s done any COM development. It’s not quite the same—the classic COM versions of this API start with ‘C’ rather than ‘R’, so that’d be CoInitialize, and if you called the version that accepted a threading mode (CoInitializeEx) that’d be COINIT_APARTMENTTHREADED.

But at this stage, WinRT definitely sounds like native COM, albeit spoken in a silly voice.

Old-School Error Handling

You’ll have noticed the HRESULT in that first line of code. If you’ve done any COM, you’ll be all too familiar with this. It’s just a 32-bit integer, and all COM operations (APIs and also method calls on objects) return these. If the top bit is set, that indicates an error, and the number may or may not tell you something about what failed. You have to check these every time you do anything. So I wrote a little helper:

inline void CheckHresult(HRESULT hr, LPCWSTR message)
{
  if (FAILED(hr))
  {
    wcout << L"Error (0x" << hex << hr << L") during: " << message << endl;
    exit(1);
  }
}

That’s a bit brutal, but it’ll do for now. We should call it after RoInitialize:

CheckHresult(hr, L"RoInitialize");

And we’ll be seeing more of that sort of thing.

Creating an Object

Now that we’ve initialized WinRT, we need an object. The first thing most immersive applications do is create an Application object. For example, in the high-level world of the C++ projection for WinRT, here’s the generated program entry point in App.cs.g from an ordinary metro app:

int main(lang::array<Platform::String^>^ args)
{
  auto app = ref new App();

  app->Application::Run();
}

That first line constructs the App object, which derives from the Application class. For now, I’m not going to get into derivation—for this blog post, I’m just going to construct the base Application class directly. As you can see above, in the world of the C++ projection for WinRT creating an object is one line of code. Here’s the native version of that one line of code:

const wchar_t *appClassName = L"Windows.UI.Xaml.Application";
HSTRING hstring;
hr = ::WindowsCreateString(appClassName,
       static_cast<UINT32>(::wcslen(appClassName)), &hstring);
CheckHresult(hr, L"WindowsCreateString");
IInspectable* pInspApp;
hr = ::RoActivateInstance(hstring, &pInspApp);
CheckHresult(hr, L"RoActivateInstance");
::WindowsDeleteString(hstring);
CheckHresult(hr, L"WindowsDeleteString");

What a lot of code. Actually the interesting part is just two lines in the middle:

IInspectable* pInspApp;
hr = ::RoActivateInstance(hstring, &pInspApp);

The rest is all string handling or error handling, which is exactly the sort of low-level cruft that the language projections save you from. All this sort of thing will be going on, it’s just that if you choose to use the high-level projections, they hide all that for you.

HSTRING is WinRT’s native representation of strings. COM veterans will know that this is new—in old-school COM, we represented strings in numerous ways, but this wasn’t one of them. (In the VB/scripting/IDispatch/dual side of the COM house, strings were typically BSTRs, while in the non-C++-languages-need-not-apply side of COM, they were often just plain old LPWSTRs, although there were a bunch of other more unusual options.) I’ll leave the what and why of HSTRING for another time, so for now, just know that this is how WinRT expects its strings to look, so we had to create one from our C-style string constant to be able to call RoActivateInstance.

So that’s two departures from classic COM: there’s a new string type, but there’s also the fact that we’re using a string at all. I’m passing a string containing the name of the class I want to instantiate (“Windows.UI.Xaml.Application”) to RoActivateInstance. The nearest equivalent classic COM API was CoCreateInstance, and that used GUIDs to identify types. But in WinRT, you’ll see strings in a lot of places you used to see GUIDs.

In fact that call to RoActivateInstance introduces a third new thing: IInspectable.

IInspectable

In classic COM, all interfaces derived from a base interface called IUnknown, which offered two services: reference counting-based lifetime management (through the AddRef and Release methods), and the ability to request other interfaces that the object might offer (through the QueryInterface method). IUnknown is still there, but there’s a new interface which everything in WinRT seems to derive from: IInspectable.

IInspectable derives from IUnknown, as we can see from the native C++ definition (in the SDK’s inspectable.h file, which looks like it was generated from IDL):

MIDL_INTERFACE("AF86E2E0-B12D-4c6a-9C5A-D7AA65101E90")
IInspectable : public IUnknown
{
public:
  virtual HRESULT STDMETHODCALLTYPE GetIids( 
    __RPC__out ULONG *iidCount,
    __RPC__deref_out_ecount_full_opt(*iidCount) IID **iids) = 0;
        
  virtual HRESULT STDMETHODCALLTYPE GetRuntimeClassName( 
    __RPC__deref_out_opt HSTRING *className) = 0;
        
  virtual HRESULT STDMETHODCALLTYPE GetTrustLevel( 
    __RPC__out TrustLevel *trustLevel) = 0;
        
};

So IUnknown is still there—this still looks and feels like COM. But every WinRT interface gets three new features on top of IUnknown’s services. GetIids lets us ask an object for a list of the interfaces it offers, and whatever it returns in this list, it is committed to making available through QueryInterface. (The old-school COM model is that you had to know what to ask the object for. Now you can ask it what it offers.)

You can also ask an object its type—with classic COM there wasn’t a standard ubiquitous way that you could ask any old interface pointer “what kind of object do you point to?” The assumption was that since you wrote the program, you should know what the object is. (And if you don’t know what the object is, what makes you think you can do anything useful with it?) But some of the languages WinRT projects into just assume it’s possible to ask an object its type, so this method makes that possible.

Finally, there’s GetTrustLevel. As the documentation (http://msdn.microsoft.com/library/br205824(v=VS.85) ) helpfully says, this “Gets the trust level of the current Windows Runtime object.” Well that clears things up. I’m assuming this has something to do with the security sandboxing model, but I haven’t yet had time to look at that in any detail.

As it happens, we’re not going to use any of the IInspectable features here. I want to call a method on the WinRT Application class, so I already know precisely which interface I want. I can therefore use the classic COM mechanism for getting hold of it:

Windows::UI::Xaml::IApplication* pApplication;
hr = pInspApp->QueryInterface(__uuidof(pApplication), (void**) &pApplication);
CheckHresult(hr, L"QI for IApplication");

That’s pretty ordinary COM. (Beautiful, isn’t it? *shudder*)

I’ve now got two references to the object—one typed as IInspectable, and one as IApplication. IApplication is a WinRT interface so it derives from IInspectable, making that first reference is superfluous—my pApplication pointer gives me all I could need, so I’ll let the other one go:

pInspApp->Release();

Remember, Release (along with AddRef) is one of the very few COM interface methods that doesn’t return an HRESULT, so we don’t need to check that this worked. It’s not allowed to fail.

So, we have finally written the native equivalent of that first line of code in the high-level projected C++ program. It was a while ago, so in case you’ve forgotten it, here’s the high level entry point code again:

int main(lang::array<Platform::String^>^ args)
{
    auto app = ref new App();

    app->Application::Run();
}

C++ may produce fewer machine code instructions per line of source than the other WinRT languages, but sometimes it achieves this by making you do all the work yourself… (I can hear all the people who used VB back in the 1990s when I was a C++ COM developer saying “I told you so!”)

We’re now ready to move onto the second line—the method call.

Calling Methods

Now that we’re up and running with our object, you may be relieved to hear that invoking methods is pretty straightforward:

hr = pApplication->Run();
CheckHresult(hr, L"Application.Run");

OK, it’s still twice as much code as you’d expect to write in VB or C# thanks to the return code based error handling, but it’s much less effort than it took to get to this point. COM makes fairly light work of invoking methods. Which reminds me…

That’s Not a Vtbl—THIS is a Vtbl

In the ‘big picture’ talks on the first afternoon of //build/ we were shown a C++ Metro app, and a big deal was made of showing the disassembly for a WinRT method call. It looked something like this:

	myTextBlock->SelectAll();
00F55F4F  mov         ecx,dword ptr [ebx+0C4h]  
00F55F55  call        Windows::UI::Xaml::Controls::TextBlock::Windows::UI::Xaml::Controls[::ITextBlock]::SelectAll (0F56160h)  

That’s a call to a TextBlock’s SelectAll method, which they chose because it’s a simple no-parameters method, which makes the resulting compiled code really simple. There are two instructions. The first instruction (mov) loads the implicit ‘this’ argument, passing it via the ECX register (which is one of the numerous ways of passing arguments in assembly language, although most go on the stack). The second instruction (call) is what simple method calls look like in assembly language.

This was proudly announced as a vtbl call, which was offered as evidence of the innate efficiency of C++ compared to some other languages. But as anyone who’s done much C++ COM development will have noticed, that wasn’t true—that’s not what vtbl calls look like. And if you step into that call in the debugger, the claims for efficiency look a whole lot more doubtful, because you end up in a compiler-generated thunk that’s 55 instructions long! (There is a real vtbl call, but it’s buried somewhere in the middle of those 55 instructions.)

The C++ projection for WinRT looks pretty expensive compared to classic COM. Going back to my truly native example, here’s what our native call to the Application object’s Run method looks like in the disassembler:

	hr = pApplication->Run();
00F211E9  mov         eax,dword ptr [esp+14h]  
00F211ED  push        eax  
00F211EE  mov         ecx,dword ptr [eax]  
00F211F0  call        dword ptr [ecx+40h]  

That’s compiled in Release mode by the way—you’ll get more verbose code in Debug. This is about as efficient as a vtbl call gets. The first instruction (mov) is loading the pApplication variable from memory into a CPU register. The second instruction (push) is passing that as the implicit ‘this’ argument—here we’re using the stack, which is how it’s done in COM. (COM doesn’t ever put ‘this’ in ECX, which was one giveaway that the earlier code wasn’t native COM. Everything goes on the stack in COM.) And then the final two instructions are what a vtbl call looks like. COM interface pointers point into a part of the object that contains another pointer, which points to the vtbl for whichever interface you’re working with. The vtbl is an array of function pointers, one for each method in the interface.

The vtbl here is for IApplication. Looking at the function pointers in the vtbl, the methods defined by base interfaces come first, so the first three slots are for IUnknown’s QueryInterface, AddRef, and Release, and the next three are for IInspectable’s methods, so the IApplication methods actually start at slot 6 (or in 0-based counting, at offset 5 which, given 32-bit function pointers, is actually offset 0x16, i.e. 20). The call instruction is looking up the slot at offset 0x40, and since this is a 32-bit process, turning that byte offset back into a slot offset we get 0x10, i.e. 16, which is the interface’s 17th method. So taking out the 6 methods of IUnknown and IInspectable, that means this code is invoking the 11th method in IApplication. And if you go and look at the interface definition for IApplication (which appears to be in Windows.UI.Xaml-coretypes.h), you’ll see that this is indeed the Run method, as you’d expect.

COM vtbl calls always involve this multiple indirection. We always use COM objects via interface pointers. To do anything useful with an interface pointer, we dereference it to get the vtbl. And then we retrieve nth entry in the vtbl. And that points to a method, so we perform an indirected call through that vtbl entry.

Modern CPUs are not very good at dealing with calls through pointers by the way—they like to look ahead, but this sort of indirection prevent them from knowing where they’re going until they get there. So vtbl calls are relatively expensive—much more expensive than, say, an inlined method call such as the CLR might perform. Native C++ can offer some performance benefits over managed code, but it’s not as clear cuts as a lot of people seem to think, particularly with COM in the picture. (Anything crossing a COM boundary defeats a lot of optimizations, something that's not true when using a .NET library.)

Reimagining Success

Incidentally, this call to Run fails. I know I’m right back in the world of COM because I get a return HRESULT of E_FAIL (0x80004005), which means roughly “Something went wrong, and the developer who wrote this method couldn’t [be bothered to] find a more informative error code.” If you pass that to the Windows API for formatting error messages you just get “Unspecified error”.

At the time of writing this, I have some theories as to why this might have failed, but I’ve not tested them yet. But since the //BUILD/ conference is apparently about reimagining everything, I’m going to reimagine what success means. My goal here was to show some of the very basic operations—creating new objects and invoking methods—done in real native code, and I’ve done that, even though my application does nothing useful as yet. To build something meaningful, I need to get into more complex mechanisms like inheritance, and event handling. But it’s nearly time for breakfast, and I want to get this posted before this morning’s talks, so I’ll leave things broken for now, and will follow up with an application that actually does something in a future post.

[Update (2011/09/20): as mentioned in the update above, this turned out to be a threading model issue. WinRT wants this part of the application initialization to happen from a multithreaded context, rather than a singlethreaded one. Also, I put back a missing p tag that had caused a paragraph to vanish in the original post.]

Obviously, nobody in their right mind is going to write applications this way. I just like to know what’s really going on under the covers, so I think it’s interesting to explore the details at this level—if you want to stand a chance of realizing any of the benefits that native code hypothetically offers, I think it’s important to understand this level of detail even if you ultimately choose to work at a higher level. If you care about performance, you need to know what the language projections are really doing for you.

Copyright © 2002-2013, Interact Software Ltd. Content by Ian Griffiths. Please direct all Web site inquiries to webmaster@interact-sw.co.uk