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.

1143 lines
34 KiB

  1. //---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997 - 2000.
  5. //
  6. // File: DBERROR.CXX
  7. //
  8. // Contents: Ole DB Error implementation for CI
  9. //
  10. // History: 28-Apr-97 KrishnaN Created
  11. //
  12. //----------------------------------------------------------------------------
  13. #include <pch.cxx>
  14. #pragma hdrstop
  15. #include <mssql.h> // parser errors
  16. #include <parserr.h> // IDS_ values of parser errors (mc generated header)
  17. //#include <initguid.h>
  18. #define DBINITCONSTANTS
  19. #include <msdaguid.h>
  20. #define ERROR_MESSAGE_SIZE 512
  21. extern long gulcInstances;
  22. // Implementation of CCIOleDBError
  23. //+---------------------------------------------------------------------------
  24. //
  25. // Member: CCIOleDBError::CCIOleDBError, public
  26. //
  27. // Synopsis: Constructor. Gets the class factory for error object.
  28. //
  29. // Arguments: [rUnknown] - Controlling unknown.
  30. //
  31. // History: 28-Apr-97 KrishnaN Created
  32. //----------------------------------------------------------------------------
  33. //
  34. CCIOleDBError::CCIOleDBError ( IUnknown & rUnknown, CMutexSem & mutex ) :
  35. _mutex( mutex ),
  36. _rUnknown(rUnknown),
  37. _pErrClassFact (0)
  38. {
  39. }
  40. //+---------------------------------------------------------------------------
  41. //
  42. // Member: CCIOleDBError::~CCIOleDBError, public
  43. //
  44. // Synopsis: Releases class factory.
  45. //
  46. // Arguments:
  47. //
  48. // History: 05-May-97 KrishnaN Created
  49. //----------------------------------------------------------------------------
  50. CCIOleDBError::~CCIOleDBError()
  51. {
  52. if ( 0 != _pErrClassFact )
  53. _pErrClassFact->Release();
  54. }
  55. //+---------------------------------------------------------------------------
  56. //
  57. // Member: CCIOleDBError::QueryInterface, public
  58. //
  59. // Synopsis: Supports IID_IUnknown and IID_ISupportErrorInfo
  60. //
  61. // History: 28-Apr-97 KrishnaN Created
  62. //----------------------------------------------------------------------------
  63. STDMETHODIMP CCIOleDBError::QueryInterface(REFIID riid, void **ppvObject)
  64. {
  65. return _rUnknown.QueryInterface(riid, ppvObject);
  66. } //QueryInterface
  67. //+---------------------------------------------------------------------------
  68. //
  69. // Member: CCIOleDBError::AddRef, public
  70. //
  71. // History: 17-Mar-97 KrishnaN Created
  72. //
  73. //----------------------------------------------------------------------------
  74. STDMETHODIMP_(ULONG) CCIOleDBError::AddRef()
  75. {
  76. return _rUnknown.AddRef();
  77. } //AddRef
  78. //+---------------------------------------------------------------------------
  79. //
  80. // Member: CCIOleDBError::Release, public
  81. //
  82. // History: 17-Mar-97 KrishnaN Created
  83. //
  84. //----------------------------------------------------------------------------
  85. STDMETHODIMP_(ULONG) CCIOleDBError::Release()
  86. {
  87. return _rUnknown.Release();
  88. } //Release
  89. // ISupportErrorInfo method
  90. //+---------------------------------------------------------------------------
  91. //
  92. // Member: CCIOleDBError::InterfaceSupportsErrorInfo, public
  93. //
  94. // Synopsis: Checks if error reporting on the specified interface is supported
  95. //
  96. // Arguments: [riid] - The interface in question
  97. //
  98. // History: 28-Apr-97 KrishnaN Created
  99. //----------------------------------------------------------------------------
  100. STDMETHODIMP CCIOleDBError::InterfaceSupportsErrorInfo(REFIID riid)
  101. {
  102. ULONG ul;
  103. // See if the interface asked about, actually
  104. // creates an error object.
  105. for(ul=0; ul < _cErrInt; ul++)
  106. {
  107. if( *(_rgpErrInt[ul]) == riid )
  108. return S_OK;
  109. }
  110. return S_FALSE;
  111. } // InterfaceSupportsErrorInfo
  112. //+---------------------------------------------------------------------------
  113. //
  114. // Member: CCIOleDBError::GetErrorInterfaces, private
  115. //
  116. // Synopsis: Gets the error interfaces, IErrorInfo and IErrorRecords.
  117. //
  118. // Arguments: [ppIErrorInfo] - Pointer to hold IErrorInfo i/f pointer
  119. // [ppIErrorRecords] - Pointer to hold IErrorRecords i/f pointer
  120. //
  121. // History: 28-Apr-97 KrishnaN Created
  122. //----------------------------------------------------------------------------
  123. //
  124. HRESULT CCIOleDBError::GetErrorInterfaces(IErrorInfo** ppIErrorInfo,
  125. IErrorRecords** ppIErrorRecords)
  126. {
  127. if (0 == ppIErrorInfo || 0 == ppIErrorRecords)
  128. return E_INVALIDARG;
  129. *ppIErrorInfo = 0;
  130. *ppIErrorRecords = 0;
  131. if FAILED(_GetErrorClassFact())
  132. return E_NOINTERFACE;
  133. //
  134. // Do we have a class factory on CLSID_EXTENDEDERROR ?
  135. //
  136. if (0 == _pErrClassFact)
  137. return E_NOINTERFACE;
  138. HRESULT hr = S_OK;
  139. //
  140. // Obtain the error object or create a new one if none exists
  141. //
  142. GetErrorInfo(0, ppIErrorInfo);
  143. if ( !*ppIErrorInfo )
  144. {
  145. if( FAILED(hr = _pErrClassFact->CreateInstance(NULL,
  146. IID_IErrorInfo, (LPVOID*)ppIErrorInfo)) )
  147. return hr;
  148. }
  149. //
  150. // Obtain the IErrorRecord Interface
  151. //
  152. hr = (*ppIErrorInfo)->QueryInterface(IID_IErrorRecords,
  153. (LPVOID*)ppIErrorRecords);
  154. //
  155. // On a failure retrieving IErrorRecords, we need to release
  156. // the IErrorInfo interface
  157. //
  158. if( FAILED(hr) && *ppIErrorInfo )
  159. {
  160. (*ppIErrorInfo)->Release();
  161. *ppIErrorInfo = NULL;
  162. }
  163. return hr;
  164. }
  165. //+---------------------------------------------------------------------------
  166. //
  167. // Member: CCIOleDBError::PostHResult, public
  168. //
  169. // Synopsis: Post an HRESULT to be looked up in ole-db sdk's error
  170. // collection OR CI provided error lookup service.
  171. //
  172. // Arguments: [hrErr] - Code returned by the method that caused the error.
  173. // [piid] - Interface where the error occurred.
  174. //
  175. // Returns: The incoming hrErr is echoed back to simplify error reporting
  176. // in the calling code. So the caller can simply say something like
  177. // "return PostHResult(E_INVALIDARG, &IID_ICommand);" instead of:
  178. // "PostHResult(E_INVALIDARG, &IID_ICommand); return E_INVALIDARG;".
  179. //
  180. // History: 28-Apr-97 KrishnaN Created
  181. //----------------------------------------------------------------------------
  182. HRESULT CCIOleDBError::PostHResult(HRESULT hrErr, const IID & refiid)
  183. {
  184. SCODE hr = S_OK;
  185. ERRORINFO ErrorInfo;
  186. //
  187. // Obtain the error object or create a new one if none exists
  188. //
  189. XInterface<IErrorInfo> xErrorInfo;
  190. XInterface<IErrorRecords> xErrorRecords;
  191. hr = GetErrorInterfaces((IErrorInfo **)xErrorInfo.GetQIPointer(),
  192. (IErrorRecords **)xErrorRecords.GetQIPointer());
  193. if (FAILED(hr))
  194. return hrErr;
  195. //
  196. // Content Index methods sometimes throw NTSTATUS errors. So check for
  197. // those and translate them to HRESULTs, just as is done in GetOleError()
  198. //
  199. switch (hrErr)
  200. {
  201. case STATUS_NO_MEMORY:
  202. case HRESULT_FROM_WIN32( ERROR_COMMITMENT_LIMIT ):
  203. case HRESULT_FROM_WIN32( ERROR_NO_SYSTEM_RESOURCES ):
  204. case STG_E_TOOMANYOPENFILES:
  205. case STG_E_INSUFFICIENTMEMORY:
  206. case STATUS_INSUFFICIENT_RESOURCES:
  207. hrErr = E_OUTOFMEMORY;
  208. break;
  209. case HRESULT_FROM_WIN32( ERROR_SEM_TIMEOUT ):
  210. case HRESULT_FROM_WIN32( ERROR_PIPE_BUSY ):
  211. hrErr = CI_E_TIMEOUT;
  212. break;
  213. case HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ):
  214. hrErr = CI_E_NOT_RUNNING;
  215. break;
  216. case STATUS_NOT_FOUND:
  217. hrErr = CI_E_NOT_FOUND;
  218. break;
  219. case STATUS_INVALID_PARAMETER:
  220. hrErr = E_INVALIDARG;
  221. break;
  222. case STATUS_ACCESS_DENIED:
  223. hrErr = E_ACCESSDENIED;
  224. break;
  225. case STATUS_INVALID_PARAMETER_MIX:
  226. default:
  227. break;
  228. }
  229. //
  230. // Check to see if we have already posted this error
  231. //
  232. if ( NeedToSetError(hrErr, xErrorInfo.GetPointer(), xErrorRecords.GetPointer()) )
  233. {
  234. //
  235. // Assign static information across each error record added
  236. //
  237. ErrorInfo.clsid = CLSID_CI_PROVIDER;
  238. ErrorInfo.dispid = NULL;
  239. ErrorInfo.hrError = hrErr;
  240. ErrorInfo.iid = refiid;
  241. ErrorInfo.dwMinor = 0;
  242. //
  243. // If this is a CI error, then add it with the lookup code IDENTIFIER_CI_ERROR
  244. // If not, then it must be a Ole DB error or a Windows error. In either
  245. // case, the default Ole DB sdk error lookup service will handle it. So
  246. // post non-CI errors with IDENTIFIER_SDK_ERROR lookup id.
  247. //
  248. DWORD dwLookupId = IsCIError(hrErr) ? IDENTIFIER_CI_ERROR : IDENTIFIER_SDK_ERROR;
  249. //
  250. // Add the record to the Error Service Object
  251. //
  252. hr = xErrorRecords->AddErrorRecord(&ErrorInfo, dwLookupId, NULL, NULL, 0);
  253. //
  254. // Pass the error object to the Ole Automation DLL
  255. //
  256. if (SUCCEEDED(hr))
  257. {
  258. hr = SetErrorInfo(0, xErrorInfo.GetPointer());
  259. }
  260. }
  261. //
  262. // Release the interfaces to transfer ownership to
  263. // the Ole Automation DLL. This will happen when
  264. // xErrorInfo and xErrorRecords destruct, at the
  265. // exit point of this method.
  266. //
  267. return hrErr;
  268. }
  269. //+---------------------------------------------------------------------------
  270. //
  271. // Member: CCIOleDBError::PostHResult, public
  272. //
  273. // Synopsis: Post an HRESULT to be looked up in ole-db sdk's error
  274. // collection OR CI provided error lookup service.
  275. //
  276. // Arguments: [e] - CException object containing error code.
  277. // [piid] - Interface where the error occurred.
  278. //
  279. // Returns: The incoming hrErr is echoed back to simplify error reporting
  280. // in the calling code. So the caller can simply say something like
  281. // "return PostHResult(E_INVALIDARG, &IID_ICommand);" instead of:
  282. // "PostHResult(E_INVALIDARG, &IID_ICommand); return E_INVALIDARG;".
  283. //
  284. // This override allows for posting two error records in the case
  285. // where the SCODE is converted into a less informative error code
  286. // such as E_FAIL.
  287. //
  288. // History: 01-04-97 DanLeg Created
  289. //----------------------------------------------------------------------------
  290. HRESULT CCIOleDBError::PostHResult(CException &e, const IID & refiid)
  291. {
  292. SCODE sc = e.GetErrorCode();
  293. SCODE scOLE = GetOleError(e);
  294. if ( sc != scOLE )
  295. {
  296. PostHResult( sc, refiid );
  297. sc = scOLE;
  298. }
  299. PostHResult( sc, refiid );
  300. return sc;
  301. }
  302. //+---------------------------------------------------------------------------
  303. //
  304. // Member: CCIOleDBError::PostParserError, public
  305. //
  306. // Synopsis: This method is used to post static strings and DISPPARAMS to
  307. // the error objects. The static strings are stored in the resource
  308. // fork, and thus an id needs to be specified. This method receives
  309. // in dwIds Monarch's error ids. Needs to change them to our
  310. // resource ids (dwIdPostError). dwIdPost error is marked with flag
  311. // (ERR_MONARCH_STATIC), so that GetErrorDescription may take the
  312. // proper parameters.
  313. //
  314. // NOTE: If the error object is not our implementation of IID_IErrorInfo,
  315. // we will not be able to load IErrorRecord and add our records.
  316. //
  317. // Arguments: [hrErr] - HRESULT to associate
  318. // [dwIds] - string ID
  319. // [ppdispparams] - dispatch params
  320. //
  321. // Returns: HResult indicating status
  322. // S_OK | Success
  323. // E_FAIL | OLE DB Error service object missing
  324. //
  325. //
  326. // History: 11-03-97 danleg Created from Monarch
  327. //----------------------------------------------------------------------------
  328. HRESULT CCIOleDBError::PostParserError
  329. (
  330. HRESULT hrErr, //@parm IN | HResult to associate
  331. DWORD dwIds, //@parm IN | String id
  332. DISPPARAMS **ppdispparams //@parm IN/OUT | Dispatch Params
  333. )
  334. {
  335. SCODE sc = S_OK;
  336. DWORD dwIdPostError;
  337. // Translation array from MONSQL values to IDS values
  338. static const UINT s_rgTranslate[] = {
  339. IDS_MON_PARSE_ERR_2_PARAM, // MONSQL_PARSE_ERROR w/ 2 parameter
  340. IDS_MON_PARSE_ERR_1_PARAM, // MONSQL_PARSE_ERROR w/ 1 parameter
  341. IDS_MON_ILLEGAL_PASSTHROUGH, // MONSQL_CITEXTTOSELECTTREE_FAILED
  342. IDS_MON_DEFAULT_ERROR, // MONSQL_PARSE_STACK_OVERFLOW
  343. IDS_MON_DEFAULT_ERROR, // MONSQL_CANNOT_BACKUP_PARSER
  344. IDS_MON_SEMI_COLON, // MONSQL_SEMI_COLON
  345. IDS_MON_ORDINAL_OUT_OF_RANGE, // MONSQL_ORDINAL_OUT_OF_RANGE
  346. IDS_MON_VIEW_NOT_DEFINED, // MONSQL_VIEW_NOT_DEFINED
  347. IDS_MON_BUILTIN_VIEW, // MONSQL_BUILTIN_VIEW
  348. IDS_MON_COLUMN_NOT_DEFINED, // MONSQL_COLUMN_NOT_DEFINED
  349. IDS_MON_OUT_OF_MEMORY, // MONSQL_OUT_OF_MEMORY
  350. IDS_MON_SELECT_STAR, // MONSQL_SELECT_STAR
  351. IDS_MON_OR_NOT, // MONSQL_OR_NOT
  352. IDS_MON_CANNOT_CONVERT, // MONSQL_CANNOT_CONVERT
  353. IDS_MON_OUT_OF_RANGE, // MONSQL_OUT_OF_RANGE
  354. IDS_MON_RELATIVE_INTERVAL, // MONSQL_RELATIVE_INTERVAL
  355. IDS_MON_NOT_COLUMN_OF_VIEW, // MONSQL_NOT_COLUMN_OF_VIEW
  356. IDS_MON_BUILTIN_PROPERTY, // MONSQL_BUILTIN_PROPERTY
  357. IDS_MON_WEIGHT_OUT_OF_RANGE, // MONSQL_WEIGHT_OUT_OF_RANGE
  358. IDS_MON_MATCH_STRING, // MONSQL_MATCH_STRING
  359. IDS_MON_PROPERTY_NAME_IN_VIEW, // MONSQL_PROPERTY_NAME_IN_VIEW
  360. IDS_MON_VIEW_ALREADY_DEFINED, // MONSQL_VIEW_ALREADY_DEFINED
  361. IDS_MON_INVALID_CATALOG, // MONSQL_INVALID_CATALOG
  362. };
  363. Win4Assert( ppdispparams );
  364. // special fixup for MONSQL_PARSE_ERROR
  365. if ( dwIds == MONSQL_PARSE_ERROR )
  366. {
  367. Win4Assert( *ppdispparams && (((*ppdispparams)->cArgs == 1) || ((*ppdispparams)->cArgs == 2)) );
  368. if ( ((*ppdispparams) != NULL) &&
  369. ((*ppdispparams)->cArgs == 2) )
  370. {
  371. dwIds = 0; //Change to point to index of 2 parameter parse error
  372. }
  373. }
  374. if ( dwIds < NUMELEM( s_rgTranslate ) )
  375. dwIdPostError = s_rgTranslate[dwIds];
  376. else
  377. dwIdPostError= IDS_MON_DEFAULT_ERROR;
  378. sc = PostError(hrErr, IID_ICommandText, dwIdPostError, *ppdispparams);
  379. // free dispparams in case of error
  380. if ( (*ppdispparams) != NULL )
  381. {
  382. if ( ((*ppdispparams)->cArgs > 0) &&
  383. ((*ppdispparams)->rgvarg!= NULL) )
  384. {
  385. for (ULONG ul=0; ul<(*ppdispparams)->cArgs; ul++)
  386. VariantClear(&((*ppdispparams)->rgvarg[ul]));
  387. CoTaskMemFree(((*ppdispparams)->rgvarg));
  388. (*ppdispparams)->rgvarg= NULL;
  389. (*ppdispparams)->cArgs = 0;
  390. };
  391. CoTaskMemFree((*ppdispparams));
  392. *ppdispparams = NULL;
  393. }
  394. return sc;
  395. }
  396. //+---------------------------------------------------------------------------
  397. //
  398. // Member: CCIOleDBError::PostError, public
  399. //
  400. // Synopsis: This method is used to post static strings to the error objects.
  401. // The static strings are stored in the resource fork, and thus an
  402. // id needs to be specified.
  403. //
  404. // @devnote If the error object is not our implementation of
  405. // IID_IErrorInfo, we will not be able to load IErrorRecord and add
  406. // our records.
  407. //
  408. //
  409. // Arguments: [hrErr] - HRESULT to associate
  410. // [refiid] - IID of interface with error.
  411. // [dwIds] - String id
  412. // [pdispparams] - Parameters for the static string
  413. //
  414. // Returns: HResult indicating status
  415. // S_OK | Success
  416. // E_FAIL | OLE DB Error service object missing
  417. //
  418. //
  419. // History: 11-03-97 danleg Created from Monarch
  420. //----------------------------------------------------------------------------//-----------------------------------------------------------------------------
  421. //
  422. // @mfunc
  423. // @rdesc HResult indicating status
  424. // @flags S_OK | Success
  425. // @flags E_FAIL | OLE DB Error service object missing
  426. //
  427. HRESULT CCIOleDBError::PostError
  428. (
  429. HRESULT hrErr,
  430. const IID & refiid,
  431. DWORD dwIds,
  432. DISPPARAMS* pdispparams
  433. )
  434. {
  435. SCODE sc = S_OK;
  436. ERRORINFO ErrorInfo;
  437. IErrorInfo* pIErrorInfo = NULL;
  438. IErrorRecords* pIErrorRecords = NULL;
  439. // Obtain the error object or create a new one if none exists
  440. sc = GetErrorInterfaces( &pIErrorInfo, &pIErrorRecords );
  441. if ( FAILED(sc) )
  442. goto EXIT_PROCESS_ERRORS;
  443. // Assign static information across each error record added
  444. ErrorInfo.clsid = CLSID_CI_PROVIDER;
  445. ErrorInfo.hrError = hrErr;
  446. ErrorInfo.iid = refiid;
  447. ErrorInfo.dispid = NULL;
  448. ErrorInfo.dwMinor = 0;
  449. // Add the record to the Error Service Object
  450. sc = pIErrorRecords->AddErrorRecord( &ErrorInfo,
  451. dwIds,
  452. pdispparams,
  453. NULL,
  454. 0 );
  455. if ( FAILED(sc) )
  456. goto EXIT_PROCESS_ERRORS;
  457. // Pass the error object to the Ole Automation DLL
  458. sc = SetErrorInfo(0, pIErrorInfo);
  459. // Release the interfaces to transfer ownership to
  460. // the Ole Automation DLL
  461. EXIT_PROCESS_ERRORS:
  462. if ( pIErrorRecords )
  463. pIErrorRecords->Release();
  464. if ( pIErrorInfo )
  465. pIErrorInfo->Release();
  466. return sc;
  467. }
  468. //-----------------------------------------------------------------------------
  469. //
  470. // Member: CCIOleDBError::NeedToSetError - private
  471. //
  472. // Synopsis: Determine if error needs to be set.
  473. //
  474. // Arguments: [scError] - Error code to look for
  475. //
  476. // Returns: TRUE if the error needs to be set. FALSE, if it already
  477. // exists and has a valid description string.
  478. //
  479. // Notes:
  480. //
  481. // History: 15 Jan 1998 KrishnaN Created
  482. // 03-01-98 danleg adopted from ixsso with few changes
  483. //
  484. //-----------------------------------------------------------------------------
  485. BOOL CCIOleDBError::NeedToSetError
  486. (
  487. SCODE scError,
  488. IErrorInfo * pErrorInfo,
  489. IErrorRecords * pErrorRecords
  490. )
  491. {
  492. BOOL fFound = FALSE;
  493. if ( 0 == pErrorInfo )
  494. return TRUE;
  495. XBStr xDescription;
  496. BSTR pDescription = xDescription.GetPointer();
  497. if (0 == pErrorRecords)
  498. {
  499. // No error records. Do we at least have the top level description set?
  500. // If so, that indicates an automation client called SetErrorInfo before us
  501. // and we should not overwrite them.
  502. pErrorInfo->GetDescription(&pDescription);
  503. fFound = (BOOL)(pDescription != 0);
  504. }
  505. else
  506. {
  507. ULONG cErrRecords;
  508. SCODE sc = pErrorRecords->GetRecordCount(&cErrRecords);
  509. Win4Assert(!fFound);
  510. // look for the target error code. stop when one is found
  511. ERRORINFO ErrorInfo;
  512. for (ULONG i = 0; i < cErrRecords; i++)
  513. {
  514. sc = pErrorRecords->GetBasicErrorInfo(i, &ErrorInfo);
  515. Win4Assert(S_OK == sc);
  516. if (scError == ErrorInfo.hrError)
  517. {
  518. pErrorInfo->GetDescription(&pDescription);
  519. fFound = (BOOL)(pDescription != 0);
  520. break;
  521. }
  522. }
  523. }
  524. if (!fFound)
  525. return TRUE;
  526. // we found the error code and it has a description.
  527. // no need to set this error again, but we have to
  528. // put this error info back so the client can find it.
  529. SetErrorInfo(0, pErrorInfo);
  530. return FALSE;
  531. }
  532. //+---------------------------------------------------------------------------
  533. //
  534. // Member: CCIOleDBError::_GetErrorClassFact, private
  535. //
  536. // Synopsis: Initializes error class factory.
  537. //
  538. // Returns: Success code.
  539. //
  540. // History: 28-Apr-97 KrishnaN Created
  541. //----------------------------------------------------------------------------
  542. SCODE CCIOleDBError::_GetErrorClassFact()
  543. {
  544. SCODE sc = S_OK;
  545. CLock lck( _mutex );
  546. //
  547. // If we have failed once, we should not be
  548. // attempting again. No point in doing that.
  549. //
  550. if ( 0 == _pErrClassFact )
  551. {
  552. //
  553. // We don't have an error class factory.
  554. //
  555. sc = CoGetClassObject(CLSID_EXTENDEDERRORINFO,
  556. CLSCTX_INPROC_SERVER,
  557. NULL,
  558. IID_IClassFactory,
  559. (void **) &_pErrClassFact);
  560. if (FAILED(sc))
  561. {
  562. vqDebugOut((DEB_ITRACE, "No class factory is available "
  563. " for CLSID_EXTENDEDERROR.\n"));
  564. }
  565. }
  566. return sc;
  567. }
  568. //+---------------------------------------------------------------------------
  569. //
  570. // Member: CErrorLookup::QueryInterface, public
  571. //
  572. // Synopsis: Supports IID_IUnknown and IID_IErrorLookup
  573. //
  574. // History: 28-Apr-97 KrishnaN Created
  575. // 01-30-98 danleg E_INVALIDARG if ppvObject is bad
  576. //----------------------------------------------------------------------------
  577. STDMETHODIMP CErrorLookup::QueryInterface(REFIID riid, void **ppvObject)
  578. {
  579. if ( !ppvObject )
  580. return E_INVALIDARG;
  581. if (IID_IUnknown == riid)
  582. {
  583. *ppvObject = (void *)((IUnknown *)this);
  584. AddRef();
  585. return S_OK;
  586. }
  587. else if (IID_IErrorLookup == riid)
  588. {
  589. *ppvObject = (void *)((IErrorLookup *)this);
  590. AddRef();
  591. return S_OK;
  592. }
  593. else
  594. {
  595. *ppvObject = 0;
  596. return E_NOINTERFACE;
  597. }
  598. } //QueryInterface
  599. //+---------------------------------------------------------------------------
  600. //
  601. // Member: CErrorLookup::AddRef, public
  602. //
  603. // History: 17-Mar-97 KrishnaN Created
  604. //
  605. //----------------------------------------------------------------------------
  606. STDMETHODIMP_(ULONG) CErrorLookup::AddRef()
  607. {
  608. InterlockedIncrement(&_cRefs);
  609. return _cRefs;
  610. } //AddRef
  611. //+---------------------------------------------------------------------------
  612. //
  613. // Member: CErrorLookup::Release, public
  614. //
  615. // History: 17-Mar-97 KrishnaN Created
  616. //
  617. //----------------------------------------------------------------------------
  618. STDMETHODIMP_(ULONG) CErrorLookup::Release()
  619. {
  620. Win4Assert(_cRefs > 0);
  621. LONG refCount = InterlockedDecrement(&_cRefs);
  622. if ( refCount <= 0 )
  623. delete this;
  624. return refCount;
  625. } //Release
  626. // IErrorLookup methods
  627. //+---------------------------------------------------------------------------
  628. //
  629. // Member: CErrorLookup::GetErrorDescription, public
  630. //
  631. // Synopsis: Composes the error description for the specifed error.
  632. //
  633. // Arguments: [hrError] - Code returned by the method that caused
  634. // the error.
  635. // [dwLookupId] - Provider-specific number of the error.
  636. // [pdispparams] - Params of the error. If there are no
  637. // params, this is a NULL pointer.
  638. // [lcid] - Locale ID for which to return the
  639. // description and the sources.
  640. // [pbstrSource] - Pointer to memory in which to return a
  641. // pointer to the name of the component
  642. // that generated the error.
  643. // [pbstrDescription]- Pointer to memory in which to return a
  644. // string that describes the error.
  645. //
  646. // History: 28-Apr-97 KrishnaN Created
  647. //----------------------------------------------------------------------------
  648. STDMETHODIMP CErrorLookup::GetErrorDescription (HRESULT hrError,
  649. DWORD dwLookupId,
  650. DISPPARAMS* pdispparams,
  651. LCID lcid,
  652. BSTR* pbstrSource,
  653. BSTR* pbstrDescription)
  654. {
  655. SCODE sc = S_OK;
  656. // Check the Arguments
  657. if( 0 == pbstrSource || 0 == pbstrDescription )
  658. return E_INVALIDARG;
  659. *pbstrSource = *pbstrDescription = 0;
  660. TRANSLATE_EXCEPTIONS;
  661. TRY
  662. {
  663. //
  664. // If we encounter IDENTIFIER_SDK_ERROR, make sure we return S_OK;
  665. //
  666. BOOL fGetDescription = (IDENTIFIER_SDK_ERROR != dwLookupId);
  667. BOOL fGetSource = TRUE;
  668. XBStr xbstrDescription;
  669. XBStr xbstrSource;
  670. // We only support lookup of CI generated errors and those handled
  671. // by the default error lookup service!
  672. if ( (IDENTIFIER_SDK_ERROR != dwLookupId) && !IsCIError(hrError) )
  673. {
  674. if( IsParserError(dwLookupId) )
  675. {
  676. hrError = dwLookupId;
  677. }
  678. else
  679. {
  680. fGetDescription = fGetSource = FALSE;
  681. sc = DB_E_BADHRESULT;
  682. }
  683. }
  684. if (fGetSource)
  685. {
  686. // Fix for bug# 83593: Set source string even when the default
  687. // lookup service is providing the description
  688. xbstrSource.SetText( L"Microsoft OLE DB Provider for Indexing Service" );
  689. }
  690. if (fGetDescription)
  691. {
  692. DWORD_PTR rgdwArguments[2];
  693. DWORD dwFlags = FORMAT_MESSAGE_FROM_HMODULE;
  694. if (pdispparams)
  695. {
  696. dwFlags |= FORMAT_MESSAGE_ARGUMENT_ARRAY;
  697. Win4Assert(pdispparams->cArgs == 2 || pdispparams->cArgs == 1 || pdispparams->cArgs == 0);
  698. for (UINT c=0; c < pdispparams->cArgs; c++)
  699. {
  700. rgdwArguments[c] = (DWORD_PTR)(LPWSTR)pdispparams->rgvarg[c].bstrVal;
  701. }
  702. }
  703. else
  704. {
  705. RtlZeroMemory( rgdwArguments, sizeof(rgdwArguments) );
  706. }
  707. //
  708. // Load the error string from the appropriate DLL
  709. //
  710. WCHAR wszBuffer[ERROR_MESSAGE_SIZE];
  711. //
  712. // Don't pass a specific lang id to FormatMessage since it will
  713. // fail if there's no message in that language. Instead set
  714. // the thread locale, which will get FormatMessage to use a search
  715. // algorithm to find a message of the appropriate language or
  716. // use a reasonable fallback msg if there's none.
  717. //
  718. LCID SaveLCID = GetThreadLocale();
  719. SetThreadLocale(lcid);
  720. // CLEANCODE: Since we could have differently named dlls (query.dll
  721. // or oquery.dll) we should be able to look up in the registry
  722. // and determine which one to get. Or just get the module name.
  723. // All messages are in querymsg.mc, which is in query.dll.
  724. HMODULE hModule = GetModuleHandle(L"query.dll");
  725. if (! FormatMessage( dwFlags | FORMAT_MESSAGE_MAX_WIDTH_MASK,
  726. hModule,
  727. hrError,
  728. 0,
  729. wszBuffer,
  730. ERROR_MESSAGE_SIZE,
  731. (va_list*) rgdwArguments ) )
  732. {
  733. vqDebugOut(( DEB_ERROR, "Format message failed with error 0x%x\n", GetLastError() ));
  734. swprintf( wszBuffer,
  735. L"Unable to format message for error 0x%X caught in Indexing Service.\n",
  736. hrError );
  737. }
  738. SetThreadLocale(SaveLCID);
  739. //
  740. // Convert the loaded string to a BSTR
  741. //
  742. xbstrDescription.SetText(wszBuffer);
  743. }
  744. *pbstrSource = xbstrSource.GetPointer();
  745. *pbstrDescription = xbstrDescription.GetPointer();
  746. xbstrSource.Acquire();
  747. xbstrDescription.Acquire();
  748. }
  749. CATCH( CException, e )
  750. {
  751. vqDebugOut(( DEB_ERROR, "Exception %08x in CCIOleDBError::GetErrorDescription \n",
  752. e.GetErrorCode() ));
  753. sc = GetOleError(e);
  754. }
  755. END_CATCH
  756. UNTRANSLATE_EXCEPTIONS;
  757. return sc;
  758. }
  759. //+---------------------------------------------------------------------------
  760. //
  761. // Member: CErrorLookup::GetHelpInfo, public
  762. //
  763. // Synopsis: Composes the error description for the specifed error.
  764. //
  765. // Arguments: [hrError] - Code returned by the method that caused
  766. // the error.
  767. // [dwLookupId] - Provider-specific number of the error.
  768. // [lcid] - Locale Id for which to return the Help
  769. // file path and Context ID.
  770. // [pbstrHelpFile] - Pointer to memory in which to return a
  771. // pointer the fully path of the Help file.
  772. //
  773. // [pdwHelpContext]- Pointer to memory in which to return the
  774. // Help Context ID for the error.
  775. //
  776. // History: 28-Apr-97 KrishnaN Created
  777. //----------------------------------------------------------------------------
  778. STDMETHODIMP CErrorLookup::GetHelpInfo (HRESULT hrError,
  779. DWORD dwLookupId,
  780. LCID lcid,
  781. BSTR* pbstrHelpFile,
  782. DWORD* pdwHelpContext)
  783. {
  784. if ( 0 == pbstrHelpFile || 0 == pdwHelpContext )
  785. return E_INVALIDARG;
  786. *pbstrHelpFile = 0;
  787. *pdwHelpContext = 0;
  788. //
  789. // Currently we do not return any help file
  790. // context or names, so we will just return S_OK
  791. //
  792. // NEWFEATURE: We can, if we choose to, return help file
  793. // and context for the query project.
  794. if ( lcid != GetUserDefaultLCID() )
  795. return DB_E_NOLOCALE;
  796. return S_OK;
  797. }
  798. //+---------------------------------------------------------------------------
  799. //
  800. // Member: CErrorLookup::ReleaseErrors, public
  801. //
  802. // Synopsis: Releases dynamic errors.
  803. //
  804. // Arguments: [dwDynamicErrorId] - ID of the dynamic error info to release.
  805. //
  806. // History: 28-Apr-97 KrishnaN Created
  807. //----------------------------------------------------------------------------
  808. STDMETHODIMP CErrorLookup::ReleaseErrors (const DWORD dwDynamicErrorId)
  809. {
  810. Win4Assert(!"Currently we don't support dynamic errors.");
  811. if (0 == dwDynamicErrorId)
  812. return E_INVALIDARG;
  813. //
  814. // We don't support dynamic errors, so nothing to do.
  815. //
  816. return S_OK;
  817. }
  818. //+-------------------------------------------------------------------------
  819. //
  820. // Method: CErrorLookupCF::CErrorLookupCF, public
  821. //
  822. // Synopsis: CErrorLookup class factory constructor
  823. //
  824. // History: 25-Mar-1997 KrishnaN Created
  825. //
  826. //--------------------------------------------------------------------------
  827. CErrorLookupCF::CErrorLookupCF()
  828. : _cRefs( 1 )
  829. {
  830. InterlockedIncrement( &gulcInstances );
  831. }
  832. //+-------------------------------------------------------------------------
  833. //
  834. // Method: CErrorLookupCF::~CErrorLookupCF
  835. //
  836. // Synopsis: Text IFilter class factory constructor
  837. //
  838. // History: 25-Mar-1997 KrishnaN Created
  839. //
  840. //--------------------------------------------------------------------------
  841. CErrorLookupCF::~CErrorLookupCF()
  842. {
  843. InterlockedDecrement( &gulcInstances );
  844. }
  845. //+-------------------------------------------------------------------------
  846. //
  847. // Method: CErrorLookupCF::QueryInterface, public
  848. //
  849. // Synopsis: Rebind to other interface
  850. //
  851. // Arguments: [riid] -- IID of new interface
  852. // [ppvObject] -- New interface * returned here
  853. //
  854. // Returns: S_OK if bind succeeded, E_NOINTERFACE if bind failed
  855. //
  856. // History: 25-Mar-1997 KrishnaN Created
  857. // 01-31-98 danleg E_INVALIDARG for bad ppvObject
  858. //
  859. //--------------------------------------------------------------------------
  860. SCODE STDMETHODCALLTYPE CErrorLookupCF::QueryInterface( REFIID riid,
  861. void ** ppvObject )
  862. {
  863. if ( 0 == ppvObject )
  864. return E_INVALIDARG;
  865. *ppvObject = 0;
  866. SCODE sc = S_OK;
  867. if ( IID_IClassFactory == riid )
  868. *ppvObject = (IUnknown *)(IClassFactory *)this;
  869. else if ( IID_IUnknown == riid )
  870. *ppvObject = (IUnknown *)this;
  871. else if ( IID_ITypeLib == riid )
  872. sc = E_NOINTERFACE;
  873. else
  874. sc = E_NOINTERFACE;
  875. if ( SUCCEEDED( sc ) )
  876. AddRef();
  877. return sc;
  878. }
  879. //+-------------------------------------------------------------------------
  880. //
  881. // Method: CErrorLookupCF::AddRef, public
  882. //
  883. // Synopsis: Increments refcount
  884. //
  885. // History: 25-Mar-1997 KrishnaN Created
  886. //
  887. //--------------------------------------------------------------------------
  888. ULONG STDMETHODCALLTYPE CErrorLookupCF::AddRef()
  889. {
  890. return InterlockedIncrement( &_cRefs );
  891. }
  892. //+-------------------------------------------------------------------------
  893. //
  894. // Method: CErrorLookupCF::Release, public
  895. //
  896. // Synopsis: Decrement refcount. Delete if necessary.
  897. //
  898. // History: 25-Mar-1997 KrishnaN Created
  899. //
  900. //--------------------------------------------------------------------------
  901. ULONG STDMETHODCALLTYPE CErrorLookupCF::Release()
  902. {
  903. unsigned long uTmp = InterlockedDecrement( &_cRefs );
  904. if ( 0 == uTmp )
  905. delete this;
  906. return(uTmp);
  907. }
  908. //+-------------------------------------------------------------------------
  909. //
  910. // Method: CErrorLookupCF::CreateInstance, public
  911. //
  912. // Synopsis: Creates new CIndexer object
  913. //
  914. // Arguments: [pUnkOuter] -- 'Outer' IUnknown
  915. // [riid] -- Interface to bind
  916. // [ppvObject] -- Interface returned here
  917. //
  918. // History: 25-Mar-1997 KrishnaN Created
  919. //
  920. //--------------------------------------------------------------------------
  921. SCODE STDMETHODCALLTYPE CErrorLookupCF::CreateInstance( IUnknown * pUnkOuter,
  922. REFIID riid,
  923. void * * ppvObject )
  924. {
  925. CErrorLookup * pIUnk = 0;
  926. SCODE sc = S_OK;
  927. TRY
  928. {
  929. pIUnk = new CErrorLookup();
  930. sc = pIUnk->QueryInterface( riid , ppvObject );
  931. pIUnk->Release(); // Release extra refcount from QueryInterface
  932. }
  933. CATCH( CException, e )
  934. {
  935. Win4Assert( 0 == pIUnk );
  936. sc = GetOleError(e);
  937. }
  938. END_CATCH
  939. return (sc);
  940. }
  941. //+-------------------------------------------------------------------------
  942. //
  943. // Method: CErrorLookupCF::LockServer, public
  944. //
  945. // Synopsis: Force class factory to remain loaded
  946. //
  947. // Arguments: [fLock] -- TRUE if locking, FALSE if unlocking
  948. //
  949. // Returns: S_OK
  950. //
  951. // History: 25-Mar-1997 KrishnaN Created
  952. //
  953. //--------------------------------------------------------------------------
  954. SCODE STDMETHODCALLTYPE CErrorLookupCF::LockServer(BOOL fLock)
  955. {
  956. if(fLock)
  957. InterlockedIncrement( &gulcInstances );
  958. else
  959. InterlockedDecrement( &gulcInstances );
  960. return(S_OK);
  961. }