My blog about application development on the .NET platform and Windows®.

Creating a minimal UWP app using the WRL

Continuing from my last post abut how to create a minimal UWP app in C#, this one takes a closer look at what actually happens under the hood when the app interacts with the Windows Runtime (WinRT) and how you can interact with WinRT yourself in a native way without using any language projections.

If you look at the definition of the Windows.UI.Xaml.Application base class in Visual Studio, you will see that it points to a WinMD file. This is a new kind of metadata file that was introduced in Windows 8. It has the same format as a .NET framework assembly which means that it complies with the ECMA-335 CLI specification and can be decompiled by any .NET disassembler tool, such as for example ildasm or JetBrains dotPeek. WinRT uses these WinMD files to expose a broad range of object-oriented Windows APIs that can be consumed from a number of different programming languages, including C++, VB.NET, C# and even Javascript. This was one of the key design goals of WinRT from day one. It should be easily consumable from variety of technologies and languages.

The way this works is through the use of projections that are built-in into each supported language. So although the actual implementation of the Application class, and any other WinRT type for that matter, is written in an unmanaged language, you can still use it in your C# app like you would use any other managed type. The “translation” from the managed world into the native WinRT world is all taken care of for you by the compiler and either the CoreCLR or the .NET native toolchain depending on whether you build your app in debug or release mode.

In this post, I’ve put together another code sample that provides the same minimal sample app as in the previous post but without using any of the language specific bindings (projections) that Microsoft has done a great of job of hiding away for you. This code uses the Windows Runtime C++ Template Library (WRL) to consume the WinRT APIs directly, and you can compile and run the sample app without even opening Visual Studio.

Note that this is not something that you would normally do in the “real world”. Even if you are a C++ developer, you would typically still use either the C++/CX or the C++/WinRT extensions to simplify writing native UWP apps and avoid the details of having to consume the raw WinRT components directly. The main purpose of the sample code presented here is to provide a better understanding of what happens at a lower level behind the scenes. You can view and download the full code sample at GitHub.

The code consists of three source files, a Source.cpp file which contains the main method that initializes the app, a Program.h header file and a Program.cpp file where the custom Program class is implemented. You can compile the app using the cl.exe compiler from the command line of a Visual Studio developer command prompt:

cl.exe /D WINAPI_FAMILY=WINAPI_FAMILY_APP Program.cpp Source.cpp -link RuntimeObject.lib
/APPCONTAINER /WINMD:NO /OUT:MinimalWRLSampleApp.exe

If you try to run the generated executable (.exe) by for example double-clicking on it, you will get an error message:

If you omit the /APPCONTAINER option when you compile, the app would crash at runtime. All apps that use any of the types that are defined in the Windows.UI.Xaml namespace must run in the context of an app container, and the app will run if you use the Add-AppxPackage cmdlet in Powershell to install it to your user account as part of signed app package:

powershell add-appxpackage –register AppxManifest.xml

This is where the application package manifest comes in. You will need one to be able to install and run the app. As I mentioned in the previous post, the manifest contains the mandatory information that the operating system needs to be able deploy the app.

Now let’s take a look at the code. Before you can call any of the WinRT APIs in the native world, you need to initialize the runtime. The is done by calling the RoInitialize function:

/* Initialize WinRT */
HRESULT hr = RoInitialize(RO_INIT_MULTITHREADED);
assert(SUCCEEDED(hr));

Note that the WRL is exception-free and each method returns an HRESULT, which is a 32-bit integer type that includes information about whether the operation was successful and any warning or error message if it wasn’t. In the sample code, I have omitted any error handling for brevity and simply used the assert and SUCCEEDED macros to validate that the returned HRESULT of a call equals S_OK.

WinRT is based on Component Object Model (COM) which a technology that has been around since the early 1990s. It’s the foundation technology for several other Microsoft technologies including for example ActiveX and DirectX. It allows objects to interact across process and computer boundaries and it does this by specifying that the only way to manipulate the data associated with an object is through an interface on the object.

Every COM object implements the IUnknown interface and every WinRT object implements the IInspectable interface, which inherits from IUnknown. IUnknown defines the AddRef and Release methods for managing the existence of an object by incrementing and decrementing the reference count for the interface that points to it respectively. It also defines a QueryInterface method which enables you to get pointers to other interfaces that the object implements. This enables type conversion casting between different interfaces which we will see an example of in a bit.

The IInspectable interface adds methods for getting a full list of interfaces that a class implements, what trust level an object has and the fully qualified name of the type itself. This basically makes WinRT strongly typed.

Given a name of a WinRT type, you can get a pointer to its activation factory using the RoGetActivationFactory function. A particular type can only have one activation factory associated with it and it’s the activation factory that is responsible for actually creating an instance of the runtime object under the hood. So whenever you write something like this in C#, the built-in language projections will take care of the activation for you at one point or another:

TextBlock textBlock = new TextBlock();

In the fully native world you are responsible for doing this yourself. The first thing you need is the name of the type to activate. In WinRT strings are represented by the HSTRING type. In the managed world, the C# compiler automatically translates between HSTRING and System.String for you. In a C++/WRL app, you can use the WindowsCreateString function to create a HSTRING from a wchar_t*:

//create the HSTRING
HSTRING hstring;
const wchar_t* s = L"Windows.UI.Xaml.Controls.TextBlock";
HRESULT hr = WindowsCreateString(s, wcslen(s), &hstring);
assert(SUCCEEDED(hr));
...
//delete the string
WindowsDeleteString(hstring);

The WRL also provides an easier way to create a HSTRING using the MakeReference function and the HStringReference object:

HSTRING hstring = Microsoft::WRL::Wrappers::HStringReference(RuntimeClass_Windows_UI_Xaml_Application).Get();

Once you have the HSTRING, you can create an instance of a TextBlock using the RoActivateInstance function:

/* TextBlock textBlock = new TextBlock(); */
Microsoft::WRL::ComPtr<IInspectable> inspectableClass;
HRESULT hr = RoActivateInstance(
  Microsoft::WRL::Wrappers::HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_TextBlock).Get(),
  inspectableClass.ReleaseAndGetAddressOf());
assert(SUCCEEDED(hr));

RoActivateInstance uses RoGetActivationFactory to find and load the module (DLL) in which the runtime class is actually implemented. All built-in Windows types including TextBlock are registered globally in the registry, and this is where RoGetActivationFactory searches for the location of the module. If you look at the Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsRuntime\ActivatableClassId\Windows.UI.Xaml.Controls.TextBlock registry key in regedit, you will see that its DllPath property points to C:\Windows\System32\Windows.UI.Xaml.dll.

Each module that defines a WinRT class exports an entry point named DllGetActivationFactory that takes a type name and returns an activation factory for that particular type. Once the module has been located using the registry, RoGetActivationFactory calls DllGetActivationFactory to get an instance of the activation factory, and then uses it to create an instance of the TextBlock class before it releases the activation factory. Again, this happens “automatically” in the managed world. You don’t have to do anything. But if you are anything like me, you probably still want to get a clue about what is going on deep down below all abstractions.

The ComPtr<T> class in WRL used in the code snippet above is a smart pointer type that automatically maintains a reference count for the underlying interface pointer and releases the interface when the reference count goes to zero, i.e. when the pointer goes out of scope. It basically saves you from having to remember to release the pointer explicitly like this:

IInspectable* inspectableClass;
HRESULT hr = RoActivateInstance(
  Microsoft::WRL::Wrappers::HStringReference(RuntimeClass_Windows_UI_Xaml_Controls_TextBlock).Get(),
  &inspectableClass);
assert(SUCCEEDED(hr));
inspectableClass->Release();

Note that RoActivateInstance returns an IInspectable*. This is where the type casting comes in. The underlying TextBlock object that was created by the activation factory and that the returned pointer points to implements several interfaces. You can find out which ones by calling the IInspectable.GetIids method but to be able to do the correspondence of setting the Text property of the TextBlock, you need to cast inspectableClass to an ITextBlock pointer. You can do this using the QueryInteface method:

Microsoft::WRL::ComPtr<ABI::Windows::UI::Xaml::Controls::ITextBlock> textBlock;
hr = inspectableClass->QueryInterface(__uuidof(textBlock), &textBlock);
assert(SUCCEEDED(hr));

Or you can use the As method of the ComPtr:

Microsoft::WRL::ComPtr<ABI::Windows::UI::Xaml::Controls::ITextBlock> textBlock;
hr = inspectableClass.As<ABI::Windows::UI::Xaml::Controls::ITextBlock>(&textBlock);
assert(SUCCEEDED(hr));

Once you have a pointer of the right type, you can simply use the arrow member-access operator (->) to access any member function of that interface. This is for example how setting the Text and FontSize properties of the TextBlock in C# translates to WRL code:

/* textBlock.Text = "Hello world!"; */
hr = textBlock->put_Text(Microsoft::WRL::Wrappers::HStringReference(L"Hello world!").Get());
assert(SUCCEEDED(hr));

/* textBlock.FontSize = 40; */
hr = textBlock->put_FontSize(40);
assert(SUCCEEDED(hr));

The same thing applies when you want to access some members that are defined in a base class. In the previous post I set the HorizontalAlignment and VerticalAlignment properties of the TextBlock and since these are defined in the UIElement class, you will need such a pointer to be able to access them:

/* Cast the TextBlock to a FrameworkElement to be able to set the HorizontalAlignment and VerticalAlignment properties */
Microsoft::WRL::ComPtr<ABI::Windows::UI::Xaml::IFrameworkElement> frameworkElement;
hr = inspectableClass.As<ABI::Windows::UI::Xaml::IFrameworkElement>(&frameworkElement);
assert(SUCCEEDED(hr));

/* textBlock.VerticalAlignment = VerticalAlignment.Center; */
hr = frameworkElement->put_VerticalAlignment(ABI::Windows::UI::Xaml::VerticalAlignment::VerticalAlignment_Center);
assert(SUCCEEDED(hr));

/* textBlock.HorizontalAlignment = HorizontalAlignment.Center; */
hr = frameworkElement->put_HorizontalAlignment(ABI::Windows::UI::Xaml::HorizontalAlignment::HorizontalAlignment_Center);
assert(SUCCEEDED(hr));

Speaking of base classes, COM doesn’t support code reuse through inheritance. Since you only have access to interfaces and not any underlying classes, there is no way to derive from a built-in class like for example Application. Instead a custom WinRT class derives from a common base template class called RuntimeClass. This class provides a boilerplate implementation of all IInspectable and IUnknown stuff. The type parameter(s) represent(s) the specific interface(s) to implement.

In this case I am only really interested in overriding the OnLaunched method, just as I did in the C# sample in the previous post. This is where I create the TextBlock and set the content of the window.

Static members of a type are implemented by the type’s activation factory. So in order to be able to set the Window.Current property, I will need to use the GetActivationFactory method to get an IWindowStatics pointer. This interface exposes all static members of the Window class. Once I have this I can get an IWindow pointer using the get_Current method. I then need to cast the TextBlock to an IUIElement to be able to use the put_Content method to set the window’s content to the TextBlock before I call the Activate method:

HRESULT Program::OnLaunched(ABI::Windows::ApplicationModel::Activation::ILaunchActivatedEventArgs *args)
{
	/* TextBlock textBlock = new TextBlock(); */
	...
	/* textBlock.Text = "Hello world!"; */
	...
	/* textBlock.FontSize = 40; */
	...
	/* textBlock.VerticalAlignment = VerticalAlignment.Center; */
	...
	/* textBlock.HorizontalAlignment = HorizontalAlignment.Center; */
	...

	/* Window.Current */
	Microsoft::WRL::ComPtr<ABI::Windows::UI::Xaml::IWindowStatics> window;
	hr = Windows::Foundation::GetActivationFactory(
		Microsoft::WRL::Wrappers::HStringReference(RuntimeClass_Windows_UI_Xaml_Window).Get(),
		&window);
	assert(SUCCEEDED(hr));

	Microsoft::WRL::ComPtr<ABI::Windows::UI::Xaml::IWindow> currentWindow;
	hr = window->get_Current(&currentWindow);
	assert(SUCCEEDED(hr));

	/* Cast the TextBlock to a UIElement to be able to set the Window.Current property to it */
	Microsoft::WRL::ComPtr<ABI::Windows::UI::Xaml::IUIElement> uiElement;
	hr = inspectableClass.As<ABI::Windows::UI::Xaml::IUIElement>(&uiElement);
	assert(SUCCEEDED(hr));

	/* Window.Current.Content = textBlock; */
	hr = currentWindow->put_Content(uiElement.Get());
	assert(SUCCEEDED(hr));

	/* Window.Current.Activate(); */
	hr = currentWindow->Activate();
	assert(SUCCEEDED(hr));

	return hr;
}

The OnLaunched method belongs to the IApplicationOverrides interface so I specify this as the template argument for the RuntimeClass that my custom class derives from. If you look at the metadata for the Application class in the C# project template, you will see that it also implements an IApplication interface. However none of these members are marked as virtual and they cannot be overridden.

Also note the InspectableClass macro that is used to specify the runtime class name and trust level that will be returned from the GetRuntimeClassName and GetTrustLevel methods of the IInspectable interface respectively.

class Program :
	public Microsoft::WRL::RuntimeClass<ABI::Windows::UI::Xaml::IApplicationOverrides>
{
	InspectableClass(L"MinimalWRLSampleApp.Program", TrustLevel::BaseTrust);
	...
}

I could have specified several template arguments and interfaces to implement here if I wanted to but in this case I don’t since I only care about implementing the OnLaunched method. I still need to provide implementations for the other methods of the IApplicationOverrides interface however. Since I don’t really want to override any of these, I can define a method that takes a pointer to an object that already implements them and simply let my methods call back to this implementation:

void Program::SetBaseImplementation(ABI::Windows::UI::Xaml::IApplicationOverrides* pBaseImplementation)
{
	_baseImplementation = pBaseImplementation;
}

HRESULT Program::OnActivated(ABI::Windows::ApplicationModel::Activation::IActivatedEventArgs * args)
{
	return _baseImplementation->OnActivated(args);
}

HRESULT Program::OnFileActivated(ABI::Windows::ApplicationModel::Activation::IFileActivatedEventArgs * args)
{
	return _baseImplementation->OnFileActivated(args);
}

HRESULT Program::OnSearchActivated(ABI::Windows::ApplicationModel::Activation::ISearchActivatedEventArgs * args)
{
	return _baseImplementation->OnSearchActivated(args);
}

HRESULT Program::OnShareTargetActivated(ABI::Windows::ApplicationModel::Activation::IShareTargetActivatedEventArgs * args)
{
	return _baseImplementation->OnShareTargetActivated(args);
}

HRESULT Program::OnFileOpenPickerActivated(ABI::Windows::ApplicationModel::Activation::IFileOpenPickerActivatedEventArgs * args)
{
	return _baseImplementation->OnFileOpenPickerActivated(args);
}

HRESULT Program::OnFileSavePickerActivated(ABI::Windows::ApplicationModel::Activation::IFileSavePickerActivatedEventArgs * args)
{
	return _baseImplementation->OnFileSavePickerActivated(args);
}

HRESULT Program::OnCachedFileUpdaterActivated(ABI::Windows::ApplicationModel::Activation::ICachedFileUpdaterActivatedEventArgs * args)
{
	return _baseImplementation->OnCachedFileUpdaterActivated(args);
}

HRESULT Program::OnWindowCreated(ABI::Windows::UI::Xaml::IWindowCreatedEventArgs * args)
{
	return _baseImplementation->OnWindowCreated(args);
}

This is basically what the C++ compiler does for you when you are using the language projections. It stores a pointer to the “real” class in a variable and uses this one to call any method that you don’t override in your code.

Obviously, I will need to create an instance of a class that implements the IApplicationOverrides interface somewhere and this leads us to how WinRT makes inheritance work in practice. WinRT actually supports inheritance through the activation factories. Each activation factory for a non-sealed runtime type implements an interface with a CreateInstance method that accepts an “outer” object that provides the implementations of the methods to be overridden. This would be the custom Program class in this case. Besides the created instance, the CreateInstance method also returns an “inner” object which provides the base implementation. It is this one that we pass to the SetBaseImplementation method of the Program class.

This is what happens in the callback of the Application.Start method. We use the GetActivationFactory function to get a reference to the factory for the Application class, create an instance of our custom Program class, and call the CreateInstance method of the factory. We then cast the returned IInspectable pointer to an IApplicationOverrides pointer to be able to inject the base implementation into the Program class before we return:

Microsoft::WRL::ComPtr<ABI::Windows::UI::Xaml::IApplicationInitializationCallback> callback =
Microsoft::WRL::Callback<ABI::Windows::UI::Xaml::IApplicationInitializationCallback>([](ABI::Windows::UI::Xaml::IApplicationInitializationCallbackParams*)
{
	Microsoft::WRL::ComPtr<ABI::Windows::UI::Xaml::IApplicationFactory> applicationFactory;
	HRESULT hr = Windows::Foundation::GetActivationFactory(
		Microsoft::WRL::Wrappers::HStringReference(RuntimeClass_Windows_UI_Xaml_Application).Get(),
		&applicationFactory);
	assert(SUCCEEDED(hr));

	/**/
	Microsoft::WRL::ComPtr<Program> outer = Microsoft::WRL::Make<Program>();
	IInspectable* inner;
	Microsoft::WRL::ComPtr<ABI::Windows::UI::Xaml::IApplication> instance;
	hr = applicationFactory->CreateInstance(outer.Get(), &inner, instance.GetAddressOf());
	assert(SUCCEEDED(hr));

	Microsoft::WRL::ComPtr<ABI::Windows::UI::Xaml::IApplicationOverrides> baseApp;
	hr = instance->QueryInterface(__uuidof(baseApp), &baseApp);
	assert(SUCCEEDED(hr));
	outer->SetBaseImplementation(baseApp.Get());

	return S_OK;
});

Microsoft::WRL::ComPtr<ABI::Windows::UI::Xaml::IApplicationStatics> applicationStatics;
hr = Windows::Foundation::GetActivationFactory(
	Microsoft::WRL::Wrappers::HStringReference(RuntimeClass_Windows_UI_Xaml_Application).Get(),
	&applicationStatics);
assert(SUCCEEDED(hr));

/* Application.Start(callback); */
hr = applicationStatics->Start(callback.Get());
assert(SUCCEEDED(hr));

The Make method tries to initialize a new instance of the Program class and returns either a ComPtr<Program> or a nullptr depending on whether the dynamic allocation succeeded. Remember that you can’t throw any exceptions here. You should always return an HRESULT. And just like in the C# sample, we don’t actually do anything with the instance of the Application class that was created.

As you notice, there is quite a lot more code involved here compared to when you do the same thing in C# or C++ with the language projections enabled. On the other hand it’s easier to understand where all things come from and how they fit together. Developers in general tend to like abstractions, happily unaware of what is really going on under the covers. In the case of WinRT, I think this is truer than ever. But even if you end up using these abstractions – which you certainly should in the case of developing UWP apps – having a sense for the low-level internals certainly won’t hurt you.

Advertisements


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 )

Google+ photo

You are commenting using your Google+ 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 )

Connecting to %s