Skip to content

Accessing Windows Runtime (WinRT)

During one of my sessions at XDC 2019 in Miami, I demonstrated the ability to access the Windows Runtime (sometimes abbreviated as WinRT) from within Xojo. For those not familiar with WinRT it is an application framework meant as a replacement for the decades old Win32 API (at least the non-GUI parts of it). Because WinRT is COM-based, and entirely unmanaged code, accessing it directly from Xojo is possible.

Note: this article assumes some prior knowledge of COM. Since WinRT was introduced in Windows 8, the example code listed here can only be run successfully on machines with Windows 8 or later.

While WinRT is COM-based, it does introduce some new types, like HSTRING, that are not normally seen when dealing with COM. Also, all WinRT classes inherit from the IInspectable interface, compared with other COM classes which either inherit from IUnknown or IDispatch. Another difference is that you will not be able to create the COM classes the traditional way (i.e. using CoCreateInstance). Instead, a new API was introduced (RoActivateInstance) that accomplishes the same task.

Determining the class name and unique identifier

If you’ve done anything with COM/ActiveX you know you’ll need the ProgID or CLSID in order to create the COM object. For example, this is seen when you add a COM/ActiveX control using the IDE’s Insert->ActiveX Component menu:

While the IDE shields you from some of these details, all this information lies open in the Registry, and thankfully all the WinRT classes do as well. To see a list of all the classes that are accessible you can open regedit and navigate to:

HKEY_LOCAL_MACHINE->SOFTWARE->Microsoft->WindowsRuntime->ActivatableClassId

For this example we’ll be accessing Windows.Globalization.Calendar

As mentioned, WinRT introduces some new types like HSTRING. We’ll need to create these HSTRINGs before we can call RoActivateInstance. These new APIs generally live in combase.dll so we can simply declare and call them in Xojo code:

Declare Function WindowsCreateString Lib "combase.dll" (source As WString, length As UInt32, ByRef out As Ptr) As Integer
Declare Function WindowsDeleteString Lib "combase.dll" (hstring As Ptr) As Integer
Declare Function RoActivateInstance Lib "combase.dll" (classId As Ptr, ByRef inspectable As Ptr) As Integer

Dim className As String = "Windows.Globalization.Calendar"
Dim classId As Ptr    // This is our HSTRING that is returned
Dim result As Integer = WindowsCreateString(className, className.Len, classId)

After we’ve setup the HSTRING, we can then call RoActivateInstance to create our WinRT class:

Dim inspectable As Ptr
result = RoActivateInstance(classId, inspectable)

Because all WinRT classes inherit from IInspectable you can iterate through all the available interfaces this class supports. For brevity I’ve determined that the Calendar interface’s unique identifier is “{CA30221D-86D9-40FB-A26B-D44EB7CF08EA}” so with this knowledge we can then query for this interface and start using it:

Dim unknown As New COM.IUnknown(inspectable)
Dim interfacePtr As Ptr

result = unknown.QueryInterface(COM.IIDFromString("{CA30221D-86D9-40FB-A26B-D44EB7CF08EA}"), interfacePtr)

Assuming all went well, we can start calling methods on the interface. This part of course requires intimate knowledge of what the interface supports along with the specific location of each method. Most of this information is stored in a type library, which we interrogate when building out COM classes added by the IDE using the Insert->ActiveX Component menu. Another strategy would be to simply look up the header or IDL file in the Windows SDK.

What an IDL file looks like

We do need some prior knowledge of the IUnknown and IInspectable interfaces to know how many methods deep one of these methods are (i.e. they each contain 3 methods each and since IInspectable inherits from IUnknown we can offset by 6). For this example we’ll invoke GetCalendarSystem (which lives 13 methods deep).

// Note: GetCalendarSystemFunc is a delegate with the
//       prototype as described in the IDL (converted to Xojo):
//       Func(this As Ptr, ByRef value As Ptr) As Integer

// The GetCalendarSystem function lives 13 methods deep, which means we offset
// by 12 * the size of a pointer to call the 13th method
Dim func As New GetCalendarSystemFunc(interfacePtr.Ptr(0).Ptr(12 * COM.SIZEOF_PTR))
Dim source As Ptr
result = func.Invoke(interfacePtr, source)

If result = COM.S_OK THen
    Declare Function WindowsGetStringRawBuffer Lib "combase.dll" (source As Ptr, length As Ptr) As WString

    Msgbox WindowsGetStringRawBuffer(source, Nil)
End If

You can download this example project here

The Win32 API may not be going away, but don’t expect it to be getting any additional love from Microsoft. The Windows Runtime (WinRT) is the future, but until Windows 7 becomes obsolete it is still a tough sell. While accessing WinRT from Xojo (or any Win32-based app) has been possible since it was first introduced, hosting UWP controls is another matter. Thankfully Microsoft has recently introduced some new APIs to do just that. If you’re interested in reading further about it, here are some articles:

XAML islands

Windows.UI.Xaml.Hosting docs