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.

1318 lines
45 KiB

  1. ////////////////////////////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Microsoft WMI OLE DB Provider
  4. // (C) Copyright 1999 Microsoft Corporation. All Rights Reserved.
  5. //
  6. // Error Routines
  7. //
  8. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  9. #include "headers.h"
  10. #define ERROR_GUID_ARRAYSIZE 5
  11. // NTRaid : 111781
  12. // 06/13/00
  13. #define ERROR_DESCRIPTION_SIZE 512
  14. static const ULONG INITIAL_ERROR_QUEUE_SIZE = 10;
  15. CImpISupportErrorInfo::CImpISupportErrorInfo( IUnknown* pUnkOuter)
  16. {
  17. m_cRef = 0L;
  18. m_pUnkOuter = pUnkOuter;
  19. m_cpErrInt = 0;
  20. m_rgpErrInt = NULL;
  21. m_cAllocGuid = 0;
  22. }
  23. CImpISupportErrorInfo::~CImpISupportErrorInfo()
  24. {
  25. SAFE_DELETE_ARRAY(m_rgpErrInt);
  26. }
  27. //////////////////////////////////////////////////////////////////////////////////////////////////////
  28. STDMETHODIMP_(ULONG) CImpISupportErrorInfo::AddRef(void)
  29. {
  30. InterlockedIncrement((long*)&m_cRef);
  31. return m_pUnkOuter->AddRef();
  32. }
  33. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  34. STDMETHODIMP_(ULONG) CImpISupportErrorInfo::Release(void)
  35. {
  36. InterlockedDecrement((long*)&m_cRef);
  37. return m_pUnkOuter->Release();
  38. }
  39. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  40. STDMETHODIMP CImpISupportErrorInfo::QueryInterface( REFIID riid, LPVOID * ppv )
  41. {
  42. return m_pUnkOuter->QueryInterface(riid, ppv);
  43. }
  44. // Modifications done for
  45. // NTRaid:111765
  46. HRESULT CImpISupportErrorInfo::AddInterfaceID(REFIID riid)
  47. {
  48. HRESULT hr = S_OK;
  49. if(m_rgpErrInt == NULL)
  50. {
  51. m_rgpErrInt = new GUID*[ERROR_GUID_ARRAYSIZE];
  52. if(m_rgpErrInt)
  53. {
  54. m_cAllocGuid = ERROR_GUID_ARRAYSIZE;
  55. }
  56. else
  57. {
  58. hr = E_OUTOFMEMORY;
  59. }
  60. }
  61. else
  62. if(m_cpErrInt >= m_cAllocGuid)
  63. {
  64. GUID **pTemp = m_rgpErrInt;
  65. m_rgpErrInt = NULL;
  66. m_rgpErrInt = new GUID*[m_cAllocGuid + ERROR_GUID_ARRAYSIZE];
  67. if(m_rgpErrInt)
  68. {
  69. memset(m_rgpErrInt ,0, (m_cAllocGuid + ERROR_GUID_ARRAYSIZE) * sizeof(GUID*));
  70. memcpy(m_rgpErrInt ,pTemp, m_cAllocGuid * sizeof(GUID*));
  71. m_cAllocGuid += ERROR_GUID_ARRAYSIZE;
  72. SAFE_DELETE_ARRAY(pTemp);
  73. }
  74. else
  75. {
  76. m_rgpErrInt = pTemp;
  77. hr = E_OUTOFMEMORY;
  78. }
  79. }
  80. if(m_rgpErrInt && SUCCEEDED(hr))
  81. {
  82. m_rgpErrInt[m_cpErrInt++] = (GUID *)&riid;
  83. hr = S_OK;
  84. }
  85. return hr;
  86. }
  87. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  88. //
  89. // Indicates whether a OLE DB Interface can return OLE DB error objects
  90. //
  91. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  92. STDMETHODIMP CImpISupportErrorInfo::InterfaceSupportsErrorInfo( REFIID riid )
  93. {
  94. ULONG ul;
  95. HRESULT hr = S_FALSE;
  96. //==========================================================================
  97. // See if the interface asked about, actually creates an error object.
  98. //==========================================================================
  99. for(ul=0; ul<m_cpErrInt; ul++){
  100. if ( (*(m_rgpErrInt[ul])) == riid )
  101. {
  102. hr = S_OK;
  103. break;
  104. }
  105. }
  106. return hr;
  107. }
  108. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  109. //
  110. // Constructor for this class
  111. //
  112. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  113. #pragma warning (disable:4355)
  114. CErrorLookup::CErrorLookup( LPUNKNOWN pUnkOuter ) : m_IErrorLookup(this), CBaseObj(BOT_ERROR,pUnkOuter)
  115. {
  116. }
  117. #pragma warning (default:4355)
  118. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  119. //
  120. // Returns a pointer to a specified interface. Callers use QueryInterface to determine which interfaces
  121. // the called object supports.
  122. //
  123. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  124. STDMETHODIMP CErrorLookup::QueryInterface( REFIID riid, LPVOID * ppv)
  125. {
  126. if ( ppv == NULL )
  127. return E_INVALIDARG;
  128. //=========================================================
  129. // This is the non-delegating IUnknown implementation
  130. //=========================================================
  131. if ( riid == IID_IUnknown )
  132. *ppv = (LPVOID)this;
  133. else if ( riid == IID_IErrorLookup )
  134. *ppv = (LPVOID)&m_IErrorLookup;
  135. else{
  136. *ppv = NULL;
  137. return E_NOINTERFACE;
  138. }
  139. ((LPUNKNOWN)*ppv)->AddRef();
  140. return S_OK;
  141. }
  142. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  143. //
  144. // Increments a persistence count for the object
  145. //
  146. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  147. STDMETHODIMP_(ULONG) CErrorLookup::AddRef(void)
  148. {
  149. ULONG cRef = InterlockedIncrement( (long*) &m_cRef);
  150. return cRef;
  151. }
  152. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  153. //
  154. // Decrements a persistence count for the object and if persistence count is 0, the object destroys
  155. // itself.
  156. //
  157. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  158. STDMETHODIMP_(ULONG) CErrorLookup::Release (void)
  159. {
  160. ULONG cRef = InterlockedDecrement( (long*) &m_cRef);
  161. if ( !cRef ){
  162. delete this;
  163. return 0;
  164. }
  165. return cRef;
  166. }
  167. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  168. //
  169. // Increments a reference count for the object.
  170. //
  171. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  172. STDMETHODIMP_(ULONG) CImpIErrorLookup::AddRef(void)
  173. {
  174. InterlockedIncrement((long*)&m_cRef);
  175. return m_pCErrorLookup->AddRef();
  176. }
  177. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  178. //
  179. // Decrement the object's reference count and deletes the object when the new reference count is zero.
  180. //
  181. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  182. STDMETHODIMP_(ULONG) CImpIErrorLookup::Release(void)
  183. {
  184. InterlockedDecrement((long*)&m_cRef);
  185. return m_pCErrorLookup->Release();
  186. }
  187. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  188. //
  189. // Returns a pointer to a specified interface. Callers use QueryInterface to determine which interfaces
  190. // the called object supports.
  191. //
  192. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  193. STDMETHODIMP CImpIErrorLookup::QueryInterface( REFIID riid, LPVOID * ppv)
  194. {
  195. return m_pCErrorLookup->QueryInterface(riid, ppv);
  196. }
  197. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  198. //
  199. // Retrieve the error message and source based on the HRESULT and the provider specific error number
  200. //
  201. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  202. STDMETHODIMP CImpIErrorLookup::GetErrorDescription( HRESULT hrError,
  203. DWORD dwLookupId,
  204. DISPPARAMS* pdispparams,
  205. LCID lcid,
  206. BSTR* ppwszSource,
  207. BSTR* ppwszDescription )
  208. {
  209. HRESULT hr = NOERROR;
  210. int cchBuffer;
  211. // NTRaid : 111781
  212. // 06/13/00
  213. WCHAR wszBuffer[ERROR_DESCRIPTION_SIZE];
  214. //=========================================================
  215. // Check the Arguments
  216. //=========================================================
  217. if ( !ppwszSource || !ppwszDescription )
  218. {
  219. hr = E_INVALIDARG;
  220. }
  221. else
  222. {
  223. //=========================================================
  224. // Initialize return values
  225. //=========================================================
  226. *ppwszSource = NULL;
  227. *ppwszDescription = NULL;
  228. // Check the Locale
  229. // if ( lcid != GetSystemDefaultLCID() )
  230. // return DB_E_NOLOCALE;
  231. wcscpy(wszBuffer,L"");
  232. WMIOledb_LoadStringW(IDS_WMIOLEDBDES,wszBuffer,ERROR_DESCRIPTION_SIZE);
  233. //=========================================================
  234. // Store source name
  235. //=========================================================
  236. *ppwszSource = Wmioledb_SysAllocString(wszBuffer);
  237. if ( *ppwszSource == NULL )
  238. {
  239. hr = E_OUTOFMEMORY;
  240. }
  241. else
  242. //=========================================================
  243. // If the lookup id was to be looked up in the resource dll
  244. // of the error collection, make sure we just return NULL
  245. // for the error description.
  246. //=========================================================
  247. if ( (dwLookupId &= ~IDENTIFIER_SDK_MASK) == 0 )
  248. {
  249. hr = S_OK;
  250. }
  251. else
  252. //=========================================================
  253. // After this point make sure to exit to goto
  254. // the FAILED(hr) code or drop through to the return hr,
  255. // as to make sure memory is freed if need be.
  256. // Determine if it is a static or dynamic string
  257. //=========================================================
  258. if ( dwLookupId & ERR_STATIC_STRING )
  259. {
  260. wcscpy(wszBuffer,L"");
  261. // NTRaid : 111781
  262. // 06/13/00
  263. // cchBuffer = LoadStringW(g_hInstance, (UINT)(dwLookupId & ~(ERR_STATIC_STRING)), wszBuffer,ERROR_DESCRIPTION_SIZE);
  264. cchBuffer = WMIOledb_LoadStringW( (UINT)(dwLookupId & ~(ERR_STATIC_STRING)), wszBuffer,ERROR_DESCRIPTION_SIZE);
  265. //=====================================================
  266. // Convert to a BSTR
  267. //=====================================================
  268. if (cchBuffer)
  269. {
  270. *ppwszDescription = Wmioledb_SysAllocString(wszBuffer);
  271. if ( *ppwszDescription == NULL )
  272. {
  273. hr = E_OUTOFMEMORY;
  274. }
  275. }
  276. }
  277. else
  278. {
  279. hr = g_pCError->GetErrorDescription(dwLookupId, ppwszDescription);
  280. }
  281. if ( FAILED(hr) )
  282. {
  283. //=====================================================
  284. // If allocation done, make sure that it is freed
  285. //=====================================================
  286. if ( ppwszSource )
  287. {
  288. SysFreeString(*ppwszSource);
  289. *ppwszSource = NULL;
  290. }
  291. if ( ppwszDescription )
  292. {
  293. SysFreeString(*ppwszDescription);
  294. *ppwszDescription = NULL;
  295. }
  296. }
  297. } // else for if(check valid parameters)
  298. return hr;
  299. }
  300. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  301. //
  302. // Retrieve the error message and source based on the HRESULT and the provider specific error number
  303. //
  304. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  305. STDMETHODIMP CImpIErrorLookup::GetHelpInfo( HRESULT hrError,DWORD dwLookupId, LCID lcid,
  306. BSTR* ppwszHelpFile, DWORD* pdwHelpContext )
  307. {
  308. HRESULT hr = S_OK;
  309. //=====================================================
  310. // Check the Arguments
  311. //=====================================================
  312. if ( !ppwszHelpFile || !pdwHelpContext )
  313. {
  314. hr = E_INVALIDARG;
  315. }
  316. else
  317. {
  318. //=====================================================
  319. // Initialize return values
  320. //=====================================================
  321. *ppwszHelpFile = NULL;
  322. *pdwHelpContext = 0;
  323. //=====================================================
  324. // Check the Locale
  325. //=====================================================
  326. if ( lcid != GetSystemDefaultLCID() )
  327. {
  328. hr = DB_E_NOLOCALE;
  329. }
  330. }
  331. //=====================================================
  332. // We currently can't return any help file context or
  333. // names. So, we will just return S_OK.
  334. //=====================================================
  335. return hr;
  336. }
  337. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  338. //
  339. // Method to be called to release non static error messages.
  340. //
  341. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  342. STDMETHODIMP CImpIErrorLookup::ReleaseErrors( const DWORD dwDynamicErrorID )
  343. {
  344. HRESULT hr = S_OK;
  345. //=====================================================
  346. // Check the Arguments
  347. //=====================================================
  348. if ( dwDynamicErrorID == 0 )
  349. {
  350. hr = E_INVALIDARG;
  351. }
  352. else
  353. {
  354. g_pCError->RemoveErrors(dwDynamicErrorID);
  355. }
  356. return hr;
  357. }
  358. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  359. //
  360. // Constructor for this class
  361. //
  362. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  363. #pragma warning (disable:4355)
  364. CImpIWMIErrorInfo::CImpIWMIErrorInfo( PERRORSTUFF pErrStuff )
  365. {
  366. //=====================================================
  367. // Initialize simple member vars
  368. //=====================================================
  369. m_cRef = 0L;
  370. m_hObjCollection = ULONG(-1);
  371. //=====================================================
  372. // Store values
  373. //=====================================================
  374. m_pErrStuff = pErrStuff;
  375. //=====================================================
  376. // Since the memory is created and owned by WMIoledb,
  377. // we need to make sure that this DLL is not unloaded,
  378. // else we will clean up the handed out pointer
  379. //=====================================================
  380. InterlockedIncrement(&g_cObj);
  381. }
  382. #pragma warning (default:4355)
  383. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  384. //
  385. // Destructor for this class
  386. //
  387. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  388. CImpIWMIErrorInfo::~CImpIWMIErrorInfo (void)
  389. {
  390. //=====================================================
  391. // For Abnormal Termination,Remove self from Collection
  392. //=====================================================
  393. g_pCError->RemoveFromCollection(m_hObjCollection);
  394. //=====================================================
  395. // If this object has been released, we can now
  396. // decrement our object count
  397. //=====================================================
  398. InterlockedDecrement(&g_cObj);
  399. }
  400. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  401. //
  402. // Returns a pointer to a specified interface. Callers use QueryInterface to determine which interfaces
  403. // the called object supports.
  404. //
  405. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  406. STDMETHODIMP CImpIWMIErrorInfo::QueryInterface( REFIID riid, LPVOID * ppv)
  407. {
  408. HRESULT hr = E_NOINTERFACE;
  409. if ( ppv == NULL ){
  410. hr = E_INVALIDARG;
  411. }
  412. else
  413. //=====================================================
  414. // This is the non-delegating IUnknown implementation
  415. //=====================================================
  416. if ( (riid == IID_IUnknown) || (riid == IID_IErrorInfo) ){
  417. *ppv = (LPVOID)this;
  418. }
  419. else{
  420. *ppv = NULL;
  421. }
  422. //=====================================================
  423. // If we're going to return an interface, AddRef first
  424. //=====================================================
  425. if (*ppv){
  426. ((LPUNKNOWN)*ppv)->AddRef();
  427. hr = S_OK;
  428. }
  429. return hr;
  430. }
  431. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  432. //
  433. // Increments a persistence count for the object
  434. //
  435. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  436. STDMETHODIMP_(ULONG) CImpIWMIErrorInfo::AddRef(void)
  437. {
  438. ULONG cRef = InterlockedIncrement( (long*) &m_cRef);
  439. return cRef;
  440. }
  441. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  442. //
  443. // Decrements a persistence count for the object and if persistence count is 0,object destroys itself.
  444. //
  445. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  446. STDMETHODIMP_(ULONG) CImpIWMIErrorInfo::Release (void)
  447. {
  448. ULONG cRef = InterlockedDecrement( (long*) &m_cRef);
  449. if ( !cRef ){
  450. delete this;
  451. return 0;
  452. }
  453. return cRef;
  454. }
  455. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  456. //
  457. // Return the WMIstate associated with this custom error object.
  458. //
  459. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  460. STDMETHODIMP CImpIWMIErrorInfo::GetWMIInfo( BSTR* pbstrMsg, LONG* plNativeError )
  461. {
  462. HRESULT hr = S_OK;
  463. //=====================================================
  464. // Check arguments
  465. //=====================================================
  466. if ( !pbstrMsg || !plNativeError)
  467. {
  468. hr = E_INVALIDARG;
  469. }
  470. else
  471. {
  472. //=====================================================
  473. // Initialize return values
  474. //=====================================================
  475. *pbstrMsg = Wmioledb_SysAllocString(NULL);
  476. *plNativeError = 0;
  477. //=====================================================
  478. // Handle WMIState
  479. //=====================================================
  480. if ( wcslen(m_pErrStuff->pwszMessage) > 0 )
  481. {
  482. //=================================================
  483. // If string is not NULL,then we can allocate it
  484. //=================================================
  485. *pbstrMsg = Wmioledb_SysAllocString(m_pErrStuff->pwszMessage);
  486. if ( *pbstrMsg == NULL )
  487. {
  488. hr = E_OUTOFMEMORY;
  489. }
  490. }
  491. //=====================================================
  492. // Handle Native Error Code.
  493. //=====================================================
  494. *plNativeError = m_pErrStuff->lNative;
  495. }
  496. return hr;
  497. }
  498. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  499. CError::CError( )
  500. {
  501. //=====================================================
  502. // Note that this is NOT a first-class object: it is
  503. // NOT given away outside this DLL. So we do not want
  504. // to alter global object count.
  505. //=====================================================
  506. // Clear variables
  507. m_pWMIErrorInfoCollection = NULL;
  508. m_prgErrorDex = NULL;
  509. m_cErrorsUsed = 0;
  510. m_dwId = 0;
  511. m_ulNext = 1;
  512. //=====================================================
  513. // Initialize ErrorInfo with constant information
  514. //=====================================================
  515. m_ErrorInfo.clsid = CLSID_WMIOLEDB;
  516. m_ErrorInfo.dispid = NULL;
  517. m_pcsErrors = new CCriticalSection(TRUE);
  518. }
  519. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  520. CError::~CError()
  521. {
  522. ULONG iElems;
  523. ULONG cElems;
  524. ULONG ul;
  525. PIMPIWMIERRORINFO pIWMIErrorInfo;
  526. m_pcsErrors->Enter();
  527. //=====================================================
  528. // Release the general Object
  529. //=====================================================
  530. if ( m_pWMIErrorInfoCollection ){
  531. cElems = m_pWMIErrorInfoCollection->Size();
  532. //=================================================
  533. // Loop through stored object handles and release.
  534. //=================================================
  535. for(iElems=0; iElems<cElems; iElems++){
  536. pIWMIErrorInfo = (PIMPIWMIERRORINFO )m_pWMIErrorInfoCollection->GetAt(iElems);
  537. if ( pIWMIErrorInfo != NULL )
  538. {
  539. delete pIWMIErrorInfo;
  540. }
  541. }
  542. delete m_pWMIErrorInfoCollection;
  543. }
  544. //=====================================================
  545. // Cleanup and error information hanging off the
  546. // pointer array
  547. //=====================================================
  548. if ( m_prgErrorDex ){
  549. for(ul=0; ul<m_cErrors; ul++){
  550. if ( m_prgErrorDex[ul] ){
  551. delete[] m_prgErrorDex[ul];
  552. m_prgErrorDex[ul] = NULL;
  553. }
  554. }
  555. delete[] m_prgErrorDex;
  556. }
  557. m_pcsErrors->Leave();
  558. SAFE_DELETE_PTR(m_pcsErrors);
  559. }
  560. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  561. //
  562. // If this initialization routine fails, it is the callers responsibility to delete this object.
  563. // The destructor will then clean up any allocated resources
  564. //
  565. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  566. HRESULT CError::FInit()
  567. {
  568. HRESULT hr = S_OK;
  569. //=============================================================
  570. // Create array of pointers into the heap
  571. //=============================================================
  572. m_prgErrorDex = new PERRORSTUFF[INITIAL_SIZE_FOR_ERRORSTUFF];
  573. if ( NULL == m_prgErrorDex )
  574. {
  575. hr = E_OUTOFMEMORY;
  576. }
  577. else
  578. {
  579. m_cErrors = INITIAL_SIZE_FOR_ERRORSTUFF;
  580. memset(m_prgErrorDex, 0, INITIAL_SIZE_FOR_ERRORSTUFF * sizeof(PERRORSTUFF));
  581. //=============================================================
  582. // Create WMI Error Object Collection
  583. //=============================================================
  584. m_pWMIErrorInfoCollection = new CFlexArray;
  585. if ( NULL == m_pWMIErrorInfoCollection )
  586. {
  587. hr = E_OUTOFMEMORY;
  588. }
  589. }
  590. return hr;
  591. }
  592. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  593. //
  594. // Remove the Error Information for a particular DynamicId. This could be one or more elements of the
  595. // ERRORSTUFF array and their associated pwszMessages on the Heap.
  596. //
  597. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  598. void CError::RemoveErrors( DWORD dwDynamicId )
  599. {
  600. ULONG ul;
  601. //=============================================================
  602. // At the creation of the CAutoBlock object a critical section
  603. // is entered. This is because the method manipulates shared
  604. // structures access to which must be serialized .
  605. // The criticalsection is left when this method terminate
  606. // and the destructor for CAutoBlock is called.
  607. //=============================================================
  608. CAutoBlock Crit(m_pcsErrors);
  609. for(ul=0; ul<m_cErrors; ul++){
  610. if ( m_prgErrorDex[ul] && m_prgErrorDex[ul]->dwDynamicId == dwDynamicId ){
  611. delete[] m_prgErrorDex[ul];
  612. m_prgErrorDex[ul] = NULL;
  613. m_cErrorsUsed--;
  614. //=====================================================
  615. // For each error description that we cache, we have
  616. // up'd the object count to make sure that we stay
  617. // alive while there is a possibility the error
  618. // collection could call back into us for this desc.
  619. // Here is where we decrement that count upon
  620. // release of the error message.
  621. //=====================================================
  622. InterlockedDecrement(&g_cObj);
  623. }
  624. }
  625. }
  626. ////////////////////////////////////////////////////////////////////////////////////////////
  627. //
  628. // Retrieve the WMI Server Error Message from the cache
  629. //
  630. ////////////////////////////////////////////////////////////////////////////////////////////
  631. HRESULT CError::GetErrorDescription(ULONG ulDex, BSTR* ppwszDescription )
  632. {
  633. HRESULT hr = S_OK;
  634. //======================================================
  635. // Enter critical section
  636. //======================================================
  637. CAutoBlock Crit(m_pcsErrors);
  638. //======================================================
  639. //
  640. //======================================================
  641. if (ulDex < m_cErrors && m_prgErrorDex[ulDex]){
  642. PERRORSTUFF pErrorStuff = m_prgErrorDex[ulDex];
  643. if (wcslen(pErrorStuff->pwszMessage) > 0 ){
  644. //======================================================
  645. // return the message from WMI
  646. //======================================================
  647. *ppwszDescription = Wmioledb_SysAllocString(pErrorStuff->pwszMessage);
  648. if (*ppwszDescription == NULL){
  649. hr = E_OUTOFMEMORY;
  650. }
  651. }
  652. else{
  653. //======================================================
  654. // return the standard error
  655. //======================================================
  656. WCHAR rgwchBuff[MAX_PATH+1];
  657. WCHAR *pwsz = rgwchBuff;
  658. int cwch = LoadStringW(g_hInstance, pErrorStuff->uStringId, rgwchBuff, NUMELEM(rgwchBuff));
  659. *ppwszDescription = Wmioledb_SysAllocString(pwsz);
  660. if (*ppwszDescription == NULL){
  661. hr = E_OUTOFMEMORY;
  662. }
  663. }
  664. }
  665. else{
  666. *ppwszDescription = NULL;
  667. hr = DB_E_BADLOOKUPID;
  668. }
  669. return hr;
  670. }
  671. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  672. //
  673. // Retrieve the IErrorInfo and IErrorRecords pointers whether from automation or from creating a new
  674. // instance
  675. //
  676. ///////////////////////////////////////////////////////////////////////////////////////////////////////
  677. HRESULT CError::GetErrorInterfaces( IErrorInfo** ppIErrorInfo, IErrorRecords** ppIErrorRecords )
  678. {
  679. HRESULT hr = S_OK;
  680. *ppIErrorInfo = NULL;
  681. *ppIErrorRecords = NULL;
  682. //=============================================================
  683. //Obtain the error object or create a new one if none exists
  684. //=============================================================
  685. // NTRaid:111806
  686. // 06/07/00
  687. hr = GetErrorInfo(0, ppIErrorInfo);
  688. if (SUCCEEDED(hr) && !*ppIErrorInfo){
  689. hr = g_pErrClassFact->CreateInstance(NULL, IID_IErrorInfo, (LPVOID*)ppIErrorInfo);
  690. }
  691. if(SUCCEEDED(hr))
  692. {
  693. //=============================================================
  694. // Obtain the IErrorRecord Interface
  695. //=============================================================
  696. hr = (*ppIErrorInfo)->QueryInterface(IID_IErrorRecords, (LPVOID*)ppIErrorRecords);
  697. //=============================================================
  698. // On a failure retrieving IErrorRecords, we need to release
  699. // the IErrorInfo interface
  700. //=============================================================
  701. if ( FAILED(hr) ){
  702. (*ppIErrorInfo)->Release();
  703. *ppIErrorInfo = NULL;
  704. }
  705. }
  706. return hr;
  707. }
  708. /////////////////////////////////////////////////////////////////////////////////////////////////////////
  709. //
  710. // Determine the next free index of the PERRORSTUFF array.
  711. //
  712. /////////////////////////////////////////////////////////////////////////////////////////////////////////
  713. HRESULT CError::FindFreeDex( ULONG* ulDex )
  714. {
  715. PERRORSTUFF* pNew = NULL;
  716. HRESULT hr = S_OK;
  717. //===========================================================================
  718. // Check if we need to expand the buffer
  719. // Since we do not use element 0, we need to reallocate when at m_cErrors - 1
  720. //===========================================================================
  721. if ( m_cErrorsUsed == (m_cErrors - 1))
  722. {
  723. try
  724. {
  725. pNew = new PERRORSTUFF[m_cErrors + INCREMENT_BY_FOR_ERRORSTUFF];
  726. }
  727. catch(...)
  728. {
  729. SAFE_DELETE_PTR(pNew);
  730. throw;
  731. }
  732. if ( pNew )
  733. {
  734. //===================================================================
  735. // Copy old pointers to new array
  736. //===================================================================
  737. memcpy(pNew, m_prgErrorDex, m_cErrors * sizeof(PERRORSTUFF));
  738. memset((pNew + m_cErrors), 0, INCREMENT_BY_FOR_ERRORSTUFF * sizeof(PERRORSTUFF));
  739. //===================================================================
  740. // Set the new array size
  741. //===================================================================
  742. m_ulNext = m_cErrors;
  743. m_cErrors += INCREMENT_BY_FOR_ERRORSTUFF;
  744. delete[] m_prgErrorDex;
  745. m_prgErrorDex = pNew;
  746. }
  747. else
  748. {
  749. *ulDex = 0;
  750. hr = E_OUTOFMEMORY;
  751. }
  752. }
  753. if(SUCCEEDED(hr))
  754. {
  755. //===========================================================================
  756. // Loop through looking for unused index
  757. //===========================================================================
  758. while( 1 ){
  759. //=======================================================================
  760. // If we are at the top of our buffer rap back to the begining
  761. //=======================================================================
  762. if (m_ulNext == m_cErrors)
  763. {
  764. m_ulNext = 1;
  765. }
  766. else if (NULL == m_prgErrorDex[m_ulNext])
  767. {
  768. m_cErrorsUsed++;
  769. *ulDex = m_ulNext++;
  770. break;
  771. }
  772. else
  773. {
  774. m_ulNext++;
  775. }
  776. }
  777. }
  778. return hr;
  779. }
  780. ////////////////////////////////////////////////////////////////////////////////////////////////////
  781. //
  782. // Creates error records for the WMI errors encountered. The WMIState and Native error code are
  783. // stored in a custom interface, where as the description is returned by the standard IErrorInfo
  784. // interface.
  785. //
  786. ////////////////////////////////////////////////////////////////////////////////////////////////////
  787. HRESULT CError::PostWMIErrors( HRESULT hrErr, const IID* piid, CErrorData* pErrData )
  788. {
  789. HRESULT hr = S_OK;
  790. IErrorInfo* pIErrorInfo = NULL;
  791. IErrorRecords* pIErrorRecords = NULL;
  792. PIMPIWMIERRORINFO pWMIError = NULL;
  793. ULONG iElems;
  794. ULONG cElems;
  795. PERRORSTUFF pErrStuff;
  796. DWORD dwDex;
  797. //===========================================================================
  798. // Enter critical section
  799. //===========================================================================
  800. CAutoBlock Crit(m_pcsErrors);
  801. //===========================================================================
  802. // We cannot Init the Datasource object without this pointer being set, so it
  803. // should exist at this point
  804. // Get the # errors
  805. //===========================================================================
  806. cElems = pErrData->Size();
  807. if (0 == cElems){
  808. if (FAILED(hrErr))
  809. g_pCError->PostHResult(hrErr, piid);
  810. hr = S_OK;
  811. }
  812. else{
  813. //=======================================================================
  814. // Obtain the error object or create a new one if none exists
  815. //=======================================================================
  816. if ( SUCCEEDED(hr = GetErrorInterfaces(&pIErrorInfo, &pIErrorRecords)) ){
  817. //===================================================================
  818. // Assign static information across each error record added
  819. //===================================================================
  820. m_ErrorInfo.hrError = hrErr;
  821. m_ErrorInfo.iid = *piid;
  822. m_ErrorInfo.dispid = NULL;
  823. //===================================================================
  824. // Increment Dynamic Id;
  825. //===================================================================
  826. m_dwId++;
  827. //===================================================================
  828. // Loop through an array of indexes into the error array
  829. //===================================================================
  830. for (iElems=0; iElems<cElems; iElems++){
  831. //===============================================================
  832. // Get the error stuff
  833. //===============================================================
  834. pErrData->SetAt(iElems,(void**)&pErrStuff);
  835. //===============================================================
  836. // Save the dynamic id
  837. //===============================================================
  838. pErrStuff->dwDynamicId = m_dwId;
  839. //===============================================================
  840. // Save WMI Server error code
  841. //===============================================================
  842. m_ErrorInfo.dwMinor = DWORD(pErrStuff->lNative);
  843. //===============================================================
  844. // Determine index to store heap pointer
  845. //===============================================================
  846. if ( SUCCEEDED(hr = FindFreeDex(&dwDex)) ){
  847. try
  848. {
  849. //===========================================================
  850. // Create the custom error object
  851. //===========================================================
  852. pWMIError = new CImpIWMIErrorInfo(pErrStuff);
  853. }
  854. catch(...)
  855. {
  856. SAFE_DELETE_PTR(pWMIError);
  857. throw;
  858. }
  859. if ( pWMIError == NULL ){
  860. hr = E_OUTOFMEMORY;
  861. }
  862. else{
  863. pWMIError->AddRef();
  864. if ( SUCCEEDED(hr = pWMIError->FInit()) ){
  865. //===================================================
  866. // Add the record to the Error Service Object
  867. //===================================================
  868. hr = pIErrorRecords->AddErrorRecord(&m_ErrorInfo, dwDex, NULL,(IUnknown*) pWMIError, m_dwId);
  869. if ( SUCCEEDED(hr) ){
  870. //===============================================
  871. // Release the custom Error Object
  872. //===============================================
  873. pWMIError->Release();
  874. pWMIError = NULL;
  875. //===============================================
  876. // Save the pointer to the error stuff
  877. //===============================================
  878. m_prgErrorDex[dwDex] = pErrStuff;
  879. //===============================================
  880. // For each error description that we cache, we
  881. // have up'd the the object count to make sure
  882. // that we stay alive while there is a
  883. // possibility the errorcollection could call back
  884. // into us for this description. Here is where we
  885. // increment that count.
  886. //===============================================
  887. InterlockedIncrement(&g_cObj);
  888. }
  889. }
  890. }
  891. }
  892. //================================================================
  893. // Pass the error object to the Ole Automation DLL
  894. //================================================================
  895. hr = SetErrorInfo(0, pIErrorInfo);
  896. }
  897. }
  898. }
  899. //============================================================================
  900. // Release the interfaces to transfer ownership to the Ole Automation DLL
  901. //============================================================================
  902. SAFE_RELEASE_PTR(pWMIError);
  903. SAFE_RELEASE_PTR(pIErrorRecords);
  904. SAFE_RELEASE_PTR(pIErrorInfo);
  905. //============================================================================
  906. // Free the error data
  907. //============================================================================
  908. pErrData->FreeErrors();
  909. return hr;
  910. }
  911. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  912. //
  913. // This method is used to post an HRESULT that is to be looked up in the resource fork of the error collection
  914. // object.
  915. //
  916. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  917. HRESULT CError::PostHResult( HRESULT hrErr, const IID* piid )
  918. {
  919. HRESULT hr = S_OK;
  920. IErrorInfo* pIErrorInfo = NULL;
  921. IErrorRecords* pIErrorRecords = NULL;
  922. //==================================================================
  923. // Enter critical section
  924. //==================================================================
  925. CAutoBlock Crit(m_pcsErrors);
  926. //==================================================================
  927. // Obtain the error object or create a new one if none exists
  928. //==================================================================
  929. if ( SUCCEEDED(hr = GetErrorInterfaces(&pIErrorInfo, &pIErrorRecords)) )
  930. {
  931. //==================================================================
  932. // Assign static information across each error record added
  933. //==================================================================
  934. m_ErrorInfo.hrError = hrErr;
  935. m_ErrorInfo.iid = *piid;
  936. m_ErrorInfo.dispid = NULL;
  937. m_ErrorInfo.dwMinor = 0;
  938. //==================================================================
  939. // Add the record to the Error Service Object
  940. //==================================================================
  941. hr = pIErrorRecords->AddErrorRecord(&m_ErrorInfo,IDENTIFIER_SDK_ERROR,NULL,(IUnknown*)NULL,0);
  942. if ( SUCCEEDED(hr) )
  943. {
  944. //==================================================================
  945. // Pass the error object to the Ole Automation DLL
  946. //==================================================================
  947. hr = SetErrorInfo(0, pIErrorInfo);
  948. }
  949. }
  950. //==================================================================
  951. // Release the interfaces to transfer ownership to the Ole Automation DLL
  952. //==================================================================
  953. SAFE_RELEASE_PTR(pIErrorRecords);
  954. SAFE_RELEASE_PTR(pIErrorInfo);
  955. return hrErr;
  956. }
  957. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  958. //
  959. // This method is used to post static strings to the error objects. The static strings are stored in the
  960. // resource fork, and thus an id needs to be specified.
  961. //
  962. // @devnote If the error object is not our implementation of IID_IErrorInfo, we will not be able to load
  963. // IErrorRecord and add our records.
  964. //
  965. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  966. HRESULT CError::PostError( HRESULT hrErr, const IID* piid, DWORD dwIds, DISPPARAMS* pdispparams )
  967. {
  968. HRESULT hr = S_OK;
  969. IErrorInfo* pIErrorInfo = NULL;
  970. IErrorRecords* pIErrorRecords = NULL;
  971. //====================================================================
  972. // Enter critical section
  973. //====================================================================
  974. CAutoBlock Crit(m_pcsErrors);
  975. //====================================================================
  976. // Obtain the error object or create a new one if none exists
  977. //====================================================================
  978. if ( SUCCEEDED(hr = GetErrorInterfaces(&pIErrorInfo, &pIErrorRecords)) )
  979. {
  980. //====================================================================
  981. // Assign static information across each error record added
  982. //====================================================================
  983. m_ErrorInfo.hrError = hrErr;
  984. m_ErrorInfo.iid = *piid;
  985. m_ErrorInfo.dispid = NULL;
  986. m_ErrorInfo.dwMinor = 0;
  987. //====================================================================
  988. // Add the record to the Error Service Object
  989. //====================================================================
  990. hr = pIErrorRecords->AddErrorRecord(&m_ErrorInfo, (dwIds | ERR_STATIC_STRING), pdispparams, NULL, 0);
  991. if ( SUCCEEDED(hr) )
  992. {
  993. //====================================================================
  994. // Pass the error object to the Ole Automation DLL
  995. //====================================================================
  996. hr = SetErrorInfo(0, pIErrorInfo);
  997. }
  998. }
  999. //====================================================================
  1000. // Release the interfaces to transfer ownership to the Ole Automation DLL
  1001. //====================================================================
  1002. SAFE_RELEASE_PTR(pIErrorRecords);
  1003. SAFE_RELEASE_PTR(pIErrorInfo);
  1004. return hr;
  1005. }
  1006. ////////////////////////////////////////////////////////////////////////////////////////////////
  1007. //
  1008. // This method is used to post static strings to the error objects.
  1009. //
  1010. ////////////////////////////////////////////////////////////////////////////////////////////////
  1011. HRESULT CError::PostErrorMessage( HRESULT hrErr, const IID* piid, UINT uStringId, LPCWSTR pwszMessage )
  1012. {
  1013. PERRORSTUFF pErrStuff = NULL;
  1014. ULONG cwch = wcslen(pwszMessage);
  1015. HRESULT hr = S_OK;
  1016. IErrorInfo* pIErrorInfo = NULL;
  1017. IErrorRecords* pIErrorRecords = NULL;
  1018. PIMPIWMIERRORINFO pWMIError = NULL;
  1019. DWORD dwDex;
  1020. //==========================================================
  1021. // CS because the method manipulates shared structures
  1022. // access to which must be serialized .
  1023. //==========================================================
  1024. CAutoBlock Crit(m_pcsErrors);
  1025. try
  1026. {
  1027. pErrStuff = (PERRORSTUFF) new BYTE[sizeof(ERRORSTUFF)+(cwch+2)*sizeof(WCHAR)];
  1028. }
  1029. catch(...)
  1030. {
  1031. SAFE_DELETE_ARRAY(pErrStuff);
  1032. throw;
  1033. }
  1034. if (!pErrStuff) {
  1035. hr = E_OUTOFMEMORY;
  1036. }
  1037. else
  1038. {
  1039. //==========================================================
  1040. // Initialize error stuff
  1041. //==========================================================
  1042. pErrStuff->dwDynamicId = 0;
  1043. pErrStuff->uStringId = uStringId;
  1044. pErrStuff->hr = S_OK;
  1045. pErrStuff->lNative = 0;
  1046. pErrStuff->wLineNumber = 0;
  1047. AllocateAndCopy(pErrStuff->pwszMessage, (unsigned short*)pwszMessage);
  1048. //==========================================================
  1049. // We cannot Init the Datasource object without this pointer
  1050. // being set, so it should exist at this point
  1051. // Obtain the error object or create new one if none exists
  1052. //==========================================================
  1053. if ( SUCCEEDED(hr = GetErrorInterfaces(&pIErrorInfo, &pIErrorRecords)) )
  1054. {
  1055. //==========================================================
  1056. // Assign static information across each error record added
  1057. //==========================================================
  1058. m_ErrorInfo.hrError = hrErr;
  1059. m_ErrorInfo.iid = *piid;
  1060. m_ErrorInfo.dispid = NULL;
  1061. m_ErrorInfo.dwMinor = 0;
  1062. //==========================================================
  1063. // Increment Dynamic Id and save it
  1064. //==========================================================
  1065. pErrStuff->dwDynamicId = ++m_dwId;
  1066. //==========================================================
  1067. // Determine index to store heap pointer
  1068. //==========================================================
  1069. if ( SUCCEEDED(hr = FindFreeDex(&dwDex)) )
  1070. {
  1071. try
  1072. {
  1073. //==========================================================
  1074. // Create the custom error object
  1075. //==========================================================
  1076. pWMIError = new CImpIWMIErrorInfo(pErrStuff);
  1077. }
  1078. catch(...)
  1079. {
  1080. SAFE_DELETE_ARRAY(pErrStuff);
  1081. SAFE_DELETE_PTR(pErrStuff);
  1082. throw;
  1083. }
  1084. if ( pWMIError == NULL ){
  1085. hr = E_OUTOFMEMORY;
  1086. }
  1087. else
  1088. {
  1089. //==========================================================
  1090. // Give the object existence
  1091. //==========================================================
  1092. pWMIError->AddRef();
  1093. if ( SUCCEEDED(hr = pWMIError->FInit()) )
  1094. {
  1095. //==========================================================
  1096. // Add the record to the Error Service Object
  1097. //==========================================================
  1098. if(SUCCEEDED(hr = pIErrorRecords->AddErrorRecord(&m_ErrorInfo, dwDex, NULL, (IUnknown*)pWMIError, m_dwId)))
  1099. {
  1100. //==========================================================
  1101. // Release the custom Error Object
  1102. //==========================================================
  1103. pWMIError->Release();
  1104. pWMIError = NULL;
  1105. //==========================================================
  1106. // Save the pointer to the error stuff
  1107. //==========================================================
  1108. m_prgErrorDex[dwDex] = pErrStuff;
  1109. //==========================================================
  1110. // For each error description that we cache, we have up'd the
  1111. // the object count to make sure that we stay alive while there is
  1112. // a possibility the errorcollection could call back into us for
  1113. // this description. Here is where we increment that count.
  1114. //==========================================================
  1115. InterlockedIncrement(&g_cObj);
  1116. //==========================================================
  1117. // Pass the error object to the Ole Automation DLL
  1118. //==========================================================
  1119. hr = SetErrorInfo(0, pIErrorInfo);
  1120. } // if Succeeded(AddErrorRecord(())
  1121. } // if (succeeded(pWMIError->FInit))
  1122. } // if allocation of pWMIError is successful
  1123. } // if(succeeded(FindFreeDex))
  1124. } // if succeeded(GetErrorInterfaces)
  1125. } // if propert allocation
  1126. //==========================================================
  1127. // Release the interfaces to transfer ownership to
  1128. //==========================================================
  1129. SAFE_DELETE_ARRAY(pErrStuff);
  1130. SAFE_DELETE_PTR(pErrStuff);
  1131. SAFE_RELEASE_PTR(pWMIError);
  1132. SAFE_RELEASE_PTR(pIErrorRecords);
  1133. SAFE_RELEASE_PTR(pIErrorInfo);
  1134. return hr;
  1135. }
  1136. ////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1137. //
  1138. // Frees error information and empties the array
  1139. //
  1140. ////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1141. void CError::FreeErrors()
  1142. {
  1143. ULONG iElems;
  1144. ULONG cElems;
  1145. BYTE* pb;
  1146. cElems = Size();
  1147. for (iElems=0; iElems<cElems; iElems++){
  1148. pb = (BYTE*) m_pWMIErrorInfoCollection->GetAt(iElems);
  1149. if (pb){
  1150. delete[] pb;
  1151. }
  1152. }
  1153. m_pWMIErrorInfoCollection->Empty();
  1154. }
  1155. //**********************************************************************************************************
  1156. //
  1157. //**********************************************************************************************************
  1158. ////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1159. CErrorData::CErrorData()
  1160. {
  1161. //
  1162. }
  1163. ////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1164. CErrorData::~CErrorData()
  1165. {
  1166. FreeErrors();
  1167. }
  1168. ////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1169. void CErrorData::FreeErrors()
  1170. {
  1171. }