5

I have a project (dynamic library) written in C++/CX, this project is consumed by a Windows 10 Universal App written in C# (targeting x86 and ARM32).
I want to rewrite the library to C++/WinRT in order to use vanilla C++.

Q1: Is it possible to create a C++/WinRT DLL and consume it from C#?
Q2: How do I set up the C++/WinRT project to enable it to be consumed from the store app?

Tim Hansson
  • 309
  • 2
  • 16
  • 1
    That's possible, although very tedious as of the current release. There is currently no tool support to generate the meta data required to consume a Windows Runtime Component written in C++/WinRT. Once the cppwinrt.exe compiler is made available to the general public, writing WinRT components in C++/WinRT will be feasible. – IInspectable Jun 15 '17 at 10:08
  • Hi @IInspectable, any date for when this tool support will be made available? Thanks! – Tim Hansson Jun 16 '17 at 05:00
  • 1
    To my knowledge there has been no official statement, when this will be released. The GitHub repository has a few comments (e.g. [here](https://github.com/Microsoft/cppwinrt/issues/34#issuecomment-257613614), [here](https://github.com/Microsoft/cppwinrt/issues/61#issuecomment-268309219), and [here](https://github.com/Microsoft/cppwinrt/issues/106#issuecomment-280140915)) where the intention to release the cppwinrt.exe compiler have been expressed. – IInspectable Jun 16 '17 at 10:35
  • Thanks for the update. I'll hold on tight. – Tim Hansson Jun 16 '17 at 14:31
  • 1
    The way I read [this comment](https://github.com/Microsoft/cppwinrt/issues/185#issuecomment-308503246), it sounds like the cppwinrt.exe compiler will be published with the next release (generating header files from .winmd files is one of the jobs of the cppwinrt.exe compiler). It is unclear, when the next release is due, or whether it will come with a fully-featured cppwinrt.exe compiler. Unfortunately. – IInspectable Jun 16 '17 at 14:39

1 Answers1

4

The cppwinrt.exe compiler started shipping in the Windows Preview SDK November-ish 2017. With it, you can more easily create your own C++/WinRT component so that it can be consumed by other store apps.

There's a sample on github (https://github.com/kennykerr/cppwinrt/tree/master/Store/Component) that does just this for a C++ store app. Obviously, the App project would need to be different for a C# app, but this should be enough to get you started. In particular, the C++/WinRT component project, though basic, contains most of the magic sauce you'd need to create your component.

We're actively working on making this experience even more seamlesss with project templates and other goodies, but for now, you can still do this in a way similar to the linked sample without too much work.

The short version of what's happening in the sample is:

  1. Define your component's API in an IDL file
  2. Invoke MIDL to compile the IDL into metadata (.winmd)
  3. Invoke the cppwinrt.exe compiler to generate the scaffolding to implement your runtimeclass(es) along with the DllGetActivationFactory hooks needed for activation.

Want details of what's happening?

Step 1: IDL

The sample's API is pretty simple, so I'll just post it here.

import "Windows.Foundation.idl";

namespace Component
{
  runtimeclass Button;

  [version(1.0), uuid(461c8806-8bc2-4622-8eac-b547c39f867e), exclusiveto(Button)]
  interface IButton : IInspectable
  {
    [propget] HRESULT Text([out,retval] HSTRING* value);
  };

  [version(2.0), uuid(d3235252-4081-4cc8-b0e0-8c7691813845), exclusiveto(Button)]
  interface IButton2 : IInspectable
  {
      HRESULT Show();
  };

  [version(1.0), activatable(1.0)]
  runtimeclass Button
  {
      [default] interface IButton;
      interface IButton2;
      interface Windows.Foundation.IStringable;
  }
}

Step 2: Create winmd

This just requires that you pass the correct command line arguments to MIDL, which can be seen in Visual Studio for the project properties and the properties of your IDL file. What you need are:

  • Enable Windows Runtime (adds /winrt)
  • Add your metadata reference directory. If you were targeting the 16299 SDK, this would be $(FrameworkSdkDir)References\10.0.16299.0\Windows.Foundation.FoundationContract\3.0.0.0. Update appropriately if you're targeting a different SDK.
  • Set your output metadata file. It's usually simplest to set this to $(ProjectName).winmd
  • Add /nomidl and /struct_by_ref to your MIDL command line. Just trust me.

At this point, building the project should now generate a winmd file. In the linked sample, it will be name Component.winmd. If you want, you can use ildasm to crack open the winmd and verify it's got all your stuff in it.

Step 3:

Run cppwinrt.exe to generate the scaffolding. You can see in the Component project that it has a CustomBuildStep that calls cppwinrt.exe with some arguments: cppwinrt.exe -in $(ProjectDir)Component.winmd -comp $(ProjectDir) -out "$(ProjectDir)Generated Files" -ref 10.0.17061.0 -verbose

  • -in The input winmd location. This is what you generated in step 2.
  • -comp We're running in "component" mode, so that it generates the scaffolding.
  • -out Where to put the generated scaffolding.
  • -ref Where to find the input winmd(s) that your winmd depends on. You can also specify an SDK version (which is what's happening here) or -ref local to simply use whatever is on your running OS. Using the SDK version is cleanest.
  • -verbose Self-explanatory.

Download the sample project and play with a bit. From there, it should hopefully be straightforward to set up your own component and app.

Ryan Shepherd
  • 755
  • 4
  • 11