C++/CX Part 3 of [n]: Under Construction

C++/CX Part 3 of [n]: Under Construction

Rate This
  • Comments 2

See C++/CX Part 0 of [n]: An Introduction for an introduction to this series and a table of contents with links to each article in the series.

In this article, we'll take a look at the how runtime classes are constructed. We'll use the following Widget runtime class throughout this article:

    public ref class Widget sealed
    {
    public:
    
        Widget()           : _number(0)      { }
        Widget(int number) : _number(number) { }
    
        int GetNumber() { return _number; }
    
    private:
        int _number;
    };

This type has both a default constructor and a constructor with an int parameter. C++/CX runtime class constructors are largely the same as constructors for ordinary C++ class types. Like ordinary member functions, any constructor that is part of the public interface of the runtime class can only use Windows Runtime types in its signature. This rule applies to public and protected constructors of public runtime classes, because these form the interface of the runtime class. Otherwise, there isn't much more to say about runtime class constructors.

C++/CX adds a new operator, ref new, that is used to construct an instance of a runtime class. For example, we can easily construct a Widget instance using either of its constructors:

    Widget^ widgetZero   = ref new Widget();
    Widget^ widgetAnswer = ref new Widget(42); 

The behavior of ref new is comparable to that of new: it takes the runtime class to be constructed and a set of arguments to be passed to the constructor of that runtime class, and it constructs an instance of that type. Whereas new T() yields a T* pointing to the new object, ref new T() yields a T^. In this respect, ref new is similar to the make_shared helper function that can be used to safely construct a shared_ptr.

Much as we saw in the previous articles, aside from the syntactic tags that tell the compiler that Widget is a Windows Runtime type (e.g., ^ and ref), this code looks almost exactly like equivalent C++ code that works with ordinary C++ types. Constructors are declared the same way, and ref new is largely used in the same way as new is used. However, this syntactic simplicity hides quite a bit of complex machinery, which is what we're going to investigate here.

Because C++/CX hides all of the complexity here, we'll instead use WRL to explain how object construction works. So that we have somewhere to start, we'll translate our Widget type into WRL. First the IDL that declares the Widget runtime type and its default interface, IWidget:

    [exclusiveto(Widget)]
    [uuid(ada06666-5abd-4691-8a44-56703e020d64)]
    [version(1.0)]
    interface IWidget : IInspectable
    {
        HRESULT GetNumber([out] [retvalint* number);
    }
     
    [version(1.0)]
    runtimeclass Widget
    {
        [defaultinterface IWidget;
    }

And the C++ definition of the Widget type:

    class Widget : public RuntimeClass<IWidget>
    {
        InspectableClass(RuntimeClass_WRLWidgetComponent_Widget, BaseTrust)
    
    public:
    
        Widget()           : _number(0)      { }
        Widget(int number) : _number(number) { }
    
        STDMETHODIMP GetNumber(intnumber) { *number = _number; return S_OK; }
    
    private:
    
        INT32 _number;
    };

Please note: for brevity, error handling code has been omitted from most of the examples in this article. When writing real code, please be sure to handle error conditions, including null pointers and failed HRESULTs.

While this C++ Widget class defines two constructors, these constructors are implementation details of the Widget type. Recall from Part 1 that we only ever interact with a runtime class object via an interface pointer: since the constructors are not declared by any interface, they are not part of the public interface of the runtime class.

Where Do Widgets Come From?

The structure of a runtime class is an implementation detail of the particular language and framework that are used to implement the runtime class; thus, the way in which an object of such a type is constructed is also an implementation detail, since construction is inexorably linked to the structure of the type. Windows Runtime components are consumable from any language that supports the Windows Runtime, so we need a language-neutral mechanism for constructing runtime class objects.

The Windows Runtime uses activation factories for constructing runtime class objects. An activation factory is a runtime class whose purpose is to construct objects of a particular runtime class type. We will define a WidgetFactory activation factory that constructs Widget objects.

Like any other runtime class, an activation factory implements a set of interfaces. Every activation factory must implement the IActivationFactory interface, which declares a single member function: ActivateInstance. The ActivateInstance interface function takes no arguments and returns a default-constructed object. An activation factory can also implement user-defined factory interfaces that define other "construction" functions. For our WidgetFactory, we'll use the following factory interface:

    [exclusiveto(Widget)]
    [uuid(5b197688-2f57-4d01-92cd-a888f10dcd90)]
    [version(1.0)]
    interface IWidgetFactory : IInspectable
    {
        HRESULT CreateInstance([inint value, [out] [retval] Widget** widget);
    }

A factory interface may only declare factory functions: each function must take one or more arguments and must return an instance of the runtime class. The Widget runtime class has only one non-default constructor, so we only need to declare a single factory function here, but it's possible to define as many factory functions as are needed. When using C++/CX, the compiler automatically generates a factory interface for each public ref class, with factory functions whose arguments correspond to those of each of the constructors of the ref class.

In addition to defining a factory interface for the Widget type, we also need to annotate it in the IDL as being activatable. We do so using the activatable attribute, which has two forms, both of which we will use for our Widget type:

    [activatable(1.0)]
    [activatable(IWidgetFactory, 1.0)]

The first form declares the type as being default constructible. The second form declares that the IWidgetFactory is a factory interface for the runtime class. (The 1.0 in each is a version number; it is not relevant for this discussion.) When the midlrt compiler compiles the IDL file into a Windows Metadata (WinMD) file, it will use these attributes to add the correct set of constructors to the metadata for the runtime class.

Next, we need to implement a WidgetFactory type that implements both the IActivationFactory and the IWidgetFactory interfaces. Instead of using the WRL RuntimeClass base class template, we'll use the ActivationFactory base class template, which is designed to support activation factories.

    class WidgetFactory : public ActivationFactory<IWidgetFactory>
    {
        InspectableClassStatic(RuntimeClass_WRLWidgetComponent_Widget, BaseTrust)
    
    public:
    
        STDMETHODIMP ActivateInstance(IInspectable** widgetoverride
        {
            *widget = Make<Widget>().Detach();
            return *widget != nullptr ? S_OK : E_OUTOFMEMORY;
        }
    
        STDMETHODIMP CreateInstance(int valueIWidget** widgetoverride
        {
            *widget = Make<Widget>(value).Detach();
            return *widget != nullptr ? S_OK : E_OUTOFMEMORY;
        }
    };

ActivationFactory provides a default implementation of the IActivationFactory interface; this default implementation simply defines ActivateInstance as returning E_NOTIMPL. This is suitable for runtime classes that are not default constructible; for runtime classes that are default constructible (like Widget), we need to override ActivateInstance to actually default construct an object.

Make<Widget>() is effectively equivalent to new (nothrow) Widget(): it dynamically allocates memory for a Widget and passes the provided arguments to the Widget constructor. Like new (nothrow), it yields nullptr if allocation fails (remember, we can't throw an exception from a function implementing an interface, we must return an HRESULT). It returns a ComPtr<Widget>; since we are returning the interface pointer, we simply detach the pointer and return it (the caller is responsible for calling Release on all returned interface pointers).

That's all we need to implement the WidgetFactory activation factory. If we can get an instance of the factory, we can easily create Widget objects. For example,

    void Test(ComPtr<IWidgetFactoryconstfactory)
    {
        ComPtr<IWidget> widget;
        factory->CreateInstance(42, widget.GetAddressOf());
	
        // Hooray, we have a widget!
    } 

Where Do Widget Factories Come From?

To enable construction of Widget objects, we built a WidgetFactory, so to enable construction of WidgetFactory objects, we'll build a WidgetFactoryFactory. Then, to enable construction of those... Ha! Just kidding. ;-)

Each activatable runtime class is defined in a module (DLL). Each module that defines one or more activatable runtime classes must export an entry point named DllGetActivationFactory. It is declared as follows:

    HRESULT WINAPI DllGetActivationFactory(HSTRING              activatableClassId,
                                           IActivationFactory** factory);

This function is, in a sense, a factory for activation factories: it takes as an argument the name of a runtime class (activatableClassId) and it returns via the out parameter factory an instance of the activation factory for the named type. If the module does not have an activation factory for the named type, it returns a failure error code. (Aside: HSTRING is the Windows Runtime string type, which we'll discuss in a future article.)

Conceptually, we can think of the function as being implemented like so:

    HRESULT WINAPI DllGetActivationFactory(HSTRING              activatableClassId,
                                           IActivationFactory** factory)
    {
        // Convert the HSTRING to a C string for easier comparison:
        wchar_t const* className = WindowsGetStringRawBuffer(activatableClassIdnullptr);
    
        // Are we being asked for the Widget factory?  If so, return an instance:
        if (wcscmp(className, L"WidgetComponent.Widget") == 0)
        {
            *factory = Make<WidgetFactory>().Detach();
            return S_OK;
        }
    
        // If our module defines other activatable types, we'd check for them here.
    
        // Otherwise, we return that we failed to satisfy the request:
        *factory = nullptr;
        return E_NOINTERFACE;
    }

In practice, we should never have to do much work to implement this function. When C++/CX is used to build a component, the compiler will implement this function automatically if the _WINRT_DLL macro is defined (this macro is defined by default in the Windows Runtime Component project template in Visual Studio). With WRL, a bit of work is required, but it's quite straightforward. Each activatable class must be registered with WRL using one of the ActivatableClass macros. For example, to register our Widget type with its WidgetFactory activation factory, we can use the ActivatableClassWithFactory macro:

    ActivatableClassWithFactory(WidgetWidgetFactory)

Because many types only permit default construction, and because default construction makes use of the IActivationFactory interface and doesn't require any custom, type-specific logic, WRL also provides a helpful form of this macro, ActivatableClass. This macro generates a simple activation factory that allows default construction, and registers the generated activation factory. We used this macro in Part 1 when we translated the Number class from C++/CX into WRL.

If all of the activatable runtime classes are registered with WRL, we can simply have DllGetActivationFactory delegate to WRL and let WRL do all of the hard work.

    HRESULT WINAPI DllGetActivationFactory(HSTRING              activatibleClassId,
                                           IActivationFactory** factory)
    {
        auto &module = Microsoft::WRL::Module<Microsoft::WRL::InProc>::GetModule();
        return module.GetActivationFactory(activatibleClassIdfactory);
    }

At this point, we have everything that we need to make a runtime class constructible: we have a factory that can construct instances of our runtime class and we have a well-defined way to obtain the factory for any activatable runtime class, so long as we know the module in which that runtime class is defined.

Creating an Instance

We've finished implementing our activatable runtime class; now let's take a look at ref new and what happens when we create a Widget instance. At the beginning of this article, we started off with the following:

    Widget^ widget = ref new Widget(42); 

We can translate this into the following C++ code that uses WRL instead of C++/CX:

    HStringReference classId(RuntimeClass_WidgetComponent_Widget);
    
    ComPtr<IWidgetFactory> factory;
    RoGetActivationFactory(
        classId.Get(),
        __uuidof(IWidgetFactory),
        reinterpret_cast<void**>(factory.GetAddressOf()));
    
    ComPtr<IWidget> widget;
    factory->CreateInstance(42, widget.GetAddressOf());

Instantiation is a two-step process: first we need to get the activation factory for the Widget type, then we can construct a Widget instance using that factory. These two steps are quite clear in the WRL code. RoGetActivationFactory is a part of the Windows Runtime itself. It:

  1. finds the module that defines the named runtime type,
  2. loads the module (if it hasn't already been loaded),
  3. obtains a pointer to the module's DllGetActivationFactory entry point,
  4. calls that DllGetActivationFactory function to get an instance of the activation factory,
  5. calls QueryInterface on the factory to get a pointer to the requested interface, and
  6. returns the resulting interface pointer.

Most of these are straightforward and require no further comment. The exception is the first item: how, exactly, does the Windows Runtime determine which module to load to instantiate a particular type? While there is a requirement that the metadata for a type be defined in a WinMD file whose name is similar to the type name, there is no such requirement for the naming of modules: the Widget type may be defined in any module.

Every Windows Store app contains a file named AppXManifest.xml. This manifest contains all sorts of important information about the app, including its identity, name, and logo. The manifest also contains a section containing extensions: this section contains a list of all of the modules that define activatable types and a list of all of the activatable types defined by each of those modules. For example, the following entry is similar to what we would find for the Widget type:

    <Extension Category="windows.activatableClass.inProcessServer">
     <InProcessServer>
       <Path>WidgetComponent.dll</Path>
       <ActivatableClass ActivatableClassId="WidgetComponent.Widget" ThreadingModel="both" />
     </InProcessServer>
   </Extension>

The list includes only types defined by modules contained in the app package; types provided by Windows (i.e., types in the Windows namespaces) are registered globally, in the registry, and are not included in the AppXManifest.xml manifest.

For most projects, this manifest is created as part of the app packaging task that runs after an app is built. The contents of the extensions section is automatically populated via examination of the WinMD files for any referenced components and the manifests from any referenced Extension SDKs. When our app calls RoGetActivationFactory, the Windows Runtime uses this list to find the module it needs to load for the Widget type.

It should be noted that, for performance, activation factories may be cached on both sides of the ABI boundary: our component that defines the Widget type really only needs to create a single instance of the WidgetFactory; it doesn't need to create a new instance every time it is asked for the factory. Similarly, our app can cache the factory it got back from RoGetActivationFactory to avoid having to round-trip through the runtime every time it needs to construct a Widget. If our app creates lots of Widgets, this may make a huge difference. Both WRL and C++/CX are pretty smart with respect to this caching.

In Conclusion

It suffices to say that the C++/CX syntax hides a substantial amount of complexity! We started off with what were effectively four lines of C++/CX: two lines to declare the constructors, and two statements to demonstrate use of those constructors. We have ended up with, well, an awful lot more than that. For the two constructors, we have a Widget-specific factory interface, an activation factory that implements that interface and the IActivationFactory interface, and a module entry point that creates factories. For the ref new expressions, we have a round-trip through the Windows Runtime infrastructure.

Note that everything described here applies to the general case of defining a constructible type in one module and instantiating that type from another module. That is, this is the mechanism for constructing objects through the ABI. If the type is defined in the same module as the code that is instantiating the type, the compiler is able to avoid much of the overhead that is required for calls across the ABI boundary.  A future article will discuss how things work within a single module, but know that things are often much simpler in that case.

If you've found these articles useful, we'd love to hear from you in the comments!  Let us know if you have any questions, ideas, or requests, either about this series of articles or about C++/CX in general.  You can also follow me on Twitter (@JamesMcNellis), where I tweet about a wide range of C++-related topics.

Attachment: UnderConstructionSolution.zip
  • very cool...I will look in it.and I want know how many articals about this series.is there any outline.can you send it to my email:beyondvincent@gmail.com.

    thank you!

  • Hi James,

    Just to let you know. I read the articles in this series, and you do clarify stuff. Knowing the backgrond processes often helps developing the right intuition on how to work with the higher level constructs. Please keep it going.

    Regards,

    Marc.

Page 1 of 1 (2 items)