随笔 - 17  文章 - 0 评论 - 4 
<2009年8月>
2627282930311
2345678
9101112131415
16171819202122
23242526272829
303112345

常用链接

留言簿(1)

随笔档案(17)

文章分类

搜索

  •  

最新评论

阅读排行榜

评论排行榜

Michael Lindig    
July 16, 2000

 

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

  1class CComDynamicUnkArray_GIT : public CComDynamicUnkArray
  2{
  3private:
  4 IGlobalInterfaceTable*  GIT;
  5
  6public:
  7 CComDynamicUnkArray_GIT() : CComDynamicUnkArray()
  8 {
  9  GIT = NULL;
 10
 11  CoCreateInstance(CLSID_StdGlobalInterfaceTable,
 12                   NULL,
 13                   CLSCTX_INPROC_SERVER,
 14                   __uuidof(IGlobalInterfaceTable),
 15                   reinterpret_cast< void** >(&GIT) );
 16 }

 17
 18 ~CComDynamicUnkArray_GIT()
 19 {
 20  //clean up the class
 21  clear();
 22  if( GIT != NULL )
 23  {
 24   GIT->Release();
 25  }

 26 }

 27
 28 DWORD Add(IUnknown* pUnk);
 29 BOOL Remove(DWORD dwCookie);
 30
 31 //The proxy code use this function to get the interface !
 32 CComPtr GetAt(int nIndex)
 33 {
 34  DWORD dwCookie = (DWORD)CComDynamicUnkArray::GetAt( nIndex );
 35
 36  if( dwCookie == 0 )
 37  return NULL;
 38
 39  if( CookieMap.find( dwCookie ) == CookieMap.end() )
 40  {
 41   return (IUnknown*)dwCookie;
 42  }

 43
 44  if( GIT != NULL )
 45  {
 46   CComPtr   ppv;
 47
 48   HRESULT hr = GIT->GetInterfaceFromGlobal(
 49    CookieMap[dwCookie], //Cookie identifying the desired global
 50                         //interface and its object
 51    __uuidof(IUnknown),  //IID of the registered global interface
 52    reinterpret_cast< void** >(&ppv) //Indirect pointer
 53                                     //to the desired interface
 54   );
 55
 56   if( hr == S_OK )
 57   {
 58    return ppv;
 59   }

 60
 61  //Should never be reached, a ASSERT or exception is possible
 62  }

 63  return (IUnknown*)dwCookie;
 64 }

 65
 66 //clean up the GIT
 67 void clear()
 68 {
 69  CComDynamicUnkArray::clear();
 70
 71  if( GIT != NULL )
 72  {
 73   map< DWORD, DWORD >::iterator iter;
 74   for (iter = CookieMap.begin();
 75        iter != CookieMap.end();
 76        ++iter )
 77   {
 78    GIT->RevokeInterfaceFromGlobal(
 79     iter->second      //Cookie that was returned from
 80     //RegisterInterfaceInGlobal
 81    );
 82   }

 83  }

 84  CookieMap.clear();
 85 }

 86
 87protected:
 88 map< DWORD, DWORD > CookieMap;
 89}
;
 90
 91 inline DWORD CComDynamicUnkArray_GIT::Add(IUnknown* pUnk)
 92 {
 93  DWORD Result = CComDynamicUnkArray::Add( pUnk );
 94
 95  HRESULT hr;
 96  DWORD   pdwCookie = 0;
 97  if( GIT != NULL )
 98  {
 99   hr = GIT->RegisterInterfaceInGlobal(
100    pUnk,               //Pointer to interface of type riid
101                        //of object containing global interface
102    __uuidof(IUnknown), //IID of the interface to be registered
103    &pdwCookie          //Supplies a pointer to the cookie that
104                        //provides a caller in another apartment
105                        //access to the interface pointer
106   );
107  }

108  if( hr == S_OK )
109  {
110  CookieMap[Result] = pdwCookie;
111  }

112
113 return Result;
114 }

115
116 inline BOOL CComDynamicUnkArray_GIT::Remove(DWORD dwCookie)
117 {
118  BOOL Result = CComDynamicUnkArray::Remove( dwCookie );
119
120  if( GIT != NULL )
121  {
122   if( CookieMap.find( dwCookie ) != CookieMap.end() )
123   {
124    GIT->RevokeInterfaceFromGlobal(
125     CookieMap[dwCookie] //Cookie that was returned from
126                         //RegisterInterfaceInGlobal
127        );
128
129   CookieMap.erase(dwCookie);
130   }

131  }

132  return Result;
133 }

Changes in proxy generated files:

Change:

1template <class T>
2class CProxy_ISchedulerEvents :
3public IConnectionPointImpl<T,
4                            &DIID__ISchedulerEvents,
5                            CComDynamicUnkArray>
6
to
1#include "CProxyEvent.h"
2
3template <class T>
4class CProxy_ISchedulerEvents :
5public IConnectionPointImpl<T,
6                            &DIID__ISchedulerEvents,
7                            CComDynamicUnkArray_GIT>
8

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

Change:

 1VOID Fire_Activate(IBundle * pBundle, BSTR ActivationTime)
 2{
 3 T* pT = static_cast< T* >(this);
 4 int nConnectionIndex;
 5 CComVariant* pvars = new CComVariant[2];
 6 int nConnections = m_vec.GetSize();
 7
 8 for (nConnectionIndex = 0;
 9      nConnectionIndex < nConnections;
10      nConnectionIndex++)
11 {
12  pT->Lock();
13  CComPtr< IUnknown > sp = m_vec.GetAt(nConnectionIndex);
14  pT->Unlock();
15  IDispatch* pDispatch = reinterpret_cast< IDispatch* >(sp.p);
16  if (pDispatch != NULL)
17   {
18   pvars[1= pBundle;
19   pvars[0= ActivationTime;
20   DISPPARAMS disp = { pvars, NULL, 20 };
21   pDispatch->Invoke(0x1, IID_NULL, LOCALE_USER_DEFAULT,
22                     DISPATCH_METHOD, &disp, NULL, NULL, NULL);
23  }

24 }

25 delete[] pvars;
26}

27
To
 1VOID Fire_Activate(IBundle * pBundle, BSTR ActivationTime)
 2{
 3 T* pT = static_cast< T* >(this);
 4 int nConnectionIndex;
 5 CComVariant* pvars = new CComVariant[2];
 6 int nConnections = m_vec.GetSize();
 7
 8 for (nConnectionIndex = 0;
 9      nConnectionIndex < nConnections;
10      nConnectionIndex++)
11 {
12  pT->Lock();
13  CComPtr< IUnknown > sp = m_vec.GetAt(nConnectionIndex);
14  pT->Unlock();
15  CComQIPtr< IDispatch > pDispatch( sp );
16  if (pDispatch != NULL)
17  {
18   pvars[1= pBundle;
19   pvars[0= ActivationTime;
20   DISPPARAMS disp = { pvars, NULL, 20 };
21   pDispatch->Invoke(0x1, IID_NULL, LOCALE_USER_DEFAULT,
22                     DISPATCH_METHOD, &disp, NULL, NULL, NULL);
23  }

24 }

25 delete[] pvars;
26}

27
    

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

posted on 2009-08-08 14:15 鸡蛋捞面 阅读(628) 评论(2)  编辑 收藏 引用

FeedBack:
# re: [转]ATL: Firing Events from Worker Threads 2009-08-09 10:20 99读书人
不错啊  回复  更多评论
  
# re: [转]ATL: Firing Events from Worker Threads 2009-08-12 12:38 戴尔电脑
路过踩踩!  回复  更多评论
  
只有注册用户登录后才能发表评论。