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.

2052 lines
71 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  4. // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  5. // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  6. // PARTICULAR PURPOSE.
  7. //
  8. // Copyright (c) Microsoft Corporation, 1997 - 2001. All Rights Reserved.
  9. //
  10. // PROGRAM: qsample.cxx
  11. //
  12. // PURPOSE: Illustrates a minimal query using Indexing Service.
  13. // Uses CIMakeICommand and CITextToFullTree helper functions.
  14. //
  15. // PLATFORM: Windows 2000
  16. //
  17. //--------------------------------------------------------------------------
  18. #define UNICODE
  19. #define DBINITCONSTANTS
  20. #include <stdio.h>
  21. #include <wchar.h>
  22. #include <windows.h>
  23. #include <oledberr.h>
  24. #include <oledb.h>
  25. #include <cmdtree.h>
  26. #include <ntquery.h>
  27. #include "qsample.hxx"
  28. // This is found in disptree.cxx
  29. extern void DisplayCommandTree( DBCOMMANDTREE * pNode, ULONG iLevel = 0 );
  30. //+---------------------------------------------------------------------------
  31. //
  32. // Class: XBStr
  33. //
  34. // Purpose: Smart BSTR class
  35. //
  36. //----------------------------------------------------------------------------
  37. class XBStr
  38. {
  39. public:
  40. XBStr(BSTR p = 0) : _p( p ) {}
  41. XBStr ( XBStr & x ): _p( x.Acquire() ) {}
  42. ~XBStr() { SysFreeString( _p ); }
  43. BOOL IsNull() const { return ( 0 == _p ); }
  44. void Set ( BSTR pOleStr ) { _p = pOleStr; }
  45. BSTR Acquire()
  46. {
  47. BSTR pTemp = _p;
  48. _p = 0;
  49. return pTemp;
  50. }
  51. BSTR GetPointer() const { return _p; }
  52. void Free() { SysFreeString( Acquire() ); }
  53. private:
  54. BSTR _p;
  55. };
  56. //+-------------------------------------------------------------------------
  57. //
  58. // Template: XInterface
  59. //
  60. // Synopsis: Template for managing ownership of interfaces
  61. //
  62. //--------------------------------------------------------------------------
  63. template<class T> class XInterface
  64. {
  65. public:
  66. XInterface( T * p = 0 ) : _p( p ) {}
  67. ~XInterface() { if ( 0 != _p ) _p->Release(); }
  68. T * operator->() { return _p; }
  69. T * GetPointer() const { return _p; }
  70. IUnknown ** GetIUPointer() { return (IUnknown **) &_p; }
  71. T ** GetPPointer() { return &_p; }
  72. void ** GetQIPointer() { return (void **) &_p; }
  73. T * Acquire() { T * p = _p; _p = 0; return p; }
  74. BOOL IsNull() { return ( 0 == _p ); }
  75. private:
  76. T * _p;
  77. };
  78. //+-------------------------------------------------------------------------
  79. //
  80. // Template: XPtr
  81. //
  82. // Synopsis: Template for managing ownership of memory
  83. //
  84. //--------------------------------------------------------------------------
  85. template<class T> class XPtr
  86. {
  87. public:
  88. XPtr( unsigned c ) : _p(0) { if ( 0 != c ) _p = new T [ c ]; }
  89. ~XPtr() { Free(); }
  90. void SetSize( unsigned c ) { Free(); _p = new T [ c ]; }
  91. void Set ( T * p ) { _p = p; }
  92. T * Get() const { return _p ; }
  93. void Free() { delete [] Acquire(); }
  94. T & operator[]( unsigned i ) { return _p[i]; }
  95. T const & operator[]( unsigned i ) const { return _p[i]; }
  96. T * Acquire() { T * p = _p; _p = 0; return p; }
  97. BOOL IsNull() const { return ( 0 == _p ); }
  98. private:
  99. T * _p;
  100. };
  101. //+-------------------------------------------------------------------------
  102. //
  103. // Template: CResString
  104. //
  105. // Synopsis: Class for loading string resources
  106. //
  107. //--------------------------------------------------------------------------
  108. class CResString
  109. {
  110. public:
  111. CResString() { _awc[ 0 ] = 0; }
  112. CResString( UINT strIDS ) { Load( strIDS ); }
  113. WCHAR const * Get() const { return _awc; }
  114. BOOL Load( UINT strIDS )
  115. {
  116. _awc[ 0 ] = 0;
  117. LoadString( 0, strIDS, _awc, sizeof _awc / sizeof WCHAR );
  118. return ( 0 != _awc[ 0 ] );
  119. }
  120. private:
  121. WCHAR _awc[ 200 ];
  122. };
  123. //+-------------------------------------------------------------------------
  124. //
  125. // Function: FormatError
  126. //
  127. // Synopsis: Formats an error code into a string
  128. //
  129. // Arguments: [sc] - An Indexing Service or Win32 HRESULT
  130. // [pwc] - Where to write the error string
  131. // [cwc] - Count of characters in pwc
  132. // [lcid] - Locale for the error string
  133. //
  134. //--------------------------------------------------------------------------
  135. void FormatError(
  136. SCODE sc,
  137. WCHAR * pwc,
  138. ULONG cwc,
  139. LCID lcid )
  140. {
  141. // FormatMessage works best when based on thread locale.
  142. LCID SaveLCID = GetThreadLocale();
  143. SetThreadLocale( lcid );
  144. // Is this an Indexing Service error? These errors are in query.dll.
  145. if ( ! FormatMessage( FORMAT_MESSAGE_FROM_HMODULE,
  146. GetModuleHandle( L"query.dll" ),
  147. sc,
  148. 0,
  149. pwc,
  150. cwc,
  151. 0 ) )
  152. {
  153. // Is this a Win32 error? These are in kernel32.dll
  154. const ULONG facWin32 = ( FACILITY_WIN32 << 16 );
  155. ULONG Win32Error = sc;
  156. if ( (Win32Error & facWin32) == facWin32 )
  157. Win32Error &= ~( 0x80000000 | facWin32 );
  158. if ( ! FormatMessage( FORMAT_MESSAGE_FROM_HMODULE,
  159. GetModuleHandle( L"kernel32.dll" ),
  160. Win32Error,
  161. 0,
  162. pwc,
  163. cwc,
  164. 0 ) )
  165. {
  166. // It's not from Indexing Service or Win32; display a default error
  167. CResString str( IDS_UNKNOWNERROR );
  168. wcscpy( pwc, str.Get() );
  169. }
  170. }
  171. // Restore the original thread locale
  172. SetThreadLocale( SaveLCID );
  173. } //FormatError
  174. //+-------------------------------------------------------------------------
  175. //
  176. // Function: DisplayError
  177. //
  178. // Synopsis: Prints an error message from a string resource
  179. //
  180. // Arguments: [uiError] - The error message resource id
  181. // [pwcArgument] - A string argument for the error message
  182. // [hr] - The error code
  183. // [lcid] - Locale for the error string
  184. //
  185. //--------------------------------------------------------------------------
  186. void DisplayError(
  187. UINT uiError,
  188. WCHAR const * pwcArgument,
  189. HRESULT hr,
  190. LCID lcid )
  191. {
  192. WCHAR awcError[ 200 ];
  193. FormatError( hr, awcError, sizeof awcError / sizeof WCHAR, lcid );
  194. CResString str( uiError );
  195. wprintf( str.Get(), pwcArgument, hr, awcError );
  196. } //DisplayError
  197. //+-------------------------------------------------------------------------
  198. //
  199. // Function: DisplayWin32Error
  200. //
  201. // Synopsis: Prints an error message taken from GetLastError()
  202. //
  203. // Arguments: [uiError] - The string resource to use for the error
  204. // [pwcArgument] - A string argument for the error message
  205. // [lcid] - Locale for the error string
  206. //
  207. //--------------------------------------------------------------------------
  208. HRESULT DisplayWin32Error(
  209. UINT uiError,
  210. WCHAR const * pwcArgument,
  211. LCID lcid )
  212. {
  213. HRESULT hr = HRESULT_FROM_WIN32( GetLastError() );
  214. DisplayError( uiError, pwcArgument, hr, lcid );
  215. return hr;
  216. } //DisplayWin32Error
  217. void DisplayStat( DWORD dw, UINT uiMsg )
  218. {
  219. CResString str( uiMsg );
  220. wprintf( L"%8d %ws\n", dw, str.Get() );
  221. } //DisplayStat
  222. void DisplayStat( WCHAR const *pwcMsg, UINT uiMsg )
  223. {
  224. CResString str( uiMsg );
  225. wprintf( L"%ws: %ws\n", str.Get(), pwcMsg );
  226. } //DisplayStat
  227. void DisplayStat( UINT uiMsg )
  228. {
  229. CResString str( uiMsg );
  230. wprintf( L"%ws\n", str.Get() );
  231. } //DisplayStat
  232. //+-------------------------------------------------------------------------
  233. //
  234. // Function: LocaleToCodepage
  235. //
  236. // Synopsis: Finds the best matching codepage given a locale id.
  237. //
  238. // Arguments: [lcid] - Locale to check
  239. //
  240. // Returns: The best matching codepage.
  241. //
  242. //--------------------------------------------------------------------------
  243. ULONG LocaleToCodepage( LCID lcid )
  244. {
  245. ULONG codepage;
  246. int cwc = GetLocaleInfo( lcid,
  247. LOCALE_RETURN_NUMBER |
  248. LOCALE_IDEFAULTANSICODEPAGE,
  249. (WCHAR *) &codepage,
  250. sizeof ULONG / sizeof WCHAR );
  251. // If an error occurred, return the Ansi code page
  252. if ( 0 == cwc )
  253. return CP_ACP;
  254. return codepage;
  255. } //LocaleToCodepage
  256. //+-------------------------------------------------------------------------
  257. //
  258. // Function: SetCommandProperties
  259. //
  260. // Synopsis: Sets the DBPROP_USEEXTENDEDDBTYPES property to TRUE, so
  261. // data is returned in PROPVARIANTs, as opposed to the
  262. // default, which is OLE automation VARIANTs. PROPVARIANTS
  263. // allow a superset of VARIANT data types. Use of these
  264. // types avoids costly coercions.
  265. //
  266. // Also sets the DBPROP_USECONTENTINDEX property to TRUE, so
  267. // the index will always be used to resolve the query (as
  268. // opposed to enumerating all the files on the disk), even
  269. // if the index is out of date. This is set optionally.
  270. //
  271. // Both of these properties are unique to Indexing Service's
  272. // OLE DB implementation.
  273. //
  274. // Arguments: [pICommand] - The ICommand used to set the property
  275. // [fForceUseContentIndex] - TRUE to always use index
  276. // FALSE to allow directory enumeration
  277. //
  278. // Returns: HRESULT result of setting the properties
  279. //
  280. //--------------------------------------------------------------------------
  281. HRESULT SetCommandProperties(
  282. ICommand * pICommand,
  283. BOOL fForceUseContentIndex )
  284. {
  285. static const DBID dbcolNull = { { 0,0,0, { 0,0,0,0,0,0,0,0 } },
  286. DBKIND_GUID_PROPID, 0 };
  287. static const GUID guidQueryExt = DBPROPSET_QUERYEXT;
  288. DBPROP aProp[2];
  289. aProp[0].dwPropertyID = DBPROP_USEEXTENDEDDBTYPES;
  290. aProp[0].dwOptions = DBPROPOPTIONS_OPTIONAL;
  291. aProp[0].dwStatus = 0;
  292. aProp[0].colid = dbcolNull;
  293. aProp[0].vValue.vt = VT_BOOL;
  294. aProp[0].vValue.boolVal = VARIANT_TRUE;
  295. aProp[1] = aProp[0];
  296. aProp[1].dwPropertyID = DBPROP_USECONTENTINDEX;
  297. DBPROPSET aPropSet[1];
  298. aPropSet[0].rgProperties = &aProp[0];
  299. aPropSet[0].cProperties = fForceUseContentIndex ? 2 : 1;
  300. aPropSet[0].guidPropertySet = guidQueryExt;
  301. XInterface<ICommandProperties> xICommandProperties;
  302. HRESULT hr = pICommand->QueryInterface( IID_ICommandProperties,
  303. xICommandProperties.GetQIPointer() );
  304. if ( FAILED( hr ) )
  305. return hr;
  306. return xICommandProperties->SetProperties( 1, // 1 property set
  307. aPropSet ); // the properties
  308. } //SetCommandProperties
  309. //+-------------------------------------------------------------------------
  310. //
  311. // Function: Render
  312. //
  313. // Synopsis: Prints an item in a safearray
  314. //
  315. // Arguments: [vt] - type of the element
  316. // [pa] - pointer to the item
  317. //
  318. //--------------------------------------------------------------------------
  319. void PrintSafeArray( VARTYPE vt, LPSAFEARRAY pa );
  320. void Render( VARTYPE vt, void * pv )
  321. {
  322. if ( VT_ARRAY & vt )
  323. {
  324. PrintSafeArray( vt - VT_ARRAY, *(SAFEARRAY **) pv );
  325. return;
  326. }
  327. switch ( vt )
  328. {
  329. case VT_UI1: wprintf( L"%u", (unsigned) *(BYTE *)pv ); break;
  330. case VT_I1: wprintf( L"%d", (int) *(CHAR *)pv ); break;
  331. case VT_UI2: wprintf( L"%u", (unsigned) *(USHORT *)pv ); break;
  332. case VT_I2: wprintf( L"%d", (int) *(SHORT *)pv ); break;
  333. case VT_UI4:
  334. case VT_UINT: wprintf( L"%u", (unsigned) *(ULONG *)pv ); break;
  335. case VT_I4:
  336. case VT_ERROR:
  337. case VT_INT: wprintf( L"%d", *(LONG *)pv ); break;
  338. case VT_UI8: wprintf( L"%I64u", *(unsigned __int64 *)pv ); break;
  339. case VT_I8: wprintf( L"%I64d", *(__int64 *)pv ); break;
  340. case VT_R4: wprintf( L"%f", *(float *)pv ); break;
  341. case VT_R8: wprintf( L"%lf", *(double *)pv ); break;
  342. case VT_DECIMAL:
  343. {
  344. double dbl;
  345. VarR8FromDec( (DECIMAL *) pv, &dbl );
  346. wprintf( L"%lf", dbl );
  347. break;
  348. }
  349. case VT_CY:
  350. {
  351. double dbl;
  352. VarR8FromCy( * (CY *) pv, &dbl );
  353. wprintf( L"%lf", dbl );
  354. break;
  355. }
  356. case VT_BOOL: wprintf( *(VARIANT_BOOL *)pv ? L"TRUE" : L"FALSE" ); break;
  357. case VT_BSTR: wprintf( L"%ws", *(BSTR *) pv ); break;
  358. case VT_VARIANT:
  359. {
  360. PROPVARIANT * pVar = (PROPVARIANT *) pv;
  361. Render( pVar->vt, & pVar->lVal );
  362. break;
  363. }
  364. case VT_DATE:
  365. {
  366. SYSTEMTIME st;
  367. VariantTimeToSystemTime( *(DATE *)pv, &st );
  368. BOOL pm = st.wHour >= 12;
  369. if ( st.wHour > 12 )
  370. st.wHour -= 12;
  371. else if ( 0 == st.wHour )
  372. st.wHour = 12;
  373. wprintf( L"%2d-%02d-%04d %2d:%02d%wc",
  374. (DWORD) st.wMonth,
  375. (DWORD) st.wDay,
  376. (DWORD) st.wYear,
  377. (DWORD) st.wHour,
  378. (DWORD) st.wMinute,
  379. pm ? L'p' : L'a' );
  380. break;
  381. }
  382. case VT_EMPTY:
  383. case VT_NULL:
  384. break;
  385. default :
  386. {
  387. wprintf( L"(vt 0x%x)", (int) vt );
  388. break;
  389. }
  390. }
  391. } //Render
  392. //+-------------------------------------------------------------------------
  393. //
  394. // Function: PrintSafeArray
  395. //
  396. // Synopsis: Prints items in a safearray
  397. //
  398. // Arguments: [vt] - type of elements in the safearray
  399. // [pa] - pointer to the safearray
  400. //
  401. //--------------------------------------------------------------------------
  402. void PrintSafeArray( VARTYPE vt, LPSAFEARRAY pa )
  403. {
  404. // Get the dimensions of the array
  405. UINT cDim = SafeArrayGetDim( pa );
  406. if ( 0 == cDim )
  407. return;
  408. XPtr<LONG> xDim( cDim );
  409. XPtr<LONG> xLo( cDim );
  410. XPtr<LONG> xUp( cDim );
  411. for ( UINT iDim = 0; iDim < cDim; iDim++ )
  412. {
  413. HRESULT hr = SafeArrayGetLBound( pa, iDim + 1, &xLo[iDim] );
  414. if ( FAILED( hr ) )
  415. return;
  416. xDim[ iDim ] = xLo[ iDim ];
  417. hr = SafeArrayGetUBound( pa, iDim + 1, &xUp[iDim] );
  418. if ( FAILED( hr ) )
  419. return;
  420. wprintf( L"{" );
  421. }
  422. // slog through the array
  423. UINT iLastDim = cDim - 1;
  424. BOOL fDone = FALSE;
  425. while ( !fDone )
  426. {
  427. // inter-element formatting
  428. if ( xDim[ iLastDim ] != xLo[ iLastDim ] )
  429. wprintf( L"," );
  430. // Get the element and render it
  431. void *pv;
  432. SafeArrayPtrOfIndex( pa, xDim.Get(), &pv );
  433. Render( vt, pv );
  434. // Move to the next element and carry if necessary
  435. ULONG cOpen = 0;
  436. for ( LONG iDim = iLastDim; iDim >= 0; iDim-- )
  437. {
  438. if ( xDim[ iDim ] < xUp[ iDim ] )
  439. {
  440. xDim[ iDim ] = 1 + xDim[ iDim ];
  441. break;
  442. }
  443. wprintf( L"}" );
  444. if ( 0 == iDim )
  445. fDone = TRUE;
  446. else
  447. {
  448. cOpen++;
  449. xDim[ iDim ] = xLo[ iDim ];
  450. }
  451. }
  452. for ( ULONG i = 0; !fDone && i < cOpen; i++ )
  453. wprintf( L"{" );
  454. }
  455. } //PrintSafeArray
  456. //+-------------------------------------------------------------------------
  457. //
  458. // Function: PrintVectorItems
  459. //
  460. // Synopsis: Prints items in a PROPVARIANT vector
  461. //
  462. // Arguments: [pVal] - The array of values
  463. // [cVals] - The count of values
  464. // [pcFmt] - The format string
  465. //
  466. //--------------------------------------------------------------------------
  467. template<class T> void PrintVectorItems(
  468. T * pVal,
  469. ULONG cVals,
  470. char * pcFmt )
  471. {
  472. printf( "{ " );
  473. for( ULONG iVal = 0; iVal < cVals; iVal++ )
  474. {
  475. if ( 0 != iVal )
  476. printf( "," );
  477. printf( pcFmt, *pVal++ );
  478. }
  479. printf( " }" );
  480. } //PrintVectorItems
  481. //+-------------------------------------------------------------------------
  482. //
  483. // Function: DisplayValue
  484. //
  485. // Synopsis: Displays a PROPVARIANT value. Limited formatting is done.
  486. //
  487. // Arguments: [pVar] - The value to display
  488. //
  489. //--------------------------------------------------------------------------
  490. void DisplayValue( PROPVARIANT const * pVar )
  491. {
  492. if ( 0 == pVar )
  493. {
  494. wprintf( L"NULL" );
  495. return;
  496. }
  497. // Display the most typical variant types
  498. PROPVARIANT const & v = *pVar;
  499. switch ( v.vt )
  500. {
  501. case VT_EMPTY : break;
  502. case VT_NULL : break;
  503. case VT_I4 : wprintf( L"%10d", v.lVal ); break;
  504. case VT_UI1 : wprintf( L"%10d", v.bVal ); break;
  505. case VT_I2 : wprintf( L"%10d", v.iVal ); break;
  506. case VT_R4 : wprintf( L"%10f", v.fltVal ); break;
  507. case VT_R8 : wprintf( L"%10lf", v.dblVal ); break;
  508. case VT_BOOL : wprintf( v.boolVal ? L"TRUE" : L"FALSE" ); break;
  509. case VT_I1 : wprintf( L"%10d", v.cVal ); break;
  510. case VT_UI2 : wprintf( L"%10u", v.uiVal ); break;
  511. case VT_UI4 : wprintf( L"%10u", v.ulVal ); break;
  512. case VT_INT : wprintf( L"%10d", v.lVal ); break;
  513. case VT_UINT : wprintf( L"%10u", v.ulVal ); break;
  514. case VT_I8 : wprintf( L"%20I64d", v.hVal ); break;
  515. case VT_UI8 : wprintf( L"%20I64u", v.hVal ); break;
  516. case VT_ERROR : wprintf( L"%#x", v.scode ); break;
  517. case VT_LPSTR : wprintf( L"%s", v.pszVal ); break;
  518. case VT_LPWSTR : wprintf( L"%ws", v.pwszVal ); break;
  519. case VT_BSTR : wprintf( L"%ws", v.bstrVal ); break;
  520. case VT_CY:
  521. {
  522. double dbl;
  523. VarR8FromCy( v.cyVal, &dbl );
  524. wprintf( L"%lf", dbl );
  525. break;
  526. }
  527. case VT_DECIMAL :
  528. {
  529. double dbl;
  530. VarR8FromDec( (DECIMAL *) &v.decVal, &dbl );
  531. wprintf( L"%lf", dbl );
  532. break;
  533. }
  534. case VT_FILETIME :
  535. case VT_DATE :
  536. {
  537. SYSTEMTIME st;
  538. if ( VT_DATE == v.vt )
  539. {
  540. VariantTimeToSystemTime( v.date, &st );
  541. }
  542. else
  543. {
  544. FILETIME ft;
  545. FileTimeToLocalFileTime( &v.filetime, &ft );
  546. FileTimeToSystemTime( &ft, &st );
  547. }
  548. BOOL pm = st.wHour >= 12;
  549. if ( st.wHour > 12 )
  550. st.wHour -= 12;
  551. else if ( 0 == st.wHour )
  552. st.wHour = 12;
  553. wprintf( L"%2d-%02d-%04d %2d:%02d%wc",
  554. (DWORD) st.wMonth,
  555. (DWORD) st.wDay,
  556. (DWORD) st.wYear,
  557. (DWORD) st.wHour,
  558. (DWORD) st.wMinute,
  559. pm ? L'p' : L'a' );
  560. break;
  561. }
  562. case VT_VECTOR | VT_I1:
  563. PrintVectorItems( v.cac.pElems, v.cac.cElems, "%d" ); break;
  564. case VT_VECTOR | VT_I2:
  565. PrintVectorItems( v.cai.pElems, v.cai.cElems, "%d" ); break;
  566. case VT_VECTOR | VT_I4:
  567. PrintVectorItems( v.cal.pElems, v.cal.cElems, "%d" ); break;
  568. case VT_VECTOR | VT_I8:
  569. PrintVectorItems( v.cah.pElems, v.cah.cElems, "%I64d" ); break;
  570. case VT_VECTOR | VT_UI1:
  571. PrintVectorItems( v.caub.pElems, v.caub.cElems, "%u" ); break;
  572. case VT_VECTOR | VT_UI2:
  573. PrintVectorItems( v.caui.pElems, v.caui.cElems, "%u" ); break;
  574. case VT_VECTOR | VT_UI4:
  575. PrintVectorItems( v.caul.pElems, v.caul.cElems, "%u" ); break;
  576. case VT_VECTOR | VT_ERROR:
  577. PrintVectorItems( v.cascode.pElems, v.cascode.cElems, "%#x" ); break;
  578. case VT_VECTOR | VT_UI8:
  579. PrintVectorItems( v.cauh.pElems, v.cauh.cElems, "%I64u" ); break;
  580. case VT_VECTOR | VT_BSTR:
  581. PrintVectorItems( v.cabstr.pElems, v.cabstr.cElems, "%ws" ); break;
  582. case VT_VECTOR | VT_LPSTR:
  583. PrintVectorItems( v.calpstr.pElems, v.calpstr.cElems, "%s" ); break;
  584. case VT_VECTOR | VT_LPWSTR:
  585. PrintVectorItems( v.calpwstr.pElems, v.calpwstr.cElems, "%ws" ); break;
  586. case VT_VECTOR | VT_R4:
  587. PrintVectorItems( v.caflt.pElems, v.caflt.cElems, "%f" ); break;
  588. case VT_VECTOR | VT_R8:
  589. PrintVectorItems( v.cadbl.pElems, v.cadbl.cElems, "%lf" ); break;
  590. default :
  591. {
  592. if ( VT_ARRAY & v.vt )
  593. PrintSafeArray( v.vt - VT_ARRAY, v.parray );
  594. else
  595. wprintf( L"vt 0x%05x", v.vt );
  596. break;
  597. }
  598. }
  599. } //DisplayValue
  600. //-----------------------------------------------------------------------------
  601. //
  602. // Function: GetOleDBErrorInfo
  603. //
  604. // Synopsis: Retrieves the secondary error from the OLE DB error object.
  605. //
  606. // Arguments: [pErrSrc] - Pointer to object that posted the error.
  607. // [riid] - Interface that posted the error.
  608. // [lcid] - Locale in which the text is desired.
  609. // [pErrorInfo] - Pointer to memory where ERRORINFO should be.
  610. // [ppIErrorInfo] - Holds the returning IErrorInfo. Caller
  611. // should release this.
  612. //
  613. // Returns: HRESULT for whether the error info was retrieved
  614. //
  615. //-----------------------------------------------------------------------------
  616. HRESULT GetOleDBErrorInfo(
  617. IUnknown * pErrSrc,
  618. REFIID riid,
  619. LCID lcid,
  620. ERRORINFO * pErrorInfo,
  621. IErrorInfo ** ppIErrorInfo )
  622. {
  623. *ppIErrorInfo = 0;
  624. // See if an error is available that is of interest to us.
  625. XInterface<ISupportErrorInfo> xSupportErrorInfo;
  626. HRESULT hr = pErrSrc->QueryInterface( IID_ISupportErrorInfo,
  627. xSupportErrorInfo.GetQIPointer() );
  628. if ( FAILED( hr ) )
  629. return hr;
  630. hr = xSupportErrorInfo->InterfaceSupportsErrorInfo( riid );
  631. if ( FAILED( hr ) )
  632. return hr;
  633. // Get the current error object. Return if none exists.
  634. XInterface<IErrorInfo> xErrorInfo;
  635. hr = GetErrorInfo( 0, xErrorInfo.GetPPointer() );
  636. if ( xErrorInfo.IsNull() )
  637. return hr;
  638. // Get the IErrorRecord interface and get the count of errors.
  639. XInterface<IErrorRecords> xErrorRecords;
  640. hr = xErrorInfo->QueryInterface( IID_IErrorRecords,
  641. xErrorRecords.GetQIPointer() );
  642. if ( FAILED( hr ) )
  643. return hr;
  644. ULONG cErrRecords;
  645. hr = xErrorRecords->GetRecordCount( &cErrRecords );
  646. if ( 0 == cErrRecords )
  647. return hr;
  648. #if 1 // A good way to get the complete error message...
  649. XInterface<IErrorInfo> xErrorInfoRec;
  650. ERRORINFO ErrorInfo;
  651. for ( unsigned i=0; i<cErrRecords; i++ )
  652. {
  653. // Get basic error information.
  654. xErrorRecords->GetBasicErrorInfo( i, &ErrorInfo );
  655. // Get error description and source through the IErrorInfo interface
  656. // pointer on a particular record.
  657. xErrorRecords->GetErrorInfo( i, lcid, xErrorInfoRec.GetPPointer() );
  658. XBStr bstrDescriptionOfError;
  659. XBStr bstrSourceOfError;
  660. BSTR bstrDesc = bstrDescriptionOfError.GetPointer();
  661. BSTR bstrSrc = bstrSourceOfError.GetPointer();
  662. xErrorInfoRec->GetDescription( &bstrDesc );
  663. xErrorInfoRec->GetSource( &bstrSrc );
  664. // At this point, you could call GetCustomErrorObject and query for
  665. // additional interfaces to determine what else happened.
  666. wprintf( L"%s (%#x)\n%s\n", bstrDesc, ErrorInfo.hrError, bstrSrc );
  667. }
  668. #endif
  669. // Get basic error information for the most recent error
  670. ULONG iRecord = cErrRecords - 1;
  671. hr = xErrorRecords->GetBasicErrorInfo( iRecord, pErrorInfo );
  672. if ( FAILED( hr ) )
  673. return hr;
  674. return xErrorRecords->GetErrorInfo( iRecord, lcid, ppIErrorInfo );
  675. } //GetOleDBErrorInfo
  676. //-----------------------------------------------------------------------------
  677. //
  678. // Function: DisplayRowsetStatus
  679. //
  680. // Synopsis: Retrieves status information about the rowset and catalog.
  681. //
  682. // Arguments: [xIRowset] - Rowset about which information is retrieved.
  683. //
  684. // Returns: HRESULT result of retrieving the status
  685. //
  686. //-----------------------------------------------------------------------------
  687. HRESULT DisplayRowsetStatus( XInterface<IRowset> & xIRowset )
  688. {
  689. XInterface<IRowsetInfo> xIRowsetInfo;
  690. HRESULT hr = xIRowset->QueryInterface( IID_IRowsetInfo,
  691. xIRowsetInfo.GetQIPointer() );
  692. if ( SUCCEEDED( hr ) )
  693. {
  694. // This rowset property is Indexing-Service specific
  695. DBPROPID propId = MSIDXSPROP_ROWSETQUERYSTATUS;
  696. DBPROPIDSET propSet;
  697. propSet.rgPropertyIDs = &propId;
  698. propSet.cPropertyIDs = 1;
  699. const GUID guidRowsetExt = DBPROPSET_MSIDXS_ROWSETEXT;
  700. propSet.guidPropertySet = guidRowsetExt;
  701. ULONG cPropertySets = 0;
  702. DBPROPSET * pPropertySets;
  703. hr = xIRowsetInfo->GetProperties( 1,
  704. &propSet,
  705. &cPropertySets,
  706. &pPropertySets );
  707. if ( SUCCEEDED( hr ) )
  708. {
  709. DWORD dwStatus = pPropertySets->rgProperties->vValue.ulVal;
  710. CoTaskMemFree( pPropertySets->rgProperties );
  711. CoTaskMemFree( pPropertySets );
  712. DWORD dwFill = QUERY_FILL_STATUS( dwStatus );
  713. if ( STAT_ERROR == dwFill )
  714. DisplayStat( IDS_ROWSET_STAT_ERROR );
  715. DWORD dwReliability = QUERY_RELIABILITY_STATUS( dwStatus );
  716. if ( 0 != ( STAT_PARTIAL_SCOPE & dwReliability ) )
  717. DisplayStat( IDS_ROWSET_STAT_PARTIAL_SCOPE );
  718. if ( 0 != ( STAT_NOISE_WORDS & dwReliability ) )
  719. DisplayStat( IDS_ROWSET_STAT_NOISE_WORDS );
  720. if ( 0 != ( STAT_CONTENT_OUT_OF_DATE & dwReliability ) )
  721. DisplayStat( IDS_ROWSET_STAT_CONTENT_OUT_OF_DATE );
  722. if ( 0 != ( STAT_REFRESH_INCOMPLETE & dwReliability ) )
  723. DisplayStat( IDS_ROWSET_STAT_REFRESH_INCOMPLETE );
  724. if ( 0 != ( STAT_CONTENT_QUERY_INCOMPLETE & dwReliability ) )
  725. DisplayStat( IDS_ROWSET_STAT_CONTENT_QUERY_INCOMPLETE );
  726. if ( 0 != ( STAT_TIME_LIMIT_EXCEEDED & dwReliability ) )
  727. DisplayStat( IDS_ROWSET_STAT_TIME_LIMIT_EXCEEDED );
  728. if ( 0 != ( STAT_SHARING_VIOLATION & dwReliability ) )
  729. DisplayStat( IDS_ROWSET_STAT_SHARING_VIOLATION );
  730. }
  731. }
  732. return hr;
  733. } //DisplayRowsetStatus
  734. //+-------------------------------------------------------------------------
  735. //
  736. // Function: IssueQuery
  737. //
  738. // Synopsis: Creates and executes a query, then displays the results.
  739. //
  740. // Arguments: [pwcQueryCatalog] - Catalog name over which query is run
  741. // [pwcQueryMachine] - Machine name on which query is run
  742. // [pwcQueryScope] - Scope of the query
  743. // [dwScopeFlags] - Scope flags
  744. // [pwcQueryRestrition] - The actual query string
  745. // [pwcColumns] - Output column names
  746. // [pwcSort] - Sort order names, may be 0
  747. // [fDisplayTree] - TRUE to display the command tree
  748. // [fQuiet] - if TRUE, don't display hitcount
  749. // [fForceUseContentIndex] - TRUE to always use index
  750. // FALSE to allow directory enumeration
  751. // [fNoQuery] - if TRUE, just parse and display query
  752. // [ulDialect] - Query dialect (1 or 2)
  753. // [cMaxHits] - Maximum # of hits, or 0 for no limit
  754. // [lcid] - Locale for the query
  755. //
  756. // Returns: HRESULT result of the query
  757. //
  758. //--------------------------------------------------------------------------
  759. HRESULT IssueQuery(
  760. WCHAR const * pwcQueryCatalog,
  761. WCHAR const * pwcQueryMachine,
  762. WCHAR const * pwcQueryScope,
  763. DWORD dwScopeFlags,
  764. WCHAR const * pwcQueryRestriction,
  765. WCHAR const * pwcColumns,
  766. WCHAR const * pwcSort,
  767. BOOL fDisplayTree,
  768. BOOL fQuiet,
  769. BOOL fForceUseContentIndex,
  770. BOOL fNoQuery,
  771. ULONG ulDialect,
  772. ULONG cMaxHits,
  773. LCID lcid )
  774. {
  775. // Create an ICommand object. CIMakeICommand is a shortcut for making an
  776. // ICommand. The ADVQUERY sample shows the OLE DB equivalent.
  777. XInterface<ICommand> xICommand;
  778. HRESULT hr = CIMakeICommand( xICommand.GetPPointer(), // result
  779. 1, // 1 scope
  780. &dwScopeFlags, // scope flags
  781. &pwcQueryScope, // scope path
  782. &pwcQueryCatalog, // catalog
  783. &pwcQueryMachine ); // machine
  784. if ( FAILED( hr ) )
  785. return hr;
  786. // Get a command tree object
  787. XInterface<ICommandTree> xICommandTree;
  788. hr = xICommand->QueryInterface( IID_ICommandTree,
  789. xICommandTree.GetQIPointer() );
  790. if ( FAILED( hr ) )
  791. return hr;
  792. // Create an OLE DB query tree based on query parameters.
  793. DBCOMMANDTREE * pTree;
  794. hr = CITextToFullTreeEx( pwcQueryRestriction, // the query itself
  795. ulDialect, // query dialect
  796. pwcColumns, // columns to return
  797. pwcSort, // sort order, may be 0
  798. 0, // reserved
  799. &pTree, // resulting tree
  800. 0, // no custom properties
  801. 0, // no custom properties
  802. lcid ); // default locale
  803. if ( FAILED( hr ) )
  804. return hr;
  805. // Limit the maximum number of results if requested by putting a DBOP_top
  806. // node at the top of the query tree.
  807. if ( 0 != cMaxHits )
  808. {
  809. DBCOMMANDTREE * pTop = (DBCOMMANDTREE *) CoTaskMemAlloc( sizeof DBCOMMANDTREE );
  810. if ( 0 == pTop )
  811. {
  812. xICommandTree->FreeCommandTree( &pTree );
  813. return E_OUTOFMEMORY;
  814. }
  815. memset( pTop, 0, sizeof DBCOMMANDTREE );
  816. pTop->op = DBOP_top;
  817. pTop->wKind = DBVALUEKIND_UI4;
  818. pTop->value.ulValue = cMaxHits;
  819. pTop->pctFirstChild = pTree;
  820. pTree = pTop;
  821. }
  822. // If directed, display the command tree.
  823. if ( fDisplayTree )
  824. {
  825. wprintf( L"%ws\n", pwcQueryRestriction );
  826. DisplayCommandTree( pTree );
  827. }
  828. // If directed, don't issue the query. Parsing it was sufficient.
  829. if ( fNoQuery )
  830. {
  831. xICommandTree->FreeCommandTree( &pTree );
  832. return S_OK;
  833. }
  834. // Set the tree in the ICommandTree. Ownership of the tree is transferred.
  835. hr = xICommandTree->SetCommandTree( &pTree,
  836. DBCOMMANDREUSE_NONE,
  837. FALSE );
  838. if ( FAILED( hr ) )
  839. {
  840. xICommandTree->FreeCommandTree( &pTree );
  841. return hr;
  842. }
  843. // Set required properties on the ICommand
  844. hr = SetCommandProperties( xICommand.GetPointer(),
  845. fForceUseContentIndex );
  846. if ( FAILED( hr ) )
  847. return hr;
  848. // Execute the query. The query is complete when Execute() returns.
  849. XInterface<IRowset> xIRowset;
  850. hr = xICommand->Execute( 0, // no aggregating IUnknown
  851. IID_IRowset, // IID for interface to return
  852. 0, // no DBPARAMs
  853. 0, // no rows affected
  854. xIRowset.GetIUPointer() ); // result
  855. if ( FAILED( hr ) )
  856. {
  857. // Get the real error; OLE DB permits few Execute() return codes
  858. ERRORINFO ErrorInfo;
  859. XInterface<IErrorInfo> xErrorInfo;
  860. HRESULT hr2 = GetOleDBErrorInfo( xICommand.GetPointer(),
  861. IID_ICommand,
  862. lcid,
  863. &ErrorInfo,
  864. xErrorInfo.GetPPointer() );
  865. // Post IErrorInfo only if we have a valid pointer to it.
  866. if ( SUCCEEDED( hr2 ) && !xErrorInfo.IsNull() )
  867. hr = ErrorInfo.hrError;
  868. return hr;
  869. }
  870. // Create an accessor, so data can be retrieved from the rowset.
  871. XInterface<IAccessor> xIAccessor;
  872. hr = xIRowset->QueryInterface( IID_IAccessor,
  873. xIAccessor.GetQIPointer() );
  874. if ( FAILED( hr ) )
  875. return hr;
  876. // Count the number of output columns and make bindings for them.
  877. ULONG cColumns = 1;
  878. WCHAR const *pwc = pwcColumns;
  879. while ( 0 != *pwc )
  880. {
  881. if ( L',' == *pwc )
  882. cColumns++;
  883. pwc++;
  884. }
  885. // Column iOrdinals are parallel with those passed to CiTextToFullTree,
  886. // so MapColumnIDs isn't necessary. These binding values for dwPart,
  887. // dwMemOwner, and wType are the most optimal bindings for Indexing
  888. // Service.
  889. XPtr<DBBINDING> xBindings( cColumns );
  890. if ( xBindings.IsNull() )
  891. return E_OUTOFMEMORY;
  892. memset( xBindings.Get(), 0, sizeof DBBINDING * cColumns );
  893. for ( ULONG i = 0; i < cColumns; i++ )
  894. {
  895. xBindings[i].iOrdinal = 1 + i; // 1-based column number
  896. xBindings[i].obValue = i * sizeof( PROPVARIANT * ); // offset
  897. xBindings[i].dwPart = DBPART_VALUE; // retrieve value, not status
  898. xBindings[i].dwMemOwner = DBMEMOWNER_PROVIDEROWNED; // provider owned
  899. xBindings[i].wType = DBTYPE_VARIANT | DBTYPE_BYREF; // VARIANT *
  900. }
  901. HACCESSOR hAccessor;
  902. hr = xIAccessor->CreateAccessor( DBACCESSOR_ROWDATA, // rowdata accessor
  903. cColumns, // # of columns
  904. xBindings.Get(), // columns
  905. 0, // ignored
  906. &hAccessor, // result
  907. 0 ); // no status
  908. if ( FAILED( hr ) )
  909. return hr;
  910. // Display the results of the query.
  911. XPtr<PROPVARIANT *> xData( cColumns );
  912. if ( xData.IsNull() )
  913. hr = E_OUTOFMEMORY;
  914. else
  915. {
  916. DBCOUNTITEM cRowsSoFar = 0;
  917. do
  918. {
  919. DBCOUNTITEM cRowsReturned = 0;
  920. const ULONG cRowsAtATime = 20;
  921. HROW aHRow[cRowsAtATime];
  922. HROW * pgrHRows = aHRow;
  923. hr = xIRowset->GetNextRows( 0, // no chapter
  924. 0, // no rows to skip
  925. cRowsAtATime, // # rows to get
  926. &cRowsReturned, // # rows returned
  927. &pgrHRows); // resulting hrows
  928. if ( FAILED( hr ) )
  929. break;
  930. for ( DBCOUNTITEM iRow = 0; iRow < cRowsReturned; iRow++ )
  931. {
  932. HRESULT hr2 = xIRowset->GetData( aHRow[iRow], // hrow being accessed
  933. hAccessor, // accessor to use
  934. xData.Get() ); // resulting data
  935. if ( FAILED( hr2 ) )
  936. {
  937. hr = hr2;
  938. break;
  939. }
  940. for ( ULONG iCol = 0; iCol < cColumns; iCol++ )
  941. {
  942. if ( 0 != iCol )
  943. wprintf( L" " );
  944. DisplayValue( xData[ iCol ] );
  945. }
  946. wprintf( L"\n" );
  947. }
  948. // Release the HROWs retrived in GetNextRows
  949. if ( 0 != cRowsReturned )
  950. {
  951. cRowsSoFar += cRowsReturned;
  952. xIRowset->ReleaseRows( cRowsReturned, // # of rows to release
  953. aHRow, // rows to release
  954. 0, // no options
  955. 0, // no refcounts
  956. 0 ); // no status
  957. }
  958. // Check if all rows are now retrieved.
  959. if ( DB_S_ENDOFROWSET == hr )
  960. {
  961. hr = S_OK; // succeeded, return S_OK from DoQuery
  962. break;
  963. }
  964. // Check if the query aborted because it was too costly.
  965. if ( DB_S_STOPLIMITREACHED == hr )
  966. {
  967. CResString str( IDS_QUERYTIMEDOUT );
  968. wprintf( L"%ws\n", str.Get() );
  969. hr = S_OK;
  970. break;
  971. }
  972. if ( FAILED( hr ) )
  973. break;
  974. } while ( TRUE );
  975. if ( !fQuiet )
  976. {
  977. CResString str( IDS_QUERYDONE );
  978. wprintf( str.Get(), cRowsSoFar, pwcQueryRestriction );
  979. }
  980. }
  981. xIAccessor->ReleaseAccessor( hAccessor, 0 );
  982. // Get query status information
  983. if ( SUCCEEDED( hr ) && !fQuiet )
  984. hr = DisplayRowsetStatus( xIRowset );
  985. return hr;
  986. } //IssueQuery
  987. //+-------------------------------------------------------------------------
  988. //
  989. // Function: DoQuery
  990. //
  991. // Synopsis: Issues a query and displays an error message on failure
  992. //
  993. // Arguments: [pwcQueryCatalog] - Catalog name over which query is run
  994. // [pwcQueryMachine] - Machine name on which query is run
  995. // [pwcQueryScope] - Scope of the query
  996. // [dwScopeFlags] - Scope flags
  997. // [pwcQueryRestrition] - The actual query string
  998. // [pwcColumns] - Output column names
  999. // [pwcSort] - Sort order names, may be 0
  1000. // [fDisplayTree] - TRUE to display the command tree
  1001. // [fQuiet] - if TRUE, don't display hitcount
  1002. // [fForceUseContentIndex] - TRUE to always use index
  1003. // FALSE to allow directory enumeration
  1004. // [fNoQuery] - if TRUE, just parse and display query
  1005. // [ulDialect] - Query dialect (1 or 2)
  1006. // [cMaxHits] - Maximum # of hits, or 0 for no limit
  1007. // [lcid] - Locale for the query
  1008. //
  1009. // Returns: HRESULT result of the query
  1010. //
  1011. //--------------------------------------------------------------------------
  1012. HRESULT DoQuery(
  1013. WCHAR const * pwcCatalog,
  1014. WCHAR const * pwcMachine,
  1015. WCHAR const * pwcScope,
  1016. DWORD dwScopeFlags,
  1017. WCHAR const * pwcRestriction,
  1018. WCHAR const * pwcColumns,
  1019. WCHAR const * pwcSort,
  1020. BOOL fDisplayTree,
  1021. BOOL fQuiet,
  1022. BOOL fForceUseContentIndex,
  1023. BOOL fNoQuery,
  1024. ULONG ulDialect,
  1025. ULONG cMaxHits,
  1026. LCID lcid )
  1027. {
  1028. HRESULT hr = IssueQuery( pwcCatalog,
  1029. pwcMachine,
  1030. pwcScope,
  1031. dwScopeFlags,
  1032. pwcRestriction,
  1033. pwcColumns,
  1034. pwcSort,
  1035. fDisplayTree,
  1036. fQuiet,
  1037. fForceUseContentIndex,
  1038. fNoQuery,
  1039. ulDialect,
  1040. cMaxHits,
  1041. lcid );
  1042. if ( FAILED( hr ) )
  1043. DisplayError( IDS_QUERYFAILED, pwcRestriction, hr, lcid );
  1044. return hr;
  1045. } //DoQuery
  1046. //+-------------------------------------------------------------------------
  1047. //
  1048. // Function: DoQueryFile
  1049. //
  1050. // Synopsis: Issues each query in the specified query file. A query file
  1051. // is just a text file where each line contains a query.
  1052. //
  1053. // Arguments: [pwcQueryCatalog] - Catalog name over which query is run
  1054. // [pwcQueryMachine] - Machine name on which query is run
  1055. // [pwcQueryScope] - Scope of the query
  1056. // [dwScopeFlags] - Scope flags
  1057. // [pwcColumns] - Output column names
  1058. // [pwcSort] - Sort order names, may be 0
  1059. // [fDisplayTree] - TRUE to display the command tree
  1060. // [fQuiet] - if TRUE, don't display hitcount
  1061. // [fForceUseContentIndex] - TRUE to always use index
  1062. // FALSE to allow directory enumeration
  1063. // [fNoQuery] - if TRUE, just parse and display query
  1064. // [ulDialect] - Query dialect (1 or 2)
  1065. // [cMaxHits] - Maximum # of hits, or 0 for no limit
  1066. // [lcid] - Locale for the query
  1067. // [pwcQueryFile] - File containing queries, 1 per line
  1068. //
  1069. // Returns: HRESULT result of the query
  1070. //
  1071. //--------------------------------------------------------------------------
  1072. HRESULT DoQueryFile(
  1073. WCHAR const * pwcQueryCatalog,
  1074. WCHAR const * pwcQueryMachine,
  1075. WCHAR const * pwcQueryScope,
  1076. DWORD dwScopeFlags,
  1077. WCHAR const * pwcColumns,
  1078. WCHAR const * pwcSort,
  1079. BOOL fDisplayTree,
  1080. BOOL fQuiet,
  1081. BOOL fForceUseContentIndex,
  1082. BOOL fNoQuery,
  1083. ULONG ulDialect,
  1084. ULONG cMaxHits,
  1085. LCID lcid,
  1086. WCHAR const * pwcQueryFile )
  1087. {
  1088. // Open and read the query file
  1089. HANDLE hFile = CreateFile( pwcQueryFile,
  1090. FILE_GENERIC_READ,
  1091. FILE_SHARE_READ | FILE_SHARE_DELETE,
  1092. 0,
  1093. OPEN_EXISTING,
  1094. 0,
  1095. 0 );
  1096. if ( INVALID_HANDLE_VALUE == hFile )
  1097. return DisplayWin32Error( IDS_CANTOPENFILE,
  1098. pwcQueryFile,
  1099. lcid );
  1100. DWORD cbFile = GetFileSize( hFile, 0 );
  1101. if ( 0xffffffff == cbFile )
  1102. return DisplayWin32Error( IDS_CANTGETFILESIZE,
  1103. pwcQueryFile,
  1104. lcid );
  1105. // Allocate a buffer for the file
  1106. XPtr<BYTE> xQueries( cbFile + sizeof WCHAR );
  1107. if ( xQueries.IsNull() )
  1108. {
  1109. CloseHandle( hFile );
  1110. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  1111. return DisplayWin32Error( IDS_CANTGETMEMORY,
  1112. pwcQueryFile,
  1113. lcid );
  1114. }
  1115. // Read the file into the buffer
  1116. DWORD cbRead;
  1117. BOOL fRead = ReadFile( hFile, xQueries.Get(), cbFile, &cbRead, 0 );
  1118. CloseHandle( hFile );
  1119. if ( ! fRead )
  1120. return DisplayWin32Error( IDS_CANTREADFROMFILE,
  1121. pwcQueryFile,
  1122. lcid );
  1123. // Check if the file is Unicode already
  1124. BOOL fUnicode = ( 0xfeff == ( * (WCHAR *) xQueries.Get() ) );
  1125. WCHAR * pwcIn = 0;
  1126. DWORD cwcIn = 0;
  1127. if ( fUnicode )
  1128. {
  1129. pwcIn = (WCHAR *) xQueries.Get();
  1130. // skip past the Unicode marker
  1131. pwcIn++;
  1132. cwcIn = ( cbFile / sizeof WCHAR ) - 1;
  1133. }
  1134. else
  1135. {
  1136. // Convert to Unicode. Leave a little room for slack.
  1137. DWORD cbTmp = cbFile * sizeof WCHAR + cbFile / 8;
  1138. XPtr<BYTE> xTmp( cbTmp + sizeof WCHAR );
  1139. if ( xTmp.IsNull() )
  1140. {
  1141. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  1142. return DisplayWin32Error( IDS_CANTGETMEMORY,
  1143. pwcQueryFile,
  1144. lcid );
  1145. }
  1146. cwcIn = MultiByteToWideChar( LocaleToCodepage( lcid ),
  1147. 0,
  1148. (const char *) xQueries.Get(),
  1149. cbFile,
  1150. (WCHAR *) xTmp.Get(),
  1151. cbTmp );
  1152. if ( 0 == cwcIn )
  1153. return DisplayWin32Error( IDS_CANTCONVERTTOUNICODE,
  1154. pwcQueryFile,
  1155. lcid );
  1156. pwcIn = (WCHAR *) xTmp.Get();
  1157. xQueries.Free();
  1158. xQueries.Set( xTmp.Acquire() );
  1159. }
  1160. // Read each line in the file and issue the query
  1161. pwcIn[ cwcIn ] = 0;
  1162. WCHAR * pwc = pwcIn;
  1163. do
  1164. {
  1165. while ( 0 != *pwcIn &&
  1166. L'\r' != *pwcIn &&
  1167. L'\n' != *pwcIn )
  1168. pwcIn++;
  1169. BOOL fEOF = ( 0 == *pwcIn );
  1170. *pwcIn = 0;
  1171. if ( pwc != pwcIn )
  1172. {
  1173. DoQuery( pwcQueryCatalog,
  1174. pwcQueryMachine,
  1175. pwcQueryScope,
  1176. dwScopeFlags,
  1177. pwc,
  1178. pwcColumns,
  1179. pwcSort,
  1180. fDisplayTree,
  1181. fQuiet,
  1182. fForceUseContentIndex,
  1183. fNoQuery,
  1184. ulDialect,
  1185. cMaxHits,
  1186. lcid );
  1187. wprintf( L"\n\n" );
  1188. }
  1189. if ( fEOF )
  1190. break;
  1191. pwcIn++;
  1192. while ( '\r' == *pwcIn || '\n' == *pwcIn )
  1193. pwcIn++;
  1194. pwc = pwcIn;
  1195. } while ( TRUE );
  1196. return S_OK;
  1197. } //DoQueryFile
  1198. //+-------------------------------------------------------------------------
  1199. //
  1200. // Function: Usage
  1201. //
  1202. // Synopsis: Displays information about how to use the app and exits
  1203. //
  1204. //--------------------------------------------------------------------------
  1205. void Usage()
  1206. {
  1207. HRSRC hrc = FindResource( 0, (LPCWSTR) IDR_USAGE, RT_RCDATA );
  1208. if ( 0 != hrc )
  1209. {
  1210. HGLOBAL hg = LoadResource( 0, hrc );
  1211. if ( 0 != hg )
  1212. {
  1213. void * pv = LockResource( hg );
  1214. if ( 0 != pv )
  1215. wprintf( L"%ws\n", pv );
  1216. }
  1217. }
  1218. exit( -1 );
  1219. } //Usage
  1220. //+-------------------------------------------------------------------------
  1221. //
  1222. // Function: LcidFromHttpAcceptLanguage
  1223. //
  1224. // Synopsis: Looks up an LCID given an HTTP Accept Language string
  1225. //
  1226. // Arguments: [pwc] - The string to look up
  1227. //
  1228. // Returns: The matching LCID.
  1229. //
  1230. //--------------------------------------------------------------------------
  1231. LCID LcidFromHttpAcceptLanguage( WCHAR const * pwc )
  1232. {
  1233. // Default to the system locale
  1234. if ( 0 == pwc )
  1235. return GetSystemDefaultLCID();
  1236. struct SHttpLocale
  1237. {
  1238. WCHAR const * pwcLanguage;
  1239. LCID lcid;
  1240. WCHAR const * pwcHttpAcceptLanguage;
  1241. WCHAR const * pwcHttpAcceptLanguageAbbr;
  1242. };
  1243. const struct SHttpLocale aHttpLocale[] =
  1244. {
  1245. L"Afrikaans", 0x0436, L"af", L"af",
  1246. L"Albanian", 0x041c, L"sq", L"sq",
  1247. L"Arabic(Saudi Arabia)", 0x0401, L"ar-sa", L"arsa",
  1248. L"Arabic(Iraq)", 0x0801, L"ar-iq", L"ariq",
  1249. L"Arabic(Egypt)", 0x0C01, L"ar-eg", L"areg",
  1250. L"Arabic(Libya)", 0x1001, L"ar-ly", L"arly",
  1251. L"Arabic(Algeria)", 0x1401, L"ar-dz", L"ardz",
  1252. L"Arabic(Morocco)", 0x1801, L"ar-ma", L"arma",
  1253. L"Arabic(Tunisia)", 0x1C01, L"ar-tn", L"artn",
  1254. L"Arabic(Oman)", 0x2001, L"ar-om", L"arom",
  1255. L"Arabic(Yemen)", 0x2401, L"ar-ye", L"arye",
  1256. L"Arabic(Syria)", 0x2801, L"ar-sy", L"arsy",
  1257. L"Arabic(Jordan)", 0x2C01, L"ar-jo", L"arjo",
  1258. L"Arabic(Lebanon)", 0x3001, L"ar-lb", L"arlb",
  1259. L"Arabic(Kuwait)", 0x3401, L"ar-kw", L"arkw",
  1260. L"Arabic(U.A.E.)", 0x3801, L"ar-ae", L"arae",
  1261. L"Arabic(Bahrain)", 0x3C01, L"ar-bh", L"arbh",
  1262. L"Arabic(Qatar)", 0x4001, L"ar-qa", L"arqa",
  1263. L"Basque", 0x042D, L"eu", L"eu",
  1264. L"Bulgarian", 0x0402, L"bg", L"bg",
  1265. L"Belarusian", 0x0423, L"be", L"be",
  1266. L"Catalan", 0x0403, L"ca", L"ca",
  1267. L"Chinese(Taiwan)", 0x0404, L"zh-tw", L"zhtw",
  1268. L"Chinese(PRC)", 0x0804, L"zh-cn", L"zhcn",
  1269. L"Chinese(Hong Kong SAR)", 0x0C04, L"zh-hk", L"zhhk",
  1270. L"Chinese(Singapore)", 0x1004, L"zh-sg", L"zhsg",
  1271. L"Croatian", 0x041a, L"hr", L"hr",
  1272. L"Czech", 0x0405, L"cs", L"cs",
  1273. L"Danish", 0x0406, L"da", L"da",
  1274. L"Dutch(Standard)", 0x0413, L"nl", L"nl",
  1275. L"Dutch(Belgian)", 0x0813, L"nl-be", L"nlbe",
  1276. L"English", 0x0009, L"en", L"en",
  1277. L"English(United States)", 0x0409, L"en-us", L"enus",
  1278. L"English(British)", 0x0809, L"en-gb", L"engb",
  1279. L"English(Australian)", 0x0c09, L"en-au", L"enau",
  1280. L"English(Canadian)", 0x1009, L"en-ca", L"enca",
  1281. L"English(New Zealand)", 0x1409, L"en-nz", L"ennz",
  1282. L"English(Ireland)", 0x1809, L"en-ie", L"enie",
  1283. L"English(South Africa)", 0x1c09, L"en-za", L"enza",
  1284. L"English(Jamaica)", 0x2009, L"en-jm", L"enjm",
  1285. L"English(Caribbean)", 0x2409, L"en", L"en",
  1286. L"English(Belize)", 0x2809, L"en-bz", L"enbz",
  1287. L"English(Trinidad)", 0x2c09, L"en-tt", L"entt",
  1288. L"Estonian", 0x0425, L"et", L"et",
  1289. L"Faeroese", 0x0438, L"fo", L"fo",
  1290. L"Farsi", 0x0429, L"fa", L"fa",
  1291. L"Finnish", 0x040b, L"fi", L"fi",
  1292. L"French(Standard)", 0x040c, L"fr", L"fr",
  1293. L"French(Belgian)", 0x080c, L"fr-be", L"frbe",
  1294. L"French(Canadian)", 0x0c0c, L"fr-ca", L"frca",
  1295. L"French(Swiss)", 0x100c, L"fr-ch", L"frch",
  1296. L"French(Luxembourg)", 0x140c, L"fr-lu", L"frlu",
  1297. L"Gaelic(Scots)", 0x043c, L"gd", L"gd",
  1298. L"Gaelic(Irish)", 0x083c, L"gd-ie", L"gdie",
  1299. L"German(Standard)", 0x0407, L"de", L"de",
  1300. L"German(Swiss)", 0x0807, L"de-ch", L"dech",
  1301. L"German(Austrian)", 0x0c07, L"de-at", L"deat",
  1302. L"German(Luxembourg)", 0x1007, L"de-lu", L"delu",
  1303. L"German(Liechtenstein)", 0x1407, L"de-li", L"deli",
  1304. L"Greek", 0x0408, L"el", L"el",
  1305. L"Hebrew", 0x040D, L"he", L"he",
  1306. L"Hindi", 0x0439, L"hi", L"hi",
  1307. L"Hungarian", 0x040e, L"hu", L"hu",
  1308. L"Icelandic", 0x040F, L"is", L"is",
  1309. L"Indonesian", 0x0421, L"in", L"in",
  1310. L"Italian(Standard)", 0x0410, L"it", L"it",
  1311. L"Italian(Swiss)", 0x0810, L"it-ch", L"itch",
  1312. L"Japanese", 0x0411, L"ja", L"ja",
  1313. L"Korean", 0x0412, L"ko", L"ko",
  1314. L"Korean(Johab)", 0x0812, L"ko", L"ko",
  1315. L"Latvian", 0x0426, L"lv", L"lv",
  1316. L"Lithuanian", 0x0427, L"lt", L"lt",
  1317. L"FYRO Macedonian", 0x042f, L"mk", L"mk",
  1318. L"Malaysian", 0x043e, L"ms", L"ms",
  1319. L"Maltese", 0x043a, L"mt", L"mt",
  1320. L"Norwegian(Bokmal)", 0x0414, L"no", L"no",
  1321. L"Norwegian(Nynorsk)", 0x0814, L"no", L"no",
  1322. L"Polish", 0x0415, L"pl", L"pl",
  1323. L"Portuguese(Brazilian)", 0x0416, L"pt-br", L"ptbr",
  1324. L"Portuguese(Standard)", 0x0816, L"pt", L"pt",
  1325. L"Rhaeto-Romanic", 0x0417, L"rm", L"rm",
  1326. L"Romanian", 0x0418, L"ro", L"ro",
  1327. L"Romanian(Moldavia)", 0x0818, L"ro-mo", L"romo",
  1328. L"Russian", 0x0419, L"ru", L"ru",
  1329. L"Russian(Moldavia)", 0x0819, L"ru-mo", L"rumo",
  1330. L"Sami(Lappish)", 0x043b, L"sz", L"sz",
  1331. L"Serbian(Cyrillic)", 0x0c1a, L"sr", L"sr",
  1332. L"Serbian(Latin)", 0x081a, L"sr", L"sr",
  1333. L"Slovak", 0x041b, L"sk", L"sk",
  1334. L"Slovenian", 0x0424, L"sl", L"sl",
  1335. L"Sorbian", 0x042e, L"sb", L"sb",
  1336. L"Spanish(Spain - Traditional Sort)", 0x040a, L"es", L"es",
  1337. L"Spanish(Mexican)", 0x080a, L"es-mx", L"esmx",
  1338. L"Spanish(Spain - Modern Sort)", 0x0c0a, L"es", L"es",
  1339. L"Spanish(Guatemala)", 0x100a, L"es-gt", L"esgt",
  1340. L"Spanish(Costa Rica)", 0x140a, L"es-cr", L"escr",
  1341. L"Spanish(Panama)", 0x180a, L"es-pa", L"espa",
  1342. L"Spanish(Dominican Republic)", 0x1c0a, L"es-do", L"esdo",
  1343. L"Spanish(Venezuela)", 0x200a, L"es-ve", L"esve",
  1344. L"Spanish(Colombia)", 0x240a, L"es-co", L"esco",
  1345. L"Spanish(Peru)", 0x280a, L"es-pe", L"espe",
  1346. L"Spanish(Argentina)", 0x2c0a, L"es-ar", L"esar",
  1347. L"Spanish(Ecuador)", 0x300a, L"es-ec", L"esec",
  1348. L"Spanish(Chile)", 0x340a, L"es-cl", L"escl",
  1349. L"Spanish(Uruguay)", 0x380a, L"es-uy", L"esuy",
  1350. L"Spanish(Paraguay)", 0x3c0a, L"es-py", L"espy",
  1351. L"Spanish(Bolivia)", 0x400a, L"es-bo", L"esbo",
  1352. L"Spanish(El Salvador)", 0x440a, L"es-sv", L"essv",
  1353. L"Spanish(Honduras)", 0x480a, L"es-hn", L"eshn",
  1354. L"Spanish(Nicaragua)", 0x4c0a, L"es-ni", L"esni",
  1355. L"Spanish(Puerto Rico)", 0x500a, L"es-pr", L"espr",
  1356. L"Sutu", 0x0430, L"sx", L"sx",
  1357. L"Swedish", 0x041D, L"sv", L"sv",
  1358. L"Swedish(Finland)", 0x081d, L"sv-fi", L"svfi",
  1359. L"Thai", 0x041E, L"th", L"th",
  1360. L"Tsonga", 0x0431, L"ts", L"ts",
  1361. L"Tswana", 0x0432, L"tn", L"tn",
  1362. L"Turkish", 0x041f, L"tr", L"tr",
  1363. L"Ukrainian", 0x0422, L"uk", L"uk",
  1364. L"Urdu", 0x0420, L"ur", L"ur",
  1365. L"Venda", 0x0433, L"ve", L"ve",
  1366. L"Vietnamese", 0x042a, L"vi", L"vi",
  1367. L"Xhosa", 0x0434, L"xh", L"xh",
  1368. L"Yiddish", 0x043d, L"ji", L"ji",
  1369. L"Zulu", 0x0435, L"zu", L"zu",
  1370. L"Neutral", MAKELCID( MAKELANGID( LANG_NEUTRAL, SUBLANG_NEUTRAL ), SORT_DEFAULT ), L"neutr", L"neutr",
  1371. };
  1372. const unsigned cHttpLocale = sizeof aHttpLocale / sizeof aHttpLocale[0];
  1373. for ( unsigned i = 0; i < cHttpLocale; i++ )
  1374. if ( !_wcsicmp( aHttpLocale[ i ].pwcHttpAcceptLanguage, pwc ) ||
  1375. !_wcsicmp( aHttpLocale[ i ].pwcHttpAcceptLanguageAbbr, pwc ) )
  1376. return aHttpLocale[ i ].lcid;
  1377. Usage();
  1378. return 0;
  1379. } //LcidFromHttpAcceptLanguage
  1380. //+-------------------------------------------------------------------------
  1381. //
  1382. // Function: LookupCatalog
  1383. //
  1384. // Synopsis: Looks for a catalog and machine matching the scope
  1385. //
  1386. // Arguments: [pwcScope] - The scope used to find the catalog
  1387. // [pwcMachine] - Returns the machine name
  1388. // [cwcMachine] - In/Out: Count of characters in pwcMachine
  1389. // [pwcCatalog] - Returns the catalog name
  1390. // [cwcCatalog] - In/Out: Count of characters in pwcCatalog
  1391. // [lcid] - Locale to use for errors
  1392. //
  1393. //--------------------------------------------------------------------------
  1394. HRESULT LookupCatalog(
  1395. WCHAR const * pwcScope,
  1396. WCHAR * pwcMachine,
  1397. ULONG & cwcMachine,
  1398. WCHAR * pwcCatalog,
  1399. ULONG & cwcCatalog,
  1400. LCID lcid )
  1401. {
  1402. HRESULT hr = LocateCatalogs( pwcScope, // scope to lookup
  1403. 0, // go with the first match
  1404. pwcMachine, // returns the machine
  1405. &cwcMachine, // buffer size in/out
  1406. pwcCatalog, // returns the catalog
  1407. &cwcCatalog ); // buffer size in/out
  1408. if ( FAILED( hr ) || ( S_FALSE == hr ) )
  1409. {
  1410. DisplayError( IDS_CANTFINDCATALOG, pwcScope, hr, lcid );
  1411. hr = E_FAIL;
  1412. }
  1413. return hr;
  1414. } //LookupCatalog
  1415. //+-------------------------------------------------------------------------
  1416. //
  1417. // Function: NormalizeScope
  1418. //
  1419. // Synopsis: Normalizes a scope and sets scope flags.
  1420. //
  1421. // Arguments: [pwcIn] - The scope for the query
  1422. // [pwcOut] - Returns the scope for the query
  1423. // [dwScopeFlags] - Returns the scope flags for the query
  1424. //
  1425. //--------------------------------------------------------------------------
  1426. HRESULT NormalizeScope(
  1427. WCHAR const * pwcIn,
  1428. WCHAR * pwcOut,
  1429. BOOL fShallow,
  1430. DWORD & dwScopeFlags )
  1431. {
  1432. if ( wcslen( pwcIn ) >= MAX_PATH )
  1433. return E_INVALIDARG;
  1434. if ( fShallow )
  1435. dwScopeFlags = QUERY_SHALLOW;
  1436. else
  1437. dwScopeFlags = QUERY_DEEP;
  1438. wcscpy( pwcOut, pwcIn );
  1439. // Check if the scope is an IIS virtual scope.
  1440. WCHAR wc = pwcIn[0];
  1441. if ( L'/' == wc )
  1442. {
  1443. // Set the virtual scope flag and flip the slashes.
  1444. dwScopeFlags |= QUERY_VIRTUAL_PATH;
  1445. for ( WCHAR * pwc = pwcOut; *pwc; pwc++ )
  1446. if ( '/' == *pwc )
  1447. *pwc = '\\';
  1448. }
  1449. else if ( ( !( L'\\' == wc && L'\\' == pwcIn[1] ) ) &&
  1450. ( !( L'\\' == wc && 0 == pwcIn[1] ) ) &&
  1451. L':' != pwcIn[1] &&
  1452. 0 != wc )
  1453. {
  1454. // Turn the relative path into a full path based on the current dir.
  1455. _wfullpath( pwcOut, pwcIn, MAX_PATH );
  1456. }
  1457. return S_OK;
  1458. } //NormalizeScope
  1459. //+-------------------------------------------------------------------------
  1460. //
  1461. // Function: DisplayStatus
  1462. //
  1463. // Synopsis: Displays status information about a catalog
  1464. //
  1465. // Arguments: [pwcCatalog] - Catalog name
  1466. // [pwcMachine] - Machine on which catalog resides
  1467. // [lcid] - Locale to use
  1468. //
  1469. //--------------------------------------------------------------------------
  1470. HRESULT DisplayStatus(
  1471. WCHAR const * pwcCatalog,
  1472. WCHAR const * pwcMachine,
  1473. LCID lcid )
  1474. {
  1475. CI_STATE state;
  1476. state.cbStruct = sizeof state;
  1477. DisplayStat( pwcMachine, IDS_STAT_MACHINE );
  1478. DisplayStat( pwcCatalog, IDS_STAT_CATALOG );
  1479. HRESULT hr = CIState( pwcCatalog, pwcMachine, &state );
  1480. if ( SUCCEEDED( hr ) )
  1481. {
  1482. DisplayStat( state.cTotalDocuments, IDS_STAT_TOTALDOCUMENTS );
  1483. DisplayStat( state.cFreshTest, IDS_STAT_FRESHTEST );
  1484. DisplayStat( state.cFilteredDocuments, IDS_STAT_FILTEREDDOCUMENTS );
  1485. DisplayStat( state.cDocuments, IDS_STAT_DOCUMENTS );
  1486. DisplayStat( state.cSecQDocuments, IDS_STAT_SECQDOCUMENTS );
  1487. DisplayStat( state.cUniqueKeys, IDS_STAT_UNIQUEKEYS );
  1488. DisplayStat( state.cWordList, IDS_STAT_WORDLIST );
  1489. DisplayStat( state.cPersistentIndex, IDS_STAT_PERSISTENTINDEX );
  1490. DisplayStat( state.cQueries, IDS_STAT_QUERIES );
  1491. DisplayStat( state.dwIndexSize, IDS_STAT_INDEXSIZE );
  1492. DisplayStat( state.dwPropCacheSize / 1024, IDS_STAT_PROPCACHESIZE );
  1493. DisplayStat( ( state.eState & CI_STATE_SCANNING ) ?
  1494. state.cPendingScans : 0,
  1495. IDS_STAT_SCANS );
  1496. const DWORD ALL_CI_MERGE = ( CI_STATE_SHADOW_MERGE |
  1497. CI_STATE_ANNEALING_MERGE |
  1498. CI_STATE_INDEX_MIGRATION_MERGE |
  1499. CI_STATE_MASTER_MERGE |
  1500. CI_STATE_MASTER_MERGE_PAUSED );
  1501. if ( 0 != ( ALL_CI_MERGE & state.eState ) )
  1502. {
  1503. UINT idStr;
  1504. if ( state.eState & CI_STATE_SHADOW_MERGE )
  1505. idStr = IDS_STAT_MERGE_SHADOW;
  1506. else if ( state.eState & CI_STATE_ANNEALING_MERGE )
  1507. idStr = IDS_STAT_MERGE_ANNEALING;
  1508. else if ( state.eState & CI_STATE_INDEX_MIGRATION_MERGE )
  1509. idStr = IDS_STAT_MERGE_INDEX_MIGRATION;
  1510. else if ( state.eState & CI_STATE_MASTER_MERGE )
  1511. idStr = IDS_STAT_MERGE_MASTER;
  1512. else
  1513. idStr = IDS_STAT_MERGE_MASTER_PAUSED;
  1514. DisplayStat( state.dwMergeProgress, idStr );
  1515. }
  1516. if ( CI_STATE_READ_ONLY & state.eState )
  1517. DisplayStat( IDS_STAT_READ_ONLY );
  1518. if ( CI_STATE_RECOVERING & state.eState )
  1519. DisplayStat( IDS_STAT_RECOVERING );
  1520. if ( CI_STATE_LOW_MEMORY & state.eState )
  1521. DisplayStat( IDS_STAT_LOW_MEMORY );
  1522. if ( CI_STATE_HIGH_IO & state.eState )
  1523. DisplayStat( IDS_STAT_HIGH_IO );
  1524. if ( CI_STATE_BATTERY_POWER & state.eState )
  1525. DisplayStat( IDS_STAT_BATTERY_POWER );
  1526. if ( CI_STATE_USER_ACTIVE & state.eState )
  1527. DisplayStat( IDS_STAT_USER_ACTIVE );
  1528. if ( CI_STATE_STARTING & state.eState )
  1529. DisplayStat( IDS_STAT_STARTING );
  1530. if ( CI_STATE_READING_USNS & state.eState )
  1531. DisplayStat( IDS_STAT_READING_USNS );
  1532. }
  1533. else
  1534. {
  1535. DisplayError( IDS_CANTDISPLAYSTATUS, pwcCatalog, hr, lcid );
  1536. }
  1537. return hr;
  1538. } //DisplayStatus
  1539. //+-------------------------------------------------------------------------
  1540. //
  1541. // Function: DisplayUpToDate
  1542. //
  1543. // Synopsis: Checks if the index is up to date.
  1544. //
  1545. // Arguments: [pwcCatalog] - Catalog name
  1546. // [pwcMachine] - Machine on which catalog resides
  1547. // [lcid] - Locale to use
  1548. //
  1549. //--------------------------------------------------------------------------
  1550. HRESULT DisplayUpToDate(
  1551. WCHAR const * pwcCatalog,
  1552. WCHAR const * pwcMachine,
  1553. LCID lcid )
  1554. {
  1555. CI_STATE state;
  1556. state.cbStruct = sizeof state;
  1557. HRESULT hr = CIState( pwcCatalog, pwcMachine, &state );
  1558. if ( SUCCEEDED( hr ) )
  1559. {
  1560. // It's up to date if there are no documents to filter, no scans or
  1561. // usn activity, and the index isn't starting or recovering.
  1562. BOOL fUpToDate = ( ( 0 == state.cDocuments ) &&
  1563. ( 0 == ( state.eState & CI_STATE_SCANNING ) ) &&
  1564. ( 0 == ( state.eState & CI_STATE_READING_USNS ) ) &&
  1565. ( 0 == ( state.eState & CI_STATE_STARTING ) ) &&
  1566. ( 0 == ( state.eState & CI_STATE_RECOVERING ) ) );
  1567. DisplayStat( fUpToDate ? IDS_STAT_UP_TO_DATE :
  1568. IDS_STAT_NOT_UP_TO_DATE );
  1569. }
  1570. else
  1571. {
  1572. DisplayError( IDS_CANTDISPLAYSTATUS, pwcCatalog, hr, lcid );
  1573. }
  1574. return hr;
  1575. } //DisplayUpToDate
  1576. //+-------------------------------------------------------------------------
  1577. //
  1578. // Function: wmain
  1579. //
  1580. // Synopsis: Entry point for the app. Parses command line arguments and
  1581. // issues a query.
  1582. //
  1583. // Arguments: [argc] - Argument count
  1584. // [argv] - Arguments
  1585. //
  1586. //--------------------------------------------------------------------------
  1587. extern "C" int __cdecl wmain( int argc, WCHAR * argv[] )
  1588. {
  1589. WCHAR const * pwcCatalog = 0; // default: lookup catalog
  1590. WCHAR const * pwcMachine = L"."; // default: local machine
  1591. WCHAR const * pwcScope = L"\\"; // default: entire catalog
  1592. WCHAR const * pwcRestriction = 0; // no default restriction
  1593. WCHAR const * pwcColumns = L"path"; // default output column(s)
  1594. WCHAR const * pwcSort = 0; // no sort is the default
  1595. WCHAR const * pwcQueryFile = 0; // no query file specified
  1596. WCHAR const * pwcLocale = 0; // default: system locale
  1597. BOOL fDisplayTree = FALSE; // don't display the tree
  1598. BOOL fForceUseContentIndex = TRUE; // always use the index
  1599. ULONG ulDialect = 1; // original query language dialect
  1600. BOOL fQuiet = FALSE; // show the hitcount
  1601. ULONG cMaxHits = 0; // default: retrieve all hits
  1602. BOOL fDisplayStatus = FALSE; // default: don't show status
  1603. BOOL fDisplayUpToDate = FALSE; // default: don't show up to date
  1604. ULONG cRepetitions = 1; // # of times to repeat command
  1605. BOOL fShallow = FALSE; // default: all subdirectories
  1606. BOOL fNoQuery = FALSE; // default: execute query
  1607. // Parse command line parameters
  1608. for ( int i = 1; i < argc; i++ )
  1609. {
  1610. if ( L'-' == argv[i][0] || L'/' == argv[i][0] )
  1611. {
  1612. WCHAR wc = (WCHAR) toupper( (char) argv[i][1] );
  1613. if ( ':' != argv[i][2] &&
  1614. 'D' != wc &&
  1615. 'J' != wc &&
  1616. 'N' != wc &&
  1617. 'Q' != wc &&
  1618. 'U' != wc &&
  1619. 'T' != wc )
  1620. Usage();
  1621. if ( 'C' == wc )
  1622. pwcCatalog = argv[i] + 3;
  1623. else if ( 'M' == wc )
  1624. pwcMachine = argv[i] + 3;
  1625. else if ( 'P' == wc )
  1626. pwcScope = argv[i] + 3;
  1627. else if ( 'O' == wc )
  1628. pwcColumns = argv[i] + 3;
  1629. else if ( 'S' == wc )
  1630. pwcSort = argv[i] + 3;
  1631. else if ( 'X' == wc )
  1632. cMaxHits = _wtoi( argv[i] + 3 );
  1633. else if ( 'I' == wc )
  1634. {
  1635. if ( 0 != pwcRestriction )
  1636. Usage();
  1637. pwcQueryFile = argv[i] + 3;
  1638. }
  1639. else if ( 'R' == wc)
  1640. {
  1641. // get the next arg as a number
  1642. cRepetitions = _wtol(argv[i]+3);
  1643. }
  1644. else if ( 'D' == wc )
  1645. fDisplayTree = TRUE;
  1646. else if ( 'J' == wc )
  1647. fShallow = TRUE;
  1648. else if ( 'N' == wc )
  1649. fNoQuery = TRUE;
  1650. else if ( 'Q' == wc )
  1651. fQuiet = TRUE;
  1652. else if ( 'T' == wc )
  1653. fDisplayStatus = TRUE;
  1654. else if ( 'U' == wc )
  1655. fDisplayUpToDate = TRUE;
  1656. else if ( 'E' == wc )
  1657. pwcLocale = argv[i] + 3;
  1658. else if ( 'L' == wc )
  1659. {
  1660. if ( '1' == argv[i][3] )
  1661. ulDialect = 1;
  1662. else if ( '2' == argv[i][3] )
  1663. ulDialect = 2;
  1664. else
  1665. Usage();
  1666. }
  1667. else if ( 'F' == wc )
  1668. {
  1669. if ( '+' == argv[i][3] )
  1670. fForceUseContentIndex = TRUE;
  1671. else if ( '-' == argv[i][3] )
  1672. fForceUseContentIndex = FALSE;
  1673. else
  1674. Usage();
  1675. }
  1676. else
  1677. Usage();
  1678. }
  1679. else if ( 0 != pwcRestriction || 0 != pwcQueryFile )
  1680. Usage();
  1681. else
  1682. pwcRestriction = argv[i];
  1683. }
  1684. // A query restriction, query file, or status request is necessary.
  1685. if ( 0 == pwcRestriction && 0 == pwcQueryFile &&
  1686. !fDisplayStatus && !fDisplayUpToDate)
  1687. Usage();
  1688. // Get the locale identifier to use for the query
  1689. LCID lcid = LcidFromHttpAcceptLanguage( pwcLocale );
  1690. // Normalize relative and virtual scopes
  1691. WCHAR awcScope[ MAX_PATH ];
  1692. DWORD dwScopeFlags;
  1693. HRESULT hr = NormalizeScope( pwcScope, awcScope, fShallow, dwScopeFlags );
  1694. // Initialize OLE
  1695. BOOL fCoInit = FALSE;
  1696. if ( SUCCEEDED( hr ) )
  1697. {
  1698. hr = CoInitialize( 0 );
  1699. if ( SUCCEEDED( hr ) )
  1700. fCoInit = TRUE;
  1701. }
  1702. // If no catalog was specified, infer one based on the scope
  1703. WCHAR awcMachine[ MAX_PATH ], awcCatalog[ MAX_PATH ];
  1704. if ( SUCCEEDED( hr ) && ( 0 == pwcCatalog ) && !fNoQuery )
  1705. {
  1706. ULONG cwcMachine = sizeof awcMachine / sizeof WCHAR;
  1707. ULONG cwcCatalog = sizeof awcCatalog / sizeof WCHAR;
  1708. hr = LookupCatalog( awcScope,
  1709. awcMachine,
  1710. cwcMachine,
  1711. awcCatalog,
  1712. cwcCatalog,
  1713. lcid );
  1714. pwcMachine = awcMachine;
  1715. pwcCatalog = awcCatalog;
  1716. // Turn scopes like \\machine into \ now that the lookup is done
  1717. // and we've found a catalog and machine name.
  1718. if ( SUCCEEDED( hr ) &&
  1719. L'\\' == awcScope[0] && L'\\' == awcScope[1] &&
  1720. 0 == wcschr( awcScope + 2, L'\\' ) )
  1721. awcScope[1] = 0;
  1722. }
  1723. if ( SUCCEEDED( hr ) )
  1724. {
  1725. for (ULONG j = 0; j < cRepetitions; j++)
  1726. {
  1727. if ( 0 != pwcQueryFile )
  1728. hr = DoQueryFile( fNoQuery ? L"::_noquery" : pwcCatalog,
  1729. pwcMachine,
  1730. awcScope,
  1731. dwScopeFlags,
  1732. pwcColumns,
  1733. pwcSort,
  1734. fDisplayTree,
  1735. fQuiet,
  1736. fForceUseContentIndex,
  1737. fNoQuery,
  1738. ulDialect,
  1739. cMaxHits,
  1740. lcid,
  1741. pwcQueryFile );
  1742. else if ( 0 != pwcRestriction )
  1743. hr = DoQuery( fNoQuery ? L"::_noquery" : pwcCatalog,
  1744. pwcMachine,
  1745. awcScope,
  1746. dwScopeFlags,
  1747. pwcRestriction,
  1748. pwcColumns,
  1749. pwcSort,
  1750. fDisplayTree,
  1751. fQuiet,
  1752. fForceUseContentIndex,
  1753. fNoQuery,
  1754. ulDialect,
  1755. cMaxHits,
  1756. lcid );
  1757. if ( SUCCEEDED( hr ) && fDisplayStatus )
  1758. hr = DisplayStatus( pwcCatalog, pwcMachine, lcid );
  1759. if ( SUCCEEDED( hr ) && fDisplayUpToDate )
  1760. hr = DisplayUpToDate( pwcCatalog, pwcMachine, lcid );
  1761. }
  1762. }
  1763. if ( fCoInit )
  1764. CoUninitialize();
  1765. if ( FAILED( hr ) )
  1766. return -1;
  1767. return 0;
  1768. } //wmain