1 #ifndef __DISPEXSINKCONNECTOR_H__
2 #define __DISPEXSINKCONNECTOR_H__
3
4 #include "stdafx.h"
5 #include <dispex.h>
6
7 class CDispExSinkConnector :
8 public IDispatch
9 {
10 protected:
11 class CTypeInfoHolder
12 {
13 public:
14 const GUID *m_piid;
15 const GUID *m_plibid;
16 WORD m_wMajorVer;
17 WORD m_wMinorVer;
18 LCID m_lcid;
19 CComPtr<ITypeInfo> m_pTypeInfo;
20 CSimpleMap<DISPID, BSTR> m_mapDispId;
21
22 CTypeInfoHolder(const GUID *piid, const GUID *plibid, WORD wMajorVer,
23 WORD wMinorVer, LCID lcid) :
24 m_piid(piid), m_plibid(plibid), m_wMajorVer(wMajorVer),
25 m_wMinorVer(wMinorVer), m_lcid(lcid)
26 {
27 ATLASSERT(m_piid && m_plibid);
28 LoadFunctionNames();
29 }
30
31 ~CTypeInfoHolder()
32 {
33 for(int i = 0; i < m_mapDispId.GetSize(); i++)
34 SysFreeString(m_mapDispId.GetValueAt(i));
35 }
36
37 protected:
38 HRESULT LoadFunctionNames()
39 {
40 ATLASSERT(m_pTypeInfo == NULL);
41
42 HRESULT hr;
43 CComPtr<ITypeLib> pTypeLib;
44 TYPEATTR *pta;
45
46 hr = LoadRegTypeLib(*m_plibid, m_wMajorVer, m_wMinorVer, m_lcid,
47 &pTypeLib);
48 if(FAILED(hr))
49 return hr;
50 hr = pTypeLib->GetTypeInfoOfGuid(*m_piid, &m_pTypeInfo);
51 if(FAILED(hr))
52 return hr;
53 hr = m_pTypeInfo->GetTypeAttr(&pta);
54 if(FAILED(hr))
55 return hr;
56
57 unsigned short i;
58 for(i = 0; i < pta->cFuncs; i++)
59 {
60 BSTR bsName;
61 FUNCDESC *pfd;
62 unsigned int uiNames = 0;
63
64 hr = m_pTypeInfo->GetFuncDesc(i, &pfd);
65 if(FAILED(hr))
66 continue;
67
68 hr = m_pTypeInfo->GetNames(pfd->memid, &bsName, 1, &uiNames);
69 if(SUCCEEDED(hr) && bsName && SysStringLen(bsName))
70 {
71 m_mapDispId.Add(pfd->memid, bsName);
72 }
73
74 m_pTypeInfo->ReleaseFuncDesc(pfd);
75
76 }
77 m_pTypeInfo->ReleaseTypeAttr(pta);
78
79 return hr;
80 }
81 };
82
83 class CConnectedObject :
84 public IDispatch
85 {
86 public:
87 CConnectedObject(CDispExSinkConnector *pMain, CTypeInfoHolder *ptih,
88 IUnknown *pUnkCP) :
89 m_dwCookie(0xFEFEFEFE), m_pUnkCP(pUnkCP), m_pMain(pMain),
90 m_pTIH(ptih)
91 {
92 m_pUnkCP->AddRef();
93 AtlAdvise(m_pUnkCP, this, *m_pTIH->m_piid, &m_dwCookie);
94 }
95 ~CConnectedObject()
96 {
97 Shutdown();
98
99 if(m_pTIH)
100 {
101 delete m_pTIH;
102 m_pTIH = NULL;
103 }
104 }
105
106
107 void Shutdown()
108 {
109 if(m_pUnkCP && m_dwCookie != 0xFEFEFEFE)
110 {
111 AtlUnadvise(m_pUnkCP, *m_pTIH->m_piid, m_dwCookie);
112 m_pUnkCP->Release();
113
114 m_pUnkCP = NULL;
115 m_dwCookie = 0xFEFEFEFE;
116 }
117 }
118
119
120 ULONG WINAPI AddRef() { return 1; }
121 ULONG WINAPI Release() { return 1; }
122
123 HRESULT WINAPI QueryInterface(REFIID riid, void **ppv)
124 {
125 if(::InlineIsEqualGUID(riid, *m_pTIH->m_piid))
126 {
127 *ppv = this;
128 return S_OK;
129 }
130
131 *ppv = NULL;
132 return E_NOINTERFACE;
133 }
134
135
136 STDMETHODIMP GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
137 { return E_NOTIMPL; }
138 STDMETHODIMP GetTypeInfoCount(UINT *pctinfo)
139 { return E_NOTIMPL; }
140 STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
141 { return E_NOTIMPL; }
142 STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags,
143 DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
144 {
145 HRESULT hr;
146 CComPtr<IDispatchEx> pDispEx;
147 BOOL bEnabled;
148
149 if(m_pMain == NULL)
150 return S_OK;
151
152 bEnabled = m_pMain->GetEnabled();
153 m_pMain->GetDispEx(&pDispEx);
154
155 if(bEnabled == FALSE)
156 return S_OK;
157
158
159 if(pDispEx == NULL)
160 {
161 ATLTRACE(_T("No IDispatchEx pointer set\r\n"));
162 return S_OK;
163 }
164
165
166 BSTR bsMember = NULL;
167 CComBSTR bstrFunction;
168 bstrFunction += m_bstrPrefix;
169
170 bsMember = m_pTIH->m_mapDispId.Lookup(dispIdMember);
171 if(!bsMember || SysStringLen(bsMember) == 0)
172 {
173 ATLTRACE(_T("Could not find DISPID in lookup table\r\n"));
174 return S_OK;
175 }
176
177 bstrFunction += bsMember;
178
179
180 DISPID dispIdEx;
181 hr = pDispEx->GetDispID(bstrFunction,
182 fdexNameCaseSensitive, &dispIdEx);
183 if(FAILED(hr))
184 {
185 USES_CONVERSION;
186 ATLTRACE(_T("Could not find matching function '%s' in IDispatchEx\r\n"),
187 OLE2T(bstrFunction));
188 return S_OK;
189 }
190
191
192 pDispEx->InvokeEx(dispIdEx, lcid, DISPATCH_METHOD,
193 pDispParams, pVarResult, pExcepInfo, NULL);
194
195 return S_OK;
196 }
197
198 DWORD m_dwCookie;
199 CTypeInfoHolder *m_pTIH;
200 IUnknown *m_pUnkCP;
201 CComBSTR m_bstrPrefix;
202 CDispExSinkConnector *m_pMain;
203 };
204
205 public:
206
207 CDispExSinkConnector() : m_bEnabled(TRUE), m_dwRefCount(0), m_pDispEx(NULL)
208 {
209 ATLTRACE(_T("CDispExSinkConnector::CDispExSinkConnector()\n"));
210 }
211
212 virtual ~CDispExSinkConnector()
213 {
214 ATLTRACE(_T("CDispExSinkConnector::~CDispExSinkConnector()\n"));
215 Shutdown();
216 }
217
218
219 STDMETHOD(QueryInterface)(REFIID iid, void **ppvObject)
220 { return S_OK; }
221 ULONG STDMETHODCALLTYPE AddRef()
222 { return ++m_dwRefCount; }
223 ULONG STDMETHODCALLTYPE Release()
224 {
225 if(--m_dwRefCount == 0)
226 {
227 delete this;
228 return 0;
229 }
230
231 return m_dwRefCount;
232 }
233
234
235 STDMETHOD(GetTypeInfoCount)(UINT *pctinfo)
236 { return E_NOTIMPL; }
237
238 STDMETHOD(GetTypeInfo)(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
239 { return E_NOTIMPL; }
240
241 STDMETHOD(GetIDsOfNames)(REFIID riid, OLECHAR **rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
242 { return E_NOTIMPL; }
243
244 STDMETHOD(Invoke)(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
245 { return E_NOTIMPL; }
246
247
248 HRESULT ConnectObject(IUnknown *pUnk, BSTR bstrPrefix, const GUID *piid, const GUID *plibid, WORD wMajorVer = 1, WORD wMinorVer = 0, LCID lcid = 1033)
249 {
250
251 if(!pUnk || !bstrPrefix || SysStringLen(bstrPrefix) == 0 ||
252 piid == NULL || plibid == NULL)
253 return E_INVALIDARG;
254
255 CTypeInfoHolder *ptih = new CTypeInfoHolder(piid, plibid, wMajorVer,
256 wMinorVer, lcid);
257 if(ptih == NULL)
258 return E_OUTOFMEMORY;
259
260 HRESULT hr = S_OK;
261 CConnectedObject *pObj = new CConnectedObject(this, ptih, pUnk);
262 if(pObj == NULL)
263 return E_OUTOFMEMORY;
264
265
266 pObj->m_bstrPrefix = bstrPrefix;
267 m_arrObjects.Add(pObj);
268
269 return hr;
270 }
271
272 HRESULT DisconnectObject(IUnknown *pUnk, const GUID *piid)
273 {
274 for(int i = 0; i < m_arrObjects.GetSize(); i++)
275 {
276 if(pUnk == m_arrObjects[i]->m_pUnkCP &&
277 m_arrObjects[i]->m_pTIH &&
278 ::InlineIsEqualGUID(*m_arrObjects[i]->m_pTIH->m_piid, *piid))
279 {
280 CConnectedObject *pObj = m_arrObjects[i];
281 m_arrObjects.RemoveAt(i);
282 delete pObj;
283 return S_OK;
284 }
285 }
286
287 return E_INVALIDARG;
288 }
289
290 HRESULT AddNamedObject(BSTR bsName, IDispatch *pDisp)
291 {
292 HRESULT hr;
293
294 if(m_pDispEx == NULL)
295 return E_FAIL;
296
297 if(!bsName || SysStringLen(bsName) == 0 || !pDisp)
298 return E_INVALIDARG;
299
300
301 DISPID dispIdThis = 0;
302 hr = m_pDispEx->GetDispID(bsName, fdexNameEnsure | fdexNameCaseSensitive,
303 &dispIdThis);
304 if(SUCCEEDED(hr) && dispIdThis != 0)
305 {
306
307 DISPID dispIdPut = DISPID_PROPERTYPUT;
308 DISPPARAMS params;
309 VARIANTARG vtArg;
310 EXCEPINFO ei;
311 ZeroMemory(¶ms, sizeof(DISPPARAMS));
312
313 VariantInit(&vtArg);
314 vtArg.vt = VT_DISPATCH;
315 vtArg.pdispVal = pDisp;
316
317 params.cArgs = 1;
318 params.rgvarg = &vtArg;
319 params.cNamedArgs = 1;
320 params.rgdispidNamedArgs = &dispIdPut;
321
322 pDisp->AddRef();
323
324 hr = m_pDispEx->InvokeEx(dispIdThis, LOCALE_USER_DEFAULT,
325 DISPATCH_PROPERTYPUT, ¶ms, NULL, &ei, NULL);
326
327 VariantClear(&vtArg);
328 }
329
330 return hr;
331 }
332
333 HRESULT RemoveNamedObject(BSTR bsName)
334 {
335 if(m_pDispEx == NULL)
336 return E_FAIL;
337
338 if(!bsName || SysStringLen(bsName) == 0)
339 return E_INVALIDARG;
340
341 return m_pDispEx->DeleteMemberByName(bsName, fdexNameCaseSensitive);
342 }
343
344 HRESULT AddTypeLib(REFGUID guidTypeLib, WORD wMaj, WORD wMin)
345 {
346 HRESULT hr;
347 CComPtr<ITypeLib> pTypeLib;
348 UINT uiCount, i;
349
350 if(m_pDispEx == NULL)
351 return E_FAIL;
352
353 hr = LoadRegTypeLib(guidTypeLib, wMaj, wMin, 0x407, &pTypeLib);
354 if(FAILED(hr))
355 return hr;
356
357 uiCount = pTypeLib->GetTypeInfoCount();
358 for(i = 0; i < uiCount; i++)
359 {
360 USES_CONVERSION;
361 CComPtr<ITypeInfo> pTypeInfo;
362 TYPEKIND tk;
363 TYPEATTR *pta;
364
365
366 hr = pTypeLib->GetTypeInfoType(i, &tk);
367 if(tk != TKIND_ENUM || FAILED(hr))
368 continue;
369
370 hr = pTypeLib->GetTypeInfo(i, &pTypeInfo);
371 if(FAILED(hr))
372 return hr;
373
374 hr = pTypeInfo->GetTypeAttr(&pta);
375 if(FAILED(hr))
376 return hr;
377
378 for(UINT j = 0; j < pta->cVars; j++)
379 {
380 CComBSTR bstrName;
381 VARDESC *pvd;
382
383 hr = pTypeInfo->GetVarDesc(j, &pvd);
384 if(FAILED(hr))
385 return hr;
386
387
388 hr = pTypeInfo->GetDocumentation(pvd->memid, &bstrName, NULL,
389 NULL, NULL);
390
391 if(bstrName.Length())
392 {
393
394 DISPID dispIdThis = DISPID_UNKNOWN;
395 hr = m_pDispEx->GetDispID(bstrName, fdexNameEnsure | fdexNameCaseSensitive,
396 &dispIdThis);
397 if(SUCCEEDED(hr) && dispIdThis != DISPID_UNKNOWN)
398 {
399
400 DISPID dispIdPut = DISPID_PROPERTYPUT;
401 DISPPARAMS params;
402 VARIANTARG vtArg;
403 EXCEPINFO ei;
404 ZeroMemory(¶ms, sizeof(DISPPARAMS));
405
406 VariantInit(&vtArg);
407 vtArg.vt = VT_I4;
408 vtArg.lVal = pvd->lpvarValue->lVal;
409
410 params.cArgs = 1;
411 params.rgvarg = &vtArg;
412 params.cNamedArgs = 1;
413 params.rgdispidNamedArgs = &dispIdPut;
414
415
416 hr = m_pDispEx->InvokeEx(dispIdThis, LOCALE_USER_DEFAULT,
417 DISPATCH_PROPERTYPUT, ¶ms, NULL, &ei, NULL);
418 }
419 }
420
421 pTypeInfo->ReleaseVarDesc(pvd);
422 }
423
424 pTypeInfo->ReleaseTypeAttr(pta);
425 }
426
427 return S_OK;
428 }
429
430 void Shutdown()
431 {
432 for(int i = 0; i < m_arrObjects.GetSize(); i++)
433 delete m_arrObjects[i];
434
435 m_arrObjects.RemoveAll();
436 }
437
438 void SetEnabled(BOOL bEnabled) { m_bEnabled = bEnabled; }
439 BOOL GetEnabled() { return m_bEnabled; }
440
441 void SetDispEx(IDispatchEx *pDispEx)
442 {
443 CComBSTR bstrThisGuid("AC0B188C-6B55-408f-9E8C-821B9B5467CB");
444
445 RemoveNamedObject(bstrThisGuid);
446
447
448
449 m_pDispEx = pDispEx;
450
451
452 AddNamedObject(bstrThisGuid, this);
453 }
454 BOOL GetDispEx(IDispatchEx **ppDispEx)
455 {
456 if(!ppDispEx)
457 return FALSE;
458
459 *ppDispEx = NULL;
460 if(m_pDispEx)
461 {
462 *ppDispEx = m_pDispEx;
463 (*ppDispEx)->AddRef();
464 }
465
466 return TRUE;
467 }
468
469 protected:
470 DWORD m_dwRefCount;
471
472 BOOL m_bEnabled;
473 IDispatchEx *m_pDispEx;
474 CSimpleArray<CConnectedObject*> m_arrObjects;
475 };
476
477 #endif