Click here to Skip to main content
15,867,568 members
Articles / WinRT

Building WinRT components with C++/CX

Rate me:
Please Sign up or sign in to vote.
5.00/5 (3 votes)
3 Dec 2012CPOL17 min read 32.4K   278   8   1
This article demonstrates how to create different versions of WinRT components implementing a set of common interfaces.

Introduction

Windows 8 has been released last month and Visual Studio 2012 a few months ago. You can find a lot of articles and blogs that demonstrate how to implement a WinRT component with Windows 8. I installed Windows 8 on an old machine as well as a version of Visual Studio 2012 Premium and I tried to develop some patterns that I have been implementing many times with this new technology. Doing that I bumped into some issues and while looking for a solution on various blogs, I couldn't find any that was showing what I'm demonstrating in this short article.

Background

Although Microsoft presented WinRT as a new technology, it is in fact a quite old and proven technology that WinRT is using behind the scenes. Those who have been coding in the Microsoft ecosystem between 1995 to early 2000 have certainly already discovered that WinRT is in fact based off the good old COM technology made famous by Don Box in chronicles in the MSDN journal. So if like me you are a veteran in software you will find a lot of familiar things in WinRT and this article.

The power of COM 

COM stands for Component Object Model, a lot has been written about COM and I won't repeat every detail of this technology using my own words here. For those who really want to understand this technology and its philosophy I would advise you to read the book Essential COM written by Don Box.

First of all, COM is not .NET and COM is technically very different from .NET. COM and as a matter of fact WinRT which is an evolution of COM, are native technologies. .NET (C#) and Java are using a virtual machine to execute their code, this virtual machine sits on top of the machine language to abstract the execution of the program and makes it independent of the system APIs that are written in native code. Native code is code that can be executed directly by the microprocessor of your computer. During the 10 to 15 last years the fashion has been to use managed languages that are high level languages that generate code for virtual machines and free the developer from many responsibilities he would have writing native, also know as unmanaged code.

Languages like C++ are relatively static compared to modern languages like C# or Java and lack the ability of exposing objects that can be shared and dynamically loaded by other environment and languages like VB, Java, Python, JavaScript, etc... Those who have used the native interop of C# know that they can use methods from the native Win32 API, but they can't use directly a class that has been developed in native C++ (not C++/CLI!). COM has this ability to expose the native interfaces implemented by a binary object to other languages, even JavaScript and this since a long long time. I wrote in 2000 a retail application using a COM architecture used by HTMLA (HTML for application) where the programming language was MS JavaScript and the execution engine a particular version of Internet Explorer. Basically a desktop application that was using HTML as GUI, JavaScript as programming language and COM components for the core services. Doesn't this sound familiar to you? What is one of the programming model of windows 8 metro application? HTML5 with JavaScript and WinRT components. Hey Mr. Microsoft, looks like you are reviving a 10 to 12 year old technology available with IE5 and IE5.5!! 

One of the main interest of COM is that you can easily build applications that support a plug-in architecture or what I would call a component based architecture where you can support new features or type of data without touching the code of the main application. This is possible thanks to the ability of a COM object to expose as many interfaces you want and to be dynamically loaded into memory from a central repository using a factory mechanism. Once loaded in memory by its name, the application will ask the component if he can produce the interfaces the application requires from it to execute some features. This is also known as late binding. 

What I'm going to demonstrate in that article is how to implement the same interface with different WinRT components. I also present 2 different architectures to implement COM/WinRT components with C++/CX. 

You certainly have read that a WinRT component cannot be inherited, this article will also gives a clear understanding of why this is not possible.       

Interface and implementation classes

A WinRT interface which is also a COM interface used the binary structure of a C++ vtable which makes C++ the natural language to implement WinRT components. However Microsoft has done a great job to make COM more usable in the 21st century and it is also possible to write WinRT components with .NET and C# for example, like it was possible to write COM component with .NET.

Every COM object must implement the IUnknown interface, this interface provides 3 very important methods:

  • AddRef: Increment the reference count of the object
  • Release: Decrement the reference count of the object
  • QueryInterface: Allow the caller to query for a given interface if implemented by the object.
WinRT has added a new interface which is IInspectable and basically brings a reflection mechanism to COM. I haven't yet explore this interface and its usage so I won't talk much about it. Simply know that a WinRT always implements this interface as well and you don't have to do it, the compiler extensions do it for you.

What I'm going to do in this article is to define four simple interfaces and give two different implementations of them in C++/CX. Then we are going to see, if both architecture are interoperable with each others and with a robust client technology like .NET.

The following diagram gives a simple view of the possible architectures.

COM implementation diagram

Let me detail a bit this diagram:

  • COM interfaces are the interfaces exposed by the objects to the outside world. 
  • COM classes are the implementation classes of the components. Within C++/CX those classes are public ref classes. They are used to instantiate the components.
  • The C++ implementation classes are internal classes used to create an object hierarchy of the implementation.
If you look at the interfaces you can see that they represent a hierarchy where ICitizen inherits from IPerson and has an association with IAddress.

In the COM classes layer there is no hierarchy of classes, only an association between Citizen and Address.

Then in the C++ class layer we have again a full hierarchy and association diagram.

This pattern is one of the pattern I'm going to implement in this article. The idea of using such a pattern is to benefit of the full object orientation of C++ and use inheritance, polymorphism and all the features available to this modern language.

The second pattern is also represented in the above diagram, you just need remove the C++ class implementation to get it. Each COM class will be implemented without using a C++ class internal object model. As there is no inheritance of implementation this may lead to some code duplication. However in many cases it is not the case and a kind of reuse is possible.

Implementation with composition classes

The pattern is quite simple. The object model is created in C++ using all object oriented concepts at you disposal and it is then mapped with COM classes to be exposed to the outside boundaries. This model has some important implication because we are mapping 2 worlds with different concepts. Let me explain what I mean by that.

COM/WinRT components are created by a factory and they life cycle depends on a reference counting. Every time a reference to that object is passed to a method, it's reference counter is increased and when the method, or the object doesn't use it any more the reference counter must be decreased. When this counter becomes 0, the COM components is deleted from the memory. All references to COM component point to the same instance, this is similar to a reference in C# or Java.

In the C++ world we are using pointers, class reference and value classes that present a distinct life cycle management. In the composite model, each COM implementation is having a C++ class that represents the object and the associations that exist in the outside boundary are also mapped in the C++ class model. This means that the consistency between the 2 models has to be maintained in term of instances.

When you work on a reference of a COM component you work in fact on the internal instance of the composite class. The biggest problem is that when you create a COM component and associate it to another COM component, the association must also be created at the composition class level. We will see that this has complex implications!

There is a very important concept that you must understand with COM. Once the object is instantiated the only way to access it, are the public interfaces that the object exposes to the outside world. The implementation class with its protected, internal and private members is not accessible to the outside world. Even if when you create an instance of this object with C# or C++/CX you use the name of the COM class, the pointer you get is not a pointer to that class, but a pointer to the default interface.

However when you are creating this object in C++ and that you know that you are using a particular implementation of an in-process COM, then you can cast the interface to the implementation class, and gain access to internal members. Internal are in fact public members of the implementation class that are not exported by the DLL.

The following code extract illustrate the most critical aspect if that pattern.

C++
void Citizen::Address::set(IAddress^ value)
{
 WinRTCompV2::Address^ refAddress = nullptr;

 try
 {
    refAddress = (WinRTCompV2::Address^) value;
 }
 catch(InvalidCastException^ ex)
 {
    OutputDebugString(std::wstring().append(
    L"Address::set raised exception: " , ex->Message->Data()).c_str());
 }

 if (refAddress == nullptr)
 {
    refAddress = ref new WinRTCompV2::Address(value->Street, value->ZipCode, value->City);
 }

 CAddress* ptrAddress = &refAddress->GetAddress();
 m_ptrCitizen->SetAddress(ptrAddress, false);
 m_address = refAddress;

The set property of Citizen is of type IAddress^. This means that when you set the address you pass a new instance of the COM Address to the COM Citizen

The difficulty is to create the association between the CCitizen and the CAddress objects at the same time this association is modified between the COM components. The method assumes that the IAddress interface is implemented by the WinRTCompV2::Address object which implies that we have access to the internal methods of that object and in particular the GetAddress() method that returns a pointer to the internal CAddress object of the WinRTCompV2::Address implementation.

The  code checks that the cast could be done properly and in the case the implementation is not the one expected, create a new instance of Address and create the association in the composition class layer. The consequence is that the Address reference is not the same as the one passed by the calling program which means that if you modify the content of the passed Address object after the set, this change won't be reflected in the Citizen object. This is illustrated in one of the unit tests I provide with the code of the WinRT components.

Another interesting aspect of that pattern is that pone must be very careful with the deletion of the different objects. I haven't the time to implement it (this could be another article) but I would use a smart pointer with reference counting in order to manage the different pointers of the implementation as the same pointer to a composition object may be used in a COM class and in a composition class.

Direct implementation within the body of the WinRT component

This is were I had some difficulties with the new C++/CX compiler! In the early times of COM I would have defined the interface and coded the 2 implementations of this interface in the same DLL. But at this time you needed to declare your interface in an IDL file and give it some GUID and then write the implementation of the classes using ATL. Now it is much more easy, you don't even have to explicitly create an interface if you don't need to implement it in other objects. But there is a little problem if you try to have the interface and both implementation in the same DLL. The compiler is not happy because of the generation of the .winmd file. I couldn't find a solution to put both implementations in the same DLL but fortunately I could put them in a second DLL where I referenced the one that is declaring the interfaces. 

I haven't managed to find the explanation from Microsoft but it has to do with the namespace mechanism and the name of the metadata file. This looks a lot like Java that asks you to have a source file with the same name as the class and match the namespace hierarchy with the structure of the directories, if I remember well my Java moments!

Having say that WinRT introduces more rules and restrictions than the original COM technology, and this is one of them.

The second implementation is done directly in the body of the COM classes, there are no composition classes and if you remember another limitation of those classes, you cannot inherit from another class, you can only inherit (I prefer implement) from interfaces.

That means that the class Citizen cannot inherit from the class Person and that would lead to code duplication. However the original COM addresses this problem in two ways. One is known as COM aggregation and the other is dynamic composition. I don't know how to do COM aggregation with the C++/CX but the composition is very simple to achieve.

The Citizen object creates an instance of a Person object and wraps the methods/properties of the Person interface in its own implementation.

C++
namespace WinRTCompV3
{
    Citizen::Citizen(void) :
    m_person(ref new Person()),
    m_iAddress(ref new WinRTCompV3::Address())
    {
    }

    Citizen::Citizen(String^ name, String^ surname) :
    m_person(ref new Person(name, surname)),
    m_iAddress(ref new WinRTCompV3::Address())
    {
    }

    Citizen::Citizen(String^ name, String^ surname, WinRTCompV3::Address^ address) :
        m_person(ref new Person(name, surname)),
    m_iAddress(address)
    {
    }

    String^ Citizen::Name::get()
    {
    return m_person->Name;
    }

    void Citizen::Name::set(String^ value)
    {
        m_person->Name = value;
    }

    String^ Citizen::Surname::get()
    {
        return m_person->Surname;
    }

    void Citizen::Surname::set(String^ value)
    {
        m_person->Surname = value;
    }

    WinRTCompV2::IAddress^ Citizen::Address::get()
        {
    return m_iAddress;
    }

    void Citizen::Address::set(IAddress^ value)
    {
        m_iAddress = value;
    }

    bool Citizen::CanSave()
    {
        return m_person->CanSave() && m_iAddress->CanSave();
    }
}

The above implementation illustrates the simplicity of that pattern. In the case of this example it has proved much easier to implement the Citizen, Person, Address hierarchy directly without a set of composition classes. In some most complex cases it may be more interesting to use the composition classes. This is the pattern I used more than 10 years ago to implement a more complex hierarchy of COM objects using ATL. Using ATL also opens more possibility in term of source reuse and templates because COM classes are implemented directly in C++.

The C++/CX model introduces more simplicity in writing WinRT/COM component but for those like me who have used intensively ATL it is obvious that we loose a lot of power because we don't have any more the control of the framework. However I have barely scratched the surface of that new way of implementing the WinRT/COM components and there are some great benefits like the projection that eliminates the headache of the SAFEARRAY. Those who have used them know what I'm talking about!

A last interesting aspect of that little test is to mix both implementations of the interfaces I defined.

Mixing the two implementations

Mixing both implementation of the ICitizen and IAddress interfaces illustrates perfectly the boundaries of a WinRT component  and why you have to be extremely careful when you create them. In an interface based architecture, you must not assume that you can know what class is implementing an interface.

With mechanism like reflection many developers have built patterns that are not advisable with component technology like COM. When you design a COM base architecture if you intend to publish your components and make them available for other languages or technologies than the one you have used to develop them, then you must not assume that you can ask an interface to give you a given implementation class. It is better to build the whole architecture assuming that the only way to access the object is the interfaces that it publishes.

The following codes illustrates the wrong behavior when mixing with an implementation which is only compatible with itself.

C++
public void UnitTestMixingWinRTCompV2withWinRTCompV3()
{
 WinRTCompV2.IAddress addressV2 = 
   new WinRTCompV2.Address(TestData.TEXT_STR1, TestData.TEXT_ZIP1, TestData.TEXT_CTY1);
 WinRTCompV2.IAddress addressV3 = 
   new WinRTCompV3.Address(TestData.TEXT_STR2, TestData.TEXT_ZIP2, TestData.TEXT_CTY2);

 WinRTCompV2.ICitizen citizenV2 = 
   new WinRTCompV2.Citizen(TestData.TEXT_NAME1, TestData.TEXT_SURNAME1);
 WinRTCompV2.ICitizen citizenV3 = 
   new WinRTCompV3.Citizen(TestData.TEXT_NAME2, TestData.TEXT_SURNAME2);

 citizenV2.Address = addressV2;
 addressV2.ZipCode = TestData.TEXT_ZIP2;

 string zip2 = citizenV2.Address.ZipCode;
 Assert.AreEqual(TestData.TEXT_ZIP2, zip2);

 citizenV3.Address = addressV3;
 addressV3.ZipCode = TestData.TEXT_ZIP1;

 string zip3 = citizenV3.Address.ZipCode;
 Assert.AreEqual(TestData.TEXT_ZIP1, zip3);

 // Mixing Address V3 with Citizen V2
 citizenV2.Address = addressV3;
 addressV3.Street = TestData.TEXT_STR1;

 // The Street property has been changed AFTER the Address V3 was used for the Citizen V2
 string street2 = citizenV2.Address.Street;

 // Because it was not possible to create the association at the composition classes level,
 // the Street value in Citizen.Address is not updated.
 Assert.IsFalse(TestData.TEXT_STR1 == citizenV2.Address.Street);
 // However it is possible to mix V2 with V3 because in the V3 implementation the association
 // is between WinRT instances only
 citizenV3.Address = addressV2;br> addressV2.City = TestData.TEXT_CTY2;
 string city3 = citizenV3.Address.City;
 Assert.IsTrue(TestData.TEXT_CTY2 == citizenV3.Address.City);
}

I had to use IsTrue and IsFalse because of a reason I don't know although the strings are the same, AreEqual returns false for this test.

The interesting case is when you set the IAddress property of the WinRT component using the composition classes. Because the implementation of the property fails to get the CAddress object of the Adrress WinRT component, it cannot create the association with that object. A new reference of the right Address type is created internally and the association is established in the composition classes, that's why the Street which is updated in the Address after it is set to Citizen is not showing in the Address of the Citizen that was created internally.

In the second case, using an Address V2 with a Citizen V3 works because the association is directly between the COM instances and an individual Address V2 object perfectly works.

Implementing the interfaces in a second set of components in the same DLL

I originally tried to implement the second set of components in the same DLL using different a namespace but with the same implementation class names. This method failed and I had to create two separate DLLs to achieve this goal. I was a bit frustrated not to be able to do it so I tried to think if there would be a way to do it. In the original implementation of COM, you could create many components in the same DLL that would inherit from the same interface, I did it many times. One of the differences is that the component and interfaces were identified by GUID and there was no use of namespaces. This is how I found the solution: if you want to create several implementations of the same interface in the same DLL, you need to put the interface and the components in the same namespace.

C++
#pragma once

#pragma warning( disable: 4251 )

#include "../CompRTV2/CompRTV2.h"
#include <string>

using namespace Platform;

namespace WinRTCompV2
{
    namespace WUXD = Windows::UI::Xaml::Data;

    [WUXD::Bindable]    
    public ref class Address2 sealed : IAddress
    {
    private:
        std::wstring m_street;
        std::wstring m_zipCode;
        std::wstring m_city;

    public:
        Address2(void);
        Address2(String^ street, String^ zip, String^ city);

    public:
        virtual property String^ Street {
            String^ get();
            void set(String^ value);
        }

        virtual property String^ ZipCode {
            String^ get();
            void set(String^ value);
        }

        virtual property String^ City {
            String^ get();
            void set(String^ value);
        }

        virtual bool CanSave();
    };
}

This is the code of the declaration of the class Address2 which implements the interface IAddress. As this is just an example, I used the same implementation as the one in the other DLL.

I also corrected a bug in catch((InvalidCastException^ ex) of the set method of WinRTCompV2::Citizen. The new code looks like this:

C++
try
{
    refAddress = (WinRTCompV2::Address^) value;
}
catch(InvalidCastException^ ex)
{
    std::wstring msg = L"Address::set raised exception: ";
    msg.append(ex->Message->Data());
    OutputDebugString(msg.c_str());
}

WinRT has the following rules when it comes to implement an interface with several components:

  • In a single DLL, the interface and its implementations must appear in the same namespace.
  • If an interface is implemented by components with different namespace, then one DLL must be used for each namespace.

Points of Interest

I hope that this article and the code that comes with it will help you understand the challenges of implementing WinRT components and creating software architecture with them.

As a conclusion I would say that even if the composition pattern could help reduce the code footprint in some cases, it introduces complexity and risks that must be considered. In the case of my example in fact the direct COM class implementation is smaller and safer because there is no code duplication as using the dynamic composition of objects to achieve the inheritance of Person by Citizen works.

In a component technology like WinRT/COM you cannot override a method or a property, and you cannot access protected or internal members of the implementation of COM that you encapsulate in another one, even if it is the implementation of your base interface. But you can inherit the behavior and you can create a new version of a method. There are obvious limitations with this technology but there are also many advantages. 

I have a background of electronics. Imagine that you use some transistors to build another component. You cannot take a PIN of the transistor and replace it by a new PIN, but you can use the signal on that PIN, process it, and expose the result of that composition as a new component with its own characteristics. This is what WinRT/COM components are about. You can assemble them to create new components or a complete new system.

Like a transistor you can replace a component implementation by another as long as it respects the contract described for its interface.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect Connect In Private
Singapore Singapore
Software Architect, COM, .NET and Smartcard based security specialist.

I've been working in the software industry since I graduated in Electrical and Electronics Engineering. I chose software because I preferred digital to analog.

I started to program with 6802 machine code and evolved to the current .NET technologies... that was a long way.

For more than 20 years I have always worked in technical positions as I simply like to get my hands dirty and crack my brain when things don't go right!

After 12 years in the smart card industry I can claim a strong knowledge in security solutions based on those really small computers!
I've been back into business to design the licensing system for the enterprise solution for Consistel using a .NET smart card (yes they can run .NET CLR!)

I'm currently designing a micro-payment solution using the NXP DESFire EV1 with the ACSO6 SAM of ACS. I can then add a full proficient expertise on those systems and NFC payments.
This technology being under strict NDA by NXP I cannot publish any related article about it, however I can provide professional consulting for it.

You can contact me for professional matter by using the forum or via my LinkedIn profile.

Comments and Discussions

 
QuestionPVS-Studio and C++/CX Pin
Karpov Andrey30-Jan-13 20:36
Karpov Andrey30-Jan-13 20:36 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.