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.

781 lines
18 KiB

  1. /*===================================================================
  2. Microsoft Denali
  3. Microsoft Confidential.
  4. Copyright 1997 Microsoft Corporation. All Rights Reserved.
  5. Component: MetaUtil object
  6. File: ChkError.cpp
  7. Owner: t-BrianM
  8. This file contains implementation of the check error collection for
  9. CheckSchema and CheckKey.
  10. Notes:
  11. I implemented the error stuff as a linked list of COM CheckError
  12. objects. It is assumed that the error collection will be
  13. created, all elements added to it, then used. No changes after
  14. creation! Because of the static nature of the list, the links
  15. are physicaly located in the CheckError objects, no node wrapping
  16. needed. This design cuts down on the copying and redundancy.
  17. ===================================================================*/
  18. #include "stdafx.h"
  19. #include "MetaUtil.h"
  20. #include "MUtilObj.h"
  21. #include "ChkError.h"
  22. /*------------------------------------------------------------------
  23. * C C h e c k E r r o r C o l l e c t i o n
  24. */
  25. /*===================================================================
  26. CCheckErrorCollection::CCheckErrorCollection
  27. Constructor
  28. Parameters:
  29. None
  30. Returns:
  31. Nothing
  32. ===================================================================*/
  33. CCheckErrorCollection::CCheckErrorCollection() : m_iNumErrors(0),
  34. m_pCErrorList(NULL),
  35. m_pCErrorListEnd(NULL)
  36. {
  37. }
  38. /*===================================================================
  39. CCheckErrorCollection::~CCheckErrorCollection
  40. Destructor
  41. Parameters:
  42. None
  43. Returns:
  44. Nothing
  45. ===================================================================*/
  46. CCheckErrorCollection::~CCheckErrorCollection()
  47. {
  48. // Release all of the elements
  49. CComObject<CCheckError> *pCLoop;
  50. CComObject<CCheckError> *pCRelease;
  51. pCLoop = m_pCErrorList;
  52. while (pCLoop != NULL) {
  53. pCRelease = pCLoop;
  54. pCLoop = pCLoop->GetNextError();
  55. pCRelease->Release();
  56. }
  57. }
  58. /*===================================================================
  59. CCheckErrorCollection::InterfaceSupportsErrorInfo
  60. Standard ATL implementation
  61. ===================================================================*/
  62. STDMETHODIMP CCheckErrorCollection::InterfaceSupportsErrorInfo(REFIID riid)
  63. {
  64. static const IID* arr[] =
  65. {
  66. &IID_ICheckErrorCollection,
  67. };
  68. for (int i=0;i<sizeof(arr)/sizeof(arr[0]);i++)
  69. {
  70. if (InlineIsEqualGUID(*arr[i],riid))
  71. return S_OK;
  72. }
  73. return S_FALSE;
  74. }
  75. /*===================================================================
  76. CCheckErrorCollection::get_Count
  77. Get method for Count property. Counts the number of errors in the
  78. collection.
  79. Parameters:
  80. plReturn [out, retval] Value to return to client.
  81. Returns:
  82. E_INVALIDARG if plReturn == NULL
  83. S_OK on success
  84. ===================================================================*/
  85. STDMETHODIMP CCheckErrorCollection::get_Count(long *plReturn)
  86. {
  87. TRACE0("MetaUtil: CCheckErrorCollection::get_Count\n");
  88. ASSERT_NULL_OR_POINTER(plReturn, long);
  89. if (plReturn == NULL) {
  90. return ::ReportError(E_INVALIDARG);
  91. }
  92. *plReturn = m_iNumErrors;
  93. return S_OK;
  94. }
  95. /*===================================================================
  96. CCheckErrorCollection::get_Item
  97. Get method for Item property. Returns a CheckError given its index.
  98. Parameters:
  99. varId [in] 1 based index or Name of the CheckError to get
  100. ppIReturn [out, retval] Interface for the property object
  101. Returns:
  102. E_INVALIDARG if ppIReturn == NULL or lIndex <= 0
  103. S_OK on success
  104. ===================================================================*/
  105. STDMETHODIMP CCheckErrorCollection::get_Item(long lIndex,
  106. LPDISPATCH * ppIReturn)
  107. {
  108. TRACE0("MetaUtil: CCheckErrorCollection::get_Item\n");
  109. ASSERT_NULL_OR_POINTER(ppIReturn, LPDISPATCH);
  110. if ((lIndex <= 0) || (ppIReturn == NULL)) {
  111. // 0 or less, too small OR ppIReturn == NULL
  112. return ::ReportError(E_INVALIDARG);
  113. }
  114. else if (lIndex >= m_iNumErrors) {
  115. // Too large
  116. return ::ReportError(ERROR_NO_MORE_ITEMS);
  117. }
  118. else {
  119. // Get the requested error
  120. HRESULT hr;
  121. CComObject<CCheckError> *pCLoop;
  122. pCLoop = m_pCErrorList;
  123. while ((lIndex > 1) && (pCLoop != NULL)) {
  124. lIndex--;
  125. pCLoop = pCLoop->GetNextError();
  126. }
  127. // Set the interface to IDispatch
  128. hr = pCLoop->QueryInterface(IID_IDispatch, (void **) ppIReturn);
  129. if (FAILED(hr)) {
  130. return ::ReportError(hr);
  131. }
  132. ASSERT(*ppIReturn != NULL);
  133. return S_OK;
  134. }
  135. }
  136. /*===================================================================
  137. CCheckErrorCollection::get__NewEnum
  138. Get method for _NewEnum property. Returns an enumeration object for
  139. the CheckErrors.
  140. Parameters:
  141. ppIReturn [out, retval] Interface for the enumeration object
  142. Returns:
  143. E_INVALIDARG if ppIReturn == NULL
  144. E_OUTOFMEMORY if allocation failed
  145. S_OK on success
  146. ===================================================================*/
  147. STDMETHODIMP CCheckErrorCollection::get__NewEnum(LPUNKNOWN *ppIReturn)
  148. {
  149. TRACE0("MetaUtil: CCheckErrorCollection::get__NewEnum\n");
  150. ASSERT_NULL_OR_POINTER(ppIReturn, LPUNKNOWN);
  151. if (ppIReturn == NULL) {
  152. return ::ReportError(E_INVALIDARG);
  153. }
  154. HRESULT hr;
  155. // Create the check error enumeration
  156. CComObject<CCheckErrorEnum> *pObj = NULL;
  157. ATLTRY(pObj = new CComObject<CCheckErrorEnum>);
  158. if (pObj == NULL) {
  159. return ::ReportError(E_OUTOFMEMORY);
  160. }
  161. hr = pObj->Init(m_pCErrorList);
  162. if (FAILED(hr)) {
  163. return ::ReportError(hr);
  164. }
  165. // Set the interface to IUnknown
  166. hr = pObj->QueryInterface(IID_IUnknown, (void **) ppIReturn);
  167. if (FAILED(hr)) {
  168. return ::ReportError(hr);
  169. }
  170. ASSERT(*ppIReturn != NULL);
  171. return S_OK;
  172. }
  173. /*===================================================================
  174. CCheckErrorCollection::AddError(
  175. Adds an error to the error collection.
  176. Parameters:
  177. lId Identifier for this error
  178. lSeverity Severity of the error
  179. tszDescription Description of error for users
  180. tszKey Key where error occurred
  181. lProperty Property where error occurred
  182. Returns:
  183. E_OUTOFMEMORY if allocation fails
  184. S_OK on success
  185. Notes:
  186. It is assumed that the CheckError collection will be created
  187. then all of the errors will be added before the collection is
  188. sent to the client. Similar to Init(), however it could be
  189. called multiple times.
  190. ===================================================================*/
  191. HRESULT CCheckErrorCollection::AddError(long lId,
  192. long lSeverity,
  193. LPCTSTR tszDescription,
  194. LPCTSTR tszKey,
  195. long lProperty)
  196. {
  197. ASSERT(lId > 0);
  198. ASSERT(lSeverity > 0);
  199. ASSERT_STRING(tszDescription);
  200. ASSERT_STRING(tszKey);
  201. ASSERT(lProperty >= 0);
  202. HRESULT hr;
  203. // Create the new element
  204. CComObject<CCheckError> *pNewError = NULL;
  205. ATLTRY(pNewError = new CComObject<CCheckError>);
  206. if (pNewError == NULL) {
  207. return ::ReportError(E_OUTOFMEMORY);
  208. }
  209. hr = pNewError->Init(lId, lSeverity, tszDescription, tszKey, lProperty);
  210. if (FAILED(hr)) {
  211. return ::ReportError(hr);
  212. }
  213. // AddRef it
  214. pNewError->AddRef();
  215. // Add it to the end of the list
  216. if (m_pCErrorList == NULL) {
  217. m_pCErrorList = pNewError;
  218. m_pCErrorListEnd = pNewError;
  219. }
  220. else {
  221. m_pCErrorListEnd->SetNextError(pNewError);
  222. m_pCErrorListEnd = pNewError;
  223. }
  224. // Count it
  225. m_iNumErrors++;
  226. return S_OK;
  227. }
  228. /*------------------------------------------------------------------
  229. * C C h e c k E r r o r E n u m
  230. */
  231. /*===================================================================
  232. CCheckErrorEnum::CCheckErrorEnum()
  233. Constructor
  234. Parameters:
  235. None
  236. Returns:
  237. Nothing
  238. ===================================================================*/
  239. CCheckErrorEnum::CCheckErrorEnum() : m_pCErrorList(NULL),
  240. m_pCErrorListPos(NULL)
  241. {
  242. }
  243. /*===================================================================
  244. CCheckErrorEnum::Init
  245. Constructor
  246. Parameters:
  247. pCErrorList Pointer to first element in list to enumerate.
  248. Returns:
  249. S_OK on success
  250. ===================================================================*/
  251. HRESULT CCheckErrorEnum::Init(CComObject<CCheckError> *pCErrorList)
  252. {
  253. ASSERT_NULL_OR_POINTER(pCErrorList, CComObject<CCheckError>);
  254. // Set list head and current position
  255. m_pCErrorList = pCErrorList;
  256. m_pCErrorListPos = pCErrorList;
  257. // AddRef all of the elements
  258. CComObject<CCheckError> *pCLoop;
  259. pCLoop = m_pCErrorList;
  260. while (pCLoop != NULL) {
  261. pCLoop->AddRef();
  262. pCLoop = pCLoop->GetNextError();
  263. }
  264. return S_OK;
  265. }
  266. /*===================================================================
  267. CCheckErrorEnum::~CCheckErrorEnum
  268. Destructor
  269. Parameters:
  270. None
  271. Returns:
  272. Nothing
  273. ===================================================================*/
  274. CCheckErrorEnum::~CCheckErrorEnum()
  275. {
  276. // Release all of the elements
  277. CComObject<CCheckError> *pCLoop;
  278. CComObject<CCheckError> *pCRelease;
  279. pCLoop = m_pCErrorList;
  280. while (pCLoop != NULL) {
  281. pCRelease = pCLoop;
  282. pCLoop = pCLoop->GetNextError();
  283. pCRelease->Release();
  284. }
  285. }
  286. /*===================================================================
  287. CCheckErrorEnum::Next
  288. Gets the next n items from the enumberation.
  289. Parameters:
  290. ulNumToGet [in] Number of elements to get
  291. rgvarDest [out] Array to put them in
  292. pulNumGot [out] If not NULL, number of elements rgvarDest got
  293. Returns:
  294. E_INVALIDARG if rgvarDest == NULL
  295. S_FALSE if outputs less than ulNumToGet items
  296. S_OK if outputs ulNumToGet items
  297. ===================================================================*/
  298. STDMETHODIMP CCheckErrorEnum::Next(unsigned long ulNumToGet,
  299. VARIANT FAR* rgvarDest,
  300. unsigned long FAR* pulNumGot)
  301. {
  302. TRACE0("MetaUtil: CCheckErrorEnum::Next\n");
  303. ASSERT_NULL_OR_POINTER(pulNumGot, unsigned long);
  304. // Make sure the array is big enough and we can write to it
  305. ASSERT((rgvarDest == NULL) || IsValidAddress(rgvarDest, ulNumToGet * sizeof(VARIANT), TRUE));
  306. if (pulNumGot != NULL) {
  307. pulNumGot = 0;
  308. }
  309. if (rgvarDest == NULL) {
  310. return ::ReportError(E_INVALIDARG);
  311. }
  312. HRESULT hr;
  313. unsigned int uiDestIndex;
  314. IDispatch *pIDispatch;
  315. // While we have more to get and have more left
  316. uiDestIndex = 0;
  317. while ((uiDestIndex < ulNumToGet) && (m_pCErrorListPos != NULL)) {
  318. // Set the interface to IDispatch
  319. hr = m_pCErrorListPos->QueryInterface(IID_IDispatch, (void **) &pIDispatch);
  320. if (FAILED(hr)) {
  321. return ::ReportError(hr);
  322. }
  323. ASSERT(pIDispatch != NULL);
  324. // Put it in the output array
  325. VariantInit(&(rgvarDest[uiDestIndex]));
  326. rgvarDest[uiDestIndex].vt = VT_DISPATCH;
  327. rgvarDest[uiDestIndex].pdispVal = pIDispatch;
  328. // Next element
  329. m_pCErrorListPos = m_pCErrorListPos->GetNextError();
  330. uiDestIndex++;
  331. }
  332. // If pulNumGot isn't NULL, set it
  333. if (pulNumGot != NULL) {
  334. *pulNumGot = uiDestIndex;
  335. }
  336. if (uiDestIndex == ulNumToGet) {
  337. // Returned the requested number of elements
  338. TRACE0("MetaUtil: CCheckErrorEnum::Next Ok\n");
  339. return S_OK;
  340. }
  341. else {
  342. // Returned less than the requested number of elements
  343. TRACE0("MetaUtil: CCheckErrorEnum::Next False\n");
  344. return S_FALSE;
  345. }
  346. }
  347. /*===================================================================
  348. CCheckErrorEnum::Skip
  349. Skips the next n items in an enumeration
  350. Parameters:
  351. ulNumToSkip [in] Number of elements to skip
  352. Returns:
  353. S_OK always
  354. ===================================================================*/
  355. STDMETHODIMP CCheckErrorEnum::Skip(unsigned long ulNumToSkip)
  356. {
  357. TRACE0("MetaUtil: CCheckErrorEnum::Skip\n");
  358. unsigned long ulIndex;
  359. ulIndex = ulNumToSkip;
  360. while ((ulIndex != 0) && (m_pCErrorListPos != NULL)) {
  361. m_pCErrorListPos = m_pCErrorListPos->GetNextError();
  362. ulIndex--;
  363. }
  364. return S_OK;
  365. }
  366. /*===================================================================
  367. CCheckErrorEnum::Reset
  368. Rests the enumeration to the first item
  369. Parameters:
  370. None
  371. Returns:
  372. S_OK always
  373. ===================================================================*/
  374. STDMETHODIMP CCheckErrorEnum::Reset()
  375. {
  376. TRACE0("MetaUtil: CCheckErrorEnum::Reset\n");
  377. // Set our position back to the first element
  378. m_pCErrorListPos = m_pCErrorList;
  379. return S_OK;
  380. }
  381. /*===================================================================
  382. CCheckErrorEnum::Clone
  383. Gets an interface pointer to a copy of the enumeration at its
  384. current state.
  385. Parameters:
  386. ppIReturn [out] Pointer to interface for copy
  387. Returns:
  388. E_INVALIDARG if ppIReturn == NULL
  389. E_OUTOFMEMORY if not enough memory to create clone
  390. S_OK on success
  391. ===================================================================*/
  392. STDMETHODIMP CCheckErrorEnum::Clone(IEnumVARIANT FAR* FAR* ppIReturn)
  393. {
  394. TRACE0("MetaUtil: CCheckErrorEnum::Clone\n");
  395. ASSERT_NULL_OR_POINTER(ppIReturn, LPUNKNOWN);
  396. if (ppIReturn == NULL) {
  397. return ::ReportError(E_INVALIDARG);
  398. }
  399. HRESULT hr;
  400. // Create a copy of the enumeration
  401. CComObject<CCheckErrorEnum> *pObj = NULL;
  402. ATLTRY(pObj = new CComObject<CCheckErrorEnum>);
  403. if (pObj == NULL) {
  404. return ::ReportError(E_OUTOFMEMORY);
  405. }
  406. hr = pObj->Init(m_pCErrorList);
  407. if (FAILED(hr)) {
  408. return ::ReportError(hr);
  409. }
  410. // Set the interface to IEnumVARIANT
  411. hr = pObj->QueryInterface(IID_IEnumVARIANT, (void **) ppIReturn);
  412. if (FAILED(hr)) {
  413. return ::ReportError(hr);
  414. }
  415. ASSERT(*ppIReturn != NULL);
  416. return S_OK;
  417. }
  418. /*------------------------------------------------------------------
  419. * C C h e c k E r r o r
  420. */
  421. /*===================================================================
  422. CCheckError::CCheckError
  423. Constructor
  424. Parameters:
  425. None
  426. Returns:
  427. Nothing
  428. ===================================================================*/
  429. CCheckError::CCheckError() : m_lId(0),
  430. m_lSeverity(0),
  431. m_tszDescription(NULL),
  432. m_tszKey(NULL),
  433. m_lProperty(0),
  434. m_pNextError(NULL)
  435. {
  436. }
  437. /*===================================================================
  438. CCheckError::Init
  439. Constructor
  440. Parameters:
  441. lId Identifier for this error
  442. lSeverity Severity of the error
  443. tszDescription Description of error for users
  444. tszKey Key where error occurred
  445. lProperty Property where error occurred
  446. Returns:
  447. E_OUTOFMEMORY if allocation fails
  448. S_OK on success
  449. ===================================================================*/
  450. HRESULT CCheckError::Init(long lId,
  451. long lSeverity,
  452. LPCTSTR tszDescription,
  453. LPCTSTR tszKey,
  454. long lProperty)
  455. {
  456. ASSERT(lId > 0);
  457. ASSERT(lSeverity > 0);
  458. ASSERT_STRING(tszDescription);
  459. ASSERT_STRING(tszKey);
  460. ASSERT(lProperty >= 0);
  461. m_lId = lId;
  462. m_lSeverity = lSeverity;
  463. // Copy tszDescription to m_tszDescription
  464. m_tszDescription = new TCHAR[_tcslen(tszDescription) + 1];
  465. if (m_tszDescription == NULL) {
  466. return ::ReportError(E_OUTOFMEMORY);
  467. }
  468. _tcscpy(m_tszDescription, tszDescription);
  469. // Copy tszKey to m_tszKey
  470. m_tszKey = new TCHAR[_tcslen(tszKey) + 1];
  471. if (m_tszKey == NULL) {
  472. return ::ReportError(E_OUTOFMEMORY);
  473. }
  474. _tcscpy(m_tszKey, tszKey);
  475. m_lProperty = lProperty;
  476. return S_OK;
  477. }
  478. /*===================================================================
  479. CCheckError::~CCheckError
  480. Destructor
  481. Parameters:
  482. None
  483. Returns:
  484. Nothing
  485. ===================================================================*/
  486. CCheckError::~CCheckError()
  487. {
  488. if (m_tszDescription != NULL) {
  489. delete m_tszDescription;
  490. }
  491. if (m_tszKey != NULL) {
  492. delete m_tszKey;
  493. }
  494. }
  495. /*===================================================================
  496. CCheckError::InterfaceSupportsErrorInfo
  497. Standard ATL implementation
  498. ===================================================================*/
  499. STDMETHODIMP CCheckError::InterfaceSupportsErrorInfo(REFIID riid)
  500. {
  501. static const IID* arr[] =
  502. {
  503. &IID_ICheckError,
  504. };
  505. for (int i=0;i<sizeof(arr)/sizeof(arr[0]);i++)
  506. {
  507. if (InlineIsEqualGUID(*arr[i],riid))
  508. return S_OK;
  509. }
  510. return S_FALSE;
  511. }
  512. /*===================================================================
  513. CCheckError::get_Id
  514. Get method for Id property. Gets the Id for this error, so it can
  515. be easily processed by recovery logic.
  516. Parameters:
  517. plId [out, retval] Value to return to client.
  518. Returns:
  519. E_INVALIDARG if plId == NULL
  520. S_OK on success
  521. ===================================================================*/
  522. STDMETHODIMP CCheckError::get_Id(long *plId)
  523. {
  524. TRACE0("MetaUtil: CCheckError::get_Id\n");
  525. ASSERT_NULL_OR_POINTER(plId, long);
  526. if (plId == NULL) {
  527. return E_INVALIDARG;
  528. }
  529. *plId = m_lId;
  530. return S_OK;
  531. }
  532. /*===================================================================
  533. CCheckError::get_Severity
  534. Get method for Severity property. Gets the severity for this error,
  535. so it can be filtered.
  536. Parameters:
  537. plSeverity [out, retval] Value to return to client.
  538. Returns:
  539. E_INVALIDARG if plSeverity == NULL
  540. S_OK on success
  541. ===================================================================*/
  542. STDMETHODIMP CCheckError::get_Severity(long *plSeverity)
  543. {
  544. TRACE0("MetaUtil: CCheckError::get_Severity\n");
  545. ASSERT_NULL_OR_POINTER(plSeverity, long);
  546. if (plSeverity == NULL) {
  547. return E_INVALIDARG;
  548. }
  549. *plSeverity = m_lSeverity;
  550. return S_OK;
  551. }
  552. /*===================================================================
  553. CCheckError::get_Description
  554. Get method for Description property. Gets the description for this
  555. error, so users can understand it.
  556. Parameters:
  557. pbstrDescription [out, retval] Value to return to client.
  558. Returns:
  559. E_INVALIDARG if pbstrDescription == NULL
  560. S_OK on success
  561. ===================================================================*/
  562. STDMETHODIMP CCheckError::get_Description(BSTR *pbstrDescription)
  563. {
  564. TRACE0("MetaUtil: CCheckError::get_Description\n");
  565. ASSERT_NULL_OR_POINTER(pbstrDescription, BSTR);
  566. if (pbstrDescription == NULL) {
  567. return E_INVALIDARG;
  568. }
  569. USES_CONVERSION;
  570. *pbstrDescription = T2BSTR(m_tszDescription);
  571. return S_OK;
  572. }
  573. /*===================================================================
  574. CCheckError::get_Key
  575. Get method for Key property. Gets the key where the error occurred.
  576. Parameters:
  577. pbstrKey [out, retval] Value to return to client.
  578. Returns:
  579. E_INVALIDARG if pbstrKey == NULL
  580. S_OK on success
  581. ===================================================================*/
  582. STDMETHODIMP CCheckError::get_Key(BSTR * pbstrKey)
  583. {
  584. TRACE0("MetaUtil: CCheckError::get_Key\n");
  585. ASSERT_NULL_OR_POINTER(pbstrKey, BSTR);
  586. if (pbstrKey == NULL) {
  587. return E_INVALIDARG;
  588. }
  589. USES_CONVERSION;
  590. *pbstrKey = T2BSTR(m_tszKey);
  591. return S_OK;
  592. }
  593. /*===================================================================
  594. CCheckError::get_Property
  595. Get method for Property property. Gets the property where the error
  596. occurred.
  597. Parameters:
  598. pbstrProperty [out, retval] Value to return to client.
  599. Returns:
  600. E_INVALIDARG if pbstrProperty == NULL
  601. S_OK on success
  602. ===================================================================*/
  603. STDMETHODIMP CCheckError::get_Property(long * plProperty)
  604. {
  605. TRACE0("MetaUtil: CCheckError::get_Property\n");
  606. ASSERT_NULL_OR_POINTER(plProperty, long);
  607. if (plProperty == NULL) {
  608. return E_INVALIDARG;
  609. }
  610. *plProperty = m_lProperty;
  611. return S_OK;
  612. }