Wine Developer's Guide/WinRT in Wine

From WineHQ Wiki
Jump to: navigation, search

Authors: Bernhard Koelbl

Under construction icon-red.svg
Work in progress: This page is currently undergoing extensive revision. External links to specific parts of this page may now be broken due to the section having been edited, moved, merged with another section, or removed altogether. Consult the table of contents to find the section you are looking for. There may be related discussion on the talk page.

1 Introduction

1.1 What is WinRT?

Windows Runtime (short: WinRT) is a new Win32 independent ABI, used by the Windows operating system. It finds its primary use in the Universal Windows Platform (UWP), which provides an API and execution environment (sandbox) to run apps in, but can also be directly accessed from Win32 programs.

Internally, WinRT is basically COM with extra spice and some "new" concepts.

1.2 IDL 3.0

WinRT defines its ABI in IDL files, much like COM. For this, it uses the IDL format 3.0, that has some new concepts, keywords and generally an even more object-oriented approach than the COM-IDLs.

1.2.1 Structure

A WinRT IDL file from the Windows platform SDK is generally structured like this:

import "other.idl"
import "other2.idl"

// Forward declares of enums, interfaces, structs and runtimeclasses from other files.
namespace Windows
{
    namespace OtherFeature
    {
        typedef enum OtherFooEnum;

        interface OtherFoo;
    }
}

// Forward declares of enums, interfaces, structs and runtimeclasses in this file.
namespace Windows
{
    namespace SomeFeature 
    {
        interface IFoo;
        interface IFooStatics;
        interface IFooStatics2;

        runtimeclass Bar;
        runtimeclass BarResult;
        runtimeclass BazHappeningEventArgs;
        runtimeclass Foo;
    }
}

// Declaration block of generic interfaces with a type.
namespace Windows
{
    namespace SomeFeature
    {
        declare
        {
            interface Windows.Foundation.IAsyncOperation<Windows.SomeFeature.BarResult*>;
            interface Windows.Foundation.TypedEventHandler<Wine.SomeFeature.Foo*, Wine.SomeFeature.BazHappeningEventArgs*>;
        }
    }
}

namespace Windows
{
    namespace SomeFeature
    {
        // Definitions of enums, interfaces, structs and runtimeclasses from this file. For more on this, refer to the next section.

        [
            contract(Windows.Foundation.UniversalApiContract, 1.0),
            exclusiveto(Windows.SomeFeature.Foo),
            uuid(abababab-cdcd-efef-1234-56789abcdef)
        ]
        interface IFoo : IInspectable
            requires
                Windows.SomeFeature.IFoo2
        {
            [propget] HRESULT MyProperty1([out, retval] Windows.SomeFeature.Bar **value);
            [propput] HRESULT MyProperty1(Windows.SomeFeature.Bar *value);
            HRESULT CreateOtherFoo([out, retval] Windows.OtherFeature.OtherFoo **other_foo_obj);
            HRESULT DoFoobarAsync([out, retval] Windows.Foundation.IAsyncOperation<Windows.SomeFeature.BarResult*> **operation);
            [eventadd] HRESULT OnBazHappening(
                [in] Windows.Foundation.TypedEventHandler<Windows.SomeFeature.Foo*, Windows.SomeFeature.BazHappeningEventArgs*> *handler,
                [out, retval] EventRegistrationToken *token);
            [eventremove] HRESULT OnBazHappening([in] EventRegistrationToken token);
        }

        [
            activatable(Windows.Foundation.UniversalApiContract, 1.0),
            activatable(Windows.SomeFeature.IFooFactory, Windows.Foundation.UniversalApiContract, 1.0),
            contract(Windows.Foundation.UniversalApiContract, 1.0),
            marshaling_behavior(agile),
            static(Windows.SomeFeature.IFooStatics, Windows.Foundation.UniversalApiContract, 1.0),
            static(Windows.SomeFeature.IFooStatics2, Windows.Foundation.UniversalApiContract, 5.0)
        ]
        runtimeclass Foo
        {
            [default] interface Windows.SomeFeature.IFoo;
            interface Windows.SomeFeature.IFoo2;
        }
    }
}

(Note: I didn't work out this example into far detail, meaning some things may look incomplete.)

1.2.2 Runtimeclasses

Now, let's take a look at the definition part from above, in particular the "Foo" "runtimeclass". Runtime classes (I'll refer to them as just classes from now on), are basically COM-objects and the key feature of WinRT: Based on their definition and attributes, they expose different COM-interfaces as members or statically. Classes can be instantiated directly [and/or only] through an activation factory (COM class factory), when they are marked by an "activatable" attribute.

Let's take a look at our example from above in more detail:

  • Foo resides in the "Wine.SomeFeature" namespace and has two interface members: "IFoo" and "IFoo2"
  • It can be activated (instantiated) either directly (much like a parameterless constructor in any OOP language) or through the "IFooFactory" iface, which provides all (parameterized and non parm.) constructors.
  • It also exposes static functions, through the interfaces "IFooStatics" and "IFooStatics2".

1.2.3 Interfaces

Interfaces in WinRT are mostly the same as in COM, but they have some additional features.

Let's take a closer look at "IFoo":

  • Like any COM-interface, IFoo has an interface-ID (UUID)
  • It's only meant to be used by the Foo class, thus marked with the "exclusiveto" property.
  • It inherits from IInspectable, which in turn also inherits IUnknown.
  • Any class that implements the IFoo interface also needs to implement the IFoo2 interface, denoted by "requires".
  • The interface's contents:
  1. IFoo has a property with getter and setter for a Bar object: "MyProperty1".
  2. IFoo has a method, which does its work asynchronously using the parameterized interface "IAsyncOperation".
  3. IFoo provides an event system "OnBazHappening".

1.2.4 Properties

You might already have noticed the huge amount of new properties IDL 3.0 brings with. This paragraph has a brief list of them:

Property Description
activatable An activatable (runtime) class
default The default interface of an instantiated (runtime) class
eventadd Function to add an event handler
eventremove Function to remove an event handler
out A value that is returned from a function, by reference - (Like out in C#)
propget Getter method of a property
propput Setter method of a property
retval The value that's used as return value in the C++ WinRT API
static A static interface to a class

2 Writing WinRT components for Wine

2.1 Style

WinRT components for Wine should be written in either Julliard style (e.g. ntdll, Windows.Gaming.Input) or WineD3D style (d3d11, vkd3d), with some minor additions:

  • In WinRT, lines can get very long due to the wild naming schemes introduced, so the imaginary max length of a line should be set at around 160 characters (instead of 120).
  • Replace STDMETHODCALLTYPE with WINAPI to reduce line length.