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






4.35/5 (10投票s)
2003 年 7 月 31 日
2分钟阅读

68406

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 应用程序将自行关闭。