Channels ▼
RSS

.NET

Using C++ and COM with WinRT


Traditional Windows C++ development is powered by Win32 API calls. With Windows 8 platforms, however, applications must call a set of components named the Windows Runtime APIs. These components are also referred to as the WinRT API. This API is available for various languages: C#, VB, JavaScript, and C++. For C++ developers, there are two options: C++/CX or standard ISO C++. The first option, C++/CX, is a set of compiler extensions with the existing syntax of the C++/CLI plus ^ and % characters. C++/CX generates native code and hides the plumbing of WinRT. C++/CX is very well documented with samples. The other option is to choose standard C++ programming with a new library: Windows Runtime Library (WRL). This is the option Microsoft uses to develop WinRT APIs.

Windows Runtime Library

WRL is the successor of the popular Active Template Library (ATL), which allows developers to simplify the programming of COM components. WRL is inspired by ATL: It provides C++ templates and internally uses meta-programming and modern C++ techniques to easily develop new COM components. The source code of WRL is shipped as C++ headers with the Windows SDK. WRL is documented in MSDN, but there are few samples.

Enhancements to the COM Technology

Windows 8 brings new features to the COM technology with the new IInspectable interface that defines three new methods: GetIids, GetRuntimeClassName, and GetTrustLevel. The Windows Runtime is powered by COM, but it does not embrace the OLE technology. Everything relies on IInspectable, which inherits from IUnknown. There is no support for the IDispatch interface, ActiveX controls, or connection points. Importantly, the VARIANT data-type is not supported in Windows Store Apps.

But there is a new Windows string type named HSTRING. There are also a lot of new interfaces that cover various aspects like asynchronous operations, collections containers, and iterators that are exposed for all the languages. For the VB and C# languages, asynchronous operations are handled by async and await keywords. Collections are mapped to .NET framework interfaces like IList<T> or IDictionary<K, V>. The HSTRING data-type is mapped to System.String for .NET languages.

For C++, there is no projection layer, so the practice is just to make standard COM programming tasks with WRL and Windows types. COM programming requires interface and coclass elements to be defined in an IDL file. The MIDL compiler produces C source code for the proxy/stub and a type library (TLB). From there, you follow the same C++ conventions with minor changes. Your interfaces inherit from IInspectable and your runtimeclass elements (the old term was coclass) contain one or more interfaces. The new MIDL compiler produces the C proxy/stub and a Windows metadata (WINMD) file. This winmd file can be incorporated as a reference to C#, VB, or HTML5/JS projects.

Writing a Simple WinRT Component

To start WRL programming, you can download the WRL project template. This project template creates a basic WRL library project with an IDL file, a simple component, and a module that exposes the plumbing around the class factory. There is no wizard to add properties or methods to your class. You have to modify the IDL and the class source code files (.h and .cpp files) as in traditional COM programming.

// Library1.IDL
import "inspectable.idl";
import "Windows.Foundation.idl";

#define COMPONENT_VERSION 1.0
namespace Library1
{
    interface ILogger;
    runtimeclass Logger;

    [uuid(3EC4B4D6-14A6-4D0D-BB96-31DA25224A15), version(COMPONENT_VERSION)]
    interface ILogger : IInspectable
    {
        [propget] HRESULT Name([out, retval] HSTRING* value);
        [propput] HRESULT Name([in] HSTRING value);
        HRESULT LogInfo([in] HSTRING value);
    }

    [version(COMPONENT_VERSION), activatable(COMPONENT_VERSION)]
    runtimeclass Logger
    {
        [default] interface ILogger;
    }
}

You can see that the IDL file now contains namespace support. It's a new feature that is not present in traditional COM programming. I have added the Name property and the LogInfo method. The following is the associated C++ code that implements this interface:

#include "Library1_h.h"

namespace ABI
{
    namespace Library1
    {
        class Logger : public RuntimeClass<ILogger>
        {
            InspectableClass(L"Library1.Logger", BaseTrust)

        public:
            STDMETHOD(get_Name)(HSTRING* value) { return S_OK; }
            STDMETHOD(put_Name)(HSTRING value) { return S_OK; }
            STDMETHOD(LogInfo)(HSTRING value) { return S_OK; }
        };

        ActivatableClass(Logger);
    }
}

The class is declared in the ABI namespace. This is a required convention from Microsoft. The class inherits from a RuntimeClass<T> template that takes our interface as a template parameter. There are two macros in this source code:

  • InspectableClass defines the name of the WinRT component and its trust level.
  • ActivatableClass defines the class factory plumbing for that class.

Each method has to return HRESULT, so you can reuse the COM STDMETHOD() macro that is expanded as virtual __declspec(nothrow) HRESULT __stdcall.

Real-World Scenario: Returning a Collection of Objects

When you write real-world COM components, you have to return data and you need more than a string or a basic type. The best practice is to return objects in a collection that can be used with standard conventions like supporting the ForEach iteration pattern in other languages. In standard COM/OLE, you have to implement Count and Item properties to support Visual Basic ForEach. With the Windows Runtime, you have to follow the definition of some interfaces used by language projections to enable a client application in C#, for example, to do:

            
// C# client
Library1.Root root = new Library1.Root();
IList<String> list = root.GetVector();
foreach(string s in list)
   { ... }

At this point, you enter into undocumented features of the Windows Runtime. To find the appropriate information, you need to watch the Channel9 video and open the PowerPoint material from the Windows Runtime session presented at the BUILD 2011 conference (that covered the preview of Windows 8). It covers some interfaces named IVector<T>, IVectorView<T>, and IMap<T>. Using Visual Studio 2012 or Visual Studio 2013, you will discover that theses interfaces are defined in windows.foundation.collections.h. This file is included in the Windows SDK's include\winrt folder. If you look at the Microsoft BUILD conference materials, you will gather that there is a deep integration with STL. With C++/CX, a header called collection.h (described as Windows Runtime Collection/Iterator Wrappers) provides the necessary plumbing between standard STL containers and WinRT interfaces. But if you want to use standard COM programming, you have to provide your own infrastructure to embrace the WinRT interfaces with STL containers. So the deep STL integration is really only for C++/CX. For raw COM programming using standard ISO C++, we need to implement the various interfaces within C++ classes.

Reading the windows.foundation.collections.h file and looking at the MSDN information about the IVector<T> interface, you'll notice IVector<T> inherits from IIterable<T>, which in turn introduces IIterator<T> in the First() method. So, we have to implement these interfaces and their methods into a dedicated component. A new feature appears in the definition of these interfaces. They are defined like generics or templates. Let's examine these interfaces (I have made a little modification):

template <class T>
class IVector : IInspectable /* requires IIterable<T> */
{
public:
    // read methods
    virtual HRESULT GetAt(unsigned index, T *item) = 0;
    virtual HRESULT get_Size(unsigned *size) = 0;
    virtual HRESULT GetView(IVectorView<T> **view) = 0;
    virtual HRESULT IndexOf(T value, unsigned *index, boolean *found) = 0;
    // write methods
    virtual HRESULT SetAt(unsigned index, T item) = 0;
    virtual HRESULT InsertAt(unsigned index, T item) = 0;
    virtual HRESULT RemoveAt(unsigned index) = 0;
    virtual HRESULT Append(T item) = 0;
    virtual HRESULT RemoveAtEnd() = 0;
    virtual HRESULT Clear() = 0;
    // bulk transfer methods
    virtual HRESULT GetMany(unsigned startIndex, unsigned capacity, T *value, unsigned *actual) = 0;
    virtual HRESULT ReplaceAll(unsigned count, T *value) = 0;
};

template <class T>
class IIterable : IInspectable
{
public:
    virtual HRESULT First(IIterator<T> **first) = 0;
};

template <class T>
class IIterator : IInspectable
{
public:
    virtual HRESULT get_Current(T *current) = 0;
    virtual HRESULT get_HasCurrent(boolean *hasCurrent) = 0;
    virtual HRESULT MoveNext(boolean *hasCurrent) = 0;
    virtual HRESULT GetMany(unsigned capacity, T *value, unsigned *actual) = 0;
};

The IVector<T> interface contains all the access methods required for a vector. It is not difficult to associate these methods with the std::vector<T> methods. The IIterable<T> interface allows returning an iterator via IIterator<T>. The Iterator<T> interface represents the same concept of iterator that we know in the STL.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 

Video