通过 DCOM 传递 C++ 类






4.64/5 (9投票s)
2001年11月16日
2分钟阅读

220923

2494
两个类,它们提供了更丰富的接口和更简单的语义,可以通过 COM/DCOM 传递类
引言
使用 COM 技术传递简单数据,如 long
、int
等很容易。那么像 C++ 类这样的结构化数据呢?
大多数开发人员都知道传递它的方法。 这种方法基于使用 VARIANT
作为 SAFEARRAY
传递数据。 VARIANT
是什么意思?
VARIANT
可能是传递数据的通用功能中的终极选择。 但是,其低级功能范围可能会令人望而却步。 我没有找到一个合适的库来方便地在我的项目中使用它。为了解决这个问题,我构建了两个类来提供更丰富的接口和更简单的语义。 第一个类叫做 CDComObj
。 这个类负责将数据读取/写入 VARIANT。 第二个类 CDcomObjArray
负责跨 DCOM 传递对象集合。 通过使用这两个类,很容易实现任何具有跨 DCOM 传递自身能力的 C++ 类。
使用对象的示例
客户端部分
bool CServerAccessPoint::ServerConnect(CConnection& connObj) { CComSafeArray conn; connObj.Write(conn); // Writing C++ class to VARIANT HRESULT hr = m_pDcomServer->Connect(&conn); if (FAILED(hr)) { // DO something... return false; } return true; }
服务器端部分
STDMETHODIMP CStreamingSrv::Connect(VARIANT *pConnection) { Lock(); CConnection conn; conn.Read(pConnection); // Reading C++ class from VARIANT m_connections.AddConnection(conn); Unlock(); return S_OK; }
是不是很简单?
类
class CDcomObj : public CSLObject { public: CDcomObj(); virtual ~CDcomObj(); virtual void Clear(); virtual void Copy(const CSLObject& objectSrc); void Copy(const CDcomObj& objectSrc); virtual bool IsEqual(const CSLObject& objectSrc); virtual HRESULT WriteToStream(IStream* pStream); virtual HRESULT ReadFromStream(IStream* pStream); virtual long ElementSize(); void Write(VARIANT* pSafeArray); void Write(CComSafeArray* safeArray); virtual void Write(CComSafeArray* safeArray,long& index); void Read(const CLSID& clsid); void Read(VARIANT* pSafeArray); void Read(CComSafeArray* safeArray); virtual void Read(CComSafeArray* safeArray,long& index); void ReadValue(const CComVariant& srcValue,CComVariant& destValue); void ReadValue(const CComVariant& srcValue,CComPtr& destValue); void ReadValue(const CComVariant& srcValue,IUnknown** destValue); void ReadValue(const CComVariant& srcValue,CString& destValue); void ReadValue(const CComVariant& srcValue,CComBSTR& destValue); void ReadValue(const CComVariant& srcValue,LONG& destValue); void ReadValue(const CComVariant& srcValue,CY& destValue); void ReadValue(const CComVariant& srcValue,bool& destValue); void ReadValue(const CComVariant& srcValue,UINT& destValue); void ReadValue(const CComVariant& srcValue,DWORD& destValue); void ReadValue(const CComVariant& srcValue,int& destValue); void ReadValue(const CComVariant& srcValue,double& destValue); void ReadValue(const CComVariant& srcValue,DATETIME_STRUCT& destValue); void ProgIDFromCLSID(const CLSID& clsid,CComBSTR& comBSTR); const CLSID GetCLSID(); const CComBSTR GetLastError(); const bool IsModified() const; const bool IsModified(UINT value) const; const UINT GetModified() const; void AddModified(UINT uModified); void SetModified(UINT uModified); void RemoveModified(UINT uModified); void ShowError(CString lpszError); public: CComBSTR m_strCLSID; CComBSTR m_strProgID; CComBSTR m_strObjectName; protected: // Specifics UINT m_uModified; CComBSTR m_bstrError; };
一步一步使用这些类
实现自己的 DCOM 类非常容易。
步骤 1:创建你自己的类,它派生自 CDComObj
。
class CConnection : public CDcomObj
步骤 2:重新定义以下虚成员函数
// Shows how many elements contains your class virtual long ElementSize()
// Writing class data to VARIANT (SAFEARRAY) virtual void Write(CComSafeArray* safeArray,long& index);
// Reading class data from VARIANT (SAFEARRAY) virtual void Read(CComSafeArray* safeArray,long& index);
// Copying data virtual void Copy(const CSLObject& objectSrc);
// Clear data virtual void Clear();
DComObj
包含一组宏。 因此,重新定义提到的函数很容易
一个示例
为了演示这项技术,我构建了两个类: CConnection
和 CConnectionArray
class CConnection : public CDcomObj { DCL_DCOMOBJ(CConnection) public: CConnection(); virtual ~CConnection(); virtual void Clear(); virtual void Copy(const CSLObject& objectSrc); virtual bool IsEqual(const CSLObject& objectSrc); virtual long ElementSize(); virtual void Write(CComSafeArray* safeArray,long& index); virtual void Read(CComSafeArray* safeArray,long& index); protected: CString m_strComputerName; CString m_strApplicationName; CString m_strUserName; CString m_strPassword; CString m_strServerName; CComBSTR m_strConnectionHandle; };
这是 ElementSize()
成员函数的实现
long CConnection::ElementSize() { return 6 + CDcomObj::ElementSize(); }
你可以在这里找到 Write 和 Read 成员函数的实现。
void CConnection::Write(CComSafeArray* safeArray,long& index) { SA_BEGIN_WRITE(CDcomObj); SA_WRITE(m_strComputerName); SA_WRITE(m_strUserName); SA_WRITE(m_strPassword); SA_WRITE(m_strServerName); SA_WRITE(m_strApplicationName); SA_WRITE(m_strConnectionHandle); } void CConnection::Read(CComSafeArray* safeArray,long& index) { SA_BEGIN_READ(CDcomObj); SA_READ(m_strComputerName); SA_READ(m_strUserName); SA_READ(m_strPassword); SA_READ(m_strServerName); SA_READ(m_strApplicationName); SA_READ(m_strConnectionHandle); }
为了通过 DCOM 流式传输 CConnection
对象的集合,定义如下类就足够了。
class CConnectionArray : public CDcomObjArray { DCL_DCOMOBJ_ARRAY(CConnectionArray,CConnection) public: CConnectionArray(){} CConnectionArray( ccIndex aLimit, ccIndex aDelta , bool shouldDelete = true): CDcomObjArray(aLimit,aDelta ,shouldDelete ) { } virtual ~CConnectionArray(){} };
注释
为了避免在服务器端使用 MFC,我使用了来自 WTL V.3.1 的 CString
对象。 因此,你应该从 Microsoft 网站下载一个。 在任何情况下,都不要忘记在编译器中设置此库的路径:Tools/Options/Directories。
为了方便地操作 SafeArray's
,我使用了来自 www.sellsbrothers.com 的 CComSafeArray
类
演示项目如下所示
- 通过 COM/DCOM 传递 C++ 类/类集合。
- 连接点技术
你怎么能看到呢?
- 通过使用选项 'RegServer' 启动 StreamingServer.exe 来注册服务器:StreamingServer.exe -RegServer。
- 启动客户端的第一个实例:StreamingClient.exe
- 以某个用户身份连接到服务器
- 启动另一个客户端实例
- 使用不同的用户名连接到服务器
- 建立连接后,你可以在任何客户端中看到已连接用户的列表
- 再次启动另一个实例,已连接用户的列表将会增加
发生了什么?
- 在连接阶段,客户端正在向服务器发送一个 C++ 类
CConnection
。 - 如果服务器接受了这个请求,它会将
CConnection
类的集合发送给所有已连接的客户端。