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
1
class CComDynamicUnkArray_GIT : public CComDynamicUnkArray
2

{
3
private:
4
IGlobalInterfaceTable* GIT;
5
6
public:
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
87
protected:
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
鸡蛋捞面 阅读(864)
评论(2) 编辑 收藏 引用