我正在尝试使用与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
)。我目前的解决方法是存储两个引用,IUnknown
和ICamera
,并查询后一个引用。
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
类型?
提前致谢! :)
答案 0 :(得分:1)
可聚合COM对象提供了IUnknown
的两个不同实现 - 非委派和委派。
非委托实现是“正常”实现 - 它的QueryInterface
实现接口由可聚合对象实现,其AddRef
和Release
控制该对象的生命周期。
委托实现,顾名思义,将所有三个方法调用委托给外部对象的控制IUnknown
。该对象实现的所有其他接口都有这个委托实现支持的三个IUnknown
方法。这就是聚合如何为客户端维护它处理单个COM对象的错觉 - 它允许客户端从外部实现的接口查询内部实现的接口,并且(更有趣的是)反之亦然。回想一下IUnknown
要求QueryInterface
实现对称和传递。
当使用非NULL控制未知参数调用CoCreateInstance
时,它必须从内部对象请求IUnknown
- 这是外部对象,并且只有机会获得非委托实现。您不能使用外部接口映射中内部的任何其他接口指针 - 同样,所有其他接口都由委派的未知接口支持,因此转发QueryInterface
调用它们最终会在外部调用QueryInterface
,最后在接口映射中返回,导致无限递归。