Source code of Windows XP (NT5)
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.

2181 lines
56 KiB

  1. // This is a part of the Active Template Library.
  2. // Copyright (C) 1996-1997 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Active Template Library Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Active Template Library product.
  10. #ifndef __ATLCOM_H__
  11. #define __ATLCOM_H__
  12. #ifndef __cplusplus
  13. #error ATL requires C++ compilation (use a .cpp suffix)
  14. #endif
  15. #ifndef __ATLBASE_H__
  16. #error atlcom.h requires atlbase.h to be included first
  17. #endif
  18. #pragma pack(push, _ATL_PACKING)
  19. #ifndef ATL_NO_NAMESPACE
  20. namespace ATL
  21. {
  22. #endif
  23. #define CComConnectionPointContainerImpl IConnectionPointContainerImpl
  24. #define CComISupportErrorInfoImpl ISupportErrorInfoImpl
  25. #define CComProvideClassInfo2Impl IProvideClassInfoImpl
  26. #define CComDualImpl IDispatchImpl
  27. #ifdef _ATL_DEBUG_QI
  28. HRESULT WINAPI AtlDumpIID(REFIID iid, LPCTSTR pszClassName, HRESULT hr);
  29. #define _ATLDUMPIID(iid, name, hr) AtlDumpIID(iid, name, hr)
  30. #else
  31. #define _ATLDUMPIID(iid, name, hr) hr
  32. #endif
  33. #ifdef _ATL_DEBUG_REFCOUNT
  34. //////////////////////////////////////////////////////////////////////////////
  35. // CComDebugRefCount for interface level ref counting
  36. class CComDebugRefCount
  37. {
  38. public:
  39. CComDebugRefCount()
  40. {
  41. m_nRef = 0;
  42. }
  43. ~CComDebugRefCount()
  44. {
  45. _ASSERTE(m_nRef == 0);
  46. }
  47. long m_nRef;
  48. };
  49. #define _ATL_DEBUG_ADDREF_RELEASE_IMPL(className) \
  50. public:\
  51. CComDebugRefCount _ref;\
  52. virtual ULONG STDMETHODCALLTYPE _DebugAddRef(void) \
  53. {return ((T*)this)->DebugAddRef(_ref.m_nRef, _T(#className));} \
  54. virtual ULONG STDMETHODCALLTYPE _DebugRelease(void) \
  55. {return ((T*)this)->DebugRelease(_ref.m_nRef, _T(#className));}
  56. #else
  57. #define _ATL_DEBUG_ADDREF_RELEASE_IMPL(className)\
  58. virtual ULONG STDMETHODCALLTYPE AddRef(void) = 0;\
  59. virtual ULONG STDMETHODCALLTYPE Release(void) = 0;
  60. #endif // _ATL_DEBUG_REFCOUNT
  61. HRESULT WINAPI AtlReportError(const CLSID& clsid, LPCOLESTR lpszDesc,
  62. const IID& iid = GUID_NULL, HRESULT hRes = 0);
  63. HRESULT WINAPI AtlReportError(const CLSID& clsid, LPCOLESTR lpszDesc,
  64. DWORD dwHelpID, LPCOLESTR lpszHelpFile, const IID& iid = GUID_NULL,
  65. HRESULT hRes = 0);
  66. HRESULT WINAPI AtlReportError(const CLSID& clsid, UINT nID,
  67. const IID& iid = GUID_NULL, HRESULT hRes = 0,
  68. HINSTANCE hInst = _Module.GetResourceInstance());
  69. HRESULT WINAPI AtlReportError(const CLSID& clsid, UINT nID,
  70. DWORD dwHelpID, LPCOLESTR lpszHelpFile, const IID& iid = GUID_NULL,
  71. HRESULT hRes = 0, HINSTANCE hInst = _Module.GetResourceInstance());
  72. #ifndef OLE2ANSI
  73. HRESULT WINAPI AtlReportError(const CLSID& clsid, LPCSTR lpszDesc,
  74. const IID& iid = GUID_NULL, HRESULT hRes = 0);
  75. HRESULT WINAPI AtlReportError(const CLSID& clsid, LPCSTR lpszDesc,
  76. DWORD dwHelpID, LPCSTR lpszHelpFile, const IID& iid = GUID_NULL,
  77. HRESULT hRes = 0);
  78. #endif
  79. #ifndef _ATL_NO_SECURITY
  80. /////////////////////////////////////////////////////////////////////////////
  81. // CSecurityDescriptor
  82. class CSecurityDescriptor
  83. {
  84. public:
  85. CSecurityDescriptor();
  86. ~CSecurityDescriptor();
  87. public:
  88. HRESULT Attach(PSECURITY_DESCRIPTOR pSelfRelativeSD);
  89. HRESULT AttachObject(HANDLE hObject);
  90. HRESULT Initialize();
  91. HRESULT InitializeFromProcessToken(BOOL bDefaulted = FALSE);
  92. HRESULT InitializeFromThreadToken(BOOL bDefaulted = FALSE, BOOL bRevertToProcessToken = TRUE);
  93. HRESULT SetOwner(PSID pOwnerSid, BOOL bDefaulted = FALSE);
  94. HRESULT SetGroup(PSID pGroupSid, BOOL bDefaulted = FALSE);
  95. HRESULT Allow(LPCTSTR pszPrincipal, DWORD dwAccessMask);
  96. HRESULT Deny(LPCTSTR pszPrincipal, DWORD dwAccessMask);
  97. HRESULT Revoke(LPCTSTR pszPrincipal);
  98. // utility functions
  99. // Any PSID you get from these functions should be free()ed
  100. static HRESULT SetPrivilege(LPCTSTR Privilege, BOOL bEnable = TRUE, HANDLE hToken = NULL);
  101. static HRESULT GetTokenSids(HANDLE hToken, PSID* ppUserSid, PSID* ppGroupSid);
  102. static HRESULT GetProcessSids(PSID* ppUserSid, PSID* ppGroupSid = NULL);
  103. static HRESULT GetThreadSids(PSID* ppUserSid, PSID* ppGroupSid = NULL, BOOL bOpenAsSelf = FALSE);
  104. static HRESULT CopyACL(PACL pDest, PACL pSrc);
  105. static HRESULT GetCurrentUserSID(PSID *ppSid);
  106. static HRESULT GetPrincipalSID(LPCTSTR pszPrincipal, PSID *ppSid);
  107. static HRESULT AddAccessAllowedACEToACL(PACL *Acl, LPCTSTR pszPrincipal, DWORD dwAccessMask);
  108. static HRESULT AddAccessDeniedACEToACL(PACL *Acl, LPCTSTR pszPrincipal, DWORD dwAccessMask);
  109. static HRESULT RemovePrincipalFromACL(PACL Acl, LPCTSTR pszPrincipal);
  110. operator PSECURITY_DESCRIPTOR()
  111. {
  112. return m_pSD;
  113. }
  114. public:
  115. PSECURITY_DESCRIPTOR m_pSD;
  116. PSID m_pOwner;
  117. PSID m_pGroup;
  118. PACL m_pDACL;
  119. PACL m_pSACL;
  120. };
  121. #endif // _ATL_NO_SECURITY
  122. /////////////////////////////////////////////////////////////////////////////
  123. // COM Objects
  124. #define DECLARE_PROTECT_FINAL_CONSTRUCT()\
  125. void InternalFinalConstructAddRef() {InternalAddRef();}\
  126. void InternalFinalConstructRelease() {InternalRelease();}
  127. template <class T1>
  128. class CComCreator
  129. {
  130. public:
  131. static HRESULT WINAPI CreateInstance(void* pv, REFIID riid, LPVOID* ppv)
  132. {
  133. _ASSERTE(*ppv == NULL);
  134. HRESULT hRes = E_OUTOFMEMORY;
  135. T1* p = NULL;
  136. ATLTRY(p = new T1(pv))
  137. if (p != NULL)
  138. {
  139. p->SetVoid(pv);
  140. p->InternalFinalConstructAddRef();
  141. hRes = p->FinalConstruct();
  142. p->InternalFinalConstructRelease();
  143. if (hRes == S_OK)
  144. hRes = p->QueryInterface(riid, ppv);
  145. if (hRes != S_OK)
  146. delete p;
  147. }
  148. return hRes;
  149. }
  150. };
  151. template <class T1>
  152. class CComInternalCreator
  153. {
  154. public:
  155. static HRESULT WINAPI CreateInstance(void* pv, REFIID riid, LPVOID* ppv)
  156. {
  157. _ASSERTE(*ppv == NULL);
  158. HRESULT hRes = E_OUTOFMEMORY;
  159. T1* p = NULL;
  160. ATLTRY(p = new T1(pv))
  161. if (p != NULL)
  162. {
  163. p->SetVoid(pv);
  164. p->InternalFinalConstructAddRef();
  165. hRes = p->FinalConstruct();
  166. p->InternalFinalConstructRelease();
  167. if (hRes == S_OK)
  168. hRes = p->_InternalQueryInterface(riid, ppv);
  169. if (hRes != S_OK)
  170. delete p;
  171. }
  172. return hRes;
  173. }
  174. };
  175. template <HRESULT hr>
  176. class CComFailCreator
  177. {
  178. public:
  179. static HRESULT WINAPI CreateInstance(void*, REFIID, LPVOID*)
  180. {
  181. return hr;
  182. }
  183. };
  184. template <class T1, class T2>
  185. class CComCreator2
  186. {
  187. public:
  188. static HRESULT WINAPI CreateInstance(void* pv, REFIID riid, LPVOID* ppv)
  189. {
  190. _ASSERTE(*ppv == NULL);
  191. HRESULT hRes = E_OUTOFMEMORY;
  192. if (pv == NULL)
  193. hRes = T1::CreateInstance(NULL, riid, ppv);
  194. else
  195. hRes = T2::CreateInstance(pv, riid, ppv);
  196. return hRes;
  197. }
  198. };
  199. #define DECLARE_NOT_AGGREGATABLE(x) public:\
  200. typedef CComCreator2< CComCreator< CComObject< x > >, CComFailCreator<CLASS_E_NOAGGREGATION> > _CreatorClass;
  201. #define DECLARE_AGGREGATABLE(x) public:\
  202. typedef CComCreator2< CComCreator< CComObject< x > >, CComCreator< CComAggObject< x > > > _CreatorClass;
  203. #define DECLARE_ONLY_AGGREGATABLE(x) public:\
  204. typedef CComCreator2< CComFailCreator<E_FAIL>, CComCreator< CComAggObject< x > > > _CreatorClass;
  205. #define DECLARE_POLY_AGGREGATABLE(x) public:\
  206. typedef CComCreator< CComPolyObject< x > > _CreatorClass;
  207. struct _ATL_CREATORDATA
  208. {
  209. _ATL_CREATORFUNC* pFunc;
  210. };
  211. template <class Creator>
  212. class _CComCreatorData
  213. {
  214. public:
  215. static _ATL_CREATORDATA data;
  216. };
  217. template <class Creator>
  218. _ATL_CREATORDATA _CComCreatorData<Creator>::data = {Creator::CreateInstance};
  219. struct _ATL_CACHEDATA
  220. {
  221. DWORD_PTR dwOffsetVar;
  222. _ATL_CREATORFUNC* pFunc;
  223. };
  224. template <class Creator, DWORD dwVar>
  225. class _CComCacheData
  226. {
  227. public:
  228. static _ATL_CACHEDATA data;
  229. };
  230. template <class Creator, DWORD dwVar>
  231. _ATL_CACHEDATA _CComCacheData<Creator, dwVar>::data = {dwVar, Creator::CreateInstance};
  232. struct _ATL_CHAINDATA
  233. {
  234. DWORD_PTR dwOffset;
  235. const _ATL_INTMAP_ENTRY* (WINAPI *pFunc)();
  236. };
  237. template <class base, class derived>
  238. class _CComChainData
  239. {
  240. public:
  241. static _ATL_CHAINDATA data;
  242. };
  243. template <class base, class derived>
  244. _ATL_CHAINDATA _CComChainData<base, derived>::data =
  245. {offsetofclass(base, derived), base::_GetEntries};
  246. template <class T, const CLSID* pclsid>
  247. class CComAggregateCreator
  248. {
  249. public:
  250. static HRESULT WINAPI CreateInstance(void* pv, REFIID/*riid*/, LPVOID* ppv)
  251. {
  252. _ASSERTE(*ppv == NULL);
  253. _ASSERTE(pv != NULL);
  254. T* p = (T*) pv;
  255. // Add the following line to your object if you get a message about
  256. // GetControllingUnknown() being undefined
  257. // DECLARE_GET_CONTROLLING_UNKNOWN()
  258. return CoCreateInstance(*pclsid, p->GetControllingUnknown(), CLSCTX_INPROC, IID_IUnknown, ppv);
  259. }
  260. };
  261. #ifdef _ATL_DEBUG_QI
  262. #define DEBUG_QI_ENTRY(x) \
  263. {NULL, \
  264. (ULONG_PTR)_T(#x), \
  265. (_ATL_CREATORARGFUNC*)0},
  266. #else
  267. #define DEBUG_QI_ENTRY(x)
  268. #endif //_ATL_DEBUG_QI
  269. //If you get a message that FinalConstruct is ambiguous then you need to
  270. // override it in your class and call each base class' version of this
  271. #define BEGIN_COM_MAP(x) public: \
  272. typedef x _ComMapClass; \
  273. static HRESULT WINAPI _Cache(void* pv, REFIID iid, void** ppvObject, DWORD_PTR dw)\
  274. {\
  275. _ComMapClass* p = (_ComMapClass*)pv;\
  276. p->Lock();\
  277. HRESULT hRes = CComObjectRootBase::_Cache(pv, iid, ppvObject, dw);\
  278. p->Unlock();\
  279. return hRes;\
  280. }\
  281. IUnknown* GetUnknown() \
  282. { _ASSERTE(_GetEntries()[0].pFunc == _ATL_SIMPLEMAPENTRY); return (IUnknown*)((DWORD_PTR)this+_GetEntries()->dw); } \
  283. HRESULT _InternalQueryInterface(REFIID iid, void** ppvObject) \
  284. { return InternalQueryInterface(this, _GetEntries(), iid, ppvObject); } \
  285. const static _ATL_INTMAP_ENTRY* WINAPI _GetEntries() { \
  286. static const _ATL_INTMAP_ENTRY _entries[] = { DEBUG_QI_ENTRY(x)
  287. #define DECLARE_GET_CONTROLLING_UNKNOWN() public:\
  288. virtual IUnknown* GetControllingUnknown() {return GetUnknown();}
  289. #define COM_INTERFACE_ENTRY_BREAK(x)\
  290. {&IID_##x, \
  291. NULL, \
  292. _Break},
  293. #define COM_INTERFACE_ENTRY_NOINTERFACE(x)\
  294. {&IID_##x, \
  295. NULL, \
  296. _NoInterface},
  297. #define COM_INTERFACE_ENTRY(x)\
  298. {&IID_##x, \
  299. offsetofclass(x, _ComMapClass), \
  300. _ATL_SIMPLEMAPENTRY},
  301. #define COM_INTERFACE_ENTRY_IID(iid, x)\
  302. {&iid,\
  303. offsetofclass(x, _ComMapClass),\
  304. _ATL_SIMPLEMAPENTRY},
  305. #define COM_INTERFACE_ENTRY_IMPL(x)\
  306. COM_INTERFACE_ENTRY_IID(IID_##x, x##Impl<_ComMapClass>)
  307. #define COM_INTERFACE_ENTRY_IMPL_IID(iid, x)\
  308. COM_INTERFACE_ENTRY_IID(iid, x##Impl<_ComMapClass>)
  309. #define COM_INTERFACE_ENTRY2(x, x2)\
  310. {&IID_##x,\
  311. (ULONG_PTR)((x*)(x2*)((_ComMapClass*)8))-8,\
  312. _ATL_SIMPLEMAPENTRY},
  313. #define COM_INTERFACE_ENTRY2_IID(iid, x, x2)\
  314. {&iid,\
  315. (ULONG_PTR)((x*)(x2*)((_ComMapClass*)8))-8,\
  316. _ATL_SIMPLEMAPENTRY},
  317. #define COM_INTERFACE_ENTRY_FUNC(iid, dw, func)\
  318. {&iid, \
  319. dw, \
  320. func},
  321. #define COM_INTERFACE_ENTRY_FUNC_BLIND(dw, func)\
  322. {NULL, \
  323. dw, \
  324. func},
  325. #define COM_INTERFACE_ENTRY_TEAR_OFF(iid, x)\
  326. {&iid,\
  327. (ULONG_PTR)&_CComCreatorData<\
  328. CComInternalCreator< CComTearOffObject< x > >\
  329. >::data,\
  330. _Creator},
  331. #define COM_INTERFACE_ENTRY_CACHED_TEAR_OFF(iid, x, punk)\
  332. {&iid,\
  333. (ULONG_PTR)&_CComCacheData<\
  334. CComCreator< CComCachedTearOffObject< x > >,\
  335. (DWORD)offsetof(_ComMapClass, punk)\
  336. >::data,\
  337. _Cache},
  338. #define COM_INTERFACE_ENTRY_AGGREGATE(iid, punk)\
  339. {&iid,\
  340. offsetof(_ComMapClass, punk),\
  341. _Delegate},
  342. #define COM_INTERFACE_ENTRY_AGGREGATE_BLIND(punk)\
  343. {NULL,\
  344. offsetof(_ComMapClass, punk),\
  345. _Delegate},
  346. #define COM_INTERFACE_ENTRY_AUTOAGGREGATE(iid, punk, clsid)\
  347. {&iid,\
  348. (ULONG_PTR)&_CComCacheData<\
  349. CComAggregateCreator<_ComMapClass, &clsid>,\
  350. (DWORD)offsetof(_ComMapClass, punk)\
  351. >::data,\
  352. _Cache},
  353. #define COM_INTERFACE_ENTRY_AUTOAGGREGATE_BLIND(punk, clsid)\
  354. {NULL,\
  355. (ULONG_PTR)&_CComCacheData<\
  356. CComAggregateCreator<_ComMapClass, &clsid>,\
  357. (DWORD)offsetof(_ComMapClass, punk)\
  358. >::data,\
  359. _Cache},
  360. #define COM_INTERFACE_ENTRY_CHAIN(classname)\
  361. {NULL,\
  362. (ULONG_PTR)&_CComChainData<classname, _ComMapClass>::data,\
  363. _Chain},
  364. #ifdef _ATL_DEBUG_QI
  365. #define END_COM_MAP() {NULL, 0, 0}};\
  366. return &_entries[1];}
  367. #else
  368. #define END_COM_MAP() {NULL, 0, 0}};\
  369. return _entries;}
  370. #endif // _ATL_DEBUG_QI
  371. #define BEGIN_OBJECT_MAP(x) static _ATL_OBJMAP_ENTRY x[] = {
  372. #define END_OBJECT_MAP() {NULL, NULL, NULL, NULL}};
  373. #define OBJECT_ENTRY(clsid, class) {&clsid, &class::UpdateRegistry, &class::_ClassFactoryCreatorClass::CreateInstance, &class::_CreatorClass::CreateInstance, NULL, 0, &class::GetObjectDescription },
  374. #ifdef _ATL_DEBUG_QI
  375. extern HRESULT WINAPI AtlDumpIID(REFIID iid, LPCTSTR pszClassName, HRESULT hr);
  376. #endif // _ATL_DEBUG_QI
  377. // the functions in this class don't need to be virtual because
  378. // they are called from CComObject
  379. class CComObjectRootBase
  380. {
  381. public:
  382. CComObjectRootBase()
  383. {
  384. m_dwRef = 0L;
  385. }
  386. HRESULT FinalConstruct()
  387. {
  388. return S_OK;
  389. }
  390. void FinalRelease() {}
  391. static HRESULT WINAPI InternalQueryInterface(void* pThis,
  392. const _ATL_INTMAP_ENTRY* pEntries, REFIID iid, void** ppvObject)
  393. {
  394. _ASSERTE(pThis != NULL);
  395. // First entry in the com map should be a simple map entry
  396. _ASSERTE(pEntries->pFunc == _ATL_SIMPLEMAPENTRY);
  397. #ifdef _ATL_DEBUG_QI
  398. LPCTSTR pszClassName = (LPCTSTR) pEntries[-1].dw;
  399. #endif // _ATL_DEBUG_QI
  400. HRESULT hRes = AtlInternalQueryInterface(pThis, pEntries, iid, ppvObject);
  401. return _ATLDUMPIID(iid, pszClassName, hRes);
  402. }
  403. //Outer funcs
  404. ULONG OuterAddRef()
  405. {
  406. return m_pOuterUnknown->AddRef();
  407. }
  408. ULONG OuterRelease()
  409. {
  410. return m_pOuterUnknown->Release();
  411. }
  412. HRESULT OuterQueryInterface(REFIID iid, void ** ppvObject)
  413. {
  414. return m_pOuterUnknown->QueryInterface(iid, ppvObject);
  415. }
  416. void SetVoid(void*) {}
  417. void InternalFinalConstructAddRef() {}
  418. void InternalFinalConstructRelease()
  419. {
  420. _ASSERTE(m_dwRef == 0);
  421. }
  422. // If this assert occurs, your object has probably been deleted
  423. // Try using DECLARE_PROTECT_FINAL_CONSTRUCT()
  424. static HRESULT WINAPI _Break(void* pv, REFIID iid, void** ppvObject, DWORD_PTR dw);
  425. static HRESULT WINAPI _NoInterface(void* pv, REFIID iid, void** ppvObject, DWORD_PTR dw);
  426. static HRESULT WINAPI _Creator(void* pv, REFIID iid, void** ppvObject, DWORD_PTR dw);
  427. static HRESULT WINAPI _Delegate(void* pv, REFIID iid, void** ppvObject, DWORD_PTR dw);
  428. static HRESULT WINAPI _Chain(void* pv, REFIID iid, void** ppvObject, DWORD_PTR dw);
  429. static HRESULT WINAPI _Cache(void* pv, REFIID iid, void** ppvObject, DWORD_PTR dw);
  430. union
  431. {
  432. long m_dwRef;
  433. IUnknown* m_pOuterUnknown;
  434. };
  435. };
  436. template <class ThreadModel>
  437. class CComObjectRootEx : public CComObjectRootBase
  438. {
  439. public:
  440. typedef ThreadModel _ThreadModel;
  441. typedef _ThreadModel::AutoCriticalSection _CritSec;
  442. ULONG InternalAddRef()
  443. {
  444. _ASSERTE(m_dwRef != -1L);
  445. return _ThreadModel::Increment(&m_dwRef);
  446. }
  447. ULONG InternalRelease()
  448. {
  449. return _ThreadModel::Decrement(&m_dwRef);
  450. }
  451. #ifdef _ATL_DEBUG_REFCOUNT
  452. ULONG DebugAddRef(long& dw, LPCTSTR lpszClassName)
  453. {
  454. _ThreadModel::Increment(&dw);
  455. ATLTRACE(_T("%s %d>\n"), lpszClassName, dw);
  456. return AddRef();
  457. }
  458. ULONG DebugRelease(long& dw, LPCTSTR lpszClassName)
  459. {
  460. _ThreadModel::Decrement(&dw);
  461. ATLTRACE(_T("%s %d<\n"), lpszClassName, dw);
  462. return Release();
  463. }
  464. virtual ULONG STDMETHODCALLTYPE AddRef( void) = 0;
  465. virtual ULONG STDMETHODCALLTYPE Release( void) = 0;
  466. #endif // _ATL_DEBUG_REFCOUNT
  467. void Lock() {m_critsec.Lock();}
  468. void Unlock() {m_critsec.Unlock();}
  469. private:
  470. _CritSec m_critsec;
  471. };
  472. #if _MSC_VER>1020
  473. template <>
  474. #endif
  475. class CComObjectRootEx<CComSingleThreadModel> : public CComObjectRootBase
  476. {
  477. public:
  478. typedef CComSingleThreadModel _ThreadModel;
  479. typedef _ThreadModel::AutoCriticalSection _CritSec;
  480. ULONG InternalAddRef()
  481. {
  482. _ASSERTE(m_dwRef != -1L);
  483. return _ThreadModel::Increment(&m_dwRef);
  484. }
  485. ULONG InternalRelease()
  486. {
  487. return _ThreadModel::Decrement(&m_dwRef);
  488. }
  489. #ifdef _ATL_DEBUG_REFCOUNT
  490. ULONG DebugAddRef(long& dw, LPCTSTR lpszClassName)
  491. {
  492. _ThreadModel::Increment(&dw);
  493. ATLTRACE(_T("%s %d>\n"), lpszClassName, dw);
  494. return AddRef();
  495. }
  496. ULONG DebugRelease(long& dw, LPCTSTR lpszClassName)
  497. {
  498. _ThreadModel::Decrement(&dw);
  499. ATLTRACE(_T("%s %d<\n"), lpszClassName, dw);
  500. return Release();
  501. }
  502. virtual ULONG STDMETHODCALLTYPE AddRef( void) = 0;
  503. virtual ULONG STDMETHODCALLTYPE Release( void) = 0;
  504. #endif // _ATL_DEBUG_REFCOUNT
  505. void Lock() {}
  506. void Unlock() {}
  507. };
  508. typedef CComObjectRootEx<CComObjectThreadModel> CComObjectRoot;
  509. #if defined(_WINDLL) | defined(_USRDLL)
  510. #define DECLARE_CLASSFACTORY_EX(cf) typedef CComCreator< CComObjectCached< cf > > _ClassFactoryCreatorClass;
  511. #else
  512. // don't let class factory refcount influence lock count
  513. #define DECLARE_CLASSFACTORY_EX(cf) typedef CComCreator< CComObjectNoLock< cf > > _ClassFactoryCreatorClass;
  514. #endif
  515. #define DECLARE_CLASSFACTORY() DECLARE_CLASSFACTORY_EX(CComClassFactory)
  516. #define DECLARE_CLASSFACTORY2(lic) DECLARE_CLASSFACTORY_EX(CComClassFactory2<lic>)
  517. #define DECLARE_CLASSFACTORY_AUTO_THREAD() DECLARE_CLASSFACTORY_EX(CComClassFactoryAutoThread)
  518. #define DECLARE_CLASSFACTORY_SINGLETON(obj) DECLARE_CLASSFACTORY_EX(CComClassFactorySingleton<obj>)
  519. #define DECLARE_OBJECT_DESCRIPTION(x)\
  520. static LPCTSTR WINAPI GetObjectDescription()\
  521. {\
  522. return _T(x);\
  523. }
  524. #define DECLARE_NO_REGISTRY()\
  525. static HRESULT WINAPI UpdateRegistry(BOOL /*bRegister*/)\
  526. {return S_OK;}
  527. #define DECLARE_REGISTRY(class, pid, vpid, nid, flags)\
  528. static HRESULT WINAPI UpdateRegistry(BOOL bRegister)\
  529. {\
  530. return _Module.UpdateRegistryClass(GetObjectCLSID(), pid, vpid, nid,\
  531. flags, bRegister);\
  532. }
  533. #define DECLARE_REGISTRY_RESOURCE(x)\
  534. static HRESULT WINAPI UpdateRegistry(BOOL bRegister)\
  535. {\
  536. return _Module.UpdateRegistryFromResource(_T(#x), bRegister);\
  537. }
  538. #define DECLARE_REGISTRY_RESOURCEID(x)\
  539. static HRESULT WINAPI UpdateRegistry(BOOL bRegister)\
  540. {\
  541. return _Module.UpdateRegistryFromResource(x, bRegister);\
  542. }
  543. //DECLARE_STATIC_* provided for backward compatibility
  544. #ifdef _ATL_STATIC_REGISTRY
  545. #define DECLARE_STATIC_REGISTRY_RESOURCE(x) DECLARE_REGISTRY_RESOURCE(x)
  546. #define DECLARE_STATIC_REGISTRY_RESOURCEID(x) DECLARE_REGISTRY_RESOURCEID(x)
  547. #endif //_ATL_STATIC_REGISTRY
  548. template<class Base> class CComObject; // fwd decl
  549. template <class Owner, class ThreadModel = CComObjectThreadModel>
  550. class CComTearOffObjectBase : public CComObjectRootEx<ThreadModel>
  551. {
  552. public:
  553. typedef Owner _OwnerClass;
  554. CComObject<Owner>* m_pOwner;
  555. CComTearOffObjectBase() {m_pOwner = NULL;}
  556. };
  557. //Base is the user's class that derives from CComObjectRoot and whatever
  558. //interfaces the user wants to support on the object
  559. template <class Base>
  560. class CComObject : public Base
  561. {
  562. public:
  563. typedef Base _BaseClass;
  564. CComObject(void* = NULL)
  565. {
  566. _Module.Lock();
  567. }
  568. // Set refcount to 1 to protect destruction
  569. ~CComObject()
  570. {
  571. m_dwRef = 1L;
  572. FinalRelease();
  573. _Module.Unlock();
  574. }
  575. //If InternalAddRef or InteralRelease is undefined then your class
  576. //doesn't derive from CComObjectRoot
  577. STDMETHOD_(ULONG, AddRef)() {return InternalAddRef();}
  578. STDMETHOD_(ULONG, Release)()
  579. {
  580. ULONG l = InternalRelease();
  581. if (l == 0)
  582. delete this;
  583. return l;
  584. }
  585. //if _InternalQueryInterface is undefined then you forgot BEGIN_COM_MAP
  586. STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
  587. {return _InternalQueryInterface(iid, ppvObject);}
  588. static HRESULT WINAPI CreateInstance(CComObject<Base>** pp);
  589. };
  590. template <class Base>
  591. HRESULT WINAPI CComObject<Base>::CreateInstance(CComObject<Base>** pp)
  592. {
  593. _ASSERTE(pp != NULL);
  594. HRESULT hRes = E_OUTOFMEMORY;
  595. CComObject<Base>* p = NULL;
  596. ATLTRY(p = new CComObject<Base>())
  597. if (p != NULL)
  598. {
  599. p->SetVoid(NULL);
  600. p->InternalFinalConstructAddRef();
  601. hRes = p->FinalConstruct();
  602. p->InternalFinalConstructRelease();
  603. if (hRes != S_OK)
  604. {
  605. delete p;
  606. p = NULL;
  607. }
  608. }
  609. *pp = p;
  610. return hRes;
  611. }
  612. //Base is the user's class that derives from CComObjectRoot and whatever
  613. //interfaces the user wants to support on the object
  614. // CComObjectCached is used primarily for class factories in DLL's
  615. // but it is useful anytime you want to cache an object
  616. template <class Base>
  617. class CComObjectCached : public Base
  618. {
  619. public:
  620. typedef Base _BaseClass;
  621. CComObjectCached(void* = NULL){}
  622. // Set refcount to 1 to protect destruction
  623. ~CComObjectCached(){m_dwRef = 1L; FinalRelease();}
  624. //If InternalAddRef or InteralRelease is undefined then your class
  625. //doesn't derive from CComObjectRoot
  626. STDMETHOD_(ULONG, AddRef)()
  627. {
  628. m_csCached.Lock();
  629. ULONG l = InternalAddRef();
  630. if (m_dwRef == 2)
  631. _Module.Lock();
  632. m_csCached.Unlock();
  633. return l;
  634. }
  635. STDMETHOD_(ULONG, Release)()
  636. {
  637. m_csCached.Lock();
  638. InternalRelease();
  639. ULONG l = m_dwRef;
  640. m_csCached.Unlock();
  641. if (l == 0)
  642. delete this;
  643. else if (l == 1)
  644. _Module.Unlock();
  645. return l;
  646. }
  647. //if _InternalQueryInterface is undefined then you forgot BEGIN_COM_MAP
  648. STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
  649. {return _InternalQueryInterface(iid, ppvObject);}
  650. CComGlobalsThreadModel::AutoCriticalSection m_csCached;
  651. };
  652. //Base is the user's class that derives from CComObjectRoot and whatever
  653. //interfaces the user wants to support on the object
  654. template <class Base>
  655. class CComObjectNoLock : public Base
  656. {
  657. public:
  658. typedef Base _BaseClass;
  659. CComObjectNoLock(void* = NULL){}
  660. // Set refcount to 1 to protect destruction
  661. ~CComObjectNoLock() {m_dwRef = 1L; FinalRelease();}
  662. //If InternalAddRef or InteralRelease is undefined then your class
  663. //doesn't derive from CComObjectRoot
  664. STDMETHOD_(ULONG, AddRef)() {return InternalAddRef();}
  665. STDMETHOD_(ULONG, Release)()
  666. {
  667. ULONG l = InternalRelease();
  668. if (l == 0)
  669. delete this;
  670. return l;
  671. }
  672. //if _InternalQueryInterface is undefined then you forgot BEGIN_COM_MAP
  673. STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
  674. {return _InternalQueryInterface(iid, ppvObject);}
  675. };
  676. // It is possible for Base not to derive from CComObjectRoot
  677. // However, you will need to provide FinalConstruct and InternalQueryInterface
  678. template <class Base>
  679. class CComObjectGlobal : public Base
  680. {
  681. public:
  682. typedef Base _BaseClass;
  683. CComObjectGlobal(void* = NULL){m_hResFinalConstruct = FinalConstruct();}
  684. ~CComObjectGlobal() {FinalRelease();}
  685. STDMETHOD_(ULONG, AddRef)() {return _Module.Lock();}
  686. STDMETHOD_(ULONG, Release)(){return _Module.Unlock();}
  687. STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
  688. {return _InternalQueryInterface(iid, ppvObject);}
  689. HRESULT m_hResFinalConstruct;
  690. };
  691. // It is possible for Base not to derive from CComObjectRoot
  692. // However, you will need to provide FinalConstruct and InternalQueryInterface
  693. template <class Base>
  694. class CComObjectStack : public Base
  695. {
  696. public:
  697. typedef Base _BaseClass;
  698. CComObjectStack(void* = NULL){m_hResFinalConstruct = FinalConstruct();}
  699. ~CComObjectStack() {FinalRelease();}
  700. STDMETHOD_(ULONG, AddRef)() {_ASSERTE(FALSE);return 0;}
  701. STDMETHOD_(ULONG, Release)(){_ASSERTE(FALSE);return 0;}
  702. STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
  703. {_ASSERTE(FALSE);return E_NOINTERFACE;}
  704. HRESULT m_hResFinalConstruct;
  705. };
  706. template <class Base> //Base must be derived from CComObjectRoot
  707. class CComContainedObject : public Base
  708. {
  709. public:
  710. typedef Base _BaseClass;
  711. CComContainedObject(void* pv) {m_pOuterUnknown = (IUnknown*)pv;}
  712. STDMETHOD_(ULONG, AddRef)() {return OuterAddRef();}
  713. STDMETHOD_(ULONG, Release)() {return OuterRelease();}
  714. STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
  715. {return OuterQueryInterface(iid, ppvObject);}
  716. //GetControllingUnknown may be virtual if the Base class has declared
  717. //DECLARE_GET_CONTROLLING_UNKNOWN()
  718. IUnknown* GetControllingUnknown() {return m_pOuterUnknown;}
  719. };
  720. //contained is the user's class that derives from CComObjectRoot and whatever
  721. //interfaces the user wants to support on the object
  722. template <class contained>
  723. class CComAggObject :
  724. public IUnknown,
  725. public CComObjectRootEx< contained::_ThreadModel::ThreadModelNoCS >
  726. {
  727. public:
  728. typedef contained _BaseClass;
  729. CComAggObject(void* pv) : m_contained(pv)
  730. {
  731. _Module.Lock();
  732. }
  733. //If you get a message that this call is ambiguous then you need to
  734. // override it in your class and call each base class' version of this
  735. HRESULT FinalConstruct()
  736. {
  737. CComObjectRootEx<contained::_ThreadModel::ThreadModelNoCS>::FinalConstruct();
  738. return m_contained.FinalConstruct();
  739. }
  740. void FinalRelease()
  741. {
  742. CComObjectRootEx<contained::_ThreadModel::ThreadModelNoCS>::FinalRelease();
  743. m_contained.FinalRelease();
  744. }
  745. // Set refcount to 1 to protect destruction
  746. ~CComAggObject()
  747. {
  748. m_dwRef = 1L;
  749. FinalRelease();
  750. _Module.Unlock();
  751. }
  752. STDMETHOD_(ULONG, AddRef)() {return InternalAddRef();}
  753. STDMETHOD_(ULONG, Release)()
  754. {
  755. ULONG l = InternalRelease();
  756. if (l == 0)
  757. delete this;
  758. return l;
  759. }
  760. STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
  761. {
  762. HRESULT hRes = S_OK;
  763. if (InlineIsEqualUnknown(iid))
  764. {
  765. if (ppvObject == NULL)
  766. return E_POINTER;
  767. *ppvObject = (void*)(IUnknown*)this;
  768. AddRef();
  769. }
  770. else
  771. hRes = m_contained._InternalQueryInterface(iid, ppvObject);
  772. return hRes;
  773. }
  774. CComContainedObject<contained> m_contained;
  775. };
  776. ///////////////////////////////////////////////////////////////////////////////
  777. // CComPolyObject can be either aggregated or not aggregated
  778. template <class contained>
  779. class CComPolyObject :
  780. public IUnknown,
  781. public CComObjectRootEx< contained::_ThreadModel::ThreadModelNoCS >
  782. {
  783. public:
  784. typedef contained _BaseClass;
  785. CComPolyObject(void* pv) : m_contained(pv ? pv : this)
  786. {
  787. _Module.Lock();
  788. }
  789. //If you get a message that this call is ambiguous then you need to
  790. // override it in your class and call each base class' version of this
  791. HRESULT FinalConstruct()
  792. {
  793. CComObjectRootEx<contained::_ThreadModel::ThreadModelNoCS>::FinalConstruct();
  794. return m_contained.FinalConstruct();
  795. }
  796. void FinalRelease()
  797. {
  798. CComObjectRootEx<contained::_ThreadModel::ThreadModelNoCS>::FinalRelease();
  799. m_contained.FinalRelease();
  800. }
  801. // Set refcount to 1 to protect destruction
  802. ~CComPolyObject()
  803. {
  804. m_dwRef = 1L;
  805. FinalRelease();
  806. _Module.Unlock();
  807. }
  808. STDMETHOD_(ULONG, AddRef)() {return InternalAddRef();}
  809. STDMETHOD_(ULONG, Release)()
  810. {
  811. ULONG l = InternalRelease();
  812. if (l == 0)
  813. delete this;
  814. return l;
  815. }
  816. STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
  817. {
  818. HRESULT hRes = S_OK;
  819. if (InlineIsEqualUnknown(iid))
  820. {
  821. if (ppvObject == NULL)
  822. return E_POINTER;
  823. *ppvObject = (void*)(IUnknown*)this;
  824. AddRef();
  825. }
  826. else
  827. hRes = m_contained._InternalQueryInterface(iid, ppvObject);
  828. return hRes;
  829. }
  830. CComContainedObject<contained> m_contained;
  831. };
  832. template <class Base>
  833. class CComTearOffObject : public Base
  834. {
  835. public:
  836. CComTearOffObject(void* pv)
  837. {
  838. _ASSERTE(m_pOwner == NULL);
  839. m_pOwner = reinterpret_cast<CComObject<Base::_OwnerClass>*>(pv);
  840. m_pOwner->AddRef();
  841. }
  842. // Set refcount to 1 to protect destruction
  843. ~CComTearOffObject()
  844. {
  845. m_dwRef = 1L;
  846. FinalRelease();
  847. m_pOwner->Release();
  848. }
  849. STDMETHOD_(ULONG, AddRef)() {return InternalAddRef();}
  850. STDMETHOD_(ULONG, Release)()
  851. {
  852. ULONG l = InternalRelease();
  853. if (l == 0)
  854. delete this;
  855. return l;
  856. }
  857. STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
  858. {
  859. return m_pOwner->QueryInterface(iid, ppvObject);
  860. }
  861. };
  862. template <class contained>
  863. class CComCachedTearOffObject :
  864. public IUnknown,
  865. public CComObjectRootEx<contained::_ThreadModel::ThreadModelNoCS>
  866. {
  867. public:
  868. typedef contained _BaseClass;
  869. CComCachedTearOffObject(void* pv) :
  870. m_contained(((contained::_OwnerClass*)pv)->GetControllingUnknown())
  871. {
  872. _ASSERTE(m_contained.m_pOwner == NULL);
  873. m_contained.m_pOwner = reinterpret_cast<CComObject<contained::_OwnerClass>*>(pv);
  874. }
  875. //If you get a message that this call is ambiguous then you need to
  876. // override it in your class and call each base class' version of this
  877. HRESULT FinalConstruct()
  878. {
  879. CComObjectRootEx<contained::_ThreadModel::ThreadModelNoCS>::FinalConstruct();
  880. return m_contained.FinalConstruct();
  881. }
  882. void FinalRelease()
  883. {
  884. CComObjectRootEx<contained::_ThreadModel::ThreadModelNoCS>::FinalRelease();
  885. m_contained.FinalRelease();
  886. }
  887. // Set refcount to 1 to protect destruction
  888. ~CComCachedTearOffObject(){m_dwRef = 1L; FinalRelease();}
  889. STDMETHOD_(ULONG, AddRef)() {return InternalAddRef();}
  890. STDMETHOD_(ULONG, Release)()
  891. {
  892. ULONG l = InternalRelease();
  893. if (l == 0)
  894. delete this;
  895. return l;
  896. }
  897. STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
  898. {
  899. HRESULT hRes = S_OK;
  900. if (InlineIsEqualUnknown(iid))
  901. {
  902. if (ppvObject == NULL)
  903. return E_POINTER;
  904. *ppvObject = (void*)(IUnknown*)this;
  905. AddRef();
  906. }
  907. else
  908. hRes = m_contained._InternalQueryInterface(iid, ppvObject);
  909. return hRes;
  910. }
  911. CComContainedObject<contained> m_contained;
  912. };
  913. class CComClassFactory :
  914. public IClassFactory,
  915. public CComObjectRootEx<CComGlobalsThreadModel>
  916. {
  917. public:
  918. BEGIN_COM_MAP(CComClassFactory)
  919. COM_INTERFACE_ENTRY(IClassFactory)
  920. END_COM_MAP()
  921. // IClassFactory
  922. STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid, void** ppvObj);
  923. STDMETHOD(LockServer)(BOOL fLock);
  924. // helper
  925. void SetVoid(void* pv)
  926. {
  927. m_pfnCreateInstance = (_ATL_CREATORFUNC*)pv;
  928. }
  929. _ATL_CREATORFUNC* m_pfnCreateInstance;
  930. };
  931. class CComClassFactory2Base :
  932. public IClassFactory2,
  933. public CComObjectRootEx<CComGlobalsThreadModel>
  934. {
  935. public:
  936. BEGIN_COM_MAP(CComClassFactory2Base)
  937. COM_INTERFACE_ENTRY(IClassFactory)
  938. COM_INTERFACE_ENTRY(IClassFactory2)
  939. END_COM_MAP()
  940. // IClassFactory
  941. STDMETHOD(LockServer)(BOOL fLock);
  942. // helper
  943. void SetVoid(void* pv)
  944. {
  945. m_pfnCreateInstance = (_ATL_CREATORFUNC*)pv;
  946. }
  947. _ATL_CREATORFUNC* m_pfnCreateInstance;
  948. };
  949. template <class license>
  950. class CComClassFactory2 : public CComClassFactory2Base, license
  951. {
  952. public:
  953. typedef license _LicenseClass;
  954. typedef CComClassFactory2<license> _ComMapClass;
  955. // IClassFactory
  956. STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter,
  957. REFIID riid, void** ppvObj)
  958. {
  959. _ASSERTE(m_pfnCreateInstance != NULL);
  960. if (ppvObj == NULL)
  961. return E_POINTER;
  962. *ppvObj = NULL;
  963. if (!IsLicenseValid())
  964. return CLASS_E_NOTLICENSED;
  965. if ((pUnkOuter != NULL) && !InlineIsEqualUnknown(riid))
  966. return CLASS_E_NOAGGREGATION;
  967. else
  968. return m_pfnCreateInstance(pUnkOuter, riid, ppvObj);
  969. }
  970. // IClassFactory2
  971. STDMETHOD(CreateInstanceLic)(IUnknown* pUnkOuter, IUnknown* pUnkReserved,
  972. REFIID riid, BSTR bstrKey, void** ppvObject)
  973. {
  974. _ASSERTE(m_pfnCreateInstance != NULL);
  975. if (ppvObject == NULL)
  976. return E_POINTER;
  977. *ppvObject = NULL;
  978. if ( ((bstrKey != NULL) && !VerifyLicenseKey(bstrKey)) ||
  979. ((bstrKey == NULL) && !IsLicenseValid()) )
  980. return CLASS_E_NOTLICENSED;
  981. return m_pfnCreateInstance(pUnkOuter, riid, ppvObject);
  982. }
  983. STDMETHOD(RequestLicKey)(DWORD dwReserved, BSTR* pbstrKey)
  984. {
  985. if (pbstrKey == NULL)
  986. return E_POINTER;
  987. *pbstrKey = NULL;
  988. if (!IsLicenseValid())
  989. return CLASS_E_NOTLICENSED;
  990. return GetLicenseKey(dwReserved,pbstrKey) ? S_OK : E_FAIL;
  991. }
  992. STDMETHOD(GetLicInfo)(LICINFO* pLicInfo)
  993. {
  994. if (pLicInfo == NULL)
  995. return E_POINTER;
  996. pLicInfo->cbLicInfo = sizeof(LICINFO);
  997. pLicInfo->fLicVerified = IsLicenseValid();
  998. BSTR bstr = NULL;
  999. pLicInfo->fRuntimeKeyAvail = GetLicenseKey(0,&bstr);
  1000. ::SysFreeString(bstr);
  1001. return S_OK;
  1002. }
  1003. };
  1004. /////////////////////////////////////////////////////////////////////////////////////////////
  1005. // Thread Pooling class factory
  1006. class CComClassFactoryAutoThread :
  1007. public IClassFactory,
  1008. public CComObjectRootEx<CComGlobalsThreadModel>
  1009. {
  1010. public:
  1011. BEGIN_COM_MAP(CComClassFactoryAutoThread)
  1012. COM_INTERFACE_ENTRY(IClassFactory)
  1013. END_COM_MAP()
  1014. // helper
  1015. void SetVoid(void* pv)
  1016. {
  1017. m_pfnCreateInstance = (_ATL_CREATORFUNC*)pv;
  1018. }
  1019. STDMETHODIMP CComClassFactoryAutoThread::CreateInstance(LPUNKNOWN pUnkOuter,
  1020. REFIID riid, void** ppvObj)
  1021. {
  1022. _ASSERTE(m_pfnCreateInstance != NULL);
  1023. HRESULT hRes = E_POINTER;
  1024. if (ppvObj != NULL)
  1025. {
  1026. *ppvObj = NULL;
  1027. // cannot aggregate across apartments
  1028. _ASSERTE(pUnkOuter == NULL);
  1029. if (pUnkOuter != NULL)
  1030. hRes = CLASS_E_NOAGGREGATION;
  1031. else
  1032. hRes = _Module.CreateInstance(m_pfnCreateInstance, riid, ppvObj);
  1033. }
  1034. return hRes;
  1035. }
  1036. STDMETHODIMP CComClassFactoryAutoThread::LockServer(BOOL fLock)
  1037. {
  1038. if (fLock)
  1039. _Module.Lock();
  1040. else
  1041. _Module.Unlock();
  1042. return S_OK;
  1043. }
  1044. _ATL_CREATORFUNC* m_pfnCreateInstance;
  1045. };
  1046. /////////////////////////////////////////////////////////////////////////////////////////////
  1047. // Singleton Class Factory
  1048. template <class T>
  1049. class CComClassFactorySingleton : public CComClassFactory
  1050. {
  1051. public:
  1052. // IClassFactory
  1053. STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid, void** ppvObj)
  1054. {
  1055. HRESULT hRes = E_POINTER;
  1056. if (ppvObj != NULL)
  1057. {
  1058. // can't ask for anything other than IUnknown when aggregating
  1059. _ASSERTE((pUnkOuter == NULL) || InlineIsEqualUnknown(riid));
  1060. if ((pUnkOuter != NULL) && !InlineIsEqualUnknown(riid))
  1061. hRes = CLASS_E_NOAGGREGATION;
  1062. else
  1063. hRes = m_Obj.QueryInterface(riid, ppvObj);
  1064. }
  1065. return hRes;
  1066. }
  1067. CComObjectGlobal<T> m_Obj;
  1068. };
  1069. template <class T, const CLSID* pclsid>
  1070. class CComCoClass
  1071. {
  1072. public:
  1073. DECLARE_CLASSFACTORY()
  1074. DECLARE_AGGREGATABLE(T)
  1075. typedef T _CoClass;
  1076. static const CLSID& WINAPI GetObjectCLSID() {return *pclsid;}
  1077. static LPCTSTR WINAPI GetObjectDescription() {return NULL;}
  1078. static HRESULT WINAPI Error(LPCOLESTR lpszDesc,
  1079. const IID& iid = GUID_NULL, HRESULT hRes = 0)
  1080. {
  1081. return AtlReportError(GetObjectCLSID(), lpszDesc, iid, hRes);
  1082. }
  1083. static HRESULT WINAPI Error(LPCOLESTR lpszDesc, DWORD dwHelpID,
  1084. LPCOLESTR lpszHelpFile, const IID& iid = GUID_NULL, HRESULT hRes = 0)
  1085. {
  1086. return AtlReportError(GetObjectCLSID(), lpszDesc, dwHelpID, lpszHelpFile,
  1087. iid, hRes);
  1088. }
  1089. static HRESULT WINAPI Error(UINT nID, const IID& iid = GUID_NULL,
  1090. HRESULT hRes = 0, HINSTANCE hInst = _Module.GetResourceInstance())
  1091. {
  1092. return AtlReportError(GetObjectCLSID(), nID, iid, hRes, hInst);
  1093. }
  1094. static HRESULT WINAPI Error(UINT nID, DWORD dwHelpID,
  1095. LPCOLESTR lpszHelpFile, const IID& iid = GUID_NULL,
  1096. HRESULT hRes = 0, HINSTANCE hInst = _Module.GetResourceInstance())
  1097. {
  1098. return AtlReportError(GetObjectCLSID(), nID, dwHelpID, lpszHelpFile,
  1099. iid, hRes, hInst);
  1100. }
  1101. #ifndef OLE2ANSI
  1102. static HRESULT WINAPI Error(LPCSTR lpszDesc,
  1103. const IID& iid = GUID_NULL, HRESULT hRes = 0)
  1104. {
  1105. return AtlReportError(GetObjectCLSID(), lpszDesc, iid, hRes);
  1106. }
  1107. static HRESULT WINAPI Error(LPCSTR lpszDesc, DWORD dwHelpID,
  1108. LPCSTR lpszHelpFile, const IID& iid = GUID_NULL, HRESULT hRes = 0)
  1109. {
  1110. return AtlReportError(GetObjectCLSID(), lpszDesc, dwHelpID,
  1111. lpszHelpFile, iid, hRes);
  1112. }
  1113. #endif
  1114. };
  1115. // ATL doesn't support multiple LCID's at the same time
  1116. // Whatever LCID is queried for first is the one that is used.
  1117. class CComTypeInfoHolder
  1118. {
  1119. // Should be 'protected' but can cause compiler to generate fat code.
  1120. public:
  1121. const GUID* m_pguid;
  1122. const GUID* m_plibid;
  1123. WORD m_wMajor;
  1124. WORD m_wMinor;
  1125. ITypeInfo* m_pInfo;
  1126. long m_dwRef;
  1127. public:
  1128. HRESULT GetTI(LCID lcid, ITypeInfo** ppInfo);
  1129. void AddRef();
  1130. void Release();
  1131. HRESULT GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo** pptinfo);
  1132. HRESULT GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames,
  1133. LCID lcid, DISPID* rgdispid);
  1134. HRESULT Invoke(IDispatch* p, DISPID dispidMember, REFIID riid,
  1135. LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult,
  1136. EXCEPINFO* pexcepinfo, UINT* puArgErr);
  1137. };
  1138. //////////////////////////////////////////////////////////////////////////////
  1139. // IObjectWithSite
  1140. //
  1141. template <class T>
  1142. class ATL_NO_VTABLE IObjectWithSiteImpl
  1143. {
  1144. public:
  1145. // IUnknown
  1146. //
  1147. STDMETHOD(QueryInterface)(REFIID riid, void ** ppvObject) = 0;
  1148. _ATL_DEBUG_ADDREF_RELEASE_IMPL(IObjectWithSiteImpl)
  1149. // IObjectWithSite
  1150. //
  1151. STDMETHOD(SetSite)(IUnknown *pUnkSite)
  1152. {
  1153. ATLTRACE(_T("IObjectWithSiteImpl::SetSite\n"));
  1154. T* pT = static_cast<T*>(this);
  1155. pT->m_spUnkSite = pUnkSite;
  1156. return S_OK;
  1157. }
  1158. STDMETHOD(GetSite)(REFIID riid, void **ppvSite)
  1159. {
  1160. ATLTRACE(_T("IObjectWithSiteImpl::GetSite\n"));
  1161. T* pT = static_cast<T*>(this);
  1162. _ASSERTE(ppvSite);
  1163. HRESULT hRes = E_POINTER;
  1164. if (ppvSite != NULL)
  1165. {
  1166. if (pT->m_spUnkSite)
  1167. hRes = pT->m_spUnkSite->QueryInterface(riid, ppvSite);
  1168. else
  1169. {
  1170. *ppvSite = NULL;
  1171. hRes = E_FAIL;
  1172. }
  1173. }
  1174. return hRes;
  1175. }
  1176. CComPtr<IUnknown> m_spUnkSite;
  1177. };
  1178. /////////////////////////////////////////////////////////////////////////////
  1179. // IDispatchImpl
  1180. template <class T, const IID* piid, const GUID* plibid, WORD wMajor = 1,
  1181. WORD wMinor = 0, class tihclass = CComTypeInfoHolder>
  1182. class ATL_NO_VTABLE IDispatchImpl : public T
  1183. {
  1184. public:
  1185. typedef tihclass _tihclass;
  1186. IDispatchImpl() {_tih.AddRef();}
  1187. ~IDispatchImpl() {_tih.Release();}
  1188. STDMETHOD(GetTypeInfoCount)(UINT* pctinfo)
  1189. {*pctinfo = 1; return S_OK;}
  1190. STDMETHOD(GetTypeInfo)(UINT itinfo, LCID lcid, ITypeInfo** pptinfo)
  1191. {return _tih.GetTypeInfo(itinfo, lcid, pptinfo);}
  1192. STDMETHOD(GetIDsOfNames)(REFIID riid, LPOLESTR* rgszNames, UINT cNames,
  1193. LCID lcid, DISPID* rgdispid)
  1194. {return _tih.GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);}
  1195. STDMETHOD(Invoke)(DISPID dispidMember, REFIID riid,
  1196. LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult,
  1197. EXCEPINFO* pexcepinfo, UINT* puArgErr)
  1198. {return _tih.Invoke((IDispatch*)this, dispidMember, riid, lcid,
  1199. wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);}
  1200. protected:
  1201. static _tihclass _tih;
  1202. static HRESULT GetTI(LCID lcid, ITypeInfo** ppInfo)
  1203. {return _tih.GetTI(lcid, ppInfo);}
  1204. };
  1205. template <class T, const IID* piid, const GUID* plibid, WORD wMajor,
  1206. WORD wMinor, class tihclass>
  1207. IDispatchImpl<T, piid, plibid, wMajor, wMinor, tihclass>::_tihclass
  1208. IDispatchImpl<T, piid, plibid, wMajor, wMinor, tihclass>::_tih =
  1209. {piid, plibid, wMajor, wMinor, NULL, 0};
  1210. /////////////////////////////////////////////////////////////////////////////
  1211. // IProvideClassInfoImpl
  1212. template <const CLSID* pcoclsid, const IID* psrcid, const GUID* plibid,
  1213. WORD wMajor = 1, WORD wMinor = 0, class tihclass = CComTypeInfoHolder>
  1214. class ATL_NO_VTABLE IProvideClassInfo2Impl : public IProvideClassInfo2
  1215. {
  1216. public:
  1217. typedef tihclass _tihclass;
  1218. IProvideClassInfo2Impl() {_tih.AddRef();}
  1219. ~IProvideClassInfo2Impl() {_tih.Release();}
  1220. STDMETHOD(GetClassInfo)(ITypeInfo** pptinfo)
  1221. {
  1222. return _tih.GetTypeInfo(0, LANG_NEUTRAL, pptinfo);
  1223. }
  1224. STDMETHOD(GetGUID)(DWORD dwGuidKind, GUID* pGUID)
  1225. {
  1226. if (pGUID == NULL)
  1227. return E_POINTER;
  1228. if (dwGuidKind == GUIDKIND_DEFAULT_SOURCE_DISP_IID && psrcid)
  1229. {
  1230. *pGUID = *psrcid;
  1231. return S_OK;
  1232. }
  1233. *pGUID = GUID_NULL;
  1234. return E_FAIL;
  1235. }
  1236. protected:
  1237. static _tihclass _tih;
  1238. };
  1239. template <const CLSID* pcoclsid, const IID* psrcid, const GUID* plibid,
  1240. WORD wMajor, WORD wMinor, class tihclass>
  1241. IProvideClassInfo2Impl<pcoclsid, psrcid, plibid, wMajor, wMinor, tihclass>::_tihclass
  1242. IProvideClassInfo2Impl<pcoclsid, psrcid, plibid, wMajor, wMinor, tihclass>::_tih =
  1243. {pcoclsid,plibid, wMajor, wMinor, NULL, 0};
  1244. /////////////////////////////////////////////////////////////////////////////
  1245. // ISupportErrorInfoImpl
  1246. template <const IID* piid>
  1247. class ATL_NO_VTABLE ISupportErrorInfoImpl : public ISupportErrorInfo
  1248. {
  1249. public:
  1250. STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid)\
  1251. {return (InlineIsEqualGUID(riid,*piid)) ? S_OK : S_FALSE;}
  1252. };
  1253. /////////////////////////////////////////////////////////////////////////////
  1254. // CComEnumImpl
  1255. // These _CopyXXX classes are used with enumerators in order to control
  1256. // how enumerated items are initialized, copied, and deleted
  1257. // Default is shallow copy with no special init or cleanup
  1258. template <class T>
  1259. class _Copy
  1260. {
  1261. public:
  1262. static void copy(T* p1, T* p2) {memcpy(p1, p2, sizeof(T));}
  1263. static void init(T*) {}
  1264. static void destroy(T*) {}
  1265. };
  1266. #if _MSC_VER>1020
  1267. template<>
  1268. #endif
  1269. class _Copy<VARIANT>
  1270. {
  1271. public:
  1272. static void copy(VARIANT* p1, VARIANT* p2) {VariantCopy(p1, p2);}
  1273. static void init(VARIANT* p) {VariantInit(p);}
  1274. static void destroy(VARIANT* p) {VariantClear(p);}
  1275. };
  1276. #if _MSC_VER>1020
  1277. template<>
  1278. #endif
  1279. class _Copy<LPOLESTR>
  1280. {
  1281. public:
  1282. static void copy(LPOLESTR* p1, LPOLESTR* p2)
  1283. {
  1284. (*p1) = (LPOLESTR)CoTaskMemAlloc(sizeof(OLECHAR)*(ocslen(*p2)+1));
  1285. ocscpy(*p1,*p2);
  1286. }
  1287. static void init(LPOLESTR* p) {*p = NULL;}
  1288. static void destroy(LPOLESTR* p) { CoTaskMemFree(*p);}
  1289. };
  1290. #if _MSC_VER>1020
  1291. template<>
  1292. #endif
  1293. class _Copy<OLEVERB>
  1294. {
  1295. public:
  1296. static void copy(OLEVERB* p1, OLEVERB* p2)
  1297. {
  1298. *p1 = *p2;
  1299. if (p1->lpszVerbName == NULL)
  1300. return;
  1301. p1->lpszVerbName = (LPOLESTR)CoTaskMemAlloc(sizeof(OLECHAR)*(ocslen(p2->lpszVerbName)+1));
  1302. ocscpy(p1->lpszVerbName,p2->lpszVerbName);
  1303. }
  1304. static void init(OLEVERB* p) { p->lpszVerbName = NULL;}
  1305. static void destroy(OLEVERB* p) { if (p->lpszVerbName) CoTaskMemFree(p->lpszVerbName);}
  1306. };
  1307. #if _MSC_VER>1020
  1308. template<>
  1309. #endif
  1310. class _Copy<CONNECTDATA>
  1311. {
  1312. public:
  1313. static void copy(CONNECTDATA* p1, CONNECTDATA* p2)
  1314. {
  1315. *p1 = *p2;
  1316. if (p1->pUnk)
  1317. p1->pUnk->AddRef();
  1318. }
  1319. static void init(CONNECTDATA* ) {}
  1320. static void destroy(CONNECTDATA* p) {if (p->pUnk) p->pUnk->Release();}
  1321. };
  1322. template <class T>
  1323. class _CopyInterface
  1324. {
  1325. public:
  1326. static void copy(T** p1, T** p2)
  1327. {*p1 = *p2;if (*p1) (*p1)->AddRef();}
  1328. static void init(T** ) {}
  1329. static void destroy(T** p) {if (*p) (*p)->Release();}
  1330. };
  1331. template<class T>
  1332. class ATL_NO_VTABLE CComIEnum : public IUnknown
  1333. {
  1334. public:
  1335. STDMETHOD(Next)(ULONG celt, T* rgelt, ULONG* pceltFetched) = 0;
  1336. STDMETHOD(Skip)(ULONG celt) = 0;
  1337. STDMETHOD(Reset)(void) = 0;
  1338. STDMETHOD(Clone)(CComIEnum<T>** ppEnum) = 0;
  1339. };
  1340. enum CComEnumFlags
  1341. {
  1342. //see FlagBits in CComEnumImpl
  1343. AtlFlagNoCopy = 0,
  1344. AtlFlagTakeOwnership = 2,
  1345. AtlFlagCopy = 3 // copy implies ownership
  1346. };
  1347. template <class Base, const IID* piid, class T, class Copy>
  1348. class ATL_NO_VTABLE CComEnumImpl : public Base
  1349. {
  1350. public:
  1351. CComEnumImpl() {m_begin = m_end = m_iter = NULL; m_dwFlags = 0; m_pUnk = NULL;}
  1352. ~CComEnumImpl();
  1353. STDMETHOD(Next)(ULONG celt, T* rgelt, ULONG* pceltFetched);
  1354. STDMETHOD(Skip)(ULONG celt);
  1355. STDMETHOD(Reset)(void){m_iter = m_begin;return S_OK;}
  1356. STDMETHOD(Clone)(Base** ppEnum);
  1357. HRESULT Init(T* begin, T* end, IUnknown* pUnk,
  1358. CComEnumFlags flags = AtlFlagNoCopy);
  1359. IUnknown* m_pUnk;
  1360. T* m_begin;
  1361. T* m_end;
  1362. T* m_iter;
  1363. DWORD m_dwFlags;
  1364. protected:
  1365. enum FlagBits
  1366. {
  1367. BitCopy=1,
  1368. BitOwn=2
  1369. };
  1370. };
  1371. template <class Base, const IID* piid, class T, class Copy>
  1372. CComEnumImpl<Base, piid, T, Copy>::~CComEnumImpl()
  1373. {
  1374. if (m_dwFlags & BitOwn)
  1375. {
  1376. for (T* p = m_begin; p != m_end; p++)
  1377. Copy::destroy(p);
  1378. delete [] m_begin;
  1379. }
  1380. if (m_pUnk)
  1381. m_pUnk->Release();
  1382. }
  1383. template <class Base, const IID* piid, class T, class Copy>
  1384. STDMETHODIMP CComEnumImpl<Base, piid, T, Copy>::Next(ULONG celt, T* rgelt,
  1385. ULONG* pceltFetched)
  1386. {
  1387. if (pceltFetched)
  1388. *pceltFetched = 0;
  1389. if (rgelt == NULL || (celt != 1 && pceltFetched == NULL))
  1390. return E_POINTER;
  1391. if (m_begin == NULL || m_end == NULL || m_iter == NULL)
  1392. return E_FAIL;
  1393. if (!celt)
  1394. return E_INVALIDARG;
  1395. ULONG nRem = (ULONG)(m_end - m_iter);
  1396. HRESULT hRes = S_OK;
  1397. if (nRem < celt)
  1398. hRes = S_FALSE;
  1399. ULONG nMin = min(celt, nRem);
  1400. if (pceltFetched != NULL)
  1401. *pceltFetched = nMin;
  1402. while(nMin--)
  1403. Copy::copy(rgelt++, m_iter++);
  1404. return hRes;
  1405. }
  1406. template <class Base, const IID* piid, class T, class Copy>
  1407. STDMETHODIMP CComEnumImpl<Base, piid, T, Copy>::Skip(ULONG celt)
  1408. {
  1409. if (!celt)
  1410. return E_INVALIDARG;
  1411. ULONG nRem = (ULONG)(m_end - m_iter);
  1412. if (celt <= nRem) {
  1413. m_iter += celt;
  1414. return S_OK;
  1415. }
  1416. m_iter = m_end;
  1417. return S_FALSE;
  1418. }
  1419. template <class Base, const IID* piid, class T, class Copy>
  1420. STDMETHODIMP CComEnumImpl<Base, piid, T, Copy>::Clone(Base** ppEnum)
  1421. {
  1422. typedef CComObject<CComEnum<Base, piid, T, Copy> > _class;
  1423. HRESULT hRes = E_POINTER;
  1424. if (ppEnum != NULL)
  1425. {
  1426. _class* p = NULL;
  1427. ATLTRY(p = new _class)
  1428. if (p == NULL)
  1429. {
  1430. *ppEnum = NULL;
  1431. hRes = E_OUTOFMEMORY;
  1432. }
  1433. else
  1434. {
  1435. // If the data is a copy then we need to keep "this" object around
  1436. hRes = p->Init(m_begin, m_end, (m_dwFlags & BitCopy) ? this : m_pUnk);
  1437. if (FAILED(hRes))
  1438. delete p;
  1439. else
  1440. {
  1441. p->m_iter = m_iter;
  1442. hRes = p->_InternalQueryInterface(*piid, (void**)ppEnum);
  1443. if (FAILED(hRes))
  1444. delete p;
  1445. }
  1446. }
  1447. }
  1448. return hRes;
  1449. }
  1450. template <class Base, const IID* piid, class T, class Copy>
  1451. HRESULT CComEnumImpl<Base, piid, T, Copy>::Init(T* begin, T* end, IUnknown* pUnk,
  1452. CComEnumFlags flags)
  1453. {
  1454. if (flags == AtlFlagCopy)
  1455. {
  1456. _ASSERTE(m_begin == NULL); //Init called twice?
  1457. ATLTRY(m_begin = new T[int(end-begin)])
  1458. m_iter = m_begin;
  1459. if (m_begin == NULL)
  1460. return E_OUTOFMEMORY;
  1461. for (T* i=begin; i != end; i++)
  1462. {
  1463. Copy::init(m_iter);
  1464. Copy::copy(m_iter++, i);
  1465. }
  1466. m_end = m_begin + (end-begin);
  1467. }
  1468. else
  1469. {
  1470. m_begin = begin;
  1471. m_end = end;
  1472. }
  1473. m_pUnk = pUnk;
  1474. if (m_pUnk)
  1475. m_pUnk->AddRef();
  1476. m_iter = m_begin;
  1477. m_dwFlags = flags;
  1478. return S_OK;
  1479. }
  1480. template <class Base, const IID* piid, class T, class Copy, class ThreadModel = CComObjectThreadModel>
  1481. class ATL_NO_VTABLE CComEnum :
  1482. public CComEnumImpl<Base, piid, T, Copy>,
  1483. public CComObjectRootEx< ThreadModel >
  1484. {
  1485. public:
  1486. typedef CComEnum<Base, piid, T, Copy > _CComEnum;
  1487. typedef CComEnumImpl<Base, piid, T, Copy > _CComEnumBase;
  1488. BEGIN_COM_MAP(_CComEnum)
  1489. COM_INTERFACE_ENTRY_IID(*piid, _CComEnumBase)
  1490. END_COM_MAP()
  1491. };
  1492. #ifndef _ATL_NO_CONNECTION_POINTS
  1493. /////////////////////////////////////////////////////////////////////////////
  1494. // Connection Points
  1495. struct _ATL_CONNMAP_ENTRY
  1496. {
  1497. DWORD_PTR dwOffset;
  1498. };
  1499. // We want the offset of the connection point relative to the connection
  1500. // point container base class
  1501. #define BEGIN_CONNECTION_POINT_MAP(x)\
  1502. typedef x _atl_conn_classtype;\
  1503. static const _ATL_CONNMAP_ENTRY* GetConnMap(int* pnEntries) {\
  1504. static const _ATL_CONNMAP_ENTRY _entries[] = {
  1505. // CONNECTION_POINT_ENTRY computes the offset of the connection point to the
  1506. // IConnectionPointContainer interface
  1507. #define CONNECTION_POINT_ENTRY(iid){LONG(offsetofclass(_ICPLocator<&iid>, _atl_conn_classtype)-\
  1508. offsetofclass(IConnectionPointContainerImpl<_atl_conn_classtype>, _atl_conn_classtype))},
  1509. #define END_CONNECTION_POINT_MAP() {(DWORD_PTR)-1} }; \
  1510. if (pnEntries) *pnEntries = sizeof(_entries)/sizeof(_ATL_CONNMAP_ENTRY) - 1; \
  1511. return _entries;}
  1512. #ifndef _DEFAULT_VECTORLENGTH
  1513. #define _DEFAULT_VECTORLENGTH 4
  1514. #endif
  1515. template <unsigned int nMaxSize>
  1516. class CComUnkArray
  1517. {
  1518. public:
  1519. CComUnkArray()
  1520. {
  1521. memset(m_arr, 0, sizeof(IUnknown*)*nMaxSize);
  1522. }
  1523. DWORD Add(IUnknown* pUnk);
  1524. BOOL Remove(DWORD dwCookie);
  1525. DWORD WINAPI GetCookie(IUnknown** pp)
  1526. {
  1527. ULONG iIndex;
  1528. iIndex = ULONG( pp-begin() );
  1529. return iIndex+1;
  1530. }
  1531. IUnknown* WINAPI GetUnknown(DWORD dwCookie)
  1532. {
  1533. if( dwCookie == 0 )
  1534. {
  1535. return( NULL );
  1536. }
  1537. ULONG iIndex = dwCookie-1;
  1538. return( begin()[iIndex] );
  1539. }
  1540. IUnknown** begin()
  1541. {
  1542. return &m_arr[0];
  1543. }
  1544. IUnknown** end()
  1545. {
  1546. return &m_arr[nMaxSize];
  1547. }
  1548. protected:
  1549. IUnknown* m_arr[nMaxSize];
  1550. };
  1551. template <unsigned int nMaxSize>
  1552. inline DWORD CComUnkArray<nMaxSize>::Add(IUnknown* pUnk)
  1553. {
  1554. for (IUnknown** pp = begin();pp<end();pp++)
  1555. {
  1556. if (*pp == NULL)
  1557. {
  1558. *pp = pUnk;
  1559. return (DWORD)((pp-begin())+1); // return cookie
  1560. }
  1561. }
  1562. // If this fires then you need a larger array
  1563. _ASSERTE(0);
  1564. return 0;
  1565. }
  1566. template <unsigned int nMaxSize>
  1567. inline BOOL CComUnkArray<nMaxSize>::Remove(DWORD dwCookie)
  1568. {
  1569. ULONG iIndex = dwCookie-1;
  1570. if (iIndex >= nMaxSize)
  1571. {
  1572. return FALSE;
  1573. }
  1574. begin()[iIndex] = NULL;
  1575. return TRUE;
  1576. }
  1577. #if _MSC_VER>1020
  1578. template<>
  1579. #endif
  1580. class CComUnkArray<1>
  1581. {
  1582. public:
  1583. CComUnkArray()
  1584. {
  1585. m_arr[0] = NULL;
  1586. }
  1587. DWORD Add(IUnknown* pUnk)
  1588. {
  1589. if (m_arr[0] != NULL)
  1590. {
  1591. // If this fires then you need a larger array
  1592. _ASSERTE(0);
  1593. return 0;
  1594. }
  1595. m_arr[0] = pUnk;
  1596. return 1;
  1597. }
  1598. BOOL Remove(DWORD dwCookie)
  1599. {
  1600. if (dwCookie != 1)
  1601. return FALSE;
  1602. m_arr[0] = NULL;
  1603. return TRUE;
  1604. }
  1605. DWORD WINAPI GetCookie(IUnknown** pp)
  1606. {
  1607. pp;
  1608. return 1;
  1609. }
  1610. IUnknown* WINAPI GetUnknown(DWORD dwCookie)
  1611. {
  1612. if( dwCookie == 0 )
  1613. {
  1614. return( NULL );
  1615. }
  1616. return( *begin() );
  1617. }
  1618. IUnknown** begin()
  1619. {
  1620. return &m_arr[0];
  1621. }
  1622. IUnknown** end()
  1623. {
  1624. return (&m_arr[0])+1;
  1625. }
  1626. protected:
  1627. IUnknown* m_arr[1];
  1628. };
  1629. class CComDynamicUnkArray
  1630. {
  1631. public:
  1632. CComDynamicUnkArray()
  1633. {
  1634. m_nSize = 0;
  1635. m_ppUnk = NULL;
  1636. }
  1637. ~CComDynamicUnkArray()
  1638. {
  1639. if (m_nSize > 1)
  1640. free(m_ppUnk);
  1641. }
  1642. DWORD Add(IUnknown* pUnk);
  1643. BOOL Remove(DWORD dwCookie);
  1644. DWORD WINAPI GetCookie(IUnknown** pp)
  1645. {
  1646. ULONG iIndex;
  1647. iIndex = ULONG( pp-begin() );
  1648. return iIndex+1;
  1649. }
  1650. IUnknown* WINAPI GetUnknown(DWORD dwCookie)
  1651. {
  1652. if( dwCookie == 0 )
  1653. {
  1654. return( NULL );
  1655. }
  1656. ULONG iIndex = dwCookie-1;
  1657. return begin()[iIndex];
  1658. }
  1659. IUnknown** begin()
  1660. {
  1661. return (m_nSize < 2) ? &m_pUnk : m_ppUnk;
  1662. }
  1663. IUnknown** end()
  1664. {
  1665. return (m_nSize < 2) ? (&m_pUnk)+m_nSize : &m_ppUnk[m_nSize];
  1666. }
  1667. protected:
  1668. union
  1669. {
  1670. IUnknown** m_ppUnk;
  1671. IUnknown* m_pUnk;
  1672. };
  1673. int m_nSize;
  1674. };
  1675. template <const IID* piid>
  1676. class ATL_NO_VTABLE _ICPLocator
  1677. {
  1678. //this method needs a different name than QueryInterface
  1679. STDMETHOD(_LocCPQueryInterface)(REFIID riid, void ** ppvObject) = 0;
  1680. };
  1681. template <class T, const IID* piid, class CDV = CComDynamicUnkArray >
  1682. class ATL_NO_VTABLE IConnectionPointImpl : public _ICPLocator<piid>
  1683. {
  1684. typedef CComEnum<IEnumConnections, &IID_IEnumConnections, CONNECTDATA,
  1685. _Copy<CONNECTDATA> > CComEnumConnections;
  1686. typedef CDV _CDV;
  1687. public:
  1688. ~IConnectionPointImpl();
  1689. STDMETHOD(_LocCPQueryInterface)(REFIID riid, void ** ppvObject)
  1690. {
  1691. if (ppvObject == NULL)
  1692. return E_POINTER;
  1693. if (InlineIsEqualGUID(riid, IID_IConnectionPoint) || InlineIsEqualGUID(riid, IID_IUnknown))
  1694. {
  1695. *ppvObject = this;
  1696. #ifdef _ATL_DEBUG_REFCOUNT
  1697. _DebugAddRef();
  1698. #else
  1699. AddRef();
  1700. #endif
  1701. return S_OK;
  1702. }
  1703. else
  1704. return E_NOINTERFACE;
  1705. }
  1706. _ATL_DEBUG_ADDREF_RELEASE_IMPL(IConnectionPointImpl)
  1707. STDMETHOD(GetConnectionInterface)(IID* piid2)
  1708. {
  1709. if (piid2 == NULL)
  1710. return E_POINTER;
  1711. *piid2 = *piid;
  1712. return S_OK;
  1713. }
  1714. STDMETHOD(GetConnectionPointContainer)(IConnectionPointContainer** ppCPC)
  1715. {
  1716. if (ppCPC == NULL)
  1717. return E_POINTER;
  1718. *ppCPC = reinterpret_cast<IConnectionPointContainer*>(
  1719. (IConnectionPointContainerImpl<T>*)(T*)this);
  1720. (*ppCPC)->AddRef();
  1721. return S_OK;
  1722. }
  1723. STDMETHOD(Advise)(IUnknown* pUnkSink, DWORD* pdwCookie);
  1724. STDMETHOD(Unadvise)(DWORD dwCookie);
  1725. STDMETHOD(EnumConnections)(IEnumConnections** ppEnum);
  1726. CDV m_vec;
  1727. };
  1728. template <class T, const IID* piid, class CDV>
  1729. IConnectionPointImpl<T, piid, CDV>::~IConnectionPointImpl()
  1730. {
  1731. IUnknown** pp = m_vec.begin();
  1732. while (pp < m_vec.end())
  1733. {
  1734. if (*pp != NULL)
  1735. (*pp)->Release();
  1736. pp++;
  1737. }
  1738. }
  1739. template <class T, const IID* piid, class CDV>
  1740. STDMETHODIMP IConnectionPointImpl<T, piid, CDV>::Advise(IUnknown* pUnkSink,
  1741. DWORD* pdwCookie)
  1742. {
  1743. T* pT = (T*)this;
  1744. IUnknown* p;
  1745. HRESULT hRes = S_OK;
  1746. if (pdwCookie == NULL)
  1747. return E_POINTER;
  1748. else
  1749. *pdwCookie = 0;
  1750. if (pUnkSink == NULL)
  1751. return E_POINTER;
  1752. IID iid;
  1753. GetConnectionInterface(&iid);
  1754. hRes = pUnkSink->QueryInterface(iid, (void**)&p);
  1755. if (SUCCEEDED(hRes))
  1756. {
  1757. pT->Lock();
  1758. *pdwCookie = m_vec.Add(p);
  1759. hRes = (*pdwCookie != NULL) ? S_OK : CONNECT_E_ADVISELIMIT;
  1760. pT->Unlock();
  1761. if (hRes != S_OK)
  1762. {
  1763. *pdwCookie = 0;
  1764. p->Release();
  1765. }
  1766. }
  1767. else if (hRes == E_NOINTERFACE)
  1768. hRes = CONNECT_E_CANNOTCONNECT;
  1769. return hRes;
  1770. }
  1771. template <class T, const IID* piid, class CDV>
  1772. STDMETHODIMP IConnectionPointImpl<T, piid, CDV>::Unadvise(DWORD dwCookie)
  1773. {
  1774. T* pT = (T*)this;
  1775. pT->Lock();
  1776. IUnknown* p = m_vec.GetUnknown(dwCookie);
  1777. HRESULT hRes = m_vec.Remove(dwCookie) ? S_OK : CONNECT_E_NOCONNECTION;
  1778. pT->Unlock();
  1779. if (hRes == S_OK && p != NULL)
  1780. p->Release();
  1781. return hRes;
  1782. }
  1783. template <class T, const IID* piid, class CDV>
  1784. STDMETHODIMP IConnectionPointImpl<T, piid, CDV>::EnumConnections(
  1785. IEnumConnections** ppEnum)
  1786. {
  1787. if (ppEnum == NULL)
  1788. return E_POINTER;
  1789. *ppEnum = NULL;
  1790. CComObject<CComEnumConnections>* pEnum = NULL;
  1791. ATLTRY(pEnum = new CComObject<CComEnumConnections>)
  1792. if (pEnum == NULL)
  1793. return E_OUTOFMEMORY;
  1794. T* pT = (T*)this;
  1795. pT->Lock();
  1796. CONNECTDATA* pcd = NULL;
  1797. ATLTRY(pcd = new CONNECTDATA[int(m_vec.end()-m_vec.begin())])
  1798. if (pcd == NULL)
  1799. {
  1800. delete pEnum;
  1801. pT->Unlock();
  1802. return E_OUTOFMEMORY;
  1803. }
  1804. CONNECTDATA* pend = pcd;
  1805. // Copy the valid CONNECTDATA's
  1806. for (IUnknown** pp = m_vec.begin();pp<m_vec.end();pp++)
  1807. {
  1808. if (*pp != NULL)
  1809. {
  1810. (*pp)->AddRef();
  1811. pend->pUnk = *pp;
  1812. pend->dwCookie = m_vec.GetCookie(pp);
  1813. pend++;
  1814. }
  1815. }
  1816. // don't copy the data, but transfer ownership to it
  1817. pEnum->Init(pcd, pend, NULL, AtlFlagTakeOwnership);
  1818. pT->Unlock();
  1819. HRESULT hRes = pEnum->_InternalQueryInterface(IID_IEnumConnections, (void**)ppEnum);
  1820. if (FAILED(hRes))
  1821. delete pEnum;
  1822. return hRes;
  1823. }
  1824. /////////////////////////////////////////////////////////////////////////////
  1825. // IConnectionPointContainerImpl
  1826. template <class T>
  1827. class ATL_NO_VTABLE IConnectionPointContainerImpl
  1828. {
  1829. typedef CComEnum<IEnumConnectionPoints,
  1830. &IID_IEnumConnectionPoints, IConnectionPoint*,
  1831. _CopyInterface<IConnectionPoint> >
  1832. CComEnumConnectionPoints;
  1833. public:
  1834. // IUnknown
  1835. //
  1836. STDMETHOD(QueryInterface)(REFIID riid, void ** ppvObject) = 0;
  1837. _ATL_DEBUG_ADDREF_RELEASE_IMPL(IConnectionPointContainerImpl)
  1838. STDMETHOD(EnumConnectionPoints)(IEnumConnectionPoints** ppEnum)
  1839. {
  1840. if (ppEnum == NULL)
  1841. return E_POINTER;
  1842. *ppEnum = NULL;
  1843. CComEnumConnectionPoints* pEnum = NULL;
  1844. ATLTRY(pEnum = new CComObject<CComEnumConnectionPoints>)
  1845. if (pEnum == NULL)
  1846. return E_OUTOFMEMORY;
  1847. int nCPCount;
  1848. const _ATL_CONNMAP_ENTRY* pEntry = T::GetConnMap(&nCPCount);
  1849. // allocate an initialize a vector of connection point object pointers
  1850. IConnectionPoint** ppCP = (IConnectionPoint**)alloca(sizeof(IConnectionPoint*)*nCPCount);
  1851. int i = 0;
  1852. while (pEntry->dwOffset != (DWORD_PTR)-1)
  1853. {
  1854. ppCP[i++] = (IConnectionPoint*)((ULONG_PTR)this+pEntry->dwOffset);
  1855. pEntry++;
  1856. }
  1857. // copy the pointers: they will AddRef this object
  1858. HRESULT hRes = pEnum->Init((IConnectionPoint**)&ppCP[0],
  1859. (IConnectionPoint**)&ppCP[nCPCount],
  1860. reinterpret_cast<IConnectionPointContainer*>(this), AtlFlagCopy);
  1861. if (FAILED(hRes))
  1862. {
  1863. delete pEnum;
  1864. return hRes;
  1865. }
  1866. hRes = pEnum->QueryInterface(IID_IEnumConnectionPoints, (void**)ppEnum);
  1867. if (FAILED(hRes))
  1868. delete pEnum;
  1869. return hRes;
  1870. }
  1871. STDMETHOD(FindConnectionPoint)(REFIID riid, IConnectionPoint** ppCP)
  1872. {
  1873. if (ppCP == NULL)
  1874. return E_POINTER;
  1875. *ppCP = NULL;
  1876. HRESULT hRes = CONNECT_E_NOCONNECTION;
  1877. const _ATL_CONNMAP_ENTRY* pEntry = T::GetConnMap(NULL);
  1878. IID iid;
  1879. while (pEntry->dwOffset != (DWORD_PTR)-1)
  1880. {
  1881. IConnectionPoint* pCP =
  1882. (IConnectionPoint*)((ULONG_PTR)this+pEntry->dwOffset);
  1883. if (SUCCEEDED(pCP->GetConnectionInterface(&iid)) &&
  1884. InlineIsEqualGUID(riid, iid))
  1885. {
  1886. *ppCP = pCP;
  1887. pCP->AddRef();
  1888. hRes = S_OK;
  1889. break;
  1890. }
  1891. pEntry++;
  1892. }
  1893. return hRes;
  1894. }
  1895. };
  1896. #endif //!_ATL_NO_CONNECTION_POINTS
  1897. #pragma pack(pop)
  1898. /////////////////////////////////////////////////////////////////////////////
  1899. // CComAutoThreadModule
  1900. template <class ThreadAllocator>
  1901. inline void CComAutoThreadModule<ThreadAllocator>::Init(_ATL_OBJMAP_ENTRY* p, HINSTANCE h, int nThreads)
  1902. {
  1903. m_nThreads = nThreads;
  1904. m_pApartments = new CComApartment[m_nThreads];
  1905. for (int i = 0; i < nThreads; i++)
  1906. m_pApartments[i].m_hThread = CreateThread(NULL, 0, CComApartment::_Apartment, (void*)&m_pApartments[i], 0, &m_pApartments[i].m_dwThreadID);
  1907. CComApartment::ATL_CREATE_OBJECT = RegisterWindowMessage(_T("ATL_CREATE_OBJECT"));
  1908. CComModule::Init(p, h);
  1909. }
  1910. template <class ThreadAllocator>
  1911. inline LONG CComAutoThreadModule<ThreadAllocator>::Lock()
  1912. {
  1913. LONG l = CComModule::Lock();
  1914. DWORD dwThreadID = GetCurrentThreadId();
  1915. for (int i=0; i < m_nThreads; i++)
  1916. {
  1917. if (m_pApartments[i].m_dwThreadID == dwThreadID)
  1918. {
  1919. m_pApartments[i].Lock();
  1920. break;
  1921. }
  1922. }
  1923. return l;
  1924. }
  1925. template <class ThreadAllocator>
  1926. inline LONG CComAutoThreadModule<ThreadAllocator>::Unlock()
  1927. {
  1928. LONG l = CComModule::Unlock();
  1929. DWORD dwThreadID = GetCurrentThreadId();
  1930. for (int i=0; i < m_nThreads; i++)
  1931. {
  1932. if (m_pApartments[i].m_dwThreadID == dwThreadID)
  1933. {
  1934. m_pApartments[i].Unlock();
  1935. break;
  1936. }
  1937. }
  1938. return l;
  1939. }
  1940. template <class ThreadAllocator>
  1941. HRESULT CComAutoThreadModule<ThreadAllocator>::CreateInstance(void* pfnCreateInstance, REFIID riid, void** ppvObj)
  1942. {
  1943. _ATL_CREATORFUNC* pFunc = (_ATL_CREATORFUNC*) pfnCreateInstance;
  1944. _AtlAptCreateObjData data;
  1945. data.pfnCreateInstance = pFunc;
  1946. data.piid = &riid;
  1947. data.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  1948. data.hRes = S_OK;
  1949. int nThread = m_Allocator.GetThread(m_pApartments, m_nThreads);
  1950. ::PostThreadMessage(m_pApartments[nThread].m_dwThreadID, CComApartment::ATL_CREATE_OBJECT, 0, (LPARAM)&data);
  1951. AtlWaitWithMessageLoop(data.hEvent);
  1952. CloseHandle(data.hEvent);
  1953. if (SUCCEEDED(data.hRes))
  1954. data.hRes = CoGetInterfaceAndReleaseStream(data.pStream, riid, ppvObj);
  1955. return data.hRes;
  1956. }
  1957. template <class ThreadAllocator>
  1958. CComAutoThreadModule<ThreadAllocator>::~CComAutoThreadModule()
  1959. {
  1960. for (int i=0; i < m_nThreads; i++)
  1961. {
  1962. ::PostThreadMessage(m_pApartments[i].m_dwThreadID, WM_QUIT, 0, 0);
  1963. ::WaitForSingleObject(m_pApartments[i].m_hThread, INFINITE);
  1964. }
  1965. delete[] m_pApartments;
  1966. }
  1967. #ifndef ATL_NO_NAMESPACE
  1968. }; //namespace ATL
  1969. #endif
  1970. #endif // __ATLCOM_H__
  1971. /////////////////////////////////////////////////////////////////////////////