【他山之石】在工作线触发事件

你在ATL中实现多线程,而且想在工作线程中触发事件,显示工作的状态么?

前些日子,一直饱受这个问题困扰,今天太开心,无意被我看这个篇文章,帮我解决了这个问题!

虽然问题解决了,但并不是非常理解!故而复制了该文件,贴于此,以供仔细研究!

非常感谢原文作者--Michael Lindig

 

 

原文出处:http://www.codeguru.com/Cpp/COM-Tech/atl/atl/article.php/c75

 

原文如下:

ATL: Firing Events from Worker Threads

 Michael Lindig (view profile)
July 16, 2000

 

 the sink interfaces.

 

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

 


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 !

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值