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] [retval] int* number); } [version(1.0)] runtimeclass Widget { [default] interface 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(int* number) { *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([in] int 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** widget) override { *widget = Make<Widget>().Detach(); return *widget != nullptr ? S_OK : E_OUTOFMEMORY; } STDMETHODIMP CreateInstance(int value, IWidget** widget) override { *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 callingRelease
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<IWidgetFactory> const& factory) { 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(activatableClassId, nullptr); // 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(Widget, WidgetFactory)
Because many types only permit default construction, and because default construction makes use of theIActivationFactory
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(activatibleClassId, factory); }
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 aWidget
instance using that factory. These two steps are quite clear in the WRL code. RoGetActivationFactory
is a part of the Windows Runtime itself. It:
- finds the module that defines the named runtime type,
- loads the module (if it hasn't already been loaded),
- obtains a pointer to the module's
DllGetActivationFactory
entry point, - calls that
DllGetActivationFactory
function to get an instance of the activation factory, - calls
QueryInterface
on the factory to get a pointer to the requested interface, and - 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 themetadata 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 fromRoGetActivationFactory
to avoid having to round-trip through the runtime every time it needs to construct a Widget
. If our app creates lots of Widget
s, 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.