1 // Sink.cxx : Implementation of CSink
2
3 #include "stdafx.h"
4 #include <stdio.h>
5 #include <process.h>
6
7 #include "myssink.h"
8 #include "sink.h"
9
10 /////////////////////////////////////////////////////////////////////////////
11 // CSink
12
13 // private methods
14
getHashValue(DISPID dispId)15 unsigned int CSink::getHashValue(DISPID dispId) {
16
17 // casting dispId guarantees positive result
18
19 return (unsigned int)((ULONG)dispId % EVENT_HANDLER_TBL_SIZE);
20 }
21
newEventHandlerEntry(DISPID dispId,void * handler)22 EVENT_HANDLER_ENTRY *CSink::newEventHandlerEntry(DISPID dispId, void *handler) {
23 EVENT_HANDLER_ENTRY *p;
24 p = (EVENT_HANDLER_ENTRY *)malloc(sizeof(EVENT_HANDLER_ENTRY));
25 p->dispId = dispId;
26 p->handler = handler;
27 p->next = NULL;
28
29 return p;
30 }
31
lookupHandler(DISPID dispId)32 EVENT_HANDLER_ENTRY *CSink::lookupHandler(DISPID dispId) {
33 unsigned int hashVal;
34 EVENT_HANDLER_ENTRY *p;
35
36 hashVal = getHashValue(dispId);
37
38 p = &eventHandlerTable[hashVal];
39
40 while (p) {
41 if (p->dispId == dispId) {
42 return p;
43 }
44 p = p->next;
45 }
46
47 return NULL;
48 }
49
50 // constructor
51
CSink(void)52 CSink::CSink(void) {
53 memset(eventHandlerTable,0,sizeof(eventHandlerTable));
54 }
55
56 // destructor
57
~CSink(void)58 CSink::~CSink(void) {
59 EVENT_HANDLER_ENTRY *p,*psave;
60 int i;
61
62 for (i = 0; i < EVENT_HANDLER_TBL_SIZE; i++) {
63 p = &eventHandlerTable[i];
64 while (p != NULL) {
65 if (p->handler) {
66 sink_release_handler(p->handler);
67 p->handler = NULL;
68 }
69 psave = p;
70 p = p->next;
71 free(psave);
72 }
73 }
74 }
75
set_myssink_table(void * p)76 STDMETHODIMP CSink::set_myssink_table(void * p) {
77 myssink_table = (MYSSINK_TABLE *)p;
78 return S_OK;
79 }
80
register_handler(DISPID dispId,void * handler)81 STDMETHODIMP CSink::register_handler(DISPID dispId,void * handler) {
82 unsigned int hashVal;
83 EVENT_HANDLER_ENTRY *p;
84
85 hashVal = getHashValue(dispId);
86
87 p = &eventHandlerTable[hashVal];
88
89 if (p->dispId == (DISPID)0) {
90 p->dispId = dispId;
91 p->handler = handler;
92 p->next = NULL;
93 }
94 else {
95
96 while (p != NULL) {
97
98 if (p->dispId == dispId) { // update existing entry
99 if (p->handler)
100 sink_release_handler(p->handler);
101 p->handler = handler;
102 return S_OK;
103 }
104
105 p = p->next;
106 }
107
108 p->next = newEventHandlerEntry(dispId, handler);
109 }
110
111 return S_OK;
112 }
113
unregister_handler(DISPID dispId)114 STDMETHODIMP CSink::unregister_handler(DISPID dispId) {
115 unsigned int hashVal;
116 EVENT_HANDLER_ENTRY *p;
117
118 hashVal = getHashValue(dispId);
119
120 p = &eventHandlerTable[hashVal];
121
122 if (p->dispId == (DISPID)0) { // no handler installed
123 return S_OK;
124 }
125
126 while (p != NULL) {
127 if (p->dispId == dispId) { // set existing entry to NULL
128 if (p->handler) {
129 sink_release_handler(p->handler);
130 p->handler = NULL;
131 }
132 return S_OK;
133 }
134
135 p = p->next;
136 }
137
138 return S_OK;
139 }
140
variantToSchemeObject(VARIANTARG * pVariantArg)141 void *CSink::variantToSchemeObject(VARIANTARG *pVariantArg) {
142 return sink_variant_to_scheme(pVariantArg);
143 }
144
unmarshalSchemeObject(void * obj,VARIANTARG * pVariantArg)145 void CSink::unmarshalSchemeObject(void *obj,VARIANTARG *pVariantArg) {
146 sink_unmarshal_scheme(obj, pVariantArg);
147 }
148
149 // effectively, override default implementation of IDispatch::QueryInterface
150
InternalQueryInterface(void * pThis,const _ATL_INTMAP_ENTRY * pEntries,REFIID riid,void ** ppVoid)151 HRESULT CSink::InternalQueryInterface(void *pThis,
152 const _ATL_INTMAP_ENTRY* pEntries,
153 REFIID riid,
154 void **ppVoid) {
155
156 // marshalling IID's end in 0000-0000-C0000-000000000046
157 // these seem to be requested by VB and VC++/ATL event sources
158 // the sink doesn't implement those, and doesn't need to
159
160 if (riid != IID_IUnknown && riid != IID_IDispatch && riid != IID_ISink) {
161 LPOLESTR str;
162 BOOL isSystemIID;
163
164 StringFromIID(riid,&str);
165
166 str[37] = L'\0';
167
168 isSystemIID = (_wcsicmp(str + 10,L"0000-0000-C000-000000000046") == 0);
169
170 CoTaskMemFree(str);
171
172 if (isSystemIID) {
173 return E_NOINTERFACE;
174 }
175 }
176
177 /* Don't claim to implement INoMarshal, because that disables
178 the sink for some uses, including with MzCOM */
179 if (riid == IID_INoMarshal) {
180 return E_NOINTERFACE;
181 }
182
183 // Use IUnknown pointer for IUnknown, ISink, and anything else (which we assume to be the outbound interface)
184
185 return CComObjectRootEx<CComSingleThreadModel>::InternalQueryInterface(pThis,pEntries,IID_IUnknown,ppVoid);
186
187 }
188
189 // override default implementation of IDispatch::Invoke
190
191 typedef struct _named_args_ {
192 DISPID dispId;
193 VARIANTARG *pVariantArg;
194 unsigned int index;
195 } NAMEDARG;
196
cmpNamedArgs(NAMEDARG * p1,NAMEDARG * p2)197 int cmpNamedArgs(NAMEDARG *p1,NAMEDARG *p2) {
198 return (int)p1->dispId - (int)p2->dispId;
199 }
200
Invoke(DISPID dispId,REFIID,LCID,WORD,DISPPARAMS * pDispParams,VARIANT *,EXCEPINFO *,UINT *)201 HRESULT CSink::Invoke(DISPID dispId, REFIID, LCID, WORD,
202 DISPPARAMS* pDispParams,
203 VARIANT*, EXCEPINFO*, UINT*) {
204
205 void *handler;
206 EVENT_HANDLER_ENTRY *p;
207 VARIANTARG *pCurrArg;
208 NAMEDARG namedArgs[MAXINVOKEARGS];
209 UINT numParams,actualParams,positionalParams,namedParams;
210 void *argv[MAXINVOKEARGS];
211 UINT i;
212 UINT j;
213
214 p = lookupHandler(dispId);
215
216 if (p == NULL) { // nothing registered
217 return S_OK;
218 }
219
220 handler = p->handler;
221
222 if (handler == NULL) { // handler was unregistered
223 return S_OK;
224 }
225
226 numParams = pDispParams->cArgs;
227
228 if (numParams > MAXINVOKEARGS) {
229 return DISP_E_TYPEMISMATCH;
230 }
231
232 namedParams = pDispParams->cNamedArgs;
233
234 if (namedParams > 0) {
235 for (i = 0; i < namedParams; i++) {
236 namedArgs[i].dispId = pDispParams->rgdispidNamedArgs[i];
237 namedArgs[i].pVariantArg = &pDispParams->rgvarg[i];
238 }
239
240 qsort(namedArgs,namedParams,sizeof(NAMEDARG),
241 (int (*)(const void *,const void *))cmpNamedArgs);
242 }
243
244 /* memory layout of rgvargs:
245
246 ---------------------------------
247 | named params | required params |
248 ---------------------------------
249
250 these are in reverse order from the order
251 given to Racket
252
253 */
254
255 actualParams = 0;
256
257 positionalParams = numParams - namedParams;
258
259 for (i = 0; i < positionalParams; i++) {
260 pCurrArg = &pDispParams->rgvarg[numParams - 1 - i];
261 argv[i] = variantToSchemeObject(pCurrArg);
262 if (!argv[i]) {
263 for (i = 0; i < actualParams; i++) {
264 sink_release_arg(argv[i]);
265 }
266 return S_OK;
267 }
268 actualParams++;
269 }
270
271 int ii = positionalParams;
272 j = 0;
273
274 while (j < namedParams) {
275
276 if (ii >= MAXINVOKEARGS) {
277 return DISP_E_TYPEMISMATCH;
278 }
279
280 while(ii < namedArgs[j].dispId) {
281 if (ii >= MAXINVOKEARGS) {
282 return DISP_E_TYPEMISMATCH;
283 }
284
285 argv[ii] = make_scode(DISP_E_PARAMNOTFOUND);
286 ii++,actualParams++;
287 }
288
289 argv[ii] = variantToSchemeObject(namedArgs[j].pVariantArg);
290 if (!argv[ii]) {
291 for (i = 0; i < actualParams; i++) {
292 sink_release_arg(argv[i]);
293 }
294 return S_OK;
295 }
296 namedArgs[j].index = ii;
297 ii++,j++,actualParams++;
298 }
299
300 (void)sink_apply(handler,actualParams,argv);
301
302 // updating of boxes needs to be reflected in BYREF parameters
303
304 for (i = 0; i < positionalParams; i++) {
305 pCurrArg = &pDispParams->rgvarg[numParams - 1 - i];
306 unmarshalSchemeObject(argv[i],pCurrArg);
307 }
308
309 for (i = 0; i < namedParams; i++) {
310 pCurrArg = namedArgs[i].pVariantArg;
311 j = namedArgs[i].index;
312 unmarshalSchemeObject(argv[j],pCurrArg);
313 }
314
315 return S_OK;
316 }
317
318