Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1685 lines
53 KiB

  1. /******************************************************************************
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. MPC_COM.h
  5. Abstract:
  6. This file contains the declaration of various classes and macros to deal with COM.
  7. Revision History:
  8. Davide Massarenti (Dmassare) 06/18/99
  9. created
  10. ******************************************************************************/
  11. #if !defined(__INCLUDED___MPC___COM_H___)
  12. #define __INCLUDED___MPC___COM_H___
  13. #include <atlbase.h>
  14. #include <atlcom.h>
  15. #include <dispex.h>
  16. #include <MPC_trace.h>
  17. #include <MPC_main.h>
  18. #include <process.h>
  19. ////////////////////////////////////////////////////////////////////////////////
  20. #define MPC_FORWARD_CALL_0(obj,method) return obj ? obj->method() : E_HANDLE
  21. #define MPC_FORWARD_CALL_1(obj,method,a1) return obj ? obj->method(a1) : E_HANDLE
  22. #define MPC_FORWARD_CALL_2(obj,method,a1,a2) return obj ? obj->method(a1,a2) : E_HANDLE
  23. #define MPC_FORWARD_CALL_3(obj,method,a1,a2,a3) return obj ? obj->method(a1,a2,a3) : E_HANDLE
  24. #define MPC_FORWARD_CALL_4(obj,method,a1,a2,a3,a4) return obj ? obj->method(a1,a2,a3,a4) : E_HANDLE
  25. #define MPC_FORWARD_CALL_5(obj,method,a1,a2,a3,a4,a5) return obj ? obj->method(a1,a2,a3,a4,a5) : E_HANDLE
  26. #define MPC_FORWARD_CALL_6(obj,method,a1,a2,a3,a4,a5,a6) return obj ? obj->method(a1,a2,a3,a4,a5,a6) : E_HANDLE
  27. #define MPC_FORWARD_CALL_7(obj,method,a1,a2,a3,a4,a5,a6,a7) return obj ? obj->method(a1,a2,a3,a4,a5,a6,a7) : E_HANDLE
  28. #define MPC_FORWARD_CALL_8(obj,method,a1,a2,a3,a4,a5,a6,a7,a8) return obj ? obj->method(a1,a2,a3,a4,a5,a6,a7,a8) : E_HANDLE
  29. /////////////////////////////////////////////////////////////////////////////
  30. #define MPC_SCRIPTHELPER_FAIL_IF_NOT_AN_OBJECT(var) \
  31. if(((var).vt != VT_UNKNOWN && (var).vt != VT_DISPATCH) || \
  32. ((var).vt == VT_UNKNOWN && (var).punkVal == NULL ) || \
  33. ((var).vt == VT_DISPATCH && (var).pdispVal == NULL ) ) __MPC_SET_ERROR_AND_EXIT(hr, E_INVALIDARG)
  34. #define MPC_SCRIPTHELPER_GET__DIRECT(dst,obj,prop) \
  35. { \
  36. __MPC_EXIT_IF_METHOD_FAILS(hr, obj->get_##prop( &(dst) )); \
  37. }
  38. #define MPC_SCRIPTHELPER_GET__DIRECT__NOTNULL(dst,obj,prop) \
  39. { \
  40. MPC_SCRIPTHELPER_GET__DIRECT(dst,obj,prop); \
  41. if((dst) == NULL) __MPC_SET_ERROR_AND_EXIT(hr, E_NOINTERFACE); \
  42. }
  43. ////////////////////
  44. #define MPC_SCRIPTHELPER_GET_OBJECT(dst,obj,prop) \
  45. { \
  46. CComPtr<IDispatch> __disp; \
  47. \
  48. MPC_SCRIPTHELPER_GET__DIRECT(__disp,obj,prop); \
  49. if(__disp) \
  50. { \
  51. __MPC_EXIT_IF_METHOD_FAILS(hr, __disp->QueryInterface( __uuidof(dst), (LPVOID*)&(dst) )); \
  52. } \
  53. }
  54. #define MPC_SCRIPTHELPER_GET_OBJECT__NOTNULL(dst,obj,prop) \
  55. { \
  56. MPC_SCRIPTHELPER_GET_OBJECT(dst,obj,prop); \
  57. if((dst) == NULL) __MPC_SET_ERROR_AND_EXIT(hr, E_NOINTERFACE); \
  58. }
  59. ////////////////////
  60. #define MPC_SCRIPTHELPER_GET_OBJECT__VARIANT(dst,obj,prop) \
  61. { \
  62. CComVariant __v; \
  63. \
  64. MPC_SCRIPTHELPER_GET__DIRECT(__v,obj,prop); \
  65. \
  66. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::COMUtil::VarToInterface( __v, __uuidof(dst), (IUnknown **)&(dst) )); \
  67. }
  68. #define MPC_SCRIPTHELPER_GET_STRING__VARIANT(dst,obj,prop) \
  69. { \
  70. CComVariant __v; \
  71. \
  72. MPC_SCRIPTHELPER_GET__DIRECT(__v,obj,prop); \
  73. \
  74. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::COMUtil::VarToBSTR( __v, dst )); \
  75. }
  76. ////////////////////
  77. #define MPC_SCRIPTHELPER_GET_PROPERTY(dst,obj,prop) \
  78. { \
  79. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::COMUtil::GetPropertyByName( obj, L#prop, dst )); \
  80. }
  81. #define MPC_SCRIPTHELPER_GET_PROPERTY__BSTR(dst,obj,prop) \
  82. { \
  83. CComVariant __v; \
  84. \
  85. MPC_SCRIPTHELPER_GET_PROPERTY(__v,obj,prop); \
  86. \
  87. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::COMUtil::VarToBSTR( __v, dst )); \
  88. }
  89. ////////////////////
  90. #define MPC_SCRIPTHELPER_GET_COLLECTIONITEM(dst,obj,item) \
  91. { \
  92. CComVariant __v; \
  93. \
  94. __MPC_EXIT_IF_METHOD_FAILS(hr, obj->get_Item( item, &__v )); \
  95. \
  96. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::COMUtil::VarToInterface( __v, __uuidof(dst), (IUnknown **)&(dst) )); \
  97. if((dst) == NULL) __MPC_SET_ERROR_AND_EXIT(hr, E_NOINTERFACE); \
  98. }
  99. ////////////////////
  100. #define MPC_SCRIPTHELPER_PUT__DIRECT(obj,prop,val) \
  101. { \
  102. __MPC_EXIT_IF_METHOD_FAILS(hr, obj->put_##prop( val )); \
  103. }
  104. #define MPC_SCRIPTHELPER_PUT__VARIANT(obj,prop,val) \
  105. { \
  106. CComVariant v(val); \
  107. \
  108. MPC_SCRIPTHELPER_PUT__DIRECT(obj,prop,v); \
  109. }
  110. ////////////////////////////////////////////////////////////////////////////////
  111. #ifndef _ATL_DLL_IMPL
  112. namespace ATL
  113. {
  114. #endif
  115. #ifndef _ATL_DLL_IMPL
  116. }; //namespace ATL
  117. #endif
  118. ////////////////////////////////////////////////////////////////////////////////
  119. namespace MPC
  120. {
  121. class MPCMODULE;
  122. extern MPCMODULE _MPC_Module;
  123. /////////////////////////////////////////////////////////////////////////////
  124. namespace COMUtil
  125. {
  126. HRESULT GetPropertyByName( /*[in]*/ IDispatch* obj, /*[in]*/ LPCWSTR szName , /*[out]*/ CComVariant& v );
  127. HRESULT GetPropertyByName( /*[in]*/ IDispatch* obj, /*[in]*/ LPCWSTR szName , /*[out]*/ CComBSTR& bstr );
  128. HRESULT GetPropertyByName( /*[in]*/ IDispatch* obj, /*[in]*/ LPCWSTR szName , /*[out]*/ bool& fValue );
  129. HRESULT GetPropertyByName( /*[in]*/ IDispatch* obj, /*[in]*/ LPCWSTR szName , /*[out]*/ long& lValue );
  130. HRESULT VarToBSTR ( /*[in]*/ CComVariant& v, /*[out]*/ CComBSTR& str );
  131. HRESULT VarToInterface( /*[in]*/ CComVariant& v, /*[in]*/ const IID& iid, /*[out]*/ IUnknown* *obj );
  132. template <class Base, class Itf> HRESULT CopyInterface( Base* src, Itf* *dst )
  133. {
  134. if(!dst) return E_POINTER;
  135. if(src)
  136. {
  137. return src->QueryInterface( __uuidof(*dst), (void**)dst );
  138. }
  139. *dst = NULL;
  140. return S_FALSE;
  141. }
  142. };
  143. /////////////////////////////////////////////////////////////////////////////
  144. HRESULT SafeInitializeCriticalSection( /*[in/out]*/ CRITICAL_SECTION& sec );
  145. HRESULT SafeDeleteCriticalSection ( /*[in/out]*/ CRITICAL_SECTION& sec );
  146. class CComSafeAutoCriticalSection
  147. {
  148. public:
  149. CComSafeAutoCriticalSection ();
  150. ~CComSafeAutoCriticalSection();
  151. void Lock ();
  152. void Unlock();
  153. CRITICAL_SECTION m_sec;
  154. };
  155. class CComSafeMultiThreadModel
  156. {
  157. public:
  158. static ULONG WINAPI Increment(LPLONG p) { return InterlockedIncrement( p ); }
  159. static ULONG WINAPI Decrement(LPLONG p) { return InterlockedDecrement( p ); }
  160. typedef MPC::CComSafeAutoCriticalSection AutoCriticalSection;
  161. typedef CComCriticalSection CriticalSection;
  162. typedef CComMultiThreadModelNoCS ThreadModelNoCS;
  163. };
  164. /////////////////////////////////////////////////////////////////////////////
  165. //
  166. // Same as ATL::CComObjectCached, but with CreateInstance and no critical section.
  167. //
  168. // Base is the user's class that derives from CComObjectRoot and whatever
  169. // interfaces the user wants to support on the object
  170. // CComObjectCached is used primarily for class factories in DLL's
  171. // but it is useful anytime you want to cache an object
  172. template <class Base> class CComObjectCached : public Base
  173. {
  174. public:
  175. typedef Base _BaseClass;
  176. CComObjectCached(void* = NULL)
  177. {
  178. }
  179. // Set refcount to 1 to protect destruction
  180. ~CComObjectCached()
  181. {
  182. m_dwRef = 1L;
  183. FinalRelease();
  184. }
  185. //If InternalAddRef or InternalRelease is undefined then your class
  186. //doesn't derive from CComObjectRoot
  187. STDMETHOD_(ULONG, AddRef)()
  188. {
  189. ULONG l = InternalAddRef();
  190. if(l == 2) _Module.Lock();
  191. return l;
  192. }
  193. STDMETHOD_(ULONG, Release)()
  194. {
  195. ULONG l = InternalRelease();
  196. if (l == 0) delete this;
  197. else if(l == 1) _Module.Unlock();
  198. return l;
  199. }
  200. //if _InternalQueryInterface is undefined then you forgot BEGIN_COM_MAP
  201. STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject) { return _InternalQueryInterface(iid, ppvObject); }
  202. template <class Q> HRESULT STDMETHODCALLTYPE QueryInterface(Q** pp) { return QueryInterface(__uuidof(Q), (void**)pp); }
  203. static HRESULT WINAPI CreateInstance( CComObjectCached<Base>** pp )
  204. {
  205. ATLASSERT(pp != NULL);
  206. HRESULT hRes = E_OUTOFMEMORY;
  207. CComObjectCached<Base>* p = NULL;
  208. ATLTRY(p = new CComObjectCached<Base>())
  209. if(p != NULL)
  210. {
  211. p->SetVoid(NULL);
  212. p->InternalFinalConstructAddRef();
  213. hRes = p->FinalConstruct();
  214. p->InternalFinalConstructRelease();
  215. if(hRes != S_OK)
  216. {
  217. delete p;
  218. p = NULL;
  219. }
  220. }
  221. *pp = p;
  222. return hRes;
  223. }
  224. };
  225. //
  226. // Same as ATL::CComObjectNoLock, but with CreateInstance.
  227. //
  228. template <class Base> class CComObjectNoLock : public Base
  229. {
  230. public:
  231. typedef Base _BaseClass;
  232. CComObjectNoLock(void* = NULL)
  233. {
  234. }
  235. // Set refcount to 1 to protect destruction
  236. ~CComObjectNoLock()
  237. {
  238. m_dwRef = 1L;
  239. FinalRelease();
  240. }
  241. //If InternalAddRef or InternalRelease is undefined then your class
  242. //doesn't derive from CComObjectRoot
  243. STDMETHOD_(ULONG, AddRef)()
  244. {
  245. return InternalAddRef();
  246. }
  247. STDMETHOD_(ULONG, Release)()
  248. {
  249. ULONG l = InternalRelease();
  250. if(l == 0) delete this;
  251. return l;
  252. }
  253. //if _InternalQueryInterface is undefined then you forgot BEGIN_COM_MAP
  254. STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject) { return _InternalQueryInterface(iid, ppvObject); }
  255. template <class Q> HRESULT STDMETHODCALLTYPE QueryInterface(Q** pp) { return QueryInterface(__uuidof(Q), (void**)pp); }
  256. static HRESULT WINAPI CreateInstance( CComObjectNoLock<Base>** pp )
  257. {
  258. ATLASSERT(pp != NULL);
  259. HRESULT hRes = E_OUTOFMEMORY;
  260. CComObjectNoLock<Base>* p = NULL;
  261. ATLTRY(p = new CComObjectNoLock<Base>())
  262. if(p != NULL)
  263. {
  264. p->SetVoid(NULL);
  265. p->InternalFinalConstructAddRef();
  266. hRes = p->FinalConstruct();
  267. p->InternalFinalConstructRelease();
  268. if(hRes != S_OK)
  269. {
  270. delete p;
  271. p = NULL;
  272. }
  273. }
  274. *pp = p;
  275. return hRes;
  276. }
  277. };
  278. //
  279. // Same as ATL::CComObjectGlobal, but with no module locking.
  280. //
  281. template <class Base> class CComObjectGlobalNoLock : public Base
  282. {
  283. public:
  284. typedef Base _BaseClass;
  285. CComObjectGlobalNoLock(void* = NULL)
  286. {
  287. m_hResFinalConstruct = FinalConstruct();
  288. }
  289. ~CComObjectGlobalNoLock()
  290. {
  291. FinalRelease();
  292. }
  293. STDMETHOD_(ULONG, AddRef)() { return 2; }
  294. STDMETHOD_(ULONG, Release)() { return 1; }
  295. STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
  296. {
  297. return _InternalQueryInterface(iid, ppvObject);
  298. }
  299. HRESULT m_hResFinalConstruct;
  300. };
  301. ////////////////////////////////////////////////////////////////////////////////
  302. interface CComObjectRootParentBase : IUnknown
  303. {
  304. virtual ULONG STDMETHODCALLTYPE WeakAddRef (void) = 0;
  305. virtual ULONG STDMETHODCALLTYPE WeakRelease(void) = 0;
  306. void Passivate()
  307. {
  308. }
  309. template <class C, class P> HRESULT CreateChild( P* pParent, C* *pVal )
  310. {
  311. C* obj;
  312. HRESULT hr;
  313. *pVal = NULL;
  314. if(SUCCEEDED(hr = obj->CreateInstance( &obj )))
  315. {
  316. obj->AddRef();
  317. obj->Child_LinkToParent( pParent );
  318. *pVal = obj;
  319. }
  320. return hr;
  321. }
  322. };
  323. template <class ThreadModel, class T> class CComObjectRootChildEx : public CComObjectRootEx<ThreadModel>
  324. {
  325. private:
  326. T* m_Child_pParent;
  327. void Child_UnlinkParent()
  328. {
  329. Lock();
  330. if(m_Child_pParent)
  331. {
  332. m_Child_pParent->WeakRelease();
  333. m_Child_pParent = NULL;
  334. }
  335. Unlock();
  336. }
  337. public:
  338. CComObjectRootChildEx() : m_Child_pParent(NULL) {}
  339. virtual ~CComObjectRootChildEx()
  340. {
  341. Child_UnlinkParent();
  342. }
  343. void Child_LinkToParent( T* pParent )
  344. {
  345. Lock();
  346. Child_UnlinkParent();
  347. if((m_Child_pParent = pParent))
  348. {
  349. m_Child_pParent->WeakAddRef();
  350. }
  351. Unlock();
  352. }
  353. void Child_GetParent( T* *ppParent )
  354. {
  355. Lock();
  356. if((*ppParent = m_Child_pParent))
  357. {
  358. m_Child_pParent->AddRef();
  359. }
  360. Unlock();
  361. }
  362. };
  363. template <class Base> class CComObjectParent : public Base
  364. {
  365. public:
  366. typedef Base _BaseClass;
  367. CComObjectParent(void* = NULL)
  368. {
  369. m_dwRefWeak = 0L;
  370. ::_Module.Lock();
  371. }
  372. // Set refcount to 1 to protect destruction
  373. ~CComObjectParent()
  374. {
  375. m_dwRef = 1L;
  376. FinalRelease();
  377. ::_Module.Unlock();
  378. }
  379. STDMETHOD_(ULONG, AddRef)()
  380. {
  381. ULONG l;
  382. Lock();
  383. l = ++m_dwRef;
  384. Unlock();
  385. return l;
  386. }
  387. STDMETHOD_(ULONG, Release)()
  388. {
  389. ULONG l;
  390. bool readytodelete = false;
  391. Lock();
  392. l = --m_dwRef;
  393. if(l == 0)
  394. {
  395. m_dwRef += 2; // Protect ourself during the "Passivate" process.
  396. Unlock();
  397. Passivate();
  398. Lock();
  399. m_dwRef -= 2;
  400. if(m_dwRefWeak == 0)
  401. {
  402. readytodelete = true;
  403. }
  404. }
  405. Unlock();
  406. if(readytodelete)
  407. {
  408. delete this;
  409. }
  410. return l;
  411. }
  412. //if _InternalQueryInterface is undefined then you forgot BEGIN_COM_MAP
  413. STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
  414. {
  415. return _InternalQueryInterface(iid, ppvObject);
  416. }
  417. STDMETHOD_(ULONG, WeakAddRef)()
  418. {
  419. ULONG l;
  420. Lock();
  421. l = ++m_dwRefWeak;
  422. Unlock();
  423. return l;
  424. }
  425. STDMETHOD_(ULONG, WeakRelease)()
  426. {
  427. ULONG l;
  428. bool readytodelete = false;
  429. Lock();
  430. l = --m_dwRefWeak;
  431. if(m_dwRef == 0)
  432. {
  433. if(m_dwRefWeak == 0)
  434. {
  435. readytodelete = true;
  436. }
  437. }
  438. Unlock();
  439. if(readytodelete)
  440. {
  441. delete this;
  442. }
  443. return l;
  444. }
  445. static HRESULT WINAPI CreateInstance( CComObjectParent<Base>** pp );
  446. ULONG m_dwRefWeak;
  447. };
  448. template <class Base> HRESULT WINAPI CComObjectParent<Base>::CreateInstance( CComObjectParent<Base>** pp )
  449. {
  450. ATLASSERT(pp != NULL);
  451. HRESULT hRes = E_OUTOFMEMORY;
  452. CComObjectParent<Base>* p = NULL;
  453. ATLTRY(p = new CComObjectParent<Base>())
  454. if(p != NULL)
  455. {
  456. p->SetVoid(NULL);
  457. p->InternalFinalConstructAddRef();
  458. hRes = p->FinalConstruct();
  459. p->InternalFinalConstructRelease();
  460. if(hRes != S_OK)
  461. {
  462. delete p;
  463. p = NULL;
  464. }
  465. }
  466. *pp = p;
  467. return hRes;
  468. }
  469. template <class T, const CLSID* pclsid = &CLSID_NULL> class CComParentCoClass : public CComCoClass<T, pclsid>
  470. {
  471. public:
  472. typedef CComCreator2< CComCreator< MPC::CComObjectParent< T > >, CComFailCreator<CLASS_E_NOAGGREGATION> > _CreatorClass;
  473. };
  474. /////////////////////////////////////////////////////////////////////////////
  475. //
  476. // Smart Lock class, so that locks on ATL objects can be easily acquired and released.
  477. //
  478. template <class ThreadModel> class SmartLock
  479. {
  480. CComObjectRootEx<ThreadModel>* m_p;
  481. SmartLock( const SmartLock& );
  482. public:
  483. SmartLock(CComObjectRootEx<ThreadModel>* p) : m_p(p)
  484. {
  485. if(p) p->Lock();
  486. }
  487. ~SmartLock()
  488. {
  489. if(m_p) m_p->Unlock();
  490. }
  491. SmartLock& operator=( /*[in]*/ CComObjectRootEx<ThreadModel>* p )
  492. {
  493. if(m_p) m_p->Unlock();
  494. if(p ) p ->Lock ();
  495. m_p = p;
  496. return *this;
  497. }
  498. };
  499. //
  500. // Smart Lock class, works with every class exposing 'Lock' and 'Unlock'.
  501. //
  502. template <class T> class SmartLockGeneric
  503. {
  504. T* m_p;
  505. SmartLockGeneric( const SmartLockGeneric& );
  506. public:
  507. SmartLockGeneric( T* p ) : m_p(p)
  508. {
  509. if(p) p->Lock();
  510. }
  511. ~SmartLockGeneric()
  512. {
  513. if(m_p) m_p->Unlock();
  514. }
  515. SmartLockGeneric& operator=( /*[in]*/ T* p )
  516. {
  517. if(m_p) m_p->Unlock();
  518. if(p ) p ->Lock ();
  519. m_p = p;
  520. return *this;
  521. }
  522. };
  523. /////////////////////////////////////////////////////////////////////////////
  524. //
  525. // Class used to act as an hub for all the instances of CComPtrThreadNeutral<T>.
  526. // It holds the Global Interface Table.
  527. //
  528. class CComPtrThreadNeutral_GIT
  529. {
  530. IGlobalInterfaceTable* m_pGIT;
  531. CRITICAL_SECTION m_sec;
  532. void Lock ();
  533. void Unlock();
  534. HRESULT GetGIT( IGlobalInterfaceTable* *ppGIT );
  535. public:
  536. CComPtrThreadNeutral_GIT();
  537. ~CComPtrThreadNeutral_GIT();
  538. HRESULT Init();
  539. HRESULT Term();
  540. HRESULT RegisterInterface( /*[in]*/ IUnknown* pUnk, /*[in]*/ REFIID riid, /*[out]*/ DWORD *pdwCookie );
  541. HRESULT RevokeInterface ( /*[in]*/ DWORD dwCookie );
  542. HRESULT GetInterface ( /*[in]*/ DWORD dwCookie, /*[in]*/ REFIID riid, /*[out]*/ void* *ppv );
  543. };
  544. //
  545. // This smart pointer template stores THREAD-INDEPEDENT pointers to COM objects.
  546. //
  547. // The best way to use it is to store an object reference into it and then assign
  548. // the object itself to a CComPtr<T>.
  549. //
  550. // This way the proper proxy is looked up and the smart pointer will keep it alive.
  551. //
  552. template <class T> class CComPtrThreadNeutral
  553. {
  554. private:
  555. DWORD m_dwCookie;
  556. void Inner_Register( T* lp )
  557. {
  558. if(lp && _MPC_Module.m_GITHolder)
  559. {
  560. _MPC_Module.m_GITHolder->RegisterInterface( lp, __uuidof(T), &m_dwCookie );
  561. }
  562. }
  563. public:
  564. typedef T _PtrClass;
  565. CComPtrThreadNeutral()
  566. {
  567. m_dwCookie = 0xFEFEFEFE;
  568. }
  569. CComPtrThreadNeutral( /*[in]*/ const CComPtrThreadNeutral<T>& t )
  570. {
  571. m_dwCookie = 0xFEFEFEFE;
  572. *this = t;
  573. }
  574. CComPtrThreadNeutral( T* lp )
  575. {
  576. m_dwCookie = 0xFEFEFEFE;
  577. Inner_Register( lp );
  578. }
  579. ~CComPtrThreadNeutral()
  580. {
  581. Release();
  582. }
  583. //////////////////////////////////////////////////////////////////////
  584. operator CComPtr<T>() const
  585. {
  586. CComPtr<T> res;
  587. (void)Access( &res );
  588. return res;
  589. }
  590. CComPtr<T> operator=( T* lp )
  591. {
  592. Release();
  593. Inner_Register( lp );
  594. return (CComPtr<T>)(*this);
  595. }
  596. CComPtrThreadNeutral& operator=( /*[in]*/ const CComPtrThreadNeutral<T>& t )
  597. {
  598. CComPtr<T> obj;
  599. Release();
  600. if(SUCCEEDED(t.Access( &obj )))
  601. {
  602. Inner_Register( obj );
  603. }
  604. return *this;
  605. }
  606. bool operator!() const
  607. {
  608. return (m_dwCookie == 0xFEFEFEFE);
  609. }
  610. //////////////////////////////////////////////////////////////////////
  611. void Release()
  612. {
  613. if(m_dwCookie != 0xFEFEFEFE)
  614. {
  615. _MPC_Module.m_GITHolder->RevokeInterface( m_dwCookie );
  616. m_dwCookie = 0xFEFEFEFE;
  617. }
  618. }
  619. void Attach( T* p )
  620. {
  621. *this = p;
  622. if(p) p->Release();
  623. }
  624. T* Detach()
  625. {
  626. T* pt;
  627. (void)Access( &pt );
  628. Release();
  629. return pt;
  630. }
  631. HRESULT Access( T* *ppt ) const
  632. {
  633. HRESULT hr;
  634. if(ppt == NULL)
  635. {
  636. hr = E_POINTER;
  637. }
  638. else
  639. {
  640. *ppt = NULL;
  641. if(m_dwCookie != 0xFEFEFEFE)
  642. {
  643. hr = _MPC_Module.m_GITHolder->GetInterface( m_dwCookie, __uuidof(T), (void**)ppt );
  644. }
  645. else
  646. {
  647. hr = S_FALSE;
  648. }
  649. }
  650. return hr;
  651. }
  652. };
  653. ////////////////////////////////////////////////////////////////////////////////
  654. template <class T, const IID* piid, const GUID* plibid>
  655. class ATL_NO_VTABLE IDispatchExImpl :
  656. public IDispatchImpl<T, piid, plibid>,
  657. public IDispatchEx
  658. {
  659. public:
  660. typedef IDispatchExImpl<T, piid, plibid> self;
  661. typedef IDispatchImpl<T, piid, plibid> super;
  662. //
  663. // IDispatch
  664. //
  665. STDMETHOD(GetTypeInfoCount)( UINT* pctinfo )
  666. {
  667. return super::GetTypeInfoCount( pctinfo );
  668. }
  669. STDMETHOD(GetTypeInfo)( UINT itinfo ,
  670. LCID lcid ,
  671. ITypeInfo* *pptinfo )
  672. {
  673. return super::GetTypeInfo( itinfo, lcid, pptinfo );
  674. }
  675. STDMETHOD(GetIDsOfNames)( REFIID riid ,
  676. LPOLESTR* rgszNames ,
  677. UINT cNames ,
  678. LCID lcid ,
  679. DISPID* rgdispid )
  680. {
  681. return super::GetIDsOfNames( riid, rgszNames, cNames, lcid, rgdispid );
  682. }
  683. STDMETHOD(Invoke)( DISPID dispidMember ,
  684. REFIID riid ,
  685. LCID lcid ,
  686. WORD wFlags ,
  687. DISPPARAMS* pdispparams ,
  688. VARIANT* pvarResult ,
  689. EXCEPINFO* pexcepinfo ,
  690. UINT* puArgErr )
  691. {
  692. return super::Invoke( dispidMember, riid , lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr );
  693. }
  694. //
  695. // IDispatchEx
  696. //
  697. STDMETHOD(GetDispID)( /*[in] */ BSTR bstrName ,
  698. /*[in] */ DWORD grfdex ,
  699. /*[out]*/ DISPID *pid )
  700. {
  701. if(grfdex & fdexNameEnsure) return E_NOTIMPL;
  702. return GetIDsOfNames( IID_NULL, &bstrName, 1, 0, pid );
  703. }
  704. STDMETHOD(InvokeEx)( /*[in] */ DISPID id ,
  705. /*[in] */ LCID lcid ,
  706. /*[in] */ WORD wFlags ,
  707. /*[in] */ DISPPARAMS* pdp ,
  708. /*[out]*/ VARIANT* pvarRes ,
  709. /*[out]*/ EXCEPINFO* pei ,
  710. /*[in] */ IServiceProvider* pspCaller )
  711. {
  712. return Invoke( id, IID_NULL, lcid, wFlags, pdp, pvarRes, pei, NULL );
  713. }
  714. STDMETHOD(DeleteMemberByName)( /*[in]*/ BSTR bstrName ,
  715. /*[in]*/ DWORD grfdex )
  716. {
  717. return E_NOTIMPL;
  718. }
  719. STDMETHOD(DeleteMemberByDispID)( /*[in]*/ DISPID id )
  720. {
  721. return E_NOTIMPL;
  722. }
  723. STDMETHOD(GetMemberProperties)( /*[in] */ DISPID id ,
  724. /*[in] */ DWORD grfdexFetch ,
  725. /*[out]*/ DWORD *pgrfdex )
  726. {
  727. return E_NOTIMPL;
  728. }
  729. STDMETHOD(GetMemberName)( /*[in] */ DISPID id ,
  730. /*[out]*/ BSTR *pbstrName )
  731. {
  732. return E_NOTIMPL;
  733. }
  734. STDMETHOD(GetNextDispID)( /*[in] */ DWORD grfdex ,
  735. /*[in] */ DISPID id ,
  736. /*[out]*/ DISPID *pid )
  737. {
  738. return E_NOTIMPL;
  739. }
  740. STDMETHOD(GetNameSpaceParent)( /*[out]*/ IUnknown* *ppunk )
  741. {
  742. return E_NOTIMPL;
  743. }
  744. };
  745. class CComConstantHolder
  746. {
  747. typedef std::map<DISPID,CComVariant> MemberLookup;
  748. typedef MemberLookup::iterator MemberLookupIter;
  749. typedef MemberLookup::const_iterator MemberLookupIterConst;
  750. ////////////////////
  751. const GUID* m_plibid;
  752. WORD m_wMajor;
  753. WORD m_wMinor;
  754. CComPtr<ITypeLib> m_pTypeLib;
  755. MemberLookup m_const;
  756. HRESULT EnsureLoaded( /*[in]*/ LCID lcid );
  757. public:
  758. CComConstantHolder( /*[in]*/ const GUID* plibid ,
  759. /*[in]*/ WORD wMajor = 1 ,
  760. /*[in]*/ WORD wMinor = 0 );
  761. HRESULT GetIDsOfNames( /*[in]*/ LPOLESTR* rgszNames ,
  762. /*[in]*/ UINT cNames ,
  763. /*[in]*/ LCID lcid ,
  764. /*[out]*/ DISPID* rgdispid );
  765. HRESULT GetValue( /*[in]*/ DISPID dispidMember ,
  766. /*[in]*/ LCID lcid ,
  767. /*[out]*/ VARIANT* pvarResult );
  768. };
  769. /////////////////////////////////////////////////////////////////////////////
  770. //
  771. // Template used to manage work threads.
  772. // Class 'T' should implement a method like this: 'HRESULT <method>()'.
  773. //
  774. template <class T, class Itf, DWORD dwThreading = COINIT_MULTITHREADED> class Thread
  775. {
  776. public:
  777. typedef HRESULT (T::*THREAD_RUN)();
  778. private:
  779. CRITICAL_SECTION m_sec;
  780. T* m_SelfDirect;
  781. THREAD_RUN m_Callback;
  782. CComPtrThreadNeutral<Itf> m_Self; // The keep the object alive will the thread is running.
  783. HANDLE m_hThread; // The thread itself.
  784. bool m_fRunning; // If true the thread is still running.
  785. HANDLE m_hEvent; // Used to notify the worker thread.
  786. HANDLE m_hEventReverse; // Used to notify the main thread.
  787. bool m_fAbort; // Used to tell the thread to abort and exit.
  788. // Passed to _beginthreadex.
  789. static unsigned __stdcall Thread_Startup( /*[in]*/ void* pv )
  790. {
  791. __MPC_FUNC_ENTRY( COMMONID, "MPC::Thread::Thread_Startup" );
  792. HRESULT hRes = ::CoInitializeEx( NULL, dwThreading );
  793. Thread<T,Itf,dwThreading>* pThis = (Thread<T,Itf,dwThreading>*)pv;
  794. if(SUCCEEDED(hRes))
  795. {
  796. try
  797. {
  798. pThis->Thread_InnerRun();
  799. }
  800. catch(...)
  801. {
  802. pThis->Thread_Lock();
  803. pThis->m_fAbort = true;
  804. pThis->Thread_Unlock();
  805. }
  806. ::CoUninitialize();
  807. }
  808. pThis->Thread_Lock();
  809. pThis->m_fRunning = false;
  810. pThis->Thread_Unlock();
  811. __MPC_FUNC_EXIT(0);
  812. }
  813. //
  814. // The core loop that would keep calling 'Thread_Run' until:
  815. //
  816. // a) m_fAbort is set, and
  817. //
  818. // b) hr reports a success.
  819. //
  820. HRESULT Thread_InnerRun()
  821. {
  822. __MPC_FUNC_ENTRY( COMMONID, "MPC::Thread::Thread_InnerRun" );
  823. HRESULT hr = S_OK;
  824. Thread_Lock();
  825. if(m_SelfDirect && m_Callback)
  826. {
  827. while(m_fAbort == false && SUCCEEDED(hr))
  828. {
  829. Thread_Unlock(); // Always unlock before waiting for signal.
  830. (void)MPC::WaitForSingleObject( m_hEvent, INFINITE );
  831. Thread_Lock(); // Lock again.
  832. if(m_fAbort == false)
  833. {
  834. Thread_Unlock(); // Unlock while handling the request.
  835. hr = (m_SelfDirect->*m_Callback)();
  836. Thread_Lock(); // Lock again.
  837. }
  838. }
  839. }
  840. Thread_Release();
  841. Thread_Unlock();
  842. __MPC_FUNC_EXIT(hr);
  843. }
  844. void Thread_Lock () { ::EnterCriticalSection( &m_sec ); }
  845. void Thread_Unlock() { ::LeaveCriticalSection( &m_sec ); }
  846. protected:
  847. DWORD Thread_WaitForEvents( HANDLE hEvent, DWORD dwTimeout )
  848. {
  849. HANDLE hEvents[2] = { m_hEvent, hEvent };
  850. DWORD dwWait;
  851. return ::WaitForMultipleObjects( hEvent ? 2 : 1, hEvents, FALSE, dwTimeout );
  852. }
  853. HANDLE Thread_GetSignalEvent()
  854. {
  855. return m_hEvent;
  856. }
  857. public:
  858. Thread()
  859. {
  860. ::InitializeCriticalSection( &m_sec );
  861. // CRITICAL_SECTION m_sec;
  862. //
  863. m_SelfDirect = NULL; // T* m_SelfDirect;
  864. // CComPtrThreadNeutral<Itf> m_Self
  865. //
  866. m_hThread = NULL; // HANDLE m_hThread;
  867. m_fRunning = false; // bool m_fRunning;
  868. //
  869. m_hEvent = NULL; // HANDLE m_hEvent;
  870. m_hEventReverse = NULL; // HANDLE m_hEventReverse;
  871. m_fAbort = false; // bool m_fAbort;
  872. }
  873. ~Thread()
  874. {
  875. Thread_Wait();
  876. ::DeleteCriticalSection( &m_sec );
  877. }
  878. HRESULT Thread_Start( /*[in]*/ T* selfDirect, /*[in]*/ THREAD_RUN callback, /*[in]*/ Itf* self )
  879. {
  880. __MPC_FUNC_ENTRY( COMMONID, "MPC::Thread::Thread_Start" );
  881. HRESULT hr;
  882. DWORD dwThreadID;
  883. //
  884. // First of all, kill the currently running thread, if any.
  885. //
  886. Thread_Abort();
  887. Thread_Wait ();
  888. Thread_Lock();
  889. m_SelfDirect = selfDirect;
  890. m_Callback = callback;
  891. m_Self = self;
  892. m_fAbort = false;
  893. m_fRunning = false;
  894. //
  895. // Create the event used to signal the worker thread about changes in the queue or termination requests.
  896. //
  897. // The Event is created in the SET state, so the worker thread doesn't wait in the WaitForSingleObject the first time.
  898. //
  899. __MPC_EXIT_IF_CALL_RETURNS_NULL(hr, (m_hEvent = ::CreateEvent( NULL, FALSE, TRUE, NULL )));
  900. //
  901. // Create the event used to signal the main thread.
  902. //
  903. __MPC_EXIT_IF_CALL_RETURNS_NULL(hr, (m_hEventReverse = ::CreateEvent( NULL, FALSE, FALSE, NULL )));
  904. //
  905. // Create the worker thread.
  906. //
  907. __MPC_EXIT_IF_CALL_RETURNS_NULL(hr, (m_hThread = (HANDLE)_beginthreadex( NULL, 0, Thread_Startup, this, 0, (unsigned*)&dwThreadID )));
  908. m_fRunning = true;
  909. hr = S_OK;
  910. __MPC_FUNC_CLEANUP;
  911. Thread_Unlock();
  912. __MPC_FUNC_EXIT(hr);
  913. }
  914. bool Thread_SameThread()
  915. {
  916. Thread_Lock();
  917. bool fRes = (::GetCurrentThread() == m_hThread);
  918. Thread_Unlock();
  919. return fRes;
  920. }
  921. void Thread_Wait( /*[in]*/ bool fForce = true, /*[in]*/ bool fNoMsg = false )
  922. {
  923. __MPC_FUNC_ENTRY( COMMONID, "MPC::Thread::Thread_Wait" );
  924. Thread_Lock();
  925. if(m_hThread && m_hEvent)
  926. {
  927. if(::GetCurrentThread() != m_hThread)
  928. {
  929. while(m_fRunning == true)
  930. {
  931. if(fForce) Thread_Abort();
  932. Thread_Unlock(); // Always unlock before waiting for signal.
  933. if(fNoMsg)
  934. {
  935. (void)::WaitForSingleObject( m_hThread, INFINITE );
  936. }
  937. else
  938. {
  939. (void)MPC::WaitForSingleObject( m_hThread, INFINITE );
  940. }
  941. Thread_Lock(); // Lock again.
  942. }
  943. }
  944. }
  945. if(m_hEventReverse)
  946. {
  947. ::CloseHandle( m_hEventReverse );
  948. m_hEventReverse = NULL;
  949. }
  950. if(m_hEvent)
  951. {
  952. ::CloseHandle( m_hEvent );
  953. m_hEvent = NULL;
  954. }
  955. if(m_hThread)
  956. {
  957. ::CloseHandle( m_hThread );
  958. m_hThread = NULL;
  959. }
  960. Thread_Release();
  961. Thread_Unlock();
  962. }
  963. DWORD Thread_WaitNotificationFromWorker( /*[in]*/ DWORD dwTimeout, /*[in]*/ bool fNoMessagePump )
  964. {
  965. __MPC_FUNC_ENTRY( COMMONID, "MPC::Thread::Thread_WaitNotificationFromWorker" );
  966. DWORD dwRes = WAIT_TIMEOUT;
  967. Thread_Lock();
  968. if(Thread_IsRunning() && m_hEventReverse && ::GetCurrentThread() != m_hThread)
  969. {
  970. Thread_Unlock(); // Always unlock before waiting for signal.
  971. if(fNoMessagePump)
  972. {
  973. dwRes = ::WaitForSingleObject( m_hEventReverse, dwTimeout );
  974. }
  975. else
  976. {
  977. dwRes = MPC::WaitForSingleObject( m_hEventReverse, dwTimeout );
  978. }
  979. Thread_Lock(); // Lock again.
  980. }
  981. Thread_Unlock();
  982. __MPC_FUNC_EXIT(dwRes);
  983. }
  984. void Thread_Release()
  985. {
  986. __MPC_FUNC_ENTRY( COMMONID, "MPC::Thread::Thread_Release" );
  987. Thread_Lock();
  988. m_SelfDirect = NULL;
  989. m_Callback = NULL;
  990. m_Self = NULL;
  991. Thread_Unlock();
  992. }
  993. void Thread_Signal()
  994. {
  995. __MPC_FUNC_ENTRY( COMMONID, "MPC::Thread::Thread_Signal" );
  996. Thread_Lock();
  997. if(m_hEvent)
  998. {
  999. ::SetEvent( m_hEvent );
  1000. }
  1001. Thread_Unlock();
  1002. }
  1003. void Thread_SignalMain()
  1004. {
  1005. __MPC_FUNC_ENTRY( COMMONID, "MPC::Thread::Thread_SignalMain" );
  1006. Thread_Lock();
  1007. if(m_hEventReverse)
  1008. {
  1009. ::SetEvent( m_hEventReverse );
  1010. }
  1011. Thread_Unlock();
  1012. }
  1013. void Thread_Abort()
  1014. {
  1015. __MPC_FUNC_ENTRY( COMMONID, "MPC::Thread::Thread_Abort" );
  1016. Thread_Lock();
  1017. if(m_hEvent)
  1018. {
  1019. m_fAbort = true;
  1020. ::SetEvent( m_hEvent );
  1021. }
  1022. Thread_Unlock();
  1023. }
  1024. CComPtr<Itf> Thread_Self()
  1025. {
  1026. __MPC_FUNC_ENTRY( COMMONID, "MPC::Thread::Thread_Self" );
  1027. //
  1028. // Do NOT use locking, because:
  1029. //
  1030. // 1) It's not needed (m_Self is used internally to the thread, it's not a shared resource).
  1031. // 2) GIT can cause a thread switch and a deadlock...
  1032. //
  1033. CComPtr<Itf> res = m_Self;
  1034. __MPC_FUNC_EXIT(res);
  1035. }
  1036. bool Thread_IsAborted()
  1037. {
  1038. __MPC_FUNC_ENTRY( COMMONID, "MPC::Thread::Thread_IsAborted" );
  1039. bool res;
  1040. Thread_Lock();
  1041. res = m_fAbort;
  1042. Thread_Unlock();
  1043. __MPC_FUNC_EXIT(res);
  1044. }
  1045. bool Thread_IsRunning()
  1046. {
  1047. __MPC_FUNC_ENTRY( COMMONID, "MPC::Thread::Thread_IsRunning" );
  1048. bool res;
  1049. Thread_Lock();
  1050. res = m_fRunning;
  1051. Thread_Unlock();
  1052. __MPC_FUNC_EXIT(res);
  1053. }
  1054. };
  1055. /////////////////////////////////////////////////////////////////////////////
  1056. //
  1057. // Async Invoke class, used to call IDispatch interfaces in an asynchronous way.
  1058. //
  1059. class AsyncInvoke : // hungarian: mpcai
  1060. public CComObjectRootEx<MPC::CComSafeMultiThreadModel>, // For the locking support...
  1061. public Thread<AsyncInvoke,IUnknown>
  1062. {
  1063. public:
  1064. //
  1065. // These two classes, CallItem and CallDesc, are useful also outside this class,
  1066. // because "CallDesc" allows to have an object that can call any IDispatch-related methods,
  1067. // irregardless to the apartment model, while "CallItem" does the same for VARIANTs.
  1068. //
  1069. class CallItem // hungarian: ci
  1070. {
  1071. VARTYPE m_vt;
  1072. CComPtrThreadNeutral<IUnknown> m_Unknown;
  1073. CComPtrThreadNeutral<IDispatch> m_Dispatch;
  1074. CComVariant m_Other;
  1075. public:
  1076. CallItem();
  1077. CallItem& operator=( const CComVariant& var );
  1078. operator CComVariant() const;
  1079. };
  1080. class CallDesc // hungarian: cd
  1081. {
  1082. CComPtrThreadNeutral<IDispatch> m_dispTarget;
  1083. DISPID m_dispidMethod;
  1084. CallItem* m_rgciVars;
  1085. DWORD m_dwVars;
  1086. public:
  1087. CallDesc( IDispatch* dispTarget, DISPID dispidMethod, const CComVariant* rgvVars, int dwVars );
  1088. ~CallDesc();
  1089. HRESULT Call();
  1090. };
  1091. private:
  1092. typedef std::list< CallDesc* > List;
  1093. typedef List::iterator Iter;
  1094. typedef List::const_iterator IterConst;
  1095. List m_lstEvents;
  1096. HRESULT Thread_Run();
  1097. public:
  1098. HRESULT Init();
  1099. HRESULT Term();
  1100. HRESULT Invoke( IDispatch* dispTarget, DISPID dispidMethod, const CComVariant* rgvVars, int dwVars );
  1101. };
  1102. /////////////////////////////////////////////////////////////////////////////
  1103. //
  1104. // This template facilitate the implementation of Collections and Enumerators.
  1105. //
  1106. // It implements a Collections of objects, all implementing the <class Itf> interface, through Type Library <const GUID* plibid>.
  1107. //
  1108. // All the client has to do is call "AddItem", to add elements to the collection:
  1109. //
  1110. // class ATL_NO_VTABLE CNewClass : // Hungarian: hsc
  1111. // public MPC::CComCollection< INewClass, &LIBID_NewLib, CComMultiThreadModel>
  1112. // {
  1113. // public:
  1114. // BEGIN_COM_MAP(CNewClass)
  1115. // COM_INTERFACE_ENTRY(IDispatch)
  1116. // COM_INTERFACE_ENTRY(INewClass)
  1117. // END_COM_MAP()
  1118. // };
  1119. //
  1120. template <class Itf, const GUID* plibid, class ThreadModel>
  1121. class CComCollection :
  1122. public CComObjectRootEx<ThreadModel>,
  1123. public ICollectionOnSTLImpl<
  1124. IDispatchImpl< Itf, &__uuidof(Itf), plibid >,
  1125. std::list < VARIANT >,
  1126. VARIANT ,
  1127. _Copy < VARIANT >,
  1128. CComEnumOnSTL< IEnumVARIANT, &IID_IEnumVARIANT, VARIANT, _Copy<VARIANT>, std::list< VARIANT >, ThreadModel >
  1129. >
  1130. {
  1131. public:
  1132. typedef std::list< VARIANT > CollectionList;
  1133. typedef CollectionList::iterator CollectionIter;
  1134. typedef CollectionList::const_iterator CollectionIterConst;
  1135. void FinalRelease()
  1136. {
  1137. Erase();
  1138. }
  1139. void Erase()
  1140. {
  1141. MPC::SmartLock<_ThreadModel> lock( this );
  1142. MPC::ReleaseAllVariant( m_coll );
  1143. }
  1144. HRESULT AddItem( /*[in]*/ IDispatch* pDisp )
  1145. {
  1146. MPC::SmartLock<_ThreadModel> lock( this );
  1147. if(pDisp)
  1148. {
  1149. VARIANT vItem;
  1150. ::VariantInit( &vItem );
  1151. vItem.vt = VT_DISPATCH;
  1152. vItem.pdispVal = pDisp; pDisp->AddRef();
  1153. m_coll.push_back( vItem );
  1154. }
  1155. return S_OK;
  1156. }
  1157. };
  1158. //////////////////////////////////////////////////////////////////////
  1159. template <class Base, const IID* piid, class ThreadModel> class ConnectionPointImpl :
  1160. public CComObjectRootEx<ThreadModel>,
  1161. public IConnectionPointContainerImpl< Base >,
  1162. public IConnectionPointImpl < Base, piid, CComDynamicUnkArray >
  1163. {
  1164. public:
  1165. BEGIN_CONNECTION_POINT_MAP(Base)
  1166. CONNECTION_POINT_ENTRY((*piid))
  1167. END_CONNECTION_POINT_MAP()
  1168. protected:
  1169. //
  1170. // Event firing methods.
  1171. //
  1172. HRESULT FireAsync_Generic( DISPID dispid, CComVariant* pVars, DWORD dwVars, CComPtr<IDispatch> pJScript )
  1173. {
  1174. HRESULT hr;
  1175. MPC::IDispatchList lst;
  1176. //
  1177. // Only this part should be inside a critical section, otherwise deadlocks could occur.
  1178. //
  1179. {
  1180. MPC::SmartLock<_ThreadModel> lock( this );
  1181. MPC::CopyConnections( m_vec, lst ); // Get a copy of the connection point clients.
  1182. }
  1183. hr = MPC::FireAsyncEvent( dispid, pVars, dwVars, lst, pJScript );
  1184. MPC::ReleaseAll( lst );
  1185. return hr;
  1186. }
  1187. HRESULT FireSync_Generic( DISPID dispid, CComVariant* pVars, DWORD dwVars, CComPtr<IDispatch> pJScript )
  1188. {
  1189. HRESULT hr;
  1190. MPC::IDispatchList lst;
  1191. //
  1192. // Only this part should be inside a critical section, otherwise deadlocks could occur.
  1193. //
  1194. {
  1195. MPC::SmartLock<_ThreadModel> lock( this );
  1196. MPC::CopyConnections( m_vec, lst ); // Get a copy of the connection point clients.
  1197. }
  1198. hr = MPC::FireEvent( dispid, pVars, dwVars, lst, pJScript );
  1199. MPC::ReleaseAll( lst );
  1200. return hr;
  1201. }
  1202. };
  1203. HRESULT FireAsyncEvent( DISPID dispid, CComVariant* pVars, DWORD dwVars, const IDispatchList& lst, IDispatch* pJScript = NULL, bool fFailOnError = false );
  1204. HRESULT FireEvent ( DISPID dispid, CComVariant* pVars, DWORD dwVars, const IDispatchList& lst, IDispatch* pJScript = NULL, bool fFailOnError = false );
  1205. template <class Coll> HRESULT CopyConnections( Coll& coll ,
  1206. IDispatchList& lst )
  1207. {
  1208. int nConnectionIndex;
  1209. int nConnections = coll.GetSize();
  1210. //
  1211. // nConnectionIndex == -1 is a special case, for calling a JavaScript function!
  1212. //
  1213. for(nConnectionIndex = 0; nConnectionIndex < nConnections; nConnectionIndex++)
  1214. {
  1215. CComQIPtr<IDispatch> sp( coll.GetAt(nConnectionIndex) );
  1216. if(sp)
  1217. {
  1218. lst.push_back( sp.Detach() );
  1219. }
  1220. }
  1221. return S_OK;
  1222. }
  1223. /////////////////////////////////////////////////////////////////////////////
  1224. class MPCMODULE
  1225. {
  1226. class AnchorBase
  1227. {
  1228. public:
  1229. virtual void Call ( ) = 0;
  1230. virtual bool Match( void* pObj ) = 0;
  1231. };
  1232. template <class C> class Anchor : public AnchorBase
  1233. {
  1234. typedef void (C::*CLASS_METHOD)();
  1235. C* m_pThis;
  1236. CLASS_METHOD m_pCallback;
  1237. public:
  1238. Anchor( /*[in]*/ C* pThis, /*[in]*/ CLASS_METHOD pCallback )
  1239. {
  1240. m_pThis = pThis;
  1241. m_pCallback = pCallback;
  1242. }
  1243. void Call()
  1244. {
  1245. (m_pThis->*m_pCallback)();
  1246. }
  1247. bool Match( /*[in]*/ void* pObj )
  1248. {
  1249. return m_pThis == (C*)pObj;
  1250. }
  1251. };
  1252. typedef std::list< AnchorBase* > List;
  1253. typedef List::iterator Iter;
  1254. typedef List::const_iterator IterConst;
  1255. static LONG m_lInitialized;
  1256. static LONG m_lInitializing;
  1257. static CComCriticalSection m_sec;
  1258. static List* m_lstTermCallback;
  1259. ////////////////////////////////////////
  1260. static HRESULT Initialize();
  1261. HRESULT RegisterCallbackInner ( /*[in]*/ AnchorBase* pElem, /*[in]*/ void* pThis );
  1262. HRESULT UnregisterCallbackInner( /*[in]*/ void* pThis );
  1263. public:
  1264. CComPtrThreadNeutral_GIT* m_GITHolder;
  1265. AsyncInvoke* m_AsyncInvoke;
  1266. HRESULT Init();
  1267. HRESULT Term();
  1268. template <class C> HRESULT RegisterCallback( C* pThis, void (C::*pCallback)() )
  1269. {
  1270. if(pThis == NULL) return E_POINTER;
  1271. return RegisterCallbackInner( new Anchor<C>( pThis, pCallback ), pThis );
  1272. }
  1273. template <class C> HRESULT UnregisterCallback( C* pThis )
  1274. {
  1275. return UnregisterCallbackInner( pThis );
  1276. }
  1277. };
  1278. extern MPCMODULE _MPC_Module;
  1279. //
  1280. // Function to call a method in an asynchronous mode (however, no return values will be given).
  1281. //
  1282. HRESULT AsyncInvoke( IDispatch* dispTarget, DISPID dispidMethod, const CComVariant* rgvVars, int dwVars );
  1283. //
  1284. // This is like Sleep(), but it spins the message pump.
  1285. //
  1286. void SleepWithMessagePump( /*[in]*/ DWORD dwTimeout );
  1287. //
  1288. // Functions to wait on events even in an STA context.
  1289. //
  1290. DWORD WaitForSingleObject ( /*[in]*/ HANDLE hEvent , /*[in]*/ DWORD dwTimeout = INFINITE );
  1291. DWORD WaitForMultipleObjects( /*[in]*/ DWORD dwEvents, /*[in]*/ HANDLE* rgEvents, /*[in]*/ DWORD dwTimeout = INFINITE );
  1292. }; // namespace
  1293. #endif // !defined(__INCLUDED___MPC___COM_H___)