Building WinRT or COM Components with C++ and WRL

When you want to make Windows 8.x applications using C++, there are few possibilities:

  • using C++/CX which are C++ compiler extensions
  • using WRL in standard C++ project

C++/CX is a complete change for writting C++ classes. The pointer and references symbols have changed. You have to pass only Windows Runtime types in your methods. Objects need to be constructed using ref new instead of new. Example:

// h file
namespace WindowsRuntimeComponent1
{
public ref class Logger sealed
{
public:
Logger();

public:
void LogInfo(String^ message);
};
}

// cpp file
using namespace WindowsRuntimeComponent1;

Logger::Logger()
{
}

void Logger::LogInfo(String^ message)
{
std::wstring str = message->Data();
String^ str2 = ref new String();
str2 = L"hello String^";
}

C++/CX is easy but your code is completely stucked with thoses ugly C++/CX extensions. There is another way to make WinRT components. This is the Microsoft way of doing things. It is called WRL, Windows Runtime Library. It is like ATL, the new ATL. Here is an example of a WinRT component using WRL:

// idl file
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), exclusiveto(Logger)]
interface ILogger : IInspectable
{
HRESULT LogInfo([in] HSTRING value);
HRESULT GetInt32([out] int * pValue);
}

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

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

public:
Logger();

public:
STDMETHOD(LogInfo)(HSTRING value);
STDMETHOD(GetInt32)(int * pValue);
};

ActivatableClass(Logger);
}
}

// cpp file
namespace ABI
{
namespace Library1
{
Logger::Logger()
{
}

STDMETHODIMP Logger::LogInfo(HSTRING value)
{
HString str;
str.Set(value);
std::wstring ws = str.GetRawBuffer(nullptr);
return S_OK;
}

STDMETHODIMP Logger::GetInt32(int * pValue)
{
*pValue = 10;
return S_OK;
}
}
}

With this kind of code, you stay with the real C++ and you use the built-in Windows type.
For string handling, there is a new handle or pointer called HSTRING and the WRL class that handles it is HString.

With WRL you can also create standard COM components. You just have to change the header or your classes to use a different RuntimeClass template and adjust your IDL file to use COM built-in types:

// idl file
import "oaidl.idl";
import "ocidl.idl";

#define COMPONENT_VERSION 1.0

[uuid(3AAF07AA-A699-4E7C-8F01-BFF237D22B1B), version(COMPONENT_VERSION)]
interface ILogger : IUnknown
{
HRESULT LogInfo([in] BSTR bstrMessage);
}

[uuid(F15D3912-E8B8-40C8-8CF3-354F0B8B93CC), version(COMPONENT_VERSION)]
library WRLCOMLibrary1
{
[uuid(75DB8F5A-F13F-4E16-A487-9CD26A874654), version(COMPONENT_VERSION)]
coclass Logger
{
[default] interface ILogger;
}
}

// h file
class Logger : public RuntimeClass<RuntimeClassFlags<ClassicCom>, ILogger>
{
public:
Logger();

public:
STDMETHOD(LogInfo)(BSTR bstrMessage);
};

CoCreatableClass(Logger);

This kind of construction works if you build a standard Win32 dll and add runtimeobject.lib to your linker input.

Advertisements

Tagged: , ,

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: