65.9K
CodeProject 正在变化。 阅读更多。
Home

重用 COM 对象

2002年2月12日

4分钟阅读

viewsIcon

28717

本文讨论了在 ATL 中重用 COM 对象

引言

本文介绍在客户端应用程序或另一个 COM 对象中重用 COM 对象的技术。要理解它,您需要了解 COM 和 ATL 的一些基础知识,主要是您需要了解 IUnknown 接口及其方法 (QueryInerface(), AddRef(),Release()),以及一个简单的 ATL 对象是如何工作和实现的。所以,您可以先看看 CodeProject 上关于 ATL 基础的文章。

C++ 中的对象重用

众所周知,在 C++ 中重用现有类的两种方法是 **组合** 和 **继承**。组合是在类作用域内声明一个对象。我们来看一个例子。

class CMyCalss
{
protected:
     CBaseclass m_base;
public:
     CMyClass(){m_base.basefunction();}
     DoSomething(){m_base.DoSomething();}
}

您可以看到 CMyClass **包含** 了预先存在的 "CBaseclass" 的一个实例,并且它可以控制对 CBaseclass 对象的访问。

另一种技术是 **继承**

class CMyClass public CBaseClass
{
public:
      CMyClass(){basefunction();}
}

在这里,您可以作为 CMyClass 的成员来访问 CBaseclass 的公共和保护成员函数。

好的,我知道您都了解这些,所以我们来谈谈 COM。

COM

COM 支持组合,但它不支持 C++ 那样的继承。在上面的例子中,CMyClass 继承了 CBaseclass 实现的功能。CBaseclass 的公共或保护成员函数对 CMyClass 可用。这种继承称为 *实现* 继承。

现在我们来看一个 COM 中继承的例子。

IMyInreface:public IUnknown
{
//IMyInterface methods declaration
}

有什么区别?

通过将一个接口派生自另一个接口,您可以指定用于保存方法指针的 **vtable** 的结构。在上面的例子中,这意味着 IMyInterface 除了拥有自己的方法外,还拥有 IUnknown 接口的三个函数:QueryInterface, AddRef, Release

这里没有 C++ 和 MFC 中的 *虚函数*。在这里,IMyInterface 拥有 IUnknown 接口的 QueryInterface 方法。如果您想要另一个 QueryInterface 方法,您必须自己实现 IUnknown 接口并更改其 QueryInterface,然后将 IMyInterface 派生自您自己的 IUnknown 接口。这种继承称为 **接口** 继承。清楚了吗?嗯!

包含

组合是让一个组件成为另一个组件的成员变量。(还记得 C++ 中的组合吗?)外部(控制、包含)组件使用内部(被包含)组件,但不会直接将其暴露给客户端。外部组件管理内部组件的生命周期。它在初始化自身时(在 FinalConstruct() 中)使用 CoCtreateInstance() 创建内部组件,并在取消初始化自身时(在 FinalRelease() 中)释放内部组件的接口指针。可以说,外部组件所做的与标准客户端所做的没有太大区别。

聚合

在聚合中,内部对象的接口直接暴露给客户端,而无需包装器集合。客户端创建外部对象,当它查询(QueryInterface())内部对象支持的接口时,会获得指向内部对象接口的指针。

与组合相比,聚合的一个优点是实现外部组件的人员对内部组件的了解要求大大降低。另一个优点是绕过包装器层可以使组件效率更高。
聚合的缺点是,内部对象只能在直接加载到与外部对象相同的 apartment 中的 DLL 中实现。不支持跨 apartment、跨进程或跨计算机的聚合。

为了使聚合正常工作,内部对象必须是 *可聚合的*,它必须被编写成支持聚合。要使内部组件可聚合,必须具有三个 IUnknown 方法(QueryInterface(), AddRef()Release())的两个 *不同* 实现。一种版本称为 **非委托**,由外部对象使用;另一种版本称为 **委托**,由客户端使用。(因为外部对象的客户端现在可以获取内部对象暴露的接口指针)。

聚合可用于执行“黑盒”代码重用。您可以从两个角度来看待“黑盒”重用:首先,外部对象正在为内部对象添加功能,或者它故意创建内部对象来实现一个或多个接口。在这两种情况下,复合对象的标识 *就是* 外部对象。外部对象可以聚合许多不同的对象,每个对象都有自己的标识,但它们将被组合成一个单一的、具有一个标识的对象。

编写可聚合对象可能很有用。这样做不会影响对象的内在有用性,但会稍微增加代码的体积(例如 COM 运行时)。

聚合是一个有点复杂的主题,尽管 ATL 向导会为您处理聚合的难点。

参考文献

  • 《Beginning ATL3 COM Programming》作者 Dr.Richard Grimes
  • 《Microsoft Visual C++ 6.0 MCSD 培训教材》桌面应用程序
  • MSDN
© . All rights reserved.