Weak references and how to write WinRT classes without using the C++/CX extensions

We have seen that WinRT objects are COM-based and circular references can cause memory leaks. Cycles should be avoided, whenever possible, and should be disposed by carefully releasing references. Cycles can be solved more easily by using weak references, such as weak_ptr in standard C++. WinRT defines a couple of standard interfaces for weak references, defined in WeakReference.idl:

 interface IWeakReferenceSource : IUnknown
 {
    HRESULT GetWeakReference(
        [out, retval] IWeakReference **weakReference);
 } 

 interface IWeakReference: IUnknown
 {
    HRESULT Resolve(
        [in] REFIID riid,
        [out, retval, iid_is(riid)] IInspectable **objectReference);
 }

Every class that wants to support weak references must implement IWeakReferenceSource, where the method GetWeakReference provides a weak reference for the object. The interface IWeakReference exposes the method Resolve, which resolves a weak reference by returning a strong reference to the object.

Windows Runtime Library helper functions

We know that two “kinds” of C++ can be used to work with WinRT objects. There is the old, plain C++, with COM interfaces, and there are several language extensions (named C++/CX) which offer syntax very similar to the old managed C++/CLI, completely hiding the details of the underlying COM implementation. The C++/CX extensions are certainly the recommended way to work with WinRT and should be used as much as possible. From what concerns weak references, the Windows Runtime Library, wrl.h, provides some helper C++ (not C++/CX) smart pointer classes and also a WeakRef class that wraps the interfaces above. These classes can also be used in C++/CX code. As explained here, WinRT system components generally implement IWeakReferenceSource, so if our reference cycle includes one system component, it can be broken. This code sample, also taken from here, shows how to use a WeakRef with a standard PropertySet collection.

#include <stdio.h>
#include <wrl.h> 

ref struct Foo
{
    Foo() { puts("Foo"); }
    ~Foo() { puts("~Foo"); } 

#ifndef WEAKREF
    property Platform::Object^ Container;
#else 
    Microsoft::WRL::WeakRef weakContainer;
    property Platform::Object^ Container
    {
        Platform::Object^ get()
        {
            Microsoft::WRL::ComPtr<IInspectable> objRaw(nullptr);
            weakContainer.As(&objRaw);
            return reinterpret_cast<Platform::Object^>(objRaw.Get());
        }
        void set(Platform::Object^ obj)
        {
            Microsoft::WRL::AsWeak(reinterpret_cast<IInspectable*>(obj), &weakContainer);
        }
    }
#endif 
}; 

int main(lang::array<Platform::String^>^ args)
{
    Foo^ foo = ref new Foo();
    Windows::Foundation::Collections::PropertySet^ ps = ref new Windows::Foundation::Collections::PropertySet(); 

    // create a reference cycle 
    ps->Insert("foo", foo);
    foo->Container = ps; 

    // make sure we can dereference the weak ref 
    assert(dynamic_cast<Windows::Foundation::Collections::PropertySet>(foo->Container)->Lookup("foo") == foo); 

    // clear roots 
    ps = nullptr;
    foo = nullptr;
}

Compiled with: cl.exe /ZW /AI C:\Windows\System32\WinMetadata, the code above causes a circular reference and the ~Foo() destructor is never called. But adding /DWEAKREF to bring in the  WRL::WeakRef code, we can see that Foo is properly destroyed at the end of the scope.

Implementing WinRT classes with “Native C++”

Unfortunately, the classes declared using the ref class extension do not implement IWeakReferenceSource, so there is no easy way (at least, in this pre-release version of VS11) to support weak references in custom classes. So, the only solution I found to implement a WinRT class that supports the IWeakReferenceSource interface is to follow the “not easy” way: disable the WinRT extensions (the /ZW compilation flag) and use pure, good ol’ C++. There is one of the WinRT samples (the “DLL server authoring sample”) that shows what to do and it’s a very useful reference. Weak references aside, manually implementing a WinRT class is a very useful experiment, which shines a light on the details of the internal WinRT machinery. The procedure to follow to implement a WinRT object is not very different from the one that was required to implement COM objects with ATL, in the past.

1. The first step is to create a normal Win32 DLL project, without WinRT extensions. Then, we create a file .idl that contains the declaration of our RT object and of its interfaces:

#include <sdkddkver.h>
import "Windows.Foundation.idl";

namespace Microsoft.Samples.DllServerAuthoring
{
    // Forward declarations
    runtimeclass Toaster;

    // Interface definitions
    [version(1.0), uuid(6A112353-4F87-4460-A908-2944E92686F3), exclusiveto(Toaster)]
    interface IToaster : IInspectable
    {
        HRESULT MakeToast([in] HSTRING message);
    }
    [version(1.0), activatable(1.0)]
    runtimeclass Toaster
    {
        [default] interface IToaster;
    }
}

This file is compiled with the standard MIDL tool, which is now been upgrated to support WinRT. Together with the header file, the proxy/stub implementation and the type library, it now also generates a metadata file in the .winmd format. The command line for MIDL is:

/metadata_dir "C:\Program Files (x86)\Windows Kits\8.0\Windows Metadata"
/winrt /W1 /nologo /char signed /env win32 /winmd  "<file>.winmd" /h "<file>.h"
/iid "<file>_i.c" /proxy "<file>_p.c" /tlb "Debug\<file>.tlb" /enum_class

The winmd file is .NET compatible and viewable with the ILDASM tool:

clip_image001

2. The next step is to implement the WinRT class. For COM we would have used the ATL template library to simplify the work and reuse a lot of complicated boilerplate code. Here we can use WRL, the Windows Runtime Library, normally installed under C:\program files (x86)\windows kits\8.0\include\winrt. It is a very interesting piece of code, implemented with very elegant template programming at the state of the art, and that I hope to be able to describe more in a future post. The important class here is WRL::RuntimeClass, which has more or less the role that CComObjectRoot used to have in ATL. The Toaster object declared in the idl will be implemented with code like this:

#include <Windows.Foundation.h>
#include <wrl\implements.h>
#include <wrl\event.h>

#include "Microsoft.Samples.DllServerAuthoring.h"

namespace Microsoft { namespace Samples { namespace DllServerAuthoring {
class Toaster : public Microsoft::WRL::RuntimeClass<
        Microsoft::Samples::DllServerAuthoring::IToaster>
{
    InspectableClass(RuntimeClass_Microsoft_Samples_DllServerAuthoring_Toaster,
                     TrustLevel::BaseTrust);
    public:
        Toaster() {}
        ~Toaster() {}

        // IToaster
        IFACEMETHOD(MakeToast)(_In_ HSTRING hstrMessage) { … }
};

} /* DllServerAuthoring */ } /* Samples */ } /* Microsoft */

One of the nice things of RuntimeClass is that, by default, it is configured to automatically implement IWeakReferenceSource. So, weak references come for free with the code above.

3. Finally, we need to add what is left to compile the DLL. A DEF file, which exports the two following functions:

LIBRARY Microsoft.Samples.DllServerAuthoring.dll

EXPORTS
    DllCanUnloadNow         PRIVATE
    DllGetActivationFactory PRIVATE

And a few lines of code to implement the two functions using WRL:

#include <wrl\module.h>
#include "Microsoft.Samples.DllServerAuthoring.h" // generated from the idl
#include "Toaster.h"

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

STDAPI DllCanUnloadNow()
{
    auto &module = Microsoft::WRL::Module<Microsoft::WRL::InProc>::GetModule();
    return module.Terminate() ? S_OK : S_FALSE;
}

namespace Microsoft { namespace Samples { namespace DllServerAuthoring {
    ActivatableClass(Toaster)
} /* DllServerAuthoring */ } /* Samples */ } /* Microsoft */

This is all. The DLL, once compile, will be the “COM server” for the WinRT “Toaster” class, which supports weak references.

2 thoughts on “Weak references and how to write WinRT classes without using the C++/CX extensions

  1. Thank you very much and congratulations for this great article! I am curious to know if the collection interfaces (like Windows.Foundation.Collections.IIterable) are defined in IDLs too? I see them in the winmd but I can’t find them in the IDLs supplied in the Windows Kits folder. Thanks, best regards!!

  2. Hi Cesar, I have not played with WinRT for a long time now, but I guess that the reason there is no Windows.Foundation.Collections.idl is that the IIterable interface is templatized, and IDLs do not support templates (I think). Instead, the concrete IIterables are declared in several IDLs, for example windows.ui.xaml.idl has declarations for Windows.Foundation.Collections.IIterable<Windows.UI.Xaml.DependencyObject*> (and many others). Thanks again and Best regards!

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