Introduction

This sample demonstrates how to create a simple Windows Runtime component in C++ using the WRL Library.It also demonstrates how to build async method and methods that return vector collection from STL vector container. It also support event handling.

Building the Sample

The sample is made with Visual C++ 2013.

Description

To provide async method, you have to inherit from a WRL template class and implement the IAsyncOperation interface.

 To provide a method that return a vector collection, you have to implement IVector, IIterable and IIterator interfaces. The template class Vector<T> can be used to handle all theses interfaces.

C++
Edit|Remove
        STDMETHODIMP Root::GetLoggerAsync(IAsyncOperation<ILogger*>** value) 
        { 
            ComPtr<task_based_async_operation<ILogger>> pObject = Make<task_based_async_operation<ILogger>>( 
                std::async([&]() -> ILogger* 
            { 
                ComPtr<Logger> p = Make<Logger>(); 
                return p.Detach(); 
            })); 
            *value = pObject.Detach(); 
            return S_OK; 
        } 
 
        STDMETHODIMP Root::GetVector(IVector<HSTRING>** value) 
        { 
            try 
            { 
                ComPtr<Vector<HSTRING>> v = Make<Vector<HSTRING>>(); 
                HString str1; 
                str1.Set(L"Edith"); 
                v->Append(str1.Get()); 
                HString str2; 
                str2.Set(L"Lisa"); 
                v->Append(str2.Get()); 
                HString str3; 
                str3.Set(L"Audrey"); 
                v->Append(str3.Get()); 
                *value = v.Detach(); 
                return S_OK; 
            } 
            catch (...) 
            { 
                return E_FAIL; 
            } 
        } 
 
        STDMETHODIMP Root::GetVectorInt(IVector<int>** value) 
        { 
            ComPtr<Vector<int>> v = Make<Vector<int>>(); 
            v->Append(11); 
            v->Append(8); 
            v->Append(3); 
            *value = v.Detach(); 
            return S_OK; 
        } 
 
        STDMETHODIMP Root::GetVectorData(IVector<IMyData *>** value) 
        { 
            ComPtr<Vector<IMyData *>> v = Make<Vector<IMyData *>>(); 
 
            HString str1; 
            str1.Set(L"Lisa"); 
            ComPtr<MyData> data1 = Make<MyData>(); 
            data1->put_Name(str1.Detach()); 
            data1->put_Age(8); 
            v->Append(data1.Detach()); 
 
            HString str2; 
            str2.Set(L"Audrey"); 
            ComPtr<MyData> data2 = Make<MyData>(); 
            data2->put_Name(str2.Detach()); 
            data2->put_Age(3); 
            v->Append(data2.Detach()); 
 
            *value = v.Detach(); 
            return S_OK; 
        } 

Source Code Files

How to wrap your custom type in a collection

Before using your custom type into a collection, like Vector<T>, you have to define a class and an interface for your custom type. The methods named GetCustomData() returns a vector of MyData objects, witch implement IMyData interface. Everything is defines into an IDL file:

 

C++
Edit|Remove
// Library1.IDL 
import "inspectable.idl"; 
import "Windows.Foundation.idl"; 
 
#define COMPONENT_VERSION 1.0 
 
namespace Library1 
{ 
    interface IMyData; 
    declare 
    { 
        interface Windows.Foundation.Collections.IObservableVector<HSTRING>; 
        interface Windows.Foundation.Collections.IObservableVector<int>; 
        interface Windows.Foundation.Collections.IObservableVector<IMyData *>; 
    } 
} 
 
namespace Library1 
{ 
    interface ILogger; 
    runtimeclass Logger; 
 
    [uuid(1FCD374B-2C3C-49E3-93A7-6FB801080D45), version(COMPONENT_VERSION)] 
    delegate HRESULT LoggerEventHandler([in] HSTRING e); 
 
    [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); 
        HRESULT GetInt32([out] int * pValue); 
        [eventadd] HRESULT LoggerChanged([in] LoggerEventHandler* handler, [out][retval] EventRegistrationToken* token); 
        [eventremove] HRESULT LoggerChanged([in] EventRegistrationToken token); 
    } 
 
    [version(COMPONENT_VERSION), activatable(COMPONENT_VERSION)] 
    runtimeclass Logger 
    { 
        [default] interface ILogger; 
    } 
 
    declare 
    { 
        interface Windows.Foundation.IAsyncOperation<ILogger*>; 
    } 
 
    interface IMyData; 
    runtimeclass MyData; 
 
    [uuid(3EC5B5D7-14A6-4D0D-BB96-31DA25224A16), version(COMPONENT_VERSION)] 
    interface IMyData : IInspectable 
    { 
        [propget] HRESULT Name([out, retval] HSTRING* value); 
        [propput] HRESULT Name([in] HSTRING value); 
        [propget] HRESULT Age([out, retval] int* value); 
        [propput] HRESULT Age([in] int value); 
    } 
 
    [version(COMPONENT_VERSION), activatable(COMPONENT_VERSION)] 
    runtimeclass MyData 
    { 
        [default] interface IMyData; 
    } 
 
    interface IRoot; 
    runtimeclass Root; 
 
    [uuid(3EC4B4D6-14A6-4D0D-BB96-31DA25224A16), version(COMPONENT_VERSION), exclusiveto(Root)] 
    interface IRoot : IInspectable 
    { 
        HRESULT GetLoggerAsync([out][retval] Windows.Foundation.IAsyncOperation<ILogger*>** value); 
        HRESULT GetVector([out][retval] Windows.Foundation.Collections.IVector<HSTRING>** value); 
        HRESULT GetVectorInt([out][retval] Windows.Foundation.Collections.IVector<int>** value); 
        HRESULT GetVectorData([out][retval] Windows.Foundation.Collections.IVector<IMyData *>** value); 
    } 
 
    [version(COMPONENT_VERSION), activatable(COMPONENT_VERSION)] 
    runtimeclass Root 
    { 
        [default] interface IRoot; 
    } 
} 

Support for Event Handler

The Logger component provided a LoggerChanged event that is raised each time the Logger.LogInfo method is called. Event support is declared in the IDL file with a delegate. Events are handled with the WRL template class EventSource<T>.

Support for IObservableVector<T> and VectorChanged event

The Vector<T> template class handles changes via triggered events : add_VectorChanged, remove_VectorChanged.

 

C#
Edit|Remove
        private void Button_Click_VectorString(object sender, RoutedEventArgs e) 
        { 
            try 
            { 
                Root root = new Root(); 
                LogInfo("root.GetVector()..."); 
                IList<string> list1 = root.GetVector(); 
                LogInfo("foreach..."); 
                foreach (string s in list1) 
                { 
                    LogInfo("string: " + s); 
                } 
 
                int count = list1.Count; 
                LogInfo("list Count=" + count.ToString()); 
 
                LogInfo("list1[0]=" + list1[0]); 
 
                IObservableVector<string> obsList1 = (IObservableVector<string>)list1; 
                obsList1.VectorChanged += obsList1_VectorChanged; 
 
                LogInfo("modifying item0..."); 
                string item0 = list1[0]; 
                LogInfo("list1[0]=" + item0); 
                list1[0] = "string 0 updated"; 
                list1[1] = "string 1 updated"; 
                list1.Clear(); 
                list1.Add("a new string A"); 
                list1.Add("a new string B"); 
                list1.Insert(0"another new string"); 
                list1.RemoveAt(1); 
 
                obsList1.VectorChanged -= obsList1_VectorChanged; 
            } 
            catch (Exception ex) 
            { 
                LogInfo("Exception! " + ex.Message + " " + ex.StackTrace); 
            } 
        } 

 

More Information

For more information on this sample, you can contact me or email me at christophepichaud@hotmail.com.

WRL is a C++ template library shipped with the Windows SDK 8 and 8.1. It allows to build WinRT components.

WinRT components are used in Windows Store Apps. Microsoft provides a new C++ set of compiler extensions for building WinRT components but this is not the standard ISO C++ and has some changes with operator ^ and ref keywords. Thoses extensions are aligned with the Managed C++ syntax but it generates native code.

But a lot of developers want to develop using the real and standard ISO C++ so this article is dedicated only with standard ISO C++. It is possible to write WinRT components using the WRL library and consume them into JS, C# or C++ XAML apps.

To start using WRL, you can download the WRL project template. First, a WinRT component is based on COM. So you have to provide a MIDL file with various interfaces. In COM, you used to inherit from IUnknown interface but with WinRT, you have inherit from IInspectable.

To implement async methods, Microsoft provides you a complete set of extensions to use with C++ extensions called C++/CX and PPL Taks. If you want to use Standard ISO C++ you have to investigate into the WRL include files and its inner C++ templates. There are no samples. The MSDN documentation describes some classes like AsyncBase but you have to provide your own plumbing around it.

To deal with collections, you have to use the new Windows types. Every thing is described into the windows.foundation.collections.h header. If you want to use Standard ISO C++ you have to investigate into this WinRT include files and its inner C++ templates. There are no samples to provide those kind of methods that return a collection of elements except for C++/CX compiler extensions.

For additional containers support, you can upgrade to this sample : http://code.msdn.microsoft.com/windowsapps/Windows-Runtime-Component-9b6c6989

Acknowledgements

I would like to say thanks to the creator of WRL, Sridhar Madhugiri, whose helpful comments led me to make improvements great and small to the source code. I extend my deep-felt thanks to Visual C++ Lead, Tarek Madkour, who transferred my first questions directly to Sridhar.