COM 经验的八个教训(8):共享对象并不容易

来源:互联网 发布:flotherm软件破解 编辑:程序博客网 时间:2024/04/30 19:51

共享对象并不容易

从我收到的邮件和在会议上被问到的问题判断,困扰许多 COM 程序员的一个问题是如何将两个或更多的客户端与一个对象实例连接。要回答这个问题,写出长篇大论(或是一本小册子)都很容易,但其实只要说明与现有对象的连接既不容易也不自动化,就足够了。COM 提供了大量创建对象的方式,包括很受欢迎的 CoCreateInstance(Ex) 函数。但是 COM 缺乏一种通用的命名服务,允许使用名称或 GUID 来标识对象实例。而且它没有提供内置的方式来创建对象,然后将它标识为调用的目标以检索接口指针。

这是不是意味着将多个客户端与单一对象实例连接就不可能了呢?当然不是。实现这一点有五种方式。在这些资源链接中,您可以找到更多信息甚至是示例代码,来指导您的操作。请注意,这些技术从一般意义上讲不能互换;通常,环境因素会决定哪种方式(如果有)适用于手边的任务: Singleton 对象 Singleton 对象就是只实例化一次的对象。可能会有 10 个客户端调用 CoCreateInstance 来“创建”Singleton 对象,但实际上,它们都是接收指向同一对象的接口指针。ATL COM 类可通过在其类的声明中添加 DECLARE_CLASSFACTORY_SINGLETON 语句,来转换为 Singleton。

文件名字对象 如果一个对象实现了 IpersistFile,并在运行中对象表 (ROT) 中使用文件名字对象(它封装了传递给对象的 IPersistFile::Load 方法的文件名称)注册了自己,那么客户端就可以使用文件名字对象连接对象的现有实例了。实际上,文件名字对象允许使用文件名称来命名对象实例,对象可在这些文件名称中存储它们的持久性数据。它们甚至能够跨机器工作。

CoMarshalInterface 和 CoUnmarshalInterface 保存接口指针的 COM 客户端可以与其他客户端共享这些接口指针,只要它们愿意封送指针。COM 为愿意将接口指针封送给同一进程中其他线程的线程提供了优化(请参见教训 2),但是如果客户端线程属于其他进程,CoMarshalInterface 和 CoUnmarshalInterface 就是实现接口共享的关键途径了。有关讨论和示例代码,请参阅 MSJ ?? 1999 年 8 月刊中我的超酷代码专栏。

自定义类对象 所有“可以在外部创建的”COM 对象都伴随有独立对象,称为类对象,它们的作用是创建所谓 COM 对象的实例。大多数类对象都要实现一个名为 IClassFactory 的接口,其中包括一个可以创建对象实例的名为 CreateInstance 的方法。(在底层,COM 将 CoCreateInstance(Ex) 调用转换为对 IClassFactory::CreateInstance 的调用)。IClassFactory 的问题在于,在检索指向以前创建的对象实例的接口指针时,它一点用处都没有。自定义类对象是实现替代 IClassFactory 的自定义激活接口的类对象。由于定义了接口,您还可以定义方法来检索对已由该类对象创建的对象的引用。更多信息和以 ATL 编写的示例,请参阅 1999 年 2 月的超酷代码专栏。

自定义名字对象 1999 年 11 月的超酷代码专栏介绍了允许使用 C 样式字符串命名对象实例的自定义名字对象类。将一个实例名称传递给 MkParseDisplayName,您就获得了一个与对象实例连接的名字对象。这些类型的名字对象的一个缺点是,它们在 Windows NT 4.0 中不能跨机器工作。

在使用这些方法中的任一个在客户端之间共享对象实例之前,请问自己一个问题:共享是必需的吗?如果方法调用从一个外部数据源(数据库、硬件设备,甚至可能是全局变量)检索数据以响应客户端的请求,那么为什么不为每个客户端分配一个对象实例,并允许每个实例访问数据源呢?您可能必须同步化对数据源的访问,但不一定要使用自定义类对象、自定义名字对象等手段。这就是用 Microsoft 事务服务 (MTS) 构建的应用程序的工作方式,从各种理由来看,它已经证明是一种引人注目的编程模型,而不仅仅是实现上的简便和性能的改善。

原创粉丝点击