Implementing Asynchronous Data Transfer for COM Clients

The demo for this article was built and compiled on Windows 98 using Visual C++ 6.0. To build the demo, load the async client project and do a complete build. This should also build the COM server project at the same time. You can test the demo by clicking the Asynchronous Request button and performing user actions such moving the window around, displaying a message box and minimizing or closing the window.

If you have a situation when you need to get data from a com server that may take an undetermined amount of time and you require your user interface to respond to user commands during this time, this article is for you. It discusses and provides a mechanism for asynchronous data transfer when retrieving data from a COM server. The basic idea is to provide a base class, which I call CAsyncClass, that you inherit from, which will create a separate thread for the data retrieval and override the windows message loop while waiting for the data to return. The following steps outline how to use the CAsyncClass functionality.

1. Add the files async.h and async.cpp to your project.

2. Create and inherit a new class from CAsyncClass.

3. Add data members in your new class to hold the values returned from your com server calls.

4. Optional: Add a Get/Set methods for your data members.

5. Add an OnNotify method to your client inorder to extract the data from your class.

6. Override the virtual method CAsyncClass::OnNotifyComplete to call the OnNotify method when the synchronous data transfer is complete.

7. Override the virtual method OnRequestData to CREATE an interface to your com server object and request your data. NOTE: By the time OnReqestData is called, it will be operating in a separate thread. You cannot use an existing interface that was created in another thread.

8. Add a method in your client to call CAsyncClass::DoRequestData.

EXAMPLE

//////////////////////////////////////////////////////////////////////
// CDemoClass sample class used in this demo

class CDemoClass :public CAsyncClass
{
// Construction
public:
  CDemoClass(CAsyncclientDlg* pOwner)
    :CAsyncClass() 
  {
    m_pOwner=pOwner; 
  }

// Attributes
private:
  _bstr_t           m_bstrData;
  CAsyncclientDlg*  m_pOwner;

// Operations
public:
  _bstr_t&  GetData()               { return m_bstrData; }	
  void      SetData(_bstr_t& bstr)  { m_bstrData=bstr;   }	

// Operations
public:
  void OnNotifyComplete() { m_pOwner->OnDemoNotify(); }
 
  void OnRequestData()
  {
    try
    {
      IasyncProducerPtr p(_T("Asyncserver.asyncProducer.1"));
      SetData(p->GetAsyncData());	
    }
    catch(_com_error &e)
    {
      SetError(e.Error());
    }
  }
};

//////////////////////////////////////////////////////////////////////
// The client window used in this demo

void CAsyncclientDlg::OnDemoNotify() 
{ 
  DWORD dwError=m_pDemoClass->GetError();

  if(dwError)
    m_sReturn.Format(_T("Error %d"),dwError); 
  else
    m_sReturn=(LPTSTR)m_pDemoClass->GetData();

  UpdateData(FALSE); 
}

void CAsyncclientDlg::OnAsyncButton() 
{
  m_sReturn.Empty();

  UpdateData(FALSE);

  if(m_pDemoClass)
    m_pDemoClass->DoRequestData();
}

Download demo project - 68 KB

Download source code - 2 KB

Date Last Updated: May 17, 1999