Christophe Pichaud on Microsoft Technologies - MVP Developer Technologies 2019-2020
Using WRL to implement events in a WinRT component with Standard ISO C++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.
To provide the support of event in a component, you have to declare a special type in the IDL file.
Here is a Logger component with its ILogger interface. This component has a LogInfo method and an event called LoggerChanged that will be invoked when the LogInfo is called and will provide the associated string parameter.
// Library1.IDL import "inspectable.idl"; import "Windows.Foundation.idl"; #define COMPONENT_VERSION 1.0 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 { HRESULT LogInfo([in] HSTRING value); [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; } }
Now we have a MIDL file, we can provide a class to implement our methods.
Microsoft has chosen to put every component in the ABI namespace so we respect this convention.
#pragma once #include "Library1_h.h" namespace ABI { namespace Library1 { class Logger : public RuntimeClass<ILogger> { InspectableClass(L"Library1.Logger", BaseTrust) public: Logger(); STDMETHOD(LogInfo)(HSTRING value); STDMETHOD(add_LoggerChanged)(ILoggerEventHandler* handler, EventRegistrationToken* token); STDMETHOD(remove_LoggerChanged)(EventRegistrationToken token); private: void Notify(HSTRING value); private: std::wstring name; bool m_observed; EventSource<ILoggerEventHandler> m_events; }; ActivatableClass(Logger); } }
The event LoggerChanged declared in the IDL file is provided with two methods with the add_ and remove_ prefix.
The event handling is made with a list of handler via the WRL EventSource<T> template with T has the delegate type.
The handlers are managed with Add and Remove methods for EventSource class. The invocation is done with the InvokeAll() method.
A WinRT class have to include the InspectableClass macro wich provides the name of the component. It is like the ProgId in COM.
You can notice there is also the ActivatableClass macro.
Let's look at the CPP implementation file.
#include "pch.h" #include "Logger.h" namespace ABI { namespace Library1 { Logger::Logger() { m_observed = false; } STDMETHODIMP Logger::LogInfo(HSTRING value) { HString str; str.Set(value); std::wstring ws = str.GetRawBuffer(nullptr); _LogInfo(ws.c_str()); Notify(value); return S_OK; } STDMETHODIMP Logger::add_LoggerChanged(ILoggerEventHandler* handler, EventRegistrationToken* token) { m_observed = true; m_events.Add(handler, token); return S_OK; } STDMETHODIMP Logger::remove_LoggerChanged(EventRegistrationToken token) { m_events.Remove(token); return S_OK; } void Logger::Notify(HSTRING value) { if (m_observed) { HString str; str.Set(value); m_events.InvokeAll(str.Detach()); } } } }
To handle HSTRING type, you can use the HString class. It allows to return std::wstring.
The entire source code of this article is available on the Windows Dev Center: WRL Sample for Vector,Async and Event support