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.

886 lines
32 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Copyright (C) 1997, Microsoft Corporation.
  4. //
  5. // File: SlickDLL.cpp
  6. //
  7. // Contents: Visual Slick 3.0 extension to call Index Server
  8. //
  9. // History: 15-Oct-97 KyleP Created
  10. //
  11. //----------------------------------------------------------------------------
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <stddef.h>
  15. // VSAPI includes windows.h. The define keeps windowsx.h out.
  16. #define _INC_WINDOWSX 1
  17. #include <vsapi.h>
  18. // #define OLEDBVER 0x0250 // enable ICommandTree interface
  19. #define DBINITCONSTANTS
  20. #include <oledberr.h>
  21. #include <oledb.h>
  22. #include <cmdtree.h>
  23. #include <oledbdep.h>
  24. #include <ntquery.h>
  25. #include <cierror.h>
  26. // This is the *only* thing needed from nt.h by the command tree helpers.
  27. typedef LONG NTSTATUS;
  28. #include <dbcmdtre.hxx>
  29. #define Win4Assert(x)
  30. #include <tgrow.hxx>
  31. //
  32. // Local prototypes and structures
  33. //
  34. HRESULT SetCommandProperties( ICommand * pICommand );
  35. HRESULT SetScope( ICommand * pICommand, WCHAR const * pwcQueryScope );
  36. void ErrorMessagePopup( SCODE sc );
  37. struct SResultItem
  38. {
  39. LONGLONG llSize;
  40. FILETIME ftWrite;
  41. ULONG ulAttrib;
  42. WCHAR * pwcsPath;
  43. };
  44. //
  45. // Local constants
  46. //
  47. CIPROPERTYDEF aProperties[] = { { L"FUNC",
  48. DBTYPE_WSTR | DBTYPE_BYREF,
  49. { { 0x8dee0300, 0x16c2, 0x101b, 0xb1, 0x21, 0x08, 0x00, 0x2b, 0x2e, 0xcd, 0xa9 },
  50. DBKIND_GUID_NAME,
  51. L"func"
  52. }
  53. },
  54. { L"CLASS",
  55. DBTYPE_WSTR | DBTYPE_BYREF,
  56. { { 0x8dee0300, 0x16c2, 0x101b, 0xb1, 0x21, 0x08, 0x00, 0x2b, 0x2e, 0xcd, 0xa9 },
  57. DBKIND_GUID_NAME,
  58. L"class"
  59. }
  60. }
  61. };
  62. //
  63. // Static command tree (sans select node) to fetch required columns and sort by Rank.
  64. //
  65. // NOTE: There are some funny casts below, because of the requirement to
  66. // statically initialize a union.
  67. //
  68. const DBID dbcolSize = { { 0xb725f130, 0x47ef, 0x101a, 0xa5, 0xf1, 0x02, 0x60, 0x8c, 0x9e, 0xeb, 0xac },
  69. DBKIND_GUID_PROPID,
  70. (LPWSTR)12 };
  71. const DBID dbcolWrite = { { 0xb725f130, 0x47ef, 0x101a, 0xa5, 0xf1, 0x02, 0x60, 0x8c, 0x9e, 0xeb, 0xac },
  72. DBKIND_GUID_PROPID,
  73. (LPWSTR)14 };
  74. const DBID dbcolAttrib = { { 0xb725f130, 0x47ef, 0x101a, 0xa5, 0xf1, 0x02, 0x60, 0x8c, 0x9e, 0xeb, 0xac },
  75. DBKIND_GUID_PROPID,
  76. (LPWSTR)13 };
  77. const DBID dbcolPath = { { 0xb725f130, 0x47ef, 0x101a, 0xa5, 0xf1, 0x02, 0x60, 0x8c, 0x9e, 0xeb, 0xac },
  78. DBKIND_GUID_PROPID,
  79. (LPWSTR)11 };
  80. const DBID dbcolRank = { { 0x49691c90, 0x7e17, 0x101a, 0xa9, 0x1c, 0x08, 0x00, 0x2b, 0x2e, 0xcd, 0xa9 },
  81. DBKIND_GUID_PROPID,
  82. (LPWSTR)3 };
  83. //
  84. // Columns
  85. //
  86. DBCOMMANDTREE dbcmdColumnSize = { DBOP_column_name, DBVALUEKIND_ID, 0, 0, (ULONG_PTR)&dbcolSize, S_OK };
  87. DBCOMMANDTREE dbcmdColumnWrite = { DBOP_column_name, DBVALUEKIND_ID, 0, 0, (ULONG_PTR)&dbcolWrite, S_OK };
  88. DBCOMMANDTREE dbcmdColumnAttrib = { DBOP_column_name, DBVALUEKIND_ID, 0, 0, (ULONG_PTR)&dbcolAttrib, S_OK };
  89. DBCOMMANDTREE dbcmdColumnPath = { DBOP_column_name, DBVALUEKIND_ID, 0, 0, (ULONG_PTR)&dbcolPath, S_OK };
  90. DBCOMMANDTREE dbcmdColumnRank = { DBOP_column_name, DBVALUEKIND_ID, 0, 0, (ULONG_PTR)&dbcolRank, S_OK };
  91. //
  92. // Forward declare a few nodes to make linking easy
  93. //
  94. extern DBCOMMANDTREE dbcmdSortListAnchor;
  95. extern DBCOMMANDTREE dbcmdProjectListAnchor;
  96. //
  97. // The Select node. The actual Select expression will be plugged in to the dbcmdTable node.
  98. //
  99. WCHAR wszTable[] = L"Table";
  100. DBCOMMANDTREE dbcmdTable = { DBOP_table_name,
  101. DBVALUEKIND_WSTR,
  102. 0,
  103. 0, // CITextToSelectTree goes here...
  104. (ULONG_PTR)&wszTable[0],
  105. S_OK };
  106. DBCOMMANDTREE dbcmdSelect = { DBOP_select,
  107. DBVALUEKIND_EMPTY,
  108. &dbcmdTable,
  109. &dbcmdProjectListAnchor,
  110. 0,
  111. S_OK };
  112. //
  113. // Project (Path, GUID, ...)
  114. //
  115. // NOTE: The order here defines the ordinals of columns.
  116. //
  117. DBCOMMANDTREE dbcmdProjectPath = { DBOP_project_list_element,
  118. DBVALUEKIND_EMPTY,
  119. &dbcmdColumnPath,
  120. 0,
  121. 0,
  122. S_OK };
  123. DBCOMMANDTREE dbcmdProjectAttrib = { DBOP_project_list_element,
  124. DBVALUEKIND_EMPTY,
  125. &dbcmdColumnAttrib,
  126. &dbcmdProjectPath,
  127. 0,
  128. S_OK };
  129. DBCOMMANDTREE dbcmdProjectWrite = { DBOP_project_list_element,
  130. DBVALUEKIND_EMPTY,
  131. &dbcmdColumnWrite,
  132. &dbcmdProjectAttrib,
  133. 0,
  134. S_OK };
  135. DBCOMMANDTREE dbcmdProjectSize = { DBOP_project_list_element,
  136. DBVALUEKIND_EMPTY,
  137. &dbcmdColumnSize,
  138. &dbcmdProjectWrite,
  139. 0,
  140. S_OK };
  141. DBCOMMANDTREE dbcmdProjectListAnchor = { DBOP_project_list_anchor,
  142. DBVALUEKIND_EMPTY,
  143. &dbcmdProjectSize,
  144. 0,
  145. 0,
  146. S_OK };
  147. DBCOMMANDTREE dbcmdProject = { DBOP_project,
  148. DBVALUEKIND_EMPTY,
  149. &dbcmdSelect,
  150. &dbcmdSortListAnchor,
  151. 0,
  152. S_OK };
  153. //
  154. // Sort (Descending by Rank)
  155. //
  156. DBSORTINFO dbsortDescending = { TRUE, LOCALE_NEUTRAL };
  157. DBCOMMANDTREE dbcmdSortByRank = { DBOP_sort_list_element,
  158. DBVALUEKIND_SORTINFO,
  159. &dbcmdColumnRank,
  160. 0,
  161. (ULONG_PTR)&dbsortDescending,
  162. S_OK };
  163. DBCOMMANDTREE dbcmdSortListAnchor = { DBOP_sort_list_anchor,
  164. DBVALUEKIND_EMPTY,
  165. &dbcmdSortByRank,
  166. 0,
  167. 0,
  168. S_OK };
  169. DBCOMMANDTREE dbcmdSort = { DBOP_sort,
  170. DBVALUEKIND_EMPTY,
  171. &dbcmdProject,
  172. 0,
  173. 0,
  174. S_OK };
  175. //
  176. // Bindings
  177. //
  178. DBBINDING aColumns[] = { { 1, // Column 1 -- Size
  179. offsetof(SResultItem,llSize), // obValue
  180. 0, // obLength
  181. 0, // obStatus
  182. 0, // pTypeInfo
  183. 0, // pObject
  184. 0, // pBindExt
  185. DBPART_VALUE, // retrieve only value
  186. 0, // dwMemOwner
  187. 0, // eParamIO
  188. 0, // cbMaxLen doesn't apply to fixed types
  189. 0, // dwFlags
  190. DBTYPE_I8, // dwType
  191. 0, // dwPrecision
  192. 0 // dwScale
  193. },
  194. { 2, // Column 2 -- Write time
  195. offsetof(SResultItem,ftWrite), // obValue
  196. 0, // obLength
  197. 0, // obStatus
  198. 0, // pTypeInfo
  199. 0, // pObject
  200. 0, // pBindExt
  201. DBPART_VALUE, // retrieve only value
  202. 0, // dwMemOwner
  203. 0, // eParamIO
  204. 0, // cbMaxLen doesn't apply to fixed types
  205. 0, // dwFlags
  206. VT_FILETIME, // dwType
  207. 0, // dwPrecision
  208. 0 // dwScale
  209. },
  210. { 3, // Column 3 -- Attributes
  211. offsetof(SResultItem,ulAttrib),// obValue
  212. 0, // obLength
  213. 0, // obStatus
  214. 0, // pTypeInfo
  215. 0, // pObject
  216. 0, // pBindExt
  217. DBPART_VALUE, // retrieve only value
  218. 0, // dwMemOwner
  219. 0, // eParamIO
  220. 0, // cbMaxLen doesn't apply to fixed types
  221. 0, // dwFlags
  222. VT_UI4, // dwType
  223. 0, // dwPrecision
  224. 0 // dwScale
  225. },
  226. { 4, // Column 4 -- Path
  227. offsetof(SResultItem,pwcsPath), // obValue
  228. 0, // obLength
  229. 0, // obStatus
  230. 0, // pTypeInfo
  231. 0, // pObject
  232. 0, // pBindExt
  233. DBPART_VALUE, // retrieve only value
  234. DBMEMOWNER_PROVIDEROWNED, // Index Server owned
  235. 0, // eParamIO
  236. 0, // cbMaxLen doesn't apply to fixed types
  237. 0, // dwFlags
  238. DBTYPE_WSTR|DBTYPE_BYREF, // dwType
  239. 0, // dwPrecision
  240. 0 // dwScale
  241. }
  242. };
  243. //
  244. // C++ Helpers
  245. //
  246. //+-------------------------------------------------------------------------
  247. //
  248. // Template: XInterface
  249. //
  250. // Synopsis: Template for managing ownership of interfaces
  251. //
  252. //--------------------------------------------------------------------------
  253. template<class T> class XInterface
  254. {
  255. public:
  256. XInterface( T * p = 0 ) : _p( p ) {}
  257. ~XInterface() { if ( 0 != _p ) _p->Release(); }
  258. T * operator->() { return _p; }
  259. T * GetPointer() const { return _p; }
  260. IUnknown ** GetIUPointer() { return (IUnknown **) &_p; }
  261. T ** GetPPointer() { return &_p; }
  262. void ** GetQIPointer() { return (void **) &_p; }
  263. T * Acquire() { T * p = _p; _p = 0; return p; }
  264. private:
  265. T * _p;
  266. };
  267. extern "C" {
  268. //+---------------------------------------------------------------------------
  269. //
  270. // Function: vsDllInit, public
  271. //
  272. // Synopsis: Always called by VSlick
  273. //
  274. // History: 15-Oct-97 KyleP Stole from VSlick sample (simple.c)
  275. //
  276. // Notes: Called from VSlick's dllmain.obj
  277. //
  278. //----------------------------------------------------------------------------
  279. void VSAPI vsDllInit()
  280. {
  281. }
  282. //+---------------------------------------------------------------------------
  283. //
  284. // Function: vsDllRegisterExports, public
  285. //
  286. // Synopsis: Called by VSlick to register new commands
  287. //
  288. // History: 15-Oct-97 KyleP Stole from VSlick sample (simple.c)
  289. //
  290. //----------------------------------------------------------------------------
  291. void VSAPI vsDllRegisterExports()
  292. {
  293. //
  294. // This call says CISearch takes two parameters. The first is a filename
  295. // and the second is just a string. The *_ARG2 mean the command can
  296. // be called from many different places in VSlick.
  297. //
  298. vsDllExport( "_command void CISearch(VSPSZ,VSPSZ)",
  299. VSFILE_ARG,
  300. VSNCW_ARG2|VSICON_ARG2|VSCMDLINE_ARG2|VSREAD_ONLY_ARG2 );
  301. }
  302. //+---------------------------------------------------------------------------
  303. //
  304. // Function: vsDllExit, public
  305. //
  306. // Synopsis: Always called by VSlick
  307. //
  308. // History: 15-Oct-97 KyleP Stole from VSlick sample (simple.c)
  309. //
  310. // Notes: Called from VSlick's dllmain.obj
  311. //
  312. //----------------------------------------------------------------------------
  313. void VSAPI vsDllExit()
  314. {
  315. }
  316. //+---------------------------------------------------------------------------
  317. //
  318. // Function: CISearch, public
  319. //
  320. // Synopsis: Execute an Index Server search
  321. //
  322. // Arguments: [pszScope] -- Scope to search. Also used to locate catalog.
  323. // [pszQuery] -- Query, in Tripolish
  324. //
  325. // History: 15-Oct-97 KyleP Created
  326. //
  327. //----------------------------------------------------------------------------
  328. void VSAPI CISearch(VSPSZ pszScope, VSPSZ pszQuery)
  329. {
  330. long status;
  331. // Current object/window is mdi child
  332. status=vsExecute(0,"edit .SearchResults","");
  333. if ( status && status!=NEW_FILE_RC )
  334. {
  335. MessageBox(HWND_DESKTOP,
  336. L"VSNTQ: Error loading file",
  337. L"DLL Error",
  338. 0);
  339. return;
  340. }
  341. if ( status==NEW_FILE_RC )
  342. // Delete the blank line in the new file created
  343. vsDeleteLine(0);
  344. else
  345. vsExecute( 0, "bottom_of_buffer", "" );
  346. vsExecute( 0, "fileman-mode", "" );
  347. //
  348. // Convert arguments to WCHAR
  349. //
  350. unsigned ccQuery = strlen( pszQuery );
  351. XGrowable<WCHAR> xwcsQuery( ccQuery + ccQuery/2 + 1 );
  352. mbstowcs( xwcsQuery.Get(), pszQuery, xwcsQuery.Count() );
  353. unsigned ccScope = strlen( pszScope );
  354. XGrowable<WCHAR> xwcsScope( ccScope + ccScope/2 + 1 );
  355. mbstowcs( xwcsScope.Get(), pszScope, xwcsScope.Count() );
  356. //
  357. // Find catalog
  358. //
  359. XGrowable<WCHAR> xwcsMachine;
  360. ULONG ccMachine = xwcsMachine.Count();
  361. XGrowable<WCHAR> xwcsCat;
  362. ULONG ccCat = xwcsCat.Count();
  363. SCODE sc = LocateCatalogs( xwcsScope.Get(), // Scope
  364. 0, // Bookmark
  365. xwcsMachine.Get(), // Machine
  366. &ccMachine, // Size
  367. xwcsCat.Get(), // Catalog
  368. &ccCat ); // Size
  369. if ( S_OK == sc )
  370. {
  371. //
  372. // Execute query
  373. //
  374. SCODE hr = S_OK;
  375. do
  376. {
  377. //
  378. // Create an ICommand object. The default scope for the query is the
  379. // entire catalog. CICreateCommand is a shortcut for making an
  380. // ICommand. The ADVQUERY sample shows the OLE DB equivalent.
  381. //
  382. XInterface<ICommand> xICommand;
  383. hr = CICreateCommand( xICommand.GetIUPointer(), // result
  384. 0, // controlling unknown
  385. IID_ICommand, // IID requested
  386. xwcsCat.Get(), // catalog name
  387. xwcsMachine.Get() ); // machine name
  388. if ( FAILED( hr ) )
  389. break;
  390. // Set required properties on the ICommand
  391. hr = SetCommandProperties( xICommand.GetPointer() );
  392. if ( FAILED( hr ) )
  393. break;
  394. hr = SetScope( xICommand.GetPointer(), xwcsScope.Get() );
  395. if ( FAILED( hr ) )
  396. break;
  397. //
  398. // Create an OLE DB query tree from a text restriction, column
  399. // set, and sort order.
  400. //
  401. DBCOMMANDTREE * pTree;
  402. hr = CITextToSelectTree( xwcsQuery.Get(), // the query itself
  403. &pTree, // resulting tree
  404. sizeof(aProperties)/sizeof(aProperties[0]), // custom properties
  405. aProperties, // custom properties
  406. 0 ); // neutral locale
  407. if ( QPLIST_E_DUPLICATE == hr )
  408. hr = CITextToSelectTree( xwcsQuery.Get(), // the query itself
  409. &pTree, // resulting tree
  410. 0, // custom properties
  411. 0, // custom properties
  412. 0 ); // neutral locale
  413. if ( FAILED( hr ) )
  414. break; // Worth a special message?
  415. //
  416. // Set the Select node.
  417. //
  418. // Since this code uses a global command tree it is not
  419. // thread-safe. I don't think this is a problem for VSlick.
  420. //
  421. dbcmdTable.pctNextSibling = pTree;
  422. pTree = &dbcmdSort;
  423. // Set the tree in the ICommandTree
  424. XInterface<ICommandTree> xICommandTree;
  425. hr = xICommand->QueryInterface( IID_ICommandTree,
  426. xICommandTree.GetQIPointer() );
  427. if ( FAILED( hr ) )
  428. break;
  429. hr = xICommandTree->SetCommandTree( &pTree,
  430. DBCOMMANDREUSE_NONE,
  431. TRUE );
  432. if ( FAILED( hr ) )
  433. break;
  434. // Execute the query. The query is complete when Execute() returns
  435. XInterface<IRowset> xIRowset;
  436. hr = xICommand->Execute( 0, // no aggregating IUnknown
  437. IID_IRowset, // IID for interface to return
  438. 0, // no DBPARAMs
  439. 0, // no rows affected
  440. xIRowset.GetIUPointer() ); // result
  441. if ( FAILED( hr ) )
  442. break; // Worth a special message?
  443. // Create an accessor, so data can be retrieved from the rowset
  444. XInterface<IAccessor> xIAccessor;
  445. hr = xIRowset->QueryInterface( IID_IAccessor,
  446. xIAccessor.GetQIPointer() );
  447. if ( FAILED( hr ) )
  448. break;
  449. //
  450. // Column iOrdinals are parallel with those passed to CiTextToFullTree,
  451. // so MapColumnIDs isn't necessary. These binding values for dwPart,
  452. // dwMemOwner, and wType are the most optimal bindings for Index Server.
  453. //
  454. HACCESSOR hAccessor;
  455. hr = xIAccessor->CreateAccessor( DBACCESSOR_ROWDATA, // rowdata accessor
  456. sizeof(aColumns)/sizeof(aColumns[0]), // # of columns
  457. aColumns, // columns
  458. 0, // ignored
  459. &hAccessor, // result
  460. 0 ); // no status
  461. if ( FAILED( hr ) )
  462. break;
  463. //
  464. // Display the results of the query. Print in 'fileman mode' format.
  465. //
  466. static char const szQueryCaption[] = "Query: ";
  467. XGrowable<char> xszLine1( ccQuery + sizeof(szQueryCaption) );
  468. strcpy( xszLine1.Get(), szQueryCaption );
  469. strcat( xszLine1.Get(), pszQuery );
  470. vsInsertLine(0,"",-1);
  471. vsInsertLine(0,xszLine1.Get(),-1);
  472. vsInsertLine(0,"",-1);
  473. DBCOUNTITEM cRowsSoFar = 0;
  474. do
  475. {
  476. DBCOUNTITEM cRowsReturned = 0;
  477. const ULONG cRowsAtATime = 10;
  478. HROW aHRow[cRowsAtATime];
  479. HROW * pgrHRows = aHRow;
  480. hr = xIRowset->GetNextRows( 0, // no chapter
  481. 0, // no rows to skip
  482. cRowsAtATime, // # rows to get
  483. &cRowsReturned, // # rows returned
  484. &pgrHRows); // resulting hrows
  485. if ( FAILED( hr ) )
  486. break;
  487. for ( ULONG iRow = 0; iRow < cRowsReturned; iRow++ )
  488. {
  489. SResultItem result;
  490. hr = xIRowset->GetData( aHRow[iRow], // hrow being accessed
  491. hAccessor, // accessor to use
  492. &result ); // resulting data
  493. if ( FAILED( hr ) )
  494. break;
  495. //
  496. // Note: there is no Data type error checking. But our
  497. // schema here is fixed so it's safe.
  498. //
  499. unsigned ccPath = wcslen( result.pwcsPath );
  500. XGrowable<char> xszResult( ccPath + ccPath/2 + 40 );
  501. //
  502. // Size (or <DIR>)
  503. //
  504. if ( result.ulAttrib & FILE_ATTRIBUTE_DIRECTORY )
  505. strcpy( xszResult.Get(), " <DIR> " );
  506. else
  507. sprintf( xszResult.Get(), "%11I64u ", result.llSize );
  508. //
  509. // Date and time
  510. //
  511. FILETIME ftLocal;
  512. FileTimeToLocalFileTime( &result.ftWrite, &ftLocal );
  513. SYSTEMTIME systime;
  514. FileTimeToSystemTime( &ftLocal, &systime );
  515. sprintf( xszResult.Get() + 13, "%2u-%02u-%4u %2u:%02u%c ",
  516. systime.wMonth, systime.wDay, systime.wYear,
  517. systime.wHour % 12, systime.wMinute, (systime.wHour >= 12) ? 'p' : 'a' );
  518. //
  519. // Attributes
  520. //
  521. char szAttrib[] = "RSHDA ";
  522. szAttrib[0] = ( result.ulAttrib & FILE_ATTRIBUTE_READONLY ) ? 'R' : '-';
  523. szAttrib[1] = ( result.ulAttrib & FILE_ATTRIBUTE_SYSTEM ) ? 'S' : '-';
  524. szAttrib[2] = ( result.ulAttrib & FILE_ATTRIBUTE_HIDDEN ) ? 'H' : '-';
  525. szAttrib[3] = ( result.ulAttrib & FILE_ATTRIBUTE_DIRECTORY ) ? 'D' : '-';
  526. szAttrib[4] = ( result.ulAttrib & FILE_ATTRIBUTE_ARCHIVE ) ? 'A' : '-';
  527. strcat( xszResult.Get(), szAttrib );
  528. //
  529. // Path
  530. //
  531. wcstombs( xszResult.Get() + 39, result.pwcsPath, ccPath + ccPath/2 );
  532. //
  533. // Write out to the VSlick buffer
  534. //
  535. vsInsertLine(0, xszResult.Get(), -1);
  536. }
  537. if ( 0 != cRowsReturned )
  538. xIRowset->ReleaseRows( cRowsReturned, // # of rows to release
  539. aHRow, // rows to release
  540. 0, // no options
  541. 0, // no refcounts
  542. 0 ); // no status
  543. if ( DB_S_ENDOFROWSET == hr )
  544. {
  545. hr = S_OK; // succeeded, return S_OK from DoQuery
  546. break;
  547. }
  548. if ( FAILED( hr ) )
  549. break;
  550. cRowsSoFar += cRowsReturned;
  551. } while ( TRUE );
  552. if ( FAILED(hr) )
  553. break;
  554. xIAccessor->ReleaseAccessor( hAccessor, 0 );
  555. } while ( FALSE );
  556. //
  557. // Clean up Select node.
  558. //
  559. if ( 0 != dbcmdTable.pctNextSibling )
  560. {
  561. CDbCmdTreeNode * pSelect = (CDbCmdTreeNode *)(ULONG_PTR)dbcmdTable.pctNextSibling;
  562. delete pSelect;
  563. dbcmdTable.pctNextSibling = 0;
  564. }
  565. if ( FAILED(hr) )
  566. ErrorMessagePopup( hr );
  567. }
  568. else
  569. {
  570. MessageBox( HWND_DESKTOP,
  571. L"Unable to find catalog covering specified scope.",
  572. L"Error",
  573. MB_OK | MB_ICONERROR );
  574. }
  575. }
  576. } // "C"
  577. //
  578. // Non-VSlick stuff
  579. //
  580. //+-------------------------------------------------------------------------
  581. //
  582. // Function: SetCommandProperties
  583. //
  584. // Synopsis: Sets the DBPROP_USEEXTENDEDDBTYPES property to TRUE, so
  585. // data is returned in PROPVARIANTs, as opposed to the
  586. // default, which is OLE automation VARIANTs. PROPVARIANTS
  587. // allow a superset of VARIANT data types. Use of these
  588. // types avoids costly coercions.
  589. //
  590. // Also sets the DBPROP_USECONTENTINDEX property to TRUE, so
  591. // the index will always be used to resolve the query (as
  592. // opposed to enumerating all the files on the disk), even
  593. // if the index is out of date.
  594. //
  595. // Both of these properties are unique to Index Server's OLE DB
  596. // implementation.
  597. //
  598. // Arguments: [pICommand] - The ICommand used to set the property
  599. //
  600. // Returns: HRESULT result of setting the properties
  601. //
  602. //--------------------------------------------------------------------------
  603. HRESULT SetCommandProperties( ICommand * pICommand )
  604. {
  605. static const DBID dbcolNull = { { 0,0,0, { 0,0,0,0,0,0,0,0 } },
  606. DBKIND_GUID_PROPID, 0 };
  607. static const GUID guidQueryExt = DBPROPSET_QUERYEXT;
  608. DBPROP aProp[2];
  609. aProp[0].dwPropertyID = DBPROP_USEEXTENDEDDBTYPES;
  610. aProp[0].dwOptions = DBPROPOPTIONS_OPTIONAL;
  611. aProp[0].dwStatus = 0;
  612. aProp[0].colid = dbcolNull;
  613. aProp[0].vValue.vt = VT_BOOL;
  614. aProp[0].vValue.boolVal = VARIANT_TRUE;
  615. aProp[1] = aProp[0];
  616. aProp[1].dwPropertyID = DBPROP_USECONTENTINDEX;
  617. DBPROPSET aPropSet[1];
  618. aPropSet[0].rgProperties = &aProp[0];
  619. aPropSet[0].cProperties = 2;
  620. aPropSet[0].guidPropertySet = guidQueryExt;
  621. XInterface<ICommandProperties> xICommandProperties;
  622. HRESULT hr = pICommand->QueryInterface( IID_ICommandProperties,
  623. xICommandProperties.GetQIPointer() );
  624. if ( FAILED( hr ) )
  625. return hr;
  626. return xICommandProperties->SetProperties( 1, // 1 property set
  627. aPropSet ); // the properties
  628. } //SetCommandProperties
  629. //+-------------------------------------------------------------------------
  630. //
  631. // Function: SetScope
  632. //
  633. // Synopsis: Sets the catalog and machine properties in the ICommand.
  634. // Also sets a default scope.
  635. //
  636. // Arguments: [pICommand] - ICommand to set props on
  637. // [pwcQueryScope] - Scope for the query
  638. //
  639. // Returns: HRESULT result of the operation
  640. //
  641. //--------------------------------------------------------------------------
  642. HRESULT SetScope( ICommand * pICommand, WCHAR const * pwcQueryScope )
  643. {
  644. // Get an ICommandProperties so we can set the properties
  645. XInterface<ICommandProperties> xICommandProperties;
  646. HRESULT hr = pICommand->QueryInterface( IID_ICommandProperties,
  647. xICommandProperties.GetQIPointer() );
  648. if ( FAILED( hr ) )
  649. return hr;
  650. // note: SysAllocString, SafeArrayCreate, and SafeArrayPutElement can
  651. // fail, but this isn't checked here for brevity.
  652. SAFEARRAYBOUND rgBound[1];
  653. rgBound[0].lLbound = 0;
  654. rgBound[0].cElements = 1;
  655. long i = 0;
  656. SAFEARRAY * pScopes = SafeArrayCreate( VT_BSTR, 1, rgBound );
  657. hr = SafeArrayPutElement( pScopes, &i, SysAllocString( pwcQueryScope ) );
  658. if ( FAILED( hr ) )
  659. return hr;
  660. LONG lFlags = QUERY_DEEP;
  661. SAFEARRAY * pFlags = SafeArrayCreate( VT_I4, 1, rgBound );
  662. hr = SafeArrayPutElement( pFlags, &i, &lFlags );
  663. if ( FAILED( hr ) )
  664. return hr;
  665. DBPROP aScopeProperties[2];
  666. memset( aScopeProperties, 0, sizeof aScopeProperties );
  667. aScopeProperties[0].dwPropertyID = DBPROP_CI_INCLUDE_SCOPES;
  668. aScopeProperties[0].vValue.vt = VT_BSTR | VT_ARRAY;
  669. aScopeProperties[0].vValue.parray = pScopes;
  670. aScopeProperties[1].dwPropertyID = DBPROP_CI_SCOPE_FLAGS;
  671. aScopeProperties[1].vValue.vt = VT_I4 | VT_ARRAY;
  672. aScopeProperties[1].vValue.parray = pFlags;
  673. const GUID guidFSCI = DBPROPSET_FSCIFRMWRK_EXT;
  674. DBPROPSET aAllPropsets[1];
  675. aAllPropsets[0].rgProperties = aScopeProperties;
  676. aAllPropsets[0].cProperties = 2;
  677. aAllPropsets[0].guidPropertySet = guidFSCI;
  678. const ULONG cPropertySets = sizeof aAllPropsets / sizeof aAllPropsets[0];
  679. hr = xICommandProperties->SetProperties( cPropertySets, // # of propsets
  680. aAllPropsets ); // the propsets
  681. SafeArrayDestroy( pScopes );
  682. SafeArrayDestroy( pFlags );
  683. return hr;
  684. } //SetScopeCatalogAndMachine
  685. //+-------------------------------------------------------------------------
  686. //
  687. // Function: ErrorMessagePopup
  688. //
  689. // Synopsis: Popup error dialog.
  690. //
  691. // Arguments: [sc] -- Error code
  692. //
  693. //--------------------------------------------------------------------------
  694. void ErrorMessagePopup( SCODE sc )
  695. {
  696. WCHAR * pBuf = 0;
  697. if ( !FormatMessage( FORMAT_MESSAGE_FROM_HMODULE |
  698. FORMAT_MESSAGE_ALLOCATE_BUFFER,
  699. GetModuleHandle(L"query.dll"),
  700. sc,
  701. GetSystemDefaultLCID(),
  702. (WCHAR *)&pBuf,
  703. 0,
  704. 0 ) &&
  705. !FormatMessage( FORMAT_MESSAGE_FROM_HMODULE |
  706. FORMAT_MESSAGE_ALLOCATE_BUFFER,
  707. GetModuleHandle(L"kernel32.dll"),
  708. sc,
  709. GetSystemDefaultLCID(),
  710. (WCHAR *)&pBuf,
  711. 0,
  712. 0 ) )
  713. {
  714. XGrowable<WCHAR> xawcText(100);
  715. wsprintf( xawcText.Get(), L"Query error: 0x%x", sc );
  716. MessageBox( HWND_DESKTOP,
  717. xawcText.Get(),
  718. L"Error",
  719. MB_OK | MB_ICONERROR );
  720. }
  721. else
  722. {
  723. MessageBox( HWND_DESKTOP,
  724. pBuf,
  725. L"Error",
  726. MB_OK | MB_ICONERROR );
  727. LocalFree( pBuf );
  728. }
  729. }