Click here to Skip to main content
Click here to Skip to main content

Building WinRT components that implement interfaces with C#

, 14 Dec 2012
Rate this:
Please Sign up or sign in to vote.
This article demonstrates how to implement interfaces defined for a WinRT component in a C# Windows store DLL or a C# Windows store application.

Introduction

In a previous article I showed how to create WinRT components in C++/CX that implement a set of interfaces. For demonstration I provided several implementations of the same interface in different components. This article extends the exercise and will show you how to create WinRT components in C#, i.e., .NET that implement interfaces that have been defined in a C++/CX Windows store DLL. 

What I'm showing in this article is valid at the time I'm writing it because while creating those components with Visual Studio 2012, I discovered some bugs in the compilers and hopefully those bugs will soon be fixed by Microsoft.

Background

I suggest that before going through this article, you first read the previous one as the interfaces I'm using are created there. As I mentioned before even if Microsoft is trying to hide it, WinRT is in fact fully based on the COM technology introduced in Windows 3.11 for OLE (Object Linking and Embedding). So if you have a COM knowledge you will find this very simple.

The interfaces 

In the previous article I have defined with C++/CX three very simple interfaces IPerson, ICitizen, and IAddress, and I have given few different implementation in C++. C++/CX makes it very easy to create components for the Windows store, so easy that it even hides the fact that those components can only exist if they have an interface, so they generate a default one for you.

However if you create your own component architecture, you will design your own interfaces that are the only way to interact with components. Unlike in a class based design, in a component design, objects can only be accessed by their interfaces that expose behaviors and properties. A component like an interface only has public members, there is no protected, internal or even private members in a component. There is its interfaces and the implementation which you don't have access.

The interfaces are defines as follows.

namespace WinRTCompV2
{
    /**
        @brief Defines the behavior of an object that can be saved.
    */
    public interface class ISaveable
    {
        /**
            Check if the object can be saved
            @return  true if can be saved, false otherwise
        */
        bool CanSave();
    };

    /**
        @brief Represents a simple address
    */
    public interface class IAddress : ISaveable
    {
        /**
            Street element of the address
        */
        property String^ Street;

        /**
            ZipCode of the address
        */
        property String^ ZipCode;

        /**
            City of the address
        */
        property String^ City;

    };

    /**
        @brief Represents a simple person object
    */
    public interface class IPerson : ISaveable
    {
        /**
            Name property for the person
        */
        property String^ Name;

        /**
            Name property for the person
        */
        property String^ Surname;
    };

    /**
        @brief Represents a citizen, defined as a person with an address
    */
    public interface class ICitizen : IPerson
    {
        property IAddress^ Address;
    };
}

C++/CX defines the keyword interface as an extension to the C++ language. This interface when you create WinRT component is not like in C# a reference to a managed object, it is really pointing to a physical address in memory. WinRT components are native. Of course when you're going to implement it in C# the code is going to be executed in the CLR, but the pointer to this object that you would get when creating it in a C++ program is a pointer to a kind of bootstrap that is calling the C# implementation.

One characteristic of COM was that you could implement a COM component with different languages like C++ or VB and later C# in .NET. WinRT is not different and that's why we can also implement WinRT components in C#. In fact I suspect that the code behind the scene when you implement a WinRT component in C# is very similar to the one of a COM component implemented in C# as well!  

Implementing the interfaces in a Windows store C# DLL

In Visual Studio if you select C# and Windows store, you are given few project templates. The one we are interested in now is Windows Runtime Component. In a Windows Runtime component all classes that are marked public will be exported as WinRT components, which means that they will be modern COM objects!

There are few rules that you have to follow when you create a WinRT components with a C# class.

  • The class must be marked sealed
  • The class cannot inherit from any other class
  • The class can implement one or several interfaces

The first implementation I did of the interface IPerson was the following:

public  sealed class Person : IPerson
{
    #region Fields

    private string name;
    private string surname;

    #endregion

    #region Constructors

    public Person()
    {
    }

    public Person(string name, string surname)
    {
        this.name = name;
        this.surname = surname;
    }

    #endregion

    public string Name
    {
        get { return name; }
        set { name = value; }
    }

    public string Surname
    {
        get { return surname; }
        set { surname = value; }
    }

    public bool CanSave()
    {
        return name.Length > 0 && surname.Length > 0;
    }
}

At first sight this code looks correct and it should because it is what the compiler generates for you when you ask it to implement the interface. 

But in fact this code doesn't compile because there is currently a bug with the C# compiler. If you try to compile this code you will get the following error for both the Name and Surname properties:

Method 'WinRTCompNetDll.Person.WinRTCompV2.IPerson.set_Name(System.String)' has a parameter named '' whereas the corresponding parameter in the implemented interface method 'WinRTCompV2.IPerson.Name.set(System.String)' is named '__param0'. Please make sure that the names are identical.    

This problem is known by the Visual Studio product group of Microsoft and they kindly gave me two workarounds to be able to implement an interface defined in C++/CX DLL in a C# component. 

The first and most efficient solution to create a C# component is to simply implement the interface explicitly. The code that can now compile looks like this:

public  sealed class Person : IPerson
{
    #region Fields

    private string name;
    private string surname;

    #endregion

    #region Constructors

    public Person()
    {
    }

    public Person(string name, string surname)
    {
        this.name = name;
        this.surname = surname;
    }

    #endregion

    string IPerson.Name
    {
        get { return name; }
        set { name = value; }
    }

    string IPerson.Surname
    {
        get { return surname; }
        set { surname = value; }
    }

    public bool CanSave()
    {
        return name.Length > 0 && surname.Length > 0;
    }
}

This solution has a little side effect in the way you can use the component in your program. In their quest to simplification of COM the architects of WinRT have decided that the compiler will automatically generate an interface from the public members of the implementation class. Unlike pure COM you don't need to always have an interface to use the component, you can directly use the class if you only need the default interface of your component. The problem is that now the properties of our class Person are private and can only be used when you explicitly get the interface. If you try to use directly the implementation class, you will only see the method CanSave(). This aspect is demonstrated in the unit test of the project.

The second solution they gave me is to implement the components in a Windows store application.

Implementing the interfaces in a Windows store C# application

In fact this is the first solution that a very helpful support of Microsoft gave me and when I tried it I found few issues that I want to share with the readers of CodeProject.

In a Windows store component DLL if you try to create a public class that is not sealed you will get a compilation error. However when I tried to implement my interfaces in a Windows store App I discovered that I can create a public class that implements a C++/CX interface that is not sealed... This is breaking the rule that all Windows store component classes must be sealed.

Then because I was able to create that non sealed classes I tried to create a public sealed class that inherits from that previous class and implements one of my C++/CX interfaces. This is breaking another rule of a WinRT component class, which is that you cannot inherit from another class.

Here is the code of those classes.

namespace WinRTCompNet
{
    public class Person : IPerson
    {
        protected string display = string.Empty;
        private string name = string.Empty;
        private string surname = string.Empty;

        public Person()
        {
        }

        public Person(string name, string surname)
        {
            this.name = name;
            this.surname = surname;
            FormatDisplay();
        }

        public string Name
        {
            get { return name; }
            set 
            { 
                name = value;
                FormatDisplay();
            }
        }

        public string Surname
        {
            get { return surname; }
            set 
            {
                surname = value;
                FormatDisplay();
            }
        }

        public bool CanSave()
        {
            return Name.Length > 0 && Surname.Length > 0;
        }

        private void FormatDisplay()
        {
            display = string.Format("{0} {1}", name, surname);
        }
    }
}

namespace WinRTCompNet
{
    public sealed class Citizen : Person, ICitizen
    {
        public Citizen() :
            base()
        {
            this.Address = new Address();
        }

        public Citizen(string name, string surname, Address address) :
            base(name, surname)
        {
            this.Address = address;
        }

        public IAddress Address
        {
            get;
            set;
        }

        public string FormatDisplay()
        {
            return display;
        }

        public bool CanSave()
        {
            return base.CanSave() && Address.CanSave();
        }
    }
}

There is more than just the sealed and inheritance issue to consider. I declared a protected member in the class Person as well as a private method with the only purpose to set the value of the protected member. Then in the inherited class I created a public method with the same name as the private of the base class and which returns the value of the protected member. All this compile and perfectly work!

You can also notice that in the Windows store app, the public implementation of the interface IPerson works while it was giving a compilation error in the DLL.

I have tested this implementation in a C# unit test and it works. In this test I declare a variable of IPerson type and I assign to this interface either the C++/CX implementation or the C# implementation from the Windows store application. I have also used the component implemented in the Exe in a very simple app. Those two tests seem to prove that those illegitimate components can be use properly. However I wanted to be 100% sure that they really are WinRT components by using them in a C++ unit test.

The Exe can be referenced in the project and intellisense sees the namespace and the components, so I wrote a simple test but unfortunately the DLL cannot compile. The weird stuff is that the compiler simply cannot find the namespace... while intellisense can. I have submitted those few issues to Microsoft and I'm expecting an explanation or a solution any time soon. 

Points of Interest

The example I give is very simple, but as it illustrates few issues that you will encounter if you try to implement in C# interfaces that you have defined in a C++/CX component, I hope that you will find it useful. I personally searched this issue on the internet and because I couldn't find any solution to this problem, I wrote a post on a Microsoft forum and I got a fast answer from them as well as a very good follow-up on that problem.

WinRT even if it's been built on top of a proved technology like COM still looks like in the early stage of maturation. It is obvious that the support in Visual Studio of WinRT still needs to be polished by the VS product group of Microsoft. But it is an exciting evolution of Windows app development that puts C++ and component architecture development back into business.

License

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

About the Author

orouit
Architect Consistel - Singapore
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'm currently back in the business to design the licensing system for the enterprise solution I'm currenly working on, using a .NET smart card (yes they can run .NET CLR!)
 
View my profile on LinkedIn
 
You can contact me for professional consulting by using the forum.

Comments and Discussions

 
-- There are no messages in this forum --
| Advertise | Privacy | Mobile
Web01 | 2.8.140709.1 | Last Updated 14 Dec 2012
Article Copyright 2012 by orouit
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid