Trouble Casting COM Object to a C#/.NET Class

Category: c# language

Question

swtdrgn on Mon, 24 Sep 2012 00:27:56


I have a base class that is written in C# that implements an interface defined in an IDL library. I have a C++ class that manages the single instance of this class. I also have a C# project that needs to make use of the class [instance (that is obtained through the C++ project)]. I want to cast the COM interface that my base class implements back into my C# base class.

However, when I cast the generic object that I acquired from the C++ proportion into my C# base class, I received an error. When I cast it to the implemented interface, there is no problem.

What is the process to cast this COM object to the C# object successfully?

public class NETBase : COMInterface{ ... }

public class CSDriver{
    private NETBase m_NETBaseInstance;

    ...

    public object NETBaseInstance{
        set{
            COMInterface test;
            if( value is COMInterface ){
                // This is evaluated.
                test = value as COMInterface;
            }

            if( value is NETBase ){
                // This is not evaluated.
                m_NETBaseInstance = value as NETBase;
            }

            if( test is NETBase ){
                // This is not evaluated.
                m_NETBaseInstance = test as NETBase;
            }
        }
    }
}

Thank you in advance for any answers.

Replies

Lim Bio Liong on Mon, 24 Sep 2012 08:20:17


Hello swtdrgn,

>> However, when I cast the generic object that I acquired from the C++ proportion into my C# base class, I received an error.

What is the error description ?

- Bio.

swtdrgn on Mon, 24 Sep 2012 11:50:58


When the program tries to execute the following line:

m_NETBaseInstance = (NETBase) value;

It produces the following error message:

"Unable to cast COM object of type 'System.__ComObject' to class type 'NetBase'. Instances of types that represent COM components cannot be cast to types that do not represent COM components; however they can be cast to interfaces as long as the underlying COM component supports QueryInterface calls for the IID of the interface."

So, I guess it's not possible?

Lim Bio Liong on Mon, 24 Sep 2012 13:58:53


Hello swtdrgn,

1. >> Unable to cast COM object of type 'System.__ComObject' to class type 'NetBase'.

1.1 This means that "value" did not originate from the C# NETBase class.

1.2 If it was, it would not be of type "System.__ComObject". It would certainly be of type NETBase due to the presence of metadata which will be detected by the CLR.

2. Check to see if the C++ project really returns an instance of the NETBase class. It might be returning an unmanaged object that also implements COMInterface.

- Bio.

swtdrgn on Mon, 24 Sep 2012 17:29:20


Bio, thank you for the responses.

In the above example with the function call NETBaseInstance, the "value is COMInterface" is evaluated to be true, and NETBase is the only class that implements COMInterface. It successfully casted the generic object to COMInterface, and I am able to make function calls in COMInterface successfully. Yet, I cannot cast it to NETBase.

The NetBase instance is created through CoCreateInstance (which returns ATL::ComPtrBase<IDispatch> in the VS debugger) in the C++ component. It did pass the same reference that it created to the function NETBaseInstance. COMInterface produces the expected results from NETBase when calling its public members.

Other than these information, I do not know how to verify that the instance is indeed of type NETBase.


Lim Bio Liong on Tue, 25 Sep 2012 08:41:13


Hello swtdrgn,

1. >> The NetBase instance is created through CoCreateInstance (which returns ATL::ComPtrBase<IDispatch> in the VS debugger) in the C++ component...

1.1 Make sure that the CLSID that was used in the call to CoCreateInstance() is indeed the one designated for the NETBase class.

1.2 Did you use a ProgId (e.g. "NetBaseClassLib.NETBase") to determine the CLSID (via CLSIDFromProgID()) ?

- Bio.

swtdrgn on Tue, 25 Sep 2012 10:12:06


No, I did not use CLSIDfromProgID(). I used CLSIDFromString() which gets the CLSID from a GUID, and that GUID matches the one that I assigned to my class.

Lim Bio Liong on Tue, 25 Sep 2012 11:08:17


Hello swtdrgn,

1. It is indeed very unusual.

2. The expected situation is that when a managed object is instantiated as a COM object with the help of a COM-callable-wrapper, it is recognized by the CLR whenever it is passed back to managed code.

3. This is due to the presence of the managed object's metadata.

4. I currently have no idea as to why your NETBase object is somehow not recognized as a managed object.

5. One final check (mostly out of curiosity on my part) that I hope you can make is to use OLEVIEW to look up the Type Library generated for the assembly in which NETBase is defined.

6. Check up the coclass definition generated for the NETBase class. It should be something like the following :

    [
      uuid(14A91CCC-FDEF-4154-8FBF-E2CD30D31D60),
      version(1.0),
        custom({0F21F359-AB84-41E8-9A78-36D110E6D2F9}, "NetBaseClassLib.NETBase")
    ]
    coclass NETBase {
      ...
      ...
      ...
    };

6.1 Note the presence of a custom attribute with GUID "0F21F359-AB84-41E8-9A78-36D110E6D2F9". This is a custom IDL attribute generated by the Type Library Exporter when REGASM.EXE is called on an Assembly that contains COM Visible items.

6.2 The custom IDL attribute will indicate that the NETBase coclass originated from managed code and the ProgID is "NetBaseClassLib.NETBase".

6.3 Please see if this custom attribute exists in the generated type library.

- Bio.

Lisa Zhu on Tue, 02 Oct 2012 08:09:24


Hi swtdrgn ,

I provisionally marked Lim 's reply as answer.

Please  feel  free to unmark it if you think the information does not help.

Regards ,