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.

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