Delphi中如何实现可聚合的COM对象(50分)

  • 主题发起人 主题发起人 GISxChen
  • 开始时间 开始时间
G

GISxChen

Unregistered / Unconfirmed
GUEST, unregistred user!
在《Inside COM》一书中,有关于利用已有组件构建新组件的方法(包容和聚合),
对于包容是比较容易理解和实现的,对于聚合模型虽有些抽象,但是还能理解。书中是用
C++实现的。在Delphi语言中,可聚合的COM对象是如何实现的呢?
 
能举一个包容的例子吗?
 
Delphi高手何在? 在VCL的COMOBJ中有关于TAggregatedObject和TContainedObject的定义
但是比较抽象,有大瞎能解释以下吗?
 
包容和聚合是两种不同的COM对象的代码重用方法.
1.包容:
这种方法是比较容易但也效率比较差的方法.它需要实做它所包容的COM对象的所有
Interface.在包容对象建立时,同时在内部建立被包容的对象,在Client调用它所包容
的对象的方法时,其实是调用的包容对象实现的方法,由包容对象将调用传递给被包容
的对象.
2.聚合:
这种方法是将被包容的对象的Interface publish出来,Client直接调用被包容的对象
的方法. 这种方法有两个问题,第一是Client调用包容对象的IUnknown的queryinterface
方法时,怎样能够得到内部被包容对象的Interface. 第二是被包容对象的AddRef和Release
方法必须影响的是包容对象的参照,而不是被包容对象.
通过以下方法可以达成这个目的:
++++++++以下摘自MSDN++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 When creating the inner object, the outer object must pass its own IUnknown
to the inner object through the pUnkOuter parameter of
IClassFactory::CreateInstance. pUnkOuter in this case is called the controlling
unknown.
2.The inner object must check pUnkOuter in its implementation of CreateInstance.
If this parameter is non-NULL, then
the inner object knows it is being created
as part of an aggregate. If the inner objectdo
es not support aggregation,
then
it must fail with CLASS_E_NOAGGREGATION. If aggregation is supported,
the inner object saves pUnkOuter for later use, butdo
es not call AddRef on it.
The reason is that the inner object's lifetime is entirely contained within
the outer object's lifetime, so there is no need for the call and todo
so
would create a circular reference.
3.If the inner object detects a non-NULL pUnkOuter in CreateInstance, and the
call requests the interface IUnknown itself (as is almost always the case),
the inner object must be sure to return its non-delegating IUnknown.
4.If the inner object itself aggregates other objects (which is unknown to the
outer object) it must pass the same pUnkOuter pointer it receivesdo
wn to the
next inner object.
5.When the outer object is queried for an interface it exposes from the inner
object, the outer object calls QueryInterface in the non-delegating IUnknown
to obtain the pointer to return to the client.
6.The inner object must delegate to the controlling unknown, that is,
pUnkOuter, all IUnknown calls occurring in any interface it implements other
than the non-delegating IUnknown.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
通过以上的说明,我想应该不难理解COM对象聚合.
 
to HongJiang:
对包容和聚合模型我是能理解的,并且在VC中也能实现,但是在Delphi中,包容也是容易实现的,
聚合却很头疼。从Tcomobject的VCL源代码中可以看出,COM对象是支持聚合功能的,他有两个
Constructor:
constructor Create;
constructor CreateAggregated(const Controller: IUnknown);
Delphi实现聚合与COM教科书(或您所给的MSDN中的规范)不太一致,没有在内部组件中实现两种
接口(代理和非代理),而是通过传递外部对象(Controller)的Iunknown。我想用VC中聚合的方法
来在Delphi实现,不知道外部组件何时用到CreateAggregated(const Controller: IUnknown)
并把外部组件的IUnknown传给内部组件。
谢谢您的回答,很希望有大虾能做一个实例。我的观点是COM 有两条腿在支撑,一条是
怎样用OOA/OOD来划分应用成为COM,而另一条腿就是在应用集成时,利用基础组件来构建应用
系统的框架,而包容和聚合就是搭建的工具,他提供了在二进制代码级的组装,并可在不要重新
编译和连接的情况下更换组件。
 
GISxChen:
我认为Delphi实现聚合的方式和MSDN中的规范是一致的. 关键还是在于对聚合的理解.
聚合最主要的问题在于怎样将内部被聚合对象的Interface和外部对象的Interface结合,
我想这也是聚合这个名词的意义之所在. 我想举个例子来说明:
比如有一个对象CoInner,它实现了IInner Interface并支持被聚合;另外有一个对象
CoOuter,它实现了IOuter Interface并要聚合对象CoInner. 那么CoOuter将在其内部建立
CoInner,并在IOuter Interface的QueryInterface中实现对IInner Interface的查询,这样
Client可以通过IOuter Interface得到IInner Interface. 但是,COM要求Interface的
QueryInterface必须是对称的, 也就是说, 你如果可以通过IOuter Interface得到
IInner Interface, 那么你通过IInner Interface也应该可以得到IOuter Interface.
你现在应该可以看到问题所在. 因为CoInner的实现在CoOuter之前, 所以CoOuter可以知道
CoInner的信息,但是CoInner并不知道CoOuter的信息. 解决这个问题的方法就是CoOuter在
建立CoInner时将自己的IOuter Interface传递给CoInner, CoInner如果支持聚合的话,它
必须保存传给它的Interface, 并在其QueryInterface的实现中调用IOuter Interface的
QueryInterface. 不管是VC还是Delphi, 其实实现方法是一样的. 如果你看一下Delphi的
TComObjectFactory.CreateInstanceLic方法, 你就会看到MSDN中所说的对pUnkOuter的
处理.
 
接受答案了.
 
后退
顶部