Compile dll using ATL with method parameter as Int

2019-08-19 06:24发布

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;
    };
};

标签: c++ .net com atl
1条回答
霸刀☆藐视天下
2楼-- · 2019-08-19 07:17

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.

查看更多
登录 后发表回答