问题
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