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 }
posted on 2009-08-08 14:15
鸡蛋捞面 阅读(859)
评论(2) 编辑 收藏 引用