现有的普通C ++类是否可以实现IDL接口而无需转换为COM类?

时间:2016-01-31 10:38:07

标签: c++ com interop atl midl

我有一个COM对象, CProvider ,使用ATL实现。此类包含另一个类 CProviderInfo ,并维护此内部类类型的对象的静态向量。

以下是它的样子:

//-------------
// CProvider.h
//-------------

//
// COM object class
//
class ATL_NO_VTABLE CProvider :
    public CComObjectRootEx<CComMultiThreadModel>,
    public CComCoClass<CProvider, &CLSID_Provider>,
    public Interface1,
    public Interface2
{
public:
    BEGIN_COM_MAP(CProvider)
       COM_INTERFACE_ENTRY(Interface1)
       COM_INTERFACE_ENTRY(Interface2)
    END_COM_MAP()

    //
    // The inner class
    //
    class CProviderInfo
    {
    public:
        CProviderInfo();
        CComBSTR m_strName;
        GUID m_guidRegistration;
    };

private:
    //
    // static vector of inner class type
    //
    static vector<CProviderInfo> m_vProviderInfo;
};

我想要做的是在 CProvider 上引入一个方法,该方法返回静态向量 m_vProviderInfo 的副本。为了达到这个目的,我尝试使用COM规则,我引入了一个新的IDL接口 IProviderInfoRetriever

//---------
// IDL file
//---------

//
// IProviderInfoRetriever interface
//
[
    // uuid, version ... etc.
]
interface IProviderInfoRetriever : IUnknown
{
    HRESULT GetProviderInfo(
        [out, retval] SAFEARRAY(IProviderInfo*) *ppProviderInfo);
}

//
// The interface of the class holding the info
//
[
    // uuid, version ... etc.
]
interface IProviderInfo : IUnknown
{
    [propget] 
    HRESULT Name(
        [out, retval] BSTR *pbstrName);

    [propget]
    HRESULT Registration(
        [out, retval] GUID *pguidRegistration);
}

我的计划是让 CProvider 实现 IProviderInfoRetriever ,有效地将静态向量 m_vProviderInfo 的内容复制到 IProviderInfoRetriever的输出SAFEARRAY中:: GetProviderInfo()

我的问题是:是否可以让内部类 CProviderInfo 实现 IProviderInfo ?是否会破坏创建 CProviderInfo

类型的局部变量的现有代码

1 个答案:

答案 0 :(得分:1)

我做了一些广泛的研究,答案很简单:是的,但这并不容易。您不太可能只是拥有一个普通的C ++类继承/实现IDL中定义的接口,而不会破坏依赖于所述C ++类的现有代码。

首先,如果你使用ATL的工具将你的C ++类转换为COM类,你会突然发现这个C ++类由于ATL宏引入的所有纯虚函数而变得抽象。因此,至少,您将IUnknown AddRef()Release()QueryInterface()由ATL宏添加到您的C ++类中虚函数,例如

class ATL_NO_VTABLE CProviderInfo:
    public CComObjectRootEx<CComMultiThreadModel>,
    public IProviderInfo
{
public:
    BEGIN_COM_MAP(CProviderInfo)
        COM_INTERFACE_ENTRY(IProviderInfo)
    END_COM_MAP() // This line adds IUnknown's AddRef(), Release(),
                  // and QueryInterface() as pure virtual functions.

    // ...        
};

仅此一项就会破坏用于创建C ++类实例的任何现有代码,无论是堆栈还是堆(使用new运算符)。所以,最后你有两个选择:

  1. 使用ATL的工具将您的C ++类转换为COM类。

    这会将您的C ++类变成抽象类。您必须修改源代码中创建C ++类对象的所有位置,以使用ATL的类,即CComObjectCComObjectStack等等。

  2. 直接和手动继承/实现IDL中定义的接口。

    这将需要提供您自己的IUnknownIDispatch或两者的实现,具体取决于您的接口,以及您的接口本身定义的任何方法的实现。此选项的优点是不太可能破坏代码库中C ++类的任何现有用法。

    然而,在没有ATL的情况下滚动自己的COM接口实现并不总是那么容易,特别是如果您的C ++类涉及复杂的场景,例如互操作。