Whenever your Windows Runtime (WinRT) component has to implement COM interfaces as well as WinRT interfaces, Microsoft advises you to use the Windows Runtime Template Library (WRL), because the C++/CX – which otherwise is recommended to develop WinRT components – does not allow to implement COM interfaces.
However, if you are trying to use some of Microsoft’s publicly available samples from a .NET component, you might run into trouble. The problem is, that the winmd file that gets generated when you compile a WRL C++ Component – by default – does NOT reference the “Windows.winmd”-file, which provides the meta data for the WinRT API as a whole. Instead, it references only the particular winmd-files that describe partial areas of the WinRT API. These partial WinRT descriptions can all be found at a location similar to “C:\Windows\System32\WinMetadata”, whereas the complete WinRT API can be found at “C:\Program Files (x86)\Windows Kits\8.0\Windows Metadata\Windows.winmd”.
To demonstrate this problem I am referring to Microsoft’s “Real-time communication sample” that can be found at http://code.msdn.microsoft.com/windowsapps/Simple-Communication-Sample-eac73290. If you try to consume the “Microsoft.Samples.SimpleCommunication” component, which is part of the solution, from a Metro-style based C# application, you will have to add a reference to the components winmd-file (“Microsoft.Samples.SimpleCommunication.winmd”). Your C# application will still work fine. However, try to instantiate a class such as StspMediaSink next:
Microsoft.Samples.SimpleCommunication.StspMediaSink k = new Microsoft.Samples.SimpleCommunication.StspMediaSink();
This should produce the following error at compile time:
The type 'Windows.Media.IMediaExtension' is defined in an assembly that is not referenced. You must add a reference to assembly 'Windows.Media, Version=255.255.255.255, Culture=neutral, PublicKeyToken=null, ContentType=WindowsRuntime'.
Metro-style based C# applications by default reference the WinRT API as a whole. This means that your project references the “Windows.winmd”-file. The problem now is, that the compiler is not smart enough to recognize, that the Windows.Media.IMediaExtension-interface, which is implemented by the StspMediaSink-class, is already defined in the referenced “Windows.winmd”-file. Instead it wants you to add a reference to the same “Assembly”.
You cannot simply go ahead and add a reference to the “Windows.Media.winmd”-file as requested. If you added a reference to Windows.Media.winmd the compiler would complain about ambiguous references to Windows.Media.IMediaExtension. Instead we have to modify the C++ Microsoft.Samples.SimpleCommunication-project in a way that it does not reference the “Windows.Media.winmd”-file anymore, but instead the “Windows.winmd”-file.
This can be achieved by adding the following custom build step to the C++ project:
Command Line: mdmerge -partial -i “$(OutDir).” -o “$(OutDir)Output” -metadata_dir “$(WindowsSDK_MetadataPath)” && copy /y $(OutDir)Output\* $(OutDir)
Execute After: Midl
If you recompile the component now, you should be able to reference and consume it from your C# component. If you disassemble the component’s winmd-file, you will notice that it now references “Windows.winmd” and not the “Windows.Media.winmd”-file anymore.
In a future blog post I am going to describe how you can create your own WRL C++ project from scratch as Visual Studio 2011 currently does not ship a project template, unfortunately.