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.

2307 lines
73 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 - 1999. All Rights Reserved.
  9. //
  10. // PROGRAM: ci.cxx
  11. //
  12. // PLATFORM: Windows
  13. //
  14. //--------------------------------------------------------------------------
  15. #define UNICODE
  16. #define DBINITCONSTANTS
  17. #include <stdio.h>
  18. #include <wchar.h>
  19. #include <windows.h>
  20. #include <oledberr.h>
  21. #include <oledb.h>
  22. #include <cmdtree.h>
  23. #include <ntquery.h>
  24. #include <mlang.h>
  25. #include <ciodm.h>
  26. #include "ci.hxx"
  27. #ifndef DBOP_firstrows
  28. #define DBOP_firstrows 258
  29. #endif
  30. // This is found in disptree.cxx
  31. extern void DisplayCommandTree( DBCOMMANDTREE * pNode, ULONG iLevel = 0 );
  32. // These are found in isrch.cxx
  33. extern HRESULT DoISearch( WCHAR const * pwcRestriction,
  34. WCHAR const * pwcFilename,
  35. BOOL fPrintFile,
  36. BOOL fDefineCPP,
  37. LCID lcid );
  38. extern HINSTANCE PrepareForISearch();
  39. extern void DoneWithISearch( HINSTANCE h );
  40. const ULONG MAX_CATALOGS = 8;
  41. CIPROPERTYDEF aCPPProperties[] =
  42. {
  43. {
  44. L"FUNC",
  45. DBTYPE_WSTR | DBTYPE_BYREF,
  46. {
  47. { 0x8dee0300, 0x16c2, 0x101b, 0xb1, 0x21, 0x08, 0x00, 0x2b, 0x2e, 0xcd, 0xa9 },
  48. DBKIND_GUID_NAME,
  49. L"func"
  50. }
  51. },
  52. {
  53. L"CLASS",
  54. DBTYPE_WSTR | DBTYPE_BYREF,
  55. {
  56. { 0x8dee0300, 0x16c2, 0x101b, 0xb1, 0x21, 0x08, 0x00, 0x2b, 0x2e, 0xcd, 0xa9 },
  57. DBKIND_GUID_NAME,
  58. L"class"
  59. }
  60. }
  61. };
  62. unsigned cCPPProperties = sizeof aCPPProperties /
  63. sizeof aCPPProperties[0];
  64. //+---------------------------------------------------------------------------
  65. //
  66. // Class: XBStr
  67. //
  68. // Purpose: Smart BSTR class
  69. //
  70. //----------------------------------------------------------------------------
  71. class XBStr
  72. {
  73. public:
  74. XBStr(BSTR p = 0) : _p( p ) {}
  75. XBStr ( XBStr & x ): _p( x.Acquire() ) {}
  76. ~XBStr() { SysFreeString( _p ); }
  77. BOOL IsNull() const { return ( 0 == _p ); }
  78. void Set ( BSTR pOleStr ) { _p = pOleStr; }
  79. BSTR Acquire()
  80. {
  81. BSTR pTemp = _p;
  82. _p = 0;
  83. return pTemp;
  84. }
  85. BSTR GetPointer() const { return _p; }
  86. void Free() { SysFreeString( Acquire() ); }
  87. private:
  88. BSTR _p;
  89. };
  90. //+-------------------------------------------------------------------------
  91. //
  92. // Template: XInterface
  93. //
  94. // Synopsis: Template for managing ownership of interfaces
  95. //
  96. //--------------------------------------------------------------------------
  97. template<class T> class XInterface
  98. {
  99. public:
  100. XInterface( T * p = 0 ) : _p( p ) {}
  101. ~XInterface() { if ( 0 != _p ) _p->Release(); }
  102. T * operator->() { return _p; }
  103. T * GetPointer() const { return _p; }
  104. IUnknown ** GetIUPointer() { return (IUnknown **) &_p; }
  105. T ** GetPPointer() { return &_p; }
  106. void ** GetQIPointer() { return (void **) &_p; }
  107. T * Acquire() { T * p = _p; _p = 0; return p; }
  108. BOOL IsNull() { return ( 0 == _p ); }
  109. private:
  110. T * _p;
  111. };
  112. //+-------------------------------------------------------------------------
  113. //
  114. // Template: XPtr
  115. //
  116. // Synopsis: Template for managing ownership of memory
  117. //
  118. //--------------------------------------------------------------------------
  119. template<class T> class XPtr
  120. {
  121. public:
  122. XPtr( unsigned c ) : _p(0) { if ( 0 != c ) _p = new T [ c ]; }
  123. ~XPtr() { Free(); }
  124. void SetSize( unsigned c ) { Free(); _p = new T [ c ]; }
  125. void Set ( T * p ) { _p = p; }
  126. T * Get() const { return _p ; }
  127. void Free() { delete [] Acquire(); }
  128. T & operator[]( unsigned i ) { return _p[i]; }
  129. T const & operator[]( unsigned i ) const { return _p[i]; }
  130. T * Acquire() { T * p = _p; _p = 0; return p; }
  131. BOOL IsNull() const { return ( 0 == _p ); }
  132. private:
  133. T * _p;
  134. };
  135. //+-------------------------------------------------------------------------
  136. //
  137. // Template: CResString
  138. //
  139. // Synopsis: Class for loading string resources
  140. //
  141. //--------------------------------------------------------------------------
  142. class CResString
  143. {
  144. public:
  145. CResString() { _awc[ 0 ] = 0; }
  146. CResString( UINT strIDS ) { Load( strIDS ); }
  147. WCHAR const * Get() const { return _awc; }
  148. BOOL Load( UINT strIDS )
  149. {
  150. _awc[ 0 ] = 0;
  151. LoadString( 0, strIDS, _awc, sizeof _awc / sizeof WCHAR );
  152. return ( 0 != _awc[ 0 ] );
  153. }
  154. private:
  155. WCHAR _awc[ 200 ];
  156. };
  157. //+-------------------------------------------------------------------------
  158. //
  159. // Function: FormatError
  160. //
  161. // Synopsis: Formats an error code into a string
  162. //
  163. // Arguments: [sc] - An Indexing Service or Win32 HRESULT
  164. // [pwc] - Where to write the error string
  165. // [cwc] - Count of characters in pwc
  166. // [lcid] - Locale for the error string
  167. //
  168. //--------------------------------------------------------------------------
  169. void FormatError(
  170. SCODE sc,
  171. WCHAR * pwc,
  172. ULONG cwc,
  173. LCID lcid )
  174. {
  175. // FormatMessage works best when based on thread locale.
  176. LCID SaveLCID = GetThreadLocale();
  177. SetThreadLocale( lcid );
  178. // Is this an Indexing Service error? These errors are in query.dll.
  179. if ( ! FormatMessage( FORMAT_MESSAGE_FROM_HMODULE,
  180. GetModuleHandle( L"query.dll" ),
  181. sc,
  182. 0,
  183. pwc,
  184. cwc,
  185. 0 ) )
  186. {
  187. // Is this a Win32 error? These are in kernel32.dll
  188. const ULONG facWin32 = ( FACILITY_WIN32 << 16 );
  189. ULONG Win32Error = sc;
  190. if ( (Win32Error & facWin32) == facWin32 )
  191. Win32Error &= ~( 0x80000000 | facWin32 );
  192. if ( ! FormatMessage( FORMAT_MESSAGE_FROM_HMODULE,
  193. GetModuleHandle( L"kernel32.dll" ),
  194. Win32Error,
  195. 0,
  196. pwc,
  197. cwc,
  198. 0 ) )
  199. {
  200. // It's not from Indexing Service or Win32; display a default error
  201. CResString str( IDS_UNKNOWNERROR );
  202. wcscpy( pwc, str.Get() );
  203. }
  204. }
  205. // Restore the original thread locale
  206. SetThreadLocale( SaveLCID );
  207. } //FormatError
  208. //+-------------------------------------------------------------------------
  209. //
  210. // Function: DisplayError
  211. //
  212. // Synopsis: Prints an error message from a string resource
  213. //
  214. // Arguments: [uiError] - The error message resource id
  215. // [pwcArgument] - A string argument for the error message
  216. // [hr] - The error code
  217. // [lcid] - Locale for the error string
  218. //
  219. //--------------------------------------------------------------------------
  220. HRESULT DisplayError(
  221. UINT uiError,
  222. WCHAR const * pwcArgument,
  223. HRESULT hr,
  224. LCID lcid )
  225. {
  226. WCHAR awcError[ 200 ];
  227. FormatError( hr, awcError, sizeof awcError / sizeof WCHAR, lcid );
  228. CResString str( uiError );
  229. wprintf( str.Get(), pwcArgument, hr, awcError );
  230. return hr;
  231. } //DisplayError
  232. //+-------------------------------------------------------------------------
  233. //
  234. // Function: DisplayWin32Error
  235. //
  236. // Synopsis: Prints an error message taken from GetLastError()
  237. //
  238. // Arguments: [uiError] - The string resource to use for the error
  239. // [pwcArgument] - A string argument for the error message
  240. // [lcid] - Locale for the error string
  241. //
  242. //--------------------------------------------------------------------------
  243. HRESULT DisplayWin32Error(
  244. UINT uiError,
  245. WCHAR const * pwcArgument,
  246. LCID lcid )
  247. {
  248. HRESULT hr = HRESULT_FROM_WIN32( GetLastError() );
  249. DisplayError( uiError, pwcArgument, hr, lcid );
  250. return hr;
  251. } //DisplayWin32Error
  252. void DisplayStat( DWORD dw, UINT uiMsg )
  253. {
  254. CResString str( uiMsg );
  255. wprintf( L"%8d %ws\n", dw, str.Get() );
  256. } //DisplayStat
  257. void DisplayStat( WCHAR const *pwcMsg, UINT uiMsg )
  258. {
  259. CResString str( uiMsg );
  260. wprintf( L"%ws: %ws\n", str.Get(), pwcMsg );
  261. } //DisplayStat
  262. void DisplayStat( UINT uiMsg )
  263. {
  264. CResString str( uiMsg );
  265. wprintf( L"%ws\n", str.Get() );
  266. } //DisplayStat
  267. //+-------------------------------------------------------------------------
  268. //
  269. // Function: Usage
  270. //
  271. // Synopsis: Displays information about how to use the app and exits
  272. //
  273. //--------------------------------------------------------------------------
  274. void Usage()
  275. {
  276. HRSRC hrc = FindResource( 0, (LPCWSTR) IDR_USAGE, RT_RCDATA );
  277. if ( 0 != hrc )
  278. {
  279. HGLOBAL hg = LoadResource( 0, hrc );
  280. if ( 0 != hg )
  281. {
  282. void * pv = LockResource( hg );
  283. if ( 0 != pv )
  284. wprintf( L"%ws\n", pv );
  285. }
  286. }
  287. exit( -1 );
  288. } //Usage
  289. //+-------------------------------------------------------------------------
  290. //
  291. // Function: LocaleToCodepage
  292. //
  293. // Synopsis: Finds the best matching codepage given a locale id.
  294. //
  295. // Arguments: [lcid] - Locale to check
  296. //
  297. // Returns: The best matching codepage.
  298. //
  299. //--------------------------------------------------------------------------
  300. ULONG LocaleToCodepage( LCID lcid )
  301. {
  302. ULONG codepage;
  303. int cwc = GetLocaleInfo( lcid,
  304. LOCALE_RETURN_NUMBER |
  305. LOCALE_IDEFAULTANSICODEPAGE,
  306. (WCHAR *) &codepage,
  307. sizeof ULONG / sizeof WCHAR );
  308. // If an error occurred, return the Ansi code page
  309. if ( 0 == cwc )
  310. return CP_ACP;
  311. return codepage;
  312. } //LocaleToCodepage
  313. //+-------------------------------------------------------------------------
  314. //
  315. // Function: GetLocaleString
  316. //
  317. // Synopsis: Looks up a locale string given an LCID
  318. //
  319. // Arguments: [lcid] - The lcid to look up
  320. //
  321. // Returns: The matching string (in a static buffer, caller beware).
  322. //
  323. //--------------------------------------------------------------------------
  324. WCHAR const * GetLocaleString( LCID lcid )
  325. {
  326. static WCHAR awcLocale[ 100 ];
  327. wcscpy( awcLocale, L"Neutral" );
  328. XInterface<IMultiLanguage> xMultiLang;
  329. HRESULT hr = CoCreateInstance( CLSID_CMultiLanguage,
  330. 0,
  331. CLSCTX_INPROC_SERVER,
  332. IID_IMultiLanguage,
  333. xMultiLang.GetQIPointer() );
  334. if ( SUCCEEDED( hr ) )
  335. {
  336. BSTR bstrLocale;
  337. hr = xMultiLang->GetRfc1766FromLcid( lcid, &bstrLocale );
  338. if ( SUCCEEDED( hr ) )
  339. {
  340. wcscpy( awcLocale, bstrLocale );
  341. SysFreeString( bstrLocale );
  342. }
  343. }
  344. return awcLocale;
  345. } //GetLocaleString
  346. //+-------------------------------------------------------------------------
  347. //
  348. // Function: LcidFromHttpAcceptLanguage
  349. //
  350. // Synopsis: Looks up an LCID given an HTTP Accept Language string
  351. //
  352. // Arguments: [pwc] - The string to look up
  353. //
  354. // Returns: The matching LCID.
  355. //
  356. //--------------------------------------------------------------------------
  357. LCID LcidFromHttpAcceptLanguage( WCHAR const * pwc )
  358. {
  359. // Default to the system locale
  360. LCID lcid = GetSystemDefaultLCID();
  361. if ( 0 != pwc )
  362. {
  363. XInterface<IMultiLanguage> xMultiLang;
  364. HRESULT hr = CoCreateInstance( CLSID_CMultiLanguage,
  365. 0,
  366. CLSCTX_INPROC_SERVER,
  367. IID_IMultiLanguage,
  368. xMultiLang.GetQIPointer() );
  369. if ( SUCCEEDED( hr ) )
  370. {
  371. BSTR bstr = SysAllocString( pwc );
  372. if ( 0 != bstr )
  373. {
  374. hr = xMultiLang->GetLcidFromRfc1766( &lcid, bstr );
  375. SysFreeString( bstr );
  376. if ( S_FALSE == hr ||
  377. E_FAIL == hr )
  378. {
  379. if ( !_wcsicmp( pwc, L"neutral" ) ||
  380. !_wcsicmp( pwc, L"neutr" ) )
  381. lcid = 0;
  382. else
  383. Usage();
  384. }
  385. else if ( FAILED( hr ) )
  386. {
  387. Usage();
  388. }
  389. }
  390. }
  391. }
  392. return lcid;
  393. } //LcidFromHttpAcceptLanguage
  394. //+-------------------------------------------------------------------------
  395. //
  396. // Function: SetCommandProperties
  397. //
  398. // Synopsis: Sets the DBPROP_USEEXTENDEDDBTYPES property to TRUE, so
  399. // data is returned in PROPVARIANTs, as opposed to the
  400. // default, which is OLE automation VARIANTs. PROPVARIANTS
  401. // allow a superset of VARIANT data types. Use of these
  402. // types avoids costly coercions.
  403. //
  404. // Also sets the DBPROP_USECONTENTINDEX property to TRUE, so
  405. // the index will always be used to resolve the query (as
  406. // opposed to enumerating all the files on the disk), even
  407. // if the index is out of date. This is set optionally.
  408. //
  409. // Both of these properties are unique to Indexing Service's
  410. // OLE DB implementation.
  411. //
  412. // Arguments: [pICommand] - The ICommand used to set the property
  413. // [fForceUseContentIndex] - TRUE to always use index
  414. // FALSE to allow directory enumeration
  415. //
  416. // Returns: HRESULT result of setting the properties
  417. //
  418. //--------------------------------------------------------------------------
  419. HRESULT SetCommandProperties(
  420. ICommand * pICommand,
  421. BOOL fForceUseContentIndex )
  422. {
  423. static const DBID dbcolNull = { { 0,0,0, { 0,0,0,0,0,0,0,0 } },
  424. DBKIND_GUID_PROPID, 0 };
  425. static const GUID guidQueryExt = DBPROPSET_QUERYEXT;
  426. DBPROP aProp[2];
  427. aProp[0].dwPropertyID = DBPROP_USEEXTENDEDDBTYPES;
  428. aProp[0].dwOptions = DBPROPOPTIONS_OPTIONAL;
  429. aProp[0].dwStatus = 0;
  430. aProp[0].colid = dbcolNull;
  431. aProp[0].vValue.vt = VT_BOOL;
  432. aProp[0].vValue.boolVal = VARIANT_TRUE;
  433. aProp[1] = aProp[0];
  434. aProp[1].dwPropertyID = DBPROP_USECONTENTINDEX;
  435. DBPROPSET aPropSet[1];
  436. aPropSet[0].rgProperties = &aProp[0];
  437. aPropSet[0].cProperties = fForceUseContentIndex ? 2 : 1;
  438. aPropSet[0].guidPropertySet = guidQueryExt;
  439. XInterface<ICommandProperties> xICommandProperties;
  440. HRESULT hr = pICommand->QueryInterface( IID_ICommandProperties,
  441. xICommandProperties.GetQIPointer() );
  442. if ( FAILED( hr ) )
  443. return hr;
  444. return xICommandProperties->SetProperties( 1, // 1 property set
  445. aPropSet ); // the properties
  446. } //SetCommandProperties
  447. //+-------------------------------------------------------------------------
  448. //
  449. // Function: Render
  450. //
  451. // Synopsis: Prints an item in a safearray
  452. //
  453. // Arguments: [vt] - type of the element
  454. // [pa] - pointer to the item
  455. //
  456. //--------------------------------------------------------------------------
  457. void PrintSafeArray( VARTYPE vt, LPSAFEARRAY pa );
  458. void Render( VARTYPE vt, void * pv )
  459. {
  460. if ( VT_ARRAY & vt )
  461. {
  462. PrintSafeArray( vt - VT_ARRAY, *(SAFEARRAY **) pv );
  463. return;
  464. }
  465. switch ( vt )
  466. {
  467. case VT_UI1: wprintf( L"%u", (unsigned) *(BYTE *)pv ); break;
  468. case VT_I1: wprintf( L"%d", (int) *(CHAR *)pv ); break;
  469. case VT_UI2: wprintf( L"%u", (unsigned) *(USHORT *)pv ); break;
  470. case VT_I2: wprintf( L"%d", (int) *(SHORT *)pv ); break;
  471. case VT_UI4:
  472. case VT_UINT: wprintf( L"%u", (unsigned) *(ULONG *)pv ); break;
  473. case VT_I4:
  474. case VT_ERROR:
  475. case VT_INT: wprintf( L"%d", *(LONG *)pv ); break;
  476. case VT_UI8: wprintf( L"%I64u", *(unsigned __int64 *)pv ); break;
  477. case VT_I8: wprintf( L"%I64d", *(__int64 *)pv ); break;
  478. case VT_R4: wprintf( L"%f", *(float *)pv ); break;
  479. case VT_R8: wprintf( L"%lf", *(double *)pv ); break;
  480. case VT_DECIMAL:
  481. {
  482. double dbl;
  483. VarR8FromDec( (DECIMAL *) pv, &dbl );
  484. wprintf( L"%lf", dbl );
  485. break;
  486. }
  487. case VT_CY:
  488. {
  489. double dbl;
  490. VarR8FromCy( * (CY *) pv, &dbl );
  491. wprintf( L"%lf", dbl );
  492. break;
  493. }
  494. case VT_BOOL: wprintf( *(VARIANT_BOOL *)pv ? L"TRUE" : L"FALSE" ); break;
  495. case VT_BSTR: wprintf( L"%ws", *(BSTR *) pv ); break;
  496. case VT_VARIANT:
  497. {
  498. PROPVARIANT * pVar = (PROPVARIANT *) pv;
  499. Render( pVar->vt, & pVar->lVal );
  500. break;
  501. }
  502. case VT_DATE:
  503. {
  504. SYSTEMTIME st;
  505. VariantTimeToSystemTime( *(DATE *)pv, &st );
  506. BOOL pm = st.wHour >= 12;
  507. if ( st.wHour > 12 )
  508. st.wHour -= 12;
  509. else if ( 0 == st.wHour )
  510. st.wHour = 12;
  511. wprintf( L"%2d-%02d-%04d %2d:%02d%wc",
  512. (DWORD) st.wMonth,
  513. (DWORD) st.wDay,
  514. (DWORD) st.wYear,
  515. (DWORD) st.wHour,
  516. (DWORD) st.wMinute,
  517. pm ? L'p' : L'a' );
  518. break;
  519. }
  520. case VT_EMPTY:
  521. case VT_NULL:
  522. break;
  523. default :
  524. {
  525. wprintf( L"(vt 0x%x)", (int) vt );
  526. break;
  527. }
  528. }
  529. } //Render
  530. //+-------------------------------------------------------------------------
  531. //
  532. // Function: PrintSafeArray
  533. //
  534. // Synopsis: Prints items in a safearray
  535. //
  536. // Arguments: [vt] - type of elements in the safearray
  537. // [pa] - pointer to the safearray
  538. //
  539. //--------------------------------------------------------------------------
  540. void PrintSafeArray( VARTYPE vt, LPSAFEARRAY pa )
  541. {
  542. // Get the dimensions of the array
  543. UINT cDim = SafeArrayGetDim( pa );
  544. if ( 0 == cDim )
  545. return;
  546. XPtr<LONG> xDim( cDim );
  547. XPtr<LONG> xLo( cDim );
  548. XPtr<LONG> xUp( cDim );
  549. for ( UINT iDim = 0; iDim < cDim; iDim++ )
  550. {
  551. HRESULT hr = SafeArrayGetLBound( pa, iDim + 1, &xLo[iDim] );
  552. if ( FAILED( hr ) )
  553. return;
  554. xDim[ iDim ] = xLo[ iDim ];
  555. hr = SafeArrayGetUBound( pa, iDim + 1, &xUp[iDim] );
  556. if ( FAILED( hr ) )
  557. return;
  558. wprintf( L"{" );
  559. }
  560. // slog through the array
  561. UINT iLastDim = cDim - 1;
  562. BOOL fDone = FALSE;
  563. while ( !fDone )
  564. {
  565. // inter-element formatting
  566. if ( xDim[ iLastDim ] != xLo[ iLastDim ] )
  567. wprintf( L"," );
  568. // Get the element and render it
  569. void *pv;
  570. SafeArrayPtrOfIndex( pa, xDim.Get(), &pv );
  571. Render( vt, pv );
  572. // Move to the next element and carry if necessary
  573. ULONG cOpen = 0;
  574. for ( LONG iDim = iLastDim; iDim >= 0; iDim-- )
  575. {
  576. if ( xDim[ iDim ] < xUp[ iDim ] )
  577. {
  578. xDim[ iDim ] = 1 + xDim[ iDim ];
  579. break;
  580. }
  581. wprintf( L"}" );
  582. if ( 0 == iDim )
  583. fDone = TRUE;
  584. else
  585. {
  586. cOpen++;
  587. xDim[ iDim ] = xLo[ iDim ];
  588. }
  589. }
  590. for ( ULONG i = 0; !fDone && i < cOpen; i++ )
  591. wprintf( L"{" );
  592. }
  593. } //PrintSafeArray
  594. //+-------------------------------------------------------------------------
  595. //
  596. // Function: PrintVectorItems
  597. //
  598. // Synopsis: Prints items in a PROPVARIANT vector
  599. //
  600. // Arguments: [pVal] - The array of values
  601. // [cVals] - The count of values
  602. // [pcFmt] - The format string
  603. //
  604. //--------------------------------------------------------------------------
  605. template<class T> void PrintVectorItems(
  606. T * pVal,
  607. ULONG cVals,
  608. char * pcFmt )
  609. {
  610. printf( "{ " );
  611. for( ULONG iVal = 0; iVal < cVals; iVal++ )
  612. {
  613. if ( 0 != iVal )
  614. printf( "," );
  615. printf( pcFmt, *pVal++ );
  616. }
  617. printf( " }" );
  618. } //PrintVectorItems
  619. //+-------------------------------------------------------------------------
  620. //
  621. // Function: DisplayValue
  622. //
  623. // Synopsis: Displays a PROPVARIANT value. Limited formatting is done.
  624. //
  625. // Arguments: [pVar] - The value to display
  626. //
  627. //--------------------------------------------------------------------------
  628. void DisplayValue( PROPVARIANT const * pVar )
  629. {
  630. if ( 0 == pVar )
  631. {
  632. wprintf( L"NULL" );
  633. return;
  634. }
  635. // Display the most typical variant types
  636. PROPVARIANT const & v = *pVar;
  637. switch ( v.vt )
  638. {
  639. case VT_EMPTY : break;
  640. case VT_NULL : break;
  641. case VT_I4 : wprintf( L"%10d", v.lVal ); break;
  642. case VT_UI1 : wprintf( L"%10d", v.bVal ); break;
  643. case VT_I2 : wprintf( L"%10d", v.iVal ); break;
  644. case VT_R4 : wprintf( L"%10f", v.fltVal ); break;
  645. case VT_R8 : wprintf( L"%10lf", v.dblVal ); break;
  646. case VT_BOOL : wprintf( v.boolVal ? L"TRUE" : L"FALSE" ); break;
  647. case VT_I1 : wprintf( L"%10d", v.cVal ); break;
  648. case VT_UI2 : wprintf( L"%10u", v.uiVal ); break;
  649. case VT_UI4 : wprintf( L"%10u", v.ulVal ); break;
  650. case VT_INT : wprintf( L"%10d", v.lVal ); break;
  651. case VT_UINT : wprintf( L"%10u", v.ulVal ); break;
  652. case VT_I8 : wprintf( L"%20I64d", v.hVal ); break;
  653. case VT_UI8 : wprintf( L"%20I64u", v.hVal ); break;
  654. case VT_ERROR : wprintf( L"%#x", v.scode ); break;
  655. case VT_LPSTR : wprintf( L"%S", v.pszVal ); break;
  656. case VT_LPWSTR : wprintf( L"%ws", v.pwszVal ); break;
  657. case VT_BSTR : wprintf( L"%ws", v.bstrVal ); break;
  658. case VT_CY:
  659. {
  660. double dbl;
  661. VarR8FromCy( v.cyVal, &dbl );
  662. wprintf( L"%lf", dbl );
  663. break;
  664. }
  665. case VT_DECIMAL :
  666. {
  667. double dbl;
  668. VarR8FromDec( (DECIMAL *) &v.decVal, &dbl );
  669. wprintf( L"%lf", dbl );
  670. break;
  671. }
  672. case VT_FILETIME :
  673. case VT_DATE :
  674. {
  675. SYSTEMTIME st;
  676. if ( VT_DATE == v.vt )
  677. {
  678. VariantTimeToSystemTime( v.date, &st );
  679. }
  680. else
  681. {
  682. FILETIME ft;
  683. FileTimeToLocalFileTime( &v.filetime, &ft );
  684. FileTimeToSystemTime( &ft, &st );
  685. }
  686. BOOL pm = st.wHour >= 12;
  687. if ( st.wHour > 12 )
  688. st.wHour -= 12;
  689. else if ( 0 == st.wHour )
  690. st.wHour = 12;
  691. wprintf( L"%2d-%02d-%04d %2d:%02d%wc",
  692. (DWORD) st.wMonth,
  693. (DWORD) st.wDay,
  694. (DWORD) st.wYear,
  695. (DWORD) st.wHour,
  696. (DWORD) st.wMinute,
  697. pm ? L'p' : L'a' );
  698. break;
  699. }
  700. case VT_VECTOR | VT_I1:
  701. PrintVectorItems( v.cac.pElems, v.cac.cElems, "%d" ); break;
  702. case VT_VECTOR | VT_I2:
  703. PrintVectorItems( v.cai.pElems, v.cai.cElems, "%d" ); break;
  704. case VT_VECTOR | VT_I4:
  705. PrintVectorItems( v.cal.pElems, v.cal.cElems, "%d" ); break;
  706. case VT_VECTOR | VT_I8:
  707. PrintVectorItems( v.cah.pElems, v.cah.cElems, "%I64d" ); break;
  708. case VT_VECTOR | VT_UI1:
  709. PrintVectorItems( v.caub.pElems, v.caub.cElems, "%u" ); break;
  710. case VT_VECTOR | VT_UI2:
  711. PrintVectorItems( v.caui.pElems, v.caui.cElems, "%u" ); break;
  712. case VT_VECTOR | VT_UI4:
  713. PrintVectorItems( v.caul.pElems, v.caul.cElems, "%u" ); break;
  714. case VT_VECTOR | VT_ERROR:
  715. PrintVectorItems( v.cascode.pElems, v.cascode.cElems, "%#x" ); break;
  716. case VT_VECTOR | VT_UI8:
  717. PrintVectorItems( v.cauh.pElems, v.cauh.cElems, "%I64u" ); break;
  718. case VT_VECTOR | VT_BSTR:
  719. PrintVectorItems( v.cabstr.pElems, v.cabstr.cElems, "%ws" ); break;
  720. case VT_VECTOR | VT_LPSTR:
  721. PrintVectorItems( v.calpstr.pElems, v.calpstr.cElems, "%S" ); break;
  722. case VT_VECTOR | VT_LPWSTR:
  723. PrintVectorItems( v.calpwstr.pElems, v.calpwstr.cElems, "%ws" ); break;
  724. case VT_VECTOR | VT_R4:
  725. PrintVectorItems( v.caflt.pElems, v.caflt.cElems, "%f" ); break;
  726. case VT_VECTOR | VT_R8:
  727. PrintVectorItems( v.cadbl.pElems, v.cadbl.cElems, "%lf" ); break;
  728. default :
  729. {
  730. if ( VT_ARRAY & v.vt )
  731. PrintSafeArray( v.vt - VT_ARRAY, v.parray );
  732. else
  733. wprintf( L"vt 0x%05x", v.vt );
  734. break;
  735. }
  736. }
  737. } //DisplayValue
  738. //-----------------------------------------------------------------------------
  739. //
  740. // Function: GetOleDBErrorInfo
  741. //
  742. // Synopsis: Retrieves the secondary error from the OLE DB error object.
  743. //
  744. // Arguments: [pErrSrc] - Pointer to object that posted the error.
  745. // [riid] - Interface that posted the error.
  746. // [lcid] - Locale in which the text is desired.
  747. // [pErrorInfo] - Pointer to memory where ERRORINFO should be.
  748. // [ppIErrorInfo] - Holds the returning IErrorInfo. Caller
  749. // should release this.
  750. //
  751. // Returns: HRESULT for whether the error info was retrieved
  752. //
  753. //-----------------------------------------------------------------------------
  754. HRESULT GetOleDBErrorInfo(
  755. IUnknown * pErrSrc,
  756. REFIID riid,
  757. LCID lcid,
  758. ERRORINFO * pErrorInfo,
  759. IErrorInfo ** ppIErrorInfo )
  760. {
  761. *ppIErrorInfo = 0;
  762. // See if an error is available that is of interest to us.
  763. XInterface<ISupportErrorInfo> xSupportErrorInfo;
  764. HRESULT hr = pErrSrc->QueryInterface( IID_ISupportErrorInfo,
  765. xSupportErrorInfo.GetQIPointer() );
  766. if ( FAILED( hr ) )
  767. return hr;
  768. hr = xSupportErrorInfo->InterfaceSupportsErrorInfo( riid );
  769. if ( FAILED( hr ) )
  770. return hr;
  771. // Get the current error object. Return if none exists.
  772. XInterface<IErrorInfo> xErrorInfo;
  773. hr = GetErrorInfo( 0, xErrorInfo.GetPPointer() );
  774. if ( xErrorInfo.IsNull() )
  775. return hr;
  776. // Get the IErrorRecord interface and get the count of errors.
  777. XInterface<IErrorRecords> xErrorRecords;
  778. hr = xErrorInfo->QueryInterface( IID_IErrorRecords,
  779. xErrorRecords.GetQIPointer() );
  780. if ( FAILED( hr ) )
  781. return hr;
  782. ULONG cErrRecords;
  783. hr = xErrorRecords->GetRecordCount( &cErrRecords );
  784. if ( 0 == cErrRecords )
  785. return hr;
  786. #if 1 // A good way to get the complete error message...
  787. XInterface<IErrorInfo> xErrorInfoRec;
  788. ERRORINFO ErrorInfo;
  789. for ( unsigned i=0; i<cErrRecords; i++ )
  790. {
  791. // Get basic error information.
  792. xErrorRecords->GetBasicErrorInfo( i, &ErrorInfo );
  793. // Get error description and source through the IErrorInfo interface
  794. // pointer on a particular record.
  795. xErrorRecords->GetErrorInfo( i, lcid, xErrorInfoRec.GetPPointer() );
  796. XBStr bstrDescriptionOfError;
  797. XBStr bstrSourceOfError;
  798. BSTR bstrDesc = bstrDescriptionOfError.GetPointer();
  799. BSTR bstrSrc = bstrSourceOfError.GetPointer();
  800. xErrorInfoRec->GetDescription( &bstrDesc );
  801. xErrorInfoRec->GetSource( &bstrSrc );
  802. // At this point, you could call GetCustomErrorObject and query for
  803. // additional interfaces to determine what else happened.
  804. wprintf( L"%s (%#x)\n%s\n", bstrDesc, ErrorInfo.hrError, bstrSrc );
  805. }
  806. #endif
  807. // Get basic error information for the most recent error
  808. ULONG iRecord = cErrRecords - 1;
  809. hr = xErrorRecords->GetBasicErrorInfo( iRecord, pErrorInfo );
  810. if ( FAILED( hr ) )
  811. return hr;
  812. return xErrorRecords->GetErrorInfo( iRecord, lcid, ppIErrorInfo );
  813. } //GetOleDBErrorInfo
  814. //-----------------------------------------------------------------------------
  815. //
  816. // Function: DisplayRowsetStatus
  817. //
  818. // Synopsis: Retrieves status information about the rowset and catalog.
  819. //
  820. // Arguments: [xIRowset] - Rowset about which information is retrieved.
  821. //
  822. // Returns: HRESULT result of retrieving the status
  823. //
  824. //-----------------------------------------------------------------------------
  825. HRESULT DisplayRowsetStatus( XInterface<IRowset> & xIRowset )
  826. {
  827. XInterface<IRowsetInfo> xIRowsetInfo;
  828. HRESULT hr = xIRowset->QueryInterface( IID_IRowsetInfo,
  829. xIRowsetInfo.GetQIPointer() );
  830. if ( SUCCEEDED( hr ) )
  831. {
  832. // This rowset property is Indexing-Service specific
  833. DBPROPID propId = MSIDXSPROP_ROWSETQUERYSTATUS;
  834. DBPROPIDSET propSet;
  835. propSet.rgPropertyIDs = &propId;
  836. propSet.cPropertyIDs = 1;
  837. const GUID guidRowsetExt = DBPROPSET_MSIDXS_ROWSETEXT;
  838. propSet.guidPropertySet = guidRowsetExt;
  839. ULONG cPropertySets = 0;
  840. DBPROPSET * pPropertySets;
  841. hr = xIRowsetInfo->GetProperties( 1,
  842. &propSet,
  843. &cPropertySets,
  844. &pPropertySets );
  845. if ( SUCCEEDED( hr ) )
  846. {
  847. DWORD dwStatus = pPropertySets->rgProperties->vValue.ulVal;
  848. CoTaskMemFree( pPropertySets->rgProperties );
  849. CoTaskMemFree( pPropertySets );
  850. DWORD dwFill = QUERY_FILL_STATUS( dwStatus );
  851. if ( STAT_ERROR == dwFill )
  852. DisplayStat( IDS_ROWSET_STAT_ERROR );
  853. DWORD dwReliability = QUERY_RELIABILITY_STATUS( dwStatus );
  854. if ( 0 != ( STAT_PARTIAL_SCOPE & dwReliability ) )
  855. DisplayStat( IDS_ROWSET_STAT_PARTIAL_SCOPE );
  856. if ( 0 != ( STAT_NOISE_WORDS & dwReliability ) )
  857. DisplayStat( IDS_ROWSET_STAT_NOISE_WORDS );
  858. if ( 0 != ( STAT_CONTENT_OUT_OF_DATE & dwReliability ) )
  859. DisplayStat( IDS_ROWSET_STAT_CONTENT_OUT_OF_DATE );
  860. if ( 0 != ( STAT_REFRESH_INCOMPLETE & dwReliability ) )
  861. DisplayStat( IDS_ROWSET_STAT_REFRESH_INCOMPLETE );
  862. if ( 0 != ( STAT_CONTENT_QUERY_INCOMPLETE & dwReliability ) )
  863. DisplayStat( IDS_ROWSET_STAT_CONTENT_QUERY_INCOMPLETE );
  864. if ( 0 != ( STAT_TIME_LIMIT_EXCEEDED & dwReliability ) )
  865. DisplayStat( IDS_ROWSET_STAT_TIME_LIMIT_EXCEEDED );
  866. if ( 0 != ( STAT_SHARING_VIOLATION & dwReliability ) )
  867. DisplayStat( IDS_ROWSET_STAT_SHARING_VIOLATION );
  868. }
  869. }
  870. return hr;
  871. } //DisplayRowsetStatus
  872. ULONG CountEntries( WCHAR const * pwc, WCHAR wc )
  873. {
  874. WCHAR const * p = wcschr( pwc, wc );
  875. ULONG c = 1;
  876. while ( 0 != p )
  877. {
  878. c++;
  879. p++;
  880. p = wcschr( p, wc );
  881. }
  882. return c;
  883. } //CountEntries
  884. //+-------------------------------------------------------------------------
  885. //
  886. // Function: IssueQuery
  887. //
  888. // Synopsis: Creates and executes a query, then displays the results.
  889. //
  890. // Arguments: [pwcQueryCatalog] - Catalog name over which query is run
  891. // [pwcQueryMachine] - Machine name on which query is run
  892. // [pwcQueryScope] - Scope of the query
  893. // [dwScopeFlags] - Scope flags
  894. // [pwcQueryRestrition] - The actual query string
  895. // [pwcColumns] - Output column names
  896. // [pwcSort] - Sort order names, may be 0
  897. // [fDisplayTree] - TRUE to display the command tree
  898. // [fQuiet] - if TRUE, don't display hitcount
  899. // [fForceUseContentIndex] - TRUE to always use index
  900. // FALSE to allow directory enumeration
  901. // [fNoQuery] - if TRUE, just parse and display query
  902. // [fSearchHit] - if TRUE invoke isrchdmp.exe
  903. // [ulDialect] - Query dialect (1 or 2)
  904. // [cMaxHits] - Maximum # of hits, or 0 for no limit
  905. // [fFirstHits] - TRUE for first N or FALSE for best N
  906. // [lcid] - Locale for the query
  907. // [fDefineCPP] - TRUE to define func and class props
  908. //
  909. // Returns: HRESULT result of the query
  910. //
  911. //--------------------------------------------------------------------------
  912. HRESULT IssueQuery(
  913. WCHAR const * pwcQueryCatalog,
  914. WCHAR const * pwcQueryMachine,
  915. WCHAR const * pwcQueryScope,
  916. DWORD dwScopeFlags,
  917. WCHAR const * pwcQueryRestriction,
  918. WCHAR const * pwcColumns,
  919. WCHAR const * pwcSort,
  920. BOOL fDisplayTree,
  921. BOOL fQuiet,
  922. BOOL fForceUseContentIndex,
  923. BOOL fNoQuery,
  924. BOOL fSearchHit,
  925. ULONG ulDialect,
  926. ULONG cMaxHits,
  927. BOOL fFirstHits,
  928. LCID lcid,
  929. BOOL fDefineCPP )
  930. {
  931. // Create an ICommand object. CIMakeICommand is a shortcut for making an
  932. // ICommand. The ADVQUERY sample shows the OLE DB equivalent.
  933. XInterface<ICommand> xICommand;
  934. HRESULT hr;
  935. // Handle distributed and single catalog queries
  936. if ( ( 0 != wcschr( pwcQueryCatalog, L',' ) ) ||
  937. ( 0 != wcschr( pwcQueryMachine, L',' ) ) )
  938. {
  939. ULONG cCat = CountEntries( pwcQueryCatalog, L',' );
  940. ULONG cMac = CountEntries( pwcQueryMachine, L',' );
  941. if ( ( ( cCat != cMac ) && ( 1 != cCat ) && ( 1 != cMac ) ) ||
  942. ( cCat > MAX_CATALOGS || cMac > MAX_CATALOGS ) )
  943. Usage();
  944. WCHAR awcCat[ MAX_PATH ];
  945. wcscpy( awcCat, pwcQueryCatalog );
  946. WCHAR awcMac[ MAX_PATH ];
  947. wcscpy( awcMac, pwcQueryMachine );
  948. WCHAR * aCat[ MAX_CATALOGS ];
  949. WCHAR * aMac[ MAX_CATALOGS ];
  950. WCHAR const * aSco[ MAX_CATALOGS ];
  951. DWORD aFla[ MAX_CATALOGS ];
  952. WCHAR * pwcCat = awcCat;
  953. WCHAR * pwcMac = awcMac;
  954. for ( ULONG i = 0; i < __max( cCat, cMac ); i++ )
  955. {
  956. aFla[i] = dwScopeFlags;
  957. aSco[i] = pwcQueryScope;
  958. aMac[i] = pwcMac;
  959. if ( 1 != cMac )
  960. {
  961. pwcMac = wcschr( pwcMac, L',' );
  962. if ( 0 != pwcMac )
  963. *pwcMac++ = 0;
  964. }
  965. aCat[i] = pwcCat;
  966. if ( 1 != cCat )
  967. {
  968. pwcCat = wcschr( pwcCat, L',' );
  969. if ( 0 != pwcCat )
  970. *pwcCat++ = 0;
  971. }
  972. }
  973. hr = CIMakeICommand( xICommand.GetPPointer(),
  974. cCat,
  975. aFla,
  976. aSco,
  977. aCat,
  978. aMac );
  979. }
  980. else
  981. {
  982. hr = CIMakeICommand( xICommand.GetPPointer(), // result
  983. 1, // 1 scope
  984. &dwScopeFlags, // scope flags
  985. &pwcQueryScope, // scope path
  986. &pwcQueryCatalog, // catalog
  987. &pwcQueryMachine ); // machine
  988. }
  989. if ( FAILED( hr ) )
  990. return hr;
  991. // Get a command tree object
  992. XInterface<ICommandTree> xICommandTree;
  993. hr = xICommand->QueryInterface( IID_ICommandTree,
  994. xICommandTree.GetQIPointer() );
  995. if ( FAILED( hr ) )
  996. return hr;
  997. // Create an OLE DB query tree based on query parameters.
  998. DBCOMMANDTREE * pTree;
  999. ULONG cDefinedProperties = fDefineCPP ? cCPPProperties : 0;
  1000. hr = CITextToFullTreeEx( pwcQueryRestriction, // the query itself
  1001. ulDialect, // query dialect
  1002. pwcColumns, // columns to return
  1003. pwcSort, // sort order, may be 0
  1004. 0, // reserved
  1005. &pTree, // resulting tree
  1006. cDefinedProperties, // C++ properties
  1007. aCPPProperties, // C++ properties
  1008. lcid ); // default locale
  1009. if ( FAILED( hr ) )
  1010. return hr;
  1011. // Limit the maximum number of results if requested by putting a DBOP_top
  1012. // node at the top of the query tree.
  1013. if ( 0 != cMaxHits )
  1014. {
  1015. DBCOMMANDTREE * pTop = (DBCOMMANDTREE *) CoTaskMemAlloc( sizeof DBCOMMANDTREE );
  1016. if ( 0 == pTop )
  1017. {
  1018. xICommandTree->FreeCommandTree( &pTree );
  1019. return E_OUTOFMEMORY;
  1020. }
  1021. memset( pTop, 0, sizeof DBCOMMANDTREE );
  1022. if ( fFirstHits )
  1023. pTop->op = DBOP_firstrows;
  1024. else
  1025. pTop->op = DBOP_top;
  1026. pTop->wKind = DBVALUEKIND_UI4;
  1027. pTop->value.ulValue = cMaxHits;
  1028. pTop->pctFirstChild = pTree;
  1029. pTree = pTop;
  1030. }
  1031. // If directed, display the command tree.
  1032. if ( fDisplayTree )
  1033. {
  1034. wprintf( L"%ws\n", pwcQueryRestriction );
  1035. DisplayCommandTree( pTree );
  1036. }
  1037. // If directed, don't issue the query. Parsing it was sufficient.
  1038. if ( fNoQuery )
  1039. {
  1040. xICommandTree->FreeCommandTree( &pTree );
  1041. return S_OK;
  1042. }
  1043. // Set the tree in the ICommandTree. Ownership of the tree is transferred.
  1044. hr = xICommandTree->SetCommandTree( &pTree,
  1045. DBCOMMANDREUSE_NONE,
  1046. FALSE );
  1047. if ( FAILED( hr ) )
  1048. {
  1049. xICommandTree->FreeCommandTree( &pTree );
  1050. return hr;
  1051. }
  1052. // Set required properties on the ICommand
  1053. hr = SetCommandProperties( xICommand.GetPointer(),
  1054. fForceUseContentIndex );
  1055. if ( FAILED( hr ) )
  1056. return hr;
  1057. // Execute the query. The query is complete when Execute() returns.
  1058. XInterface<IRowset> xIRowset;
  1059. hr = xICommand->Execute( 0, // no aggregating IUnknown
  1060. IID_IRowset, // IID for interface to return
  1061. 0, // no DBPARAMs
  1062. 0, // no rows affected
  1063. xIRowset.GetIUPointer() ); // result
  1064. if ( FAILED( hr ) )
  1065. {
  1066. // Get the real error; OLE DB permits few Execute() return codes
  1067. ERRORINFO ErrorInfo;
  1068. XInterface<IErrorInfo> xErrorInfo;
  1069. HRESULT hr2 = GetOleDBErrorInfo( xICommand.GetPointer(),
  1070. IID_ICommand,
  1071. lcid,
  1072. &ErrorInfo,
  1073. xErrorInfo.GetPPointer() );
  1074. // Post IErrorInfo only if we have a valid pointer to it.
  1075. if ( SUCCEEDED( hr2 ) && !xErrorInfo.IsNull() )
  1076. hr = ErrorInfo.hrError;
  1077. return hr;
  1078. }
  1079. // Create an accessor, so data can be retrieved from the rowset.
  1080. XInterface<IAccessor> xIAccessor;
  1081. hr = xIRowset->QueryInterface( IID_IAccessor,
  1082. xIAccessor.GetQIPointer() );
  1083. if ( FAILED( hr ) )
  1084. return hr;
  1085. // Count the number of output columns and make bindings for them.
  1086. ULONG cColumns = 1;
  1087. WCHAR const *pwc = pwcColumns;
  1088. while ( 0 != *pwc )
  1089. {
  1090. if ( L',' == *pwc )
  1091. cColumns++;
  1092. pwc++;
  1093. }
  1094. // Column iOrdinals are parallel with those passed to CiTextToFullTree,
  1095. // so MapColumnIDs isn't necessary. These binding values for dwPart,
  1096. // dwMemOwner, and wType are the most optimal bindings for Indexing
  1097. // Service.
  1098. XPtr<DBBINDING> xBindings( cColumns );
  1099. if ( xBindings.IsNull() )
  1100. return E_OUTOFMEMORY;
  1101. memset( xBindings.Get(), 0, sizeof DBBINDING * cColumns );
  1102. for ( ULONG i = 0; i < cColumns; i++ )
  1103. {
  1104. xBindings[i].iOrdinal = 1 + i; // 1-based column number
  1105. xBindings[i].obValue = i * sizeof( PROPVARIANT * ); // offset
  1106. xBindings[i].dwPart = DBPART_VALUE; // retrieve value, not status
  1107. xBindings[i].dwMemOwner = DBMEMOWNER_PROVIDEROWNED; // provider owned
  1108. xBindings[i].wType = DBTYPE_VARIANT | DBTYPE_BYREF; // VARIANT *
  1109. }
  1110. HACCESSOR hAccessor;
  1111. hr = xIAccessor->CreateAccessor( DBACCESSOR_ROWDATA, // rowdata accessor
  1112. cColumns, // # of columns
  1113. xBindings.Get(), // columns
  1114. 0, // ignored
  1115. &hAccessor, // result
  1116. 0 ); // no status
  1117. if ( FAILED( hr ) )
  1118. return hr;
  1119. DBORDINAL iPathColumn = ~0;
  1120. if ( fSearchHit )
  1121. {
  1122. const DBID dbcolPath = { PSGUID_STORAGE,
  1123. DBKIND_GUID_PROPID,
  1124. (LPWSTR) (ULONG_PTR) PID_STG_PATH };
  1125. XInterface<IColumnsInfo> xColInfo;
  1126. hr = xIRowset->QueryInterface( IID_IColumnsInfo, xColInfo.GetQIPointer() );
  1127. if ( FAILED( hr ) )
  1128. return hr;
  1129. hr = xColInfo->MapColumnIDs( 1,
  1130. & dbcolPath,
  1131. & iPathColumn );
  1132. if ( FAILED( hr ) )
  1133. return hr;
  1134. // Change from 1-based to 0-based.
  1135. iPathColumn--;
  1136. }
  1137. // Display the results of the query.
  1138. XPtr<PROPVARIANT *> xData( cColumns );
  1139. if ( xData.IsNull() )
  1140. hr = E_OUTOFMEMORY;
  1141. else
  1142. {
  1143. DBCOUNTITEM cRowsSoFar = 0;
  1144. do
  1145. {
  1146. DBCOUNTITEM cRowsReturned = 0;
  1147. const ULONG cRowsAtATime = 20;
  1148. HROW aHRow[cRowsAtATime];
  1149. HROW * pgrHRows = aHRow;
  1150. hr = xIRowset->GetNextRows( 0, // no chapter
  1151. 0, // no rows to skip
  1152. cRowsAtATime, // # rows to get
  1153. &cRowsReturned, // # rows returned
  1154. &pgrHRows); // resulting hrows
  1155. if ( FAILED( hr ) )
  1156. break;
  1157. for ( DBCOUNTITEM iRow = 0; iRow < cRowsReturned; iRow++ )
  1158. {
  1159. HRESULT hr2 = xIRowset->GetData( aHRow[iRow], // hrow being accessed
  1160. hAccessor, // accessor to use
  1161. xData.Get() ); // resulting data
  1162. if ( FAILED( hr2 ) )
  1163. {
  1164. hr = hr2;
  1165. break;
  1166. }
  1167. if ( ( 1 != cColumns ) || !fSearchHit )
  1168. {
  1169. for ( ULONG iCol = 0; iCol < cColumns; iCol++ )
  1170. {
  1171. if ( 0 != iCol )
  1172. wprintf( L" " );
  1173. DisplayValue( xData[ iCol ] );
  1174. }
  1175. wprintf( L"\n" );
  1176. }
  1177. if ( fSearchHit )
  1178. {
  1179. PROPVARIANT * pPropVar = xData[ (unsigned int)iPathColumn ];
  1180. if ( ( VT_LPWSTR == pPropVar->vt ) &&
  1181. ( 0 != pPropVar->pwszVal ) )
  1182. {
  1183. DoISearch( pwcQueryRestriction,
  1184. pPropVar->pwszVal,
  1185. ( 1 == cColumns ),
  1186. fDefineCPP,
  1187. lcid );
  1188. }
  1189. }
  1190. }
  1191. // Release the HROWs retrived in GetNextRows
  1192. if ( 0 != cRowsReturned )
  1193. {
  1194. cRowsSoFar += cRowsReturned;
  1195. xIRowset->ReleaseRows( cRowsReturned, // # of rows to release
  1196. aHRow, // rows to release
  1197. 0, // no options
  1198. 0, // no refcounts
  1199. 0 ); // no status
  1200. }
  1201. // Check if all rows are now retrieved.
  1202. if ( DB_S_ENDOFROWSET == hr || DB_S_ROWLIMITEXCEEDED == hr )
  1203. {
  1204. hr = S_OK; // succeeded, return S_OK from DoQuery
  1205. break;
  1206. }
  1207. // Check if the query aborted because it was too costly.
  1208. if ( DB_S_STOPLIMITREACHED == hr )
  1209. {
  1210. CResString str( IDS_QUERYTIMEDOUT );
  1211. wprintf( L"%ws\n", str.Get() );
  1212. hr = S_OK;
  1213. break;
  1214. }
  1215. if ( FAILED( hr ) )
  1216. break;
  1217. } while ( TRUE );
  1218. if ( !fQuiet )
  1219. {
  1220. CResString str( IDS_QUERYDONE );
  1221. wprintf( str.Get(), cRowsSoFar, pwcQueryRestriction );
  1222. }
  1223. }
  1224. xIAccessor->ReleaseAccessor( hAccessor, 0 );
  1225. // Get query status information
  1226. if ( SUCCEEDED( hr ) && !fQuiet )
  1227. hr = DisplayRowsetStatus( xIRowset );
  1228. return hr;
  1229. } //IssueQuery
  1230. //+-------------------------------------------------------------------------
  1231. //
  1232. // Function: DoQuery
  1233. //
  1234. // Synopsis: Issues a query and displays an error message on failure
  1235. //
  1236. // Arguments: [pwcQueryCatalog] - Catalog name over which query is run
  1237. // [pwcQueryMachine] - Machine name on which query is run
  1238. // [pwcQueryScope] - Scope of the query
  1239. // [dwScopeFlags] - Scope flags
  1240. // [pwcQueryRestrition] - The actual query string
  1241. // [pwcColumns] - Output column names
  1242. // [pwcSort] - Sort order names, may be 0
  1243. // [fDisplayTree] - TRUE to display the command tree
  1244. // [fQuiet] - if TRUE, don't display hitcount
  1245. // [fForceUseContentIndex] - TRUE to always use index
  1246. // FALSE to allow directory enumeration
  1247. // [fNoQuery] - if TRUE, just parse and display query
  1248. // [fSearchHit] - if TRUE invoke isrchdmp.exe
  1249. // [ulDialect] - Query dialect (1 or 2)
  1250. // [cMaxHits] - Maximum # of hits, or 0 for no limit
  1251. // [fFirstHits] - TRUE for first N or FALSE for best N
  1252. // [lcid] - Locale for the query
  1253. // [fDefineCPP] - TRUE to define func and class props
  1254. //
  1255. // Returns: HRESULT result of the query
  1256. //
  1257. //--------------------------------------------------------------------------
  1258. HRESULT DoQuery(
  1259. WCHAR const * pwcCatalog,
  1260. WCHAR const * pwcMachine,
  1261. WCHAR const * pwcScope,
  1262. DWORD dwScopeFlags,
  1263. WCHAR const * pwcRestriction,
  1264. WCHAR const * pwcColumns,
  1265. WCHAR const * pwcSort,
  1266. BOOL fDisplayTree,
  1267. BOOL fQuiet,
  1268. BOOL fForceUseContentIndex,
  1269. BOOL fNoQuery,
  1270. BOOL fSearchHit,
  1271. ULONG ulDialect,
  1272. ULONG cMaxHits,
  1273. BOOL fFirstHits,
  1274. LCID lcid,
  1275. BOOL fDefineCPP )
  1276. {
  1277. HRESULT hr = IssueQuery( pwcCatalog,
  1278. pwcMachine,
  1279. pwcScope,
  1280. dwScopeFlags,
  1281. pwcRestriction,
  1282. pwcColumns,
  1283. pwcSort,
  1284. fDisplayTree,
  1285. fQuiet,
  1286. fForceUseContentIndex,
  1287. fNoQuery,
  1288. fSearchHit,
  1289. ulDialect,
  1290. cMaxHits,
  1291. fFirstHits,
  1292. lcid,
  1293. fDefineCPP );
  1294. if ( FAILED( hr ) )
  1295. DisplayError( IDS_QUERYFAILED, pwcRestriction, hr, lcid );
  1296. return hr;
  1297. } //DoQuery
  1298. //+-------------------------------------------------------------------------
  1299. //
  1300. // Function: DoQueryFile
  1301. //
  1302. // Synopsis: Issues each query in the specified query file. A query file
  1303. // is just a text file where each line contains a query.
  1304. //
  1305. // Arguments: [pwcQueryCatalog] - Catalog name over which query is run
  1306. // [pwcQueryMachine] - Machine name on which query is run
  1307. // [pwcQueryScope] - Scope of the query
  1308. // [dwScopeFlags] - Scope flags
  1309. // [pwcColumns] - Output column names
  1310. // [pwcSort] - Sort order names, may be 0
  1311. // [fDisplayTree] - TRUE to display the command tree
  1312. // [fQuiet] - if TRUE, don't display hitcount
  1313. // [fForceUseContentIndex] - TRUE to always use index
  1314. // FALSE to allow directory enumeration
  1315. // [fNoQuery] - if TRUE, just parse and display query
  1316. // [fSearchHit] - if TRUE invoke isrchdmp.exe
  1317. // [ulDialect] - Query dialect (1 or 2)
  1318. // [cMaxHits] - Maximum # of hits, or 0 for no limit
  1319. // [fFirstHits] - TRUE for first N or FALSE for best N
  1320. // [lcid] - Locale for the query
  1321. // [pwcQueryFile] - File containing queries, 1 per line
  1322. // [fDefineCPP] - TRUE to define func and class props
  1323. //
  1324. // Returns: HRESULT result of the query
  1325. //
  1326. //--------------------------------------------------------------------------
  1327. HRESULT DoQueryFile(
  1328. WCHAR const * pwcQueryCatalog,
  1329. WCHAR const * pwcQueryMachine,
  1330. WCHAR const * pwcQueryScope,
  1331. DWORD dwScopeFlags,
  1332. WCHAR const * pwcColumns,
  1333. WCHAR const * pwcSort,
  1334. BOOL fDisplayTree,
  1335. BOOL fQuiet,
  1336. BOOL fForceUseContentIndex,
  1337. BOOL fNoQuery,
  1338. BOOL fSearchHit,
  1339. ULONG ulDialect,
  1340. ULONG cMaxHits,
  1341. BOOL fFirstHits,
  1342. LCID lcid,
  1343. WCHAR const * pwcQueryFile,
  1344. BOOL fDefineCPP )
  1345. {
  1346. // Open and read the query file
  1347. HANDLE hFile = CreateFile( pwcQueryFile,
  1348. FILE_GENERIC_READ,
  1349. FILE_SHARE_READ | FILE_SHARE_DELETE,
  1350. 0,
  1351. OPEN_EXISTING,
  1352. 0,
  1353. 0 );
  1354. if ( 0 == hFile || INVALID_HANDLE_VALUE == hFile )
  1355. return DisplayWin32Error( IDS_CANTOPENFILE,
  1356. pwcQueryFile,
  1357. lcid );
  1358. DWORD cbFile = GetFileSize( hFile, 0 );
  1359. if ( 0xffffffff == cbFile )
  1360. {
  1361. CloseHandle( hFile );
  1362. return DisplayWin32Error( IDS_CANTGETFILESIZE,
  1363. pwcQueryFile,
  1364. lcid );
  1365. }
  1366. // Allocate a buffer for the file
  1367. XPtr<BYTE> xQueries( cbFile + sizeof WCHAR );
  1368. if ( xQueries.IsNull() )
  1369. {
  1370. CloseHandle( hFile );
  1371. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  1372. return DisplayWin32Error( IDS_CANTGETMEMORY,
  1373. pwcQueryFile,
  1374. lcid );
  1375. }
  1376. // Read the file into the buffer
  1377. DWORD cbRead;
  1378. BOOL fRead = ReadFile( hFile, xQueries.Get(), cbFile, &cbRead, 0 );
  1379. CloseHandle( hFile );
  1380. if ( ! fRead )
  1381. return DisplayWin32Error( IDS_CANTREADFROMFILE,
  1382. pwcQueryFile,
  1383. lcid );
  1384. // Check if the file is Unicode already
  1385. BOOL fUnicode = ( 0xfeff == ( * (WCHAR *) xQueries.Get() ) );
  1386. WCHAR * pwcIn = 0;
  1387. DWORD cwcIn = 0;
  1388. if ( fUnicode )
  1389. {
  1390. pwcIn = (WCHAR *) xQueries.Get();
  1391. // skip past the Unicode marker
  1392. pwcIn++;
  1393. cwcIn = ( cbFile / sizeof WCHAR ) - 1;
  1394. }
  1395. else
  1396. {
  1397. // Convert to Unicode. Leave a little room for slack.
  1398. DWORD cbTmp = cbFile * sizeof WCHAR + cbFile / 8;
  1399. XPtr<BYTE> xTmp( cbTmp + sizeof WCHAR );
  1400. if ( xTmp.IsNull() )
  1401. {
  1402. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  1403. return DisplayWin32Error( IDS_CANTGETMEMORY,
  1404. pwcQueryFile,
  1405. lcid );
  1406. }
  1407. cwcIn = MultiByteToWideChar( LocaleToCodepage( lcid ),
  1408. 0,
  1409. (const char *) xQueries.Get(),
  1410. cbFile,
  1411. (WCHAR *) xTmp.Get(),
  1412. cbTmp );
  1413. if ( 0 == cwcIn )
  1414. return DisplayWin32Error( IDS_CANTCONVERTTOUNICODE,
  1415. pwcQueryFile,
  1416. lcid );
  1417. pwcIn = (WCHAR *) xTmp.Get();
  1418. xQueries.Free();
  1419. xQueries.Set( xTmp.Acquire() );
  1420. }
  1421. // Read each line in the file and issue the query
  1422. pwcIn[ cwcIn ] = 0;
  1423. WCHAR * pwc = pwcIn;
  1424. do
  1425. {
  1426. while ( 0 != *pwcIn &&
  1427. L'\r' != *pwcIn &&
  1428. L'\n' != *pwcIn )
  1429. pwcIn++;
  1430. BOOL fEOF = ( 0 == *pwcIn );
  1431. *pwcIn = 0;
  1432. if ( pwc != pwcIn )
  1433. {
  1434. DoQuery( pwcQueryCatalog,
  1435. pwcQueryMachine,
  1436. pwcQueryScope,
  1437. dwScopeFlags,
  1438. pwc,
  1439. pwcColumns,
  1440. pwcSort,
  1441. fDisplayTree,
  1442. fQuiet,
  1443. fForceUseContentIndex,
  1444. fNoQuery,
  1445. fSearchHit,
  1446. ulDialect,
  1447. cMaxHits,
  1448. fFirstHits,
  1449. lcid,
  1450. fDefineCPP );
  1451. wprintf( L"\n\n" );
  1452. }
  1453. if ( fEOF )
  1454. break;
  1455. pwcIn++;
  1456. while ( '\r' == *pwcIn || '\n' == *pwcIn )
  1457. pwcIn++;
  1458. pwc = pwcIn;
  1459. } while ( TRUE );
  1460. return S_OK;
  1461. } //DoQueryFile
  1462. //+-------------------------------------------------------------------------
  1463. //
  1464. // Function: LookupCatalog
  1465. //
  1466. // Synopsis: Looks for a catalog and machine matching the scope
  1467. //
  1468. // Arguments: [pwcScope] - The scope used to find the catalog
  1469. // [pwcMachine] - Returns the machine name
  1470. // [cwcMachine] - In/Out: Count of characters in pwcMachine
  1471. // [pwcCatalog] - Returns the catalog name
  1472. // [cwcCatalog] - In/Out: Count of characters in pwcCatalog
  1473. // [lcid] - Locale to use for errors
  1474. //
  1475. //--------------------------------------------------------------------------
  1476. HRESULT LookupCatalog(
  1477. WCHAR const * pwcScope,
  1478. WCHAR * pwcMachine,
  1479. ULONG & cwcMachine,
  1480. WCHAR * pwcCatalog,
  1481. ULONG & cwcCatalog,
  1482. LCID lcid )
  1483. {
  1484. HRESULT hr = LocateCatalogs( pwcScope, // scope to lookup
  1485. 0, // go with the first match
  1486. pwcMachine, // returns the machine
  1487. &cwcMachine, // buffer size in/out
  1488. pwcCatalog, // returns the catalog
  1489. &cwcCatalog ); // buffer size in/out
  1490. if ( FAILED( hr ) || ( S_FALSE == hr ) )
  1491. {
  1492. DisplayError( IDS_CANTFINDCATALOG, pwcScope, hr, lcid );
  1493. hr = E_FAIL;
  1494. }
  1495. return hr;
  1496. } //LookupCatalog
  1497. //+-------------------------------------------------------------------------
  1498. //
  1499. // Function: NormalizeScope
  1500. //
  1501. // Synopsis: Normalizes a scope and sets scope flags.
  1502. //
  1503. // Arguments: [pwcIn] - The scope for the query
  1504. // [pwcOut] - Returns the scope for the query
  1505. // [dwScopeFlags] - Returns the scope flags for the query
  1506. //
  1507. //--------------------------------------------------------------------------
  1508. HRESULT NormalizeScope(
  1509. WCHAR const * pwcIn,
  1510. WCHAR * pwcOut,
  1511. BOOL fShallow,
  1512. DWORD & dwScopeFlags )
  1513. {
  1514. if ( wcslen( pwcIn ) >= MAX_PATH )
  1515. return E_INVALIDARG;
  1516. if ( fShallow )
  1517. dwScopeFlags = QUERY_SHALLOW;
  1518. else
  1519. dwScopeFlags = QUERY_DEEP;
  1520. wcscpy( pwcOut, pwcIn );
  1521. // Check if the scope is an IIS virtual scope.
  1522. WCHAR wc = pwcIn[0];
  1523. if ( L'/' == wc )
  1524. {
  1525. // Set the virtual scope flag and flip the slashes.
  1526. dwScopeFlags |= QUERY_VIRTUAL_PATH;
  1527. for ( WCHAR * pwc = pwcOut; *pwc; pwc++ )
  1528. if ( '/' == *pwc )
  1529. *pwc = '\\';
  1530. }
  1531. else if ( ( !( L'\\' == wc && L'\\' == pwcIn[1] ) ) &&
  1532. ( !( L'\\' == wc && 0 == pwcIn[1] ) ) &&
  1533. L':' != pwcIn[1] &&
  1534. 0 != wc )
  1535. {
  1536. // Turn the relative path into a full path based on the current dir.
  1537. _wfullpath( pwcOut, pwcIn, MAX_PATH );
  1538. }
  1539. return S_OK;
  1540. } //NormalizeScope
  1541. //+-------------------------------------------------------------------------
  1542. //
  1543. // Function: DisplayStatus
  1544. //
  1545. // Synopsis: Displays status information about a catalog
  1546. //
  1547. // Arguments: [pwcCatalog] - Catalog name
  1548. // [pwcMachine] - Machine on which catalog resides
  1549. // [lcid] - Locale to use
  1550. //
  1551. //--------------------------------------------------------------------------
  1552. HRESULT DisplayStatus(
  1553. WCHAR const * pwcCatalog,
  1554. WCHAR const * pwcMachine,
  1555. LCID lcid )
  1556. {
  1557. CI_STATE state;
  1558. state.cbStruct = sizeof state;
  1559. DisplayStat( pwcMachine, IDS_STAT_MACHINE );
  1560. DisplayStat( pwcCatalog, IDS_STAT_CATALOG );
  1561. HRESULT hr = CIState( pwcCatalog, pwcMachine, &state );
  1562. if ( SUCCEEDED( hr ) )
  1563. {
  1564. DisplayStat( state.cTotalDocuments, IDS_STAT_TOTALDOCUMENTS );
  1565. DisplayStat( state.cFreshTest, IDS_STAT_FRESHTEST );
  1566. DisplayStat( state.cFilteredDocuments, IDS_STAT_FILTEREDDOCUMENTS );
  1567. DisplayStat( state.cDocuments, IDS_STAT_DOCUMENTS );
  1568. DisplayStat( state.cSecQDocuments, IDS_STAT_SECQDOCUMENTS );
  1569. DisplayStat( state.cUniqueKeys, IDS_STAT_UNIQUEKEYS );
  1570. DisplayStat( state.cWordList, IDS_STAT_WORDLIST );
  1571. DisplayStat( state.cPersistentIndex, IDS_STAT_PERSISTENTINDEX );
  1572. DisplayStat( state.cQueries, IDS_STAT_QUERIES );
  1573. DisplayStat( state.dwIndexSize, IDS_STAT_INDEXSIZE );
  1574. DisplayStat( state.dwPropCacheSize / 1024, IDS_STAT_PROPCACHESIZE );
  1575. DisplayStat( ( state.eState & CI_STATE_SCANNING ) ?
  1576. state.cPendingScans : 0,
  1577. IDS_STAT_SCANS );
  1578. const DWORD ALL_CI_MERGE = ( CI_STATE_SHADOW_MERGE |
  1579. CI_STATE_ANNEALING_MERGE |
  1580. CI_STATE_INDEX_MIGRATION_MERGE |
  1581. CI_STATE_MASTER_MERGE |
  1582. CI_STATE_MASTER_MERGE_PAUSED );
  1583. if ( 0 != ( ALL_CI_MERGE & state.eState ) )
  1584. {
  1585. UINT idStr;
  1586. if ( state.eState & CI_STATE_SHADOW_MERGE )
  1587. idStr = IDS_STAT_MERGE_SHADOW;
  1588. else if ( state.eState & CI_STATE_ANNEALING_MERGE )
  1589. idStr = IDS_STAT_MERGE_ANNEALING;
  1590. else if ( state.eState & CI_STATE_INDEX_MIGRATION_MERGE )
  1591. idStr = IDS_STAT_MERGE_INDEX_MIGRATION;
  1592. else if ( state.eState & CI_STATE_MASTER_MERGE )
  1593. idStr = IDS_STAT_MERGE_MASTER;
  1594. else
  1595. idStr = IDS_STAT_MERGE_MASTER_PAUSED;
  1596. DisplayStat( state.dwMergeProgress, idStr );
  1597. }
  1598. if ( CI_STATE_READ_ONLY & state.eState )
  1599. DisplayStat( IDS_STAT_READ_ONLY );
  1600. if ( CI_STATE_RECOVERING & state.eState )
  1601. DisplayStat( IDS_STAT_RECOVERING );
  1602. if ( CI_STATE_LOW_MEMORY & state.eState )
  1603. DisplayStat( IDS_STAT_LOW_MEMORY );
  1604. if ( CI_STATE_HIGH_IO & state.eState )
  1605. DisplayStat( IDS_STAT_HIGH_IO );
  1606. if ( CI_STATE_BATTERY_POWER & state.eState )
  1607. DisplayStat( IDS_STAT_BATTERY_POWER );
  1608. if ( CI_STATE_USER_ACTIVE & state.eState )
  1609. DisplayStat( IDS_STAT_USER_ACTIVE );
  1610. if ( CI_STATE_STARTING & state.eState )
  1611. DisplayStat( IDS_STAT_STARTING );
  1612. if ( CI_STATE_READING_USNS & state.eState )
  1613. DisplayStat( IDS_STAT_READING_USNS );
  1614. }
  1615. else
  1616. {
  1617. DisplayError( IDS_CANTDISPLAYSTATUS, pwcCatalog, hr, lcid );
  1618. }
  1619. return hr;
  1620. } //DisplayStatus
  1621. //+-------------------------------------------------------------------------
  1622. //
  1623. // Function: ForceMerge
  1624. //
  1625. // Synopsis: Forces a master merge on the catalog
  1626. //
  1627. // Arguments: [pwcCatalog] - Catalog name
  1628. // [pwcMachine] - Machine on which catalog resides
  1629. // [lcid] - Locale to use
  1630. //
  1631. //--------------------------------------------------------------------------
  1632. HRESULT ForceMerge(
  1633. WCHAR const * pwcCatalog,
  1634. WCHAR const * pwcMachine,
  1635. LCID lcid )
  1636. {
  1637. // Create the main Indexing Service administration object.
  1638. CLSID clsid;
  1639. HRESULT hr = CLSIDFromProgID( L"Microsoft.ISAdm", &clsid );
  1640. if ( FAILED( hr ) )
  1641. return DisplayError( IDS_CANTFORCEMERGE,
  1642. pwcCatalog,
  1643. hr,
  1644. lcid );
  1645. XInterface<IAdminIndexServer> xAdmin;
  1646. hr = CoCreateInstance( clsid,
  1647. 0,
  1648. CLSCTX_INPROC_SERVER,
  1649. __uuidof(IAdminIndexServer),
  1650. xAdmin.GetQIPointer() );
  1651. if ( FAILED( hr ) )
  1652. return DisplayError( IDS_CANTFORCEMERGE,
  1653. pwcCatalog,
  1654. hr,
  1655. lcid );
  1656. // Set the machine name.
  1657. BSTR bstrMachine = SysAllocString( pwcMachine );
  1658. if ( 0 == bstrMachine )
  1659. return DisplayError( IDS_CANTFORCEMERGE,
  1660. pwcCatalog,
  1661. E_OUTOFMEMORY,
  1662. lcid );
  1663. XBStr xbstr( bstrMachine );
  1664. hr = xAdmin->put_MachineName( bstrMachine );
  1665. if ( FAILED( hr ) )
  1666. return DisplayError( IDS_CANTFORCEMERGE,
  1667. pwcCatalog,
  1668. hr,
  1669. lcid );
  1670. // Get a catalog administration object.
  1671. BSTR bstrCatalog = SysAllocString( pwcCatalog );
  1672. if ( 0 == bstrCatalog )
  1673. return DisplayError( IDS_CANTFORCEMERGE,
  1674. pwcCatalog,
  1675. E_OUTOFMEMORY,
  1676. lcid );
  1677. xbstr.Free();
  1678. xbstr.Set( bstrCatalog );
  1679. XInterface<ICatAdm> xCatAdmin;
  1680. hr = xAdmin->GetCatalogByName( bstrCatalog,
  1681. (IDispatch **) xCatAdmin.GetQIPointer() );
  1682. if ( FAILED( hr ) )
  1683. return DisplayError( IDS_CANTFORCEMERGE,
  1684. pwcCatalog,
  1685. hr,
  1686. lcid );
  1687. // Force the merge.
  1688. hr = xCatAdmin->ForceMasterMerge();
  1689. if ( FAILED( hr ) )
  1690. return DisplayError( IDS_CANTFORCEMERGE,
  1691. pwcCatalog,
  1692. hr,
  1693. lcid );
  1694. return hr;
  1695. } //ForceMerge
  1696. //+-------------------------------------------------------------------------
  1697. //
  1698. // Function: DisplayUpToDate
  1699. //
  1700. // Synopsis: Checks if the index is up to date.
  1701. //
  1702. // Arguments: [pwcCatalog] - Catalog name
  1703. // [pwcMachine] - Machine on which catalog resides
  1704. // [lcid] - Locale to use
  1705. //
  1706. //--------------------------------------------------------------------------
  1707. HRESULT DisplayUpToDate(
  1708. WCHAR const * pwcCatalog,
  1709. WCHAR const * pwcMachine,
  1710. LCID lcid )
  1711. {
  1712. CI_STATE state;
  1713. state.cbStruct = sizeof state;
  1714. HRESULT hr = CIState( pwcCatalog, pwcMachine, &state );
  1715. if ( SUCCEEDED( hr ) )
  1716. {
  1717. // It's up to date if there are no documents to filter, no scans or
  1718. // usn activity, and the index isn't starting or recovering.
  1719. BOOL fUpToDate = ( ( 0 == state.cDocuments ) &&
  1720. ( 0 == ( state.eState & CI_STATE_SCANNING ) ) &&
  1721. ( 0 == ( state.eState & CI_STATE_READING_USNS ) ) &&
  1722. ( 0 == ( state.eState & CI_STATE_STARTING ) ) &&
  1723. ( 0 == ( state.eState & CI_STATE_RECOVERING ) ) );
  1724. DisplayStat( fUpToDate ? IDS_STAT_UP_TO_DATE :
  1725. IDS_STAT_NOT_UP_TO_DATE );
  1726. }
  1727. else
  1728. {
  1729. DisplayError( IDS_CANTDISPLAYSTATUS, pwcCatalog, hr, lcid );
  1730. }
  1731. return hr;
  1732. } //DisplayUpToDate
  1733. //+-------------------------------------------------------------------------
  1734. //
  1735. // Function: wmain
  1736. //
  1737. // Synopsis: Entry point for the app. Parses command line arguments and
  1738. // issues a query.
  1739. //
  1740. // Arguments: [argc] - Argument count
  1741. // [argv] - Arguments
  1742. //
  1743. //--------------------------------------------------------------------------
  1744. extern "C" int __cdecl wmain( int argc, WCHAR * argv[] )
  1745. {
  1746. WCHAR const * pwcCatalog = 0; // default: lookup catalog
  1747. WCHAR const * pwcMachine = L"."; // default: local machine
  1748. WCHAR const * pwcScope = L"\\"; // default: entire catalog
  1749. WCHAR const * pwcRestriction = 0; // no default restriction
  1750. WCHAR const * pwcColumns = L"path"; // default output column(s)
  1751. WCHAR const * pwcSort = 0; // no sort is the default
  1752. WCHAR const * pwcQueryFile = 0; // no query file specified
  1753. WCHAR const * pwcLocale = 0; // default: system locale
  1754. BOOL fDisplayTree = FALSE; // don't display the tree
  1755. BOOL fForceUseContentIndex = TRUE; // always use the index
  1756. ULONG ulDialect = 1; // old tripolish dialect
  1757. BOOL fQuiet = FALSE; // show the hitcount
  1758. ULONG cMaxHits = 0; // default: retrieve all hits
  1759. BOOL fFirstHits = FALSE; // First vs Best N hits
  1760. BOOL fDisplayStatus = FALSE; // default: don't show status
  1761. BOOL fDisplayUpToDate = FALSE; // default: don't show up to date
  1762. ULONG cRepetitions = 1; // # of times to repeat command
  1763. BOOL fShallow = FALSE; // default: all subdirectories
  1764. BOOL fNoQuery = FALSE; // default: execute query
  1765. BOOL fSearchHit = FALSE; // default: don't isrchdmp.exe
  1766. BOOL fDefineCPP = FALSE; // default: don't define props
  1767. BOOL fForceMerge = FALSE; // default: don't force a MM
  1768. // Parse command line parameters
  1769. for ( int i = 1; i < argc; i++ )
  1770. {
  1771. if ( L'-' == argv[i][0] || L'/' == argv[i][0] )
  1772. {
  1773. WCHAR wc = (WCHAR) toupper( (char) argv[i][1] );
  1774. if ( ':' != argv[i][2] &&
  1775. 'D' != wc &&
  1776. 'G' != wc &&
  1777. 'H' != wc &&
  1778. 'J' != wc &&
  1779. 'N' != wc &&
  1780. 'Q' != wc &&
  1781. 'U' != wc &&
  1782. 'T' != wc &&
  1783. 'Z' != wc )
  1784. Usage();
  1785. if ( 'C' == wc )
  1786. pwcCatalog = argv[i] + 3;
  1787. else if ( 'M' == wc )
  1788. pwcMachine = argv[i] + 3;
  1789. else if ( 'P' == wc )
  1790. pwcScope = argv[i] + 3;
  1791. else if ( 'O' == wc )
  1792. pwcColumns = argv[i] + 3;
  1793. else if ( 'S' == wc )
  1794. pwcSort = argv[i] + 3;
  1795. else if ( 'X' == wc )
  1796. cMaxHits = _wtoi( argv[i] + 3 );
  1797. else if ( 'Y' == wc )
  1798. {
  1799. cMaxHits = _wtoi( argv[i] + 3 );
  1800. fFirstHits = TRUE;
  1801. }
  1802. else if ( 'I' == wc )
  1803. {
  1804. if ( 0 != pwcRestriction )
  1805. Usage();
  1806. pwcQueryFile = argv[i] + 3;
  1807. }
  1808. else if ( 'R' == wc)
  1809. {
  1810. // get the next arg as a number
  1811. cRepetitions = _wtol(argv[i]+3);
  1812. }
  1813. else if ( 'D' == wc )
  1814. fDisplayTree = TRUE;
  1815. else if ( 'G' == wc )
  1816. fForceMerge = TRUE;
  1817. else if ( 'H' == wc )
  1818. fSearchHit = TRUE;
  1819. else if ( 'J' == wc )
  1820. fShallow = TRUE;
  1821. else if ( 'N' == wc )
  1822. fNoQuery = TRUE;
  1823. else if ( 'Q' == wc )
  1824. fQuiet = TRUE;
  1825. else if ( 'T' == wc )
  1826. fDisplayStatus = TRUE;
  1827. else if ( 'U' == wc )
  1828. fDisplayUpToDate = TRUE;
  1829. else if ( 'E' == wc )
  1830. pwcLocale = argv[i] + 3;
  1831. else if ( 'L' == wc )
  1832. {
  1833. if ( '1' == argv[i][3] )
  1834. ulDialect = 1;
  1835. else if ( '2' == argv[i][3] )
  1836. ulDialect = 2;
  1837. else
  1838. Usage();
  1839. }
  1840. else if ( 'F' == wc )
  1841. {
  1842. if ( '+' == argv[i][3] )
  1843. fForceUseContentIndex = TRUE;
  1844. else if ( '-' == argv[i][3] )
  1845. fForceUseContentIndex = FALSE;
  1846. else
  1847. Usage();
  1848. }
  1849. else if ( 'Z' == wc )
  1850. fDefineCPP = TRUE;
  1851. else
  1852. Usage();
  1853. }
  1854. else if ( 0 != pwcRestriction || 0 != pwcQueryFile )
  1855. Usage();
  1856. else
  1857. pwcRestriction = argv[i];
  1858. }
  1859. // A query restriction, query file, or status request is necessary.
  1860. if ( 0 == pwcRestriction && 0 == pwcQueryFile &&
  1861. !fDisplayStatus && !fDisplayUpToDate && !fForceMerge )
  1862. Usage();
  1863. // Normalize relative and virtual scopes
  1864. WCHAR awcScope[ MAX_PATH ];
  1865. DWORD dwScopeFlags;
  1866. HRESULT hr = NormalizeScope( pwcScope, awcScope, fShallow, dwScopeFlags );
  1867. // Initialize OLE
  1868. BOOL fCoInit = FALSE;
  1869. if ( SUCCEEDED( hr ) )
  1870. {
  1871. hr = CoInitialize( 0 );
  1872. if ( SUCCEEDED( hr ) )
  1873. fCoInit = TRUE;
  1874. }
  1875. // Get the locale identifier to use for the query
  1876. LCID lcid = LcidFromHttpAcceptLanguage( pwcLocale );
  1877. HINSTANCE hISearch = 0;
  1878. if ( fSearchHit )
  1879. {
  1880. hISearch = PrepareForISearch();
  1881. if ( 0 == hISearch )
  1882. Usage();
  1883. }
  1884. // If no catalog was specified, infer one based on the scope
  1885. WCHAR awcMachine[ MAX_PATH ], awcCatalog[ MAX_PATH ];
  1886. if ( SUCCEEDED( hr ) && ( 0 == pwcCatalog ) && !fNoQuery )
  1887. {
  1888. ULONG cwcMachine = sizeof awcMachine / sizeof WCHAR;
  1889. ULONG cwcCatalog = sizeof awcCatalog / sizeof WCHAR;
  1890. hr = LookupCatalog( awcScope,
  1891. awcMachine,
  1892. cwcMachine,
  1893. awcCatalog,
  1894. cwcCatalog,
  1895. lcid );
  1896. pwcMachine = awcMachine;
  1897. pwcCatalog = awcCatalog;
  1898. // Turn scopes like \\machine into \ now that the lookup is done
  1899. // and we've found a catalog and machine name.
  1900. if ( SUCCEEDED( hr ) &&
  1901. L'\\' == awcScope[0] && L'\\' == awcScope[1] &&
  1902. 0 == wcschr( awcScope + 2, L'\\' ) )
  1903. awcScope[1] = 0;
  1904. }
  1905. if ( SUCCEEDED( hr ) )
  1906. {
  1907. for (ULONG j = 0; j < cRepetitions; j++)
  1908. {
  1909. if ( 0 != pwcQueryFile )
  1910. hr = DoQueryFile( fNoQuery ? L"::_noquery" : pwcCatalog,
  1911. pwcMachine,
  1912. awcScope,
  1913. dwScopeFlags,
  1914. pwcColumns,
  1915. pwcSort,
  1916. fDisplayTree,
  1917. fQuiet,
  1918. fForceUseContentIndex,
  1919. fNoQuery,
  1920. fSearchHit,
  1921. ulDialect,
  1922. cMaxHits,
  1923. fFirstHits,
  1924. lcid,
  1925. pwcQueryFile,
  1926. fDefineCPP );
  1927. else if ( 0 != pwcRestriction )
  1928. hr = DoQuery( fNoQuery ? L"::_noquery" : pwcCatalog,
  1929. pwcMachine,
  1930. awcScope,
  1931. dwScopeFlags,
  1932. pwcRestriction,
  1933. pwcColumns,
  1934. pwcSort,
  1935. fDisplayTree,
  1936. fQuiet,
  1937. fForceUseContentIndex,
  1938. fNoQuery,
  1939. fSearchHit,
  1940. ulDialect,
  1941. cMaxHits,
  1942. fFirstHits,
  1943. lcid,
  1944. fDefineCPP );
  1945. if ( SUCCEEDED( hr ) && fForceMerge )
  1946. hr = ForceMerge( pwcCatalog, pwcMachine, lcid );
  1947. if ( SUCCEEDED( hr ) && fDisplayStatus )
  1948. hr = DisplayStatus( pwcCatalog, pwcMachine, lcid );
  1949. if ( SUCCEEDED( hr ) && fDisplayUpToDate )
  1950. hr = DisplayUpToDate( pwcCatalog, pwcMachine, lcid );
  1951. }
  1952. }
  1953. if ( fCoInit )
  1954. CoUninitialize();
  1955. if ( 0 != hISearch )
  1956. DoneWithISearch( hISearch );
  1957. if ( FAILED( hr ) )
  1958. return -1;
  1959. return 0;
  1960. } //wmain