Windows NT 4.0 source code leak
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.

579 lines
19 KiB

4 years ago
  1. // Ftsrch.cpp -- Main interface function
  2. #include "stdafx.h"
  3. // #include <strstrea.h>
  4. #include "resource.h"
  5. #include "dialogs.h"
  6. #include "Globals.h"
  7. #include "FTSIFace.h"
  8. #include "ftsrch.h"
  9. #include "memex.h"
  10. #include "dict.h"
  11. #include "vector.h"
  12. #include "query.h"
  13. #include "hilite.h"
  14. #define SIZESTRING 256 // max characters in string
  15. /*rmk-->
  16. int cLetters = 0;
  17. BYTE bCharTypes [256] = { 0 };
  18. BYTE xlateCollate [256] = { 0xFF };
  19. BYTE xlateCollateInv [256] = { 0xFF };
  20. BYTE xlateCollateIC [256] = { 0xFF };
  21. BYTE map_to_lower_case[256] = { 0xFF };
  22. BYTE map_to_upper_case[256] = { 0xFF };
  23. BYTE map_to_char_class[256] = { 0 };
  24. static const PBYTE pbLetters = (PBYTE) &"Aa��������������BbCc��Dd��Ee��������FfGgHhIi��������JjKkLlMmNn��Oo��������������PpQqRrSs��TtUu��������VvWwXxYy����Zz��";
  25. static const PBYTE pbLetrcls = (PBYTE) &"aaaaaaaaaaaaaaaabbccccddddeeeeeeeeeeffgghhiiiiiiiiiijjkkllmmnnnnooooooooooooooooppqqrrssssttuuuuuuuuuuvvwwxxyyyyyyzz��";
  26. static const PBYTE pbUpperCase = (PBYTE)&"A�������BC�D�E����FGHI����JKLMN�O�����،PQRS�TU����VWXY��Z�";
  27. static const PBYTE pbAccented = (PBYTE) &"��������������������������������������������������������������";
  28. static const PBYTE pbPseudoLetters = (PBYTE) &"$_�";
  29. static const PBYTE pbDigits = (PBYTE) &"0123456789";
  30. static const PBYTE pbLetterImbeds = (PBYTE) &"'-";
  31. static const PBYTE pbDigitImbeds = (PBYTE) &",.";
  32. <--rmk*/
  33. void InitialTables()
  34. {
  35. // This routine sets up the tables which TBrowse uses to parse text streams into
  36. // symbols and punctuation. The tables are also used for collating sequence
  37. // comparisons and for sorting.
  38. /*rmk-->
  39. BYTE *pb, *pb2, b, b2;
  40. int c;
  41. for (c= 256, pb= &bCharTypes[0]; c--; ) *pb++ = 0;
  42. bCharTypes[ 0] = NULL_CHAR;
  43. for (pb= pbLetters ; b= *pb++; ++cLetters) bCharTypes[b] = LETTER_CHAR;
  44. for (pb= pbPseudoLetters; b= *pb++; ) bCharTypes[b] = LETTER_CHAR;
  45. for (pb= pbUpperCase ; b= *pb++; ) bCharTypes[b] |= UPPER_CASE_CHAR;
  46. for (pb= pbAccented ; b= *pb++; ) bCharTypes[b] |= ACCENTED_CHAR;
  47. for (pb= pbDigits ; b= *pb++; ) bCharTypes[b] = DIGIT_CHAR;
  48. for (pb= pbLetterImbeds ; b= *pb++; ) bCharTypes[b] = LETTER_IMBED;
  49. for (pb= pbDigitImbeds ; b= *pb++; ) bCharTypes[b] = DIGIT_IMBED;
  50. for (c= 0; c < 256; ++c)
  51. {
  52. map_to_lower_case[c]= c;
  53. map_to_upper_case[c]= c;
  54. map_to_char_class[c]= c;
  55. xlateCollate [c]= 0xFF;
  56. }
  57. for (pb= pbLetters, pb2= pbLetrcls; b= *pb++; )
  58. {
  59. map_to_char_class[b ]= *pb2++;
  60. map_to_lower_case[b ]= b2= *pb++;
  61. map_to_upper_case[b2]= b;
  62. map_to_char_class[b2]= *pb2++;
  63. }
  64. for (pb= pbLetters, b2=0; b= *pb++; ) xlateCollate[b]= b2++;
  65. for (pb= pbPseudoLetters; b= *pb++; ) xlateCollate[b]= b2++;
  66. for (pb= pbDigits ; b= *pb++; ) xlateCollate[b]= b2++;
  67. xlateCollate[' ' ]= b2++;
  68. xlateCollate['\t']= b2++;
  69. for (c= 0x20; c < 0x100; ++c) if (xlateCollate[c] == 0xFF) xlateCollate[c]= b2++;
  70. for (c= 0x01; c < 0x20 ; ++c) if (xlateCollate[c] == 0xFF) xlateCollate[c]= b2++;
  71. for (c= 0; c < 256; c++) xlateCollateIC[c]= xlateCollate[c];
  72. for (pb= pbLetters, pb2= pbLetrcls; b= *pb++; ) xlateCollateIC[b] = xlateCollateIC[*pb2++];
  73. for (c= 256; c--; ) xlateCollateInv[xlateCollate[c]] = c;
  74. <--rmk*/
  75. }
  76. extern "C" void __stdcall NextAnimation(void)
  77. {
  78. // You are calling the animation routines when the animate object in
  79. // winhelp (or the calling app does not exist, or has not been registered
  80. // with the RegisterAnimator call.
  81. // ASSERT(FALSE);
  82. }
  83. ANIMATOR pAnimate = NextAnimation; // Put a asserting routing there to start
  84. extern "C" HINDEX APIENTRY NewIndex(const PBYTE pbSourceName, UINT uiTime1, UINT uiTime2,
  85. UINT iCharsetDefault, UINT lcidDefault, UINT fdwOptions
  86. )
  87. {
  88. pAnimate();
  89. UINT cbSourceName= strlen(PCHAR(pbSourceName)) + 1;
  90. FILETIME ft;
  91. ft. dwLowDateTime = uiTime1;
  92. ft.dwHighDateTime = uiTime2;
  93. HINDEX hinx= CGlobals::NewIndexGlobals(pbSourceName, cbSourceName, &ft, iCharsetDefault, lcidDefault, fdwOptions);
  94. return hinx;
  95. }
  96. extern "C" ERRORCODE APIENTRY ScanTopicTitle(HINDEX hinx, PBYTE pbTitle, UINT cbTitle,
  97. UINT iTopic, HANDLE hTopic, UINT iCharset, UINT lcid
  98. )
  99. {
  100. pAnimate();
  101. if (!CGlobals::ValidObject((CGlobals *)hinx, CGlobals::Indexer)) return NOT_INDEXER;
  102. ERRORCODE ec= ((CGlobals *)hinx)->ScanTopicTitle(pbTitle, cbTitle, iTopic, hTopic, iCharset, lcid);
  103. return ec;
  104. }
  105. extern "C" ERRORCODE APIENTRY ScanTopicText (HINDEX hinx, PBYTE pbText, UINT cbText, UINT iCharset, UINT lcid)
  106. {
  107. pAnimate();
  108. if (!CGlobals::ValidObject((CGlobals *)hinx, CGlobals::Indexer)) return NOT_INDEXER;
  109. ERRORCODE ec= ((CGlobals *)hinx)->ScanTopicText(pbText, cbText, iCharset, lcid);
  110. return ec;
  111. }
  112. extern "C" ERRORCODE APIENTRY SaveIndex(HINDEX hinx, PSZ pszFileName)
  113. {
  114. pAnimate();
  115. if (!CGlobals::ValidObject((CGlobals *)hinx, CGlobals::Indexer)) return NOT_INDEXER;
  116. ERRORCODE ec= ((CGlobals *)hinx)->SaveIndex(pszFileName);
  117. return ec;
  118. }
  119. extern "C" ERRORCODE APIENTRY DeleteIndex(HINDEX hinx)
  120. {
  121. pAnimate();
  122. if (!CGlobals::ValidObject((CGlobals *)hinx, CGlobals::Indexer)) return NOT_INDEXER;
  123. delete (CGlobals *)hinx;
  124. return 0;
  125. }
  126. extern "C" BOOL APIENTRY IsValidIndex(PSZ pszFileName, UINT dwOptions)
  127. {
  128. return CPersist::IsValidIndex(pszFileName, dwOptions & (TOPIC_SEARCH | PHRASE_SEARCH | PHRASE_FEEDBACK | VECTOR_SEARCH));
  129. }
  130. extern "C" HSEARCHER APIENTRY NewSearcher()
  131. {
  132. return (HSEARCHER) (CGlobals::NewSearcherGlobals());
  133. }
  134. extern "C" INT APIENTRY OpenIndex(HSEARCHER hsrch, PSZ pszIndexFileName,
  135. PBYTE pbSourceName, PUINT pcbSourceNameLimit,
  136. PUINT pTime1, PUINT pTime2
  137. )
  138. {
  139. if (!CGlobals::ValidObject((CGlobals *)hsrch, CGlobals::Searcher)) return NOT_SEARCHER;
  140. FILETIME ft;
  141. ft.dwLowDateTime = pTime1? *pTime1 : 0;
  142. ft.dwHighDateTime = pTime2? *pTime2 : 0;
  143. INT iResult= ((CGlobals *) hsrch)->OpenIndex(pszIndexFileName, pbSourceName, pcbSourceNameLimit, &ft);
  144. if (pTime1) *pTime1= ft.dwLowDateTime;
  145. if (pTime2) *pTime2= ft.dwHighDateTime;
  146. return iResult;
  147. }
  148. extern "C" ERRORCODE APIENTRY DiscardIndex(HSEARCHER hsrch, INT iIndex)
  149. {
  150. if (!CGlobals::ValidObject((CGlobals *)hsrch, CGlobals::Searcher)) return NOT_SEARCHER;
  151. return ((CGlobals *) hsrch)->DiscardIndex(iIndex);
  152. }
  153. extern "C" ERRORCODE APIENTRY QueryOptions (HSEARCHER hsrch, INT iIndex, PUINT pfdwOptions)
  154. {
  155. if (!CGlobals::ValidObject((CGlobals *)hsrch, CGlobals::Searcher)) return NOT_SEARCHER;
  156. return ((CGlobals *) hsrch)->QueryOptions(iIndex, pfdwOptions);
  157. }
  158. extern "C" ERRORCODE APIENTRY SaveGroup(HSEARCHER hsrch, PSZ pszFileName)
  159. {
  160. if (!CGlobals::ValidObject((CGlobals *)hsrch, CGlobals::Searcher)) return NOT_SEARCHER;
  161. return ((CGlobals *) hsrch)->SaveGroup(hsrch, pszFileName);
  162. }
  163. extern "C" ERRORCODE APIENTRY LoadGroup(HSEARCHER hsrch, PSZ pszFileName)
  164. {
  165. if (!CGlobals::ValidObject((CGlobals *)hsrch, CGlobals::Searcher)) return NOT_SEARCHER;
  166. return ((CGlobals *) hsrch)->LoadGroup(hsrch, pszFileName);
  167. }
  168. extern "C" HWND APIENTRY OpenDialog(HSEARCHER hsrch, HWND hwndParent)
  169. {
  170. if (!CGlobals::ValidObject((CGlobals *)hsrch, CGlobals::Searcher)) return NULL;
  171. return ((CGlobals *) hsrch)->OpenDialog(hwndParent);
  172. }
  173. extern "C" ERRORCODE APIENTRY DeleteSearcher(HSEARCHER hsrch)
  174. {
  175. if (!CGlobals::ValidObject((CGlobals *)hsrch, CGlobals::Searcher)) return NOT_SEARCHER;
  176. delete (CGlobals *) hsrch;
  177. return 0;
  178. }
  179. extern "C" HCOMPRESSOR APIENTRY NewCompressor(UINT iCharsetDefault)
  180. {
  181. return (HCOMPRESSOR) (CGlobals::NewCompressorGlobals(iCharsetDefault));
  182. }
  183. extern "C" ERRORCODE APIENTRY ScanText(HCOMPRESSOR hcmp, PBYTE pbText, UINT cbText, UINT iCharset)
  184. {
  185. if (!CGlobals::ValidObject((CGlobals *)hcmp, CGlobals::Compressor)) return NOT_COMPRESSOR;
  186. return ((CGlobals *) hcmp)->ScanForStats(pbText, cbText, iCharset);
  187. }
  188. extern "C" ERRORCODE APIENTRY GetPhraseTable(HCOMPRESSOR hcmp, PUINT pcPhrases, PBYTE *ppbImages, PUINT pcbImages,
  189. PBYTE *ppacbImageCompressed, PUINT pcbCompressed
  190. )
  191. {
  192. if (!CGlobals::ValidObject((CGlobals *)hcmp, CGlobals::Compressor)) return NOT_COMPRESSOR;
  193. return ((CGlobals *) hcmp)->GetPhraseTable(pcPhrases, ppbImages, pcbImages,
  194. ppacbImageCompressed, pcbCompressed
  195. );
  196. }
  197. extern "C" ERRORCODE APIENTRY SetPhraseTable(HCOMPRESSOR hcmp, PBYTE pbImages, UINT cbImages,
  198. PBYTE pacbImageCompressed, UINT cbCompressed
  199. )
  200. {
  201. if (!CGlobals::ValidObject((CGlobals *)hcmp, CGlobals::Compressor)) return NOT_COMPRESSOR;
  202. return ((CGlobals *) hcmp)->SetPhraseTable(pbImages, cbImages,
  203. pacbImageCompressed, cbCompressed
  204. );
  205. }
  206. extern "C" INT APIENTRY CompressText(HCOMPRESSOR hcmp, PBYTE pbText, UINT cbText, PBYTE *ppbCompressed, UINT iCharset)
  207. {
  208. if (!CGlobals::ValidObject((CGlobals *)hcmp, CGlobals::Compressor)) return NOT_COMPRESSOR;
  209. return ((CGlobals *) hcmp)->CompressText(pbText, cbText, ppbCompressed, iCharset);
  210. }
  211. extern "C" INT APIENTRY DecompressText(HCOMPRESSOR hcmp, PBYTE pbCompressed, UINT cbCompressed, PBYTE pbText)
  212. {
  213. if (!CGlobals::ValidObject((CGlobals *)hcmp, CGlobals::Compressor)) return NOT_COMPRESSOR;
  214. return ((CGlobals *) hcmp)->DecompressText(pbCompressed, cbCompressed, pbText);
  215. }
  216. extern "C" ERRORCODE APIENTRY DeleteCompressor(HCOMPRESSOR hcmp)
  217. {
  218. if (!CGlobals::ValidObject((CGlobals *)hcmp, CGlobals::Compressor)) return NOT_COMPRESSOR;
  219. delete (CGlobals *) hcmp;
  220. return 0;
  221. }
  222. HINSTANCE hinstDLL = NULL;
  223. HINSTANCE hLexLib = NULL;
  224. HINSTANCE hMPRLib = NULL;
  225. UINT uOpSys = NULL;
  226. UINT uOpSysVer = NULL;
  227. HCURSOR hcurArrow = NULL;
  228. HCURSOR hcurBusy = NULL;
  229. HBITMAP hbmGray50pc = NULL;
  230. HBITMAP hbmCheckered = NULL;
  231. PWORDBREAKW pWordBreakW = NULL;
  232. PWORDBREAKA pWordBreakA = NULL;
  233. PWNETADDCONNECTION2A pWNetAddConnection2 = NULL;
  234. PWNETCANCELCONNECTION2A pWNetCancelConnection2 = NULL;
  235. #define MAX_ERROR_STRING 256
  236. #define MAX_TITLE 128
  237. char szDisk_Full_Err [MAX_ERROR_STRING];
  238. char szDisk_Full_Err2 [MAX_TITLE];
  239. char szMem_Err [MAX_ERROR_STRING];
  240. char szNeed_More_Memory[MAX_TITLE];
  241. UINT cAttachedProcesses = 0;
  242. extern "C" void InitialFTSLex();
  243. extern "C" void ShutdownFTSLex();
  244. extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD fdwReason, LPVOID pvReserved)
  245. {
  246. // BugBug! Need a Mutex Semaphore for this code...
  247. if (!hinstDLL) hinstDLL= hInstance;
  248. switch (fdwReason)
  249. {
  250. case DLL_PROCESS_ATTACH:
  251. if (!cAttachedProcesses++)
  252. {
  253. InitialFTSLex();
  254. char szLexLib[20];
  255. wsprintf(szLexLib, "ftlx%04lx.dll", GetUserDefaultLCID());
  256. hLexLib = LoadLibrary(szLexLib); // attempt to load non-English word break
  257. if (!hLexLib && szLexLib[4] != '0' && szLexLib[5] != '4')
  258. {
  259. szLexLib[4] = '0'; // not successful, search for 04XX word break
  260. szLexLib[5] = '4';
  261. hLexLib = LoadLibrary(szLexLib); // attempt to load non-English word break
  262. }
  263. if (hLexLib)
  264. {
  265. pWordBreakA = (PWORDBREAKA)GetProcAddress(hLexLib, "FTSWordBreakA");
  266. pWordBreakW = (PWORDBREAKW)GetProcAddress(hLexLib, "FTSWordBreakW");
  267. if (!pWordBreakA || !pWordBreakW)
  268. {
  269. // If we failed to get both proc addresses, we set the pointer variables back to NULL.
  270. pWordBreakA = &FTSWordBreakA;
  271. pWordBreakW = &FTSWordBreakW;
  272. }
  273. }
  274. else
  275. {
  276. pWordBreakA = &FTSWordBreakA;
  277. pWordBreakW = &FTSWordBreakW;
  278. }
  279. if ( !::LoadString(hinstDLL, IDS_DISK_FULL_ERR , szDisk_Full_Err , MAX_ERROR_STRING)
  280. || !::LoadString(hinstDLL, IDS_DISK_FULL_ERR2 , szDisk_Full_Err2 , MAX_TITLE )
  281. || !::LoadString(hinstDLL, IDS_MEM_ERR , szMem_Err , MAX_ERROR_STRING)
  282. || !::LoadString(hinstDLL, IDS_NEED_MORE_MEMORY, szNeed_More_Memory, MAX_TITLE )
  283. ) return FALSE;
  284. if (!_CRT_INIT(hInstance, fdwReason, pvReserved))
  285. return FALSE;
  286. InitialTables();
  287. hcurArrow = ::LoadCursor(NULL, IDC_ARROW );
  288. hcurBusy = ::LoadCursor(NULL, IDC_WAIT );
  289. hbmGray50pc = ::LoadBitmap(hinstDLL, "GRAY_50_PER_CENT");
  290. hbmCheckered = ::LoadBitmap(hinstDLL, "CHECKERED" );
  291. char map[4] = {WINNT,WIN16,WIN32S,WIN40};
  292. DWORD dwVer = GetVersion();
  293. #if defined (WIN32)
  294. uOpSys = map[dwVer >> 30];
  295. #else
  296. uOpSys = WIN16;
  297. #endif
  298. uOpSysVer = LOWORD(dwVer);
  299. if (!hcurArrow || !hcurBusy || !hbmGray50pc || !hbmCheckered)
  300. {
  301. if (hbmGray50pc ) DeleteObject(hbmGray50pc );
  302. if (hbmCheckered) DeleteObject(hbmCheckered);
  303. return FALSE;
  304. }
  305. }
  306. return CFind::RegisterWndClass(hinstDLL) &&
  307. CTextView::RegisterWndClass(hinstDLL);
  308. break;
  309. case DLL_PROCESS_DETACH:
  310. CGlobals::ProcessShutdown();
  311. ShutdownFTSLex();
  312. LiberateHeap();
  313. if (!--cAttachedProcesses)
  314. {
  315. ASSERT(!CGlobals::AnyGlobalsActive());
  316. DeleteObject(hbmGray50pc );
  317. DeleteObject(hbmCheckered);
  318. if (hLexLib)
  319. FreeLibrary(hLexLib);
  320. if (hMPRLib)
  321. FreeLibrary(hMPRLib);
  322. hLexLib = NULL;
  323. pWordBreakW = NULL;
  324. pWordBreakA = NULL;
  325. hMPRLib = NULL;
  326. }
  327. _CRT_INIT(hInstance, fdwReason, pvReserved);
  328. break;
  329. default:
  330. _CRT_INIT(hInstance, fdwReason, pvReserved);
  331. break;
  332. }
  333. return TRUE;
  334. }
  335. // WinHelp interfaces -- note WINAPI calling convention
  336. extern "C" HWND WINAPI OpenTabDialog(HWND hwndParent, DWORD val1, DWORD val2)
  337. {
  338. return OpenDialog((HSEARCHER) val1, hwndParent);
  339. }
  340. BOOL fAnimatorExternal = FALSE;
  341. extern "C" ERRORCODE APIENTRY RegisterAnimator(ANIMATOR pAnimator, HWND hwndAnimator)
  342. {
  343. if (pAnimator == NULL)
  344. {
  345. pAnimate = NextAnimation; // Null routine with an assert
  346. hwndMain = NULL;
  347. fAnimatorExternal = FALSE;
  348. }
  349. else
  350. {
  351. pAnimate = pAnimator;
  352. hwndMain = hwndAnimator;
  353. fAnimatorExternal = TRUE;
  354. }
  355. return 0;
  356. }
  357. ///////////////////////////////////////////////////////////////////////////////////////
  358. // New Hilite Functions
  359. // "NewHiliter" creates a hiliter tied to a particular searcher.
  360. // We also pass it a windows handle so it can notify us whenever the
  361. // current query state (in a given hiliter) becomes outdated.
  362. // [if you do not wish to be notified pass a null handle]
  363. // Returns a handle to the new hiliter.
  364. extern "C" HHILITER APIENTRY NewHiliter(HSEARCHER hSearch)
  365. {
  366. if (!CGlobals::ValidObject((CGlobals*)hSearch, CGlobals::Searcher)) return 0;
  367. // make sure we have a valid searcher
  368. HHILITER hhil = (HHILITER) (CHiliter::NewHiliter(hSearch));
  369. // if so, go down a level
  370. return hhil; // .. and return new handle
  371. }
  372. extern "C" ERRORCODE APIENTRY DeleteHiliter(HHILITER hhil)
  373. {
  374. pAnimate();
  375. if (!CHiliter::ValidObject(hhil)) return NOT_HILITER;
  376. delete (CHiliter*)hhil;
  377. return 0;
  378. }
  379. // --------------------------------------------------------------------------
  380. // "ScanDisplayText" supplies the display text for which hilite information
  381. // is to be computed. This function may be called iteratively to pass across
  382. // the relevant display text. This is necessary because the text may be
  383. // composed of segments with different Charsets and/or lcid's.
  384. extern "C" ERRORCODE APIENTRY ScanDisplayText(HHILITER hhil, PBYTE pbText, int cbText,
  385. UINT iCharset, LCID lcid)
  386. {
  387. if (!CHiliter::ValidObject(hhil)) return NOT_HILITER;
  388. // make sure we have a valid hiliter
  389. ERRORCODE ec = ((CHiliter*)hhil)->ScanDisplayText(pbText, cbText, iCharset, lcid);
  390. return ec; // .. and return any errors
  391. }
  392. // --------------------------------------------------------------------------
  393. // ClearDisplayText discards the display text.
  394. // It is not necessary to call this with a newly created Hiliter handle.
  395. extern "C" ERRORCODE APIENTRY ClearDisplayText(HHILITER hhil)
  396. {
  397. if (!CHiliter::ValidObject(hhil)) return NOT_HILITER;
  398. // make sure we have a valid hiliter
  399. ERRORCODE ec = ((CHiliter*)hhil)->ClearDisplayText(); // if so, go down a level
  400. return ec; // .. and return any errors
  401. }
  402. // --------------------------------------------------------------------------
  403. // CountHilites returns the number of hilites for a specified byte offset range.
  404. // If limit == -1 then the range will extend to the end of the buffer.
  405. extern "C" int APIENTRY CountHilites(HHILITER hhil, int base, int limit)
  406. {
  407. if (!CHiliter::ValidObject(hhil)) return NOT_HILITER;
  408. // make sure we have a valid hiliter
  409. UINT count = ((CHiliter*)hhil)->CountHilites(base, limit);
  410. return count; // .. and return the count
  411. }
  412. // --------------------------------------------------------------------------
  413. // "QueryHilites" retrieves hilite information for the specified byte offset
  414. // range. It returns the number of hilites for which information has been
  415. // returned. cHilites and paHilites describe a buffer reserved for the
  416. // returned hilite information. If limit == -1 the range will extend
  417. // to the end of the buffer.
  418. extern "C" int APIENTRY QueryHilites(HHILITER hhil, int base, int limit,
  419. int cHilites, HILITE* paHilites)
  420. {
  421. if (!CHiliter::ValidObject(hhil)) return NOT_HILITER;
  422. // make sure we have a valid hiliter
  423. int count = ((CHiliter*)hhil)->QueryHilites(base, limit, cHilites, paHilites);
  424. return count; // .. and return the count
  425. }
  426. // If you want to get the highlights sequentially you can use the above
  427. // call in a loop as follows:
  428. // while (TRUE) {
  429. // if (QueryHilites(hhil, base, limit, 1, pHilite) != 1 ) break;
  430. //
  431. // // TODO -- your processing code
  432. //
  433. // base = pHilite->limit;
  434. // }
  435. ///////////////////////////////////////////////////////////////////////////////