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