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;
};
};
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
andIQTTest
are both interfaces, with the same Guid and methods. ButQTTest
has an extra attribute,CoClassAttribute(QTTestClass)
, that allows Microsoft's C# compiler to compilenew QTTest()
intonew 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.