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.

5771 lines
145 KiB

  1. // This is a part of the Active Template Library.
  2. // Copyright (C) 1996-2001 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. #pragma once
  13. #ifndef _ATL_NO_PRAGMA_WARNINGS
  14. #pragma warning (push)
  15. #pragma warning(disable: 4702) // unreachable code
  16. #pragma warning(disable: 4355) // 'this' used in initializer list
  17. #pragma warning(disable: 4511) // copy constructor could not be generated
  18. #pragma warning(disable: 4512) // assignment operator could not be generated
  19. #endif //!_ATL_NO_PRAGMA_WARNINGS
  20. #ifndef __cplusplus
  21. #error ATL requires C++ compilation (use a .cpp suffix)
  22. #endif
  23. #ifndef __ATLBASE_H__
  24. #error atlcom.h requires atlbase.h to be included first
  25. #endif
  26. //REVIEW: Just to fix VSEE
  27. #pragma push_macro("min")
  28. #pragma push_macro("max")
  29. #undef min
  30. #undef max
  31. #define min(a,b) (((a) < (b)) ? (a) : (b))
  32. #define max(a,b) (((a) > (b)) ? (a) : (b))
  33. #pragma pack(push, _ATL_PACKING)
  34. EXTERN_C const IID IID_ITargetFrame;
  35. #include <atlbase.inl>
  36. #include <limits.h>
  37. namespace ATL
  38. {
  39. #define CComConnectionPointContainerImpl ATL::IConnectionPointContainerImpl
  40. #define CComISupportErrorInfoImpl ATL::ISupportErrorInfoImpl
  41. #define CComProvideClassInfo2Impl ATL::IProvideClassInfoImpl
  42. #define CComDualImpl ATL::IDispatchImpl
  43. #ifdef _ATL_DEBUG_QI
  44. #ifndef _ATL_DEBUG
  45. #define _ATL_DEBUG
  46. #endif // _ATL_DEBUG
  47. #endif // _ATL_DEBUG_QI
  48. #ifdef _ATL_DEBUG_QI
  49. #define _ATLDUMPIID(iid, name, hr) AtlDumpIID(iid, name, hr)
  50. #else
  51. #define _ATLDUMPIID(iid, name, hr) hr
  52. #endif
  53. #define _ATL_DEBUG_ADDREF_RELEASE_IMPL(className)\
  54. virtual ULONG STDMETHODCALLTYPE AddRef(void) = 0;\
  55. virtual ULONG STDMETHODCALLTYPE Release(void) = 0;
  56. /////////////////////////////////////////////////////////////////////////////
  57. // AtlReportError
  58. inline HRESULT WINAPI AtlReportError(const CLSID& clsid, UINT nID, const IID& iid = GUID_NULL,
  59. HRESULT hRes = 0, HINSTANCE hInst = _AtlBaseModule.GetResourceInstance())
  60. {
  61. return AtlSetErrorInfo(clsid, (LPCOLESTR)MAKEINTRESOURCE(nID), 0, NULL, iid, hRes, hInst);
  62. }
  63. inline HRESULT WINAPI AtlReportError(const CLSID& clsid, UINT nID, DWORD dwHelpID,
  64. LPCOLESTR lpszHelpFile, const IID& iid = GUID_NULL, HRESULT hRes = 0,
  65. HINSTANCE hInst = _AtlBaseModule.GetResourceInstance())
  66. {
  67. return AtlSetErrorInfo(clsid, (LPCOLESTR)MAKEINTRESOURCE(nID), dwHelpID,
  68. lpszHelpFile, iid, hRes, hInst);
  69. }
  70. inline HRESULT WINAPI AtlReportError(const CLSID& clsid, LPCSTR lpszDesc,
  71. DWORD dwHelpID, LPCSTR lpszHelpFile, const IID& iid = GUID_NULL, HRESULT hRes = 0)
  72. {
  73. ATLASSERT(lpszDesc != NULL);
  74. USES_CONVERSION;
  75. return AtlSetErrorInfo(clsid, A2COLE(lpszDesc), dwHelpID, A2CW(lpszHelpFile),
  76. iid, hRes, NULL);
  77. }
  78. inline HRESULT WINAPI AtlReportError(const CLSID& clsid, LPCSTR lpszDesc,
  79. const IID& iid = GUID_NULL, HRESULT hRes = 0)
  80. {
  81. ATLASSERT(lpszDesc != NULL);
  82. USES_CONVERSION;
  83. return AtlSetErrorInfo(clsid, A2COLE(lpszDesc), 0, NULL, iid, hRes, NULL);
  84. }
  85. inline HRESULT WINAPI AtlReportError(const CLSID& clsid, LPCOLESTR lpszDesc,
  86. const IID& iid = GUID_NULL, HRESULT hRes = 0)
  87. {
  88. return AtlSetErrorInfo(clsid, lpszDesc, 0, NULL, iid, hRes, NULL);
  89. }
  90. inline HRESULT WINAPI AtlReportError(const CLSID& clsid, LPCOLESTR lpszDesc, DWORD dwHelpID,
  91. LPCOLESTR lpszHelpFile, const IID& iid = GUID_NULL, HRESULT hRes = 0)
  92. {
  93. return AtlSetErrorInfo(clsid, lpszDesc, dwHelpID, lpszHelpFile, iid, hRes, NULL);
  94. }
  95. // Returns the apartment type that the current thread is in. false is returned
  96. // if the thread isn't in an apartment.
  97. inline bool AtlGetApartmentType(DWORD* pApartmentType)
  98. {
  99. HRESULT hr = CoInitialize(NULL);
  100. if (SUCCEEDED(hr))
  101. CoUninitialize();
  102. if (hr == S_FALSE)
  103. {
  104. *pApartmentType = COINIT_APARTMENTTHREADED;
  105. return true;
  106. }
  107. #if ((_WIN32_WINNT >= 0x0400 ) || defined(_WIN32_DCOM))
  108. else
  109. if (hr == RPC_E_CHANGED_MODE)
  110. {
  111. *pApartmentType = COINIT_MULTITHREADED;
  112. return true;
  113. }
  114. #endif
  115. return false;
  116. }
  117. //////////////////////////////////////////////////////////////////////////////
  118. // IPersistImpl
  119. template <class T>
  120. class ATL_NO_VTABLE IPersistImpl : public IPersist
  121. {
  122. public:
  123. STDMETHOD(GetClassID)(CLSID *pClassID)
  124. {
  125. ATLTRACE(atlTraceCOM, 2, _T("IPersistImpl::GetClassID\n"));
  126. if (pClassID == NULL)
  127. return E_FAIL;
  128. *pClassID = T::GetObjectCLSID();
  129. return S_OK;
  130. }
  131. };
  132. //////////////////////////////////////////////////////////////////////////////
  133. // CFakeFirePropNotifyEvent
  134. class CFakeFirePropNotifyEvent
  135. {
  136. public:
  137. static HRESULT FireOnRequestEdit(IUnknown* /*pUnk*/, DISPID /*dispID*/)
  138. {
  139. return S_OK;
  140. }
  141. static HRESULT FireOnChanged(IUnknown* /*pUnk*/, DISPID /*dispID*/)
  142. {
  143. return S_OK;
  144. }
  145. };
  146. typedef CFakeFirePropNotifyEvent _ATL_PROP_NOTIFY_EVENT_CLASS;
  147. //////////////////////////////////////////////////////////////////////////////
  148. // ALT_PROP_VAL_MAP
  149. struct ATL_PROPVALMAP_ENTRY
  150. {
  151. DISPID dispid;
  152. VARIANT val;
  153. LPCOLESTR szDesc;
  154. };
  155. #define BEGIN_PROP_VAL_MAP(theClass) \
  156. static ATL::ATL_PROPVALMAP_ENTRY* GetPropValMap(int *cnt)\
  157. {\
  158. static ATL::ATL_PROPVALMAP_ENTRY pPropMap[] = \
  159. {
  160. #define PROP_VAL_INT(dispid, ival, str) \
  161. {dispid, {VT_I4, 0, 0, 0, ival}, OLESTR(str)},
  162. #define END_PROP_VAL_MAP() \
  163. }; \
  164. if (cnt) \
  165. *cnt = sizeof(pPropMap)/sizeof(pPropMap[0]); \
  166. return pPropMap; \
  167. }
  168. #define DECLARE_EMPTY_PROP_VAL_MAP() \
  169. public: \
  170. static ATL::ATL_PROPVALMAP_ENTRY* GetPropValMap(int *cnt)\
  171. { \
  172. if (cnt) \
  173. *cnt = 0; \
  174. return NULL; \
  175. }
  176. //////////////////////////////////////////////////////////////////////////////
  177. // ATL Persistence
  178. struct ATL_PROPMAP_ENTRY
  179. {
  180. LPCOLESTR szDesc;
  181. DISPID dispid;
  182. const CLSID* pclsidPropPage;
  183. const IID* piidDispatch;
  184. DWORD dwOffsetData;
  185. DWORD dwSizeData;
  186. VARTYPE vt;
  187. };
  188. // This one is DEPRECATED and is used for ATL 2.X controls
  189. // it includes an implicit m_sizeExtent
  190. #define BEGIN_PROPERTY_MAP(theClass) \
  191. __if_not_exists(__ATL_PROP_NOTIFY_EVENT_CLASS) \
  192. { \
  193. typedef ATL::_ATL_PROP_NOTIFY_EVENT_CLASS __ATL_PROP_NOTIFY_EVENT_CLASS; \
  194. } \
  195. typedef theClass _PropMapClass; \
  196. static ATL::ATL_PROPMAP_ENTRY* GetPropertyMap()\
  197. {\
  198. static ATL::ATL_PROPMAP_ENTRY pPropMap[] = \
  199. { \
  200. {OLESTR("_cx"), 0, &CLSID_NULL, NULL, offsetof(_PropMapClass, m_sizeExtent.cx), sizeof(long), VT_UI4}, \
  201. {OLESTR("_cy"), 0, &CLSID_NULL, NULL, offsetof(_PropMapClass, m_sizeExtent.cy), sizeof(long), VT_UI4},
  202. // This one can be used on any type of object, but does not
  203. // include the implicit m_sizeExtent
  204. #define BEGIN_PROP_MAP(theClass) \
  205. __if_not_exists(__ATL_PROP_NOTIFY_EVENT_CLASS) \
  206. { \
  207. typedef ATL::_ATL_PROP_NOTIFY_EVENT_CLASS __ATL_PROP_NOTIFY_EVENT_CLASS; \
  208. } \
  209. typedef theClass _PropMapClass; \
  210. static ATL::ATL_PROPMAP_ENTRY* GetPropertyMap()\
  211. {\
  212. static ATL::ATL_PROPMAP_ENTRY pPropMap[] = \
  213. {
  214. #define PROP_ENTRY(szDesc, dispid, clsid) \
  215. {OLESTR(szDesc), dispid, &clsid, &__uuidof(IDispatch), 0, 0, 0},
  216. #define PROP_ENTRY_EX(szDesc, dispid, clsid, iidDispatch) \
  217. {OLESTR(szDesc), dispid, &clsid, &iidDispatch, 0, 0, 0},
  218. #define PROP_PAGE(clsid) \
  219. {NULL, NULL, &clsid, &IID_NULL, 0, 0, 0},
  220. #define PROP_DATA_ENTRY(szDesc, member, vt) \
  221. {OLESTR(szDesc), 0, &CLSID_NULL, NULL, offsetof(_PropMapClass, member), sizeof(((_PropMapClass*)0)->member), vt},
  222. #define END_PROPERTY_MAP() \
  223. {NULL, 0, NULL, &IID_NULL, 0, 0, 0} \
  224. }; \
  225. return pPropMap; \
  226. }
  227. #define END_PROP_MAP() \
  228. {NULL, 0, NULL, &IID_NULL, 0, 0, 0} \
  229. }; \
  230. return pPropMap; \
  231. }
  232. #ifdef _ATL_DLL
  233. ATLAPI AtlIPersistStreamInit_Load(LPSTREAM pStm, ATL_PROPMAP_ENTRY* pMap, void* pThis, IUnknown* pUnk);
  234. #else
  235. ATLINLINE ATLAPI AtlIPersistStreamInit_Load(LPSTREAM pStm, ATL_PROPMAP_ENTRY* pMap, void* pThis, IUnknown* pUnk)
  236. {
  237. ATLASSERT(pMap != NULL);
  238. HRESULT hr = S_OK;
  239. DWORD dwVer;
  240. hr = pStm->Read(&dwVer, sizeof(DWORD), NULL);
  241. if (FAILED(hr))
  242. return hr;
  243. if (dwVer > _ATL_VER)
  244. return E_FAIL;
  245. CComPtr<IDispatch> pDispatch;
  246. const IID* piidOld = NULL;
  247. for (int i = 0; pMap[i].pclsidPropPage != NULL; i++)
  248. {
  249. if (pMap[i].szDesc == NULL)
  250. continue;
  251. // check if raw data entry
  252. if (pMap[i].dwSizeData != 0)
  253. {
  254. void* pData = (void*) (pMap[i].dwOffsetData + (DWORD_PTR)pThis);
  255. // call CComBSTR::ReadFromStream for BSTRs
  256. if (pMap[i].vt == VT_BSTR)
  257. {
  258. CComBSTR bstrRead;
  259. hr = bstrRead.ReadFromStream(pStm);
  260. (*(BSTR*)pData) = bstrRead.Detach();
  261. }
  262. else
  263. hr = pStm->Read(pData, pMap[i].dwSizeData, NULL);
  264. if (FAILED(hr))
  265. return hr;
  266. continue;
  267. }
  268. CComVariant var;
  269. hr = var.ReadFromStream(pStm);
  270. if (FAILED(hr))
  271. break;
  272. if (pMap[i].piidDispatch != piidOld)
  273. {
  274. pDispatch.Release();
  275. if (FAILED(pUnk->QueryInterface(*pMap[i].piidDispatch, (void**)&pDispatch)))
  276. {
  277. ATLTRACE(atlTraceCOM, 0, _T("Failed to get a dispatch pointer for property #%i\n"), i);
  278. hr = E_FAIL;
  279. break;
  280. }
  281. piidOld = pMap[i].piidDispatch;
  282. }
  283. if (FAILED(pDispatch.PutProperty(pMap[i].dispid, &var)))
  284. {
  285. ATLTRACE(atlTraceCOM, 0, _T("Invoked failed on DISPID %x\n"), pMap[i].dispid);
  286. hr = E_FAIL;
  287. break;
  288. }
  289. }
  290. return hr;
  291. }
  292. #endif //_ATL_DLL
  293. #ifdef _ATL_DLL
  294. ATLAPI AtlIPersistStreamInit_Save(LPSTREAM pStm, BOOL fClearDirty, ATL_PROPMAP_ENTRY* pMap, void* pThis, IUnknown* pUnk);
  295. #else
  296. ATLINLINE ATLAPI AtlIPersistStreamInit_Save(LPSTREAM pStm,
  297. BOOL /* fClearDirty */, ATL_PROPMAP_ENTRY* pMap,
  298. void* pThis, IUnknown* pUnk)
  299. {
  300. ATLASSERT(pMap != NULL);
  301. DWORD dw = _ATL_VER;
  302. HRESULT hr = pStm->Write(&dw, sizeof(DWORD), NULL);
  303. if (FAILED(hr))
  304. return hr;
  305. CComPtr<IDispatch> pDispatch;
  306. const IID* piidOld = NULL;
  307. for (int i = 0; pMap[i].pclsidPropPage != NULL; i++)
  308. {
  309. if (pMap[i].szDesc == NULL)
  310. continue;
  311. // check if raw data entry
  312. if (pMap[i].dwSizeData != 0)
  313. {
  314. void* pData = (void*) (pMap[i].dwOffsetData + (DWORD_PTR)pThis);
  315. // call CComBSTR::WriteToStream for BSTRs
  316. if (pMap[i].vt == VT_BSTR)
  317. {
  318. CComBSTR bstrWrite;
  319. bstrWrite.Attach(*(BSTR*)pData);
  320. hr = bstrWrite.WriteToStream(pStm);
  321. bstrWrite.Detach();
  322. }
  323. else
  324. hr = pStm->Write(pData, pMap[i].dwSizeData, NULL);
  325. if (FAILED(hr))
  326. return hr;
  327. continue;
  328. }
  329. CComVariant var;
  330. if (pMap[i].piidDispatch != piidOld)
  331. {
  332. pDispatch.Release();
  333. if (FAILED(pUnk->QueryInterface(*pMap[i].piidDispatch, (void**)&pDispatch)))
  334. {
  335. ATLTRACE(atlTraceCOM, 0, _T("Failed to get a dispatch pointer for property #%i\n"), i);
  336. hr = E_FAIL;
  337. break;
  338. }
  339. piidOld = pMap[i].piidDispatch;
  340. }
  341. if (FAILED(pDispatch.GetProperty(pMap[i].dispid, &var)))
  342. {
  343. ATLTRACE(atlTraceCOM, 0, _T("Invoked failed on DISPID %x\n"), pMap[i].dispid);
  344. hr = E_FAIL;
  345. break;
  346. }
  347. hr = var.WriteToStream(pStm);
  348. if (FAILED(hr))
  349. break;
  350. }
  351. return hr;
  352. }
  353. #endif //_ATL_DLL
  354. #ifdef _ATL_DLL
  355. ATLAPI AtlIPersistPropertyBag_Load(LPPROPERTYBAG pPropBag, LPERRORLOG pErrorLog, ATL_PROPMAP_ENTRY* pMap, void* pThis, IUnknown* pUnk);
  356. #else
  357. ATLINLINE ATLAPI AtlIPersistPropertyBag_Load(LPPROPERTYBAG pPropBag, LPERRORLOG pErrorLog, ATL_PROPMAP_ENTRY* pMap, void* pThis, IUnknown* pUnk)
  358. {
  359. USES_CONVERSION;
  360. CComPtr<IDispatch> pDispatch;
  361. const IID* piidOld = NULL;
  362. for (int i = 0; pMap[i].pclsidPropPage != NULL; i++)
  363. {
  364. if (pMap[i].szDesc == NULL)
  365. continue;
  366. CComVariant var;
  367. // If raw entry skip it - we don't handle it for property bags just yet
  368. if (pMap[i].dwSizeData != 0)
  369. {
  370. var.vt = pMap[i].vt;
  371. void* pData = (void*) (pMap[i].dwOffsetData + (DWORD_PTR)pThis);
  372. HRESULT hr = pPropBag->Read(pMap[i].szDesc, &var, pErrorLog);
  373. if (SUCCEEDED(hr))
  374. {
  375. // check the type - we only deal with limited set
  376. switch (pMap[i].vt)
  377. {
  378. case VT_UI1:
  379. case VT_I1:
  380. *((BYTE*)pData) = var.bVal;
  381. break;
  382. case VT_BOOL:
  383. *((VARIANT_BOOL*)pData) = var.boolVal;
  384. break;
  385. case VT_I2:
  386. case VT_UI2:
  387. *((short*)pData) = var.iVal;
  388. break;
  389. case VT_I4:
  390. case VT_UI4:
  391. case VT_INT:
  392. case VT_UINT:
  393. *((long*)pData) = var.lVal;
  394. break;
  395. case VT_BSTR:
  396. *((BSTR*)pData) = ::SysAllocString(var.bstrVal);
  397. if (*((BSTR*)pData) == NULL && var.bstrVal != NULL)
  398. return E_OUTOFMEMORY;
  399. break;
  400. }
  401. }
  402. continue;
  403. }
  404. if (pMap[i].piidDispatch != piidOld)
  405. {
  406. pDispatch.Release();
  407. if (FAILED(pUnk->QueryInterface(*pMap[i].piidDispatch, (void**)&pDispatch)))
  408. {
  409. ATLTRACE(atlTraceCOM, 0, _T("Failed to get a dispatch pointer for property #%i\n"), i);
  410. return E_FAIL;
  411. }
  412. piidOld = pMap[i].piidDispatch;
  413. }
  414. if (FAILED(pDispatch.GetProperty(pMap[i].dispid, &var)))
  415. {
  416. ATLTRACE(atlTraceCOM, 0, _T("Invoked failed on DISPID %x\n"), pMap[i].dispid);
  417. return E_FAIL;
  418. }
  419. HRESULT hr = pPropBag->Read(pMap[i].szDesc, &var, pErrorLog);
  420. if (FAILED(hr))
  421. {
  422. if (hr == E_INVALIDARG)
  423. {
  424. ATLTRACE(atlTraceCOM, 0, _T("Property %s not in Bag\n"), OLE2CT(pMap[i].szDesc));
  425. }
  426. else
  427. {
  428. // Many containers return different ERROR values for Member not found
  429. ATLTRACE(atlTraceCOM, 0, _T("Error attempting to read Property %s from PropertyBag \n"), OLE2CT(pMap[i].szDesc));
  430. }
  431. continue;
  432. }
  433. if (FAILED(pDispatch.PutProperty(pMap[i].dispid, &var)))
  434. {
  435. ATLTRACE(atlTraceCOM, 0, _T("Invoked failed on DISPID %x\n"), pMap[i].dispid);
  436. return E_FAIL;
  437. }
  438. }
  439. return S_OK;
  440. }
  441. #endif //_ATL_DLL
  442. #ifdef _ATL_DLL
  443. ATLAPI AtlIPersistPropertyBag_Save(LPPROPERTYBAG pPropBag, BOOL fClearDirty, BOOL fSaveAllProperties, ATL_PROPMAP_ENTRY* pMap, void* pThis, IUnknown* pUnk);
  444. #else
  445. ATLINLINE ATLAPI AtlIPersistPropertyBag_Save(LPPROPERTYBAG pPropBag,
  446. BOOL /* fClearDirty */, BOOL /* fSaveAllProperties */,
  447. ATL_PROPMAP_ENTRY* pMap, void* pThis, IUnknown* pUnk)
  448. {
  449. if (pPropBag == NULL)
  450. {
  451. ATLTRACE(atlTraceCOM, 0, _T("PropBag pointer passed in was invalid\n"));
  452. return E_POINTER;
  453. }
  454. CComPtr<IDispatch> pDispatch;
  455. const IID* piidOld = NULL;
  456. for (int i = 0; pMap[i].pclsidPropPage != NULL; i++)
  457. {
  458. if (pMap[i].szDesc == NULL)
  459. continue;
  460. CComVariant var;
  461. // If raw entry skip it - we don't handle it for property bags just yet
  462. if (pMap[i].dwSizeData != 0)
  463. {
  464. void* pData = (void*) (pMap[i].dwOffsetData + (DWORD_PTR)pThis);
  465. // check the type - we only deal with limited set
  466. bool bTypeOK = false;
  467. switch (pMap[i].vt)
  468. {
  469. case VT_UI1:
  470. case VT_I1:
  471. var.bVal = *((BYTE*)pData);
  472. bTypeOK = true;
  473. break;
  474. case VT_BOOL:
  475. var.boolVal = *((VARIANT_BOOL*)pData);
  476. bTypeOK = true;
  477. break;
  478. case VT_UI2:
  479. var.iVal = *((short*)pData);
  480. bTypeOK = true;
  481. break;
  482. case VT_UI4:
  483. case VT_INT:
  484. case VT_UINT:
  485. var.lVal = *((long*)pData);
  486. bTypeOK = true;
  487. break;
  488. case VT_BSTR:
  489. var.bstrVal = ::SysAllocString(*((BSTR*)pData));
  490. if (var.bstrVal == NULL && *((BSTR*)pData) != NULL)
  491. return E_OUTOFMEMORY;
  492. bTypeOK = true;
  493. break;
  494. }
  495. if (bTypeOK)
  496. {
  497. var.vt = pMap[i].vt;
  498. HRESULT hr = pPropBag->Write(pMap[i].szDesc, &var);
  499. if (FAILED(hr))
  500. return hr;
  501. }
  502. continue;
  503. }
  504. if (pMap[i].piidDispatch != piidOld)
  505. {
  506. pDispatch.Release();
  507. if (FAILED(pUnk->QueryInterface(*pMap[i].piidDispatch, (void**)&pDispatch)))
  508. {
  509. ATLTRACE(atlTraceCOM, 0, _T("Failed to get a dispatch pointer for property #%i\n"), i);
  510. return E_FAIL;
  511. }
  512. piidOld = pMap[i].piidDispatch;
  513. }
  514. if (FAILED(pDispatch.GetProperty(pMap[i].dispid, &var)))
  515. {
  516. ATLTRACE(atlTraceCOM, 0, _T("Invoked failed on DISPID %x\n"), pMap[i].dispid);
  517. return E_FAIL;
  518. }
  519. if (var.vt == VT_UNKNOWN || var.vt == VT_DISPATCH)
  520. {
  521. if (var.punkVal == NULL)
  522. {
  523. ATLTRACE(atlTraceCOM, 2, _T("Warning skipping empty IUnknown in Save\n"));
  524. continue;
  525. }
  526. }
  527. HRESULT hr = pPropBag->Write(pMap[i].szDesc, &var);
  528. if (FAILED(hr))
  529. return hr;
  530. }
  531. return S_OK;
  532. }
  533. #endif //_ATL_DLL
  534. //////////////////////////////////////////////////////////////////////////////
  535. // IPersistStreamInitImpl
  536. template <class T>
  537. class ATL_NO_VTABLE IPersistStreamInitImpl : public IPersistStreamInit
  538. {
  539. public:
  540. // IPersist
  541. STDMETHOD(GetClassID)(CLSID *pClassID)
  542. {
  543. ATLTRACE(atlTraceCOM, 2, _T("IPersistStreamInitImpl::GetClassID\n"));
  544. if (pClassID == NULL)
  545. return E_FAIL;
  546. *pClassID = T::GetObjectCLSID();
  547. return S_OK;
  548. }
  549. // IPersistStream
  550. STDMETHOD(IsDirty)()
  551. {
  552. ATLTRACE(atlTraceCOM, 2, _T("IPersistStreamInitImpl::IsDirty\n"));
  553. T* pT = static_cast<T*>(this);
  554. return (pT->m_bRequiresSave) ? S_OK : S_FALSE;
  555. }
  556. STDMETHOD(Load)(LPSTREAM pStm)
  557. {
  558. ATLTRACE(atlTraceCOM, 2, _T("IPersistStreamInitImpl::Load\n"));
  559. T* pT = static_cast<T*>(this);
  560. return pT->IPersistStreamInit_Load(pStm, T::GetPropertyMap());
  561. }
  562. STDMETHOD(Save)(LPSTREAM pStm, BOOL fClearDirty)
  563. {
  564. T* pT = static_cast<T*>(this);
  565. ATLTRACE(atlTraceCOM, 2, _T("IPersistStreamInitImpl::Save\n"));
  566. return pT->IPersistStreamInit_Save(pStm, fClearDirty, T::GetPropertyMap());
  567. }
  568. STDMETHOD(GetSizeMax)(ULARGE_INTEGER* pcbSize)
  569. {
  570. HRESULT hr = S_OK;
  571. T* pT = static_cast<T*>(this);
  572. ATLTRACE(atlTraceCOM, 2, _T("IPersistStreamInitImpl::GetSizeMax\n"));
  573. if (pcbSize == NULL)
  574. return E_POINTER;
  575. ATL_PROPMAP_ENTRY* pMap = T::GetPropertyMap();
  576. ATLASSERT(pMap != NULL);
  577. // Start the size with the size of the ATL version we write out.
  578. ULARGE_INTEGER nSize;
  579. nSize.HighPart = 0;
  580. nSize.LowPart = sizeof(DWORD);
  581. CComPtr<IDispatch> pDispatch;
  582. const IID* piidOld = NULL;
  583. for (int i = 0; pMap[i].pclsidPropPage != NULL; i++)
  584. {
  585. if (pMap[i].szDesc == NULL)
  586. continue;
  587. // check if raw data entry
  588. if (pMap[i].dwSizeData != 0)
  589. {
  590. nSize.QuadPart += pMap[i].dwSizeData;
  591. continue;
  592. }
  593. CComVariant var;
  594. if (pMap[i].piidDispatch != piidOld)
  595. {
  596. pDispatch.Release();
  597. if (FAILED(pT->GetUnknown()->QueryInterface(*pMap[i].piidDispatch, (void**)&pDispatch)))
  598. {
  599. ATLTRACE(atlTraceCOM, 0, _T("Failed to get a dispatch pointer for property #%i\n"), i);
  600. hr = E_FAIL;
  601. break;
  602. }
  603. piidOld = pMap[i].piidDispatch;
  604. }
  605. if (FAILED(pDispatch.GetProperty(pMap[i].dispid, &var)))
  606. {
  607. ATLTRACE(atlTraceCOM, 0, _T("Invoked failed on DISPID %x\n"), pMap[i].dispid);
  608. hr = E_FAIL;
  609. break;
  610. }
  611. nSize.QuadPart += var.GetSize();
  612. }
  613. *pcbSize = nSize;
  614. return hr;
  615. }
  616. // IPersistStreamInit
  617. STDMETHOD(InitNew)()
  618. {
  619. ATLTRACE(atlTraceCOM, 2, _T("IPersistStreamInitImpl::InitNew\n"));
  620. T* pT = static_cast<T*>(this);
  621. pT->m_bRequiresSave = TRUE;
  622. return S_OK;
  623. }
  624. HRESULT IPersistStreamInit_Load(LPSTREAM pStm, ATL_PROPMAP_ENTRY* pMap)
  625. {
  626. T* pT = static_cast<T*>(this);
  627. HRESULT hr = AtlIPersistStreamInit_Load(pStm, pMap, pT, pT->GetUnknown());
  628. if (SUCCEEDED(hr))
  629. pT->m_bRequiresSave = FALSE;
  630. return hr;
  631. }
  632. HRESULT IPersistStreamInit_Save(LPSTREAM pStm, BOOL fClearDirty, ATL_PROPMAP_ENTRY* pMap)
  633. {
  634. T* pT = static_cast<T*>(this);
  635. return AtlIPersistStreamInit_Save(pStm, fClearDirty, pMap, pT, pT->GetUnknown());
  636. }
  637. };
  638. //////////////////////////////////////////////////////////////////////////////
  639. // IPersistStorageImpl
  640. template <class T>
  641. class ATL_NO_VTABLE IPersistStorageImpl : public IPersistStorage
  642. {
  643. public:
  644. // IPersist
  645. STDMETHOD(GetClassID)(CLSID *pClassID)
  646. {
  647. ATLTRACE(atlTraceCOM, 2, _T("IPersistStorageImpl::GetClassID\n"));
  648. if (pClassID == NULL)
  649. return E_FAIL;
  650. *pClassID = T::GetObjectCLSID();
  651. return S_OK;
  652. }
  653. // IPersistStorage
  654. STDMETHOD(IsDirty)(void)
  655. {
  656. ATLTRACE(atlTraceCOM, 2, _T("IPersistStorageImpl::IsDirty\n"));
  657. CComPtr<IPersistStreamInit> p;
  658. p.p = IPSI_GetIPersistStreamInit();
  659. return (p != NULL) ? p->IsDirty() : E_FAIL;
  660. }
  661. STDMETHOD(InitNew)(IStorage*)
  662. {
  663. ATLTRACE(atlTraceCOM, 2, _T("IPersistStorageImpl::InitNew\n"));
  664. CComPtr<IPersistStreamInit> p;
  665. p.p = IPSI_GetIPersistStreamInit();
  666. return (p != NULL) ? p->InitNew() : E_FAIL;
  667. }
  668. STDMETHOD(Load)(IStorage* pStorage)
  669. {
  670. ATLTRACE(atlTraceCOM, 2, _T("IPersistStorageImpl::Load\n"));
  671. CComPtr<IPersistStreamInit> p;
  672. p.p = IPSI_GetIPersistStreamInit();
  673. HRESULT hr = E_FAIL;
  674. if (p != NULL)
  675. {
  676. CComPtr<IStream> spStream;
  677. hr = pStorage->OpenStream(OLESTR("Contents"), NULL,
  678. STGM_DIRECT | STGM_SHARE_EXCLUSIVE, 0, &spStream);
  679. if (SUCCEEDED(hr))
  680. hr = p->Load(spStream);
  681. }
  682. return hr;
  683. }
  684. STDMETHOD(Save)(IStorage* pStorage, BOOL fSameAsLoad)
  685. {
  686. ATLTRACE(atlTraceCOM, 2, _T("IPersistStorageImpl::Save\n"));
  687. CComPtr<IPersistStreamInit> p;
  688. p.p = IPSI_GetIPersistStreamInit();
  689. HRESULT hr = E_FAIL;
  690. if (p != NULL)
  691. {
  692. CComPtr<IStream> spStream;
  693. static LPCOLESTR vszContents = OLESTR("Contents");
  694. hr = pStorage->CreateStream(vszContents,
  695. STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE,
  696. 0, 0, &spStream);
  697. if (SUCCEEDED(hr))
  698. hr = p->Save(spStream, fSameAsLoad);
  699. }
  700. return hr;
  701. }
  702. STDMETHOD(SaveCompleted)(IStorage* /* pStorage */)
  703. {
  704. ATLTRACE(atlTraceCOM, 2, _T("IPersistStorageImpl::SaveCompleted\n"));
  705. return S_OK;
  706. }
  707. STDMETHOD(HandsOffStorage)(void)
  708. {
  709. ATLTRACE(atlTraceCOM, 2, _T("IPersistStorageImpl::HandsOffStorage\n"));
  710. return S_OK;
  711. }
  712. private:
  713. IPersistStreamInit* IPSI_GetIPersistStreamInit();
  714. };
  715. template <class T>
  716. IPersistStreamInit* IPersistStorageImpl<T>::IPSI_GetIPersistStreamInit()
  717. {
  718. T* pT = static_cast<T*>(this);
  719. IPersistStreamInit* p;
  720. if (FAILED(pT->GetUnknown()->QueryInterface(__uuidof(IPersistStreamInit), (void**)&p)))
  721. pT->_InternalQueryInterface(__uuidof(IPersistStreamInit), (void**)&p);
  722. return p;
  723. }
  724. //////////////////////////////////////////////////////////////////////////////
  725. // IPersistPropertyBagImpl
  726. template <class T>
  727. class ATL_NO_VTABLE IPersistPropertyBagImpl : public IPersistPropertyBag
  728. {
  729. public:
  730. // IPersist
  731. STDMETHOD(GetClassID)(CLSID *pClassID)
  732. {
  733. ATLTRACE(atlTraceCOM, 2, _T("IPersistPropertyBagImpl::GetClassID\n"));
  734. if (pClassID == NULL)
  735. return E_FAIL;
  736. *pClassID = T::GetObjectCLSID();
  737. return S_OK;
  738. }
  739. // IPersistPropertyBag
  740. //
  741. STDMETHOD(InitNew)()
  742. {
  743. ATLTRACE(atlTraceCOM, 2, _T("IPersistPropertyBagImpl::InitNew\n"));
  744. T* pT = static_cast<T*>(this);
  745. pT->m_bRequiresSave = TRUE;
  746. return S_OK;
  747. }
  748. STDMETHOD(Load)(LPPROPERTYBAG pPropBag, LPERRORLOG pErrorLog)
  749. {
  750. ATLTRACE(atlTraceCOM, 2, _T("IPersistPropertyBagImpl::Load\n"));
  751. T* pT = static_cast<T*>(this);
  752. ATL_PROPMAP_ENTRY* pMap = T::GetPropertyMap();
  753. ATLASSERT(pMap != NULL);
  754. return pT->IPersistPropertyBag_Load(pPropBag, pErrorLog, pMap);
  755. }
  756. STDMETHOD(Save)(LPPROPERTYBAG pPropBag, BOOL fClearDirty, BOOL fSaveAllProperties)
  757. {
  758. ATLTRACE(atlTraceCOM, 2, _T("IPersistPropertyBagImpl::Save\n"));
  759. T* pT = static_cast<T*>(this);
  760. ATL_PROPMAP_ENTRY* pMap = T::GetPropertyMap();
  761. ATLASSERT(pMap != NULL);
  762. return pT->IPersistPropertyBag_Save(pPropBag, fClearDirty, fSaveAllProperties, pMap);
  763. }
  764. HRESULT IPersistPropertyBag_Load(LPPROPERTYBAG pPropBag, LPERRORLOG pErrorLog, ATL_PROPMAP_ENTRY* pMap)
  765. {
  766. T* pT = static_cast<T*>(this);
  767. HRESULT hr = AtlIPersistPropertyBag_Load(pPropBag, pErrorLog, pMap, pT, pT->GetUnknown());
  768. if (SUCCEEDED(hr))
  769. pT->m_bRequiresSave = FALSE;
  770. return hr;
  771. }
  772. HRESULT IPersistPropertyBag_Save(LPPROPERTYBAG pPropBag, BOOL fClearDirty, BOOL fSaveAllProperties, ATL_PROPMAP_ENTRY* pMap)
  773. {
  774. T* pT = static_cast<T*>(this);
  775. return AtlIPersistPropertyBag_Save(pPropBag, fClearDirty, fSaveAllProperties, pMap, pT, pT->GetUnknown());
  776. }
  777. };
  778. //////////////////////////////////////////////////////////////////////////////
  779. // CSecurityDescriptor
  780. class CSecurityDescriptor
  781. {
  782. public:
  783. CSecurityDescriptor();
  784. ~CSecurityDescriptor();
  785. public:
  786. HRESULT Attach(PSECURITY_DESCRIPTOR pSelfRelativeSD);
  787. HRESULT AttachObject(HANDLE hObject);
  788. HRESULT Initialize();
  789. HRESULT InitializeFromProcessToken(BOOL bDefaulted = FALSE);
  790. HRESULT InitializeFromThreadToken(BOOL bDefaulted = FALSE, BOOL bRevertToProcessToken = TRUE);
  791. HRESULT SetOwner(PSID pOwnerSid, BOOL bDefaulted = FALSE);
  792. HRESULT SetGroup(PSID pGroupSid, BOOL bDefaulted = FALSE);
  793. HRESULT Allow(LPCTSTR pszPrincipal, DWORD dwAccessMask);
  794. HRESULT Deny(LPCTSTR pszPrincipal, DWORD dwAccessMask);
  795. HRESULT Revoke(LPCTSTR pszPrincipal);
  796. HRESULT Allow(PSID pSid, DWORD dwAccessMask);
  797. HRESULT Deny(PSID pSid, DWORD dwAccessMask);
  798. HRESULT Revoke(PSID pSid);
  799. // utility functions
  800. // Any PSID you get from these functions should be free()ed
  801. static HRESULT SetPrivilege(LPCTSTR Privilege, BOOL bEnable = TRUE, HANDLE hToken = NULL);
  802. static HRESULT GetTokenSids(HANDLE hToken, PSID* ppUserSid, PSID* ppGroupSid);
  803. static HRESULT GetProcessSids(PSID* ppUserSid, PSID* ppGroupSid = NULL);
  804. static HRESULT GetThreadSids(PSID* ppUserSid, PSID* ppGroupSid = NULL, BOOL bOpenAsSelf = FALSE);
  805. static HRESULT CopyACL(PACL pDest, PACL pSrc);
  806. static HRESULT GetCurrentUserSID(PSID *ppSid);
  807. static HRESULT GetPrincipalSID(LPCTSTR pszPrincipal, PSID *ppSid);
  808. static HRESULT AddAccessAllowedACEToACL(PACL *Acl, PSID pSid, DWORD dwAccessMask);
  809. static HRESULT AddAccessDeniedACEToACL(PACL *Acl, PSID pSid, DWORD dwAccessMask);
  810. static HRESULT RemovePrincipalFromACL(PACL Acl, PSID pSid);
  811. static HRESULT CloneSID(PSID *ppSIDDest, PSID pSIDSrc)
  812. {
  813. HRESULT hr = S_OK;
  814. if (ppSIDDest == NULL)
  815. return E_POINTER;
  816. if (*ppSIDDest != NULL)
  817. return E_INVALIDARG;
  818. DWORD dwSize = GetLengthSid(pSIDSrc);
  819. *ppSIDDest = NULL;
  820. ATLTRY(*ppSIDDest = (PSID) malloc(dwSize));
  821. if (*ppSIDDest == NULL)
  822. return E_OUTOFMEMORY;
  823. if (!CopySid(dwSize, *ppSIDDest, pSIDSrc))
  824. {
  825. hr = AtlHresultFromLastError();
  826. ATLASSERT(FALSE);
  827. free(*ppSIDDest);
  828. *ppSIDDest = NULL;
  829. }
  830. return hr;
  831. }
  832. operator PSECURITY_DESCRIPTOR()
  833. {
  834. return m_pSD;
  835. }
  836. public:
  837. PSECURITY_DESCRIPTOR m_pSD;
  838. PSID m_pOwner;
  839. PSID m_pGroup;
  840. PACL m_pDACL;
  841. PACL m_pSACL;
  842. };
  843. inline CSecurityDescriptor::CSecurityDescriptor()
  844. {
  845. m_pSD = NULL;
  846. m_pOwner = NULL;
  847. m_pGroup = NULL;
  848. m_pDACL = NULL;
  849. m_pSACL= NULL;
  850. }
  851. inline CSecurityDescriptor::~CSecurityDescriptor()
  852. {
  853. delete m_pSD;
  854. free(m_pOwner);
  855. free(m_pGroup);
  856. free(m_pDACL);
  857. free(m_pSACL);
  858. }
  859. inline HRESULT CSecurityDescriptor::Initialize()
  860. {
  861. delete m_pSD;
  862. m_pSD = NULL;
  863. free(m_pOwner);
  864. m_pOwner = NULL;
  865. free(m_pGroup);
  866. m_pGroup = NULL;
  867. free(m_pDACL);
  868. m_pDACL = NULL;
  869. free(m_pSACL);
  870. m_pSACL = NULL;
  871. ATLTRY(m_pSD = new SECURITY_DESCRIPTOR);
  872. if (m_pSD != NULL)
  873. {
  874. if (InitializeSecurityDescriptor(m_pSD, SECURITY_DESCRIPTOR_REVISION))
  875. if (SetSecurityDescriptorDacl(m_pSD, TRUE, NULL, FALSE))
  876. return S_OK;
  877. HRESULT hr = AtlHresultFromLastError();
  878. delete m_pSD;
  879. m_pSD = NULL;
  880. ATLASSERT(FALSE);
  881. return hr;
  882. }
  883. return E_OUTOFMEMORY;
  884. }
  885. inline HRESULT CSecurityDescriptor::InitializeFromProcessToken(BOOL bDefaulted)
  886. {
  887. PSID pUserSid = NULL;
  888. PSID pGroupSid = NULL;
  889. HRESULT hr;
  890. hr = Initialize();
  891. if (SUCCEEDED(hr))
  892. {
  893. hr = GetProcessSids(&pUserSid, &pGroupSid);
  894. if (SUCCEEDED(hr))
  895. {
  896. hr = SetOwner(pUserSid, bDefaulted);
  897. if (SUCCEEDED(hr))
  898. hr = SetGroup(pGroupSid, bDefaulted);
  899. }
  900. // If something failed reinitialize the object
  901. if (FAILED(hr))
  902. Initialize();
  903. free(pUserSid);
  904. free(pGroupSid);
  905. }
  906. return hr;
  907. }
  908. inline HRESULT CSecurityDescriptor::InitializeFromThreadToken(BOOL bDefaulted, BOOL bRevertToProcessToken)
  909. {
  910. PSID pUserSid = NULL;
  911. PSID pGroupSid = NULL;
  912. HRESULT hr = Initialize();
  913. if (SUCCEEDED(hr))
  914. {
  915. hr = GetThreadSids(&pUserSid, &pGroupSid);
  916. if (HRESULT_CODE(hr) == ERROR_NO_TOKEN && bRevertToProcessToken)
  917. hr = GetProcessSids(&pUserSid, &pGroupSid);
  918. if (SUCCEEDED(hr))
  919. {
  920. hr = SetOwner(pUserSid, bDefaulted);
  921. if (SUCCEEDED(hr))
  922. hr = SetGroup(pGroupSid, bDefaulted);
  923. }
  924. // If something failed reinitialize the object
  925. if (FAILED(hr))
  926. Initialize();
  927. free(pUserSid);
  928. free(pGroupSid);
  929. }
  930. return hr;
  931. }
  932. inline HRESULT CSecurityDescriptor::SetOwner(PSID pOwnerSid, BOOL bDefaulted)
  933. {
  934. ATLASSERT(m_pSD);
  935. HRESULT hr = S_OK;
  936. // Mark the SD as having no owner
  937. if (SetSecurityDescriptorOwner(m_pSD, NULL, bDefaulted))
  938. {
  939. free(m_pOwner);
  940. m_pOwner = NULL;
  941. // If they asked for no owner don't do the copy
  942. if (pOwnerSid == NULL)
  943. return S_OK;
  944. // Make a copy of the Sid for the return value
  945. hr = CloneSID(&m_pOwner, pOwnerSid);
  946. if (SUCCEEDED(hr))
  947. {
  948. ATLASSERT(IsValidSid(m_pOwner));
  949. if (!SetSecurityDescriptorOwner(m_pSD, m_pOwner, bDefaulted))
  950. {
  951. hr = AtlHresultFromLastError();
  952. ATLASSERT(FALSE);
  953. free(m_pOwner);
  954. m_pOwner = NULL;
  955. }
  956. }
  957. }
  958. else
  959. {
  960. hr = AtlHresultFromLastError();
  961. ATLASSERT(FALSE);
  962. }
  963. return hr;
  964. }
  965. inline HRESULT CSecurityDescriptor::SetGroup(PSID pGroupSid, BOOL bDefaulted)
  966. {
  967. ATLASSERT(m_pSD);
  968. HRESULT hr = S_OK;
  969. // Mark the SD as having no Group
  970. if (SetSecurityDescriptorGroup(m_pSD, NULL, bDefaulted))
  971. {
  972. free(m_pGroup);
  973. m_pGroup = NULL;
  974. // If they asked for no Group don't do the copy
  975. if (pGroupSid == NULL)
  976. return S_OK;
  977. // Make a copy of the Sid for the return value
  978. hr = CloneSID(&m_pGroup, pGroupSid);
  979. if (SUCCEEDED(hr))
  980. {
  981. ATLASSERT(IsValidSid(m_pGroup));
  982. if (!SetSecurityDescriptorGroup(m_pSD, m_pGroup, bDefaulted))
  983. {
  984. hr = AtlHresultFromLastError();
  985. ATLASSERT(FALSE);
  986. free(m_pGroup);
  987. m_pGroup = NULL;
  988. }
  989. }
  990. }
  991. else
  992. {
  993. hr = AtlHresultFromLastError();
  994. ATLASSERT(FALSE);
  995. }
  996. return hr;
  997. }
  998. inline HRESULT CSecurityDescriptor::Allow(LPCTSTR pszPrincipal, DWORD dwAccessMask)
  999. {
  1000. PSID pSid;
  1001. HRESULT hr = GetPrincipalSID(pszPrincipal, &pSid);
  1002. if (SUCCEEDED(hr))
  1003. {
  1004. hr = AddAccessAllowedACEToACL(&m_pDACL, pSid, dwAccessMask);
  1005. if (SUCCEEDED(hr))
  1006. {
  1007. if (!SetSecurityDescriptorDacl(m_pSD, TRUE, m_pDACL, FALSE))
  1008. hr = AtlHresultFromLastError();
  1009. }
  1010. free(pSid);
  1011. }
  1012. return hr;
  1013. }
  1014. inline HRESULT CSecurityDescriptor::Deny(LPCTSTR pszPrincipal, DWORD dwAccessMask)
  1015. {
  1016. PSID pSid;
  1017. HRESULT hr = GetPrincipalSID(pszPrincipal, &pSid);
  1018. if (SUCCEEDED(hr))
  1019. {
  1020. hr = AddAccessDeniedACEToACL(&m_pDACL, pSid, dwAccessMask);
  1021. if (SUCCEEDED(hr))
  1022. {
  1023. if (!SetSecurityDescriptorDacl(m_pSD, TRUE, m_pDACL, FALSE))
  1024. hr = AtlHresultFromLastError();
  1025. }
  1026. free(pSid);
  1027. }
  1028. return hr;
  1029. }
  1030. inline HRESULT CSecurityDescriptor::Revoke(LPCTSTR pszPrincipal)
  1031. {
  1032. PSID pSid;
  1033. HRESULT hr = GetPrincipalSID(pszPrincipal, &pSid);
  1034. if (SUCCEEDED(hr))
  1035. {
  1036. hr = RemovePrincipalFromACL(m_pDACL, pSid);
  1037. if (SUCCEEDED(hr))
  1038. {
  1039. if (!SetSecurityDescriptorDacl(m_pSD, TRUE, m_pDACL, FALSE))
  1040. hr = AtlHresultFromLastError();
  1041. }
  1042. free(pSid);
  1043. }
  1044. return hr;
  1045. }
  1046. inline HRESULT CSecurityDescriptor::Allow(PSID pSid, DWORD dwAccessMask)
  1047. {
  1048. HRESULT hr = AddAccessAllowedACEToACL(&m_pDACL, pSid, dwAccessMask);
  1049. if (SUCCEEDED(hr))
  1050. {
  1051. if (!SetSecurityDescriptorDacl(m_pSD, TRUE, m_pDACL, FALSE))
  1052. hr = AtlHresultFromLastError();
  1053. }
  1054. return hr;
  1055. }
  1056. inline HRESULT CSecurityDescriptor::Deny(PSID pSid, DWORD dwAccessMask)
  1057. {
  1058. HRESULT hr = AddAccessDeniedACEToACL(&m_pDACL, pSid, dwAccessMask);
  1059. if (SUCCEEDED(hr))
  1060. {
  1061. if (!SetSecurityDescriptorDacl(m_pSD, TRUE, m_pDACL, FALSE))
  1062. hr = AtlHresultFromLastError();
  1063. }
  1064. return hr;
  1065. }
  1066. inline HRESULT CSecurityDescriptor::Revoke(PSID pSid)
  1067. {
  1068. HRESULT hr = RemovePrincipalFromACL(m_pDACL, pSid);
  1069. if (SUCCEEDED(hr))
  1070. {
  1071. if (!SetSecurityDescriptorDacl(m_pSD, TRUE, m_pDACL, FALSE))
  1072. hr = AtlHresultFromLastError();
  1073. }
  1074. return hr;
  1075. }
  1076. inline HRESULT CSecurityDescriptor::GetProcessSids(PSID* ppUserSid, PSID* ppGroupSid)
  1077. {
  1078. HRESULT hr = S_OK;
  1079. HANDLE hToken = NULL;
  1080. if (ppUserSid)
  1081. *ppUserSid = NULL;
  1082. if (ppGroupSid)
  1083. *ppGroupSid = NULL;
  1084. if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
  1085. {
  1086. hr = GetTokenSids(hToken, ppUserSid, ppGroupSid);
  1087. CloseHandle(hToken);
  1088. }
  1089. else
  1090. {
  1091. // Couldn't open process token
  1092. hr = AtlHresultFromLastError();
  1093. ATLASSERT(FALSE);
  1094. }
  1095. return hr;
  1096. }
  1097. inline HRESULT CSecurityDescriptor::GetThreadSids(PSID* ppUserSid, PSID* ppGroupSid, BOOL bOpenAsSelf)
  1098. {
  1099. HRESULT hr = S_OK;
  1100. HANDLE hToken = NULL;
  1101. if (ppUserSid)
  1102. *ppUserSid = NULL;
  1103. if (ppGroupSid)
  1104. *ppGroupSid = NULL;
  1105. if(OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, bOpenAsSelf, &hToken))
  1106. {
  1107. hr = GetTokenSids(hToken, ppUserSid, ppGroupSid);
  1108. CloseHandle(hToken);
  1109. }
  1110. else
  1111. // Couldn't open thread token
  1112. hr = AtlHresultFromLastError();
  1113. return hr;
  1114. }
  1115. inline HRESULT CSecurityDescriptor::GetTokenSids(HANDLE hToken, PSID* ppUserSid, PSID* ppGroupSid)
  1116. {
  1117. DWORD dwSize;
  1118. HRESULT hr = S_OK;
  1119. if (ppUserSid != NULL)
  1120. *ppUserSid = NULL;
  1121. if (ppGroupSid != NULL)
  1122. *ppGroupSid = NULL;
  1123. if (ppUserSid != NULL)
  1124. {
  1125. PTOKEN_USER ptkUser = NULL;
  1126. // Get length required for TokenUser by specifying buffer length of 0
  1127. GetTokenInformation(hToken, TokenUser, NULL, 0, &dwSize);
  1128. // Expected ERROR_INSUFFICIENT_BUFFER
  1129. DWORD dwError = GetLastError();
  1130. if (dwError == ERROR_INSUFFICIENT_BUFFER)
  1131. {
  1132. ATLTRY(ptkUser = (TOKEN_USER*) malloc(dwSize));
  1133. if (ptkUser != NULL)
  1134. {
  1135. // Get Sid of process token.
  1136. if (GetTokenInformation(hToken, TokenUser, ptkUser, dwSize, &dwSize))
  1137. {
  1138. // Make a copy of the Sid for the return value
  1139. hr = CloneSID(ppUserSid, ptkUser->User.Sid);
  1140. #ifdef _DEBUG
  1141. if (SUCCEEDED(hr))
  1142. {
  1143. ATLASSERT(IsValidSid(*ppUserSid));
  1144. }
  1145. #endif
  1146. }
  1147. else
  1148. // Couldn't get user info
  1149. hr = AtlHresultFromLastError();
  1150. free(ptkUser);
  1151. ptkUser = NULL;
  1152. }
  1153. else
  1154. hr = E_OUTOFMEMORY;
  1155. }
  1156. else
  1157. {
  1158. ATLASSERT(FALSE);
  1159. hr = AtlHresultFromWin32(dwError);
  1160. }
  1161. }
  1162. if (SUCCEEDED(hr) && ppGroupSid != NULL)
  1163. {
  1164. PTOKEN_PRIMARY_GROUP ptkGroup = NULL;
  1165. // Get length required for TokenPrimaryGroup by specifying buffer length of 0
  1166. GetTokenInformation(hToken, TokenPrimaryGroup, NULL, 0, &dwSize);
  1167. DWORD dwError = GetLastError();
  1168. // Expected ERROR_INSUFFICIENT_BUFFER
  1169. if (dwError == ERROR_INSUFFICIENT_BUFFER)
  1170. {
  1171. ATLTRY(ptkGroup = (TOKEN_PRIMARY_GROUP*) malloc(dwSize));
  1172. if (ptkGroup != NULL)
  1173. {
  1174. // Get Sid of process token.
  1175. if (GetTokenInformation(hToken, TokenPrimaryGroup, ptkGroup, dwSize, &dwSize))
  1176. {
  1177. // Make a copy of the Sid for the return value
  1178. hr = CloneSID(ppGroupSid, ptkGroup->PrimaryGroup);
  1179. #ifdef _DEBUG
  1180. if (SUCCEEDED(hr))
  1181. {
  1182. ATLASSERT(IsValidSid(*ppGroupSid));
  1183. }
  1184. #endif
  1185. }
  1186. else
  1187. // Couldn't get user info
  1188. hr = AtlHresultFromLastError();
  1189. free(ptkGroup);
  1190. ptkGroup = NULL;
  1191. }
  1192. else
  1193. hr = E_OUTOFMEMORY;
  1194. }
  1195. else
  1196. hr = AtlHresultFromWin32(dwError);
  1197. }
  1198. if (FAILED(hr))
  1199. {
  1200. if (ppUserSid != NULL)
  1201. {
  1202. free (*ppUserSid);
  1203. *ppUserSid = NULL;
  1204. }
  1205. if (ppGroupSid != NULL)
  1206. {
  1207. free (*ppGroupSid);
  1208. *ppGroupSid = NULL;
  1209. }
  1210. }
  1211. return hr;
  1212. }
  1213. inline HRESULT CSecurityDescriptor::GetCurrentUserSID(PSID *ppSid)
  1214. {
  1215. if (ppSid == NULL)
  1216. return E_POINTER;
  1217. *ppSid = NULL;
  1218. HANDLE tkHandle;
  1219. HRESULT hr = S_OK;
  1220. if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &tkHandle))
  1221. {
  1222. TOKEN_USER *tkUser = NULL;
  1223. DWORD tkSize;
  1224. // Get length required for TokenPrimaryGroup by specifying buffer length of 0
  1225. GetTokenInformation(tkHandle, TokenUser, NULL, 0, &tkSize);
  1226. DWORD dwError = GetLastError();
  1227. // Expected ERROR_INSUFFICIENT_BUFFER
  1228. if (dwError == ERROR_INSUFFICIENT_BUFFER)
  1229. {
  1230. ATLTRY(tkUser = (TOKEN_USER *) malloc(tkSize));
  1231. if (tkUser != NULL)
  1232. {
  1233. // Now make the real call
  1234. if (GetTokenInformation(tkHandle, TokenUser, tkUser, tkSize, &tkSize))
  1235. {
  1236. hr = CloneSID(ppSid, tkUser->User.Sid);
  1237. #ifdef _DEBUG
  1238. if (SUCCEEDED(hr))
  1239. {
  1240. ATLASSERT(IsValidSid(*ppSid));
  1241. }
  1242. #endif
  1243. }
  1244. else
  1245. hr = AtlHresultFromLastError();
  1246. free (tkUser);
  1247. tkUser = NULL;
  1248. }
  1249. else
  1250. hr = E_OUTOFMEMORY;
  1251. }
  1252. else
  1253. {
  1254. hr = AtlHresultFromWin32(dwError);
  1255. ATLASSERT(FALSE);
  1256. }
  1257. CloseHandle(tkHandle);
  1258. }
  1259. else
  1260. hr = AtlHresultFromLastError();
  1261. return hr;
  1262. }
  1263. inline HRESULT CSecurityDescriptor::GetPrincipalSID(LPCTSTR pszPrincipal, PSID *ppSid)
  1264. {
  1265. if (ppSid == NULL)
  1266. return E_POINTER;
  1267. *ppSid = NULL;
  1268. HRESULT hr;
  1269. LPTSTR pszRefDomain = NULL;
  1270. DWORD dwDomainSize = 0;
  1271. DWORD dwSidSize = 0;
  1272. SID_NAME_USE snu;
  1273. DWORD dwError;
  1274. // Call to get size info for alloc
  1275. LookupAccountName(NULL, pszPrincipal, NULL, &dwSidSize, NULL, &dwDomainSize, &snu);
  1276. dwError = GetLastError();
  1277. if (dwError == ERROR_INSUFFICIENT_BUFFER)
  1278. {
  1279. ATLTRY(pszRefDomain = new TCHAR[dwDomainSize]);
  1280. if (pszRefDomain != NULL)
  1281. {
  1282. ATLTRY(*ppSid = (PSID) malloc(dwSidSize));
  1283. if (*ppSid != NULL)
  1284. {
  1285. if (LookupAccountName(NULL, pszPrincipal, *ppSid, &dwSidSize, pszRefDomain, &dwDomainSize, &snu))
  1286. {
  1287. hr = S_OK;
  1288. }
  1289. else
  1290. {
  1291. hr = AtlHresultFromLastError();
  1292. free(*ppSid);
  1293. *ppSid = NULL;
  1294. }
  1295. }
  1296. else
  1297. hr = E_OUTOFMEMORY;
  1298. delete[] pszRefDomain;
  1299. }
  1300. else
  1301. hr = E_OUTOFMEMORY;
  1302. }
  1303. else
  1304. hr = AtlHresultFromWin32(dwError);
  1305. return hr;
  1306. }
  1307. inline HRESULT CSecurityDescriptor::Attach(PSECURITY_DESCRIPTOR pSelfRelativeSD)
  1308. {
  1309. PACL pDACL = NULL;
  1310. PACL pSACL = NULL;
  1311. BOOL bDACLPresent, bSACLPresent;
  1312. BOOL bDefaulted;
  1313. ACCESS_ALLOWED_ACE* pACE;
  1314. HRESULT hr;
  1315. PSID pUserSid;
  1316. PSID pGroupSid;
  1317. hr = Initialize();
  1318. if(FAILED(hr))
  1319. return hr;
  1320. // get the existing DACL.
  1321. if (GetSecurityDescriptorDacl(pSelfRelativeSD, &bDACLPresent, &pDACL, &bDefaulted))
  1322. {
  1323. if (bDACLPresent)
  1324. {
  1325. // pDACL should be valid if bDACLPresnet is true
  1326. ATLASSERT(pDACL != NULL);
  1327. // allocate new DACL.
  1328. m_pDACL = NULL;
  1329. ATLTRY(m_pDACL = (PACL) malloc(pDACL->AclSize));
  1330. if (m_pDACL != NULL)
  1331. {
  1332. // initialize the DACL
  1333. if (InitializeAcl(m_pDACL, pDACL->AclSize, ACL_REVISION))
  1334. {
  1335. // copy the ACES
  1336. for (int i = 0; SUCCEEDED(hr) && i < pDACL->AceCount; i++)
  1337. {
  1338. if (GetAce(pDACL, i, (void **)&pACE))
  1339. {
  1340. if (!AddAccessAllowedAce(m_pDACL, ACL_REVISION, pACE->Mask, (PSID)&(pACE->SidStart)))
  1341. hr = AtlHresultFromLastError();
  1342. }
  1343. else
  1344. hr = AtlHresultFromLastError();
  1345. }
  1346. if (SUCCEEDED(hr) && !IsValidAcl(m_pDACL))
  1347. hr = AtlHresultFromLastError();
  1348. }
  1349. else
  1350. hr = AtlHresultFromLastError();
  1351. }
  1352. else
  1353. hr = E_OUTOFMEMORY;
  1354. }
  1355. // set the DACL
  1356. if (SUCCEEDED(hr) && !SetSecurityDescriptorDacl(m_pSD, bDACLPresent, m_pDACL, bDefaulted))
  1357. hr = AtlHresultFromLastError();
  1358. }
  1359. // get the existing SACL.
  1360. if (SUCCEEDED(hr) && GetSecurityDescriptorSacl(pSelfRelativeSD, &bSACLPresent, &pSACL, &bDefaulted))
  1361. {
  1362. if (bSACLPresent)
  1363. {
  1364. // pSACL should be valid if bSACLPresnet is true
  1365. ATLASSERT(pSACL != NULL);
  1366. // allocate new SACL.
  1367. m_pSACL = NULL;
  1368. ATLTRY(m_pSACL = (PACL) malloc(pSACL->AclSize));
  1369. if (m_pSACL != NULL)
  1370. {
  1371. // initialize the SACL
  1372. if (InitializeAcl(m_pSACL, pSACL->AclSize, ACL_REVISION))
  1373. {
  1374. // copy the ACES
  1375. for (int i = 0; SUCCEEDED(hr) && i < pSACL->AceCount; i++)
  1376. {
  1377. if (GetAce(pSACL, i, (void **)&pACE))
  1378. {
  1379. if (!AddAccessAllowedAce(m_pSACL, ACL_REVISION, pACE->Mask, (PSID)&(pACE->SidStart)))
  1380. hr = AtlHresultFromLastError();
  1381. }
  1382. else
  1383. hr = AtlHresultFromLastError();
  1384. }
  1385. if (SUCCEEDED(hr) && !IsValidAcl(m_pSACL))
  1386. hr = AtlHresultFromLastError();
  1387. }
  1388. else
  1389. hr = AtlHresultFromLastError();
  1390. }
  1391. else
  1392. hr = E_OUTOFMEMORY;
  1393. }
  1394. // set the SACL
  1395. if (SUCCEEDED(hr) && !SetSecurityDescriptorSacl(m_pSD, bSACLPresent, m_pSACL, bDefaulted))
  1396. hr = AtlHresultFromLastError();
  1397. }
  1398. if (SUCCEEDED(hr))
  1399. {
  1400. if (GetSecurityDescriptorOwner(pSelfRelativeSD, &pUserSid, &bDefaulted))
  1401. {
  1402. if (SUCCEEDED(hr = SetOwner(pUserSid, bDefaulted)))
  1403. {
  1404. if (GetSecurityDescriptorGroup(pSelfRelativeSD, &pGroupSid, &bDefaulted))
  1405. {
  1406. if (SUCCEEDED(hr = SetGroup(pGroupSid, bDefaulted)))
  1407. {
  1408. if (!IsValidSecurityDescriptor(m_pSD))
  1409. hr = AtlHresultFromLastError();
  1410. }
  1411. }
  1412. else
  1413. hr = AtlHresultFromLastError();
  1414. }
  1415. }
  1416. else
  1417. hr = AtlHresultFromLastError();
  1418. }
  1419. if (FAILED(hr))
  1420. {
  1421. free(m_pDACL);
  1422. m_pDACL = NULL;
  1423. free(m_pSACL);
  1424. m_pSACL = NULL;
  1425. free(m_pSD);
  1426. m_pSD = NULL;
  1427. }
  1428. return hr;
  1429. }
  1430. inline HRESULT CSecurityDescriptor::AttachObject(HANDLE hObject)
  1431. {
  1432. HRESULT hr;
  1433. DWORD dwError;
  1434. DWORD dwSize = 0;
  1435. PSECURITY_DESCRIPTOR pSD = NULL;
  1436. GetKernelObjectSecurity(hObject, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
  1437. DACL_SECURITY_INFORMATION, NULL, 0, &dwSize);
  1438. dwError = GetLastError();
  1439. if (dwError != ERROR_INSUFFICIENT_BUFFER)
  1440. return AtlHresultFromWin32(dwError);
  1441. ATLTRY(pSD = (PSECURITY_DESCRIPTOR) malloc(dwSize));
  1442. if (pSD != NULL)
  1443. {
  1444. if (GetKernelObjectSecurity(hObject, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
  1445. DACL_SECURITY_INFORMATION, pSD, dwSize, &dwSize))
  1446. hr = Attach(pSD);
  1447. else
  1448. hr = AtlHresultFromLastError();
  1449. free(pSD);
  1450. }
  1451. else
  1452. hr = E_OUTOFMEMORY;
  1453. return hr;
  1454. }
  1455. inline HRESULT CSecurityDescriptor::CopyACL(PACL pDest, PACL pSrc)
  1456. {
  1457. ACL_SIZE_INFORMATION aclSizeInfo;
  1458. LPVOID pAce;
  1459. ACE_HEADER *aceHeader;
  1460. if (pSrc == NULL)
  1461. return S_OK;
  1462. if (!GetAclInformation(pSrc, (LPVOID) &aclSizeInfo, sizeof(ACL_SIZE_INFORMATION), AclSizeInformation))
  1463. return AtlHresultFromLastError();
  1464. // Copy all of the ACEs to the new ACL
  1465. for (UINT i = 0; i < aclSizeInfo.AceCount; i++)
  1466. {
  1467. if (!GetAce(pSrc, i, &pAce))
  1468. return AtlHresultFromLastError();
  1469. aceHeader = (ACE_HEADER *) pAce;
  1470. if (!AddAce(pDest, ACL_REVISION, 0xffffffff, pAce, aceHeader->AceSize))
  1471. return AtlHresultFromLastError();
  1472. }
  1473. return S_OK;
  1474. }
  1475. inline HRESULT CSecurityDescriptor::AddAccessDeniedACEToACL(PACL *ppAcl, PSID pSid, DWORD dwAccessMask)
  1476. {
  1477. ACL_SIZE_INFORMATION aclSizeInfo;
  1478. int aclSize;
  1479. PACL oldACL, newACL = NULL;
  1480. HRESULT hr = S_OK;
  1481. if (ppAcl == NULL)
  1482. return E_POINTER;
  1483. oldACL = *ppAcl;
  1484. aclSizeInfo.AclBytesInUse = 0;
  1485. if (*ppAcl != NULL && !GetAclInformation(oldACL, (LPVOID) &aclSizeInfo, sizeof(ACL_SIZE_INFORMATION), AclSizeInformation))
  1486. hr = AtlHresultFromLastError();
  1487. if (SUCCEEDED(hr))
  1488. {
  1489. aclSize = aclSizeInfo.AclBytesInUse + sizeof(ACL) + sizeof(ACCESS_DENIED_ACE) + GetLengthSid(pSid) - sizeof(DWORD);
  1490. ATLTRY(newACL = (PACL) malloc(aclSize));
  1491. if (newACL != NULL)
  1492. {
  1493. if (InitializeAcl(newACL, aclSize, ACL_REVISION))
  1494. {
  1495. // access denied ACEs should be before access allowed ACEs
  1496. if (AddAccessDeniedAce(newACL, ACL_REVISION2, dwAccessMask, pSid))
  1497. {
  1498. // Copy existing ACEs to the new ACL
  1499. hr = CopyACL(newACL, oldACL);
  1500. if (SUCCEEDED(hr))
  1501. {
  1502. *ppAcl = newACL;
  1503. free(oldACL);
  1504. }
  1505. }
  1506. else
  1507. hr = AtlHresultFromLastError();
  1508. }
  1509. else
  1510. hr = AtlHresultFromLastError();
  1511. if (FAILED(hr))
  1512. free(newACL);
  1513. }
  1514. else
  1515. hr = E_OUTOFMEMORY;
  1516. }
  1517. return hr;
  1518. }
  1519. inline HRESULT CSecurityDescriptor::AddAccessAllowedACEToACL(PACL *ppAcl, PSID pSid, DWORD dwAccessMask)
  1520. {
  1521. ACL_SIZE_INFORMATION aclSizeInfo;
  1522. int aclSize;
  1523. HRESULT hr = S_OK;
  1524. PACL oldACL, newACL = NULL;
  1525. if (ppAcl == NULL)
  1526. return E_POINTER;
  1527. oldACL = *ppAcl;
  1528. aclSizeInfo.AclBytesInUse = 0;
  1529. if (*ppAcl != NULL && !GetAclInformation(oldACL, (LPVOID) &aclSizeInfo, (DWORD) sizeof(ACL_SIZE_INFORMATION), AclSizeInformation))
  1530. hr = AtlHresultFromLastError();
  1531. if (SUCCEEDED(hr))
  1532. {
  1533. aclSize = aclSizeInfo.AclBytesInUse + sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(pSid) - sizeof(DWORD);
  1534. ATLTRY(newACL = (PACL) malloc(aclSize));
  1535. if (newACL != NULL)
  1536. {
  1537. if (InitializeAcl(newACL, aclSize, ACL_REVISION))
  1538. {
  1539. // Copy existing ACEs
  1540. hr = CopyACL(newACL, oldACL);
  1541. if (SUCCEEDED(hr))
  1542. {
  1543. // Add access Allowed ACEs after all other existing ACEs (possibly access denied ACEs)
  1544. if (AddAccessAllowedAce(newACL, ACL_REVISION2, dwAccessMask, pSid))
  1545. {
  1546. *ppAcl = newACL;
  1547. free(oldACL);
  1548. }
  1549. else
  1550. hr = AtlHresultFromLastError();
  1551. }
  1552. }
  1553. else
  1554. hr = AtlHresultFromLastError();
  1555. if (FAILED(hr))
  1556. free(newACL);
  1557. }
  1558. else
  1559. hr = E_OUTOFMEMORY;
  1560. }
  1561. return hr;
  1562. }
  1563. inline HRESULT CSecurityDescriptor::RemovePrincipalFromACL(PACL pAcl, PSID pSid)
  1564. {
  1565. ACL_SIZE_INFORMATION aclSizeInfo;
  1566. ULONG i;
  1567. LPVOID ace;
  1568. ACCESS_ALLOWED_ACE *accessAllowedAce;
  1569. ACCESS_DENIED_ACE *accessDeniedAce;
  1570. SYSTEM_AUDIT_ACE *systemAuditAce;
  1571. HRESULT hr;
  1572. ACE_HEADER *aceHeader;
  1573. if (GetAclInformation(pAcl, (LPVOID) &aclSizeInfo, (DWORD) sizeof(ACL_SIZE_INFORMATION), AclSizeInformation))
  1574. {
  1575. for (i = 0; i < aclSizeInfo.AceCount; i++)
  1576. {
  1577. if (GetAce(pAcl, i, &ace))
  1578. {
  1579. aceHeader = (ACE_HEADER *) ace;
  1580. if (aceHeader->AceType == ACCESS_ALLOWED_ACE_TYPE)
  1581. {
  1582. accessAllowedAce = (ACCESS_ALLOWED_ACE *) ace;
  1583. if (EqualSid(pSid, (PSID) &accessAllowedAce->SidStart))
  1584. {
  1585. if (!DeleteAce(pAcl, i))
  1586. hr = AtlHresultFromLastError();
  1587. break;
  1588. }
  1589. }
  1590. else if (aceHeader->AceType == ACCESS_DENIED_ACE_TYPE)
  1591. {
  1592. accessDeniedAce = (ACCESS_DENIED_ACE *) ace;
  1593. if (EqualSid(pSid, (PSID) &accessDeniedAce->SidStart))
  1594. {
  1595. if (!DeleteAce(pAcl, i))
  1596. hr = AtlHresultFromLastError();
  1597. break;
  1598. }
  1599. }
  1600. else if (aceHeader->AceType == SYSTEM_AUDIT_ACE_TYPE)
  1601. {
  1602. systemAuditAce = (SYSTEM_AUDIT_ACE *) ace;
  1603. if (EqualSid(pSid, (PSID) &systemAuditAce->SidStart))
  1604. {
  1605. if (!DeleteAce(pAcl, i))
  1606. hr = AtlHresultFromLastError();
  1607. break;
  1608. }
  1609. }
  1610. }
  1611. else
  1612. {
  1613. hr = AtlHresultFromLastError();
  1614. break;
  1615. }
  1616. }
  1617. }
  1618. else
  1619. hr = AtlHresultFromLastError();
  1620. return hr;
  1621. }
  1622. inline HRESULT CSecurityDescriptor::SetPrivilege(LPCTSTR privilege, BOOL bEnable, HANDLE hToken)
  1623. {
  1624. TOKEN_PRIVILEGES tpPrevious;
  1625. TOKEN_PRIVILEGES tp;
  1626. DWORD cbPrevious = sizeof(TOKEN_PRIVILEGES);
  1627. LUID luid;
  1628. HANDLE hTokenUsed;
  1629. if (!LookupPrivilegeValue(NULL, privilege, &luid ))
  1630. goto _Error;
  1631. // if no token specified open process token
  1632. if (hToken != 0)
  1633. hTokenUsed = hToken;
  1634. else
  1635. if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hTokenUsed))
  1636. goto _Error;
  1637. tp.PrivilegeCount = 1;
  1638. tp.Privileges[0].Luid = luid;
  1639. tp.Privileges[0].Attributes = 0;
  1640. if (!AdjustTokenPrivileges(hTokenUsed, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), &tpPrevious, &cbPrevious))
  1641. goto _Error_CloseHandle;
  1642. tpPrevious.PrivilegeCount = 1;
  1643. tpPrevious.Privileges[0].Luid = luid;
  1644. if (bEnable)
  1645. tpPrevious.Privileges[0].Attributes |= SE_PRIVILEGE_ENABLED;
  1646. else
  1647. tpPrevious.Privileges[0].Attributes &= ~SE_PRIVILEGE_ENABLED;
  1648. if (!AdjustTokenPrivileges(hTokenUsed, FALSE, &tpPrevious, cbPrevious, NULL, NULL))
  1649. goto _Error_CloseHandle;
  1650. if(hToken == 0)
  1651. CloseHandle(hTokenUsed);
  1652. return S_OK;
  1653. HRESULT hr;
  1654. _Error:
  1655. hr = AtlHresultFromLastError();
  1656. return hr;
  1657. _Error_CloseHandle:
  1658. hr = AtlHresultFromLastError();
  1659. if (hToken == 0)
  1660. CloseHandle(hTokenUsed);
  1661. return hr;
  1662. }
  1663. /////////////////////////////////////////////////////////////////////////////
  1664. // COM Objects
  1665. #define DECLARE_PROTECT_FINAL_CONSTRUCT()\
  1666. void InternalFinalConstructAddRef() {InternalAddRef();}\
  1667. void InternalFinalConstructRelease() {InternalRelease();}
  1668. template <class T1>
  1669. class CComCreator
  1670. {
  1671. public:
  1672. static HRESULT WINAPI CreateInstance(void* pv, REFIID riid, LPVOID* ppv)
  1673. {
  1674. ATLASSERT(ppv != NULL);
  1675. if (ppv == NULL)
  1676. return E_POINTER;
  1677. *ppv = NULL;
  1678. HRESULT hRes = E_OUTOFMEMORY;
  1679. T1* p = NULL;
  1680. ATLTRY(p = new T1(pv))
  1681. if (p != NULL)
  1682. {
  1683. p->SetVoid(pv);
  1684. p->InternalFinalConstructAddRef();
  1685. hRes = p->FinalConstruct();
  1686. if (SUCCEEDED(hRes))
  1687. hRes = p->_AtlFinalConstruct();
  1688. p->InternalFinalConstructRelease();
  1689. if (hRes == S_OK)
  1690. hRes = p->QueryInterface(riid, ppv);
  1691. if (hRes != S_OK)
  1692. delete p;
  1693. }
  1694. return hRes;
  1695. }
  1696. };
  1697. template <class T1>
  1698. class CComInternalCreator
  1699. {
  1700. public:
  1701. static HRESULT WINAPI CreateInstance(void* pv, REFIID riid, LPVOID* ppv)
  1702. {
  1703. ATLASSERT(ppv != NULL);
  1704. if (ppv == NULL)
  1705. return E_POINTER;
  1706. *ppv = NULL;
  1707. HRESULT hRes = E_OUTOFMEMORY;
  1708. T1* p = NULL;
  1709. ATLTRY(p = new T1(pv))
  1710. if (p != NULL)
  1711. {
  1712. p->SetVoid(pv);
  1713. p->InternalFinalConstructAddRef();
  1714. hRes = p->FinalConstruct();
  1715. if (SUCCEEDED(hRes))
  1716. hRes = p->_AtlFinalConstruct();
  1717. p->InternalFinalConstructRelease();
  1718. if (hRes == S_OK)
  1719. hRes = p->_InternalQueryInterface(riid, ppv);
  1720. if (hRes != S_OK)
  1721. delete p;
  1722. }
  1723. return hRes;
  1724. }
  1725. };
  1726. template <HRESULT hr>
  1727. class CComFailCreator
  1728. {
  1729. public:
  1730. static HRESULT WINAPI CreateInstance(void*, REFIID, LPVOID* ppv)
  1731. {
  1732. if (ppv == NULL)
  1733. return E_POINTER;
  1734. *ppv = NULL;
  1735. return hr;
  1736. }
  1737. };
  1738. template <class T1, class T2>
  1739. class CComCreator2
  1740. {
  1741. public:
  1742. static HRESULT WINAPI CreateInstance(void* pv, REFIID riid, LPVOID* ppv)
  1743. {
  1744. ATLASSERT(ppv != NULL);
  1745. return (pv == NULL) ?
  1746. T1::CreateInstance(NULL, riid, ppv) :
  1747. T2::CreateInstance(pv, riid, ppv);
  1748. }
  1749. };
  1750. #define DECLARE_NOT_AGGREGATABLE(x) public:\
  1751. typedef ATL::CComCreator2< ATL::CComCreator< ATL::CComObject< x > >, ATL::CComFailCreator<CLASS_E_NOAGGREGATION> > _CreatorClass;
  1752. #define DECLARE_AGGREGATABLE(x) public:\
  1753. typedef ATL::CComCreator2< ATL::CComCreator< ATL::CComObject< x > >, ATL::CComCreator< ATL::CComAggObject< x > > > _CreatorClass;
  1754. #define DECLARE_ONLY_AGGREGATABLE(x) public:\
  1755. typedef ATL::CComCreator2< ATL::CComFailCreator<E_FAIL>, ATL::CComCreator< ATL::CComAggObject< x > > > _CreatorClass;
  1756. #define DECLARE_POLY_AGGREGATABLE(x) public:\
  1757. typedef ATL::CComCreator< ATL::CComPolyObject< x > > _CreatorClass;
  1758. struct _ATL_CREATORDATA
  1759. {
  1760. _ATL_CREATORFUNC* pFunc;
  1761. };
  1762. template <class Creator>
  1763. class _CComCreatorData
  1764. {
  1765. public:
  1766. static _ATL_CREATORDATA data;
  1767. };
  1768. template <class Creator>
  1769. _ATL_CREATORDATA _CComCreatorData<Creator>::data = {Creator::CreateInstance};
  1770. struct _ATL_CACHEDATA
  1771. {
  1772. DWORD dwOffsetVar;
  1773. _ATL_CREATORFUNC* pFunc;
  1774. };
  1775. template <class Creator, DWORD dwVar>
  1776. class _CComCacheData
  1777. {
  1778. public:
  1779. static _ATL_CACHEDATA data;
  1780. };
  1781. template <class Creator, DWORD dwVar>
  1782. _ATL_CACHEDATA _CComCacheData<Creator, dwVar>::data = {dwVar, Creator::CreateInstance};
  1783. struct _ATL_CHAINDATA
  1784. {
  1785. DWORD_PTR dwOffset;
  1786. const _ATL_INTMAP_ENTRY* (WINAPI *pFunc)();
  1787. };
  1788. template <class base, class derived>
  1789. class _CComChainData
  1790. {
  1791. public:
  1792. static _ATL_CHAINDATA data;
  1793. };
  1794. template <class base, class derived>
  1795. _ATL_CHAINDATA _CComChainData<base, derived>::data =
  1796. {offsetofclass(base, derived), base::_GetEntries};
  1797. template <class T, const CLSID* pclsid>
  1798. class CComAggregateCreator
  1799. {
  1800. public:
  1801. static HRESULT WINAPI CreateInstance(void* pv, REFIID/*riid*/, LPVOID* ppv) throw()
  1802. {
  1803. // Only Assert here. CoCreateInstance will return the correct HRESULT if ppv == NULL
  1804. ATLASSERT(ppv != NULL);
  1805. ATLASSERT(pv != NULL);
  1806. T* p = (T*) pv;
  1807. // Add the following line to your object if you get a message about
  1808. // GetControllingUnknown() being undefined
  1809. // DECLARE_GET_CONTROLLING_UNKNOWN()
  1810. return CoCreateInstance(*pclsid, p->GetControllingUnknown(), CLSCTX_INPROC, __uuidof(IUnknown), ppv);
  1811. }
  1812. };
  1813. #ifdef _ATL_DEBUG
  1814. #define DEBUG_QI_ENTRY(x) \
  1815. {NULL, \
  1816. (DWORD_PTR)_T(#x), \
  1817. (ATL::_ATL_CREATORARGFUNC*)0},
  1818. #else
  1819. #define DEBUG_QI_ENTRY(x)
  1820. #endif //_ATL_DEBUG
  1821. #ifdef _ATL_DEBUG_INTERFACES
  1822. #define _ATL_DECLARE_GET_UNKNOWN(x)\
  1823. IUnknown* GetUnknown() throw() \
  1824. { \
  1825. IUnknown* p; \
  1826. _AtlDebugInterfacesModule.AddNonAddRefThunk(_GetRawUnknown(), _T(#x), &p); \
  1827. return p; \
  1828. }
  1829. #else
  1830. #define _ATL_DECLARE_GET_UNKNOWN(x) IUnknown* GetUnknown() throw() {return _GetRawUnknown();}
  1831. #endif
  1832. //If you get a message that FinalConstruct is ambiguous then you need to
  1833. // override it in your class and call each base class' version of this
  1834. #define BEGIN_COM_MAP(x) public: \
  1835. typedef x _ComMapClass; \
  1836. static HRESULT WINAPI _Cache(void* pv, REFIID iid, void** ppvObject, DWORD_PTR dw) throw()\
  1837. {\
  1838. _ComMapClass* p = (_ComMapClass*)pv;\
  1839. p->Lock();\
  1840. HRESULT hRes = ATL::CComObjectRootBase::_Cache(pv, iid, ppvObject, dw);\
  1841. p->Unlock();\
  1842. return hRes;\
  1843. }\
  1844. IUnknown* _GetRawUnknown() throw() \
  1845. { ATLASSERT(_GetEntries()[0].pFunc == _ATL_SIMPLEMAPENTRY); return (IUnknown*)((INT_PTR)this+_GetEntries()->dw); } \
  1846. _ATL_DECLARE_GET_UNKNOWN(x)\
  1847. HRESULT _InternalQueryInterface(REFIID iid, void** ppvObject) throw() \
  1848. { return InternalQueryInterface(this, _GetEntries(), iid, ppvObject); } \
  1849. const static ATL::_ATL_INTMAP_ENTRY* WINAPI _GetEntries() throw() { \
  1850. static const ATL::_ATL_INTMAP_ENTRY _entries[] = { DEBUG_QI_ENTRY(x)
  1851. // For use by attributes for chaining to existing COM_MAP
  1852. #define BEGIN_ATTRCOM_MAP(x) public: \
  1853. typedef x _AttrComMapClass; \
  1854. const static ATL::_ATL_INTMAP_ENTRY* WINAPI _GetAttrEntries() throw() { \
  1855. static const ATL::_ATL_INTMAP_ENTRY _entries[] = {
  1856. #define DECLARE_GET_CONTROLLING_UNKNOWN() public:\
  1857. virtual IUnknown* GetControllingUnknown() throw() {return GetUnknown();}
  1858. #define COM_INTERFACE_ENTRY_BREAK(x)\
  1859. {&_ATL_IIDOF(x), \
  1860. NULL, \
  1861. _Break},
  1862. #define COM_INTERFACE_ENTRY_NOINTERFACE(x)\
  1863. {&_ATL_IIDOF(x), \
  1864. NULL, \
  1865. _NoInterface},
  1866. #define COM_INTERFACE_ENTRY(x)\
  1867. {&_ATL_IIDOF(x), \
  1868. offsetofclass(x, _ComMapClass), \
  1869. _ATL_SIMPLEMAPENTRY},
  1870. #define COM_INTERFACE_ENTRY_IID(iid, x)\
  1871. {&iid,\
  1872. offsetofclass(x, _ComMapClass),\
  1873. _ATL_SIMPLEMAPENTRY},
  1874. // The impl macros are now obsolete
  1875. #define COM_INTERFACE_ENTRY_IMPL(x)\
  1876. COM_INTERFACE_ENTRY_IID(_ATL_IIDOF(x), x##Impl<_ComMapClass>)
  1877. #define COM_INTERFACE_ENTRY_IMPL_IID(iid, x)\
  1878. COM_INTERFACE_ENTRY_IID(iid, x##Impl<_ComMapClass>)
  1879. //
  1880. #define COM_INTERFACE_ENTRY2(x, x2)\
  1881. {&_ATL_IIDOF(x),\
  1882. reinterpret_cast<DWORD_PTR>(static_cast<x*>(static_cast<x2*>(reinterpret_cast<_ComMapClass*>(8))))-8,\
  1883. _ATL_SIMPLEMAPENTRY},
  1884. #define COM_INTERFACE_ENTRY2_IID(iid, x, x2)\
  1885. {&iid,\
  1886. reinterpret_cast<DWORD_PTR>(static_cast<x*>(static_cast<x2*>(reinterpret_cast<_ComMapClass*>(8))))-8,\
  1887. _ATL_SIMPLEMAPENTRY},
  1888. #define COM_INTERFACE_ENTRY_FUNC(iid, dw, func)\
  1889. {&iid, \
  1890. dw, \
  1891. func},
  1892. #define COM_INTERFACE_ENTRY_FUNC_BLIND(dw, func)\
  1893. {NULL, \
  1894. dw, \
  1895. func},
  1896. #define COM_INTERFACE_ENTRY_TEAR_OFF(iid, x)\
  1897. {&iid,\
  1898. (DWORD_PTR)&ATL::_CComCreatorData<\
  1899. ATL::CComInternalCreator< ATL::CComTearOffObject< x > >\
  1900. >::data,\
  1901. _Creator},
  1902. #define COM_INTERFACE_ENTRY_CACHED_TEAR_OFF(iid, x, punk)\
  1903. {&iid,\
  1904. (DWORD_PTR)&ATL::_CComCacheData<\
  1905. ATL::CComCreator< ATL::CComCachedTearOffObject< x > >,\
  1906. (DWORD_PTR)offsetof(_ComMapClass, punk)\
  1907. >::data,\
  1908. _Cache},
  1909. #define COM_INTERFACE_ENTRY_AGGREGATE(iid, punk)\
  1910. {&iid,\
  1911. (DWORD_PTR)offsetof(_ComMapClass, punk),\
  1912. _Delegate},
  1913. #define COM_INTERFACE_ENTRY_AGGREGATE_BLIND(punk)\
  1914. {NULL,\
  1915. (DWORD_PTR)offsetof(_ComMapClass, punk),\
  1916. _Delegate},
  1917. #define COM_INTERFACE_ENTRY_AUTOAGGREGATE(iid, punk, clsid)\
  1918. {&iid,\
  1919. (DWORD_PTR)&ATL::_CComCacheData<\
  1920. ATL::CComAggregateCreator<_ComMapClass, &clsid>,\
  1921. (DWORD_PTR)offsetof(_ComMapClass, punk)\
  1922. >::data,\
  1923. _Cache},
  1924. #define COM_INTERFACE_ENTRY_AUTOAGGREGATE_BLIND(punk, clsid)\
  1925. {NULL,\
  1926. (DWORD_PTR)&ATL::_CComCacheData<\
  1927. ATL::CComAggregateCreator<_ComMapClass, &clsid>,\
  1928. (DWORD_PTR)offsetof(_ComMapClass, punk)\
  1929. >::data,\
  1930. _Cache},
  1931. #define COM_INTERFACE_ENTRY_CHAIN(classname)\
  1932. {NULL,\
  1933. (DWORD_PTR)&ATL::_CComChainData<classname, _ComMapClass>::data,\
  1934. _Chain},
  1935. #ifdef _ATL_DEBUG
  1936. #define END_COM_MAP() \
  1937. __if_exists(_GetAttrEntries) {{NULL, (DWORD_PTR)_GetAttrEntries, _ChainAttr }, }\
  1938. {NULL, 0, 0}}; return &_entries[1];} \
  1939. virtual ULONG STDMETHODCALLTYPE AddRef( void) throw() = 0; \
  1940. virtual ULONG STDMETHODCALLTYPE Release( void) throw() = 0; \
  1941. STDMETHOD(QueryInterface)(REFIID, void**) throw() = 0;
  1942. #else
  1943. #define END_COM_MAP() \
  1944. __if_exists(_GetAttrEntries) {{NULL, (DWORD_PTR)_GetAttrEntries, _ChainAttr }, }\
  1945. {NULL, 0, 0}}; return _entries;} \
  1946. virtual ULONG STDMETHODCALLTYPE AddRef( void) throw() = 0; \
  1947. virtual ULONG STDMETHODCALLTYPE Release( void) throw() = 0; \
  1948. STDMETHOD(QueryInterface)(REFIID, void**) throw() = 0;
  1949. #endif // _ATL_DEBUG
  1950. #define END_ATTRCOM_MAP() \
  1951. {NULL, 0, 0}}; return _entries;}
  1952. #define BEGIN_CATEGORY_MAP(x)\
  1953. static const struct ATL::_ATL_CATMAP_ENTRY* GetCategoryMap() throw() {\
  1954. static const struct ATL::_ATL_CATMAP_ENTRY pMap[] = {
  1955. #define IMPLEMENTED_CATEGORY( catid ) { _ATL_CATMAP_ENTRY_IMPLEMENTED, &catid },
  1956. #define REQUIRED_CATEGORY( catid ) { _ATL_CATMAP_ENTRY_REQUIRED, &catid },
  1957. #define END_CATEGORY_MAP()\
  1958. { _ATL_CATMAP_ENTRY_END, NULL } };\
  1959. return( pMap ); }
  1960. #define BEGIN_OBJECT_MAP(x) static ATL::_ATL_OBJMAP_ENTRY x[] = {
  1961. #define END_OBJECT_MAP() {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}};
  1962. #define OBJECT_ENTRY(clsid, class) {&clsid, class::UpdateRegistry, class::_ClassFactoryCreatorClass::CreateInstance, class::_CreatorClass::CreateInstance, NULL, 0, class::GetObjectDescription, class::GetCategoryMap, class::ObjectMain },
  1963. #define OBJECT_ENTRY_NON_CREATEABLE(class) {&CLSID_NULL, class::UpdateRegistry, NULL, NULL, NULL, 0, NULL, class::GetCategoryMap, class::ObjectMain },
  1964. #define OBJECT_ENTRY_NON_CREATEABLE_EX(clsid, class) {&clsid, class::UpdateRegistry, NULL, NULL, NULL, 0, NULL, class::GetCategoryMap, class::ObjectMain },
  1965. #ifndef OBJECT_ENTRY_PRAGMA
  1966. #if defined(_M_IX86)
  1967. #define OBJECT_ENTRY_PRAGMA(class) __pragma(comment(linker, "/include:___pobjMap_" #class))
  1968. #elif defined(_M_AMD64) || defined(_M_IA64)
  1969. #define OBJECT_ENTRY_PRAGMA(class) __pragma(comment(linker, "/include:__pobjMap_" #class))
  1970. #else
  1971. #error Unknown Platform. define OBJECT_ENTRY_PRAGMA
  1972. #endif
  1973. #endif //OBJECT_ENTRY_PRAGMA
  1974. #define OBJECT_ENTRY_AUTO(clsid, class) \
  1975. __declspec(selectany) ATL::_ATL_OBJMAP_ENTRY __objMap_##class = \
  1976. {&clsid, class::UpdateRegistry, class::_ClassFactoryCreatorClass::CreateInstance, class::_CreatorClass::CreateInstance, NULL, 0, class::GetObjectDescription, class::GetCategoryMap, class::ObjectMain }; \
  1977. extern "C" __declspec(allocate("ATL$__m")) __declspec(selectany) ATL::_ATL_OBJMAP_ENTRY* const __pobjMap_##class = &__objMap_##class; \
  1978. OBJECT_ENTRY_PRAGMA(class)
  1979. #define OBJECT_ENTRY_NON_CREATEABLE_EX_AUTO(clsid, class) \
  1980. __declspec(selectany) ATL::_ATL_OBJMAP_ENTRY __objMap_##class = {&clsid, class::UpdateRegistry, NULL, NULL, NULL, 0, NULL, class::GetCategoryMap, class::ObjectMain }; \
  1981. extern "C" __declspec(allocate("ATL$__m")) __declspec(selectany) ATL::_ATL_OBJMAP_ENTRY* const __pobjMap_##class = &__objMap_##class; \
  1982. OBJECT_ENTRY_PRAGMA(class)
  1983. #ifdef _ATL_DEBUG
  1984. extern HRESULT WINAPI AtlDumpIID(REFIID iid, LPCTSTR pszClassName, HRESULT hr);
  1985. #endif // _ATL_DEBUG
  1986. // the functions in this class don't need to be virtual because
  1987. // they are called from CComObject
  1988. class CComObjectRootBase
  1989. {
  1990. public:
  1991. CComObjectRootBase()
  1992. {
  1993. m_dwRef = 0L;
  1994. }
  1995. HRESULT FinalConstruct()
  1996. {
  1997. return S_OK;
  1998. }
  1999. // For library initialization only
  2000. HRESULT _AtlFinalConstruct()
  2001. {
  2002. return S_OK;
  2003. }
  2004. void FinalRelease() {}
  2005. void _AtlFinalRelease() {} // temp
  2006. void _HRPass(HRESULT hr) // temp
  2007. {
  2008. hr;
  2009. }
  2010. void _HRFail(HRESULT hr) // temp...
  2011. {
  2012. hr;
  2013. }
  2014. //ObjectMain is called during Module::Init and Module::Term
  2015. static void WINAPI ObjectMain(bool /* bStarting */) {}
  2016. static const struct _ATL_CATMAP_ENTRY* GetCategoryMap() {return NULL;};
  2017. static HRESULT WINAPI InternalQueryInterface(void* pThis,
  2018. const _ATL_INTMAP_ENTRY* pEntries, REFIID iid, void** ppvObject)
  2019. {
  2020. // Only Assert here. AtlInternalQueryInterface will return the correct HRESULT if ppvObject == NULL
  2021. #ifndef _ATL_OLEDB_CONFORMANCE_TESTS
  2022. ATLASSERT(ppvObject != NULL);
  2023. #endif
  2024. ATLASSERT(pThis != NULL);
  2025. // First entry in the com map should be a simple map entry
  2026. ATLASSERT(pEntries->pFunc == _ATL_SIMPLEMAPENTRY);
  2027. #if defined(_ATL_DEBUG_INTERFACES) || defined(_ATL_DEBUG_QI)
  2028. LPCTSTR pszClassName = (LPCTSTR) pEntries[-1].dw;
  2029. #endif // _ATL_DEBUG_INTERFACES
  2030. HRESULT hRes = AtlInternalQueryInterface(pThis, pEntries, iid, ppvObject);
  2031. #ifdef _ATL_DEBUG_INTERFACES
  2032. _AtlDebugInterfacesModule.AddThunk((IUnknown**)ppvObject, pszClassName, iid);
  2033. #endif // _ATL_DEBUG_INTERFACES
  2034. return _ATLDUMPIID(iid, pszClassName, hRes);
  2035. }
  2036. //Outer funcs
  2037. ULONG OuterAddRef()
  2038. {
  2039. return m_pOuterUnknown->AddRef();
  2040. }
  2041. ULONG OuterRelease()
  2042. {
  2043. return m_pOuterUnknown->Release();
  2044. }
  2045. HRESULT OuterQueryInterface(REFIID iid, void ** ppvObject)
  2046. {
  2047. return m_pOuterUnknown->QueryInterface(iid, ppvObject);
  2048. }
  2049. void SetVoid(void*) {}
  2050. void InternalFinalConstructAddRef() {}
  2051. void InternalFinalConstructRelease()
  2052. {
  2053. ATLASSERT(m_dwRef == 0);
  2054. }
  2055. // If this assert occurs, your object has probably been deleted
  2056. // Try using DECLARE_PROTECT_FINAL_CONSTRUCT()
  2057. static HRESULT WINAPI _Break(void* /* pv */, REFIID iid, void** /* ppvObject */, DWORD_PTR /* dw */)
  2058. {
  2059. iid;
  2060. _ATLDUMPIID(iid, _T("Break due to QI for interface "), S_OK);
  2061. DebugBreak();
  2062. return S_FALSE;
  2063. }
  2064. static HRESULT WINAPI _NoInterface(void* /* pv */, REFIID /* iid */, void** /* ppvObject */, DWORD_PTR /* dw */)
  2065. {
  2066. return E_NOINTERFACE;
  2067. }
  2068. static HRESULT WINAPI _Creator(void* pv, REFIID iid, void** ppvObject, DWORD_PTR dw)
  2069. {
  2070. _ATL_CREATORDATA* pcd = (_ATL_CREATORDATA*)dw;
  2071. return pcd->pFunc(pv, iid, ppvObject);
  2072. }
  2073. static HRESULT WINAPI _Delegate(void* pv, REFIID iid, void** ppvObject, DWORD_PTR dw)
  2074. {
  2075. HRESULT hRes = E_NOINTERFACE;
  2076. IUnknown* p = *(IUnknown**)((DWORD_PTR)pv + dw);
  2077. if (p != NULL)
  2078. hRes = p->QueryInterface(iid, ppvObject);
  2079. return hRes;
  2080. }
  2081. static HRESULT WINAPI _Chain(void* pv, REFIID iid, void** ppvObject, DWORD_PTR dw)
  2082. {
  2083. _ATL_CHAINDATA* pcd = (_ATL_CHAINDATA*)dw;
  2084. void* p = (void*)((DWORD_PTR)pv + pcd->dwOffset);
  2085. return InternalQueryInterface(p, pcd->pFunc(), iid, ppvObject);
  2086. }
  2087. static HRESULT WINAPI _ChainAttr(void* pv, REFIID iid, void** ppvObject, DWORD_PTR dw)
  2088. {
  2089. const _ATL_INTMAP_ENTRY* (WINAPI *pFunc)() = (const _ATL_INTMAP_ENTRY* (WINAPI *)())dw;
  2090. const _ATL_INTMAP_ENTRY *pEntries = pFunc();
  2091. if (pEntries == NULL)
  2092. return S_OK;
  2093. return InternalQueryInterface(pv, pEntries, iid, ppvObject);
  2094. }
  2095. static HRESULT WINAPI _Cache(void* pv, REFIID iid, void** ppvObject, DWORD_PTR dw)
  2096. {
  2097. HRESULT hRes = E_NOINTERFACE;
  2098. _ATL_CACHEDATA* pcd = (_ATL_CACHEDATA*)dw;
  2099. IUnknown** pp = (IUnknown**)((DWORD_PTR)pv + pcd->dwOffsetVar);
  2100. if (*pp == NULL)
  2101. hRes = pcd->pFunc(pv, __uuidof(IUnknown), (void**)pp);
  2102. if (*pp != NULL)
  2103. hRes = (*pp)->QueryInterface(iid, ppvObject);
  2104. return hRes;
  2105. }
  2106. union
  2107. {
  2108. long m_dwRef;
  2109. IUnknown* m_pOuterUnknown;
  2110. };
  2111. };
  2112. //foward declaration
  2113. template <class ThreadModel>
  2114. class CComObjectRootEx;
  2115. template <class ThreadModel>
  2116. class CComObjectLockT
  2117. {
  2118. public:
  2119. CComObjectLockT(CComObjectRootEx<ThreadModel>* p)
  2120. {
  2121. if (p)
  2122. p->Lock();
  2123. m_p = p;
  2124. }
  2125. ~CComObjectLockT()
  2126. {
  2127. if (m_p)
  2128. m_p->Unlock();
  2129. }
  2130. CComObjectRootEx<ThreadModel>* m_p;
  2131. };
  2132. template <> class CComObjectLockT<CComSingleThreadModel>;
  2133. template <class ThreadModel>
  2134. class CComObjectRootEx : public CComObjectRootBase
  2135. {
  2136. public:
  2137. typedef ThreadModel _ThreadModel;
  2138. typedef _ThreadModel::AutoCriticalSection _CritSec;
  2139. typedef CComObjectLockT<_ThreadModel> ObjectLock;
  2140. ULONG InternalAddRef()
  2141. {
  2142. ATLASSERT(m_dwRef != -1L);
  2143. return _ThreadModel::Increment(&m_dwRef);
  2144. }
  2145. ULONG InternalRelease()
  2146. {
  2147. #ifdef _DEBUG
  2148. LONG nRef = _ThreadModel::Decrement(&m_dwRef);
  2149. if (nRef < -(LONG_MAX / 2))
  2150. {
  2151. ATLASSERT(0 && _T("Release called on a pointer that has already been released"));
  2152. }
  2153. return nRef;
  2154. #else
  2155. return _ThreadModel::Decrement(&m_dwRef);
  2156. #endif
  2157. }
  2158. void Lock() {m_critsec.Lock();}
  2159. void Unlock() {m_critsec.Unlock();}
  2160. private:
  2161. _CritSec m_critsec;
  2162. };
  2163. template <>
  2164. class CComObjectRootEx<CComSingleThreadModel> : public CComObjectRootBase
  2165. {
  2166. public:
  2167. typedef CComSingleThreadModel _ThreadModel;
  2168. typedef _ThreadModel::AutoCriticalSection _CritSec;
  2169. typedef CComObjectLockT<_ThreadModel> ObjectLock;
  2170. ULONG InternalAddRef()
  2171. {
  2172. ATLASSERT(m_dwRef != -1L);
  2173. return _ThreadModel::Increment(&m_dwRef);
  2174. }
  2175. ULONG InternalRelease()
  2176. {
  2177. #ifdef _DEBUG
  2178. long nRef = _ThreadModel::Decrement(&m_dwRef);
  2179. if (nRef < -(LONG_MAX / 2))
  2180. {
  2181. ATLASSERT(0 && _T("Release called on a pointer that has already been released"));
  2182. }
  2183. return nRef;
  2184. #else
  2185. return _ThreadModel::Decrement(&m_dwRef);
  2186. #endif
  2187. }
  2188. void Lock() {}
  2189. void Unlock() {}
  2190. };
  2191. template <>
  2192. class CComObjectLockT<CComSingleThreadModel>
  2193. {
  2194. public:
  2195. CComObjectLockT(CComObjectRootEx<CComSingleThreadModel>*) {}
  2196. ~CComObjectLockT() {}
  2197. };
  2198. typedef CComObjectRootEx<CComObjectThreadModel> CComObjectRoot;
  2199. #if defined(_WINDLL) | defined(_USRDLL)
  2200. #define DECLARE_CLASSFACTORY_EX(cf) typedef ATL::CComCreator< ATL::CComObjectCached< cf > > _ClassFactoryCreatorClass;
  2201. #else
  2202. // don't let class factory refcount influence lock count
  2203. #define DECLARE_CLASSFACTORY_EX(cf) typedef ATL::CComCreator< ATL::CComObjectNoLock< cf > > _ClassFactoryCreatorClass;
  2204. #endif
  2205. #define DECLARE_CLASSFACTORY() DECLARE_CLASSFACTORY_EX(ATL::CComClassFactory)
  2206. #define DECLARE_CLASSFACTORY2(lic) DECLARE_CLASSFACTORY_EX(ATL::CComClassFactory2<lic>)
  2207. #define DECLARE_CLASSFACTORY_AUTO_THREAD() DECLARE_CLASSFACTORY_EX(ATL::CComClassFactoryAutoThread)
  2208. #define DECLARE_CLASSFACTORY_SINGLETON(obj) DECLARE_CLASSFACTORY_EX(ATL::CComClassFactorySingleton<obj>)
  2209. #define DECLARE_OBJECT_DESCRIPTION(x)\
  2210. static LPCTSTR WINAPI GetObjectDescription() throw()\
  2211. {\
  2212. return _T(x);\
  2213. }
  2214. #define DECLARE_NO_REGISTRY()\
  2215. static HRESULT WINAPI UpdateRegistry(BOOL /*bRegister*/) throw()\
  2216. {return S_OK;}
  2217. #define DECLARE_REGISTRY(class, pid, vpid, nid, flags)\
  2218. static HRESULT WINAPI UpdateRegistry(BOOL bRegister) throw()\
  2219. {\
  2220. return _Module.UpdateRegistryClass(GetObjectCLSID(), pid, vpid, nid,\
  2221. flags, bRegister);\
  2222. }
  2223. #define DECLARE_REGISTRY_RESOURCE(x)\
  2224. static HRESULT WINAPI UpdateRegistry(BOOL bRegister) throw()\
  2225. {\
  2226. __if_exists(_GetMiscStatus) \
  2227. { \
  2228. ATL::_ATL_REGMAP_ENTRY regMapEntries[2]; \
  2229. memset(&regMapEntries[1], 0, sizeof(ATL::_ATL_REGMAP_ENTRY)); \
  2230. regMapEntries[0].szKey = L"OLEMISC"; \
  2231. TCHAR szOleMisc[10]; \
  2232. wsprintf(szOleMisc, _T("%d"), _GetMiscStatus()); \
  2233. USES_CONVERSION; \
  2234. regMapEntries[0].szData = T2OLE(szOleMisc); \
  2235. __if_exists(_Module) \
  2236. { \
  2237. return _Module.UpdateRegistryFromResource(_T(#x), bRegister, regMapEntries); \
  2238. } \
  2239. __if_not_exists(_Module) \
  2240. { \
  2241. return ATL::_pAtlModule->UpdateRegistryFromResource(_T(#x), bRegister, regMapEntries); \
  2242. } \
  2243. } \
  2244. __if_not_exists(_GetMiscStatus) \
  2245. { \
  2246. __if_exists(_Module) \
  2247. { \
  2248. return _Module.UpdateRegistryFromResource(_T(#x), bRegister); \
  2249. } \
  2250. __if_not_exists(_Module) \
  2251. { \
  2252. return ATL::_pAtlModule->UpdateRegistryFromResource(_T(#x), bRegister); \
  2253. } \
  2254. } \
  2255. }
  2256. #define DECLARE_REGISTRY_RESOURCEID(x)\
  2257. static HRESULT WINAPI UpdateRegistry(BOOL bRegister) throw()\
  2258. {\
  2259. __if_exists(_GetMiscStatus) \
  2260. { \
  2261. ATL::_ATL_REGMAP_ENTRY regMapEntries[2]; \
  2262. memset(&regMapEntries[1], 0, sizeof(ATL::_ATL_REGMAP_ENTRY)); \
  2263. regMapEntries[0].szKey = L"OLEMISC"; \
  2264. TCHAR szOleMisc[10]; \
  2265. wsprintf(szOleMisc, _T("%d"), _GetMiscStatus()); \
  2266. USES_CONVERSION; \
  2267. regMapEntries[0].szData = T2OLE(szOleMisc); \
  2268. __if_exists(_Module) \
  2269. { \
  2270. return _Module.UpdateRegistryFromResource(x, bRegister, regMapEntries); \
  2271. } \
  2272. __if_not_exists(_Module) \
  2273. { \
  2274. return ATL::_pAtlModule->UpdateRegistryFromResource(x, bRegister, regMapEntries); \
  2275. } \
  2276. } \
  2277. __if_not_exists(_GetMiscStatus) \
  2278. { \
  2279. __if_exists(_Module) \
  2280. { \
  2281. return _Module.UpdateRegistryFromResource(x, bRegister); \
  2282. } \
  2283. __if_not_exists(_Module) \
  2284. { \
  2285. return ATL::_pAtlModule->UpdateRegistryFromResource(x, bRegister); \
  2286. } \
  2287. } \
  2288. }
  2289. //DECLARE_STATIC_* provided for backward compatibility
  2290. #ifdef _ATL_STATIC_REGISTRY
  2291. #define DECLARE_STATIC_REGISTRY_RESOURCE(x) DECLARE_REGISTRY_RESOURCE(x)
  2292. #define DECLARE_STATIC_REGISTRY_RESOURCEID(x) DECLARE_REGISTRY_RESOURCEID(x)
  2293. #endif //_ATL_STATIC_REGISTRY
  2294. #define DECLARE_OLEMISC_STATUS(x) \
  2295. static DWORD _GetMiscStatus() throw() \
  2296. { \
  2297. static DWORD m_dwOleMisc = x; \
  2298. return m_dwOleMisc; \
  2299. }
  2300. template<class Base> class CComObject; // fwd decl
  2301. template <class Owner, class ThreadModel = CComObjectThreadModel>
  2302. class CComTearOffObjectBase : public CComObjectRootEx<ThreadModel>
  2303. {
  2304. public:
  2305. typedef Owner _OwnerClass;
  2306. Owner* m_pOwner;
  2307. CComTearOffObjectBase() {m_pOwner = NULL;}
  2308. };
  2309. //Base is the user's class that derives from CComObjectRoot and whatever
  2310. //interfaces the user wants to support on the object
  2311. template <class Base>
  2312. class CComObject : public Base
  2313. {
  2314. public:
  2315. typedef Base _BaseClass;
  2316. CComObject(void* = NULL) throw()
  2317. {
  2318. _pAtlModule->Lock();
  2319. }
  2320. // Set refcount to -(LONG_MAX/2) to protect destruction and
  2321. // also catch mismatched Release in debug builds
  2322. ~CComObject() throw()
  2323. {
  2324. m_dwRef = -(LONG_MAX/2);
  2325. FinalRelease();
  2326. #ifdef _ATL_DEBUG_INTERFACES
  2327. _AtlDebugInterfacesModule.DeleteNonAddRefThunk(_GetRawUnknown());
  2328. #endif
  2329. _pAtlModule->Unlock();
  2330. }
  2331. //If InternalAddRef or InternalRelease is undefined then your class
  2332. //doesn't derive from CComObjectRoot
  2333. STDMETHOD_(ULONG, AddRef)() throw() {return InternalAddRef();}
  2334. STDMETHOD_(ULONG, Release)() throw()
  2335. {
  2336. ULONG l = InternalRelease();
  2337. if (l == 0)
  2338. delete this;
  2339. return l;
  2340. }
  2341. //if _InternalQueryInterface is undefined then you forgot BEGIN_COM_MAP
  2342. STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject) throw()
  2343. {return _InternalQueryInterface(iid, ppvObject);}
  2344. template <class Q>
  2345. HRESULT STDMETHODCALLTYPE QueryInterface(Q** pp) throw()
  2346. {
  2347. return QueryInterface(__uuidof(Q), (void**)pp);
  2348. }
  2349. static HRESULT WINAPI CreateInstance(CComObject<Base>** pp) throw();
  2350. };
  2351. template <class Base>
  2352. HRESULT WINAPI CComObject<Base>::CreateInstance(CComObject<Base>** pp) throw()
  2353. {
  2354. ATLASSERT(pp != NULL);
  2355. if (pp == NULL)
  2356. return E_POINTER;
  2357. *pp = NULL;
  2358. HRESULT hRes = E_OUTOFMEMORY;
  2359. CComObject<Base>* p = NULL;
  2360. ATLTRY(p = new CComObject<Base>())
  2361. if (p != NULL)
  2362. {
  2363. p->SetVoid(NULL);
  2364. p->InternalFinalConstructAddRef();
  2365. hRes = p->FinalConstruct();
  2366. if (SUCCEEDED(hRes))
  2367. hRes = p->_AtlFinalConstruct();
  2368. p->InternalFinalConstructRelease();
  2369. if (hRes != S_OK)
  2370. {
  2371. delete p;
  2372. p = NULL;
  2373. }
  2374. }
  2375. *pp = p;
  2376. return hRes;
  2377. }
  2378. //Base is the user's class that derives from CComObjectRoot and whatever
  2379. //interfaces the user wants to support on the object
  2380. // CComObjectCached is used primarily for class factories in DLL's
  2381. // but it is useful anytime you want to cache an object
  2382. template <class Base>
  2383. class CComObjectCached : public Base
  2384. {
  2385. public:
  2386. typedef Base _BaseClass;
  2387. CComObjectCached(void* = NULL){}
  2388. // Set refcount to -(LONG_MAX/2) to protect destruction and
  2389. // also catch mismatched Release in debug builds
  2390. ~CComObjectCached()
  2391. {
  2392. m_dwRef = -(LONG_MAX/2);
  2393. FinalRelease();
  2394. #ifdef _ATL_DEBUG_INTERFACES
  2395. _AtlDebugInterfacesModule.DeleteNonAddRefThunk(_GetRawUnknown());
  2396. #endif
  2397. }
  2398. //If InternalAddRef or InternalRelease is undefined then your class
  2399. //doesn't derive from CComObjectRoot
  2400. STDMETHOD_(ULONG, AddRef)()
  2401. {
  2402. m_csCached.Lock();
  2403. ULONG l = InternalAddRef();
  2404. if (m_dwRef == 2)
  2405. _pAtlModule->Lock();
  2406. m_csCached.Unlock();
  2407. return l;
  2408. }
  2409. STDMETHOD_(ULONG, Release)()
  2410. {
  2411. m_csCached.Lock();
  2412. InternalRelease();
  2413. ULONG l = m_dwRef;
  2414. m_csCached.Unlock();
  2415. if (l == 0)
  2416. delete this;
  2417. else if (l == 1)
  2418. _pAtlModule->Unlock();
  2419. return l;
  2420. }
  2421. //if _InternalQueryInterface is undefined then you forgot BEGIN_COM_MAP
  2422. STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
  2423. {return _InternalQueryInterface(iid, ppvObject);}
  2424. CComGlobalsThreadModel::AutoCriticalSection m_csCached;
  2425. };
  2426. //Base is the user's class that derives from CComObjectRoot and whatever
  2427. //interfaces the user wants to support on the object
  2428. template <class Base>
  2429. class CComObjectNoLock : public Base
  2430. {
  2431. public:
  2432. typedef Base _BaseClass;
  2433. CComObjectNoLock(void* = NULL){}
  2434. // Set refcount to -(LONG_MAX/2) to protect destruction and
  2435. // also catch mismatched Release in debug builds
  2436. ~CComObjectNoLock()
  2437. {
  2438. m_dwRef = -(LONG_MAX/2);
  2439. FinalRelease();
  2440. #ifdef _ATL_DEBUG_INTERFACES
  2441. _AtlDebugInterfacesModule.DeleteNonAddRefThunk(_GetRawUnknown());
  2442. #endif
  2443. }
  2444. //If InternalAddRef or InternalRelease is undefined then your class
  2445. //doesn't derive from CComObjectRoot
  2446. STDMETHOD_(ULONG, AddRef)() {return InternalAddRef();}
  2447. STDMETHOD_(ULONG, Release)()
  2448. {
  2449. ULONG l = InternalRelease();
  2450. if (l == 0)
  2451. delete this;
  2452. return l;
  2453. }
  2454. //if _InternalQueryInterface is undefined then you forgot BEGIN_COM_MAP
  2455. STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
  2456. {return _InternalQueryInterface(iid, ppvObject);}
  2457. };
  2458. // It is possible for Base not to derive from CComObjectRoot
  2459. // However, you will need to provide _InternalQueryInterface
  2460. template <class Base>
  2461. class CComObjectGlobal : public Base
  2462. {
  2463. public:
  2464. typedef Base _BaseClass;
  2465. CComObjectGlobal(void* = NULL)
  2466. {
  2467. m_hResFinalConstruct = S_OK;
  2468. __if_exists(FinalConstruct)
  2469. {
  2470. __if_exists(InternalFinalConstructAddRef)
  2471. {
  2472. InternalFinalConstructAddRef();
  2473. }
  2474. m_hResFinalConstruct = FinalConstruct();
  2475. __if_exists(InternalFinalConstructRelease)
  2476. {
  2477. InternalFinalConstructRelease();
  2478. }
  2479. }
  2480. }
  2481. ~CComObjectGlobal()
  2482. {
  2483. __if_exists(FinalRelease)
  2484. {
  2485. FinalRelease();
  2486. }
  2487. #ifdef _ATL_DEBUG_INTERFACES
  2488. _AtlDebugInterfacesModule.DeleteNonAddRefThunk(_GetRawUnknown());
  2489. #endif
  2490. }
  2491. STDMETHOD_(ULONG, AddRef)()
  2492. {
  2493. return _pAtlModule->Lock();
  2494. }
  2495. STDMETHOD_(ULONG, Release)()
  2496. {
  2497. return _pAtlModule->Unlock();
  2498. }
  2499. STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
  2500. {
  2501. return _InternalQueryInterface(iid, ppvObject);
  2502. }
  2503. HRESULT m_hResFinalConstruct;
  2504. };
  2505. // It is possible for Base not to derive from CComObjectRoot
  2506. // However, you will need to provide FinalConstruct and InternalQueryInterface
  2507. template <class Base>
  2508. class CComObjectStack : public Base
  2509. {
  2510. public:
  2511. typedef Base _BaseClass;
  2512. CComObjectStack(void* = NULL){m_hResFinalConstruct = FinalConstruct();}
  2513. ~CComObjectStack()
  2514. {
  2515. FinalRelease();
  2516. #ifdef _ATL_DEBUG_INTERFACES
  2517. _AtlDebugInterfacesModule.DeleteNonAddRefThunk(_GetRawUnknown());
  2518. #endif
  2519. }
  2520. STDMETHOD_(ULONG, AddRef)() {ATLASSERT(FALSE);return 0;}
  2521. STDMETHOD_(ULONG, Release)(){ATLASSERT(FALSE);return 0;}
  2522. STDMETHOD(QueryInterface)(REFIID, void**)
  2523. {ATLASSERT(FALSE);return E_NOINTERFACE;}
  2524. HRESULT m_hResFinalConstruct;
  2525. };
  2526. // Base must be derived from CComObjectRoot
  2527. template <class Base>
  2528. class CComObjectStackEx : public Base
  2529. {
  2530. public:
  2531. typedef Base _BaseClass;
  2532. CComObjectStackEx(void* = NULL)
  2533. {
  2534. #ifdef _DEBUG
  2535. m_dwRef = 0;
  2536. #endif
  2537. m_hResFinalConstruct = FinalConstruct();
  2538. }
  2539. ~CComObjectStackEx()
  2540. {
  2541. // This assert indicates mismatched ref counts.
  2542. //
  2543. // The ref count has no control over the
  2544. // lifetime of this object, so you must ensure
  2545. // by some other means that the object remains
  2546. // alive while clients have references to its interfaces.
  2547. ATLASSERT(m_dwRef == 0);
  2548. FinalRelease();
  2549. #ifdef _ATL_DEBUG_INTERFACES
  2550. _AtlDebugInterfacesModule.DeleteNonAddRefThunk(_GetRawUnknown());
  2551. #endif
  2552. }
  2553. STDMETHOD_(ULONG, AddRef)()
  2554. {
  2555. #ifdef _DEBUG
  2556. return InternalAddRef();
  2557. #else
  2558. return 0;
  2559. #endif
  2560. }
  2561. STDMETHOD_(ULONG, Release)()
  2562. {
  2563. #ifdef _DEBUG
  2564. return InternalRelease();
  2565. #else
  2566. return 0;
  2567. #endif
  2568. }
  2569. STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
  2570. {
  2571. return _InternalQueryInterface(iid, ppvObject);
  2572. }
  2573. HRESULT m_hResFinalConstruct;
  2574. };
  2575. template <class Base> //Base must be derived from CComObjectRoot
  2576. class CComContainedObject : public Base
  2577. {
  2578. public:
  2579. typedef Base _BaseClass;
  2580. CComContainedObject(void* pv) {m_pOuterUnknown = (IUnknown*)pv;}
  2581. #ifdef _ATL_DEBUG_INTERFACES
  2582. ~CComContainedObject()
  2583. {
  2584. _AtlDebugInterfacesModule.DeleteNonAddRefThunk(_GetRawUnknown());
  2585. _AtlDebugInterfacesModule.DeleteNonAddRefThunk(m_pOuterUnknown);
  2586. }
  2587. #endif
  2588. STDMETHOD_(ULONG, AddRef)() {return OuterAddRef();}
  2589. STDMETHOD_(ULONG, Release)() {return OuterRelease();}
  2590. STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
  2591. {
  2592. return OuterQueryInterface(iid, ppvObject);
  2593. }
  2594. template <class Q>
  2595. HRESULT STDMETHODCALLTYPE QueryInterface(Q** pp)
  2596. {
  2597. return QueryInterface(__uuidof(Q), (void**)pp);
  2598. }
  2599. //GetControllingUnknown may be virtual if the Base class has declared
  2600. //DECLARE_GET_CONTROLLING_UNKNOWN()
  2601. IUnknown* GetControllingUnknown()
  2602. {
  2603. #ifdef _ATL_DEBUG_INTERFACES
  2604. IUnknown* p;
  2605. _AtlDebugInterfacesModule.AddNonAddRefThunk(m_pOuterUnknown, _T("CComContainedObject"), &p);
  2606. return p;
  2607. #else
  2608. return m_pOuterUnknown;
  2609. #endif
  2610. }
  2611. };
  2612. //contained is the user's class that derives from CComObjectRoot and whatever
  2613. //interfaces the user wants to support on the object
  2614. template <class contained>
  2615. class CComAggObject :
  2616. public IUnknown,
  2617. public CComObjectRootEx< contained::_ThreadModel::ThreadModelNoCS >
  2618. {
  2619. public:
  2620. typedef contained _BaseClass;
  2621. CComAggObject(void* pv) : m_contained(pv)
  2622. {
  2623. _pAtlModule->Lock();
  2624. }
  2625. //If you get a message that this call is ambiguous then you need to
  2626. // override it in your class and call each base class' version of this
  2627. HRESULT FinalConstruct()
  2628. {
  2629. CComObjectRootEx<contained::_ThreadModel::ThreadModelNoCS>::FinalConstruct();
  2630. return m_contained.FinalConstruct();
  2631. }
  2632. void FinalRelease()
  2633. {
  2634. CComObjectRootEx<contained::_ThreadModel::ThreadModelNoCS>::FinalRelease();
  2635. m_contained.FinalRelease();
  2636. }
  2637. // Set refcount to -(LONG_MAX/2) to protect destruction and
  2638. // also catch mismatched Release in debug builds
  2639. ~CComAggObject()
  2640. {
  2641. m_dwRef = -(LONG_MAX/2);
  2642. FinalRelease();
  2643. #ifdef _ATL_DEBUG_INTERFACES
  2644. _AtlDebugInterfacesModule.DeleteNonAddRefThunk(this);
  2645. #endif
  2646. _pAtlModule->Unlock();
  2647. }
  2648. STDMETHOD_(ULONG, AddRef)() {return InternalAddRef();}
  2649. STDMETHOD_(ULONG, Release)()
  2650. {
  2651. ULONG l = InternalRelease();
  2652. if (l == 0)
  2653. delete this;
  2654. return l;
  2655. }
  2656. STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
  2657. {
  2658. ATLASSERT(ppvObject != NULL);
  2659. if (ppvObject == NULL)
  2660. return E_POINTER;
  2661. *ppvObject = NULL;
  2662. HRESULT hRes = S_OK;
  2663. if (InlineIsEqualUnknown(iid))
  2664. {
  2665. *ppvObject = (void*)(IUnknown*)this;
  2666. AddRef();
  2667. #ifdef _ATL_DEBUG_INTERFACES
  2668. _AtlDebugInterfacesModule.AddThunk((IUnknown**)ppvObject, (LPCTSTR)contained::_GetEntries()[-1].dw, iid);
  2669. #endif // _ATL_DEBUG_INTERFACES
  2670. }
  2671. else
  2672. hRes = m_contained._InternalQueryInterface(iid, ppvObject);
  2673. return hRes;
  2674. }
  2675. template <class Q>
  2676. HRESULT STDMETHODCALLTYPE QueryInterface(Q** pp)
  2677. {
  2678. return QueryInterface(__uuidof(Q), (void**)pp);
  2679. }
  2680. static HRESULT WINAPI CreateInstance(LPUNKNOWN pUnkOuter, CComAggObject<contained>** pp)
  2681. {
  2682. ATLASSERT(pp != NULL);
  2683. HRESULT hRes = E_OUTOFMEMORY;
  2684. CComAggObject<contained>* p = NULL;
  2685. ATLTRY(p = new CComAggObject<contained>(pUnkOuter))
  2686. if (p != NULL)
  2687. {
  2688. p->SetVoid(NULL);
  2689. p->InternalFinalConstructAddRef();
  2690. hRes = p->FinalConstruct();
  2691. if (SUCCEEDED(hRes))
  2692. hRes = p->_AtlFinalConstruct();
  2693. p->InternalFinalConstructRelease();
  2694. if (hRes != S_OK)
  2695. {
  2696. delete p;
  2697. p = NULL;
  2698. }
  2699. }
  2700. *pp = p;
  2701. return hRes;
  2702. }
  2703. CComContainedObject<contained> m_contained;
  2704. };
  2705. ///////////////////////////////////////////////////////////////////////////////
  2706. // CComPolyObject can be either aggregated or not aggregated
  2707. template <class contained>
  2708. class CComPolyObject :
  2709. public IUnknown,
  2710. public CComObjectRootEx< contained::_ThreadModel::ThreadModelNoCS >
  2711. {
  2712. public:
  2713. typedef contained _BaseClass;
  2714. CComPolyObject(void* pv) : m_contained(pv ? pv : this)
  2715. {
  2716. _pAtlModule->Lock();
  2717. }
  2718. //If you get a message that this call is ambiguous then you need to
  2719. // override it in your class and call each base class' version of this
  2720. HRESULT FinalConstruct()
  2721. {
  2722. InternalAddRef();
  2723. CComObjectRootEx<contained::_ThreadModel::ThreadModelNoCS>::FinalConstruct();
  2724. HRESULT hr = m_contained.FinalConstruct();
  2725. InternalRelease();
  2726. return hr;
  2727. }
  2728. void FinalRelease()
  2729. {
  2730. CComObjectRootEx<contained::_ThreadModel::ThreadModelNoCS>::FinalRelease();
  2731. m_contained.FinalRelease();
  2732. }
  2733. // Set refcount to -(LONG_MAX/2) to protect destruction and
  2734. // also catch mismatched Release in debug builds
  2735. ~CComPolyObject()
  2736. {
  2737. m_dwRef = -(LONG_MAX/2);
  2738. FinalRelease();
  2739. #ifdef _ATL_DEBUG_INTERFACES
  2740. _AtlDebugInterfacesModule.DeleteNonAddRefThunk(this);
  2741. #endif
  2742. _pAtlModule->Unlock();
  2743. }
  2744. STDMETHOD_(ULONG, AddRef)() {return InternalAddRef();}
  2745. STDMETHOD_(ULONG, Release)()
  2746. {
  2747. ULONG l = InternalRelease();
  2748. if (l == 0)
  2749. delete this;
  2750. return l;
  2751. }
  2752. STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
  2753. {
  2754. #ifndef _ATL_OLEDB_CONFORMANCE_TESTS
  2755. ATLASSERT(ppvObject != NULL);
  2756. #endif
  2757. if (ppvObject == NULL)
  2758. return E_POINTER;
  2759. *ppvObject = NULL;
  2760. HRESULT hRes = S_OK;
  2761. if (InlineIsEqualUnknown(iid))
  2762. {
  2763. *ppvObject = (void*)(IUnknown*)this;
  2764. AddRef();
  2765. #ifdef _ATL_DEBUG_INTERFACES
  2766. _AtlDebugInterfacesModule.AddThunk((IUnknown**)ppvObject, (LPCTSTR)contained::_GetEntries()[-1].dw, iid);
  2767. #endif // _ATL_DEBUG_INTERFACES
  2768. }
  2769. else
  2770. hRes = m_contained._InternalQueryInterface(iid, ppvObject);
  2771. return hRes;
  2772. }
  2773. template <class Q>
  2774. HRESULT STDMETHODCALLTYPE QueryInterface(Q** pp)
  2775. {
  2776. return QueryInterface(__uuidof(Q), (void**)pp);
  2777. }
  2778. static HRESULT WINAPI CreateInstance(LPUNKNOWN pUnkOuter, CComPolyObject<contained>** pp)
  2779. {
  2780. ATLASSERT(pp != NULL);
  2781. if (pp == NULL)
  2782. return E_POINTER;
  2783. HRESULT hRes = E_OUTOFMEMORY;
  2784. CComPolyObject<contained>* p = NULL;
  2785. ATLTRY(p = new CComPolyObject<contained>(pUnkOuter))
  2786. if (p != NULL)
  2787. {
  2788. p->SetVoid(NULL);
  2789. p->InternalFinalConstructAddRef();
  2790. hRes = p->FinalConstruct();
  2791. if (SUCCEEDED(hRes))
  2792. hRes = p->_AtlFinalConstruct();
  2793. p->InternalFinalConstructRelease();
  2794. if (hRes != S_OK)
  2795. {
  2796. delete p;
  2797. p = NULL;
  2798. }
  2799. }
  2800. *pp = p;
  2801. return hRes;
  2802. }
  2803. CComContainedObject<contained> m_contained;
  2804. };
  2805. template <class Base>
  2806. class CComTearOffObject : public Base
  2807. {
  2808. public:
  2809. CComTearOffObject(void* pv)
  2810. {
  2811. ATLASSERT(m_pOwner == NULL);
  2812. m_pOwner = reinterpret_cast<Base::_OwnerClass*>(pv);
  2813. m_pOwner->AddRef();
  2814. }
  2815. // Set refcount to -(LONG_MAX/2) to protect destruction and
  2816. // also catch mismatched Release in debug builds
  2817. ~CComTearOffObject()
  2818. {
  2819. m_dwRef = -(LONG_MAX/2);
  2820. FinalRelease();
  2821. #ifdef _ATL_DEBUG_INTERFACES
  2822. _AtlDebugInterfacesModule.DeleteNonAddRefThunk(_GetRawUnknown());
  2823. #endif
  2824. m_pOwner->Release();
  2825. }
  2826. STDMETHOD_(ULONG, AddRef)() {return InternalAddRef();}
  2827. STDMETHOD_(ULONG, Release)()
  2828. {
  2829. ULONG l = InternalRelease();
  2830. if (l == 0)
  2831. delete this;
  2832. return l;
  2833. }
  2834. STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
  2835. {
  2836. return m_pOwner->QueryInterface(iid, ppvObject);
  2837. }
  2838. };
  2839. template <class contained>
  2840. class CComCachedTearOffObject :
  2841. public IUnknown,
  2842. public CComObjectRootEx<contained::_ThreadModel::ThreadModelNoCS>
  2843. {
  2844. public:
  2845. typedef contained _BaseClass;
  2846. CComCachedTearOffObject(void* pv) :
  2847. m_contained(((contained::_OwnerClass*)pv)->GetControllingUnknown())
  2848. {
  2849. ATLASSERT(m_contained.m_pOwner == NULL);
  2850. m_contained.m_pOwner = reinterpret_cast<contained::_OwnerClass*>(pv);
  2851. }
  2852. //If you get a message that this call is ambiguous then you need to
  2853. // override it in your class and call each base class' version of this
  2854. HRESULT FinalConstruct()
  2855. {
  2856. CComObjectRootEx<contained::_ThreadModel::ThreadModelNoCS>::FinalConstruct();
  2857. return m_contained.FinalConstruct();
  2858. }
  2859. void FinalRelease()
  2860. {
  2861. CComObjectRootEx<contained::_ThreadModel::ThreadModelNoCS>::FinalRelease();
  2862. m_contained.FinalRelease();
  2863. }
  2864. // Set refcount to -(LONG_MAX/2) to protect destruction and
  2865. // also catch mismatched Release in debug builds
  2866. ~CComCachedTearOffObject()
  2867. {
  2868. m_dwRef = -(LONG_MAX/2);
  2869. FinalRelease();
  2870. #ifdef _ATL_DEBUG_INTERFACES
  2871. _AtlDebugInterfacesModule.DeleteNonAddRefThunk(this);
  2872. #endif
  2873. }
  2874. STDMETHOD_(ULONG, AddRef)() {return InternalAddRef();}
  2875. STDMETHOD_(ULONG, Release)()
  2876. {
  2877. ULONG l = InternalRelease();
  2878. if (l == 0)
  2879. delete this;
  2880. return l;
  2881. }
  2882. STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
  2883. {
  2884. ATLASSERT(ppvObject != NULL);
  2885. if (ppvObject == NULL)
  2886. return E_POINTER;
  2887. *ppvObject = NULL;
  2888. HRESULT hRes = S_OK;
  2889. if (InlineIsEqualUnknown(iid))
  2890. {
  2891. *ppvObject = (void*)(IUnknown*)this;
  2892. AddRef();
  2893. #ifdef _ATL_DEBUG_INTERFACES
  2894. _AtlDebugInterfacesModule.AddThunk((IUnknown**)ppvObject, (LPCTSTR)contained::_GetEntries()[-1].dw, iid);
  2895. #endif // _ATL_DEBUG_INTERFACES
  2896. }
  2897. else
  2898. hRes = m_contained._InternalQueryInterface(iid, ppvObject);
  2899. return hRes;
  2900. }
  2901. CComContainedObject<contained> m_contained;
  2902. };
  2903. class CComClassFactory :
  2904. public IClassFactory,
  2905. public CComObjectRootEx<CComGlobalsThreadModel>
  2906. {
  2907. public:
  2908. BEGIN_COM_MAP(CComClassFactory)
  2909. COM_INTERFACE_ENTRY(IClassFactory)
  2910. END_COM_MAP()
  2911. // IClassFactory
  2912. STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid, void** ppvObj)
  2913. {
  2914. ATLASSERT(m_pfnCreateInstance != NULL);
  2915. HRESULT hRes = E_POINTER;
  2916. if (ppvObj != NULL)
  2917. {
  2918. *ppvObj = NULL;
  2919. // can't ask for anything other than IUnknown when aggregating
  2920. if ((pUnkOuter != NULL) && !InlineIsEqualUnknown(riid))
  2921. {
  2922. ATLTRACE(atlTraceCOM, 0, _T("CComClassFactory: asked for non IUnknown interface while creating an aggregated object"));
  2923. hRes = CLASS_E_NOAGGREGATION;
  2924. }
  2925. else
  2926. hRes = m_pfnCreateInstance(pUnkOuter, riid, ppvObj);
  2927. }
  2928. return hRes;
  2929. }
  2930. STDMETHOD(LockServer)(BOOL fLock)
  2931. {
  2932. if (fLock)
  2933. _pAtlModule->Lock();
  2934. else
  2935. _pAtlModule->Unlock();
  2936. return S_OK;
  2937. }
  2938. // helper
  2939. void SetVoid(void* pv)
  2940. {
  2941. m_pfnCreateInstance = (_ATL_CREATORFUNC*)pv;
  2942. }
  2943. _ATL_CREATORFUNC* m_pfnCreateInstance;
  2944. };
  2945. template <class license>
  2946. class CComClassFactory2 :
  2947. public IClassFactory2,
  2948. public CComObjectRootEx<CComGlobalsThreadModel>,
  2949. public license
  2950. {
  2951. public:
  2952. typedef license _LicenseClass;
  2953. typedef CComClassFactory2<license> _ComMapClass;
  2954. BEGIN_COM_MAP(CComClassFactory2<license>)
  2955. COM_INTERFACE_ENTRY(IClassFactory)
  2956. COM_INTERFACE_ENTRY(IClassFactory2)
  2957. END_COM_MAP()
  2958. // IClassFactory
  2959. STDMETHOD(LockServer)(BOOL fLock)
  2960. {
  2961. if (fLock)
  2962. _pAtlModule->Lock();
  2963. else
  2964. _pAtlModule->Unlock();
  2965. return S_OK;
  2966. }
  2967. STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter,
  2968. REFIID riid, void** ppvObj)
  2969. {
  2970. ATLASSERT(m_pfnCreateInstance != NULL);
  2971. if (ppvObj == NULL)
  2972. return E_POINTER;
  2973. *ppvObj = NULL;
  2974. if (!IsLicenseValid())
  2975. return CLASS_E_NOTLICENSED;
  2976. if ((pUnkOuter != NULL) && !InlineIsEqualUnknown(riid))
  2977. return CLASS_E_NOAGGREGATION;
  2978. else
  2979. return m_pfnCreateInstance(pUnkOuter, riid, ppvObj);
  2980. }
  2981. // IClassFactory2
  2982. STDMETHOD(CreateInstanceLic)(IUnknown* pUnkOuter,
  2983. IUnknown* /* pUnkReserved */, REFIID riid, BSTR bstrKey,
  2984. void** ppvObject)
  2985. {
  2986. ATLASSERT(m_pfnCreateInstance != NULL);
  2987. if (ppvObject == NULL)
  2988. return E_POINTER;
  2989. *ppvObject = NULL;
  2990. if ( ((bstrKey != NULL) && !VerifyLicenseKey(bstrKey)) ||
  2991. ((bstrKey == NULL) && !IsLicenseValid()) )
  2992. return CLASS_E_NOTLICENSED;
  2993. if ((pUnkOuter != NULL) && !InlineIsEqualUnknown(riid))
  2994. return CLASS_E_NOAGGREGATION;
  2995. else
  2996. return m_pfnCreateInstance(pUnkOuter, riid, ppvObject);
  2997. }
  2998. STDMETHOD(RequestLicKey)(DWORD dwReserved, BSTR* pbstrKey)
  2999. {
  3000. if (pbstrKey == NULL)
  3001. return E_POINTER;
  3002. *pbstrKey = NULL;
  3003. if (!IsLicenseValid())
  3004. return CLASS_E_NOTLICENSED;
  3005. return GetLicenseKey(dwReserved,pbstrKey) ? S_OK : E_FAIL;
  3006. }
  3007. STDMETHOD(GetLicInfo)(LICINFO* pLicInfo)
  3008. {
  3009. if (pLicInfo == NULL)
  3010. return E_POINTER;
  3011. pLicInfo->cbLicInfo = sizeof(LICINFO);
  3012. pLicInfo->fLicVerified = IsLicenseValid();
  3013. BSTR bstr = NULL;
  3014. pLicInfo->fRuntimeKeyAvail = GetLicenseKey(0,&bstr);
  3015. ::SysFreeString(bstr);
  3016. return S_OK;
  3017. }
  3018. void SetVoid(void* pv)
  3019. {
  3020. m_pfnCreateInstance = (_ATL_CREATORFUNC*)pv;
  3021. }
  3022. _ATL_CREATORFUNC* m_pfnCreateInstance;
  3023. };
  3024. /////////////////////////////////////////////////////////////////////////////////////////////
  3025. // Thread Pooling class factory
  3026. class CComClassFactoryAutoThread :
  3027. public IClassFactory,
  3028. public CComObjectRootEx<CComGlobalsThreadModel>
  3029. {
  3030. public:
  3031. BEGIN_COM_MAP(CComClassFactoryAutoThread)
  3032. COM_INTERFACE_ENTRY(IClassFactory)
  3033. END_COM_MAP()
  3034. // helper
  3035. void SetVoid(void* pv)
  3036. {
  3037. m_pfnCreateInstance = (_ATL_CREATORFUNC*)pv;
  3038. }
  3039. STDMETHODIMP CreateInstance(LPUNKNOWN pUnkOuter,
  3040. REFIID riid, void** ppvObj)
  3041. {
  3042. ATLASSERT(m_pfnCreateInstance != NULL);
  3043. HRESULT hRes = E_POINTER;
  3044. if (ppvObj != NULL)
  3045. {
  3046. *ppvObj = NULL;
  3047. // cannot aggregate across apartments
  3048. ATLASSERT(pUnkOuter == NULL);
  3049. if (pUnkOuter != NULL)
  3050. hRes = CLASS_E_NOAGGREGATION;
  3051. else
  3052. {
  3053. ATLASSERT(_pAtlAutoThreadModule && _T("Global instance of CAtlAutoThreadModule not declared"));
  3054. if (_pAtlAutoThreadModule == NULL)
  3055. return E_FAIL;
  3056. hRes = _pAtlAutoThreadModule->CreateInstance(m_pfnCreateInstance, riid, ppvObj);
  3057. }
  3058. }
  3059. return hRes;
  3060. }
  3061. STDMETHODIMP LockServer(BOOL fLock)
  3062. {
  3063. if (fLock)
  3064. _pAtlModule->Lock();
  3065. else
  3066. _pAtlModule->Unlock();
  3067. return S_OK;
  3068. }
  3069. _ATL_CREATORFUNC* m_pfnCreateInstance;
  3070. };
  3071. /////////////////////////////////////////////////////////////////////////////////////////////
  3072. // Singleton Class Factory
  3073. template <class T>
  3074. class CComClassFactorySingleton : public CComClassFactory
  3075. {
  3076. public:
  3077. // IClassFactory
  3078. STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid, void** ppvObj)
  3079. {
  3080. HRESULT hRes = E_POINTER;
  3081. if (ppvObj != NULL)
  3082. {
  3083. *ppvObj = NULL;
  3084. // aggregation is not supported in Singletons
  3085. ATLASSERT(pUnkOuter == NULL);
  3086. if (pUnkOuter != NULL)
  3087. hRes = CLASS_E_NOAGGREGATION;
  3088. else
  3089. {
  3090. if (m_Obj.m_hResFinalConstruct != S_OK)
  3091. hRes = m_Obj.m_hResFinalConstruct;
  3092. else
  3093. hRes = m_Obj.QueryInterface(riid, ppvObj);
  3094. }
  3095. }
  3096. return hRes;
  3097. }
  3098. CComObjectGlobal<T> m_Obj;
  3099. };
  3100. template <class T, const CLSID* pclsid = &CLSID_NULL>
  3101. class CComCoClass
  3102. {
  3103. public:
  3104. DECLARE_CLASSFACTORY()
  3105. DECLARE_AGGREGATABLE(T)
  3106. typedef T _CoClass;
  3107. static const CLSID& WINAPI GetObjectCLSID() {return *pclsid;}
  3108. static LPCTSTR WINAPI GetObjectDescription() {return NULL;}
  3109. static HRESULT WINAPI Error(LPCOLESTR lpszDesc,
  3110. const IID& iid = GUID_NULL, HRESULT hRes = 0)
  3111. {
  3112. return AtlReportError(GetObjectCLSID(), lpszDesc, iid, hRes);
  3113. }
  3114. static HRESULT WINAPI Error(LPCOLESTR lpszDesc, DWORD dwHelpID,
  3115. LPCOLESTR lpszHelpFile, const IID& iid = GUID_NULL, HRESULT hRes = 0)
  3116. {
  3117. return AtlReportError(GetObjectCLSID(), lpszDesc, dwHelpID, lpszHelpFile,
  3118. iid, hRes);
  3119. }
  3120. static HRESULT WINAPI Error(UINT nID, const IID& iid = GUID_NULL,
  3121. HRESULT hRes = 0, HINSTANCE hInst = _AtlBaseModule.GetResourceInstance())
  3122. {
  3123. return AtlReportError(GetObjectCLSID(), nID, iid, hRes, hInst);
  3124. }
  3125. static HRESULT WINAPI Error(UINT nID, DWORD dwHelpID,
  3126. LPCOLESTR lpszHelpFile, const IID& iid = GUID_NULL,
  3127. HRESULT hRes = 0, HINSTANCE hInst = _AtlBaseModule.GetResourceInstance())
  3128. {
  3129. return AtlReportError(GetObjectCLSID(), nID, dwHelpID, lpszHelpFile,
  3130. iid, hRes, hInst);
  3131. }
  3132. static HRESULT WINAPI Error(LPCSTR lpszDesc,
  3133. const IID& iid = GUID_NULL, HRESULT hRes = 0)
  3134. {
  3135. return AtlReportError(GetObjectCLSID(), lpszDesc, iid, hRes);
  3136. }
  3137. static HRESULT WINAPI Error(LPCSTR lpszDesc, DWORD dwHelpID,
  3138. LPCSTR lpszHelpFile, const IID& iid = GUID_NULL, HRESULT hRes = 0)
  3139. {
  3140. return AtlReportError(GetObjectCLSID(), lpszDesc, dwHelpID,
  3141. lpszHelpFile, iid, hRes);
  3142. }
  3143. template <class Q>
  3144. static HRESULT CreateInstance(IUnknown* punkOuter, Q** pp)
  3145. {
  3146. return T::_CreatorClass::CreateInstance(punkOuter, __uuidof(Q), (void**) pp);
  3147. }
  3148. template <class Q>
  3149. static HRESULT CreateInstance(Q** pp)
  3150. {
  3151. return T::_CreatorClass::CreateInstance(NULL, __uuidof(Q), (void**) pp);
  3152. }
  3153. };
  3154. // ATL doesn't support multiple LCID's at the same time
  3155. // Whatever LCID is queried for first is the one that is used.
  3156. class CComTypeInfoHolder
  3157. {
  3158. // Should be 'protected' but can cause compiler to generate fat code.
  3159. public:
  3160. const GUID* m_pguid;
  3161. const GUID* m_plibid;
  3162. WORD m_wMajor;
  3163. WORD m_wMinor;
  3164. ITypeInfo* m_pInfo;
  3165. long m_dwRef;
  3166. struct stringdispid
  3167. {
  3168. CComBSTR bstr;
  3169. int nLen;
  3170. DISPID id;
  3171. };
  3172. stringdispid* m_pMap;
  3173. int m_nCount;
  3174. public:
  3175. #ifdef _ATL_DLL_IMPL
  3176. CComTypeInfoHolder(const GUID* pguid, const GUID* plibid, WORD wMajor, WORD wMinor) :
  3177. m_pguid(pguid), m_plibid(plibid), m_wMajor(wMajor), m_wMinor(wMinor),
  3178. m_pInfo(NULL), m_dwRef(0), m_pMap(NULL), m_nCount(0)
  3179. {
  3180. }
  3181. ~CComTypeInfoHolder()
  3182. {
  3183. if (m_pInfo != NULL)
  3184. m_pInfo->Release();
  3185. m_pInfo = NULL;
  3186. delete [] m_pMap;
  3187. m_pMap = NULL;
  3188. }
  3189. #endif
  3190. HRESULT GetTI(LCID lcid, ITypeInfo** ppInfo)
  3191. {
  3192. ATLASSERT(ppInfo != NULL);
  3193. if (ppInfo == NULL)
  3194. return E_POINTER;
  3195. HRESULT hr = S_OK;
  3196. if (m_pInfo == NULL)
  3197. hr = GetTI(lcid);
  3198. *ppInfo = m_pInfo;
  3199. if (m_pInfo != NULL)
  3200. {
  3201. m_pInfo->AddRef();
  3202. hr = S_OK;
  3203. }
  3204. return hr;
  3205. }
  3206. HRESULT GetTI(LCID lcid);
  3207. HRESULT EnsureTI(LCID lcid)
  3208. {
  3209. HRESULT hr = S_OK;
  3210. if (m_pInfo == NULL || m_pMap == NULL)
  3211. hr = GetTI(lcid);
  3212. return hr;
  3213. }
  3214. // This function is called by the module on exit
  3215. // It is registered through _pAtlModule->AddTermFunc()
  3216. static void __stdcall Cleanup(DWORD_PTR dw)
  3217. {
  3218. CComTypeInfoHolder* p = (CComTypeInfoHolder*) dw;
  3219. if (p->m_pInfo != NULL)
  3220. p->m_pInfo->Release();
  3221. p->m_pInfo = NULL;
  3222. delete [] p->m_pMap;
  3223. p->m_pMap = NULL;
  3224. }
  3225. HRESULT GetTypeInfo(UINT /* itinfo */, LCID lcid, ITypeInfo** pptinfo)
  3226. {
  3227. HRESULT hRes = E_POINTER;
  3228. if (pptinfo != NULL)
  3229. hRes = GetTI(lcid, pptinfo);
  3230. return hRes;
  3231. }
  3232. HRESULT GetIDsOfNames(REFIID /* riid */, LPOLESTR* rgszNames, UINT cNames,
  3233. LCID lcid, DISPID* rgdispid)
  3234. {
  3235. HRESULT hRes = EnsureTI(lcid);
  3236. if (m_pInfo != NULL)
  3237. {
  3238. if (m_pMap != NULL)
  3239. {
  3240. for (int i=0; i<(int)cNames; i++)
  3241. {
  3242. int n = int( ocslen(rgszNames[i]) );
  3243. int j;
  3244. for (j=m_nCount-1; j>=0; j--)
  3245. {
  3246. if ((n == m_pMap[j].nLen) &&
  3247. (memcmp(m_pMap[j].bstr, rgszNames[i], m_pMap[j].nLen * sizeof(OLECHAR)) == 0))
  3248. {
  3249. rgdispid[i] = m_pMap[j].id;
  3250. break;
  3251. }
  3252. }
  3253. // if name is not in cache, delegate to ITypeInfo::GetIDsOfNames
  3254. if (j < 0)
  3255. {
  3256. hRes = m_pInfo->GetIDsOfNames(rgszNames, cNames, rgdispid);
  3257. // since we've gotten all names, break out of loop
  3258. break;
  3259. }
  3260. }
  3261. }
  3262. else
  3263. hRes = m_pInfo->GetIDsOfNames(rgszNames, cNames, rgdispid);
  3264. }
  3265. return hRes;
  3266. }
  3267. HRESULT Invoke(IDispatch* p, DISPID dispidMember, REFIID /* riid */,
  3268. LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult,
  3269. EXCEPINFO* pexcepinfo, UINT* puArgErr)
  3270. {
  3271. HRESULT hRes = EnsureTI(lcid);
  3272. if (m_pInfo != NULL)
  3273. hRes = m_pInfo->Invoke(p, dispidMember, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
  3274. return hRes;
  3275. }
  3276. HRESULT LoadNameCache(ITypeInfo* pTypeInfo)
  3277. {
  3278. TYPEATTR* pta;
  3279. HRESULT hr = pTypeInfo->GetTypeAttr(&pta);
  3280. if (SUCCEEDED(hr))
  3281. {
  3282. m_nCount = pta->cFuncs;
  3283. m_pMap = NULL;
  3284. if (m_nCount != 0)
  3285. {
  3286. ATLTRY(m_pMap = new stringdispid[m_nCount]);
  3287. if (m_pMap == NULL)
  3288. {
  3289. pTypeInfo->ReleaseTypeAttr(pta);
  3290. return E_OUTOFMEMORY;
  3291. }
  3292. }
  3293. for (int i=0; i<m_nCount; i++)
  3294. {
  3295. FUNCDESC* pfd;
  3296. if (SUCCEEDED(pTypeInfo->GetFuncDesc(i, &pfd)))
  3297. {
  3298. CComBSTR bstrName;
  3299. if (SUCCEEDED(pTypeInfo->GetDocumentation(pfd->memid, &bstrName, NULL, NULL, NULL)))
  3300. {
  3301. m_pMap[i].bstr.Attach(bstrName.Detach());
  3302. m_pMap[i].nLen = SysStringLen(m_pMap[i].bstr);
  3303. m_pMap[i].id = pfd->memid;
  3304. }
  3305. pTypeInfo->ReleaseFuncDesc(pfd);
  3306. }
  3307. }
  3308. pTypeInfo->ReleaseTypeAttr(pta);
  3309. }
  3310. return S_OK;
  3311. }
  3312. };
  3313. inline HRESULT CComTypeInfoHolder::GetTI(LCID lcid)
  3314. {
  3315. //If this assert occurs then most likely didn't initialize properly
  3316. ATLASSERT(m_plibid != NULL && m_pguid != NULL);
  3317. ATLASSERT(!InlineIsEqualGUID(*m_plibid, GUID_NULL) && "Did you forget to pass the LIBID to CComModule::Init?");
  3318. if (m_pInfo != NULL && m_pMap != NULL)
  3319. return S_OK;
  3320. CComCritSecLock<CComCriticalSection> lock(_pAtlModule->m_csStaticDataInitAndTypeInfo, false);
  3321. HRESULT hRes = lock.Lock();
  3322. if (FAILED(hRes))
  3323. {
  3324. ATLTRACE(atlTraceCOM, 0, _T("ERROR : Unable to lock critical section in CComTypeInfoHolder::GetTI\n"));
  3325. ATLASSERT(0);
  3326. return hRes;
  3327. }
  3328. hRes = E_FAIL;
  3329. if (m_pInfo == NULL)
  3330. {
  3331. ITypeLib* pTypeLib;
  3332. hRes = LoadRegTypeLib(*m_plibid, m_wMajor, m_wMinor, lcid, &pTypeLib);
  3333. if (SUCCEEDED(hRes))
  3334. {
  3335. CComPtr<ITypeInfo> spTypeInfo;
  3336. hRes = pTypeLib->GetTypeInfoOfGuid(*m_pguid, &spTypeInfo);
  3337. if (SUCCEEDED(hRes))
  3338. {
  3339. CComPtr<ITypeInfo> spInfo(spTypeInfo);
  3340. CComPtr<ITypeInfo2> spTypeInfo2;
  3341. if (SUCCEEDED(spTypeInfo->QueryInterface(&spTypeInfo2)))
  3342. spInfo = spTypeInfo2;
  3343. m_pInfo = spInfo.Detach();
  3344. }
  3345. pTypeLib->Release();
  3346. #ifndef _ATL_DLL_IMPL
  3347. _pAtlModule->AddTermFunc(Cleanup, (DWORD_PTR)this);
  3348. #endif
  3349. }
  3350. }
  3351. else
  3352. {
  3353. // Another thread has loaded the typeinfo so we're OK.
  3354. hRes = S_OK;
  3355. }
  3356. if (m_pInfo != NULL && m_pMap == NULL)
  3357. LoadNameCache(m_pInfo);
  3358. return hRes;
  3359. }
  3360. //////////////////////////////////////////////////////////////////////////////
  3361. // IObjectWithSite
  3362. //
  3363. template <class T>
  3364. class ATL_NO_VTABLE IObjectWithSiteImpl : public IObjectWithSite
  3365. {
  3366. public:
  3367. STDMETHOD(SetSite)(IUnknown *pUnkSite)
  3368. {
  3369. ATLTRACE(atlTraceCOM, 2, _T("IObjectWithSiteImpl::SetSite\n"));
  3370. T* pT = static_cast<T*>(this);
  3371. pT->m_spUnkSite = pUnkSite;
  3372. return S_OK;
  3373. }
  3374. STDMETHOD(GetSite)(REFIID riid, void **ppvSite)
  3375. {
  3376. ATLTRACE(atlTraceCOM, 2, _T("IObjectWithSiteImpl::GetSite\n"));
  3377. T* pT = static_cast<T*>(this);
  3378. ATLASSERT(ppvSite);
  3379. HRESULT hRes = E_POINTER;
  3380. if (ppvSite != NULL)
  3381. {
  3382. if (pT->m_spUnkSite)
  3383. hRes = pT->m_spUnkSite->QueryInterface(riid, ppvSite);
  3384. else
  3385. {
  3386. *ppvSite = NULL;
  3387. hRes = E_FAIL;
  3388. }
  3389. }
  3390. return hRes;
  3391. }
  3392. HRESULT SetChildSite(IUnknown* punkChild)
  3393. {
  3394. if (punkChild == NULL)
  3395. return E_POINTER;
  3396. HRESULT hr;
  3397. CComPtr<IObjectWithSite> spChildSite;
  3398. hr = punkChild->QueryInterface(__uuidof(IObjectWithSite), (void**)&spChildSite);
  3399. if (SUCCEEDED(hr))
  3400. hr = spChildSite->SetSite((IUnknown*)this);
  3401. return hr;
  3402. }
  3403. static HRESULT SetChildSite(IUnknown* punkChild, IUnknown* punkParent)
  3404. {
  3405. return AtlSetChildSite(punkChild, punkParent);
  3406. }
  3407. CComPtr<IUnknown> m_spUnkSite;
  3408. };
  3409. //////////////////////////////////////////////////////////////////////////////
  3410. // IServiceProvider
  3411. //
  3412. template <class T>
  3413. class ATL_NO_VTABLE IServiceProviderImpl : public IServiceProvider
  3414. {
  3415. public:
  3416. STDMETHOD(QueryService)(REFGUID guidService, REFIID riid, void** ppvObject)
  3417. {
  3418. ATLTRACE(atlTraceCOM, 2, _T("IServiceProviderImpl::QueryService\n"));
  3419. T* pT = static_cast<T*>(this);
  3420. return pT->_InternalQueryService(guidService, riid, ppvObject);
  3421. }
  3422. };
  3423. #define BEGIN_SERVICE_MAP(x) public: \
  3424. HRESULT _InternalQueryService(REFGUID guidService, REFIID riid, void** ppvObject) \
  3425. { \
  3426. ATLASSERT(ppvObject != NULL); \
  3427. if (ppvObject == NULL) \
  3428. return E_POINTER; \
  3429. *ppvObject = NULL;
  3430. #define SERVICE_ENTRY(x) \
  3431. if (InlineIsEqualGUID(guidService, x)) \
  3432. return QueryInterface(riid, ppvObject);
  3433. #define SERVICE_ENTRY_CHAIN(x) \
  3434. ATL::CComQIPtr<IServiceProvider, &__uuidof(IServiceProvider)> spProvider(x); \
  3435. if (spProvider != NULL) \
  3436. return spProvider->QueryService(guidService, riid, ppvObject);
  3437. #define END_SERVICE_MAP() \
  3438. return E_NOINTERFACE; \
  3439. }
  3440. /////////////////////////////////////////////////////////////////////////////
  3441. // IDispEventImpl
  3442. #ifdef _ATL_DLL
  3443. ATLAPI AtlGetObjectSourceInterface(IUnknown* punkObj, GUID* plibid, IID* piid, unsigned short* pdwMajor, unsigned short* pdwMinor);
  3444. #else
  3445. ATLINLINE ATLAPI AtlGetObjectSourceInterface(IUnknown* punkObj, GUID* plibid, IID* piid, unsigned short* pdwMajor, unsigned short* pdwMinor)
  3446. {
  3447. HRESULT hr = E_FAIL;
  3448. if (punkObj != NULL)
  3449. {
  3450. CComPtr<IDispatch> spDispatch;
  3451. hr = punkObj->QueryInterface(__uuidof(IDispatch), (void**)&spDispatch);
  3452. if (SUCCEEDED(hr))
  3453. {
  3454. CComPtr<ITypeInfo> spTypeInfo;
  3455. hr = spDispatch->GetTypeInfo(0, 0, &spTypeInfo);
  3456. if (SUCCEEDED(hr))
  3457. {
  3458. CComPtr<ITypeLib> spTypeLib;
  3459. hr = spTypeInfo->GetContainingTypeLib(&spTypeLib, 0);
  3460. if (SUCCEEDED(hr))
  3461. {
  3462. TLIBATTR* plibAttr;
  3463. hr = spTypeLib->GetLibAttr(&plibAttr);
  3464. if (SUCCEEDED(hr))
  3465. {
  3466. memcpy(plibid, &plibAttr->guid, sizeof(GUID));
  3467. *pdwMajor = plibAttr->wMajorVerNum;
  3468. *pdwMinor = plibAttr->wMinorVerNum;
  3469. spTypeLib->ReleaseTLibAttr(plibAttr);
  3470. // First see if the object is willing to tell us about the
  3471. // default source interface via IProvideClassInfo2
  3472. CComPtr<IProvideClassInfo2> spInfo;
  3473. hr = punkObj->QueryInterface(__uuidof(IProvideClassInfo2), (void**)&spInfo);
  3474. if (SUCCEEDED(hr) && spInfo != NULL)
  3475. hr = spInfo->GetGUID(GUIDKIND_DEFAULT_SOURCE_DISP_IID, piid);
  3476. else
  3477. {
  3478. // No, we have to go hunt for it
  3479. CComPtr<ITypeInfo> spInfoCoClass;
  3480. // If we have a clsid, use that
  3481. // Otherwise, try to locate the clsid from IPersist
  3482. CComPtr<IPersist> spPersist;
  3483. CLSID clsid;
  3484. hr = punkObj->QueryInterface(__uuidof(IPersist), (void**)&spPersist);
  3485. if (SUCCEEDED(hr))
  3486. {
  3487. hr = spPersist->GetClassID(&clsid);
  3488. if (SUCCEEDED(hr))
  3489. {
  3490. hr = spTypeLib->GetTypeInfoOfGuid(clsid, &spInfoCoClass);
  3491. if (SUCCEEDED(hr))
  3492. {
  3493. TYPEATTR* pAttr=NULL;
  3494. spInfoCoClass->GetTypeAttr(&pAttr);
  3495. if (pAttr != NULL)
  3496. {
  3497. HREFTYPE hRef;
  3498. for (int i = 0; i < pAttr->cImplTypes; i++)
  3499. {
  3500. int nType;
  3501. hr = spInfoCoClass->GetImplTypeFlags(i, &nType);
  3502. if (SUCCEEDED(hr))
  3503. {
  3504. if (nType == (IMPLTYPEFLAG_FDEFAULT | IMPLTYPEFLAG_FSOURCE))
  3505. {
  3506. // we found it
  3507. hr = spInfoCoClass->GetRefTypeOfImplType(i, &hRef);
  3508. if (SUCCEEDED(hr))
  3509. {
  3510. CComPtr<ITypeInfo> spInfo;
  3511. hr = spInfoCoClass->GetRefTypeInfo(hRef, &spInfo);
  3512. if (SUCCEEDED(hr))
  3513. {
  3514. TYPEATTR* pAttrIF;
  3515. spInfo->GetTypeAttr(&pAttrIF);
  3516. if (pAttrIF != NULL)
  3517. {
  3518. memcpy(piid, &pAttrIF->guid, sizeof(GUID));
  3519. }
  3520. spInfo->ReleaseTypeAttr(pAttrIF);
  3521. }
  3522. }
  3523. break;
  3524. }
  3525. }
  3526. }
  3527. spInfoCoClass->ReleaseTypeAttr(pAttr);
  3528. }
  3529. }
  3530. }
  3531. }
  3532. }
  3533. }
  3534. }
  3535. }
  3536. }
  3537. }
  3538. return hr;
  3539. }
  3540. #endif // _ATL_DLL
  3541. #if defined(_M_IA64)
  3542. template <class T>
  3543. class CComStdCallThunk
  3544. {
  3545. public:
  3546. typedef void (__stdcall T::*TMFP)();
  3547. void* pVtable;
  3548. void* pFunc;
  3549. _stdcallthunk thunk;
  3550. void Init(TMFP dw, void* pThis)
  3551. {
  3552. pVtable = &pFunc;
  3553. pFunc = &thunk;
  3554. union {
  3555. DWORD_PTR dwFunc;
  3556. TMFP pfn;
  3557. } pfn;
  3558. pfn.pfn = dw;
  3559. thunk.Init(pfn.dwFunc, pThis);
  3560. }
  3561. };
  3562. #elif defined(_M_AMD64) || defined(_M_IX86)
  3563. template <class T>
  3564. class CComStdCallThunk
  3565. {
  3566. public:
  3567. typedef void (__stdcall T::*TMFP)();
  3568. void *pVTable;
  3569. void *pThis;
  3570. TMFP pfn;
  3571. void (__stdcall *pfnHelper)();
  3572. void Init(TMFP pf, void *p);
  3573. };
  3574. #if defined(_M_AMD64)
  3575. #pragma comment(lib, "atlamd64.lib")
  3576. extern "C" void CComStdCallThunkHelper(void);
  3577. #else
  3578. inline void __declspec(naked) __stdcall CComStdCallThunkHelper()
  3579. {
  3580. __asm
  3581. {
  3582. mov eax, [esp+4]; // get pThunk
  3583. mov ebx, [eax+4]; // get the pThunk->pThis
  3584. mov [esp+4], ebx; // replace pThunk with pThis
  3585. mov eax, [eax+8]; // get pThunk->pfn
  3586. jmp eax; // jump pfn
  3587. };
  3588. }
  3589. #endif
  3590. template <class T>
  3591. void CComStdCallThunk<T>::Init(TMFP pf, void *p)
  3592. {
  3593. pfnHelper = CComStdCallThunkHelper;
  3594. pVTable = &pfnHelper;
  3595. pThis = p;
  3596. pfn = pf;
  3597. }
  3598. #else
  3599. #error "No Target Architecture"
  3600. #endif
  3601. #ifndef _ATL_MAX_VARTYPES
  3602. #define _ATL_MAX_VARTYPES 8
  3603. #endif
  3604. struct _ATL_FUNC_INFO
  3605. {
  3606. CALLCONV cc;
  3607. VARTYPE vtReturn;
  3608. SHORT nParams;
  3609. VARTYPE pVarTypes[_ATL_MAX_VARTYPES];
  3610. };
  3611. class ATL_NO_VTABLE _IDispEvent
  3612. {
  3613. public:
  3614. _IDispEvent() : m_libid(GUID_NULL), m_iid(IID_NULL), m_wMajorVerNum(0), m_wMinorVerNum(0), m_dwEventCookie(0xFEFEFEFE) { }
  3615. //this method needs a different name than QueryInterface
  3616. STDMETHOD(_LocDEQueryInterface)(REFIID riid, void ** ppvObject) = 0;
  3617. virtual ULONG STDMETHODCALLTYPE AddRef(void) = 0;
  3618. virtual ULONG STDMETHODCALLTYPE Release(void) = 0;
  3619. GUID m_libid; // used for dynamic case
  3620. IID m_iid; // used for dynamic case
  3621. unsigned short m_wMajorVerNum; // Major version number. used for dynamic case
  3622. unsigned short m_wMinorVerNum; // Minor version number. used for dynamic case
  3623. DWORD m_dwEventCookie;
  3624. HRESULT DispEventAdvise(IUnknown* pUnk, const IID* piid)
  3625. {
  3626. ATLASSERT(m_dwEventCookie == 0xFEFEFEFE);
  3627. return AtlAdvise(pUnk, (IUnknown*)this, *piid, &m_dwEventCookie);
  3628. }
  3629. HRESULT DispEventUnadvise(IUnknown* pUnk, const IID* piid)
  3630. {
  3631. HRESULT hr = AtlUnadvise(pUnk, *piid, m_dwEventCookie);
  3632. m_dwEventCookie = 0xFEFEFEFE;
  3633. return hr;
  3634. }
  3635. //---- add Advise & Unadvise for ease of calling from attribute code ----
  3636. HRESULT Advise(IUnknown *punk)
  3637. {
  3638. AtlGetObjectSourceInterface(punk, &m_libid, &m_iid, &m_wMajorVerNum, &m_wMinorVerNum);
  3639. return DispEventAdvise(punk, &m_iid);
  3640. }
  3641. HRESULT Unadvise(IUnknown *punk)
  3642. {
  3643. AtlGetObjectSourceInterface(punk, &m_libid, &m_iid, &m_wMajorVerNum, &m_wMinorVerNum);
  3644. return DispEventUnadvise(punk, &m_iid);
  3645. }
  3646. };
  3647. template <UINT nID, const IID* piid>
  3648. class ATL_NO_VTABLE _IDispEventLocator : public _IDispEvent
  3649. {
  3650. public:
  3651. };
  3652. template <UINT nID, class T, const IID* pdiid>
  3653. class ATL_NO_VTABLE IDispEventSimpleImpl : public _IDispEventLocator<nID, pdiid>
  3654. {
  3655. public:
  3656. STDMETHOD(_LocDEQueryInterface)(REFIID riid, void ** ppvObject)
  3657. {
  3658. ATLASSERT(ppvObject != NULL);
  3659. if (ppvObject == NULL)
  3660. return E_POINTER;
  3661. *ppvObject = NULL;
  3662. if (InlineIsEqualGUID(riid, IID_NULL))
  3663. return E_NOINTERFACE;
  3664. if (InlineIsEqualGUID(riid, *pdiid) ||
  3665. InlineIsEqualUnknown(riid) ||
  3666. InlineIsEqualGUID(riid, __uuidof(IDispatch)) ||
  3667. InlineIsEqualGUID(riid, m_iid))
  3668. {
  3669. *ppvObject = this;
  3670. AddRef();
  3671. #ifdef _ATL_DEBUG_INTERFACES
  3672. _AtlDebugInterfacesModule.AddThunk((IUnknown**)ppvObject, _T("IDispEventImpl"), riid);
  3673. #endif // _ATL_DEBUG_INTERFACES
  3674. return S_OK;
  3675. }
  3676. else
  3677. return E_NOINTERFACE;
  3678. }
  3679. // These are here only to support use in non-COM objects
  3680. virtual ULONG STDMETHODCALLTYPE AddRef()
  3681. {
  3682. return 1;
  3683. }
  3684. virtual ULONG STDMETHODCALLTYPE Release()
  3685. {
  3686. return 1;
  3687. }
  3688. STDMETHOD(GetTypeInfoCount)(UINT* /*pctinfo*/)
  3689. {ATLTRACENOTIMPL(_T("IDispEventSimpleImpl::GetTypeInfoCount"));}
  3690. STDMETHOD(GetTypeInfo)(UINT /*itinfo*/, LCID /*lcid*/, ITypeInfo** /*pptinfo*/)
  3691. {ATLTRACENOTIMPL(_T("IDispEventSimpleImpl::GetTypeInfo"));}
  3692. STDMETHOD(GetIDsOfNames)(REFIID /*riid*/, LPOLESTR* /*rgszNames*/, UINT /*cNames*/,
  3693. LCID /*lcid*/, DISPID* /*rgdispid*/)
  3694. {ATLTRACENOTIMPL(_T("IDispEventSimpleImpl::GetIDsOfNames"));}
  3695. STDMETHOD(Invoke)(DISPID dispidMember, REFIID /*riid*/,
  3696. LCID lcid, WORD /*wFlags*/, DISPPARAMS* pdispparams, VARIANT* pvarResult,
  3697. EXCEPINFO* /*pexcepinfo*/, UINT* /*puArgErr*/)
  3698. {
  3699. const _ATL_EVENT_ENTRY<T>* pMap = T::_GetSinkMap();
  3700. const _ATL_EVENT_ENTRY<T>* pFound = NULL;
  3701. while (pMap->piid != NULL)
  3702. {
  3703. if ((pMap->nControlID == nID) && (pMap->dispid == dispidMember) &&
  3704. (IsEqualIID(*(pMap->piid), *pdiid)))
  3705. {
  3706. pFound = pMap;
  3707. break;
  3708. }
  3709. pMap++;
  3710. }
  3711. if (pFound == NULL)
  3712. return S_OK;
  3713. _ATL_FUNC_INFO info;
  3714. _ATL_FUNC_INFO* pInfo;
  3715. if (pFound->pInfo != NULL)
  3716. pInfo = pFound->pInfo;
  3717. else
  3718. {
  3719. pInfo = &info;
  3720. HRESULT hr = GetFuncInfoFromId(*pdiid, dispidMember, lcid, info);
  3721. if (FAILED(hr))
  3722. return S_OK;
  3723. }
  3724. InvokeFromFuncInfo(pFound->pfn, *pInfo, pdispparams, pvarResult);
  3725. return S_OK;
  3726. }
  3727. //Helper for invoking the event
  3728. HRESULT InvokeFromFuncInfo(void (__stdcall T::*pEvent)(), _ATL_FUNC_INFO& info, DISPPARAMS* pdispparams, VARIANT* pvarResult)
  3729. {
  3730. ATLASSERT(pdispparams->cArgs == (UINT)info.nParams);
  3731. T* pT = static_cast<T*>(this);
  3732. VARIANTARG** pVarArgs = info.nParams ? (VARIANTARG**)alloca(sizeof(VARIANTARG*)*info.nParams) : 0;
  3733. UINT nIndex = 0;
  3734. #ifndef _ATL_IGNORE_NAMED_ARGS
  3735. for (nIndex; nIndex < pdispparams->cNamedArgs; nIndex++)
  3736. pVarArgs[pdispparams->rgdispidNamedArgs[nIndex]] = &pdispparams->rgvarg[nIndex];
  3737. #endif
  3738. for (; nIndex < pdispparams->cArgs; nIndex++)
  3739. pVarArgs[info.nParams-nIndex-1] = &pdispparams->rgvarg[nIndex];
  3740. CComStdCallThunk<T> thunk;
  3741. thunk.Init(pEvent, pT);
  3742. CComVariant tmpResult;
  3743. if (pvarResult == NULL)
  3744. pvarResult = &tmpResult;
  3745. HRESULT hr = DispCallFunc(
  3746. &thunk,
  3747. 0,
  3748. info.cc,
  3749. info.vtReturn,
  3750. info.nParams,
  3751. info.pVarTypes,
  3752. pVarArgs,
  3753. pvarResult);
  3754. ATLASSERT(SUCCEEDED(hr));
  3755. return hr;
  3756. }
  3757. //Helper for finding the function index for a DISPID
  3758. virtual HRESULT GetFuncInfoFromId(const IID& /*iid*/, DISPID /*dispidMember*/, LCID /*lcid*/, _ATL_FUNC_INFO& /*info*/)
  3759. {
  3760. ATLTRACE(_T("TODO: Classes using IDispEventSimpleImpl should override this method\n"));
  3761. ATLASSERT(0);
  3762. ATLTRACENOTIMPL(_T("IDispEventSimpleImpl::GetFuncInfoFromId"));
  3763. }
  3764. //Helpers for sinking events on random IUnknown*
  3765. HRESULT DispEventAdvise(IUnknown* pUnk, const IID* piid)
  3766. {
  3767. ATLASSERT(m_dwEventCookie == 0xFEFEFEFE);
  3768. return AtlAdvise(pUnk, (IUnknown*)this, *piid, &m_dwEventCookie);
  3769. }
  3770. HRESULT DispEventUnadvise(IUnknown* pUnk, const IID* piid)
  3771. {
  3772. HRESULT hr = AtlUnadvise(pUnk, *piid, m_dwEventCookie);
  3773. m_dwEventCookie = 0xFEFEFEFE;
  3774. return hr;
  3775. }
  3776. HRESULT DispEventAdvise(IUnknown* pUnk)
  3777. {
  3778. return _IDispEvent::DispEventAdvise(pUnk, pdiid);
  3779. }
  3780. HRESULT DispEventUnadvise(IUnknown* pUnk)
  3781. {
  3782. return _IDispEvent::DispEventUnadvise(pUnk, pdiid);
  3783. }
  3784. };
  3785. //Helper for advising connections points from a sink map
  3786. template <class T>
  3787. inline HRESULT AtlAdviseSinkMap(T* pT, bool bAdvise)
  3788. {
  3789. ATLASSERT(::IsWindow(pT->m_hWnd));
  3790. const _ATL_EVENT_ENTRY<T>* pEntries = T::_GetSinkMap();
  3791. if (pEntries == NULL)
  3792. return S_OK;
  3793. HRESULT hr = S_OK;
  3794. while (pEntries->piid != NULL)
  3795. {
  3796. _IDispEvent* pDE = (_IDispEvent*)((DWORD_PTR)pT+pEntries->nOffset);
  3797. bool bNotAdvised = pDE->m_dwEventCookie == 0xFEFEFEFE;
  3798. if (bAdvise ^ bNotAdvised)
  3799. {
  3800. pEntries++;
  3801. continue;
  3802. }
  3803. hr = E_FAIL;
  3804. HWND h = pT->GetDlgItem(pEntries->nControlID);
  3805. ATLASSERT(h != NULL);
  3806. if (h != NULL)
  3807. {
  3808. CComPtr<IUnknown> spUnk;
  3809. AtlAxGetControl(h, &spUnk);
  3810. ATLASSERT(spUnk != NULL);
  3811. if (spUnk != NULL)
  3812. {
  3813. if (bAdvise)
  3814. {
  3815. if (!InlineIsEqualGUID(IID_NULL, *pEntries->piid))
  3816. hr = pDE->DispEventAdvise(spUnk, pEntries->piid);
  3817. else
  3818. {
  3819. AtlGetObjectSourceInterface(spUnk, &pDE->m_libid, &pDE->m_iid, &pDE->m_wMajorVerNum, &pDE->m_wMinorVerNum);
  3820. hr = pDE->DispEventAdvise(spUnk, &pDE->m_iid);
  3821. }
  3822. }
  3823. else
  3824. {
  3825. if (!InlineIsEqualGUID(IID_NULL, *pEntries->piid))
  3826. hr = pDE->DispEventUnadvise(spUnk, pEntries->piid);
  3827. else
  3828. hr = pDE->DispEventUnadvise(spUnk, &pDE->m_iid);
  3829. }
  3830. ATLASSERT(hr == S_OK);
  3831. }
  3832. }
  3833. if (FAILED(hr))
  3834. break;
  3835. pEntries++;
  3836. }
  3837. return hr;
  3838. }
  3839. #pragma warning(push)
  3840. #pragma warning(disable: 4061) // enumerate XXX not explicitly handled by a case label
  3841. inline VARTYPE AtlGetUserDefinedType(ITypeInfo *pTI, HREFTYPE hrt)
  3842. {
  3843. if (pTI == NULL)
  3844. E_INVALIDARG;
  3845. CComPtr<ITypeInfo> spTypeInfo;
  3846. VARTYPE vt = VT_USERDEFINED;
  3847. HRESULT hr = E_FAIL;
  3848. hr = pTI->GetRefTypeInfo(hrt, &spTypeInfo);
  3849. if(FAILED(hr))
  3850. return vt;
  3851. TYPEATTR *pta = NULL;
  3852. hr = spTypeInfo->GetTypeAttr(&pta);
  3853. if(SUCCEEDED(hr) && pta && (pta->typekind == TKIND_ALIAS || pta->typekind == TKIND_ENUM))
  3854. {
  3855. if (pta->tdescAlias.vt == VT_USERDEFINED)
  3856. vt = AtlGetUserDefinedType(spTypeInfo, pta->tdescAlias.hreftype);
  3857. else
  3858. {
  3859. switch (pta->typekind)
  3860. {
  3861. case TKIND_ENUM :
  3862. vt = VT_I4;
  3863. break;
  3864. case TKIND_INTERFACE :
  3865. vt = VT_UNKNOWN;
  3866. break;
  3867. case TKIND_DISPATCH :
  3868. vt = VT_DISPATCH;
  3869. break;
  3870. default:
  3871. vt = pta->tdescAlias.vt;
  3872. }
  3873. }
  3874. }
  3875. if(pta)
  3876. spTypeInfo->ReleaseTypeAttr(pta);
  3877. return vt;
  3878. }
  3879. #pragma warning(pop)
  3880. inline HRESULT AtlGetFuncInfoFromId(ITypeInfo* pTypeInfo, const IID& /*iid*/, DISPID dispidMember, LCID /*lcid*/, _ATL_FUNC_INFO& info)
  3881. {
  3882. if (pTypeInfo == NULL)
  3883. return E_INVALIDARG;
  3884. HRESULT hr = S_OK;
  3885. FUNCDESC* pFuncDesc = NULL;
  3886. TYPEATTR* pAttr;
  3887. hr = pTypeInfo->GetTypeAttr(&pAttr);
  3888. if (FAILED(hr))
  3889. return hr;
  3890. int i;
  3891. for (i=0;i<pAttr->cFuncs;i++)
  3892. {
  3893. hr = pTypeInfo->GetFuncDesc(i, &pFuncDesc);
  3894. if (FAILED(hr))
  3895. return hr;
  3896. if (pFuncDesc->memid == dispidMember)
  3897. break;
  3898. pTypeInfo->ReleaseFuncDesc(pFuncDesc);
  3899. pFuncDesc = NULL;
  3900. }
  3901. pTypeInfo->ReleaseTypeAttr(pAttr);
  3902. if (pFuncDesc == NULL)
  3903. return E_FAIL;
  3904. // If this assert occurs, then add a #define _ATL_MAX_VARTYPES nnnn
  3905. // before including atlcom.h
  3906. ATLASSERT(pFuncDesc->cParams <= _ATL_MAX_VARTYPES);
  3907. if (pFuncDesc->cParams > _ATL_MAX_VARTYPES)
  3908. return E_FAIL;
  3909. for (i = 0; i < pFuncDesc->cParams; i++)
  3910. {
  3911. info.pVarTypes[i] = pFuncDesc->lprgelemdescParam[i].tdesc.vt;
  3912. if (info.pVarTypes[i] == VT_PTR)
  3913. info.pVarTypes[i] = (VARTYPE)(pFuncDesc->lprgelemdescParam[i].tdesc.lptdesc->vt | VT_BYREF);
  3914. if (info.pVarTypes[i] == VT_USERDEFINED)
  3915. info.pVarTypes[i] = AtlGetUserDefinedType(pTypeInfo, pFuncDesc->lprgelemdescParam[i].tdesc.hreftype);
  3916. }
  3917. VARTYPE vtReturn = pFuncDesc->elemdescFunc.tdesc.vt;
  3918. switch(vtReturn)
  3919. {
  3920. case VT_INT:
  3921. vtReturn = VT_I4;
  3922. break;
  3923. case VT_UINT:
  3924. vtReturn = VT_UI4;
  3925. break;
  3926. case VT_VOID:
  3927. vtReturn = VT_EMPTY; // this is how DispCallFunc() represents void
  3928. break;
  3929. case VT_HRESULT:
  3930. vtReturn = VT_ERROR;
  3931. break;
  3932. }
  3933. info.vtReturn = vtReturn;
  3934. info.cc = pFuncDesc->callconv;
  3935. info.nParams = pFuncDesc->cParams;
  3936. pTypeInfo->ReleaseFuncDesc(pFuncDesc);
  3937. return S_OK;
  3938. }
  3939. template <UINT nID, class T, const IID* pdiid = &IID_NULL, const GUID* plibid = &GUID_NULL,
  3940. WORD wMajor = 0, WORD wMinor = 0, class tihclass = CComTypeInfoHolder>
  3941. class ATL_NO_VTABLE IDispEventImpl : public IDispEventSimpleImpl<nID, T, pdiid>
  3942. {
  3943. public:
  3944. typedef tihclass _tihclass;
  3945. IDispEventImpl()
  3946. {
  3947. m_libid = *plibid;
  3948. m_iid = *pdiid;
  3949. m_wMajorVerNum = wMajor;
  3950. m_wMinorVerNum = wMinor;
  3951. }
  3952. STDMETHOD(GetTypeInfoCount)(UINT* pctinfo)
  3953. {*pctinfo = 1; return S_OK;}
  3954. STDMETHOD(GetTypeInfo)(UINT itinfo, LCID lcid, ITypeInfo** pptinfo)
  3955. {return _tih.GetTypeInfo(itinfo, lcid, pptinfo);}
  3956. STDMETHOD(GetIDsOfNames)(REFIID riid, LPOLESTR* rgszNames, UINT cNames,
  3957. LCID lcid, DISPID* rgdispid)
  3958. {return _tih.GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);}
  3959. //Helper for finding the function index for a DISPID
  3960. HRESULT GetFuncInfoFromId(const IID& iid, DISPID dispidMember, LCID lcid, _ATL_FUNC_INFO& info)
  3961. {
  3962. CComPtr<ITypeInfo> spTypeInfo;
  3963. if (InlineIsEqualGUID(*_tih.m_plibid, GUID_NULL))
  3964. {
  3965. _tih.m_plibid = &m_libid;
  3966. _tih.m_pguid = &m_iid;
  3967. _tih.m_wMajor = m_wMajorVerNum;
  3968. _tih.m_wMinor = m_wMinorVerNum;
  3969. }
  3970. HRESULT hr = _tih.GetTI(lcid, &spTypeInfo);
  3971. if (FAILED(hr))
  3972. return hr;
  3973. return AtlGetFuncInfoFromId(spTypeInfo, iid, dispidMember, lcid, info);
  3974. }
  3975. VARTYPE GetUserDefinedType(ITypeInfo *pTI, HREFTYPE hrt)
  3976. {
  3977. return AtlGetUserDefinedType(pTI, hrt);
  3978. }
  3979. protected:
  3980. static _tihclass _tih;
  3981. static HRESULT GetTI(LCID lcid, ITypeInfo** ppInfo)
  3982. {return _tih.GetTI(lcid, ppInfo);}
  3983. };
  3984. template <UINT nID, class T, const IID* piid, const GUID* plibid, WORD wMajor, WORD wMinor, class tihclass>
  3985. IDispEventImpl<nID, T, piid, plibid, wMajor, wMinor, tihclass>::_tihclass
  3986. IDispEventImpl<nID, T, piid, plibid, wMajor, wMinor, tihclass>::_tih =
  3987. {piid, plibid, wMajor, wMinor, NULL, 0, NULL, 0};
  3988. template <class T>
  3989. struct _ATL_EVENT_ENTRY
  3990. {
  3991. UINT nControlID; //ID identifying object instance
  3992. const IID* piid; //dispinterface IID
  3993. int nOffset; //offset of dispinterface from this pointer
  3994. DISPID dispid; //DISPID of method/property
  3995. void (__stdcall T::*pfn)(); //method to invoke
  3996. _ATL_FUNC_INFO* pInfo;
  3997. };
  3998. //Sink map is used to set up event handling
  3999. #define BEGIN_SINK_MAP(_class)\
  4000. typedef _class _GetSinkMapFinder;\
  4001. static const ATL::_ATL_EVENT_ENTRY<_class>* _GetSinkMap()\
  4002. {\
  4003. typedef _class _atl_event_classtype;\
  4004. static const ATL::_ATL_EVENT_ENTRY<_class> map[] = {
  4005. #define SINK_ENTRY_INFO(id, iid, dispid, fn, info) {id, &iid, (int)(INT_PTR)(static_cast<ATL::_IDispEventLocator<id, &iid>*>((_atl_event_classtype*)8))-8, dispid, (void (__stdcall _atl_event_classtype::*)())fn, info},
  4006. #define SINK_ENTRY_EX(id, iid, dispid, fn) SINK_ENTRY_INFO(id, iid, dispid, fn, NULL)
  4007. #define SINK_ENTRY(id, dispid, fn) SINK_ENTRY_EX(id, IID_NULL, dispid, fn)
  4008. #define END_SINK_MAP() {0, NULL, 0, 0, NULL, NULL} }; return map;}
  4009. /////////////////////////////////////////////////////////////////////////////
  4010. // IDispatchImpl
  4011. template <class T, const IID* piid = &__uuidof(T), const GUID* plibid = &CAtlModule::m_libid, WORD wMajor = 1,
  4012. WORD wMinor = 0, class tihclass = CComTypeInfoHolder>
  4013. class ATL_NO_VTABLE IDispatchImpl : public T
  4014. {
  4015. public:
  4016. typedef tihclass _tihclass;
  4017. // IDispatch
  4018. STDMETHOD(GetTypeInfoCount)(UINT* pctinfo)
  4019. {
  4020. *pctinfo = 1;
  4021. return S_OK;
  4022. }
  4023. STDMETHOD(GetTypeInfo)(UINT itinfo, LCID lcid, ITypeInfo** pptinfo)
  4024. {
  4025. return _tih.GetTypeInfo(itinfo, lcid, pptinfo);
  4026. }
  4027. STDMETHOD(GetIDsOfNames)(REFIID riid, LPOLESTR* rgszNames, UINT cNames,
  4028. LCID lcid, DISPID* rgdispid)
  4029. {
  4030. return _tih.GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);
  4031. }
  4032. STDMETHOD(Invoke)(DISPID dispidMember, REFIID riid,
  4033. LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult,
  4034. EXCEPINFO* pexcepinfo, UINT* puArgErr)
  4035. {
  4036. return _tih.Invoke((IDispatch*)this, dispidMember, riid, lcid,
  4037. wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
  4038. }
  4039. #ifdef _ATL_DLL_IMPL
  4040. // Do not cache type info if it is used in atl70.dll
  4041. IDispatchImpl() : _tih(piid, plibid, wMajor, wMinor)
  4042. {
  4043. }
  4044. protected:
  4045. _tihclass _tih;
  4046. HRESULT GetTI(LCID lcid, ITypeInfo** ppInfo)
  4047. {
  4048. return _tih.GetTI(lcid, ppInfo);
  4049. }
  4050. #else
  4051. protected:
  4052. static _tihclass _tih;
  4053. static HRESULT GetTI(LCID lcid, ITypeInfo** ppInfo)
  4054. {
  4055. return _tih.GetTI(lcid, ppInfo);
  4056. }
  4057. #endif
  4058. };
  4059. #ifndef _ATL_DLL_IMPL
  4060. template <class T, const IID* piid, const GUID* plibid, WORD wMajor, WORD wMinor, class tihclass>
  4061. IDispatchImpl<T, piid, plibid, wMajor, wMinor, tihclass>::_tihclass
  4062. IDispatchImpl<T, piid, plibid, wMajor, wMinor, tihclass>::_tih =
  4063. {piid, plibid, wMajor, wMinor, NULL, 0, NULL, 0};
  4064. #endif
  4065. /////////////////////////////////////////////////////////////////////////////
  4066. // IProvideClassInfoImpl
  4067. template <const CLSID* pcoclsid, const GUID* plibid = &CAtlModule::m_libid,
  4068. WORD wMajor = 1, WORD wMinor = 0, class tihclass = CComTypeInfoHolder>
  4069. class ATL_NO_VTABLE IProvideClassInfoImpl : public IProvideClassInfo
  4070. {
  4071. public:
  4072. typedef tihclass _tihclass;
  4073. STDMETHOD(GetClassInfo)(ITypeInfo** pptinfo)
  4074. {
  4075. return _tih.GetTypeInfo(0, LANG_NEUTRAL, pptinfo);
  4076. }
  4077. protected:
  4078. static _tihclass _tih;
  4079. };
  4080. template <const CLSID* pcoclsid, const GUID* plibid, WORD wMajor, WORD wMinor, class tihclass>
  4081. IProvideClassInfoImpl<pcoclsid, plibid, wMajor, wMinor, tihclass>::_tihclass
  4082. IProvideClassInfoImpl<pcoclsid, plibid, wMajor, wMinor, tihclass>::_tih =
  4083. {pcoclsid,plibid, wMajor, wMinor, NULL, 0, NULL, 0};
  4084. /////////////////////////////////////////////////////////////////////////////
  4085. // IProvideClassInfo2Impl
  4086. template <const CLSID* pcoclsid, const IID* psrcid, const GUID* plibid = &CAtlModule::m_libid,
  4087. WORD wMajor = 1, WORD wMinor = 0, class tihclass = CComTypeInfoHolder>
  4088. class ATL_NO_VTABLE IProvideClassInfo2Impl : public IProvideClassInfo2
  4089. {
  4090. public:
  4091. typedef tihclass _tihclass;
  4092. STDMETHOD(GetClassInfo)(ITypeInfo** pptinfo)
  4093. {
  4094. return _tih.GetTypeInfo(0, LANG_NEUTRAL, pptinfo);
  4095. }
  4096. STDMETHOD(GetGUID)(DWORD dwGuidKind, GUID* pGUID)
  4097. {
  4098. if (pGUID == NULL)
  4099. return E_POINTER;
  4100. if (dwGuidKind == GUIDKIND_DEFAULT_SOURCE_DISP_IID && psrcid != NULL)
  4101. {
  4102. *pGUID = *psrcid;
  4103. return S_OK;
  4104. }
  4105. *pGUID = GUID_NULL;
  4106. return E_FAIL;
  4107. }
  4108. protected:
  4109. static _tihclass _tih;
  4110. };
  4111. template <const CLSID* pcoclsid, const IID* psrcid, const GUID* plibid, WORD wMajor, WORD wMinor, class tihclass>
  4112. IProvideClassInfo2Impl<pcoclsid, psrcid, plibid, wMajor, wMinor, tihclass>::_tihclass
  4113. IProvideClassInfo2Impl<pcoclsid, psrcid, plibid, wMajor, wMinor, tihclass>::_tih =
  4114. {pcoclsid,plibid, wMajor, wMinor, NULL, 0, NULL, 0};
  4115. /////////////////////////////////////////////////////////////////////////////
  4116. // ISupportErrorInfoImpl
  4117. template <const IID* piid>
  4118. class ATL_NO_VTABLE ISupportErrorInfoImpl : public ISupportErrorInfo
  4119. {
  4120. public:
  4121. STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid)
  4122. {
  4123. return (InlineIsEqualGUID(riid,*piid)) ? S_OK : S_FALSE;
  4124. }
  4125. };
  4126. /////////////////////////////////////////////////////////////////////////////
  4127. // CComEnumImpl
  4128. // These _CopyXXX classes are used with enumerators in order to control
  4129. // how enumerated items are initialized, copied, and deleted
  4130. // Default is shallow copy with no special init or cleanup
  4131. template <class T>
  4132. class _Copy
  4133. {
  4134. public:
  4135. static HRESULT copy(T* p1, T* p2) {memcpy(p1, p2, sizeof(T)); return S_OK;}
  4136. static void init(T*) {}
  4137. static void destroy(T*) {}
  4138. };
  4139. template<>
  4140. class _Copy<VARIANT>
  4141. {
  4142. public:
  4143. static HRESULT copy(VARIANT* p1, VARIANT* p2) {p1->vt = VT_EMPTY; return VariantCopy(p1, p2);}
  4144. static void init(VARIANT* p) {p->vt = VT_EMPTY;}
  4145. static void destroy(VARIANT* p) {VariantClear(p);}
  4146. };
  4147. template<>
  4148. class _Copy<LPOLESTR>
  4149. {
  4150. public:
  4151. static HRESULT copy(LPOLESTR* p1, LPOLESTR* p2)
  4152. {
  4153. HRESULT hr = S_OK;
  4154. (*p1) = (LPOLESTR)CoTaskMemAlloc(sizeof(OLECHAR)*(ocslen(*p2)+1));
  4155. if (*p1 == NULL)
  4156. hr = E_OUTOFMEMORY;
  4157. else
  4158. ocscpy(*p1,*p2);
  4159. return hr;
  4160. }
  4161. static void init(LPOLESTR* p) {*p = NULL;}
  4162. static void destroy(LPOLESTR* p) { CoTaskMemFree(*p);}
  4163. };
  4164. template<>
  4165. class _Copy<OLEVERB>
  4166. {
  4167. public:
  4168. static HRESULT copy(OLEVERB* p1, OLEVERB* p2)
  4169. {
  4170. HRESULT hr = S_OK;
  4171. *p1 = *p2;
  4172. if (p2->lpszVerbName == NULL)
  4173. return S_OK;
  4174. p1->lpszVerbName = (LPOLESTR)CoTaskMemAlloc(sizeof(OLECHAR)*(ocslen(p2->lpszVerbName)+1));
  4175. if (p1->lpszVerbName == NULL)
  4176. hr = E_OUTOFMEMORY;
  4177. else
  4178. ocscpy(p1->lpszVerbName,p2->lpszVerbName);
  4179. return hr;
  4180. }
  4181. static void init(OLEVERB* p) { p->lpszVerbName = NULL;}
  4182. static void destroy(OLEVERB* p) { if (p->lpszVerbName) CoTaskMemFree(p->lpszVerbName);}
  4183. };
  4184. template<>
  4185. class _Copy<CONNECTDATA>
  4186. {
  4187. public:
  4188. static HRESULT copy(CONNECTDATA* p1, CONNECTDATA* p2)
  4189. {
  4190. *p1 = *p2;
  4191. if (p1->pUnk)
  4192. p1->pUnk->AddRef();
  4193. return S_OK;
  4194. }
  4195. static void init(CONNECTDATA* ) {}
  4196. static void destroy(CONNECTDATA* p) {if (p->pUnk) p->pUnk->Release();}
  4197. };
  4198. template <class T>
  4199. class _CopyInterface
  4200. {
  4201. public:
  4202. static HRESULT copy(T** p1, T** p2)
  4203. {
  4204. *p1 = *p2;
  4205. if (*p1)
  4206. (*p1)->AddRef();
  4207. return S_OK;
  4208. }
  4209. static void init(T** ) {}
  4210. static void destroy(T** p) {if (*p) (*p)->Release();}
  4211. };
  4212. template<class T>
  4213. class ATL_NO_VTABLE CComIEnum : public IUnknown
  4214. {
  4215. public:
  4216. STDMETHOD(Next)(ULONG celt, T* rgelt, ULONG* pceltFetched) = 0;
  4217. STDMETHOD(Skip)(ULONG celt) = 0;
  4218. STDMETHOD(Reset)(void) = 0;
  4219. STDMETHOD(Clone)(CComIEnum<T>** ppEnum) = 0;
  4220. };
  4221. enum CComEnumFlags
  4222. {
  4223. //see FlagBits in CComEnumImpl
  4224. AtlFlagNoCopy = 0,
  4225. AtlFlagTakeOwnership = 2,
  4226. AtlFlagCopy = 3 // copy implies ownership
  4227. };
  4228. template <class Base, const IID* piid, class T, class Copy>
  4229. class ATL_NO_VTABLE CComEnumImpl : public Base
  4230. {
  4231. public:
  4232. CComEnumImpl() {m_begin = m_end = m_iter = NULL; m_dwFlags = 0;}
  4233. ~CComEnumImpl();
  4234. STDMETHOD(Next)(ULONG celt, T* rgelt, ULONG* pceltFetched);
  4235. STDMETHOD(Skip)(ULONG celt);
  4236. STDMETHOD(Reset)(void){m_iter = m_begin;return S_OK;}
  4237. STDMETHOD(Clone)(Base** ppEnum);
  4238. HRESULT Init(T* begin, T* end, IUnknown* pUnk,
  4239. CComEnumFlags flags = AtlFlagNoCopy);
  4240. CComPtr<IUnknown> m_spUnk;
  4241. T* m_begin;
  4242. T* m_end;
  4243. T* m_iter;
  4244. DWORD m_dwFlags;
  4245. protected:
  4246. enum FlagBits
  4247. {
  4248. BitCopy=1,
  4249. BitOwn=2
  4250. };
  4251. };
  4252. template <class Base, const IID* piid, class T, class Copy>
  4253. CComEnumImpl<Base, piid, T, Copy>::~CComEnumImpl()
  4254. {
  4255. if (m_dwFlags & BitOwn)
  4256. {
  4257. for (T* p = m_begin; p != m_end; p++)
  4258. Copy::destroy(p);
  4259. delete [] m_begin;
  4260. }
  4261. }
  4262. template <class Base, const IID* piid, class T, class Copy>
  4263. STDMETHODIMP CComEnumImpl<Base, piid, T, Copy>::Next(ULONG celt, T* rgelt,
  4264. ULONG* pceltFetched)
  4265. {
  4266. if (pceltFetched != NULL)
  4267. *pceltFetched = 0;
  4268. if (celt == 0)
  4269. return E_INVALIDARG;
  4270. if (rgelt == NULL || (celt != 1 && pceltFetched == NULL))
  4271. return E_POINTER;
  4272. if (m_begin == NULL || m_end == NULL || m_iter == NULL)
  4273. return E_FAIL;
  4274. ULONG nRem = (ULONG)(m_end - m_iter);
  4275. HRESULT hRes = S_OK;
  4276. if (nRem < celt)
  4277. hRes = S_FALSE;
  4278. ULONG nMin = min(celt, nRem);
  4279. if (pceltFetched != NULL)
  4280. *pceltFetched = nMin;
  4281. T* pelt = rgelt;
  4282. while(nMin--)
  4283. {
  4284. HRESULT hr = Copy::copy(pelt, m_iter);
  4285. if (FAILED(hr))
  4286. {
  4287. while (rgelt < pelt)
  4288. Copy::destroy(rgelt++);
  4289. if (pceltFetched != NULL)
  4290. *pceltFetched = 0;
  4291. return hr;
  4292. }
  4293. pelt++;
  4294. m_iter++;
  4295. }
  4296. return hRes;
  4297. }
  4298. template <class Base, const IID* piid, class T, class Copy>
  4299. STDMETHODIMP CComEnumImpl<Base, piid, T, Copy>::Skip(ULONG celt)
  4300. {
  4301. if (celt == 0)
  4302. return E_INVALIDARG;
  4303. ULONG nRem = ULONG(m_end - m_iter);
  4304. ULONG nSkip = (celt > nRem) ? nRem : celt;
  4305. m_iter += nSkip;
  4306. return (celt == nSkip) ? S_OK : S_FALSE;
  4307. }
  4308. template <class Base, const IID* piid, class T, class Copy>
  4309. STDMETHODIMP CComEnumImpl<Base, piid, T, Copy>::Clone(Base** ppEnum)
  4310. {
  4311. typedef CComObject<CComEnum<Base, piid, T, Copy> > _class;
  4312. HRESULT hRes = E_POINTER;
  4313. if (ppEnum != NULL)
  4314. {
  4315. *ppEnum = NULL;
  4316. _class* p;
  4317. hRes = _class::CreateInstance(&p);
  4318. if (SUCCEEDED(hRes))
  4319. {
  4320. // If this object has ownership of the data then we need to keep it around
  4321. hRes = p->Init(m_begin, m_end, (m_dwFlags & BitOwn) ? this : m_spUnk);
  4322. if (SUCCEEDED(hRes))
  4323. {
  4324. p->m_iter = m_iter;
  4325. hRes = p->_InternalQueryInterface(*piid, (void**)ppEnum);
  4326. }
  4327. if (FAILED(hRes))
  4328. delete p;
  4329. }
  4330. }
  4331. return hRes;
  4332. }
  4333. template <class Base, const IID* piid, class T, class Copy>
  4334. HRESULT CComEnumImpl<Base, piid, T, Copy>::Init(T* begin, T* end, IUnknown* pUnk,
  4335. CComEnumFlags flags)
  4336. {
  4337. if (flags == AtlFlagCopy)
  4338. {
  4339. ATLASSERT(m_begin == NULL); //Init called twice?
  4340. ATLTRY(m_begin = new T[end-begin])
  4341. m_iter = m_begin;
  4342. if (m_begin == NULL)
  4343. return E_OUTOFMEMORY;
  4344. for (T* i=begin; i != end; i++)
  4345. {
  4346. Copy::init(m_iter);
  4347. HRESULT hr = Copy::copy(m_iter, i);
  4348. if (FAILED(hr))
  4349. {
  4350. T* p = m_begin;
  4351. while (p < m_iter)
  4352. Copy::destroy(p++);
  4353. delete [] m_begin;
  4354. m_begin = m_end = m_iter = NULL;
  4355. return hr;
  4356. }
  4357. m_iter++;
  4358. }
  4359. m_end = m_begin + (end-begin);
  4360. }
  4361. else
  4362. {
  4363. m_begin = begin;
  4364. m_end = end;
  4365. }
  4366. m_spUnk = pUnk;
  4367. m_iter = m_begin;
  4368. m_dwFlags = flags;
  4369. return S_OK;
  4370. }
  4371. template <class Base, const IID* piid, class T, class Copy, class ThreadModel = CComObjectThreadModel>
  4372. class ATL_NO_VTABLE CComEnum :
  4373. public CComEnumImpl<Base, piid, T, Copy>,
  4374. public CComObjectRootEx< ThreadModel >
  4375. {
  4376. public:
  4377. typedef CComEnum<Base, piid, T, Copy > _CComEnum;
  4378. typedef CComEnumImpl<Base, piid, T, Copy > _CComEnumBase;
  4379. BEGIN_COM_MAP(_CComEnum)
  4380. COM_INTERFACE_ENTRY_IID(*piid, _CComEnumBase)
  4381. END_COM_MAP()
  4382. };
  4383. template <class Base, const IID* piid, class T, class Copy, class CollType>
  4384. class ATL_NO_VTABLE IEnumOnSTLImpl : public Base
  4385. {
  4386. public:
  4387. HRESULT Init(IUnknown *pUnkForRelease, CollType& collection)
  4388. {
  4389. m_spUnk = pUnkForRelease;
  4390. m_pcollection = &collection;
  4391. m_iter = m_pcollection->begin();
  4392. return S_OK;
  4393. }
  4394. STDMETHOD(Next)(ULONG celt, T* rgelt, ULONG* pceltFetched);
  4395. STDMETHOD(Skip)(ULONG celt);
  4396. STDMETHOD(Reset)(void)
  4397. {
  4398. if (m_pcollection == NULL)
  4399. return E_FAIL;
  4400. m_iter = m_pcollection->begin();
  4401. return S_OK;
  4402. }
  4403. STDMETHOD(Clone)(Base** ppEnum);
  4404. //Data
  4405. CComPtr<IUnknown> m_spUnk;
  4406. CollType* m_pcollection;
  4407. CollType::iterator m_iter;
  4408. };
  4409. template <class Base, const IID* piid, class T, class Copy, class CollType>
  4410. STDMETHODIMP IEnumOnSTLImpl<Base, piid, T, Copy, CollType>::Next(ULONG celt, T* rgelt,
  4411. ULONG* pceltFetched)
  4412. {
  4413. if (rgelt == NULL || (celt != 1 && pceltFetched == NULL))
  4414. return E_POINTER;
  4415. if (m_pcollection == NULL)
  4416. return E_FAIL;
  4417. ULONG nActual = 0;
  4418. HRESULT hr = S_OK;
  4419. T* pelt = rgelt;
  4420. while (SUCCEEDED(hr) && m_iter != m_pcollection->end() && nActual < celt)
  4421. {
  4422. hr = Copy::copy(pelt, &*m_iter);
  4423. if (FAILED(hr))
  4424. {
  4425. while (rgelt < pelt)
  4426. Copy::destroy(rgelt++);
  4427. nActual = 0;
  4428. }
  4429. else
  4430. {
  4431. pelt++;
  4432. m_iter++;
  4433. nActual++;
  4434. }
  4435. }
  4436. if (pceltFetched)
  4437. *pceltFetched = nActual;
  4438. if (SUCCEEDED(hr) && (nActual < celt))
  4439. hr = S_FALSE;
  4440. return hr;
  4441. }
  4442. template <class Base, const IID* piid, class T, class Copy, class CollType>
  4443. STDMETHODIMP IEnumOnSTLImpl<Base, piid, T, Copy, CollType>::Skip(ULONG celt)
  4444. {
  4445. HRESULT hr = S_OK;
  4446. while (celt--)
  4447. {
  4448. if (m_iter != m_pcollection->end())
  4449. m_iter++;
  4450. else
  4451. {
  4452. hr = S_FALSE;
  4453. break;
  4454. }
  4455. }
  4456. return hr;
  4457. }
  4458. template <class Base, const IID* piid, class T, class Copy, class CollType>
  4459. STDMETHODIMP IEnumOnSTLImpl<Base, piid, T, Copy, CollType>::Clone(Base** ppEnum)
  4460. {
  4461. typedef CComObject<CComEnumOnSTL<Base, piid, T, Copy, CollType> > _class;
  4462. HRESULT hRes = E_POINTER;
  4463. if (ppEnum != NULL)
  4464. {
  4465. *ppEnum = NULL;
  4466. _class* p;
  4467. hRes = _class::CreateInstance(&p);
  4468. if (SUCCEEDED(hRes))
  4469. {
  4470. hRes = p->Init(m_spUnk, *m_pcollection);
  4471. if (SUCCEEDED(hRes))
  4472. {
  4473. p->m_iter = m_iter;
  4474. hRes = p->_InternalQueryInterface(*piid, (void**)ppEnum);
  4475. }
  4476. if (FAILED(hRes))
  4477. delete p;
  4478. }
  4479. }
  4480. return hRes;
  4481. }
  4482. template <class Base, const IID* piid, class T, class Copy, class CollType, class ThreadModel = CComObjectThreadModel>
  4483. class ATL_NO_VTABLE CComEnumOnSTL :
  4484. public IEnumOnSTLImpl<Base, piid, T, Copy, CollType>,
  4485. public CComObjectRootEx< ThreadModel >
  4486. {
  4487. public:
  4488. typedef CComEnumOnSTL<Base, piid, T, Copy, CollType, ThreadModel > _CComEnum;
  4489. typedef IEnumOnSTLImpl<Base, piid, T, Copy, CollType > _CComEnumBase;
  4490. BEGIN_COM_MAP(_CComEnum)
  4491. COM_INTERFACE_ENTRY_IID(*piid, _CComEnumBase)
  4492. END_COM_MAP()
  4493. };
  4494. template <class T, class CollType, class ItemType, class CopyItem, class EnumType>
  4495. class ICollectionOnSTLImpl : public T
  4496. {
  4497. public:
  4498. STDMETHOD(get_Count)(long* pcount)
  4499. {
  4500. if (pcount == NULL)
  4501. return E_POINTER;
  4502. *pcount = m_coll.size();
  4503. return S_OK;
  4504. }
  4505. STDMETHOD(get_Item)(long Index, ItemType* pvar)
  4506. {
  4507. //Index is 1-based
  4508. if (pvar == NULL)
  4509. return E_POINTER;
  4510. if (Index < 1)
  4511. return E_INVALIDARG;
  4512. HRESULT hr = E_FAIL;
  4513. Index--;
  4514. CollType::iterator iter = m_coll.begin();
  4515. while (iter != m_coll.end() && Index > 0)
  4516. {
  4517. iter++;
  4518. Index--;
  4519. }
  4520. if (iter != m_coll.end())
  4521. hr = CopyItem::copy(pvar, &*iter);
  4522. return hr;
  4523. }
  4524. STDMETHOD(get__NewEnum)(IUnknown** ppUnk)
  4525. {
  4526. if (ppUnk == NULL)
  4527. return E_POINTER;
  4528. *ppUnk = NULL;
  4529. HRESULT hRes = S_OK;
  4530. CComObject<EnumType>* p;
  4531. hRes = CComObject<EnumType>::CreateInstance(&p);
  4532. if (SUCCEEDED(hRes))
  4533. {
  4534. hRes = p->Init(this, m_coll);
  4535. if (hRes == S_OK)
  4536. hRes = p->QueryInterface(__uuidof(IUnknown), (void**)ppUnk);
  4537. }
  4538. if (hRes != S_OK)
  4539. delete p;
  4540. return hRes;
  4541. }
  4542. CollType m_coll;
  4543. };
  4544. //////////////////////////////////////////////////////////////////////////////
  4545. // ISpecifyPropertyPagesImpl
  4546. template <class T>
  4547. class ATL_NO_VTABLE ISpecifyPropertyPagesImpl : public ISpecifyPropertyPages
  4548. {
  4549. public:
  4550. // ISpecifyPropertyPages
  4551. //
  4552. STDMETHOD(GetPages)(CAUUID* pPages)
  4553. {
  4554. ATLTRACE(atlTraceCOM, 2, _T("ISpecifyPropertyPagesImpl::GetPages\n"));
  4555. ATL_PROPMAP_ENTRY* pMap = T::GetPropertyMap();
  4556. return GetPagesHelper(pPages, pMap);
  4557. }
  4558. protected:
  4559. HRESULT GetPagesHelper(CAUUID* pPages, ATL_PROPMAP_ENTRY* pMap)
  4560. {
  4561. if (pPages == NULL)
  4562. return E_POINTER;
  4563. ATLASSERT(pMap != NULL);
  4564. if (pMap == NULL)
  4565. return E_POINTER;
  4566. int nCnt = 0;
  4567. int i;
  4568. // Get count of unique pages to alloc the array
  4569. for (i = 0; pMap[i].pclsidPropPage != NULL; i++)
  4570. {
  4571. // only allow non data entry types
  4572. if (pMap[i].vt == 0)
  4573. {
  4574. // Does this property have a page? CLSID_NULL means it does not
  4575. if (!InlineIsEqualGUID(*pMap[i].pclsidPropPage, CLSID_NULL))
  4576. nCnt++;
  4577. }
  4578. }
  4579. pPages->pElems = (GUID*) CoTaskMemAlloc(sizeof(CLSID)*nCnt);
  4580. if (pPages->pElems == NULL)
  4581. return E_OUTOFMEMORY;
  4582. // reset count of items we have added to the array
  4583. nCnt = 0;
  4584. for (i = 0; pMap[i].pclsidPropPage != NULL; i++)
  4585. {
  4586. // only allow non data entry types
  4587. if (pMap[i].vt == 0)
  4588. {
  4589. // Does this property have a page? CLSID_NULL means it does not
  4590. if (!InlineIsEqualGUID(*pMap[i].pclsidPropPage, CLSID_NULL))
  4591. {
  4592. BOOL bFound = FALSE;
  4593. // Search through array we are building up to see
  4594. // if it is already in there
  4595. for (int j=0; j<nCnt; j++)
  4596. {
  4597. if (InlineIsEqualGUID(*(pMap[i].pclsidPropPage), pPages->pElems[j]))
  4598. {
  4599. // It's already there, so no need to add it again
  4600. bFound = TRUE;
  4601. break;
  4602. }
  4603. }
  4604. // If we didn't find it in there then add it
  4605. if (!bFound)
  4606. pPages->pElems[nCnt++] = *pMap[i].pclsidPropPage;
  4607. }
  4608. }
  4609. }
  4610. pPages->cElems = nCnt;
  4611. return S_OK;
  4612. }
  4613. };
  4614. #ifndef _ATL_NO_CONNECTION_POINTS
  4615. /////////////////////////////////////////////////////////////////////////////
  4616. // Connection Points
  4617. struct _ATL_CONNMAP_ENTRY
  4618. {
  4619. DWORD_PTR dwOffset;
  4620. };
  4621. // We want the offset of the connection point relative to the connection
  4622. // point container base class
  4623. #define BEGIN_CONNECTION_POINT_MAP(x)\
  4624. __if_not_exists(_atl_conn_classtype) \
  4625. { \
  4626. typedef x _atl_conn_classtype;\
  4627. } \
  4628. static const ATL::_ATL_CONNMAP_ENTRY* GetConnMap(int* pnEntries) {\
  4629. static const ATL::_ATL_CONNMAP_ENTRY _entries[] = {
  4630. #define BEGIN_ATTRCONNECTION_POINT_MAP(x)\
  4631. __if_not_exists(_atl_conn_classtype) \
  4632. { \
  4633. typedef x _atl_conn_classtype;\
  4634. } \
  4635. static const ATL::_ATL_CONNMAP_ENTRY* GetAttrConnMap(int* pnEntries) {\
  4636. static const ATL::_ATL_CONNMAP_ENTRY _entries[] = {
  4637. // CONNECTION_POINT_ENTRY computes the offset of the connection point to the
  4638. // IConnectionPointContainer interface
  4639. #define CONNECTION_POINT_ENTRY(iid){offsetofclass(ATL::_ICPLocator<&iid>, _atl_conn_classtype)-\
  4640. offsetofclass(ATL::IConnectionPointContainerImpl<_atl_conn_classtype>, _atl_conn_classtype)},
  4641. #define END_CONNECTION_POINT_MAP() \
  4642. __if_exists(GetAttrConnMap) \
  4643. { \
  4644. {(DWORD_PTR) -2}, \
  4645. {(DWORD_PTR) GetAttrConnMap }, \
  4646. } \
  4647. {(DWORD_PTR)-1} }; \
  4648. if (pnEntries) \
  4649. { \
  4650. __if_exists(GetAttrConnMap) \
  4651. { \
  4652. GetAttrConnMap(pnEntries); \
  4653. *pnEntries += sizeof(_entries)/sizeof(ATL::_ATL_CONNMAP_ENTRY) - 3; \
  4654. } \
  4655. __if_not_exists(GetAttrConnMap) \
  4656. { \
  4657. *pnEntries = sizeof(_entries)/sizeof(ATL::_ATL_CONNMAP_ENTRY) - 1; \
  4658. } \
  4659. } \
  4660. return _entries;}
  4661. #define END_ATTRCONNECTION_POINT_MAP() \
  4662. {(DWORD_PTR)-1} }; \
  4663. if (pnEntries) \
  4664. { \
  4665. *pnEntries = sizeof(_entries)/sizeof(ATL::_ATL_CONNMAP_ENTRY) - 1; \
  4666. } \
  4667. return _entries;}
  4668. #ifndef _DEFAULT_VECTORLENGTH
  4669. #define _DEFAULT_VECTORLENGTH 4
  4670. #endif
  4671. template <unsigned int nMaxSize>
  4672. class CComUnkArray
  4673. {
  4674. public:
  4675. CComUnkArray()
  4676. {
  4677. memset(m_arr, 0, sizeof(IUnknown*)*nMaxSize);
  4678. }
  4679. DWORD Add(IUnknown* pUnk);
  4680. BOOL Remove(DWORD dwCookie);
  4681. // If there is more than one instance of the same IUnknown*,
  4682. // this function returns the cookie for the first one.
  4683. DWORD WINAPI GetCookie(IUnknown** ppFind)
  4684. {
  4685. ATLASSERT(ppFind && *ppFind);
  4686. if (ppFind && *ppFind)
  4687. {
  4688. // find IUnknown* in array
  4689. for (DWORD dwCookie = 0; dwCookie < nMaxSize; dwCookie++)
  4690. {
  4691. if (m_arr[dwCookie] == *ppFind)
  4692. return dwCookie+1; // cookie minus one is an index into the array
  4693. }
  4694. }
  4695. return 0;
  4696. }
  4697. IUnknown* WINAPI GetUnknown(DWORD dwCookie)
  4698. {
  4699. ATLASSERT(dwCookie != 0 && dwCookie <= nMaxSize);
  4700. if (dwCookie != 0 && dwCookie <= nMaxSize)
  4701. return m_arr[dwCookie-1]; // cookie minus one is an index into the array
  4702. else
  4703. return NULL;
  4704. }
  4705. IUnknown** begin()
  4706. {
  4707. return &m_arr[0];
  4708. }
  4709. IUnknown** end()
  4710. {
  4711. return &m_arr[nMaxSize];
  4712. }
  4713. protected:
  4714. IUnknown* m_arr[nMaxSize];
  4715. };
  4716. template <unsigned int nMaxSize>
  4717. inline DWORD CComUnkArray<nMaxSize>::Add(IUnknown* pUnk)
  4718. {
  4719. DWORD dwCookie = 1;
  4720. for (IUnknown** pp = begin(); pp < end(); pp++)
  4721. {
  4722. if (*pp == NULL)
  4723. {
  4724. *pp = pUnk;
  4725. return dwCookie;
  4726. }
  4727. dwCookie++;
  4728. }
  4729. // If this fires then you need a larger array
  4730. ATLASSERT(0);
  4731. return 0;
  4732. }
  4733. template <unsigned int nMaxSize>
  4734. inline BOOL CComUnkArray<nMaxSize>::Remove(DWORD dwCookie)
  4735. {
  4736. ATLASSERT(dwCookie != 0 && dwCookie <= nMaxSize);
  4737. if (dwCookie != 0 && dwCookie <= nMaxSize && m_arr[dwCookie-1] != NULL)
  4738. {
  4739. m_arr[dwCookie-1] = NULL;
  4740. return TRUE;
  4741. }
  4742. else
  4743. return FALSE;
  4744. }
  4745. template<>
  4746. class CComUnkArray<1>
  4747. {
  4748. public:
  4749. CComUnkArray()
  4750. {
  4751. m_arr[0] = NULL;
  4752. }
  4753. DWORD Add(IUnknown* pUnk)
  4754. {
  4755. if (m_arr[0] != NULL)
  4756. {
  4757. // If this fires then you need a larger array
  4758. ATLASSERT(0);
  4759. return 0;
  4760. }
  4761. m_arr[0] = pUnk;
  4762. return 1;
  4763. }
  4764. BOOL Remove(DWORD dwCookie)
  4765. {
  4766. ATLASSERT(dwCookie == 1);
  4767. if (dwCookie == 1 && m_arr[0] != NULL)
  4768. {
  4769. m_arr[0] = NULL;
  4770. return TRUE;
  4771. }
  4772. else
  4773. return FALSE;
  4774. }
  4775. DWORD WINAPI GetCookie(IUnknown** /* pp */)
  4776. {
  4777. return 1;
  4778. }
  4779. IUnknown* WINAPI GetUnknown(DWORD dwCookie)
  4780. {
  4781. ATLASSERT(dwCookie == 1);
  4782. if (dwCookie == 1)
  4783. return m_arr[0];
  4784. else
  4785. return NULL;
  4786. }
  4787. IUnknown** begin()
  4788. {
  4789. return &m_arr[0];
  4790. }
  4791. IUnknown** end()
  4792. {
  4793. return (&m_arr[0])+1;
  4794. }
  4795. protected:
  4796. IUnknown* m_arr[1];
  4797. };
  4798. class CComDynamicUnkArray
  4799. {
  4800. public:
  4801. CComDynamicUnkArray()
  4802. {
  4803. m_nSize = 0;
  4804. m_ppUnk = NULL;
  4805. }
  4806. ~CComDynamicUnkArray()
  4807. {
  4808. if (m_nSize > 1)
  4809. free(m_ppUnk);
  4810. }
  4811. DWORD Add(IUnknown* pUnk);
  4812. BOOL Remove(DWORD dwCookie);
  4813. // If there is more than one instance of the same IUnknown*,
  4814. // this function returns the cookie for the first one.
  4815. DWORD WINAPI GetCookie(IUnknown** ppFind)
  4816. {
  4817. ATLASSERT(ppFind && *ppFind);
  4818. if (ppFind && *ppFind)
  4819. {
  4820. IUnknown** ppUnk = NULL;
  4821. DWORD dwCookie = 1;
  4822. // find IUnknown* in array
  4823. for (ppUnk = begin(); ppUnk < end(); ppUnk++)
  4824. {
  4825. if (*ppUnk == *ppFind)
  4826. return dwCookie; // cookie minus one is an index into the array
  4827. dwCookie++;
  4828. }
  4829. }
  4830. return 0;
  4831. }
  4832. IUnknown* WINAPI GetUnknown(DWORD dwCookie)
  4833. {
  4834. #ifndef _ATL_OLEDB_CONFORMANCE_TESTS
  4835. ATLASSERT(dwCookie != 0 && dwCookie <= (DWORD)m_nSize);
  4836. #endif
  4837. if (dwCookie != 0 && dwCookie <= (DWORD)m_nSize)
  4838. return GetAt(dwCookie-1); // cookie minus one is an index into the array
  4839. else
  4840. return NULL;
  4841. }
  4842. IUnknown** begin()
  4843. {
  4844. return (m_nSize < 2) ? &m_pUnk : m_ppUnk;
  4845. }
  4846. IUnknown** end()
  4847. {
  4848. return (m_nSize < 2) ? (&m_pUnk)+m_nSize : &m_ppUnk[m_nSize];
  4849. }
  4850. IUnknown* GetAt(int nIndex)
  4851. {
  4852. ATLASSERT(nIndex >= 0 && nIndex < m_nSize);
  4853. if (nIndex >= 0 && nIndex < m_nSize)
  4854. return (m_nSize < 2) ? m_pUnk : m_ppUnk[nIndex];
  4855. else
  4856. return NULL;
  4857. }
  4858. int GetSize() const
  4859. {
  4860. return m_nSize;
  4861. }
  4862. void clear()
  4863. {
  4864. if (m_nSize > 1)
  4865. free(m_ppUnk);
  4866. m_nSize = 0;
  4867. }
  4868. protected:
  4869. union
  4870. {
  4871. IUnknown** m_ppUnk;
  4872. IUnknown* m_pUnk;
  4873. };
  4874. int m_nSize;
  4875. };
  4876. inline DWORD CComDynamicUnkArray::Add(IUnknown* pUnk)
  4877. {
  4878. IUnknown** pp = NULL;
  4879. // Use m_pUnk for first item. No need to allocate array.
  4880. if (m_nSize == 0)
  4881. {
  4882. m_pUnk = pUnk;
  4883. m_nSize = 1;
  4884. return 1;
  4885. }
  4886. else if (m_nSize == 1)
  4887. {
  4888. // Create array with _DEFAULT_VECTORLENGTH number of items.
  4889. ATLTRY(pp = (IUnknown**)malloc(sizeof(IUnknown*)*_DEFAULT_VECTORLENGTH));
  4890. if (pp == NULL)
  4891. return 0;
  4892. memset(pp, 0, sizeof(IUnknown*)*_DEFAULT_VECTORLENGTH);
  4893. *pp = m_pUnk;
  4894. m_ppUnk = pp;
  4895. m_nSize = _DEFAULT_VECTORLENGTH;
  4896. }
  4897. // Walk array and use empty slots if any.
  4898. DWORD dwCookie = 1;
  4899. for (pp = begin(); pp < end(); pp++)
  4900. {
  4901. if (*pp == NULL)
  4902. {
  4903. *pp = pUnk;
  4904. return dwCookie; // cookie minus one is index into array
  4905. }
  4906. dwCookie++;
  4907. }
  4908. // No empty slots so resize array.
  4909. // # of new slots is double of current size.
  4910. int nAlloc = m_nSize*2;
  4911. pp = (IUnknown**)realloc(m_ppUnk, sizeof(IUnknown*)*nAlloc);
  4912. if (pp == NULL)
  4913. return 0;
  4914. m_ppUnk = pp;
  4915. memset(&m_ppUnk[m_nSize], 0, sizeof(IUnknown*)*m_nSize);
  4916. m_ppUnk[m_nSize] = pUnk;
  4917. dwCookie = m_nSize+1;
  4918. m_nSize = nAlloc;
  4919. return dwCookie; // cookie minus one is index into array
  4920. }
  4921. inline BOOL CComDynamicUnkArray::Remove(DWORD dwCookie)
  4922. {
  4923. #ifndef _ATL_OLEDB_CONFORMANCE_TESTS
  4924. ATLASSERT(dwCookie != 0 && dwCookie <= (DWORD)m_nSize);
  4925. #endif
  4926. if (dwCookie != 0 && dwCookie <= (DWORD)m_nSize)
  4927. {
  4928. if (m_nSize == 1)
  4929. {
  4930. if (m_pUnk == NULL)
  4931. return FALSE;
  4932. m_nSize = 0;
  4933. m_pUnk = NULL;
  4934. }
  4935. else
  4936. {
  4937. // cookie minus one is index into array
  4938. if (m_ppUnk[dwCookie-1] == NULL)
  4939. return FALSE;
  4940. m_ppUnk[dwCookie-1] = NULL;
  4941. }
  4942. return TRUE;
  4943. }
  4944. else
  4945. return FALSE;
  4946. }
  4947. template <const IID* piid>
  4948. class ATL_NO_VTABLE _ICPLocator
  4949. {
  4950. public:
  4951. //this method needs a different name than QueryInterface
  4952. STDMETHOD(_LocCPQueryInterface)(REFIID riid, void ** ppvObject) = 0;
  4953. virtual ULONG STDMETHODCALLTYPE AddRef(void) = 0;
  4954. virtual ULONG STDMETHODCALLTYPE Release(void) = 0;
  4955. };
  4956. template <class T, const IID* piid, class CDV = CComDynamicUnkArray >
  4957. class ATL_NO_VTABLE IConnectionPointImpl : public _ICPLocator<piid>
  4958. {
  4959. typedef CComEnum<IEnumConnections, &__uuidof(IEnumConnections), CONNECTDATA,
  4960. _Copy<CONNECTDATA> > CComEnumConnections;
  4961. typedef CDV _CDV;
  4962. public:
  4963. ~IConnectionPointImpl();
  4964. STDMETHOD(_LocCPQueryInterface)(REFIID riid, void ** ppvObject)
  4965. {
  4966. #ifndef _ATL_OLEDB_CONFORMANCE_TESTS
  4967. ATLASSERT(ppvObject != NULL);
  4968. #endif
  4969. if (ppvObject == NULL)
  4970. return E_POINTER;
  4971. *ppvObject = NULL;
  4972. if (InlineIsEqualGUID(riid, __uuidof(IConnectionPoint)) || InlineIsEqualUnknown(riid))
  4973. {
  4974. *ppvObject = this;
  4975. AddRef();
  4976. #ifdef _ATL_DEBUG_INTERFACES
  4977. _AtlDebugInterfacesModule.AddThunk((IUnknown**)ppvObject, _T("IConnectionPointImpl"), riid);
  4978. #endif // _ATL_DEBUG_INTERFACES
  4979. return S_OK;
  4980. }
  4981. else
  4982. return E_NOINTERFACE;
  4983. }
  4984. STDMETHOD(GetConnectionInterface)(IID* piid2)
  4985. {
  4986. if (piid2 == NULL)
  4987. return E_POINTER;
  4988. *piid2 = *piid;
  4989. return S_OK;
  4990. }
  4991. STDMETHOD(GetConnectionPointContainer)(IConnectionPointContainer** ppCPC)
  4992. {
  4993. T* pT = static_cast<T*>(this);
  4994. // No need to check ppCPC for NULL since QI will do that for us
  4995. return pT->QueryInterface(__uuidof(IConnectionPointContainer), (void**)ppCPC);
  4996. }
  4997. STDMETHOD(Advise)(IUnknown* pUnkSink, DWORD* pdwCookie);
  4998. STDMETHOD(Unadvise)(DWORD dwCookie);
  4999. STDMETHOD(EnumConnections)(IEnumConnections** ppEnum);
  5000. CDV m_vec;
  5001. };
  5002. template <class T, const IID* piid, class CDV>
  5003. IConnectionPointImpl<T, piid, CDV>::~IConnectionPointImpl()
  5004. {
  5005. IUnknown** pp = m_vec.begin();
  5006. while (pp < m_vec.end())
  5007. {
  5008. if (*pp != NULL)
  5009. (*pp)->Release();
  5010. pp++;
  5011. }
  5012. }
  5013. template <class T, const IID* piid, class CDV>
  5014. STDMETHODIMP IConnectionPointImpl<T, piid, CDV>::Advise(IUnknown* pUnkSink,
  5015. DWORD* pdwCookie)
  5016. {
  5017. T* pT = static_cast<T*>(this);
  5018. IUnknown* p;
  5019. HRESULT hRes = S_OK;
  5020. if (pdwCookie != NULL)
  5021. *pdwCookie = 0;
  5022. if (pUnkSink == NULL || pdwCookie == NULL)
  5023. return E_POINTER;
  5024. IID iid;
  5025. GetConnectionInterface(&iid);
  5026. hRes = pUnkSink->QueryInterface(iid, (void**)&p);
  5027. if (SUCCEEDED(hRes))
  5028. {
  5029. pT->Lock();
  5030. *pdwCookie = m_vec.Add(p);
  5031. hRes = (*pdwCookie != NULL) ? S_OK : CONNECT_E_ADVISELIMIT;
  5032. pT->Unlock();
  5033. if (hRes != S_OK)
  5034. p->Release();
  5035. }
  5036. else if (hRes == E_NOINTERFACE)
  5037. hRes = CONNECT_E_CANNOTCONNECT;
  5038. if (FAILED(hRes))
  5039. *pdwCookie = 0;
  5040. return hRes;
  5041. }
  5042. template <class T, const IID* piid, class CDV>
  5043. STDMETHODIMP IConnectionPointImpl<T, piid, CDV>::Unadvise(DWORD dwCookie)
  5044. {
  5045. T* pT = static_cast<T*>(this);
  5046. pT->Lock();
  5047. IUnknown* p = m_vec.GetUnknown(dwCookie);
  5048. HRESULT hRes = m_vec.Remove(dwCookie) ? S_OK : CONNECT_E_NOCONNECTION;
  5049. pT->Unlock();
  5050. if (hRes == S_OK && p != NULL)
  5051. p->Release();
  5052. return hRes;
  5053. }
  5054. template <class T, const IID* piid, class CDV>
  5055. STDMETHODIMP IConnectionPointImpl<T, piid, CDV>::EnumConnections(
  5056. IEnumConnections** ppEnum)
  5057. {
  5058. if (ppEnum == NULL)
  5059. return E_POINTER;
  5060. *ppEnum = NULL;
  5061. CComObject<CComEnumConnections>* pEnum = NULL;
  5062. ATLTRY(pEnum = new CComObject<CComEnumConnections>)
  5063. if (pEnum == NULL)
  5064. return E_OUTOFMEMORY;
  5065. T* pT = static_cast<T*>(this);
  5066. pT->Lock();
  5067. CONNECTDATA* pcd = NULL;
  5068. ATLTRY(pcd = new CONNECTDATA[m_vec.end()-m_vec.begin()])
  5069. if (pcd == NULL)
  5070. {
  5071. delete pEnum;
  5072. pT->Unlock();
  5073. return E_OUTOFMEMORY;
  5074. }
  5075. CONNECTDATA* pend = pcd;
  5076. // Copy the valid CONNECTDATA's
  5077. for (IUnknown** pp = m_vec.begin();pp<m_vec.end();pp++)
  5078. {
  5079. if (*pp != NULL)
  5080. {
  5081. (*pp)->AddRef();
  5082. pend->pUnk = *pp;
  5083. pend->dwCookie = m_vec.GetCookie(pp);
  5084. pend++;
  5085. }
  5086. }
  5087. // don't copy the data, but transfer ownership to it
  5088. pEnum->Init(pcd, pend, NULL, AtlFlagTakeOwnership);
  5089. pT->Unlock();
  5090. HRESULT hRes = pEnum->_InternalQueryInterface(__uuidof(IEnumConnections), (void**)ppEnum);
  5091. if (FAILED(hRes))
  5092. delete pEnum;
  5093. return hRes;
  5094. }
  5095. /////////////////////////////////////////////////////////////////////////////
  5096. // IConnectionPointContainerImpl
  5097. template <class T>
  5098. class ATL_NO_VTABLE IConnectionPointContainerImpl : public IConnectionPointContainer
  5099. {
  5100. typedef CComEnum<IEnumConnectionPoints,
  5101. &__uuidof(IEnumConnectionPoints), IConnectionPoint*,
  5102. _CopyInterface<IConnectionPoint> >
  5103. CComEnumConnectionPoints;
  5104. public:
  5105. STDMETHOD(EnumConnectionPoints)(IEnumConnectionPoints** ppEnum)
  5106. {
  5107. if (ppEnum == NULL)
  5108. return E_POINTER;
  5109. *ppEnum = NULL;
  5110. CComEnumConnectionPoints* pEnum = NULL;
  5111. ATLTRY(pEnum = new CComObject<CComEnumConnectionPoints>)
  5112. if (pEnum == NULL)
  5113. return E_OUTOFMEMORY;
  5114. int nCPCount;
  5115. const _ATL_CONNMAP_ENTRY* pEntry = T::GetConnMap(&nCPCount);
  5116. // allocate an initialize a vector of connection point object pointers
  5117. IConnectionPoint** ppCP = (IConnectionPoint**)alloca(sizeof(IConnectionPoint*)*nCPCount);
  5118. int i = 0;
  5119. while (pEntry->dwOffset != (DWORD_PTR)-1)
  5120. {
  5121. if (pEntry->dwOffset == (DWORD_PTR)-2)
  5122. {
  5123. pEntry++;
  5124. const _ATL_CONNMAP_ENTRY* (*pFunc)(int*) = (const _ATL_CONNMAP_ENTRY* (*)(int*))(pEntry->dwOffset);
  5125. pEntry = pFunc(NULL);
  5126. continue;
  5127. }
  5128. ppCP[i++] = (IConnectionPoint*)((INT_PTR)this+pEntry->dwOffset);
  5129. pEntry++;
  5130. }
  5131. // copy the pointers: they will AddRef this object
  5132. HRESULT hRes = pEnum->Init((IConnectionPoint**)&ppCP[0],
  5133. (IConnectionPoint**)&ppCP[nCPCount],
  5134. reinterpret_cast<IConnectionPointContainer*>(this), AtlFlagCopy);
  5135. if (FAILED(hRes))
  5136. {
  5137. delete pEnum;
  5138. return hRes;
  5139. }
  5140. hRes = pEnum->QueryInterface(__uuidof(IEnumConnectionPoints), (void**)ppEnum);
  5141. if (FAILED(hRes))
  5142. delete pEnum;
  5143. return hRes;
  5144. }
  5145. STDMETHOD(FindConnectionPoint)(REFIID riid, IConnectionPoint** ppCP)
  5146. {
  5147. if (ppCP == NULL)
  5148. return E_POINTER;
  5149. *ppCP = NULL;
  5150. HRESULT hRes = CONNECT_E_NOCONNECTION;
  5151. const _ATL_CONNMAP_ENTRY* pEntry = T::GetConnMap(NULL);
  5152. IID iid;
  5153. while (pEntry->dwOffset != (DWORD_PTR)-1)
  5154. {
  5155. if (pEntry->dwOffset == (DWORD_PTR)-2)
  5156. {
  5157. pEntry++;
  5158. const _ATL_CONNMAP_ENTRY* (*pFunc)(int*) = (const _ATL_CONNMAP_ENTRY* (*)(int*))(pEntry->dwOffset);
  5159. pEntry = pFunc(NULL);
  5160. continue;
  5161. }
  5162. IConnectionPoint* pCP =
  5163. (IConnectionPoint*)((INT_PTR)this+pEntry->dwOffset);
  5164. if (SUCCEEDED(pCP->GetConnectionInterface(&iid)) &&
  5165. InlineIsEqualGUID(riid, iid))
  5166. {
  5167. *ppCP = pCP;
  5168. pCP->AddRef();
  5169. hRes = S_OK;
  5170. break;
  5171. }
  5172. pEntry++;
  5173. }
  5174. return hRes;
  5175. }
  5176. };
  5177. #endif //!_ATL_NO_CONNECTION_POINTS
  5178. /////////////////////////////////////////////////////////////////////////////
  5179. // IExternalConnectionImpl
  5180. // An object that implements IExternalConnection should explicitly call
  5181. // CoDisconnectObject on itself when its external reference count drops to 0.
  5182. // This call will cause the stub manager to call Release on the object so the
  5183. // object can destroy itself.
  5184. template <class T>
  5185. class IExternalConnectionImpl : public IExternalConnection
  5186. {
  5187. public:
  5188. IExternalConnectionImpl(void) : m_nStrongLocks(0) {}
  5189. STDMETHODIMP_(DWORD) AddConnection(DWORD extconn, DWORD /*dwReserved*/)
  5190. {
  5191. DWORD dw = 0;
  5192. if (extconn & EXTCONN_STRONG)
  5193. {
  5194. dw = T::_ThreadModel::Increment(&m_nStrongLocks);
  5195. static_cast<T*>(this)->OnAddConnection(dw == 1);
  5196. }
  5197. return dw;
  5198. }
  5199. STDMETHODIMP_(DWORD) ReleaseConnection(DWORD extconn, DWORD /*dwReserved*/, BOOL bLastUnlockReleases)
  5200. {
  5201. DWORD dw = 0;
  5202. if (extconn & EXTCONN_STRONG)
  5203. {
  5204. dw = T::_ThreadModel::Decrement(&m_nStrongLocks);
  5205. static_cast<T*>(this)->OnReleaseConnection(dw == 0, !!bLastUnlockReleases);
  5206. }
  5207. return dw;
  5208. }
  5209. // Services provided by this class
  5210. bool DoIHaveAStub() { return m_nStrongLocks != 0; }
  5211. LONG GetStrongConnectionCount() { return m_nStrongLocks; }
  5212. // Extensibility points provided by this class
  5213. void OnAddConnection(bool bThisIsFirstLock) {}
  5214. void OnReleaseConnection(bool bThisIsLastUnlock, bool bLastUnlockReleases)
  5215. {
  5216. if (bThisIsLastUnlock && bLastUnlockReleases)
  5217. CoDisconnectObject(static_cast<T*>(this)->GetUnknown(), 0);
  5218. }
  5219. // Implementation
  5220. LONG m_nStrongLocks;
  5221. };
  5222. #pragma pack(pop)
  5223. }; //namespace ATL
  5224. //REVIEW: Just to fix VSEE
  5225. #pragma pop_macro("min")
  5226. #pragma pop_macro("max")
  5227. #ifndef _ATL_NO_PRAGMA_WARNINGS
  5228. #pragma warning (pop)
  5229. #endif
  5230. #endif // __ATLCOM_H__
  5231. /////////////////////////////////////////////////////////////////////////////