0
votes

I'm using a C++ ATL library. Methods in the IDL file are declared with a IQTAction parameter, but when I use this type library in .NET I get the methods parameters of type QTAction NOT IQTAction:

namespace COMTest3Lib
{
    [ClassInterface(0)]
    [Guid("C6DD8D8E-8375-4CA6-8534-007776D96215")]
    [TypeLibType(2)]
    public class QTTestClass : IQTTest, QTTest
    {
        public QTTestClass();
        public virtual void GetActiveAction(out QTAction pActionOut);
        public virtual void RunAction(QTAction pActionIn);
    }
}

namespace COMTest3Lib
{
    [CoClass(typeof(QTActionClass))]
    [Guid("FBCC87D9-4E5C-40D2-853F-E8548E625C5B")]
    public interface QTAction : IQTAction
    {
    }
}

Why is that? How do I get it to use the interface instead of the coclass as the parameter's type?

Here are my header and IDL files:

using namespace ATL;

//QTTest.h
class ATL_NO_VTABLE CQTTest :
    public CComObjectRootEx<CComSingleThreadModel>,
    public CComCoClass<CQTTest, &CLSID_QTTest>,
    public IDispatchImpl<IQTTest, &IID_IQTTest, &LIBID_COMTest3Lib, /*wMajor =*/ 1, /*wMinor =*/ 0>
{
public:
    CQTTest()
    {
        m_pActiveAction.CoCreateInstance(CLSID_QTAction); //construct an action; 
    }

DECLARE_REGISTRY_RESOURCEID(IDR_QTTEST)


BEGIN_COM_MAP(CQTTest)
    COM_INTERFACE_ENTRY(IQTTest)
    COM_INTERFACE_ENTRY(IDispatch)
END_COM_MAP()

    DECLARE_PROTECT_FINAL_CONSTRUCT()

    HRESULT FinalConstruct()
    {
        return S_OK;
    }

    void FinalRelease()
    {
        ::MessageBox(NULL, L"#################QTTest is being disposed", L"info", 0);
    }

public:
    STDMETHOD(GetActiveAction)(/*out*/IQTAction** pActionOut);
    STDMETHOD(RunAction)(/*in*/IQTAction* pActionIn);

private:
    CComPtr<IQTAction> m_pActiveAction;
};

OBJECT_ENTRY_AUTO(__uuidof(QTTest), CQTTest)

IDL FILE:

import "oaidl.idl";
import "ocidl.idl";
[
    object,
    uuid(FBCC87D9-4E5C-40D2-853F-E8548E625C5B),
    pointer_default(unique)
]
interface IQTAction : IDispatch{
    [helpstring("method Run")] HRESULT Run(void);
};
[
    object,
    uuid(19F205D2-1D1C-4DB7-A731-498665CC297F),
    version(1.0)
]
interface IQTTest : IDispatch{
    [helpstring("method GetActiveAction")] HRESULT GetActiveAction([out] IQTAction** pActionOut);
    //[helpstring("method Run")] HRESULT Run(void);
    [helpstring("Run a specific action")] HRESULT RunAction([in] IQTAction* pActionIn);
};
[
    uuid(0E651E25-832E-4410-9A9E-F8CD8574F4D8),
]
library COMTest3Lib
{
    importlib("stdole2.tlb");
    [
        uuid(C6DD8D8E-8375-4CA6-8534-007776D96215)      
    ]
    coclass QTTest
    {
        [default] interface IQTTest;
    };
    [
        uuid(72D899CC-7722-4260-A441-3D1225132019)      
    ]
    coclass QTAction
    {
        [default] interface IQTAction;
    };
};
1
Why the down votes and the close votes? If you don't understand the op, ask him for details. To me, it's clear what is being asked: why is the QTAction .NET class type being used in the methods of IQTTest instead of the IQTAction .NET interface type?acelent
IQTAction is only implemented by QTAction in the type library. .NET interop sees it and "merges" the definitions trying to simplify things. Nevertheless you see it as QTAction on .NET side, it is still IQTAction interface.Roman R.

1 Answers

1
votes

As far as I know, the type library importer uses the coclass interface instead of the actual interface when it finds that there's only one coclass implementing that interface as the default within the same type library, and there's no way to prevent it from doing this.

However, note that QTTest and IQTTest are both interfaces, with the same Guid and methods. But QTTest has an extra attribute, CoClassAttribute(QTTestClass), that allows Microsoft's C# compiler to compile new QTTest() into new QTTestClass().

This tlbimp.exe juggling makes VB6 programmers feel at home, but it's quite weird for C++ developers. In your case, it only implies casting between two otherwise equivalent interface types.