windowswindows-runtimec++-winrtwinrt-asyncwinrt-component

Class Not Registered when communicating C++/WinRT with C#/WinRT components that return IAsyncOperation<> or IList<>


I'm currently facing an issue where i am unable to create a C#/WinRT component that returns any complex types acceptable by WinRT, like IAsyncOperation<>., IAsyncAction or IList<>. I have a project that references Microsoft.Windows.CsWinRT package and generates a .winmd file to export to WinRT by using the tag <CsWinRTComponent>true</CsWinRTComponent> I then have another project, this one being a C++/WinRT project, which references the C#/WinRT project and consumes it by calling the methods of its runtime classes.

Example:

namespace csharp_winrt {
  public sealed class CSharpWinrtInterface {
    // just a simple "async" method to be able to return a IAsyncOperation
    public IAsyncOperation<string> HelloAsync() {
      var task = Task.Run(async() => {
        await Task.Delay(2000);
        return "Hello World!";
      });

      return task.AsAsyncOperation();
    }
  }
}

I then compile the C#/WinRT project, generate all it's DLLs and .winmd file and reference them in the C++/WinRT project. The files I references are the same ones that are mentioned at the end of this commentary. Here's a snippet of the code I'm calling in C++:

#include "winrt/csharp_winrt.h" //the generated header for the C#/WinRT project
#include <winrt/Windows.Foundations.h> // definition of IAsyncOperation<> in C++

void testCSharpCall() {
  winrt::csharp_winrt::CSharpWinrtInterface csharp_winrt_interface;
  auto result = co_await chsarp_winrt_interface.HelloAsync();
  std::cout << result << std::endl; //should be "Hello World!"
}

I also wrote a manifest file in the C++/WinRT project so that my C# class could be found:

<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
    <assemblyIdentity version="1.0.0.0" name="sdk_demo.exe"/>
    <file name="WinRT.Host.dll">
        <activatableClass
            name="csharp_winrt.CSharpWinrtInterface"
            threadingModel="both"
            xmlns="urn:schemas-microsoft-com:winrt.v1" />
    </file>
</assembly>

After compiling and executing the project, i am receiving a error REGDB_E_CLASSNOTREG Class not registered in the first line of the testCSharpCall, which creates the C#/WinRT object.

After investigating a little, I realized that, if I return just a primitive type, like string (the full signature being public string HelloAsync()), and removing the co_await, the execution runs just fine and i'm able to communicate C++ with C#. C++/WinRT project compiles correctly and understands what I want to do with IAsyncOperation, even with IList<>´ (which it transforms to IVector`) for instance, but it gives the same class not registered runtime error.

Here's my question: Am I missing some configuration to make IAsyncOperation or IList<> work? Maybe the manifest is missing something? I tried multiple things like declaring the namespace where these interfaces are, or their class full name in it, but nothing works. Searched and tried multiple thing suggested by documentation and other thread, but no luck. Any idea to how to make this work?

Obs: my question is similar to this one

Obs2: documentation mentions how to integrate Windows runtime components into javascript or another C# applications, as seen here and here, but not into C++

Tried following CsWinRT documentation, trying multiple configurations in the C++/WinRT manifest file and tried following recommendations in StackOverflow and projects github threads.


Solution

  • I will post the same answer to my own question, same as in here:

    Upon taking a looking at some samples in the CsWinRT project, especially this one, AuthoringDemo, which has a C++ console application (CppConsoleApp) consuming a C#/WinRT project (AuthoringDemo), I realized I missed the declaration of the tag <CsWinRTWindowsMetadata>10.0.19041.0</CsWinRTWindowsMetadata> that's present in the file AuthoringDemo/AuthoringDemo.csproj. This tag is describe in the CsWinRT documentation as "Specifies the source for Windows metadata" and its default value should be $(WindowsSDKVersion), but it seems like this value is never setup and the C#/WinRT projection doesn't get to export some runtime declarations.

    After adding this tag with the correct SDK version (depends on your project setup), it recognized IAsyncAction, IList<> and IAsncOperation<> and probably all other runtime non-primitive projections. This AuthoringDemo.csproj should have all you need to export to WinRT correctly.

    It's also worth noting that CppConsoleApp has a manifest file CppConsoleApp.exe.manifest that must declare the C# classes you want WinRT to activate. Your C++ application should one similliar too.