COM classes show as empty struct on C# side with /clr support enabled
Previously I was using tlbimp.exe in a post-build event开发者_开发技巧 to generate a managed interop assembly for a native-only c++ COM project.
I wish to directly reference the c++ project from a C# managed project.
I changed the C++ project to have Common Language Runtime Support i.e. /clr
After I removed the old interop reference on the C# side and added the reference to the C++ project, interfaces and classes are showing up as empty static structs.
C++ side:
// IRow
[
object,
uuid("2D52A372-1094-4A59-AF6B-A874E587FA98"),
dual, helpstring("IRow Interface"),
pointer_default(unique)
]
public __interface IRow : IDispatch
{
[id(DISPID_VALUE), helpstring("method Item")]
HRESULT Item([in] LONG index, [out,retval] VARIANT* val);
};
C# side [from metadata]:
[CLSCompliant (false)]
[NativeCppClass]
public static struct IRow
{
}
Any hints at to what's missing?
__interface is part of a set of language extensions (called "attributes") introduced with Visual Studio 2002. The intent was to be able to define directly in C++ source code what you normally would define in MIDL and make ATL easier to use by having it automatically "grok" the attributes.
When you build your C++ source code without /clr and use tlbimp to import the generated type library, IRow is defined in the interop-assembly generated by tlbimp. Its definition is based entirely off of the COM type library generated from the use of __interface; that is to say, it's a normal .NET interface with a ComImport attribute.
When you build your C++ source code with /clr, the C++ compiler emits .NET metadata for IRow to denote that it is a native type as it remains a COM interface even with /clr applied. To properly use IRow from C#, you must either continue to use IRow from an interop assembly created with tlbimp (or hand-rolled), or convert IRow (and the classes that implement it) to .NET types using C++/CLI. Alternatively, you could define some wrapper classes in C++/CLI that directly use the COM types, but I don't see much benefit in doing so.
Here's what the the interface and an implementor might look like in C++/CLI:
public interface class IRow
{
System::Object^ Item(int index);
};
public ref class ImplementedRow : public IRow
{
public:
System::Object^ Item(int index) { return nullptr; }
};
I suspect this may not be a trivial rewrite for your existing COM objects, so I would probably just stick with COM interop unless you have a compelling reason not to.
精彩评论