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

将多个 COM 客户端连接到所需对象

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.35/5 (10投票s)

2003 年 7 月 31 日

2分钟阅读

viewsIcon

68406

downloadIcon

1257

如何通过使用 Moniker 绑定到正在运行的对象,将多个 COM 客户端连接到所需对象

引言

在某些情况下,服务器应用程序会创建对象池,客户端有可能绑定到特定的对象。如果池大小为一,则服务器可以创建单例实例,并且所有客户端都将连接到同一对象。如果池的大小大于一个对象,则可以使用moniker作为解决方案。我的解决方案建议更改 ATL 项目的类工厂。新的类工厂将通过创建一个强表来管理命名空间,以存储对正在运行的对象的引用。强表意味着,当最后一个客户端释放该对象时,该对象仍在运行,等待新的客户端。要关闭该对象,应用程序必须专门从表中删除该对象。在多线程环境中,至少会出现两个竞争条件

  • 两个线程将尝试使用相同的名称创建对象
  • 一个线程尝试连接到对象,而另一个线程从表中将其删除

为避免这种情况,服务器应用程序通过调用 CoInitialize(NULL) 将自身注册到 STA 中。在这种情况下,对表的访问是序列化的。

要使用新的工厂类,应将 DECLARE_CLASSFACTORY_EX(CComClassFactoryMon) 宏添加到头文件中

class ATL_NO_VTABLE CTheObject : 
... 
... 
{ 
public: 
... 
//here it is set the class factory for the object 
DECLARE_CLASSFACTORY_EX(CComClassFactoryMon) 

使用详情

服务器组件具有一个接口 ITheObject,并且该接口具有一个方法 -

HRESULT TheObjectID([out,retval]LONG* plID); 

实现类具有一个静态成员变量 m_lCounter;构造函数递增 m_lCounter 并对其进行缓存。TheObjectID 方法返回 m_lCounter 的缓存值,这样每个组件都有一个“唯一”标识符(当然,如果 m_lCounter 溢出,则唯一性会受到影响)。

对特定对象感兴趣的客户端将调用

HRESULT hr = CoGetObject(
  OLESTR("clsid:4F408B03-404A-4E14-949F-686969AE21D8:!myObject"),
  NULL, __uuidof(ITheObject), (void**)&spITheObjectPtr);

如果“myObject”尚未运行,则类工厂将创建它并将其插入表中。

不关心获得哪个对象的客户端可以调用

HRESULT hr = ::CoCreateInstance(CLSID_TheObject, NULL, 
  CLSCTX_ALL, __uuidof(ITheObject),(void**)&spITheObjectPtr);

当您决定不再需要该对象时,您必须调用

HRESULT hr = CoGetObject(
  OLESTR("clsid:4F408B03-404A-4E14-949F-686969AE21D8:"),NULL,
  __uuidof(ITheObjectsTable),(void**)&spITheObjectsTable);
if(SUCCEEDED(hr))
{
  spITheObjectsTable->RemoveObject(OLESTR("myObject"));
}

有两个项目

  • MonikerServer ATL 项目
  • MonikerClient MFC 项目

如果您在计算机上编译 MonikerServer 项目,服务器将自行注册。如果您选择不编译该项目,则运行 /Release/MonikerServer.exe以允许服务器自注册。启动 MonikerClient 应用程序并在编辑框中输入一个名称。单击“连接”,只读文本框将显示对象 ID。启动第二个 MonikerClient 实例,输入相同的名称,您应该获得相同的 ID。选择复选框“关闭时从表中删除对象”并单击“确定”。在另一个 MonikerClient 实例中单击“确定”。现在所有客户端都已消失,该对象已从表中删除,并且 MonikerServer 应用程序将自行关闭。

© . All rights reserved.