CsWinRT icon indicating copy to clipboard operation
CsWinRT copied to clipboard

No such interface supported when using foreach on out-of-process IVector.

Open jlaanstra opened this issue 2 years ago • 1 comments

Describe the bug When enumerating an out-of-process vector an exception "No such interface supported" is thrown.

To Reproduce Repro shared offline.

Expected behavior No exceptions thrown.

Version Info 1.6.4

Additional context N/A

jlaanstra avatar Jun 16 '22 17:06 jlaanstra

I was hitting this same issue, and after debugging and some internal discussions, the issue lies in the metadata-based marshalling (aka WinMD). It is currently unable to make the connection between IVector<Foo> and IIterable<Foo> for custom Foo. Given that, I don't think that CsWinRT can do much here (although I am not the owner of that decision).

There are two workarounds that I am aware of.

1. Server (the one doing the initial marshalling) side fix

The path that I know of requires the marshalling side to be packaged, although there may also be a method using binary manifests to achieve the same result. The AppxManifest.xml file for the package can be enlightened with something like the following:

<?xml version="1.0" encoding="utf-8"?>
<Package ...>
  ...
  <Extensions>
    <Extension Category="windows.activatableClass.proxyStub">
      <ProxyStub ClassId="00000355-0000-0000-C000-000000000046">
        <Path>YOUR.WINMD.winmd</Path>
        <Interface Name="Windows.Foundation.Collections.IIterable`1&lt;YOUR.TYPE&gt;" InterfaceId="GENERATED.IID" />
        ...
      </ProxyStub>
    </Extension>
    <!-- This entry forces the package registration to process the windows.activatableClass.proxyStub extension above. -->
    <Extension Category="windows.activatableClass.inProcessServer">
      <InProcessServer>
        <Path>YOUR.DLL.dll</Path>
        <ActivatableClass ActivatableClassId="Placeholder.Activatable.Class.Do.Not.Use" ThreadingModel="STA" />
      </InProcessServer>
    </Extension>
  </Extensions>
  ...
</Package>
  • 00000355-0000-0000-C000-000000000046 is a the GUID for metadata-based marshalling.
  • YOUR.WINMD.winmd should be the one containing YOUR.TYPE
  • YOUR.TYPE is a type in an IVector or IVectorView (or any container that you might want to iterate).
  • GENERATED.IID is the interface identifier that is generated for this parameterized type. I wouldn't try to calculate this myself, but instead use CsWinRT/CppWinRT (I wrote some code to spit out winrt::name_of<T> and winrt::guid_of<T> for everything we expose), or even the debugger on the server (although this is slow).
    • Repeat the Interface for every type you want to be iterable.
  • YOUR.DLL is a dll in your package, but it will not be used. This is a dummy registration to force the proxy-stub extension to be processed.

2. Client side fix

Don't use IIterable (aka IEnumerable in .Net).

for (int i = 0; i < myVector.Size; ++i)
{
  var obj = myVector[i];
  ... use obj ...
}

JohnMcPMS avatar Jun 20 '23 18:06 JohnMcPMS