CodeGuru
Earthweb Search
Forums Wireless Jars Gamelan Developer.com
CodeGuru Navigation
Member Sign In
User ID:
Password:
Remember Me:
Forgot Password?
Not a member?
Click here for more information and to register.

Become a Marketplace Partner

jobs.internet.com

internet.commerce
Partners & Affiliates
















RSS Feeds

RSSAll

RSSVC++/C++

RSS.NET/C#

RSSVB

See more EarthWeb Network feeds

Home >> Visual C++ / C++ >> COM-based Technologies >> ATL & WTL Programming >> ATL


ATL: Firing Events from Worker Threads
Rating:

Michael Lindig (view profile)
July 16, 2000

Environment: VC6 SP4, NT4 SP3

If You have ever the problem : "VB client keep crashing when compiled and not in the IDE if it has a worker thread" then here is a possible solution.
(continued)



In most cases of my work I develop ATL objects with worker threads. In the worker threads there must be often fire events for signalling thread states. The problem of firing events from worker thread is that they must enter another apartment. In this apartment the sink interfaces are not valid and thats why some clients would not be receive the events (eg VB). I found a simple solution for that. (A solution without PostMessage.)

Only the proxy code of wizard must be changed, to get the firing of events right. I use the global interface table (GIT) for my solution. "The GIT holds a list of marshaled interface pointers that, on request can be unmarshaled any number of times to any number of apartment in your process, regardless of whether the pointer is for an object or a proxy."(Professional ATL COM Programming, Dr Richard Grimes).

I wrote a new specialized class for CComDynamicUnkArray which use the GIT for accessing the sink interfaces.


Specialized class CComDynamicUnkArray_GIT

class CComDynamicUnkArray_GIT : public CComDynamicUnkArray
{
private:
 IGlobalInterfaceTable*  GIT;

public:
 CComDynamicUnkArray_GIT() : CComDynamicUnkArray()
 {
  GIT = NULL;

  CoCreateInstance(CLSID_StdGlobalInterfaceTable,
                   NULL,
                   CLSCTX_INPROC_SERVER,
                   __uuidof(IGlobalInterfaceTable),
                   reinterpret_cast< void** >(&GIT) );
 }

 ~CComDynamicUnkArray_GIT()
 {
  //clean up the class
  clear();
  if( GIT != NULL )
  {
   GIT->Release();
  }
 }

 DWORD Add(IUnknown* pUnk);
 BOOL Remove(DWORD dwCookie);

 //The proxy code use this function to get the interface !
 CComPtr GetAt(int nIndex)
 {
  DWORD dwCookie = (DWORD)CComDynamicUnkArray::GetAt( nIndex );

  if( dwCookie == 0 )
  return NULL;

  if( CookieMap.find( dwCookie ) == CookieMap.end() )
  {
   return (IUnknown*)dwCookie;
  }

  if( GIT != NULL )
  {
   CComPtr   ppv;

   HRESULT hr = GIT->GetInterfaceFromGlobal(
    CookieMap[dwCookie], //Cookie identifying the desired global
                         //interface and its object
    __uuidof(IUnknown),  //IID of the registered global interface
    reinterpret_cast< void** >(&ppv) //Indirect pointer
                                     //to the desired interface
   );

   if( hr == S_OK )
   {
    return ppv;
   }

  //Should never be reached, a ASSERT or exception is possible
  }
  return (IUnknown*)dwCookie;
 }

 //clean up the GIT
 void clear()
 {
  CComDynamicUnkArray::clear();

  if( GIT != NULL )
  {
   map< DWORD, DWORD >::iterator iter;
   for (iter = CookieMap.begin();
        iter != CookieMap.end();
        ++iter )
   {
    GIT->RevokeInterfaceFromGlobal(
     iter->second      //Cookie that was returned from
     //RegisterInterfaceInGlobal
    );
   }
  }
  CookieMap.clear();
 }

protected:
 map< DWORD, DWORD > CookieMap;
};

 inline DWORD CComDynamicUnkArray_GIT::Add(IUnknown* pUnk)
 {
  DWORD Result = CComDynamicUnkArray::Add( pUnk );

  HRESULT hr;
  DWORD   pdwCookie = 0;
  if( GIT != NULL )
  {
   hr = GIT->RegisterInterfaceInGlobal(
    pUnk,               //Pointer to interface of type riid
                        //of object containing global interface
    __uuidof(IUnknown), //IID of the interface to be registered
    &pdwCookie          //Supplies a pointer to the cookie that
                        //provides a caller in another apartment
                        //access to the interface pointer
   );
  }
  if( hr == S_OK )
  {
  CookieMap[Result] = pdwCookie;
  }

 return Result;
 }

 inline BOOL CComDynamicUnkArray_GIT::Remove(DWORD dwCookie)
 {
  BOOL Result = CComDynamicUnkArray::Remove( dwCookie );

  if( GIT != NULL )
  {
   if( CookieMap.find( dwCookie ) != CookieMap.end() )
   {
    GIT->RevokeInterfaceFromGlobal(
     CookieMap[dwCookie] //Cookie that was returned from
                         //RegisterInterfaceInGlobal
		);

   CookieMap.erase(dwCookie);
   }
  }
  return Result;
 }

Changes in proxy generated files:

Change:

template <class T>
class CProxy_ISchedulerEvents :
public IConnectionPointImpl<T,
                            &DIID__ISchedulerEvents,
                            CComDynamicUnkArray>

To

#include "CProxyEvent.h"

template <class T>
class CProxy_ISchedulerEvents :
public IConnectionPointImpl<T,
                            &DIID__ISchedulerEvents,
                            CComDynamicUnkArray_GIT>

In the proxy generated event method you must make a replace as follow:

Change:

VOID Fire_Activate(IBundle * pBundle, BSTR ActivationTime)
{
 T* pT = static_cast< T* >(this);
 int nConnectionIndex;
 CComVariant* pvars = new CComVariant[2];
 int nConnections = m_vec.GetSize();

 for (nConnectionIndex = 0;
      nConnectionIndex < nConnections;
      nConnectionIndex++)
 {
  pT->Lock();
  CComPtr< IUnknown > sp = m_vec.GetAt(nConnectionIndex);
  pT->Unlock();
  IDispatch* pDispatch = reinterpret_cast< IDispatch* >(sp.p);
  if (pDispatch != NULL)
   {
   pvars[1] = pBundle;
   pvars[0] = ActivationTime;
   DISPPARAMS disp = { pvars, NULL, 2, 0 };
   pDispatch->Invoke(0x1, IID_NULL, LOCALE_USER_DEFAULT,
                     DISPATCH_METHOD, &disp, NULL, NULL, NULL);
  }
 }
 delete[] pvars;
}

To:

VOID Fire_Activate(IBundle * pBundle, BSTR ActivationTime)
{
 T* pT = static_cast< T* >(this);
 int nConnectionIndex;
 CComVariant* pvars = new CComVariant[2];
 int nConnections = m_vec.GetSize();

 for (nConnectionIndex = 0;
      nConnectionIndex < nConnections;
      nConnectionIndex++)
 {
  pT->Lock();
  CComPtr< IUnknown > sp = m_vec.GetAt(nConnectionIndex);
  pT->Unlock();
  CComQIPtr< IDispatch > pDispatch( sp );
  if (pDispatch != NULL)
  {
   pvars[1] = pBundle;
   pvars[0] = ActivationTime;
   DISPPARAMS disp = { pvars, NULL, 2, 0 };
   pDispatch->Invoke(0x1, IID_NULL, LOCALE_USER_DEFAULT,
                     DISPATCH_METHOD, &disp, NULL, NULL, NULL);
  }
 }
 delete[] pvars;
}

Simple make a replace with IDispatch* pDispatch = reinterpret_cast< IDispatch* >(sp.p) to CComQIPtr< IDispatch > pDispatch( sp ), that's all !

Downloads

Download CEventProxy.h source - 1 Kb
Download example source (inludes VBasic client) - 62 Kb

Tools:
Add www.codeguru.com to your favorites
Add www.codeguru.com to your browser search box
IE 7 | Firefox 2.0 | Firefox 1.5.x
Receive news via our XML/RSS feed







RATE THIS ARTICLE:   Excellent  Very Good  Average  Below Average  Poor  

(You must be signed in to rank an article. Not a member? Click here to register)

Latest Comments:
Thanks a lot. It solved my crucial problem and understanding.... - yogeshd (05/24/2006)
Thank you!!! - AdamAndrewNichols (03/01/2006)
DLL Hangs when client trys to exit with multiple connections - Clive Battisby (01/27/2005)
Windows2000 and WinXP Problem - benjis (06/16/2004)
Need Help - Gajalakshmi Krishnan (04/29/2004)

View All Comments
Add a Comment:
Title:
Comment:
Pre-Formatted: Check this if you want the text to display with the formatting as typed (good for source code)



(You must be signed in to comment on an article. Not a member? Click here to register)


JupiterOnlineMedia

internet.comearthweb.comDevx.commediabistro.comGraphics.com

Search:

Jupitermedia Corporation has two divisions: Jupiterimages and JupiterOnlineMedia

Jupitermedia Corporate Info


Legal Notices, Licensing, Reprints, & Permissions, Privacy Policy.

Advertise | Newsletters | Tech Jobs | Shopping | E-mail Offers

Solutions
Whitepapers and eBooks
Intel PDF: Virtualization Delivers Data Center Efficiency
Intel eBook: Managing the Evolving Data Center
Microsoft Article: BitLocker Brings Encryption to Windows Server 2008
Symantec eBook: The Guide to E-Mail Archiving and Management
Microsoft Article: RODCs Transform Branch Office Security
Go Parallel Article: James Reinders on the Intel Parallel Studio Beta Program
Avaya Article: Advancing the State of the Art in Customer Service
Adobe Acrobat Connect Pro: Web Conferencing and eLearning Whitepapers
Avaya Article: Avaya AE Services Provide Rapid Telephony Integration with Facebook
Go Parallel Article: Getting Started with TBB on Windows
HP eBook: Storage Networking , Part 1
MORE WHITEPAPERS, EBOOKS, AND ARTICLES
Webcasts
Intel Seminar: Efficiencies in Hardware/Software Virtualization
HP Webcast: Disaster Recovery Planning
Go Parallel Video: Performance and Threading Tools for Game Developers
HP Video: StorageWorks EVA4400 and Oracle
HP Webcast: Storage Is Changing Fast - Be Ready or Be Left Behind
MORE WEBCASTS, PODCASTS, AND VIDEOS
Downloads and eKits
IBM TCO eKIT: Your IT Budget is Under Attack, Get in Control
IBM Energy Efficiency eKIT: Learn How to Reduce Costs
30-Day Trial: SPAMfighter Exchange Module
Red Gate Download: SQL Toolbelt and free High-Performance SQL Code eBook
Iron Speed Designer Application Generator
MORE DOWNLOADS, EKITS, AND FREE TRIALS
Tutorials and Demos
Microsoft Article: Silverlight Streaming--Free Video Hosting for All
Featured Algorithm: Intel Threading Building Blocks - parallel_reduce
HP Demo: StorageWorks EVA4400
MORE TUTORIALS, DEMOS AND STEP-BY-STEP GUIDES