How to declare interface that inherits from IClosable/IDisposable

两盒软妹~` 提交于 2019-12-23 15:42:23

问题


After being told in this question that my preferred solution was impossible, I'm now trying to implement a workaround. Instead of declaring my interface that inherits from IClosable in C++/CX, I'm declaring it in raw IDL. But that doesn't seem to work either.

I've created an IDL file FooSpace.idl containing

import "inspectable.idl";
import "Windows.Foundation.idl";
namespace FooSpace
{
    [uuid(01234567-89AB-CDEF-FEDC-BA9876543210)]
    [version(42)]
    interface Foo : IInspectable requires Windows.Foundation.IClosable
    {
    }
}

and generate Windows Runtime metadata from it with

midlrt /nomidl /metadata_dir "C:\Program Files (x86)\Windows Kits\8.0\References\CommonConfiguration\Neutral" FooSpace.idl

The generated FooSpace.winmd looks alright when I disassemble it with ildasm -- in particular, Foo appears to inherit from IClosable in just the same way IInputStream does in the system-provided Windows.winmd.

However, when I try to use it from C++/CX -- not even implement it, just pretending for the time being that someone else has implemented it with WRL or whatever -- it doesn't seem to work. Here's my test C++/CX source file:

void works(Windows::Storage::Streams::IInputStream^ istream) {
  Platform::IDisposable^ local = istream ;
}
void doesnt(FooSpace::Foo^ foo) {
  Platform::IDisposable^ local = foo ;
}

which produces an error for Foo but not for IInputStream:

C:\cygwin\tmp>cl /nologo /c /ZW /FU FooSpace.winmd  testit.cpp
testit.cpp
testit.cpp(5) : error C2440: 'initializing' : cannot convert from 'FooSpace::Foo ^' to 'Platform::IDisposable ^'
        No user-defined-conversion operator available, or
        Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast

What am I doing wrong here?


On the other hand the equivalent C# code seems to compile fine:

public class Whatever {
  public static void Works(Windows.Storage.Streams.IInputStream istream) {
    System.IDisposable local = istream ;
  }
  public static void AlsoWorks(FooSpace.Foo foo) {
    System.IDisposable local = foo ;
  }
}

回答1:


If you add a call to mdmerge to your cmds it should work:

midlrt /nomidl /metadata_dir "C:\Program Files (x86)\Windows Kits\8.0\References\CommonConfiguration\Neutral" FooSpace.idl
mdmerge -metadata_dir "C:\Program Files (x86)\Windows Kits\8.0\References\CommonConfiguration\Neutral" -i "." -o "merged" -v -partial
cl /nologo /c /ZW /FU merged\FooSpace.winmd /EHsc testit.cpp

With the 'merged' winmd file I am able to compile code like:

namespace ClosableTest
{
    ref class Test sealed
        : FooSpace::Foo
    {
    public: 
        virtual ~Test()
        {
           FooSpace::Foo^ f = nullptr;
           Platform::IDisposable^ d = f;
        }
    };
}

The original FooSpace.winmd file that is generated by midlrt references Windows.Foundation (C:\Windows\system32\WinMetadata\Windows.Foundation.winmd) while the mdmerge output references Windows (C:\Program Files (x86)\Windows Kits\8.0\References\CommonConfiguration\Neutral\Windows.winmd).

It is interesting that you were able to reference the mildrt-output winmd file in a c# project without problems because in the blog post How to reference C++ WRL Components from a .NET project Kevin Stumpf describes that he had some problem when not using mdmerge first.



来源:https://stackoverflow.com/questions/14653250/how-to-declare-interface-that-inherits-from-iclosable-idisposable

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!