Click here to Skip to main content
Click here to Skip to main content

Passing C++ classes across DCOM

, 15 Nov 2001
Rate this:
Please Sign up or sign in to vote.
Two classes that provide richer interfaces and easier semantics to pass classes via COM/DCOM

Sample Image

Introduction

Using COM technology to pass simple data like long, int, etc is easy. And what about structured data like C++ classes?

The most developers know the way to pass that. This way is based on passing data using VARIANT as SAFEARRAY. And what does VARIANT mean?

The VARIANT is perhaps the ultimate in general purpose functionality for passing data. But its range of low-level features can be daunting. I did not find a suitable library for the easy use of one in my projects.

To resolve this problem I built two classes to provide richer interfaces and easier semantics. The first class called CDComObj. This class is responsible for Reading/Writing data into/from VARIANT. The second class, CDcomObjArray, is responsible for passing collection of objects across DCOM. By using both of these classes it is easy to implement any C++ class which has ability to pass itself across DCOM.

An Example Using the Objects

Client part:

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;
}

Server part:

STDMETHODIMP CStreamingSrv::Connect(VARIANT *pConnection)
{
  Lock();
  CConnection conn;
  conn.Read(pConnection); // Reading C++ class from VARIANT

  m_connections.AddConnection(conn);
  Unlock();
  return S_OK;
}

Is not easy?

Classes

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<IUNKNOWN>& 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;
};

Using the classes, step by step

The implementation of own DCOM class is very easy.

Step 1: Create your own class derived from CDComObj.

 class CConnection  : public CDcomObj

Step 2: Redefine the following virtual member functions :

// 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();

The DComObj contains the set of macros. So, redefinitions of mentioned functions is easy

An Example

To demonstrate this technique I built two classes: CConnection and 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;
};

Here is the implementation of ElementSize() member function

long CConnection::ElementSize()			
{ 
  return 6 + CDcomObj::ElementSize();	
}

The implementation of Write and Read member function you can find here.

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);
}

For streaming the collection of CConnection objects across DCOM it is enough to define class like here.

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(){}

};

Notes

To avoid MFC at Server side I am using CString object from WTL V.3.1. So, you should download one from Microsoft site. In any case don't forget to setup path to this library in your Compiler: Tools/Options/Directories.

For easy manipulation of SafeArray's, I am using the CComSafeArray class from www.sellsbrothers.com

The Demo project is demonstrated as follows:

  • Passing C++ class / collection of classes across COM/DCOM.
  • Connection Point Technique

How can you see that?

  1. Register Server by starting StreamingServer.exe with option 'RegServer' : StreamingServer.exe -RegServer.
  2. Start first instance of Client: StreamingClient.exe
  3. Connect to the server as some user
  4. Start another one instance of Client
  5. Connect to server with different user name
  6. After establishing connection you can see list of connected users in any Client
  7. Start another one instance again and list of connected users will grow

What's going on?

  1. Under connection stage the client is sending to the server a C++ class CConnection.
  2. If the server accepted this request it sends a collection of CConnection classes to everything connected clients.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Eugene Khodakovsky
Software Developer (Senior)
United States United States
No Biography provided

Comments and Discussions

 
QuestionLicense PinmemberMember 896106528-May-12 23:19 
GeneralMissing licence PinmemberFrederic Souchu25-Oct-10 22:52 
QuestionHow to get it working under .NET PinmemberBen_6625-Apr-06 0:20 
QuestionStandard way Pinmemberflorin10327-Nov-05 22:14 
AnswerRe: Standard way PinmemberStupid_Stuart4-Dec-06 10:16 
GeneralAny language client Pinmembersergeyv20026-Oct-04 10:14 
GeneralBooks for COM/DCOM PinmemberSuyash15-Apr-04 23:36 
GeneralRe: Books for COM/DCOM PinmemberSnews28-Sep-04 20:09 
Questioncould you Help me ? PinmemberBrutusKiller11-Mar-04 1:41 
AnswerRe: could you Help me ? PinmemberEugene Khodakovsky11-Mar-04 2:05 
GeneralRe: could you Help me ? Pinmemberbrutuskiller11-Mar-04 2:22 
GeneralRe: could you Help me ? PinmemberEugene Khodakovsky11-Mar-04 3:02 
GeneralRe: could you Help me ? PinmemberbrutusKiiller11-Mar-04 3:38 
GeneralRe: could you Help me ? PinmemberBrutusKiller15-Mar-04 5:46 
GeneralRe: could you Help me ? PinmemberEugene Khodakovsky15-Mar-04 6:49 
GeneralRe: could you Help me ? PinmemberBrutusKiller17-Mar-04 0:13 
GeneralCompile error Pinmemberstongstong1-Sep-03 15:16 
GeneralProblem running on Windows NT4 Pinmemberronny_12-Mar-03 1:08 
GeneralThis code will not work in MTA configuration PinmemberVic_mx23-Aug-02 21:12 
GeneralError 0x80010105 PinmemberBennyf10-Apr-02 23:42 
GeneralRe: Error 0x80010105 PinmemberEugeneK11-Apr-02 3:13 
ConnectionSink is supported unlimited amount of events. Maybe you have some bug.
Try to recognize type of error before.
For do that try to use FormatMessage:
char szErrorDesc[100];
 
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, errNum,
MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),
szErrorDesc, sizeof(szErrorDesc), NULL);
 
Thanks,
Eugene
GeneralRe: Error 0x80010105 PinmemberBennyf11-Apr-02 18:46 
GeneralRe: Error 0x80010105 PinmemberTim Smith11-Apr-02 3:40 
QuestionAccess is denied? PinmemberBennyf9-Apr-02 21:23 
AnswerRe: Access is denied? PinmemberEugeneK10-Apr-02 3:27 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140721.1 | Last Updated 16 Nov 2001
Article Copyright 2001 by Eugene Khodakovsky
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid