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

通过 DCOM 传递 C++ 类

2001年11月16日

2分钟阅读

viewsIcon

220923

downloadIcon

2494

两个类,它们提供了更丰富的接口和更简单的语义,可以通过 COM/DCOM 传递类

Sample Image

引言

使用 COM 技术传递简单数据,如 longint 等很容易。那么像 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++ 类/类集合。
  • 连接点技术

你怎么能看到呢?

  1. 通过使用选项 'RegServer' 启动 StreamingServer.exe 来注册服务器:StreamingServer.exe -RegServer。
  2. 启动客户端的第一个实例:StreamingClient.exe
  3. 以某个用户身份连接到服务器
  4. 启动另一个客户端实例
  5. 使用不同的用户名连接到服务器
  6. 建立连接后,你可以在任何客户端中看到已连接用户的列表
  7. 再次启动另一个实例,已连接用户的列表将会增加

发生了什么?

  1. 在连接阶段,客户端正在向服务器发送一个 C++ 类 CConnection
  2. 如果服务器接受了这个请求,它会将 CConnection 类的集合发送给所有已连接的客户端。
© . All rights reserved.