聚合对象是否被强制为IUnknown引用?

时间:2017-01-12 13:27:19

标签: c++ visual-studio com atl midl

我正在尝试使用与ATL的COM聚合实现共享逻辑。我已经定义了一个名为CameraBase基类,它只能通过聚合获得。因此,我已将aggregateable注释添加到其coclass - 声明中。

[
    uuid(...),
    aggregatable
]
coclass CameraBase
{
    [default] interface ICamera;
};

我还将DECLARE_ONLY_AGGREGATEABLE宏添加到类定义中。

class ATL_NO_VTABLE CCameraBase :
    public CComObjectRootEx<CComMultiThreadModel>,
    public CComCoClass<CCameraBase, &CLSID_CameraBase>,
    public ISupportErrorInfo,
    public IProvideClassInfoImpl<...>,
    public IDispatchImpl<...>
{
public:
    CCameraBase()
    {
    }

    DECLARE_REGISTRY_RESOURCEID(IDR_CAMERABASE)

    DECLARE_ONLY_AGGREGATABLE(CCameraBase)

    BEGIN_COM_MAP(CCameraBase)
        ...
    END_COM_MAP()

    DECLARE_PROTECT_FINAL_CONSTRUCT()

    ...
}

现在我有不同的类在某处使用CameraBase的逻辑。因此,我已经扩展了父类的com地图(例如SampleCamera):

BEGIN_COM_MAP(CSampleCamera)
    COM_INTERFACE_ENTRY_AGGREGATE(IID_ICamera, m_base)
    ...
END_COM_MAP

DECLARE_GET_CONTROLLING_UNKNOWN()

由于我希望能够从父类调用CameraBase上的成员(通过ICamera接口),我不想使用存储内部的COM_INTERFACE_ENTRY_AUTOAGGREGATE对象的指针作为IUnknown的引用。因此,我正在使用FinalConstruct - 方法创建它:

HRESULT FinalConstruct()
{
    HRESULT hr;

    if (FAILED(hr = m_camera.CoCreateInstance(CLSID_CameraBase, this->GetControllingUnknown(), CLSCTX_INPROC_SERVER)))
        return hr;
}

m_camera定义为CComPtr<ICamera>的位置。但是,这会导致错误CLASS_E_NOAGGREGATION(HRESULT 0x80040110)。我目前的解决方法是存储两个引用,IUnknownICamera,并查询后一个引用。

if (FAILED(hr = m_base.CoCreateInstance(CLSID_CameraBase, this->GetControllingUnknown(), CLSCTX_INPROC_SERVER)) ||
    FAILED(hr = m_base->QueryInterface(&m_camera)))
    return hr;

这很有效,但感觉有点奇怪,因为在两种情况下,实现的类(CameraBase)都是相同的。我错过了什么吗?我是否使用正确的方式聚合内部对象?如果传递外部未知,为什么返回的CoCreateInstance指针必须是IUnknown类型?

提前致谢! :)

1 个答案:

答案 0 :(得分:1)

可聚合COM对象提供了IUnknown的两个不同实现 - 非委派和委派。

非委托实现是“正常”实现 - 它的QueryInterface实现接口由可聚合对象实现,其AddRefRelease控制该对象的生命周期。

委托实现,顾名思义,将所有三个方法调用委托给外部对象的控制IUnknown。该对象实现的所有其他接口都有这个委托实现支持的三个IUnknown方法。这就是聚合如何为客户端维护它处理单个COM对象的错觉 - 它允许客户端从外部实现的接口查询内部实现的接口,并且(更有趣的是)反之亦然。回想一下IUnknown要求QueryInterface实现对称和传递。

当使用非NULL控制未知参数调用CoCreateInstance时,它必须从内部对象请求IUnknown - 这是外部对象,并且只有机会获得非委托实现。您不能使用外部接口映射中内部的任何其他接口指针 - 同样,所有其他接口都由委派的未知接口支持,因此转发QueryInterface调用它们最终会在外部调用QueryInterface ,最后在接口映射中返回,导致无限递归。