Search code examples
c#comc++-cli

COM wrapper with C++/CLI and C# "as" operator


I'm writing a COM wrapper in C++/CLI and struggling with how to approach a problem.

From C# side, I'll call a code like this:

var item = myWrappedObj.getSomeItem() as AnotherItem;

C++/CLI managed side holds a pointer to the unmanaged object:

public ref class MyWrapped {
    NativeType* unManagedEl;
public:
    Object^ getSomeItem() { return unManagedEl->getSomeItem(); }
    ...
};

and C++/CLI unmanaged side does the job and, let's say returns an IUnknown* wrapped in an UnknownBase native class

public class UnknownBase {
    IUnknown* myEl;
public:
    UnknownBase(IUnknown* el) { myEl = el; }
    ...
};

public class NativeType {
    COMType* myEl;
public:
    Object^ getSomeItem() { 
        IUnknown* el; myEl->getItemNative(&el); return UnknownBase(el); 
    }
};

Now, there are a number of those "AnotherItem" types (first code section above) in the interface, and I was thinking of creating managed + unmanaged wrappers derived from UnknownBase, etc. Then what? How'll I have a corresponding code for C# "as" operator? From MSDN I understand dynamic_cast is the corresponding operator that'll be called for "as", but having wrapped the IUnknown pointer, I cannot depend on dynamic_cast alone. I just tried to find if type cast operators of classes would be used by dynamic_cast (so that I could manually check the type equality in separate type cast operators), but I think it's not?

I have a huge code base on C# side that uses a marshalled + tlbimp'ed interface so I'm trying to keep the interface exactly same (to replace the "from-the-dark-side&buggy"-marshalled interface), hence I came up with dual-wrappers (and actually, separate namespaces, etc to do more magic).


Solution

  • I realized I needed to find out what that IUnknown type is, and gcnew a corresponding managed type for it (a ref class). I simplified code for the question above, but normally it's more like the code below (with int id's referring to the correct type). And having an error in the example code above may have made it difficult to answer the question, my apologies.

    And also, there's no such thing as conversion between an unmanaged class and object^, so trying to create an UnknownBase(el) wouldn't work.

    public class NativeType {
        COMType* myEl;
    public:
        Object^ getSomeItem(int id) { 
            IUnknown* el; 
            myEl->getItemNative(id, &el); 
            switch(id) {
                case 1: return gcnew AnotherItem(el);
                case 2: return gcnew ... 
            }
        }
    };
    

    I'll test this soon.