聚合对象是否强制成为 IUnknown 引用?
Are aggregated objects forced to be an IUnknown reference?
我正在尝试使用带有 ATL 的 COM 聚合来实现共享逻辑。我定义了一个 base class,称为 CameraBase
,它只能通过聚合获得。因此,我在它的 coclass
声明中添加了 aggregateable
注释。
[
uuid(...),
aggregatable
]
coclass CameraBase
{
[default] interface ICamera;
};
我还在 class 定义中添加了 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()
...
}
现在我有不同的 classes 在某处使用 CameraBase
的逻辑。因此,我扩展了父 class 的 com 映射(例如 SampleCamera
):
BEGIN_COM_MAP(CSampleCamera)
COM_INTERFACE_ENTRY_AGGREGATE(IID_ICamera, m_base)
...
END_COM_MAP
DECLARE_GET_CONTROLLING_UNKNOWN()
由于我希望能够从父 class 调用 CameraBase
上的成员(通过 ICamera
接口),我不想使用 COM_INTERFACE_ENTRY_AUTOAGGREGATE
,它将内部对象的指针存储为 IUnknown
的引用。因此,我使用 FinalConstruct
-method:
自行创建它
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;
这行得通,但感觉有点奇怪,因为 get 实例化的 class (CameraBase
) 在两种情况下都是相同的。我错过了什么吗?我是否使用正确的方式聚合内部对象?为什么 CoCreateInstance
的返回指针需要是 IUnknown
类型,如果传递了一个外部未知数?
提前致谢! :)
可聚合 COM 对象提供了 IUnknown
- non-delegating 和委托的两个不同实现。
non-delegating 实现是 "normal" 实现 - 它的 QueryInterface
分发由可聚合对象实现的接口,以及它的 AddRef
和 Release
控件该对象的生命周期。
顾名思义,委托实现将所有三个方法调用委托给外部对象的控制 IUnknown
。该对象实现的所有其他接口都具有由该委托实现支持的三个 IUnknown
方法。这就是聚合如何为客户端保持它正在处理单个 COM 对象的错觉 - 它允许客户端从外部实现的接口查询到内部实现的接口,并且(更有趣的是)反之亦然。回想一下,IUnknown
的要求是 QueryInterface
实现是对称的和可传递的。
当使用 non-NULL 控制未知参数调用 CoCreateInstance
时,它必须从内部对象请求 IUnknown
- 这是外部获得 [=31 的唯一机会=] 实施。您不能在外部接口映射中使用来自内部的任何其他接口指针 - 同样,所有其他接口都由委托未知支持,因此将 QueryInterface
调用转发给它们最终会在外部调用 QueryInterface
,并最终回到界面映射中,导致无限递归。
我正在尝试使用带有 ATL 的 COM 聚合来实现共享逻辑。我定义了一个 base class,称为 CameraBase
,它只能通过聚合获得。因此,我在它的 coclass
声明中添加了 aggregateable
注释。
[
uuid(...),
aggregatable
]
coclass CameraBase
{
[default] interface ICamera;
};
我还在 class 定义中添加了 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()
...
}
现在我有不同的 classes 在某处使用 CameraBase
的逻辑。因此,我扩展了父 class 的 com 映射(例如 SampleCamera
):
BEGIN_COM_MAP(CSampleCamera)
COM_INTERFACE_ENTRY_AGGREGATE(IID_ICamera, m_base)
...
END_COM_MAP
DECLARE_GET_CONTROLLING_UNKNOWN()
由于我希望能够从父 class 调用 CameraBase
上的成员(通过 ICamera
接口),我不想使用 COM_INTERFACE_ENTRY_AUTOAGGREGATE
,它将内部对象的指针存储为 IUnknown
的引用。因此,我使用 FinalConstruct
-method:
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;
这行得通,但感觉有点奇怪,因为 get 实例化的 class (CameraBase
) 在两种情况下都是相同的。我错过了什么吗?我是否使用正确的方式聚合内部对象?为什么 CoCreateInstance
的返回指针需要是 IUnknown
类型,如果传递了一个外部未知数?
提前致谢! :)
可聚合 COM 对象提供了 IUnknown
- non-delegating 和委托的两个不同实现。
non-delegating 实现是 "normal" 实现 - 它的 QueryInterface
分发由可聚合对象实现的接口,以及它的 AddRef
和 Release
控件该对象的生命周期。
顾名思义,委托实现将所有三个方法调用委托给外部对象的控制 IUnknown
。该对象实现的所有其他接口都具有由该委托实现支持的三个 IUnknown
方法。这就是聚合如何为客户端保持它正在处理单个 COM 对象的错觉 - 它允许客户端从外部实现的接口查询到内部实现的接口,并且(更有趣的是)反之亦然。回想一下,IUnknown
的要求是 QueryInterface
实现是对称的和可传递的。
当使用 non-NULL 控制未知参数调用 CoCreateInstance
时,它必须从内部对象请求 IUnknown
- 这是外部获得 [=31 的唯一机会=] 实施。您不能在外部接口映射中使用来自内部的任何其他接口指针 - 同样,所有其他接口都由委托未知支持,因此将 QueryInterface
调用转发给它们最终会在外部调用 QueryInterface
,并最终回到界面映射中,导致无限递归。