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.

1154 lines
42 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: advquery.cxx
  11. //
  12. // PURPOSE: Illustrates an advanced query using Indexing Service.
  13. // Uses the OLE DB Provider for Indexing Service, not
  14. // Indexing Service helper functions.
  15. //
  16. // PLATFORM: Windows 2000
  17. //
  18. //--------------------------------------------------------------------------
  19. #ifndef UNICODE
  20. #define UNICODE
  21. #endif
  22. #include <stdio.h>
  23. #include <windows.h>
  24. #define OLEDBVER 0x0250 // need the command tree definitions
  25. #define DBINITCONSTANTS
  26. #include <oledberr.h>
  27. #include <oledb.h>
  28. #include <cmdtree.h>
  29. #include <olectl.h>
  30. #include <ntquery.h>
  31. // This is found in disptree.cxx
  32. extern void DisplayCommandTree( DBCOMMANDTREE * pNode, ULONG iLevel = 0 );
  33. //+-------------------------------------------------------------------------
  34. //
  35. // Template: XInterface
  36. //
  37. // Synopsis: Template for managing ownership of interfaces
  38. //
  39. //--------------------------------------------------------------------------
  40. template<class T> class XInterface
  41. {
  42. public:
  43. XInterface( T * p = 0 ) : _p( p ) {}
  44. ~XInterface() { if ( 0 != _p ) _p->Release(); }
  45. T * operator->() { return _p; }
  46. T * GetPointer() const { return _p; }
  47. IUnknown ** GetIUPointer() { return (IUnknown **) &_p; }
  48. T ** GetPPointer() { return &_p; }
  49. void ** GetQIPointer() { return (void **) &_p; }
  50. T * Acquire() { T * p = _p; _p = 0; return p; }
  51. private:
  52. T * _p;
  53. };
  54. //+-------------------------------------------------------------------------
  55. //
  56. // Function: CreateICommand
  57. //
  58. // Synopsis: Creates an ICommand.
  59. //
  60. // Arguments: [ppICommand] - Where the ICommand is returned on success
  61. //
  62. // Returns: HRESULT result
  63. //
  64. //--------------------------------------------------------------------------
  65. HRESULT CreateICommand( ICommand ** ppICommand )
  66. {
  67. // Instantiate the data source object
  68. XInterface<IDBInitialize> xIDBInit;
  69. static const GUID guidIndexingServiceDSO = CLSID_INDEX_SERVER_DSO;
  70. HRESULT hr = CoCreateInstance( guidIndexingServiceDSO,
  71. 0,
  72. CLSCTX_INPROC_SERVER,
  73. IID_IDBInitialize,
  74. xIDBInit.GetQIPointer() );
  75. if ( FAILED(hr) )
  76. return hr;
  77. // Initialize, verifying that we supplied the right variables
  78. hr = xIDBInit->Initialize();
  79. if ( FAILED(hr) )
  80. return hr;
  81. // Get a session object
  82. XInterface<IDBCreateSession> xIDBSess;
  83. hr = xIDBInit->QueryInterface( IID_IDBCreateSession,
  84. xIDBSess.GetQIPointer() );
  85. if ( FAILED(hr) )
  86. return hr;
  87. // Get a Create Command object
  88. XInterface<IDBCreateCommand> xICreateCommand;
  89. hr = xIDBSess->CreateSession( 0,
  90. IID_IDBCreateCommand,
  91. xICreateCommand.GetIUPointer() );
  92. if ( FAILED(hr) )
  93. return hr;
  94. // Create the ICommand
  95. XInterface<ICommand> xICommand;
  96. hr = xICreateCommand->CreateCommand( 0,
  97. IID_ICommand,
  98. xICommand.GetIUPointer() );
  99. if ( FAILED(hr) )
  100. return hr;
  101. *ppICommand = xICommand.Acquire();
  102. return hr;
  103. } //CreateICommand
  104. //+-------------------------------------------------------------------------
  105. //
  106. // Function: SetCommandProperties
  107. //
  108. // Synopsis: Sets the DBPROP_USEEXTENDEDDBTYPES property to TRUE, so
  109. // data is returned in PROPVARIANTs, as opposed to the
  110. // default, which is OLE automation VARIANTs. PROPVARIANTS
  111. // allow a superset of VARIANT data types. Use of these
  112. // types avoids costly coercions.
  113. //
  114. // Also sets the DBPROP_USECONTENTINDEX property to TRUE, so
  115. // the index will always be used to resolve the query (as
  116. // opposed to enumerating all the files on the disk), even
  117. // if the index is out of date.
  118. //
  119. // Also sets the asynchronous property, so the Execute() call
  120. // returns before the query is complete.
  121. //
  122. // Both of these properties are unique to the OLE DB Provider
  123. // for Indexing Service implementation.
  124. //
  125. // Arguments: [pICommand] - The ICommand used to set the property
  126. //
  127. // Returns: HRESULT result of setting the properties
  128. //
  129. //--------------------------------------------------------------------------
  130. HRESULT SetCommandProperties( ICommand * pICommand )
  131. {
  132. static const DBID dbcolNull = { { 0,0,0, { 0,0,0,0,0,0,0,0 } },
  133. DBKIND_GUID_PROPID, 0 };
  134. static const GUID guidQueryExt = DBPROPSET_QUERYEXT;
  135. static const GUID guidRowsetProps = DBPROPSET_ROWSET;
  136. DBPROP aProp[3];
  137. aProp[0].dwPropertyID = DBPROP_USEEXTENDEDDBTYPES;
  138. aProp[0].dwOptions = DBPROPOPTIONS_OPTIONAL;
  139. aProp[0].dwStatus = 0;
  140. aProp[0].colid = dbcolNull;
  141. aProp[0].vValue.vt = VT_BOOL;
  142. aProp[0].vValue.boolVal = VARIANT_TRUE;
  143. aProp[1] = aProp[0];
  144. aProp[1].dwPropertyID = DBPROP_USECONTENTINDEX;
  145. aProp[2] = aProp[0];
  146. aProp[2].dwOptions = DBPROPOPTIONS_REQUIRED;
  147. aProp[2].dwPropertyID = DBPROP_IDBAsynchStatus;
  148. DBPROPSET aPropSet[2];
  149. aPropSet[0].rgProperties = &aProp[0];
  150. aPropSet[0].cProperties = 2;
  151. aPropSet[0].guidPropertySet = guidQueryExt;
  152. aPropSet[1].rgProperties = &aProp[2];
  153. aPropSet[1].cProperties = 1;
  154. aPropSet[1].guidPropertySet = guidRowsetProps;
  155. XInterface<ICommandProperties> xICommandProperties;
  156. HRESULT hr = pICommand->QueryInterface( IID_ICommandProperties,
  157. xICommandProperties.GetQIPointer() );
  158. if ( FAILED( hr ) )
  159. return hr;
  160. return xICommandProperties->SetProperties( 2, // 2 property sets
  161. aPropSet ); // the properties
  162. } //SetCommandProperties
  163. //+-------------------------------------------------------------------------
  164. //
  165. // Function: SetScopeCatalogAndMachine
  166. //
  167. // Synopsis: Sets the catalog and machine properties in the ICommand.
  168. // Also sets a default scope.
  169. //
  170. // Arguments: [pICommand] - ICommand to set props on
  171. // [pwcQueryScope] - Scope for the query
  172. // [pwcQueryCatalog] - Catalog name over which query is run
  173. // [pwcQueryMachine] - Machine name on which query is run
  174. //
  175. // Returns: HRESULT result of the operation
  176. //
  177. //--------------------------------------------------------------------------
  178. HRESULT SetScopeCatalogAndMachine(
  179. ICommand * pICommand,
  180. WCHAR const * pwcQueryScope,
  181. WCHAR const * pwcQueryCatalog,
  182. WCHAR const * pwcQueryMachine )
  183. {
  184. // Get an ICommandProperties so we can set the properties
  185. XInterface<ICommandProperties> xICommandProperties;
  186. HRESULT hr = pICommand->QueryInterface( IID_ICommandProperties,
  187. xICommandProperties.GetQIPointer() );
  188. if ( FAILED( hr ) )
  189. return hr;
  190. // note: SysAllocString, SafeArrayCreate, and SafeArrayPutElement can
  191. // fail, but this isn't checked here for brevity.
  192. SAFEARRAYBOUND rgBound[1];
  193. rgBound[0].lLbound = 0;
  194. rgBound[0].cElements = 1;
  195. SAFEARRAY * pMachines = SafeArrayCreate( VT_BSTR, 1, rgBound );
  196. long i = 0;
  197. SafeArrayPutElement( pMachines, &i, SysAllocString( pwcQueryMachine ) );
  198. SAFEARRAY * pCatalogs = SafeArrayCreate( VT_BSTR, 1, rgBound );
  199. SafeArrayPutElement( pCatalogs, &i, SysAllocString( pwcQueryCatalog ) );
  200. SAFEARRAY * pScopes = SafeArrayCreate( VT_BSTR, 1, rgBound );
  201. SafeArrayPutElement( pScopes, &i, SysAllocString( pwcQueryScope ) );
  202. LONG lFlags = QUERY_DEEP;
  203. SAFEARRAY * pFlags = SafeArrayCreate( VT_I4, 1, rgBound );
  204. SafeArrayPutElement( pFlags, &i, &lFlags );
  205. DBPROP aScopeProperties[2];
  206. memset( aScopeProperties, 0, sizeof aScopeProperties );
  207. aScopeProperties[0].dwPropertyID = DBPROP_CI_INCLUDE_SCOPES;
  208. aScopeProperties[0].vValue.vt = VT_BSTR | VT_ARRAY;
  209. aScopeProperties[0].vValue.parray = pScopes;
  210. aScopeProperties[0].colid.eKind = DBKIND_GUID_PROPID;
  211. aScopeProperties[1].dwPropertyID = DBPROP_CI_SCOPE_FLAGS;
  212. aScopeProperties[1].vValue.vt = VT_I4 | VT_ARRAY;
  213. aScopeProperties[1].vValue.parray = pFlags;
  214. aScopeProperties[1].colid.eKind = DBKIND_GUID_PROPID;
  215. DBPROP aCatalogProperties[1];
  216. memset( aCatalogProperties, 0, sizeof aCatalogProperties );
  217. aCatalogProperties[0].dwPropertyID = DBPROP_CI_CATALOG_NAME;
  218. aCatalogProperties[0].vValue.vt = VT_BSTR | VT_ARRAY;
  219. aCatalogProperties[0].vValue.parray = pCatalogs;
  220. aCatalogProperties[0].colid.eKind = DBKIND_GUID_PROPID;
  221. DBPROP aMachineProperties[1];
  222. memset( aMachineProperties, 0, sizeof aMachineProperties );
  223. aMachineProperties[0].dwPropertyID = DBPROP_MACHINE;
  224. aMachineProperties[0].vValue.vt = VT_BSTR | VT_ARRAY;
  225. aMachineProperties[0].vValue.parray = pMachines;
  226. aMachineProperties[0].colid.eKind = DBKIND_GUID_PROPID;
  227. const GUID guidFSCI = DBPROPSET_FSCIFRMWRK_EXT;
  228. DBPROPSET aAllPropsets[3];
  229. aAllPropsets[0].rgProperties = aScopeProperties;
  230. aAllPropsets[0].cProperties = 2;
  231. aAllPropsets[0].guidPropertySet = guidFSCI;
  232. aAllPropsets[1].rgProperties = aCatalogProperties;
  233. aAllPropsets[1].cProperties = 1;
  234. aAllPropsets[1].guidPropertySet = guidFSCI;
  235. const GUID guidCI = DBPROPSET_CIFRMWRKCORE_EXT;
  236. aAllPropsets[2].rgProperties = aMachineProperties;
  237. aAllPropsets[2].cProperties = 1;
  238. aAllPropsets[2].guidPropertySet = guidCI;
  239. const ULONG cPropertySets = sizeof aAllPropsets / sizeof aAllPropsets[0];
  240. hr = xICommandProperties->SetProperties( cPropertySets, // # of propsets
  241. aAllPropsets ); // the propsets
  242. SafeArrayDestroy( pScopes );
  243. SafeArrayDestroy( pFlags );
  244. SafeArrayDestroy( pCatalogs );
  245. SafeArrayDestroy( pMachines );
  246. return hr;
  247. } //SetScopeCatalogAndMachine
  248. //+-------------------------------------------------------------------------
  249. //
  250. // Function: AllocAndCopy
  251. //
  252. // Synopsis: Allocates and duplicates a string.
  253. //
  254. // Arguments: [pwcIn] - The string to copy
  255. //
  256. // Returns: A string
  257. //
  258. //--------------------------------------------------------------------------
  259. WCHAR * AllocAndCopy( WCHAR const * pwcIn )
  260. {
  261. ULONG cwc = wcslen( pwcIn ) + 1;
  262. // note: CoTaskMemAlloc can return 0 if out of memory, not checked
  263. WCHAR * pwc = (WCHAR *) CoTaskMemAlloc( cwc * sizeof WCHAR );
  264. wcscpy( pwc, pwcIn );
  265. return pwc;
  266. } //AllocAndCopy
  267. //+-------------------------------------------------------------------------
  268. //
  269. // Function: NewTreeNode
  270. //
  271. // Synopsis: Allocates and initializes a DBCOMMANDTREE object
  272. //
  273. // Arguments: [op] - The node's operator
  274. // [wKind] - The kind of node
  275. //
  276. // Returns: an initialized DBCOMMANDTREE object
  277. //
  278. //--------------------------------------------------------------------------
  279. DBCOMMANDTREE * NewTreeNode(
  280. DBCOMMANDOP op,
  281. WORD wKind )
  282. {
  283. DBCOMMANDTREE * pTree = (DBCOMMANDTREE *)
  284. CoTaskMemAlloc( sizeof DBCOMMANDTREE );
  285. memset( pTree, 0, sizeof DBCOMMANDTREE );
  286. pTree->op = op;
  287. pTree->wKind = wKind;
  288. return pTree;
  289. } //NewTreeNode
  290. //+-------------------------------------------------------------------------
  291. //
  292. // Function: CreateQueryTree
  293. //
  294. // Synopsis: Creates a DBCOMMANDTREE for the query
  295. //
  296. // Arguments: [pwcQueryRestrition] - The actual query string
  297. // [ppTree] - Resulting query tree
  298. //
  299. // Returns: HRESULT result of the operation
  300. //
  301. // Notes: The query tree has a string restriction, a list of
  302. // columns to return (rank, size, and path), and a sort
  303. // order (rank).
  304. // Here are two views of the query tree
  305. //
  306. // sort:
  307. // child: project
  308. // sibling: sort_list_anchor
  309. // child: sort_list_element
  310. // value: SORTINFO (descending, lcid)
  311. // child: column_name
  312. // value: DBID rank
  313. // child: select
  314. // sibling: project_list_anchor
  315. // child: project_list_element
  316. // child: column_name
  317. // value: DBID rank
  318. // sibling: project_list_element
  319. // child: column_name
  320. // value: DBID size
  321. // sibling: project_list_element
  322. // child: column_name
  323. // value: DBID path
  324. // child: table_name
  325. // value: WSTR: "Table"
  326. // sibling: content
  327. // value: DBCONTENT (restriction, weight, lcid)
  328. // child: column_name
  329. // value: DBID contents
  330. //
  331. // +---------------------------+
  332. // | DBOP_sort |
  333. // | DBVALUEKIND_EMPTY |
  334. // +---------------------------+
  335. // |
  336. // |child
  337. // | sibling
  338. // +---------------------------+-------+---------------------------+
  339. // | DBOP_project | | DBOP_sort_list_anchor |
  340. // | DBVALUEKIND_EMPTY | | DBVALUEKIND_EMPTY |
  341. // +---------------------------+ +---------------------------+
  342. // | |
  343. // |child |child
  344. // | |
  345. // | +---------------------------+
  346. // | | DBOP_sort_list_element |
  347. // | | DBVALUEKIND_SORTINFO |
  348. // | +---------------------------+
  349. // | | |
  350. // | |child | pdbsrtinfValue
  351. // | | |
  352. // | | +-------------+
  353. // | | | DBSORTIFO |
  354. // | | | fDesc TRUE |
  355. // | | | lcid system |
  356. // | | +-------------+
  357. // | |
  358. // | |
  359. // | |
  360. // | +---------------------------+
  361. // | | DBOP_column_name |
  362. // | | DBVALUEKIND_ID |
  363. // | +---------------------------+
  364. // | |
  365. // | | pdbidValue
  366. // | |
  367. // | +------+
  368. // | | DBID |
  369. // | | rank |
  370. // | +------+
  371. // |
  372. // | sibling
  373. // +---------------------------+-------+---------------------------+-------+
  374. // | DBOP_select | | DBOP_project_list_anchor | | s
  375. // | DBVALUEKIND_EMPTY | | DBVALUEKIND_EMPTY | | i
  376. // +---------------------------+ +---------------------------+ | b
  377. // | | | l
  378. // |child |child | i
  379. // | | | n
  380. // | +---------------------------+ | g
  381. // | | DBOP_project_list_element | |
  382. // | | DBVALUEKIND_EMPTY | |
  383. // | +---------------------------+ |
  384. // | | |
  385. // | |child |
  386. // | | |
  387. // | +---------------------------+ |
  388. // | | DBOP_column_name | |
  389. // | | DBVALUEKIND_ID | |
  390. // | +---------------------------+ |
  391. // | | |
  392. // | | pdbidValue |
  393. // | | |
  394. // | +------+ |
  395. // | | DBID | |
  396. // | | rank | |
  397. // | +------+ |
  398. // | |
  399. // | +-----------------------------------+
  400. // | |
  401. // | +---------------------------+-------+
  402. // | | DBOP_project_list_element | | s
  403. // | | DBVALUEKIND_EMPTY | | i
  404. // | +---------------------------+ | b
  405. // | | | l
  406. // | |child | i
  407. // | | | n
  408. // | +---------------------------+ | g
  409. // | | DBOP_column_name | |
  410. // | | DBVALUEKIND_ID | |
  411. // | +---------------------------+ |
  412. // | | |
  413. // | | pdbidValue |
  414. // | | |
  415. // | +------+ |
  416. // | | DBID | |
  417. // | | size | |
  418. // | +------+ |
  419. // | |
  420. // | +-----------------------------------+
  421. // | |
  422. // | +---------------------------+
  423. // | | DBOP_project_list_element |
  424. // | | DBVALUEKIND_EMPTY |
  425. // | +---------------------------+
  426. // | |
  427. // | |child
  428. // | |
  429. // | +---------------------------+
  430. // | | DBOP_column_name |
  431. // | | DBVALUEKIND_ID |
  432. // | +---------------------------+
  433. // | |
  434. // | | pdbidValue
  435. // | |
  436. // | +------+
  437. // | | DBID |
  438. // | | path |
  439. // | +------+
  440. // |
  441. // | sibling
  442. // +---------------------------+-------+---------------------------+
  443. // | DBOP_table_name | | DBOP_content |
  444. // | DBVALUEKIND_WSTR: 'Table' | | DBVALUEKIND_CONTENT |
  445. // +---------------------------+ +---------------------------+
  446. // | |
  447. // |child | pdbcntntValue
  448. // | |
  449. // | +---------------------------+
  450. // | | DBCONTENT |
  451. // | | dwGenerateMethod: GENERATE_METHOD_EXACT |
  452. // | | lWeight: 1000 |
  453. // | | lcid: system |
  454. // | | pwszPhrase: the query |
  455. // | +---------------------------+
  456. // |
  457. // |
  458. // |
  459. // +---------------------------+
  460. // | DBOP_column_name |
  461. // | DBVALUEKIND_ID |
  462. // +---------------------------+
  463. // |
  464. // | pdbidValue
  465. // |
  466. // +----------+
  467. // | DBID |
  468. // | contents |
  469. // +----------+
  470. //
  471. //--------------------------------------------------------------------------
  472. HRESULT CreateQueryTree(
  473. WCHAR const * pwcQueryRestriction,
  474. DBCOMMANDTREE ** ppTree )
  475. {
  476. // These are the properties that'll be referenced below
  477. const DBID dbidContents = { PSGUID_STORAGE, DBKIND_GUID_PROPID,
  478. (LPOLESTR) PID_STG_CONTENTS };
  479. const DBID dbidPath = { PSGUID_STORAGE, DBKIND_GUID_PROPID,
  480. (LPOLESTR) PID_STG_PATH };
  481. const DBID dbidSize = { PSGUID_STORAGE, DBKIND_GUID_PROPID,
  482. (LPOLESTR) PID_STG_SIZE };
  483. DBID dbidRank;
  484. dbidRank.uGuid.guid = PSGUID_QUERY;
  485. dbidRank.eKind = DBKIND_GUID_PROPID;
  486. dbidRank.uName.ulPropid = PROPID_QUERY_RANK ;
  487. // The restriction is a content node with either a word or a phrase.
  488. // This is the most simple possible query. Other types of nodes include
  489. // AND, OR, NOT, etc.
  490. // The CITextToFullTree function is available for building more complex
  491. // queries given a text string.
  492. DBCOMMANDTREE *pRestriction = NewTreeNode( DBOP_content,
  493. DBVALUEKIND_CONTENT );
  494. DBCONTENT * pDBContent = (DBCONTENT *) CoTaskMemAlloc( sizeof DBCONTENT );
  495. memset( pDBContent, 0, sizeof DBCONTENT );
  496. pRestriction->value.pdbcntntValue = pDBContent;
  497. pDBContent->dwGenerateMethod = GENERATE_METHOD_EXACT;
  498. pDBContent->lWeight = 1000; // maximum possible weight
  499. pDBContent->lcid = GetSystemDefaultLCID();
  500. pDBContent->pwszPhrase = AllocAndCopy( pwcQueryRestriction );
  501. // This identifies "file contents" as the property for the restrition
  502. DBCOMMANDTREE *pPropID = NewTreeNode( DBOP_column_name, DBVALUEKIND_ID );
  503. pRestriction->pctFirstChild = pPropID;
  504. DBID *pDBID = (DBID *) CoTaskMemAlloc( sizeof DBID );
  505. *pDBID = dbidContents;
  506. pPropID->value.pdbidValue = pDBID;
  507. DBCOMMANDTREE *pSelect = NewTreeNode( DBOP_select, DBVALUEKIND_EMPTY );
  508. DBCOMMANDTREE *pTableId = NewTreeNode( DBOP_table_name, DBVALUEKIND_WSTR );
  509. pSelect->pctFirstChild = pTableId;
  510. pTableId->value.pwszValue = AllocAndCopy( L"Table" );
  511. pTableId->pctNextSibling = pRestriction;
  512. DBCOMMANDTREE *pProject = NewTreeNode( DBOP_project, DBVALUEKIND_EMPTY );
  513. pProject->pctFirstChild = pSelect;
  514. // The project anchor holds the list of columns that are retrieved
  515. DBCOMMANDTREE * pProjectAnchor = NewTreeNode( DBOP_project_list_anchor,
  516. DBVALUEKIND_EMPTY );
  517. pSelect->pctNextSibling = pProjectAnchor;
  518. // Retrieve rank as column 1
  519. DBCOMMANDTREE * pProjectRank = NewTreeNode( DBOP_project_list_element,
  520. DBVALUEKIND_EMPTY );
  521. pProjectAnchor->pctFirstChild = pProjectRank;
  522. DBCOMMANDTREE * pColumnRank = NewTreeNode( DBOP_column_name,
  523. DBVALUEKIND_ID );
  524. pProjectRank->pctFirstChild = pColumnRank;
  525. DBID *pDBIDRank = (DBID *) CoTaskMemAlloc( sizeof DBID );
  526. pColumnRank->value.pdbidValue = pDBIDRank;
  527. *pDBIDRank = dbidRank;
  528. // Retrieve file size as column 2
  529. DBCOMMANDTREE * pProjectSize = NewTreeNode( DBOP_project_list_element,
  530. DBVALUEKIND_EMPTY );
  531. pProjectRank->pctNextSibling = pProjectSize;
  532. DBCOMMANDTREE * pColumnSize = NewTreeNode( DBOP_column_name,
  533. DBVALUEKIND_ID );
  534. pProjectSize->pctFirstChild = pColumnSize;
  535. DBID *pDBIDSize = (DBID *) CoTaskMemAlloc( sizeof DBID );
  536. pColumnSize->value.pdbidValue = pDBIDSize;
  537. *pDBIDSize = dbidSize;
  538. // Retrieve file path as column 3
  539. DBCOMMANDTREE * pProjectPath = NewTreeNode( DBOP_project_list_element,
  540. DBVALUEKIND_EMPTY );
  541. pProjectSize->pctNextSibling = pProjectPath;
  542. DBCOMMANDTREE * pColumnPath = NewTreeNode( DBOP_column_name,
  543. DBVALUEKIND_ID );
  544. pProjectPath->pctFirstChild = pColumnPath;
  545. DBID *pDBIDPath = (DBID *) CoTaskMemAlloc( sizeof DBID );
  546. pColumnPath->value.pdbidValue = pDBIDPath;
  547. *pDBIDPath = dbidPath;
  548. // The sort node specifies the sort order for the results
  549. DBCOMMANDTREE * pSort = NewTreeNode( DBOP_sort, DBVALUEKIND_EMPTY );
  550. pSort->pctFirstChild = pProject;
  551. // The sort anchor is the start of the list of sort properties
  552. DBCOMMANDTREE * pSortAnchor = NewTreeNode( DBOP_sort_list_anchor,
  553. DBVALUEKIND_EMPTY );
  554. pProject->pctNextSibling = pSortAnchor;
  555. // The sort order is rank
  556. DBCOMMANDTREE * pSortRank = NewTreeNode( DBOP_sort_list_element,
  557. DBVALUEKIND_SORTINFO );
  558. pSortAnchor->pctFirstChild = pSortRank;
  559. DBSORTINFO * pSortInfo = (DBSORTINFO *) CoTaskMemAlloc( sizeof DBSORTINFO );
  560. memset( pSortInfo, 0, sizeof DBSORTINFO );
  561. pSortRank->value.pdbsrtinfValue = pSortInfo;
  562. pSortInfo->fDesc = TRUE; // descending, not ascending
  563. pSortInfo->lcid = GetSystemDefaultLCID();
  564. DBCOMMANDTREE * pSortColumnRank = NewTreeNode( DBOP_column_name,
  565. DBVALUEKIND_ID );
  566. pSortRank->pctFirstChild = pSortColumnRank;
  567. DBID *pDBIDSortRank = (DBID *) CoTaskMemAlloc( sizeof DBID );
  568. pSortColumnRank->value.pdbidValue = pDBIDSortRank;
  569. *pDBIDSortRank = dbidRank;
  570. // The sort node is the head of the tree
  571. *ppTree = pSort;
  572. return S_OK;
  573. } //CreateQueryTree
  574. //+---------------------------------------------------------------------------
  575. //
  576. // Class: CAsynchNotify
  577. //
  578. // Synopsis: Class for the IDBAsynchNotify callbacks
  579. //
  580. //----------------------------------------------------------------------------
  581. class CAsynchNotify : public IDBAsynchNotify
  582. {
  583. public:
  584. CAsynchNotify() :
  585. _cRef( 1 ),
  586. _cLowResource( 0 ),
  587. _hEvent( 0 )
  588. {
  589. _hEvent = CreateEventW( 0, TRUE, FALSE, 0 );
  590. }
  591. ~CAsynchNotify()
  592. {
  593. if ( 0 != _hEvent )
  594. CloseHandle( _hEvent );
  595. }
  596. BOOL IsValid() const { return 0 != _hEvent; }
  597. //
  598. // IUnknown methods.
  599. //
  600. STDMETHOD(QueryInterface) ( REFIID riid, LPVOID *ppiuk )
  601. {
  602. *ppiuk = (void **) this; // hold our breath and jump
  603. AddRef();
  604. return S_OK;
  605. }
  606. STDMETHOD_( ULONG, AddRef ) () { return InterlockedIncrement( &_cRef ); }
  607. STDMETHOD_( ULONG, Release) () { return InterlockedDecrement( &_cRef ); }
  608. //
  609. // IDBAsynchNotify methods
  610. //
  611. STDMETHOD( OnLowResource ) ( DB_DWRESERVE dwReserved )
  612. {
  613. _cLowResource++;
  614. // If we've failed a few times due to low resource, give up
  615. // on the query since there may not be sufficient resources
  616. // to ever get an OnStop call.
  617. if ( _cLowResource >= 5 )
  618. SetEvent( _hEvent );
  619. return S_OK;
  620. }
  621. STDMETHOD( OnProgress ) ( HCHAPTER hChap, DBASYNCHOP ulOp,
  622. DBCOUNTITEM ulProg, DBCOUNTITEM ulProgMax,
  623. DBASYNCHPHASE ulStat, LPOLESTR pwszStatus )
  624. {
  625. return S_OK;
  626. }
  627. STDMETHOD( OnStop ) ( HCHAPTER hChap, ULONG ulOp,
  628. HRESULT hrStat, LPOLESTR pwszStatus )
  629. {
  630. // If the query is complete (successfully or not), set the event
  631. if ( DBASYNCHOP_OPEN == ulOp )
  632. SetEvent( _hEvent );
  633. return S_OK;
  634. }
  635. void Wait()
  636. {
  637. WaitForSingleObject( _hEvent, INFINITE );
  638. }
  639. private:
  640. LONG _cRef;
  641. LONG _cLowResource;
  642. HANDLE _hEvent;
  643. };
  644. //+-------------------------------------------------------------------------
  645. //
  646. // Function: WaitForQueryToComplete
  647. //
  648. // Synopsis: Waits for the query to complete. This function polls for
  649. // completion. Alternatively, the IConnectionPointContainer
  650. // and IRowsetWatchNotify interfaces could be used for
  651. // asynchronous notification when the query completes.
  652. //
  653. // Arguments: [pRowset] -- The rowset to wait for
  654. //
  655. // Returns: HRESULT result
  656. //
  657. //--------------------------------------------------------------------------
  658. HRESULT WaitForQueryToComplete( IRowset * pRowset )
  659. {
  660. HRESULT hr;
  661. //
  662. // Both methods (notifications and polling) work. It depends on the
  663. // application which is the best choice.
  664. //
  665. #if 1
  666. // Register for notifications
  667. XInterface<IConnectionPointContainer> xCPC;
  668. hr = pRowset->QueryInterface( IID_IConnectionPointContainer,
  669. xCPC.GetQIPointer() );
  670. if (FAILED(hr))
  671. return hr;
  672. XInterface<IConnectionPoint> xCP;
  673. hr = xCPC->FindConnectionPoint( IID_IDBAsynchNotify,
  674. xCP.GetPPointer() );
  675. if (FAILED(hr) && CONNECT_E_NOCONNECTION != hr )
  676. return hr;
  677. CAsynchNotify Notify;
  678. if ( !Notify.IsValid() )
  679. return HRESULT_FROM_WIN32( GetLastError() );
  680. DWORD dwAdviseID;
  681. hr = xCP->Advise( (IUnknown *) &Notify, &dwAdviseID );
  682. if (FAILED(hr))
  683. return hr;
  684. //
  685. // In a real app, we'd be off doing other work rather than waiting
  686. // for the query to complete, but this will do.
  687. // MsgWaitForSingleObject is a good choice for a GUI app. You could
  688. // also post a user-defined windows message when a notification is
  689. // received.
  690. //
  691. Notify.Wait();
  692. hr = xCP->Unadvise( dwAdviseID );
  693. if ( S_OK != hr )
  694. return hr;
  695. Notify.Release();
  696. #else
  697. // Poll for query completion
  698. XInterface<IDBAsynchStatus> xIDBAsynch;
  699. hr = pRowset->QueryInterface( IID_IDBAsynchStatus,
  700. xIDBAsynch.GetQIPointer() );
  701. if ( FAILED( hr ) )
  702. return hr;
  703. do
  704. {
  705. DBCOUNTITEM Numerator, Denominator;
  706. DBASYNCHPHASE Phase;
  707. hr = xIDBAsynch->GetStatus( DB_NULL_HCHAPTER,
  708. DBASYNCHOP_OPEN,
  709. &Numerator,
  710. &Denominator,
  711. &Phase,
  712. 0 );
  713. if ( FAILED( hr ) )
  714. return hr;
  715. if ( DBASYNCHPHASE_COMPLETE == Phase )
  716. break;
  717. Sleep( 50 ); // Give the query a chance to run
  718. } while ( TRUE );
  719. #endif
  720. return hr;
  721. } //WaitForQueryToComplete
  722. //+-------------------------------------------------------------------------
  723. //
  724. // Function: DoQuery
  725. //
  726. // Synopsis: Creates and executes a query, then displays the results.
  727. //
  728. // Arguments: [pwcQueryScope] - Root path for all results
  729. // [pwcQueryCatalog] - Catalog name over which query is run
  730. // [pwcQueryMachine] - Machine name on which query is run
  731. // [pwcQueryRestrition] - The actual query string
  732. // [fDisplayTree] - TRUE to display the command tree
  733. //
  734. // Returns: HRESULT result of the query
  735. //
  736. //--------------------------------------------------------------------------
  737. HRESULT DoQuery(
  738. WCHAR const * pwcQueryScope,
  739. WCHAR const * pwcQueryCatalog,
  740. WCHAR const * pwcQueryMachine,
  741. WCHAR const * pwcQueryRestriction,
  742. BOOL fDisplayTree )
  743. {
  744. // Create an ICommand object. The default scope for the query is the
  745. // entire catalog.
  746. XInterface<ICommand> xICommand;
  747. HRESULT hr = CreateICommand( xICommand.GetPPointer() );
  748. if ( FAILED( hr ) )
  749. return hr;
  750. // Set the scope, catalog, and machine in the ICommand
  751. hr = SetScopeCatalogAndMachine( xICommand.GetPointer(),
  752. pwcQueryScope,
  753. pwcQueryCatalog,
  754. pwcQueryMachine );
  755. if ( FAILED( hr ) )
  756. return hr;
  757. // Set required properties on the ICommand
  758. hr = SetCommandProperties( xICommand.GetPointer() );
  759. if ( FAILED( hr ) )
  760. return hr;
  761. // Create an OLE DB query tree from a text restriction
  762. DBCOMMANDTREE * pTree;
  763. hr = CreateQueryTree( pwcQueryRestriction, // the input query
  764. &pTree ); // the output tree
  765. if ( FAILED( hr ) )
  766. return hr;
  767. // If directed, display the command tree
  768. if ( fDisplayTree )
  769. DisplayCommandTree( pTree );
  770. // Set the tree in the ICommandTree
  771. XInterface<ICommandTree> xICommandTree;
  772. hr = xICommand->QueryInterface( IID_ICommandTree,
  773. xICommandTree.GetQIPointer() );
  774. if ( FAILED( hr ) )
  775. return hr;
  776. hr = xICommandTree->SetCommandTree( &pTree,
  777. DBCOMMANDREUSE_NONE,
  778. FALSE );
  779. if ( FAILED( hr ) )
  780. return hr;
  781. // Execute the query. The query is asynchronously executed.
  782. XInterface<IRowset> xIRowset;
  783. hr = xICommand->Execute( 0, // no aggregating IUnknown
  784. IID_IRowset, // IID for interface to return
  785. 0, // no DBPARAMs
  786. 0, // no rows affected
  787. xIRowset.GetIUPointer() ); // result
  788. if ( FAILED( hr ) )
  789. return hr;
  790. // Wait for the query to complete, since DBPROP_IDBAsynchStatus was set
  791. // as a command property. If DBPROP_IDBAsynchStatus isn't set, Execute()
  792. // is synchronous and there is no need to wait for completion here.
  793. hr = WaitForQueryToComplete( xIRowset.GetPointer() );
  794. if ( FAILED( hr ) )
  795. return hr;
  796. // Create an accessor, so data can be retrieved from the rowset
  797. XInterface<IAccessor> xIAccessor;
  798. hr = xIRowset->QueryInterface( IID_IAccessor,
  799. xIAccessor.GetQIPointer() );
  800. if ( FAILED( hr ) )
  801. return hr;
  802. // Column iOrdinals are parallel with those passed to CiTextToFullTree,
  803. // so MapColumnIDs isn't necessary. These binding values for dwPart,
  804. // dwMemOwner, and wType are the most optimal bindings for Indexing
  805. // Service.
  806. const ULONG cColumns = 3; // 3 for Rank, Size, and Path
  807. DBBINDING aColumns[ cColumns ];
  808. memset( aColumns, 0, sizeof aColumns );
  809. aColumns[0].iOrdinal = 1; // first column specified above (rank)
  810. aColumns[0].obValue = 0; // offset where value is written in GetData
  811. aColumns[0].dwPart = DBPART_VALUE; // retrieve value, not status
  812. aColumns[0].dwMemOwner = DBMEMOWNER_PROVIDEROWNED; // Provider owned
  813. aColumns[0].wType = DBTYPE_VARIANT | DBTYPE_BYREF; // VARIANT *
  814. aColumns[1] = aColumns[0];
  815. aColumns[1].iOrdinal = 2; // second column specified above (size)
  816. aColumns[1].obValue = sizeof (PROPVARIANT *); // offset for value
  817. aColumns[2] = aColumns[0];
  818. aColumns[2].iOrdinal = 3; // third column specified above (path)
  819. aColumns[2].obValue = 2 * sizeof (PROPVARIANT *); // offset for value
  820. HACCESSOR hAccessor;
  821. hr = xIAccessor->CreateAccessor( DBACCESSOR_ROWDATA, // rowdata accessor
  822. cColumns, // # of columns
  823. aColumns, // columns
  824. 0, // ignored
  825. &hAccessor, // result
  826. 0 ); // no status
  827. if ( FAILED( hr ) )
  828. return hr;
  829. // Display the results of the query. Print file size and file path.
  830. printf( " Rank Size Path\n" );
  831. DBCOUNTITEM cRowsSoFar = 0;
  832. do
  833. {
  834. DBCOUNTITEM cRowsReturned = 0;
  835. const ULONG cRowsAtATime = 10;
  836. HROW aHRow[cRowsAtATime];
  837. HROW * pgrHRows = aHRow;
  838. hr = xIRowset->GetNextRows( 0, // no chapter
  839. 0, // no rows to skip
  840. cRowsAtATime, // # rows to get
  841. &cRowsReturned, // # rows returned
  842. &pgrHRows); // resulting hrows
  843. if ( FAILED( hr ) )
  844. break;
  845. for ( DBCOUNTITEM iRow = 0; iRow < cRowsReturned; iRow++ )
  846. {
  847. PROPVARIANT * aData[cColumns];
  848. hr = xIRowset->GetData( aHRow[iRow], // hrow being accessed
  849. hAccessor, // accessor to use
  850. &aData ); // resulting data
  851. if ( FAILED( hr ) )
  852. break;
  853. if ( VT_I4 == aData[0]->vt &&
  854. VT_I8 == aData[1]->vt &&
  855. VT_LPWSTR == aData[2]->vt )
  856. printf( "%5d %10I64d %ws\n",
  857. aData[0]->lVal,
  858. aData[1]->hVal,
  859. aData[2]->pwszVal );
  860. else
  861. printf( "could not retrieve a file's values\n" );
  862. }
  863. if ( 0 != cRowsReturned )
  864. xIRowset->ReleaseRows( cRowsReturned, // # of rows to release
  865. aHRow, // rows to release
  866. 0, // no options
  867. 0, // no refcounts
  868. 0 ); // no status
  869. if ( DB_S_ENDOFROWSET == hr )
  870. {
  871. hr = S_OK; // succeeded, return S_OK from DoQuery
  872. break;
  873. }
  874. if ( FAILED( hr ) )
  875. break;
  876. cRowsSoFar += cRowsReturned;
  877. } while ( TRUE );
  878. printf( "%d files matched the query '%ws'\n",
  879. cRowsSoFar,
  880. pwcQueryRestriction );
  881. xIAccessor->ReleaseAccessor( hAccessor, 0 );
  882. return hr;
  883. } //DoQuery
  884. //+-------------------------------------------------------------------------
  885. //
  886. // Function: Usage
  887. //
  888. // Synopsis: Displays information about how to use the app and exits
  889. //
  890. //--------------------------------------------------------------------------
  891. void Usage()
  892. {
  893. printf( "usage: ADVQUERY query [/c:catalog] [/m:machine] [/s:scope] [/d]\n\n" );
  894. printf( " query word or phrase used for the search\n" );
  895. printf( " /c:catalog name of the catalog, default is SYSTEM\n" );
  896. printf( " /m:machine name of the machine, default is local machine\n" );
  897. printf( " /s:scope root path, default is entire catalog (\\) \n" );
  898. printf( " /d display the DBCOMMANDTREE, default is off\n" );
  899. exit( -1 );
  900. } //Usage
  901. //+-------------------------------------------------------------------------
  902. //
  903. // Function: wmain
  904. //
  905. // Synopsis: Entry point for the app. Parses command line arguments
  906. // and issues a query.
  907. //
  908. // Arguments: [argc] - Argument count
  909. // [argv] - Arguments
  910. //
  911. //--------------------------------------------------------------------------
  912. extern "C" int __cdecl wmain( int argc, WCHAR * argv[] )
  913. {
  914. WCHAR const * pwcScope = L"\\"; // default scope: entire catalog
  915. WCHAR const * pwcCatalog = L"system"; // default: system catalog
  916. WCHAR const * pwcMachine = L"."; // default: local machine
  917. WCHAR const * pwcRestriction = 0; // no default restriction
  918. BOOL fDisplayTree = FALSE; // don't display the tree
  919. // Parse command line parameters
  920. for ( int i = 1; i < argc; i++ )
  921. {
  922. if ( L'-' == argv[i][0] || L'/' == argv[i][0] )
  923. {
  924. WCHAR wc = toupper( argv[i][1] );
  925. if ( ':' != argv[i][2] && 'D' != wc )
  926. Usage();
  927. if ( 'C' == wc )
  928. pwcCatalog = argv[i] + 3;
  929. else if ( 'M' == wc )
  930. pwcMachine = argv[i] + 3;
  931. else if ( 'S' == wc )
  932. pwcScope = argv[i] + 3;
  933. else if ( 'D' == wc )
  934. fDisplayTree = TRUE;
  935. else
  936. Usage();
  937. }
  938. else if ( 0 != pwcRestriction )
  939. Usage();
  940. else
  941. pwcRestriction = argv[i];
  942. }
  943. // A query restriction is necessary. Fail if none is given.
  944. if ( 0 == pwcRestriction )
  945. Usage();
  946. // Initialize COM
  947. HRESULT hr = CoInitialize( 0 );
  948. if ( SUCCEEDED( hr ) )
  949. {
  950. // Run the query
  951. hr = DoQuery( pwcScope,
  952. pwcCatalog,
  953. pwcMachine,
  954. pwcRestriction,
  955. fDisplayTree );
  956. CoUninitialize();
  957. }
  958. if ( FAILED( hr ) )
  959. {
  960. printf( "the query '%ws' failed with error %#x\n",
  961. pwcRestriction, hr );
  962. return -1;
  963. }
  964. return 0;
  965. } //wmain