使用 ATL 编译 dll,并将方法参数作为接口,但将它们作为 coclass 获取



我正在使用C++ ATL库。IDL 文件中的方法使用 IQTAction 参数声明,但是当我在 .NET 中使用此类型库时,我得到的是 QTAction 而不是 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
    {
    }
}

为什么?如何让它使用接口而不是 coclass 作为参数的类型?

这是我的头文件和 IDL 文件:

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 文件:

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

据我所知,当类型库导入器发现只有一个 coclass 在同一类型库中将该接口实现为默认值时,它使用 coclass 接口而不是实际接口,并且没有办法阻止它这样做。

但是,请注意,QTTestIQTTest 都是接口,具有相同的 Guid 和方法。 但是QTTest有一个额外的属性,CoClassAttribute(QTTestClass),它允许Microsoft的C#编译器将new QTTest()编译成new QTTestClass()

这种 tlbimp.exe 杂耍让 VB6 程序员有宾至如归的感觉,但对于C++开发人员来说却很奇怪。 在您的情况下,它仅意味着在两种等效的接口类型之间进行强制转换。

最新更新