Windows 8 Store apps with C++/CX: thoughts & tips

October 5, 2012

I’ve been working on Windows 8 apps lately using C++, not C#. I’ve been doing a lot of C# work in the past few years, and I must admit I love the elegance of C# and the productivity of .NET, not to mention the powerful toolset bound with Visual Studio. Still, ever since WinRT was introduced, the idea of using native code only had its appeal. Even if the app does not require special libraries, such as DirectX or C++ AMP, native code has less overhead and lower memory consumption compared to a .NET app.

Naturally, I was using the C++/CX extensions for working with Windows 8 Store apps, that certainly are much simpler than using WRL. During my coding efforts, I’ve come to a few realizations and ideas that I’m about to share. This is still work in progress, though, so I expect the list to grow over time.

Dependency Properties

Dependency properties are heavily used in templated (custom) and user controls. As I outlined in this post, declaring a dependency property with C++/CX is pretty verbose. Here’s the way to do it for some dummy user control:

// H file

[Windows::Foundation::Metadata::WebHostHidden]
public ref class DummyControl sealed : Windows::UI::Xaml::Controls::UserControl {
public:
    property DependencyProperty^ TextProperty {
        DependencyProperty^ get() { return _textProperty; }
    }
    property String^ Text {
        String^ get() { return (String^)GetValue(_textProperty); }
        void set(String^ value) { SetValue(_textProperty, value); }
    }

private:
    static DependencyProperty^ _textProperty;
};
// CPP file

DependencyProperty^ DummyControl::_textProperty = DependencyProperty::Register("Text", 
    TypeName(String::typeid), TypeName(DummyControl::typeid), 
    ref new PropertyMetadata(nullptr));

This is pretty verbose and boilerplate. I wish there was a C++/CX extension that would simply declare this for me. To improve things, I created a bunch of macros to aid in creating dependency properties. Here’s the result:

// H file
[Windows::Foundation::Metadata::WebHostHidden]
public ref class DummyControl2 sealed : Windows::UI::Xaml::Controls::UserControl {
public:
    DECLARE_DP(Text, String^);
};
// CPP file

DEFINE_DP(Text, String, DummyControl2, nullptr);

That’s it. DECLARE_DP accepts the property name and its type. DEFINE_DP accepts the property name, its type, the owner type and the default value.

If you’re having a deja-vu moment (like me), you must have been an MFC developer at some point in time. This certainly reminds me of the MFC macro pairs (such as DECLARE_DYNAMIC, IMPLEMENT_DYNAMIC and others). I don’t particularly like macros, but I feel there’s really no choice here, for productivity’s sake.

There are two more macros that we can use: DECLARE_DP_READONLY declares a DP as read only – its setter is marked as private. This is pretty useful, as it can substitute a value converter in certain scenarios. The second macro, DEFINE_DP_EX, allows specifying a callback method to execute when the DP changes. All the macros can be found in the attached file for this post.

Namespace issues

One thing that’s common in the .NET world is creating projects with names such as “MyProduct.Core” or “MyProduct.Core.Design”. The result of these kinds of names in .NET projects is a nested hierarchy of namespaces modeled after the project names. Creating a WinRT Component in C++ with a project name of “Abc.Xyz” makes the default namespace Abc_Xyz and not a nested namespace Abc.Xyz. We can change that manually (not fun, the XAML has to change as well as H and CPP files, but possible).

That’s not enough, however. When used in some app, the compiler complains that the “winmd file Abc_Xyz.winmd contains types outside the root namespace Abc_Xyz”. This is a requirement in WinRT, that namespaces and components have the same common name as top level namespace (as opposed to .NET where no explicit relationship between assemblies and namespaces need exist). That “Root namespace” is something that seems to exist as an environment variable within VS:

SNAGHTML29cad9e5_thumb1

However, there is no UI to change it. Changing the winmd file name doesn’t seem to help. Clearly, $(RootNamespace) has to come from somewhere, probably the project file itself. Closing the project and opening for editing reveals this:

  <PropertyGroup Label="Globals">
    <ProjectGuid>{885b056e-f692-4155-829f-c11f455e480e}</ProjectGuid>
    <Keyword>Win32Proj</Keyword>
    <ProjectName>Abc.Xyz</ProjectName>
    <RootNamespace>Abc_Xyz</RootNamespace>
    <DefaultLanguage>en-US</DefaultLanguage>
    <MinimumVisualStudioVersion>11.0</MinimumVisualStudioVersion>
    <AppContainerApplication>true</AppContainerApplication>
  </PropertyGroup>

OK, let’s change it from “Abc_Xyz” to “Abc.Xyz”. Now everything builds ok, but a strange bug is introduced at runtime. Any control defined in the component and used by some app (by adding a reference to the winmd file in the usual way), crashes with a strange COMException in the InitializeComponent call of the control (as part of XAML parsing). I spent hours trying to figure out what’s wrong – thinking it must be something wrong with my XAML. Eventually I made the XAML an empty control and it still crashed. Then I had an idea – I brought back the Abc_Xyz root namespace and reverted to Abc_Xyz code namespace – and voila – it started working correctly. This is clearly a bug, and I hope it’s fixed soon.

So, the moral here – don’t change the namespace name from underscore to nested namespaces!

Inheritance issues

WinRT doesn’t really like inheritance. If you’re familiar with COM, this is understandable. COM never supported inheritance in the usual sense, because there is no source code, so it’s not possible to take a C++ class and inherit a new C# class or vice versa. The closest thing COM has is known as aggregation, where an outer COM object created an inner COM object, and that inner object knows it was created as an aggregation, so it forwarded its IUnknown calls to the outer (parent) object, because it doesn’t have any way of knowing what interfaces the outer object supports:

image_thumb3

Although aggregation works (in a way), it’s awkward to setup and use. WinRT needed inheritance for UI related things, like user controls, so it must support language level inheritance. It does that by implementing the required interfaces behind the scenes with some other implementation magic, so that it looks like true inheritance.

That said, a public WinRT class must be sealed or inherit from an unsealed class. By the way, Platform::Object is a sealed class! it’s not the universal base class in the same way as System.Object is in .NET. The unsealed classes reside in the Windows::UI::Xaml namespace, such as Control, UserControl, Panel and such.

The problem is with data oriented classes. In the WPF/Silverlight world, class hierarchies are created, first with a simple class, typically named ObservableObject that implements the INotifyPropertyChanged interface, supporting the classic change mechanism required for correct data binding. How would that translate to WinRT? If we create an ObservableObject class and implement INotifyPropertyChanged (possible), we’re stuck, as the class must be marked sealed and nothing else can inherit from it.

Let’s put this aside, for a moment. Suppose we decide to implement INotifyPropertyChanged on every class that we’ll use directly and not rely on a base class. We still need a class hierarchy. Say we’re going for the classic zoo example, so we have an Animal class (that implements INotifyPropertyChanged) and now we want a Dog class that inherits from Animal. But that’s not possible, since Animal must be sealed. Is there a way out of this?

There are two options as far as I can see. The first is to use interfaces like so:

    interface class IAnimal {
        void MakeSound();
    };

    interface class IDog : IAnimal {
        void LookForBone();
    };

 

Now we can have a Dog class (implementing IDog) and so on. This works, because a WinRT class can implement as many interfaces as required. This leads to possible code duplication, as new classes would have to implement base interfaces even if they want the same implementation. We can work around that by introducing helper classes that provide stock implementation we can delegate calls to, but it’s not ideal.

Is there another way? In the WPF/Silverlight world, working with data objects that implement INotifyPropertyChanged is preferred to inheriting from DependencyObject and using dependency properties to get automatic change notifications. This is reasonable, so that we don’t get a dependency on WPF/SL assemblies, and remain neutral.

In WinRT, however, we can all WinRT classes and there is no segregation to components. The Windows::UI::Xaml::DependencyObject class is an unsealed class, so inheriting from that makes our own class unsealed as well. This allows us to write code like the following:

    public ref class Animal : Windows::UI::Xaml::DependencyObject {
    public:
        void MakeSound();
    };

    public ref class Dog : public Animal{
    public:
        void LookForBone();
    };

 

And we get close to true inheritance.

I would go as far as to say that the INotifyPropertyChanged interface is useless in WinRT, because even if we use existing C++ code, we’ll have to wrap it in WinRT types if we want that code to cross the ABI boundary.. We should just inherit from DependencyObject and use dependency properties to get change notifications. With the above macros, this is relatively easy.

I get the general feeling that C++ development for WinRT is not yet polished as it should be. Maybe that’s fine for a DirectX game, but for heavy XAML and data work, it’s barely adequate.

 

Dependency properties macros DPHelpers.h

Add comment
facebook linkedin twitter email

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*