//+------------------------------------------------------------------------- // // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A // PARTICULAR PURPOSE. // // Copyright 1998-2000 Microsoft Corporation. All Rights Reserved. // // PROGRAM: isrchdmp.cx // // PURPOSE: Illustrates a minimal query using Indexing Service. // // PLATFORM: Windows 2000 // //-------------------------------------------------------------------------- #ifndef UNICODE #define UNICODE #endif #include #include #define DBINITCONSTANTS #include #include #include #include #include #include #include "isearch.h" #include "array.hxx" extern CIPROPERTYDEF aCPPProperties[]; extern unsigned cCPPProperties; //+------------------------------------------------------------------------- // // Template: XInterface // // Synopsis: Template for managing ownership of interfaces // //-------------------------------------------------------------------------- template class XInterface { public: XInterface( T * p = 0 ) : _p( p ) {} ~XInterface() { if ( 0 != _p ) _p->Release(); } T * operator->() { return _p; } T * GetPointer() const { return _p; } IUnknown ** GetIUPointer() { return (IUnknown **) &_p; } T ** GetPPointer() { return &_p; } void ** GetQIPointer() { return (void **) &_p; } T * Acquire() { T * p = _p; _p = 0; return p; } private: T * _p; }; const GUID guidStorage = PSGUID_STORAGE; typedef void (__stdcall * PFnCIShutdown)(void); typedef HRESULT (__stdcall * PFnMakeISearch)( ISearchQueryHits ** ppSearch, DBCOMMANDTREE * pRst, WCHAR const * pwcPath ); typedef HRESULT (__stdcall * PFnLoadTextFilter)( WCHAR const * pwcPath, IFilter ** ppIFilter ); PFnCIShutdown g_pCIShutdown = 0; PFnMakeISearch g_pMakeISearch = 0; PFnLoadTextFilter g_pLoadTextFilter = 0; #define UNICODE_PARAGRAPH_SEPARATOR 0x2029 ULONG CountCR( WCHAR * pCur, ULONG cwc, WCHAR * &pwcPrev ) { pwcPrev = pCur; WCHAR * pEnd = pCur + cwc; ULONG cCR = 0; while ( pCur < pEnd ) { WCHAR c = *pCur; if ( L'\r' == c || L'\n' == c || UNICODE_PARAGRAPH_SEPARATOR == c ) { cCR++; if ( ( L'\r' == c ) && ( (pCur+1) < pEnd ) && ( L'\n' == *(pCur+1) ) ) pCur++; pwcPrev = pCur + 1; } pCur++; } return cCR; } //CountCR HRESULT WalkFile( TArray & aHits, XInterface & xIFilter, WCHAR const * pwcFile, BOOL fPrintFile ) { ULONG ulFlags; HRESULT hr = xIFilter->Init( IFILTER_INIT_CANON_PARAGRAPHS | IFILTER_INIT_CANON_HYPHENS | IFILTER_INIT_APPLY_INDEX_ATTRIBUTES, 0, 0, &ulFlags ); if ( FAILED( hr ) ) return hr; ULONG lenSoFar = 0; int cChunk = 0; BOOL fSeenProp = FALSE; ULONG iHit = 0; ULONG cLines = 1; const ULONG cwcBufSize = 65536; WCHAR *pwc = new WCHAR[cwcBufSize + 1]; if ( 0 == pwc ) return E_OUTOFMEMORY; STAT_CHUNK statChunk; hr = xIFilter->GetChunk( &statChunk ); while( SUCCEEDED( hr ) || ( FILTER_E_LINK_UNAVAILABLE == hr ) || ( FILTER_E_EMBEDDING_UNAVAILABLE == hr ) ) { if ( SUCCEEDED( hr ) && (statChunk.flags & CHUNK_TEXT) ) { // read the contents only if ( ( guidStorage == statChunk.attribute.guidPropSet ) && ( PRSPEC_PROPID == statChunk.attribute.psProperty.ulKind ) && ( PID_STG_CONTENTS == statChunk.attribute.psProperty.propid ) ) { if ( CHUNK_NO_BREAK != statChunk.breakType ) { switch( statChunk.breakType ) { case CHUNK_EOW: case CHUNK_EOS: break; case CHUNK_EOP: case CHUNK_EOC: cLines++; break; } } ULONG iIntoChunk = 0; ULONG cwcRetrieved; ULONG iPrevLine = ~0; do { cwcRetrieved = cwcBufSize; hr = xIFilter->GetText( &cwcRetrieved, pwc ); pwc[cwcRetrieved] = 0; // The buffer may be filled with zeroes. Nice filter. if ( SUCCEEDED( hr ) ) { if ( 0 != cwcRetrieved ) cwcRetrieved = __min( cwcRetrieved, wcslen( pwc ) ); while ( ( iHit < aHits.Count() ) && ( aHits[iHit].idChunk == statChunk.idChunk ) && ( aHits[iHit].cwcStart >= iIntoChunk ) && ( aHits[iHit].cwcStart < ( iIntoChunk + cwcRetrieved ) ) ) { WCHAR *pwcStart; ULONG iLine = cLines + CountCR( pwc, aHits[iHit].cwcStart - iIntoChunk, pwcStart ); WCHAR *pwcEnd = wcschr( pwcStart, L'\r' ); if ( 0 == pwcEnd ) pwcEnd = wcschr( pwcStart, L'\n' ); if ( 0 != pwcEnd ) *pwcEnd = 0; if ( iLine != iPrevLine ) { if ( fPrintFile ) wprintf( L"%ws", pwcFile ); wprintf( L"(%u): %ws\n", iLine, pwcStart ); iPrevLine = iLine; } if ( 0 != pwcEnd ) *pwcEnd = '\r'; iHit++; } WCHAR * pwcDummy; cLines += CountCR( pwc, cwcRetrieved, pwcDummy ); iIntoChunk += cwcRetrieved; } } while( SUCCEEDED( hr ) ); } } hr = xIFilter->GetChunk ( &statChunk ); } delete [] pwc; if ( FILTER_E_END_OF_CHUNKS == hr ) hr = S_OK; return hr; } //WalkFile //+------------------------------------------------------------------------- // // Function: DoISearchQuery // // Synopsis: Creates and executes a query, then displays the results. // // Arguments: [pwcFilename] - Name of the file // [pwcQueryRestrition] - The actual query string // [fPrintFile] - whether to print the filename // [lcid] - Locale of the query // [ulDialect] - Dialect of tripolish, 1 or 2. // // Returns: HRESULT result of the query // //-------------------------------------------------------------------------- HRESULT DoISearchQuery( WCHAR const * pwcFilename, WCHAR const * pwcQueryRestriction, BOOL fPrintFile, BOOL fDefineCPP, LCID lcid, ULONG ulDialect ) { // Create an OLE DB query tree from a text restriction DBCOMMANDTREE * pTree; ULONG cDefinedProperties = fDefineCPP ? cCPPProperties : 0; HRESULT hr = CITextToSelectTreeEx( pwcQueryRestriction, // the query itself ulDialect, // dialect to use &pTree, // resulting tree cDefinedProperties, // C++ properties aCPPProperties, // C++ properties lcid ); // the locale if ( FAILED( hr ) ) return hr; // Make the ISearchQueryHits object XInterface xISearch; hr = g_pMakeISearch( xISearch.GetPPointer(), pTree, 0 ); if ( FAILED( hr ) ) return hr; XInterface xIFilter; #if 1 hr = LoadIFilter( pwcFilename, 0, xIFilter.GetQIPointer() ); if ( FAILED( hr ) ) { // Fall back on the plain text filter hr = g_pLoadTextFilter( pwcFilename, xIFilter.GetPPointer() ); if ( FAILED( hr ) ) return hr; } #else // LIFF_LOAD_DEFINED_FILTER: Load the filter found for the file // LIFF_IMPLEMENT_TEXT_FILTER_FALLBACK_POLICY: Use the registry key to check to fallback // LIFF_FORCE_TEXT_FILTER_FALLBACK: Always fall back to the text filter if no other is available hr = LoadIFilterEx( pwcFilename, LIFF_IMPLEMENT_TEXT_FILTER_FALLBACK_POLICY, IID_IFilter, xIFilter.GetQIPointer() ); if ( FAILED( hr ) ) { printf( "can't load filter: %#x\n", hr ); return hr; } #endif ULONG ulFlags; hr = xIFilter->Init( IFILTER_INIT_CANON_PARAGRAPHS | IFILTER_INIT_CANON_HYPHENS | IFILTER_INIT_APPLY_INDEX_ATTRIBUTES, 0, 0, &ulFlags ); if ( FAILED( hr ) ) return hr; hr = xISearch->Init( xIFilter.GetPointer(), ulFlags ); if ( FAILED( hr ) ) return hr; // // Retrieve all the hit info. the info is wrt output from the IFilter. // a separate pass over a different IFilter is needed to match up // text to the hit info. // TArray aHits; ULONG cRegions; FILTERREGION* aRegion; hr = xISearch->NextHitOffset( &cRegions, &aRegion ); while ( S_OK == hr ) { for ( ULONG i = 0; i < cRegions; i++ ) aHits.Append( aRegion[i] ); CoTaskMemFree( aRegion ); hr = xISearch->NextHitOffset( &cRegions, &aRegion ); } #if 0 for ( ULONG i = 0; i < aHits.Count(); i++ ) printf( "hit %d, chunk %d start %d extent %d\n", i, aHits[i].idChunk, aHits[i].cwcStart, aHits[i].cwcExtent ); #endif return WalkFile( aHits, xIFilter, pwcFilename, fPrintFile ); } //DoISearchQuery //+------------------------------------------------------------------------- // // Function: GetQueryFunctions // // Synopsis: Loads needed undocumented functions from query.dll. // // Returns: The module handle or 0 on failure. // //-------------------------------------------------------------------------- HINSTANCE GetQueryFunctions() { HINSTANCE h = LoadLibrary( L"query.dll" ); if ( 0 != h ) { #ifdef _WIN64 char const * pcCIShutdown = "?CIShutdown@@YAXXZ"; char const * pcMakeISearch = "?MakeISearch@@YAJPEAPEAUISearchQueryHits@@PEAVCDbRestriction@@PEBG@Z"; #else char const * pcCIShutdown = "?CIShutdown@@YGXXZ"; char const * pcMakeISearch = "?MakeISearch@@YGJPAPAUISearchQueryHits@@PAVCDbRestriction@@PBG@Z"; #endif g_pCIShutdown = (PFnCIShutdown) GetProcAddress( h, pcCIShutdown ); if ( 0 == g_pCIShutdown ) { FreeLibrary( h ); return 0; } g_pMakeISearch = (PFnMakeISearch) GetProcAddress( h, pcMakeISearch ); if ( 0 == g_pMakeISearch ) { FreeLibrary( h ); return 0; } g_pLoadTextFilter = (PFnLoadTextFilter) GetProcAddress( h, "LoadTextFilter" ); if ( 0 == g_pLoadTextFilter ) { FreeLibrary( h ); return 0; } } return h; } //GetQueryFunctions HINSTANCE PrepareForISearch() { return GetQueryFunctions(); } //DoneWithISearch void DoneWithISearch( HINSTANCE h ) { g_pCIShutdown(); FreeLibrary( h ); } //DoneWithISearch //+------------------------------------------------------------------------- // // Function: DoISearch // // Synopsis: Invoke ISearch on the file // // Arguments: [pwcRestriction] -- the query // [pwcFilename] -- the file // [fPrintFile] -- whether to print the filename // [fDefineCPP] -- TRUE to define the C++ properties func and class // [lcid] -- locale of the query // [ulDialect] -- the dialect of the query language // //-------------------------------------------------------------------------- HRESULT DoISearch( WCHAR const * pwcRestriction, WCHAR const * pwcFilename, BOOL fPrintFile, BOOL fDefineCPP, LCID lcid, ULONG ulDialect ) { // Run the query return DoISearchQuery( pwcFilename, pwcRestriction, fPrintFile, fDefineCPP, lcid, ulDialect ); } //DoISearch