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.

428 lines
12 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 1998-2000 Microsoft Corporation. All Rights Reserved.
  9. //
  10. // PROGRAM: isrchdmp.cx
  11. //
  12. // PURPOSE: Illustrates a minimal query using Indexing Service.
  13. //
  14. // PLATFORM: Windows 2000
  15. //
  16. //--------------------------------------------------------------------------
  17. #ifndef UNICODE
  18. #define UNICODE
  19. #endif
  20. #include <stdio.h>
  21. #include <windows.h>
  22. #define DBINITCONSTANTS
  23. #include <oledberr.h>
  24. #include <oledb.h>
  25. #include <cmdtree.h>
  26. #include <ntquery.h>
  27. #include <filter.h>
  28. #include <filterr.h>
  29. #include "isearch.h"
  30. #include "array.hxx"
  31. extern CIPROPERTYDEF aCPPProperties[];
  32. extern unsigned cCPPProperties;
  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. const GUID guidStorage = PSGUID_STORAGE;
  55. typedef void (__stdcall * PFnCIShutdown)(void);
  56. typedef HRESULT (__stdcall * PFnMakeISearch)( ISearchQueryHits ** ppSearch,
  57. DBCOMMANDTREE * pRst,
  58. WCHAR const * pwcPath );
  59. typedef HRESULT (__stdcall * PFnLoadTextFilter)( WCHAR const * pwcPath,
  60. IFilter ** ppIFilter );
  61. PFnCIShutdown g_pCIShutdown = 0;
  62. PFnMakeISearch g_pMakeISearch = 0;
  63. PFnLoadTextFilter g_pLoadTextFilter = 0;
  64. #define UNICODE_PARAGRAPH_SEPARATOR 0x2029
  65. ULONG CountCR( WCHAR * pCur, ULONG cwc, WCHAR * &pwcPrev )
  66. {
  67. pwcPrev = pCur;
  68. WCHAR * pEnd = pCur + cwc;
  69. ULONG cCR = 0;
  70. while ( pCur < pEnd )
  71. {
  72. WCHAR c = *pCur;
  73. if ( L'\r' == c ||
  74. L'\n' == c ||
  75. UNICODE_PARAGRAPH_SEPARATOR == c )
  76. {
  77. cCR++;
  78. if ( ( L'\r' == c ) &&
  79. ( (pCur+1) < pEnd ) &&
  80. ( L'\n' == *(pCur+1) ) )
  81. pCur++;
  82. pwcPrev = pCur + 1;
  83. }
  84. pCur++;
  85. }
  86. return cCR;
  87. } //CountCR
  88. HRESULT WalkFile(
  89. TArray<FILTERREGION> & aHits,
  90. XInterface<IFilter> & xIFilter,
  91. WCHAR const * pwcFile,
  92. BOOL fPrintFile )
  93. {
  94. ULONG ulFlags;
  95. HRESULT hr = xIFilter->Init( IFILTER_INIT_CANON_PARAGRAPHS |
  96. IFILTER_INIT_CANON_HYPHENS |
  97. IFILTER_INIT_APPLY_INDEX_ATTRIBUTES,
  98. 0,
  99. 0,
  100. &ulFlags );
  101. if ( FAILED( hr ) )
  102. return hr;
  103. ULONG lenSoFar = 0;
  104. int cChunk = 0;
  105. BOOL fSeenProp = FALSE;
  106. ULONG iHit = 0;
  107. ULONG cLines = 1;
  108. const ULONG cwcBufSize = 65536;
  109. WCHAR *pwc = new WCHAR[cwcBufSize + 1];
  110. if ( 0 == pwc )
  111. return E_OUTOFMEMORY;
  112. STAT_CHUNK statChunk;
  113. hr = xIFilter->GetChunk( &statChunk );
  114. while( SUCCEEDED( hr ) ||
  115. ( FILTER_E_LINK_UNAVAILABLE == hr ) ||
  116. ( FILTER_E_EMBEDDING_UNAVAILABLE == hr ) )
  117. {
  118. if ( SUCCEEDED( hr ) && (statChunk.flags & CHUNK_TEXT) )
  119. {
  120. // read the contents only
  121. if ( ( guidStorage == statChunk.attribute.guidPropSet ) &&
  122. ( PRSPEC_PROPID == statChunk.attribute.psProperty.ulKind ) &&
  123. ( PID_STG_CONTENTS == statChunk.attribute.psProperty.propid ) )
  124. {
  125. if ( CHUNK_NO_BREAK != statChunk.breakType )
  126. {
  127. switch( statChunk.breakType )
  128. {
  129. case CHUNK_EOW:
  130. case CHUNK_EOS:
  131. break;
  132. case CHUNK_EOP:
  133. case CHUNK_EOC:
  134. cLines++;
  135. break;
  136. }
  137. }
  138. ULONG iIntoChunk = 0;
  139. ULONG cwcRetrieved;
  140. ULONG iPrevLine = ~0;
  141. do
  142. {
  143. cwcRetrieved = cwcBufSize;
  144. hr = xIFilter->GetText( &cwcRetrieved, pwc );
  145. pwc[cwcRetrieved] = 0;
  146. // The buffer may be filled with zeroes. Nice filter.
  147. if ( SUCCEEDED( hr ) )
  148. {
  149. if ( 0 != cwcRetrieved )
  150. cwcRetrieved = __min( cwcRetrieved,
  151. wcslen( pwc ) );
  152. while ( ( iHit < aHits.Count() ) &&
  153. ( aHits[iHit].idChunk == statChunk.idChunk ) &&
  154. ( aHits[iHit].cwcStart >= iIntoChunk ) &&
  155. ( aHits[iHit].cwcStart < ( iIntoChunk + cwcRetrieved ) ) )
  156. {
  157. WCHAR *pwcStart;
  158. ULONG iLine = cLines +
  159. CountCR( pwc,
  160. aHits[iHit].cwcStart - iIntoChunk,
  161. pwcStart );
  162. WCHAR *pwcEnd = wcschr( pwcStart, L'\r' );
  163. if ( 0 == pwcEnd )
  164. pwcEnd = wcschr( pwcStart, L'\n' );
  165. if ( 0 != pwcEnd )
  166. *pwcEnd = 0;
  167. if ( iLine != iPrevLine )
  168. {
  169. if ( fPrintFile )
  170. wprintf( L"%ws", pwcFile );
  171. wprintf( L"(%u): %ws\n", iLine, pwcStart );
  172. iPrevLine = iLine;
  173. }
  174. if ( 0 != pwcEnd )
  175. *pwcEnd = '\r';
  176. iHit++;
  177. }
  178. WCHAR * pwcDummy;
  179. cLines += CountCR( pwc, cwcRetrieved, pwcDummy );
  180. iIntoChunk += cwcRetrieved;
  181. }
  182. } while( SUCCEEDED( hr ) );
  183. }
  184. }
  185. hr = xIFilter->GetChunk ( &statChunk );
  186. }
  187. delete [] pwc;
  188. if ( FILTER_E_END_OF_CHUNKS == hr )
  189. hr = S_OK;
  190. return hr;
  191. } //WalkFile
  192. //+-------------------------------------------------------------------------
  193. //
  194. // Function: DoQuery
  195. //
  196. // Synopsis: Creates and executes a query, then displays the results.
  197. //
  198. // Arguments: [pwcFilename] - Name of the file
  199. // [pwcQueryRestrition] - The actual query string
  200. // [fPrintFile] - whether to print the filename
  201. // [lcid] - Locale of the query
  202. //
  203. // Returns: HRESULT result of the query
  204. //
  205. //--------------------------------------------------------------------------
  206. HRESULT DoQuery(
  207. WCHAR const * pwcFilename,
  208. WCHAR const * pwcQueryRestriction,
  209. BOOL fPrintFile,
  210. BOOL fDefineCPP,
  211. LCID lcid )
  212. {
  213. // Create an OLE DB query tree from a text restriction
  214. DBCOMMANDTREE * pTree;
  215. ULONG cDefinedProperties = fDefineCPP ? cCPPProperties : 0;
  216. HRESULT hr = CITextToSelectTree( pwcQueryRestriction, // the query itself
  217. &pTree, // resulting tree
  218. cDefinedProperties, // C++ properties
  219. aCPPProperties, // C++ properties
  220. lcid ); // default locale
  221. if ( FAILED( hr ) )
  222. return hr;
  223. // Make the ISearchQueryHits object
  224. XInterface<ISearchQueryHits> xISearch;
  225. hr = g_pMakeISearch( xISearch.GetPPointer(),
  226. pTree,
  227. 0 );
  228. if ( FAILED( hr ) )
  229. return hr;
  230. XInterface<IFilter> xIFilter;
  231. hr = LoadIFilter( pwcFilename, 0, xIFilter.GetQIPointer() );
  232. if ( FAILED( hr ) )
  233. {
  234. // Fall back on the plain text filter
  235. hr = g_pLoadTextFilter( pwcFilename, xIFilter.GetPPointer() );
  236. if ( FAILED( hr ) )
  237. return hr;
  238. }
  239. ULONG ulFlags;
  240. hr = xIFilter->Init( IFILTER_INIT_CANON_PARAGRAPHS |
  241. IFILTER_INIT_CANON_HYPHENS |
  242. IFILTER_INIT_APPLY_INDEX_ATTRIBUTES,
  243. 0,
  244. 0,
  245. &ulFlags );
  246. if ( FAILED( hr ) )
  247. return hr;
  248. hr = xISearch->Init( xIFilter.GetPointer(), ulFlags );
  249. if ( FAILED( hr ) )
  250. return hr;
  251. //
  252. // Retrieve all the hit info. the info is wrt output from the IFilter.
  253. // a separate pass over a different IFilter is needed to match up
  254. // text to the hit info.
  255. //
  256. TArray<FILTERREGION> aHits;
  257. ULONG cRegions;
  258. FILTERREGION* aRegion;
  259. hr = xISearch->NextHitOffset( &cRegions, &aRegion );
  260. while ( S_OK == hr )
  261. {
  262. for ( ULONG i = 0; i < cRegions; i++ )
  263. aHits.Append( aRegion[i] );
  264. CoTaskMemFree( aRegion );
  265. hr = xISearch->NextHitOffset( &cRegions, &aRegion );
  266. }
  267. #if 0
  268. for ( ULONG i = 0; i < aHits.Count(); i++ )
  269. printf( "hit %d, chunk %d start %d extent %d\n",
  270. i, aHits[i].idChunk, aHits[i].cwcStart, aHits[i].cwcExtent );
  271. #endif
  272. return WalkFile( aHits, xIFilter, pwcFilename, fPrintFile );
  273. } //DoQuery
  274. //+-------------------------------------------------------------------------
  275. //
  276. // Function: GetQueryFunctions
  277. //
  278. // Synopsis: Loads needed undocumented functions from query.dll.
  279. //
  280. // Returns: The module handle or 0 on failure.
  281. //
  282. //--------------------------------------------------------------------------
  283. HINSTANCE GetQueryFunctions()
  284. {
  285. HINSTANCE h = LoadLibrary( L"query.dll" );
  286. if ( 0 != h )
  287. {
  288. #ifdef _WIN64
  289. char const * pcCIShutdown = "?CIShutdown@@YAXXZ";
  290. char const * pcMakeISearch = "?MakeISearch@@YAJPEAPEAUISearchQueryHits@@PEAVCDbRestriction@@PEBG@Z";
  291. #else
  292. char const * pcCIShutdown = "?CIShutdown@@YGXXZ";
  293. char const * pcMakeISearch = "?MakeISearch@@YGJPAPAUISearchQueryHits@@PAVCDbRestriction@@PBG@Z";
  294. #endif
  295. g_pCIShutdown = (PFnCIShutdown) GetProcAddress( h, pcCIShutdown );
  296. if ( 0 == g_pCIShutdown )
  297. {
  298. FreeLibrary( h );
  299. return 0;
  300. }
  301. g_pMakeISearch = (PFnMakeISearch) GetProcAddress( h, pcMakeISearch );
  302. if ( 0 == g_pMakeISearch )
  303. {
  304. FreeLibrary( h );
  305. return 0;
  306. }
  307. g_pLoadTextFilter = (PFnLoadTextFilter) GetProcAddress( h, "LoadTextFilter" );
  308. if ( 0 == g_pLoadTextFilter )
  309. {
  310. FreeLibrary( h );
  311. return 0;
  312. }
  313. }
  314. return h;
  315. } //GetQueryFunctions
  316. HINSTANCE PrepareForISearch()
  317. {
  318. return GetQueryFunctions();
  319. } //DoneWithISearch
  320. void DoneWithISearch( HINSTANCE h )
  321. {
  322. g_pCIShutdown();
  323. FreeLibrary( h );
  324. } //DoneWithISearch
  325. //+-------------------------------------------------------------------------
  326. //
  327. // Function: DoISearch
  328. //
  329. // Synopsis: Invoke ISearch on the file
  330. //
  331. // Arguments: [pwcRestriction] -- the query
  332. // [pwcFilename] -- the file
  333. // [fPrintFile] -- whether to print the filename
  334. // [lcid] -- locale of the query
  335. //
  336. //--------------------------------------------------------------------------
  337. HRESULT DoISearch(
  338. WCHAR const * pwcRestriction,
  339. WCHAR const * pwcFilename,
  340. BOOL fPrintFile,
  341. BOOL fDefineCPP,
  342. LCID lcid )
  343. {
  344. // Run the query
  345. return DoQuery( pwcFilename, pwcRestriction, fPrintFile, fDefineCPP, lcid );
  346. } //DoISearch