Leaked source code of windows server 2003
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.

2088 lines
53 KiB

  1. /*++
  2. Copyright (c) 1989-2001 Microsoft Corporation
  3. Module Name:
  4. CSearch.cpp
  5. Abstract:
  6. This module contains code that handles the searching of the disk for
  7. fixed entries.
  8. Author:
  9. kinshu created July 2, 2001
  10. Notes:
  11. The search window is implemented as a modeless window that has NULL as its parent.
  12. We had to do this because we want the users to tab between the main window and the
  13. search window
  14. --*/
  15. #include "precomp.h"
  16. /////////////////////// Extern variables //////////////////////////////////////
  17. extern BOOL g_bMainAppExpanded;
  18. extern BOOL g_bSomeWizardActive;
  19. extern HINSTANCE g_hInstance;
  20. extern HWND g_hDlg;
  21. extern HIMAGELIST g_hImageList;
  22. ///////////////////////////////////////////////////////////////////////////////
  23. //////////////////////// Defines //////////////////////////////////////////////
  24. // We're using the high 4 bits of the TAGID to say what PDB the TAGID is from.
  25. #define PDB_MAIN 0x00000000
  26. #define PDB_TEST 0x10000000
  27. #define PDB_LOCAL 0x20000000
  28. // Used to get the tag ref from the tagid, the low 28 bits
  29. #define TAGREF_STRIP_TAGID 0x0FFFFFFF
  30. // Used to get the PDB from the tagid, the high 4 bits
  31. #define TAGREF_STRIP_PDB 0xF0000000
  32. // Subitems for the columns of the list view
  33. #define SEARCH_COL_AFFECTEDFILE 0
  34. #define SEARCH_COL_PATH 1
  35. #define SEARCH_COL_APP 2
  36. #define SEARCH_COL_ACTION 3
  37. #define SEARCH_COL_DBTYPE 4
  38. // Total number of columns in the search dialog list view
  39. #define TOT_COLS 5
  40. ///////////////////////////////////////////////////////////////////////////////
  41. //////////////////////// Global variables /////////////////////////////////////
  42. // Index where the next element will be inserted in the list view
  43. UINT g_nIndex = 0;
  44. // The search object
  45. CSearch* g_pSearch;
  46. // width and height of the dialog box. These are required in the WM_SIZE handler
  47. int g_cWidthSrch;
  48. int g_cHeightSrch;
  49. //
  50. // This will hold the path that we want to search. e.g c:\*.exe or c:\
  51. // This will be the content of the text box
  52. static TCHAR s_szPath[MAX_PATH + 5]; // just so that we can have *.exe at the end, if needed. This will be an invalid path.
  53. // The path that the user last searched on.
  54. static TCHAR s_szPrevPath[MAX_PATH + 5]; // just so that we can have *.exe at the end, if needed. This will be an invalid path.
  55. //
  56. // What type of entries are we looking for. The values of these will be set depending
  57. // upon if the corresponding check boxes are set
  58. BOOL s_bAppHelp; // We want to see entries with Apphelp
  59. BOOL s_bShims; // We want to see entries with shims/flags or patches
  60. BOOL s_bLayers; // We want to see entries with layers
  61. HSDB g_hSDB;
  62. // The handle to the search dialog
  63. HWND g_hSearchDlg;
  64. // The thread which does all the job
  65. HANDLE g_hSearchThread = NULL;
  66. // The handle to the search results list
  67. HWND g_hwndSearchList;
  68. // If this is TRUE, we must abort the search. Typically set when the user presses STOP button
  69. BOOL g_bAbort;
  70. // The critical section that guards g_bAbort and access to the list view
  71. CRITICAL_SECTION g_CritSect;
  72. // The handle to the main dialog
  73. HWND g_hdlgSearchDB;
  74. // This is a bit array that describes which cols are sorted in which fashion
  75. static LONG s_lColumnSort;
  76. //
  77. // This will contain the cur dir before we started search
  78. TCHAR g_szPresentDir[MAX_PATH];
  79. // This will be the path that we want to show in the status bar
  80. TCHAR g_szNewPathFound[MAX_PATH];
  81. //////////////////////////////////////////////////////////////////////////////
  82. //////////////////////// Function Declarations //////////////////////////////
  83. void
  84. ShowContextMenu(
  85. WPARAM wParam,
  86. LPARAM lParam
  87. );
  88. void
  89. OnBrowse(
  90. HWND hdlg
  91. );
  92. BOOL
  93. AddNewResult(
  94. LPARAM lParam
  95. );
  96. void
  97. DoSearch(
  98. HWND hDlg
  99. );
  100. void
  101. OnSearchInitDialog(
  102. HWND hDlg,
  103. LPARAM lParam
  104. );
  105. void
  106. SaveResults(
  107. HWND hdlg
  108. );
  109. void
  110. SearchDirectory(
  111. LPTSTR szDir,
  112. LPTSTR szExt
  113. );
  114. //////////////////////////////////////////////////////////////////////////////
  115. void
  116. GetCheckStatus(
  117. IN HWND hDlg
  118. )
  119. /*++
  120. GetCheckStatus
  121. Desc: Ses static variables by looking which check boxes have been selected
  122. Params:
  123. IN HWND hDlg: The search dialog box
  124. Return:
  125. void
  126. Notes: The check boxes work in OR manner. So if we select all of them it means select fixes
  127. that have either of them
  128. --*/
  129. {
  130. //
  131. // Do we want to search for entries with Apphelp?
  132. //
  133. s_bAppHelp = (IsDlgButtonChecked(hDlg, IDC_CHKAPP) == BST_CHECKED) ? TRUE : FALSE;
  134. //
  135. // Do we want to search for entries with shims, flags or patches?
  136. //
  137. s_bShims = (IsDlgButtonChecked(hDlg, IDC_CHKSHI) == BST_CHECKED) ? TRUE : FALSE;
  138. //
  139. // Do we want to search for entries with layers?
  140. //
  141. s_bLayers = (IsDlgButtonChecked(hDlg, IDC_CHKLAY) == BST_CHECKED) ? TRUE : FALSE;
  142. }
  143. void
  144. StopSearch(
  145. void
  146. )
  147. /*++
  148. StopSearch
  149. Desc: Enables/Disables the various buttons and does other stuff that has to
  150. be done after the search has stopped because it was complete or the user
  151. pressed Stop button
  152. Notes: Does not actually stop the search, but performs the necessary actions after
  153. search has been stopped
  154. --*/
  155. {
  156. HWND hwndList = NULL;
  157. if (g_hSearchThread) {
  158. CloseHandle(g_hSearchThread);
  159. g_hSearchThread = NULL;
  160. }
  161. KillTimer(g_hSearchDlg, 0);
  162. Animate_Stop(GetDlgItem(g_hSearchDlg, IDC_ANIMATE));
  163. SetCurrentDirectory(g_szPresentDir);
  164. EnableWindow(GetDlgItem(g_hSearchDlg, IDC_STOP), FALSE);
  165. EnableWindow(GetDlgItem(g_hSearchDlg, IDC_SEARCH), TRUE);
  166. EnableWindow(GetDlgItem(g_hSearchDlg, IDC_NEWSEARCH), TRUE);
  167. EnableWindow(GetDlgItem(g_hSearchDlg, IDC_SAVE), TRUE);
  168. EnableWindow(GetDlgItem(g_hSearchDlg, IDC_CHKAPP), TRUE);
  169. EnableWindow(GetDlgItem(g_hSearchDlg, IDC_CHKLAY), TRUE);
  170. EnableWindow(GetDlgItem(g_hSearchDlg, IDC_CHKSHI), TRUE);
  171. hwndList = GetDlgItem(g_hSearchDlg, IDC_LIST);
  172. //
  173. // We need to enable the static control if we have found some results in search
  174. //
  175. EnableWindow(GetDlgItem(g_hSearchDlg, IDC_STATIC_CAPTION),
  176. ListView_GetItemCount(hwndList) > 0);
  177. SetActiveWindow(g_hdlgSearchDB);
  178. SetFocus(g_hdlgSearchDB);
  179. }
  180. void
  181. HandleSearchSizing(
  182. IN HWND hDlg
  183. )
  184. /*++
  185. HandleSearchSizing
  186. Desc: Handles WM_SIZE for the search dialog
  187. Paras:
  188. IN HWND hDlg: The search dialog
  189. Return:
  190. void
  191. --*/
  192. {
  193. int nWidth;
  194. int nHeight;
  195. int nStatusbarTop;
  196. RECT rDlg;
  197. if (g_cWidthSrch == 0 || g_cHeightSrch == 0) {
  198. return;
  199. }
  200. GetWindowRect(hDlg, &rDlg);
  201. nWidth = rDlg.right - rDlg.left;
  202. nHeight = rDlg.bottom - rDlg.top;
  203. int deltaW = nWidth - g_cWidthSrch;
  204. int deltaH = nHeight - g_cHeightSrch;
  205. HWND hwnd;
  206. RECT r;
  207. HDWP hdwp = BeginDeferWindowPos(10);
  208. if (hdwp == NULL) {
  209. //
  210. // NULL indicates that insufficient system resources are available to
  211. // allocate the structure. To get extended error information, call GetLastError.
  212. //
  213. assert(FALSE);
  214. goto End;
  215. }
  216. //
  217. // The status bar
  218. //
  219. hwnd = GetDlgItem(hDlg, IDC_STATUSBAR);
  220. GetWindowRect(hwnd, &r);
  221. MapWindowPoints(NULL, hDlg, (LPPOINT)&r, 2);
  222. DeferWindowPos(hdwp,
  223. hwnd,
  224. NULL,
  225. r.left,
  226. nStatusbarTop = r.top + deltaH,
  227. r.right - r.left + deltaW,
  228. r.bottom - r.top + deltaH,
  229. SWP_NOZORDER | SWP_NOACTIVATE);
  230. //
  231. // The result list view
  232. //
  233. hwnd = GetDlgItem(hDlg, IDC_LIST);
  234. GetWindowRect(hwnd, &r);
  235. MapWindowPoints(NULL, hDlg, (LPPOINT)&r, 2);
  236. DeferWindowPos(hdwp,
  237. hwnd,
  238. NULL,
  239. r.left,
  240. r.top,
  241. r.right - r.left + deltaW,
  242. nStatusbarTop - r.top,
  243. SWP_NOZORDER | SWP_NOACTIVATE);
  244. //
  245. // The browse button
  246. //
  247. hwnd = GetDlgItem(hDlg, IDC_BROWSE);
  248. GetWindowRect(hwnd, &r);
  249. MapWindowPoints(NULL, hDlg, (LPPOINT)&r, 2);
  250. DeferWindowPos(hdwp,
  251. hwnd,
  252. NULL,
  253. r.left + deltaW,
  254. r.top,
  255. r.right - r.left,
  256. r.bottom - r.top,
  257. SWP_NOZORDER | SWP_NOACTIVATE);
  258. //
  259. // The search button
  260. //
  261. hwnd = GetDlgItem(hDlg, IDC_SEARCH);
  262. GetWindowRect(hwnd, &r);
  263. MapWindowPoints(NULL, hDlg, (LPPOINT)&r, 2);
  264. DeferWindowPos(hdwp,
  265. hwnd,
  266. NULL,
  267. r.left + deltaW,
  268. r.top,
  269. r.right - r.left,
  270. r.bottom - r.top,
  271. SWP_NOZORDER | SWP_NOACTIVATE);
  272. //
  273. // The save button. Used to export results to a tab separated text file
  274. //
  275. hwnd = GetDlgItem(hDlg, IDC_SAVE);
  276. GetWindowRect(hwnd, &r);
  277. MapWindowPoints(NULL, hDlg, (LPPOINT)&r, 2);
  278. DeferWindowPos(hdwp,
  279. hwnd,
  280. NULL,
  281. r.left + deltaW,
  282. r.top,
  283. r.right - r.left,
  284. r.bottom - r.top,
  285. SWP_NOZORDER | SWP_NOACTIVATE);
  286. //
  287. // The stop button
  288. //
  289. hwnd = GetDlgItem(hDlg, IDC_STOP);
  290. GetWindowRect(hwnd, &r);
  291. MapWindowPoints(NULL, hDlg, (LPPOINT)&r, 2);
  292. DeferWindowPos(hdwp,
  293. hwnd,
  294. NULL,
  295. r.left + deltaW,
  296. r.top,
  297. r.right - r.left,
  298. r.bottom - r.top,
  299. SWP_NOZORDER | SWP_NOACTIVATE);
  300. //
  301. // The new search button
  302. //
  303. hwnd = GetDlgItem(hDlg, IDC_NEWSEARCH);
  304. GetWindowRect(hwnd, &r);
  305. MapWindowPoints(NULL, hDlg, (LPPOINT)&r, 2);
  306. DeferWindowPos(hdwp,
  307. hwnd,
  308. NULL,
  309. r.left + deltaW,
  310. r.top,
  311. r.right - r.left,
  312. r.bottom - r.top,
  313. SWP_NOZORDER | SWP_NOACTIVATE);
  314. //
  315. // The help button
  316. //
  317. hwnd = GetDlgItem(hDlg, IDC_SEARCH_HELP);
  318. GetWindowRect(hwnd, &r);
  319. MapWindowPoints(NULL, hDlg, (LPPOINT)&r, 2);
  320. DeferWindowPos(hdwp,
  321. hwnd,
  322. NULL,
  323. r.left + deltaW,
  324. r.top,
  325. r.right - r.left,
  326. r.bottom - r.top,
  327. SWP_NOZORDER | SWP_NOACTIVATE);
  328. //
  329. // The animate control
  330. //
  331. hwnd = GetDlgItem(hDlg, IDC_ANIMATE);
  332. GetWindowRect(hwnd, &r);
  333. MapWindowPoints(NULL, hDlg, (LPPOINT)&r, 2);
  334. DeferWindowPos(hdwp,
  335. hwnd,
  336. NULL,
  337. r.left + deltaW,
  338. r.top,
  339. r.right - r.left,
  340. r.bottom - r.top,
  341. SWP_NOZORDER | SWP_NOACTIVATE);
  342. //
  343. // The text box
  344. //
  345. hwnd = GetDlgItem(hDlg, IDC_PATH);
  346. GetWindowRect(hwnd, &r);
  347. MapWindowPoints(NULL, hDlg, (LPPOINT)&r, 2);
  348. DeferWindowPos(hdwp,
  349. hwnd,
  350. NULL,
  351. r.left,
  352. r.top,
  353. r.right - r.left + deltaW,
  354. r.bottom - r.top,
  355. SWP_NOZORDER | SWP_NOACTIVATE);
  356. //
  357. // The group control
  358. //
  359. hwnd = GetDlgItem(hDlg, IDC_GROUP);
  360. GetWindowRect(hwnd, &r);
  361. MapWindowPoints(NULL, hDlg, (LPPOINT)&r, 2);
  362. DeferWindowPos(hdwp,
  363. hwnd,
  364. NULL,
  365. r.left,
  366. r.top,
  367. r.right - r.left + deltaW,
  368. r.bottom - r.top,
  369. SWP_NOZORDER | SWP_NOACTIVATE);
  370. EndDeferWindowPos(hdwp);
  371. ListView_SetColumnWidth(g_hwndSearchList, TOT_COLS - 1, LVSCW_AUTOSIZE_USEHEADER);
  372. g_cWidthSrch = nWidth;
  373. g_cHeightSrch = nHeight;
  374. End:
  375. return;
  376. }
  377. INT_PTR
  378. HandleTextChange(
  379. IN HWND hdlg,
  380. IN WPARAM wParam
  381. )
  382. /*++
  383. HandleTextChange
  384. Desc: Handles the WM_COMMAND messages for the text box
  385. Params:
  386. IN HWND hdlg: The handle to the query dilaog box
  387. IN WPARAM wParam: The wParam that comes with WM_COMMAND
  388. Return:
  389. TRUE: If we process this message
  390. FALSE: Otherwise
  391. --*/
  392. {
  393. TCHAR szText[MAX_PATH];
  394. DWORD dwFlags;
  395. BOOL bEnable;
  396. INT_PTR ipReturn = FALSE;
  397. switch (HIWORD(wParam)) {
  398. case EN_CHANGE:
  399. //
  400. // We disable the search button if there is no path that we can search on//
  401. //
  402. *szText = 0;
  403. GetDlgItemText(hdlg, IDC_PATH, szText, ARRAYSIZE(szText));
  404. bEnable = ValidInput(szText);
  405. //
  406. // If we have some text in the text field, enable the search button, otherwise
  407. // disable it
  408. //
  409. EnableWindow(GetDlgItem(hdlg, IDC_SEARCH), bEnable);
  410. ipReturn = TRUE;
  411. break;
  412. default: ipReturn = FALSE;
  413. }
  414. return ipReturn;
  415. }
  416. INT_PTR CALLBACK
  417. SearchDialog(
  418. IN HWND hDlg,
  419. IN UINT uMsg,
  420. IN WPARAM wParam,
  421. IN LPARAM lParam
  422. )
  423. /*++
  424. SearchDialog
  425. Desc: Dialog proc for the search dialog
  426. Paras: Standard dialog handler parameters
  427. IN HWND hDlg
  428. IN UINT uMsg
  429. IN WPARAM wParam
  430. IN LPARAM lParam
  431. Return: Standard dialog handler return
  432. --*/
  433. {
  434. switch (uMsg) {
  435. case WM_SIZE:
  436. if (wParam != SIZE_MINIMIZED) {
  437. HandleSearchSizing(hDlg);
  438. }
  439. break;
  440. case WM_GETMINMAXINFO:
  441. {
  442. MINMAXINFO* pmmi = (MINMAXINFO*)lParam;
  443. pmmi->ptMinTrackSize.x = 400;
  444. pmmi->ptMinTrackSize.y = 365;
  445. return 0;
  446. break;
  447. }
  448. case WM_INITDIALOG:
  449. OnSearchInitDialog(hDlg, lParam);
  450. break;
  451. case WM_DESTROY:
  452. {
  453. HIMAGELIST hImageList = ListView_GetImageList(g_hwndSearchList, LVSIL_SMALL);
  454. if (hImageList) {
  455. ImageList_Destroy(hImageList);
  456. }
  457. hImageList = ListView_GetImageList(g_hwndSearchList, LVSIL_NORMAL);
  458. if (hImageList) {
  459. ImageList_Destroy(hImageList);
  460. }
  461. g_hdlgSearchDB = NULL;
  462. if (g_pSearch) {
  463. delete g_pSearch;
  464. g_pSearch = NULL;
  465. }
  466. DeleteCriticalSection(&g_CritSect);
  467. //
  468. // Remove the list view contents and the items that are tied with it.
  469. //
  470. ClearResults(hDlg, TRUE);
  471. return 0;
  472. }
  473. case WM_USER_NEWMATCH:
  474. AddNewResult(lParam);
  475. break;
  476. case WM_USER_NEWFILE:
  477. {
  478. EnterCriticalSection(&g_CritSect);
  479. if (g_pSearch) {
  480. SetWindowText(g_pSearch->m_hStatusBar , (LPTSTR)lParam);
  481. }
  482. if (lParam) {
  483. delete[] ((TCHAR*)lParam);
  484. }
  485. LeaveCriticalSection(&g_CritSect);
  486. break;
  487. }
  488. case WM_CONTEXTMENU:
  489. ShowContextMenu(wParam, lParam);
  490. break;
  491. case WM_NOTIFY:
  492. {
  493. LPNMHDR lpnmhdr = (LPNMHDR)lParam;
  494. if (lpnmhdr && lpnmhdr->idFrom == IDC_LIST) {
  495. return HandleSearchListNotification(hDlg, lParam);
  496. }
  497. return FALSE;
  498. }
  499. case WM_TIMER:
  500. if (g_hSearchThread) {
  501. if (WAIT_OBJECT_0 == WaitForSingleObject(g_hSearchThread, 0)) {
  502. StopSearch();
  503. K_SIZE k_size = 260;
  504. TCHAR* pszString = new TCHAR[k_size];
  505. if (pszString == NULL) {
  506. MEM_ERR;
  507. break;
  508. }
  509. SafeCpyN(pszString, CSTRING(IDS_SEARCHCOMPLETE), k_size);
  510. SendNotifyMessage(g_hSearchDlg, WM_USER_NEWFILE, 0,(LPARAM)pszString);
  511. }
  512. }
  513. break;
  514. case WM_COMMAND:
  515. switch (LOWORD(wParam)) {
  516. case IDC_STOP:
  517. g_bAbort = TRUE;
  518. break;
  519. case IDC_BROWSE:
  520. OnBrowse(hDlg);
  521. break;
  522. case IDC_SEARCH:
  523. DoSearch(hDlg);
  524. break;
  525. case IDC_NEWSEARCH:
  526. ClearResults(hDlg, TRUE);
  527. break;
  528. case IDC_SAVE:
  529. SaveResults(hDlg);
  530. break;
  531. case IDC_PATH:
  532. HandleTextChange(hDlg, wParam);
  533. break;
  534. case IDC_SEARCH_HELP:
  535. ShowInlineHelp(TEXT("searching_for_fixes.htm"));
  536. break;
  537. case IDCANCEL:
  538. {
  539. Animate_Close(GetDlgItem(hDlg, IDC_ANIMATE));
  540. g_bAbort = TRUE;
  541. if (g_hSearchThread) {
  542. WaitForSingleObject(g_hSearchThread, INFINITE);
  543. }
  544. DestroyWindow(hDlg);
  545. break;
  546. }
  547. case ID_VIEWCONTENTS:
  548. {
  549. LVITEM lvi;
  550. PMATCHEDENTRY pmMatched;
  551. INT iSelection;
  552. iSelection = ListView_GetSelectionMark(g_hwndSearchList);
  553. if (iSelection == -1) {
  554. break;
  555. }
  556. ZeroMemory(&lvi, sizeof(lvi));
  557. lvi.iItem = iSelection;
  558. lvi.iSubItem = 0;
  559. lvi.mask = LVIF_PARAM;
  560. if (ListView_GetItem(g_hwndSearchList, &lvi)) {
  561. pmMatched = (PMATCHEDENTRY)lvi.lParam;
  562. GotoEntry(pmMatched);
  563. }
  564. break;
  565. }
  566. default:
  567. return FALSE;
  568. }
  569. break;
  570. default:
  571. return FALSE;
  572. }
  573. return TRUE;
  574. }
  575. DWORD WINAPI
  576. SearchThread(
  577. IN LPVOID pVoid
  578. )
  579. /*++
  580. SearchThread
  581. Desc: The thread routine that does the actual search
  582. Params:
  583. IN LPVOID pVoid: Pointer to the search string. We get it trimmed
  584. Return:
  585. 0
  586. --*/
  587. {
  588. LPTSTR szSearch = (LPTSTR)pVoid;
  589. PTCHAR pchFirstSlash = NULL;
  590. DWORD dwReturn;
  591. //
  592. // Separate the extension and the directory
  593. //
  594. TCHAR szDrive[_MAX_DRIVE], szDir[MAX_PATH], szFile[MAX_PATH * 2] , szExt[MAX_PATH], szDirWithDrive[MAX_PATH * 2];
  595. *szDirWithDrive = *szDrive = *szDir = *szFile = *szExt = 0;
  596. _tsplitpath(szSearch, szDrive, szDir, szFile, szExt);
  597. SafeCpyN(szDirWithDrive, szDrive, ARRAYSIZE(szDirWithDrive));
  598. StringCchCat(szDirWithDrive, ARRAYSIZE(szDirWithDrive), szDir);
  599. if (lstrlen(szDirWithDrive) == 0) {
  600. //
  601. // Only the file name is there, check in the current drive
  602. //
  603. *szDirWithDrive = 0;
  604. dwReturn = GetCurrentDirectory(MAX_PATH, szDirWithDrive);
  605. if (dwReturn > 0 && dwReturn < ARRAYSIZE(szDirWithDrive)) {
  606. pchFirstSlash = _tcschr(szDirWithDrive, TEXT('\\'));
  607. if (pchFirstSlash) {
  608. //
  609. // We will now get only the present drive in szDirWithDrive
  610. //
  611. *(++pchFirstSlash) = 0;
  612. }
  613. } else {
  614. //
  615. // Error condition.
  616. //
  617. Dbg(dlError, "[SearchThread]: Could not execute GetCurrentDirectory properly");
  618. goto End;
  619. }
  620. }
  621. StringCchCat(szFile, ARRAYSIZE(szFile), szExt);
  622. if (lstrlen(szFile) == 0) {
  623. SafeCpyN(szFile, TEXT("*.EXE"), ARRAYSIZE(szFile));
  624. }
  625. if (!SetCurrentDirectory(szDirWithDrive)) {
  626. MSGF(g_hdlgSearchDB,
  627. g_szAppName,
  628. MB_ICONINFORMATION,
  629. TEXT("\'%s\'-%s"),
  630. szDirWithDrive,
  631. GetString(IDS_PATHERROR));
  632. return 0;
  633. }
  634. SearchDirectory(szDirWithDrive, szFile);
  635. End:
  636. return 0;
  637. }
  638. void
  639. Search(
  640. IN HWND hDlg,
  641. IN LPCTSTR szSearch
  642. )
  643. /*++
  644. Search
  645. Desc: Creates the thread that will do the actual search
  646. Params:
  647. IN HWND hDlg: The search dialog
  648. IN LPCTSTR szSearch: The files to search
  649. Return:
  650. void
  651. --*/
  652. {
  653. DWORD dwID;
  654. Animate_Play(GetDlgItem(hDlg, IDC_ANIMATE), 0, -1, -1);
  655. g_hSearchThread = (HANDLE)_beginthreadex(NULL, 0, (PTHREAD_START)SearchThread, (PVOID)szSearch, 0, (unsigned int*)&dwID);
  656. }
  657. BOOL
  658. PopulateFromExes(
  659. IN LPTSTR szPath,
  660. IN TAGREF tagref
  661. )
  662. /*++
  663. PopulateFromExes
  664. Desc: For the file with path szPath, checks if it needs to be added to the results
  665. list view and if yes, then calls SendNotifyMessage() to add this to the results
  666. list view
  667. Params:
  668. IN LPTSTR szPath: The path of the file found
  669. IN TAGREF tagref: TAGREF for the entry. The TAGREF incorporates the TAGID and a
  670. constant that tells us which PDB the TAGID is from.
  671. Return:
  672. --*/
  673. {
  674. BOOL bEntryHasAppHelp = FALSE;
  675. BOOL bEntryHasShims = FALSE;
  676. BOOL bEntryHasPatches = FALSE;
  677. BOOL bEntryHasFlags = FALSE;
  678. BOOL bEntryHasLayers = FALSE;
  679. TAGID ID; //TAGID for the entry
  680. PDB pDB; //The database pdb
  681. BOOL bOk = TRUE;
  682. PMATCHEDENTRY pmEntry = new MATCHEDENTRY;
  683. if (pmEntry == NULL) {
  684. MEM_ERR;
  685. return FALSE;
  686. }
  687. //
  688. // Get the database pdb and the tag id for this tagref of the entry. We need
  689. // these so that we can get the properties of this entry from the database in which
  690. // it resides
  691. //
  692. if (!SdbTagRefToTagID(g_hSDB, tagref, &pDB, &ID)) {
  693. bOk = FALSE;
  694. assert(FALSE);
  695. goto End;
  696. }
  697. //
  698. // Find out how this entry has been fixed. Get its app-name as well
  699. //
  700. if (pDB == NULL || !LookUpEntryProperties(pDB,
  701. ID,
  702. &bEntryHasLayers,
  703. &bEntryHasShims,
  704. &bEntryHasPatches,
  705. &bEntryHasFlags,
  706. &bEntryHasAppHelp,
  707. pmEntry->strAppName)) {
  708. assert(FALSE);
  709. bOk = FALSE;
  710. goto End;
  711. }
  712. pmEntry->tiExe = ID;
  713. pmEntry->strPath = szPath;
  714. switch (tagref & TAGREF_STRIP_PDB) {
  715. case PDB_MAIN:
  716. pmEntry->strDatabase = CSTRING(IDS_GLOBAL);
  717. break;
  718. case PDB_TEST:
  719. pmEntry->strDatabase = CSTRING(IDS_TEST);
  720. break;
  721. case PDB_LOCAL:
  722. pmEntry->strDatabase = CSTRING(IDS_LOCAL);
  723. break;
  724. default:
  725. pmEntry->strDatabase = CSTRING(IDS_LOCAL);
  726. break;
  727. }
  728. if (!GetDbGuid(pmEntry->szGuid, ARRAYSIZE(pmEntry->szGuid), pDB)) {
  729. assert(FALSE);
  730. bOk = FALSE;
  731. goto End;
  732. }
  733. BOOL bShow = FALSE;
  734. if (bEntryHasAppHelp && s_bAppHelp) {
  735. pmEntry->strAction.Strcat(CSTRING(IDS_APPHELPS));
  736. bShow = TRUE;
  737. }
  738. if ((bEntryHasShims || bEntryHasFlags || bEntryHasPatches) && s_bShims) {
  739. pmEntry->strAction.Strcat(CSTRING(IDS_FIXES));
  740. bShow = TRUE;
  741. }
  742. if (bEntryHasLayers && s_bLayers) {
  743. pmEntry->strAction.Strcat(CSTRING(IDS_MODES));
  744. bShow = TRUE;
  745. }
  746. int nLength = pmEntry->strAction.Length();
  747. if (nLength) {
  748. pmEntry->strAction.SetChar(nLength - 1, TEXT('\0'));
  749. }
  750. if (bShow) {
  751. SendNotifyMessage(g_hSearchDlg, WM_USER_NEWMATCH, 0, (LPARAM)pmEntry);
  752. }
  753. //
  754. // NOTE: the strings of pmEntry that are not used later are freed by the handler
  755. // of WM_USER_NEWMATCH, only the szGuid is retained
  756. // after the handler of WM_USER_NEWMATCH ends.
  757. // This is required so that we can double click on the list item.
  758. //
  759. // The pmEntry data-structure is deleted when the window gets destroyed
  760. //
  761. End:
  762. if (bOk == FALSE && pmEntry) {
  763. delete pmEntry;
  764. }
  765. return bOk;
  766. }
  767. void
  768. SearchDirectory(
  769. IN LPTSTR pszDir,
  770. IN LPTSTR szExtension
  771. )
  772. /*++
  773. SearchDirectory
  774. Desc: Searches a directory recursively for fixed files with a specified extension.
  775. Wild cards are allowed
  776. Params:
  777. IN LPTSTR pszDir: The directory to search in. This may or may not have a ending \
  778. IN LPTSTR szExtension: The extensions to look for
  779. Return:
  780. void
  781. Note: If pszDir is a drive should have a \ at the end
  782. --*/
  783. {
  784. HANDLE hFile;
  785. WIN32_FIND_DATA Data;
  786. TCHAR szCurrentDir[MAX_PATH_BUFFSIZE];
  787. BOOL bAbort = FALSE;
  788. TCHAR* pszString = NULL;
  789. INT iLength = 0;
  790. DWORD dwReturn = 0;
  791. *szCurrentDir = 0;
  792. dwReturn = GetCurrentDirectory(ARRAYSIZE(szCurrentDir), szCurrentDir);
  793. if (dwReturn == 0 || dwReturn >= ARRAYSIZE(szCurrentDir)) {
  794. assert(FALSE);
  795. Dbg(dlError, "SearchDirectory GetCurrentDirectory Failed");
  796. return;
  797. }
  798. if (!SetCurrentDirectory(pszDir)) {
  799. //
  800. // We do not prompt here, because we might have encountered a directory that we
  801. // do not have rights to access. Typically, network paths.
  802. //
  803. return;
  804. }
  805. iLength = lstrlen(pszDir) + 1;
  806. pszString = new TCHAR[iLength];
  807. if (pszString == NULL) {
  808. MEM_ERR;
  809. return;
  810. }
  811. SafeCpyN(pszString, pszDir, iLength);
  812. SendNotifyMessage(g_hSearchDlg, WM_USER_NEWFILE, 0, (LPARAM)pszString);
  813. hFile = FindFirstFile(szExtension, &Data);
  814. if (hFile != INVALID_HANDLE_VALUE) {
  815. do {
  816. CSTRING szStr;
  817. szStr.Sprintf(TEXT("%s"), pszDir);
  818. if (*pszDir && TEXT('\\') != pszDir[lstrlen(pszDir) - 1]) {
  819. szStr.Strcat(TEXT("\\"));
  820. }
  821. szStr.Strcat(Data.cFileName);
  822. SDBQUERYRESULT Res;
  823. ZeroMemory(&Res, sizeof(SDBQUERYRESULT));
  824. //
  825. // Determine if this file is affected in any way.
  826. //
  827. if ((Data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
  828. if (SdbGetMatchingExe(g_hSDB,
  829. (LPCTSTR)szStr,
  830. NULL,
  831. NULL,
  832. SDBGMEF_IGNORE_ENVIRONMENT,
  833. &Res)) {
  834. //
  835. // At the moment we only look for exe entires. i.e. to say, we
  836. // do not catch programs fixed using the compat UI or the tab
  837. // we only show programs that have been fixed by installing some
  838. // custom database
  839. //
  840. for (int nExeLoop = 0; nExeLoop < SDB_MAX_EXES; ++nExeLoop) {
  841. if (Res.atrExes[nExeLoop]) {
  842. PopulateFromExes(szStr, Res.atrExes[nExeLoop]);
  843. }
  844. }
  845. }
  846. //
  847. // Close any local databases that might have been opened by SdbGetMatchingExe(...)
  848. //
  849. SdbReleaseMatchingExe(g_hSDB, Res.atrExes[0]);
  850. }
  851. bAbort = g_bAbort;
  852. } while (FindNextFile(hFile, &Data) && !bAbort);
  853. FindClose(hFile);
  854. }
  855. //
  856. // Now go through the sub-directories.
  857. //
  858. hFile = FindFirstFile(TEXT("*.*"), &Data);
  859. if (hFile != INVALID_HANDLE_VALUE) {
  860. do {
  861. if (Data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  862. BOOL bForbidden = FALSE;
  863. if (TEXT('.') == Data.cFileName[0]) {
  864. bForbidden = TRUE;
  865. }
  866. if (!bForbidden) {
  867. TCHAR szPath[MAX_PATH * 2];
  868. SafeCpyN(szPath, pszDir, MAX_PATH);
  869. ADD_PATH_SEPARATOR(szPath, ARRAYSIZE(szPath));
  870. StringCchCat(szPath, ARRAYSIZE(szPath), Data.cFileName);
  871. SearchDirectory(szPath, szExtension);
  872. }
  873. }
  874. bAbort = g_bAbort;
  875. } while (FindNextFile(hFile, &Data) && !bAbort);
  876. FindClose(hFile);
  877. }
  878. SetCurrentDirectory(szCurrentDir);
  879. }
  880. void
  881. CSearch::Begin(
  882. void
  883. )
  884. /*++
  885. CSearch::Begin
  886. Desc: Begins the search
  887. --*/
  888. {
  889. if (g_hSDB == NULL) {
  890. g_hSDB = SdbInitDatabase(0, NULL);
  891. }
  892. g_pSearch = this;
  893. InitializeCriticalSection(&g_CritSect);
  894. HWND hwnd = CreateDialog(g_hInstance,
  895. MAKEINTRESOURCE(IDD_SEARCH),
  896. GetDesktopWindow(),
  897. SearchDialog);
  898. ShowWindow(hwnd, SW_NORMAL);
  899. return;
  900. }
  901. void
  902. GotoEntry(
  903. IN PMATCHEDENTRY pmMatched
  904. )
  905. /*++
  906. GotoEntry
  907. Desc: Selects the entry with tagid of pmMatched->tiExe in the entry tree.
  908. Params:
  909. IN PMATCHEDENTRY pmMatched: Contains information about the entry that we want to
  910. show in the contents pane(RHS) and the database pane(LHS) in the main window
  911. Return:
  912. void
  913. --*/
  914. {
  915. if (g_bSomeWizardActive) {
  916. //
  917. // We do not want that the focus should go to some other database, because
  918. // some wizard is active, which believes that he is modal.
  919. //
  920. MessageBox(g_hdlgSearchDB, GetString(IDS_SOMEWIZARDACTIVE), g_szAppName, MB_ICONINFORMATION);
  921. return;
  922. }
  923. if (pmMatched == NULL) {
  924. assert(FALSE);
  925. return;
  926. }
  927. BOOL bMainSDB = FALSE;
  928. WCHAR wszShimDB[MAX_PATH];
  929. *wszShimDB = 0;
  930. if (pmMatched == NULL) {
  931. return;
  932. }
  933. PDATABASE pDatabase = NULL;
  934. if (lstrcmp(GlobalDataBase.szGUID, pmMatched->szGuid) == 0) {
  935. //
  936. // This is the global database
  937. //
  938. pDatabase = &GlobalDataBase;
  939. bMainSDB = TRUE;
  940. if (!g_bMainAppExpanded) {
  941. SetStatus(GetDlgItem(g_hSearchDlg, IDC_STATUSBAR), IDS_LOADINGMAIN);
  942. SetCursor(LoadCursor(NULL, IDC_WAIT));
  943. INT iResult = ShowMainEntries(g_hdlgSearchDB);
  944. if (iResult == -1) {
  945. SetStatus(GetDlgItem(g_hdlgSearchDB, IDC_STATUSBAR), CSTRING(IDS_LOADINGMAIN));
  946. SetCursor(LoadCursor(NULL, IDC_WAIT));
  947. return;
  948. } else {
  949. SetCursor(LoadCursor(NULL, IDC_ARROW));
  950. }
  951. SetStatus(GetDlgItem(g_hSearchDlg, IDC_STATUSBAR), TEXT(""));
  952. }
  953. } else {
  954. //
  955. // We have to now search for the database in the installed databases list
  956. //
  957. PDATABASE pDatabaseInstalled = InstalledDataBaseList.pDataBaseHead;
  958. while (pDatabaseInstalled) {
  959. if (lstrcmpi(pmMatched->szGuid, pDatabaseInstalled->szGUID) == 0) {
  960. pDatabase = pDatabaseInstalled;
  961. break;
  962. }
  963. pDatabaseInstalled = pDatabaseInstalled->pNext;
  964. }
  965. if (pDatabaseInstalled == NULL) {
  966. //
  967. // We might come here if the database was uninstalled after we populated
  968. // the search results
  969. //
  970. MessageBox(g_hSearchDlg, GetString(IDS_NOLONGEREXISTS), g_szAppName, MB_ICONWARNING);
  971. return;
  972. }
  973. }
  974. //
  975. // Now for this database, search the particular entry
  976. //
  977. PDBENTRY pApp = pDatabase->pEntries, pEntry;
  978. pEntry = pApp;
  979. while (pApp) {
  980. pEntry = pApp;
  981. while (pEntry) {
  982. if (pEntry->tiExe == pmMatched->tiExe) {
  983. goto EndLoop;
  984. }
  985. pEntry = pEntry->pSameAppExe;
  986. }
  987. pApp = pApp->pNext;
  988. }
  989. if (pApp == NULL) {
  990. MessageBox(g_hSearchDlg, GetString(IDS_NOLONGEREXISTS), g_szAppName, MB_ICONWARNING);
  991. return;
  992. }
  993. EndLoop:
  994. //
  995. // Select the app in the DB tree
  996. //
  997. HTREEITEM hItemEntry = DBTree.FindChild(pDatabase->hItemAllApps, (LPARAM)pApp);
  998. assert(hItemEntry);
  999. TreeView_SelectItem(DBTree.m_hLibraryTree, hItemEntry);
  1000. //
  1001. // Now select the entry within the app in the entry tree
  1002. //
  1003. hItemEntry = CTree::FindChild(g_hwndEntryTree, TVI_ROOT, (LPARAM)pEntry);
  1004. assert(hItemEntry);
  1005. if (hItemEntry) {
  1006. TreeView_SelectItem(g_hwndEntryTree, hItemEntry);
  1007. SetFocus(g_hwndEntryTree);
  1008. }
  1009. }
  1010. BOOL
  1011. HandleSearchListNotification(
  1012. IN HWND hdlg,
  1013. IN LPARAM lParam
  1014. )
  1015. /*++
  1016. HandleSearchListNotification
  1017. Desc: Handles the notification messages for the Search List
  1018. Params:
  1019. IN HWND hdlg: The search dialog
  1020. IN LPARAM lParam: The LPARAM of WM_NOTIFY
  1021. Return:
  1022. TRUE: If the message was handled by this routine.
  1023. FALSE: Otherwise
  1024. --*/
  1025. {
  1026. LPNMHDR pnm = (LPNMHDR)lParam;
  1027. HWND hwndList = GetDlgItem(hdlg, IDC_LIST);
  1028. switch (pnm->code) {
  1029. case NM_DBLCLK:
  1030. SendMessage(hdlg, WM_COMMAND, (WPARAM)ID_VIEWCONTENTS, 0);
  1031. break;
  1032. case LVN_COLUMNCLICK:
  1033. {
  1034. LPNMLISTVIEW pnmlv = (LPNMLISTVIEW)lParam;
  1035. COLSORT colSort;
  1036. colSort.hwndList = hwndList;
  1037. colSort.iCol = pnmlv->iSubItem;
  1038. colSort.lSortColMask = s_lColumnSort;
  1039. ListView_SortItemsEx(hwndList, CompareItemsEx, &colSort);
  1040. if ((s_lColumnSort & 1L << colSort.iCol) == 0) {
  1041. //
  1042. // Was in ascending order
  1043. //
  1044. s_lColumnSort |= (1L << colSort.iCol);
  1045. } else {
  1046. s_lColumnSort &= (~(1L << colSort.iCol));
  1047. }
  1048. break;
  1049. }
  1050. default: return FALSE;
  1051. }
  1052. return TRUE;
  1053. }
  1054. void
  1055. ClearResults(
  1056. IN HWND hdlg,
  1057. IN BOOL bClearSearchPath
  1058. )
  1059. /*++
  1060. ClearResults
  1061. Desc: Clears the contents of the list view and the text box
  1062. Params:
  1063. IN HWND hdlg: The search dialog
  1064. IN BOOL bClearSearchPath: Do we wish to clear the contents of the text field also
  1065. --*/
  1066. {
  1067. HWND hwndList = GetDlgItem(hdlg, IDC_LIST);
  1068. INT iCount = ListView_GetItemCount(hwndList);
  1069. LVITEM lvi;
  1070. ZeroMemory(&lvi, sizeof(lvi));
  1071. //
  1072. // Free the lParam for the list view.
  1073. //
  1074. CleanUpListView(hdlg);
  1075. SendMessage(hwndList, WM_SETREDRAW, FALSE, 0);
  1076. ListView_DeleteAllItems(hwndList);
  1077. SendMessage(hwndList, WM_SETREDRAW, TRUE, 0);
  1078. InvalidateRect(hwndList, NULL, TRUE);
  1079. UpdateWindow(hwndList);
  1080. if (bClearSearchPath) {
  1081. SetDlgItemText(hdlg, IDC_PATH, TEXT(""));
  1082. }
  1083. }
  1084. void
  1085. SaveResults(
  1086. IN HWND hdlg
  1087. )
  1088. /*++
  1089. SaveResults
  1090. Desc: Saves the search results in a tab separated file
  1091. Params:
  1092. IN HWND hdlg: The search dialog
  1093. --*/
  1094. {
  1095. CSTRING strFileName;
  1096. TCHAR szTitle[256], szFilter[128], szExt[8];
  1097. *szTitle = *szFilter = *szExt = 0;
  1098. BOOL bResult = GetFileName(hdlg,
  1099. GetString(IDS_SAVE_RESULTS_TITLE, szTitle, ARRAYSIZE(szTitle)),
  1100. GetString(IDS_SAVE_RESULTS_FILTER, szFilter, ARRAYSIZE(szFilter)),
  1101. TEXT(""),
  1102. GetString(IDS_SAVE_RESULTS_EXT, szExt, ARRAYSIZE(szExt)),
  1103. OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT,
  1104. FALSE,
  1105. strFileName,
  1106. TRUE);
  1107. if (bResult) {
  1108. SetCursor(LoadCursor(NULL, IDC_WAIT));
  1109. SaveListViewToFile(GetDlgItem(hdlg, IDC_LIST), TOT_COLS, strFileName.pszString, NULL);
  1110. SetCursor(LoadCursor(NULL, IDC_ARROW));
  1111. }
  1112. }
  1113. void
  1114. CleanUpListView(
  1115. IN HWND hdlg
  1116. )
  1117. /*++
  1118. CleanUpListView
  1119. Desc: Frees the structures associated with the lParam of the list view
  1120. Params:
  1121. IN HWND hdlg: The search dialog
  1122. ******************************************************************************
  1123. Warn: This method should not be directky called. Call ClearResults instead
  1124. ******************************************************************************
  1125. --*/
  1126. {
  1127. HWND hwndList = GetDlgItem(hdlg, IDC_LIST);
  1128. INT iCount = ListView_GetItemCount(hwndList);
  1129. LVITEM lvi;
  1130. ZeroMemory(&lvi, sizeof(lvi));
  1131. //
  1132. // Free the lParam for the list view.
  1133. //
  1134. for (INT iIndex = 0; iIndex < iCount; ++iIndex) {
  1135. lvi.mask = LVIF_PARAM;
  1136. lvi.iItem = iIndex;
  1137. lvi.iSubItem = 0;
  1138. if (ListView_GetItem(hwndList, &lvi) && lvi.lParam) {
  1139. delete (PMATCHEDENTRY)lvi.lParam;
  1140. } else {
  1141. assert(FALSE);
  1142. }
  1143. }
  1144. }
  1145. void
  1146. OnSearchInitDialog(
  1147. IN HWND hDlg,
  1148. IN LPARAM lParam
  1149. )
  1150. /*++
  1151. OnSearchInitDialog
  1152. Desc: Handles WM_INITDIALOG for the search dialog box
  1153. Params:
  1154. IN HWND hDlg: The search dialog box
  1155. IN LPARAM lParam: The lParam for WM_INITDIALOG
  1156. Return:
  1157. void
  1158. --*/
  1159. {
  1160. //
  1161. // Limit the length of the path text field
  1162. //
  1163. SendMessage(GetDlgItem(hDlg, IDC_PATH),
  1164. EM_LIMITTEXT,
  1165. (WPARAM)MAX_PATH - 1,
  1166. (LPARAM)0);
  1167. g_hdlgSearchDB = hDlg;
  1168. s_lColumnSort = 0;
  1169. Animate_OpenEx(GetDlgItem(hDlg, IDC_ANIMATE),
  1170. g_hInstance,
  1171. MAKEINTRESOURCE(IDA_SEARCH));
  1172. //
  1173. // Set all the buttons
  1174. //
  1175. CheckDlgButton(hDlg, IDC_CHKLAY, BST_CHECKED);
  1176. CheckDlgButton(hDlg, IDC_CHKSHI, BST_CHECKED);
  1177. CheckDlgButton(hDlg, IDC_CHKAPP, BST_CHECKED);
  1178. EnableWindow(GetDlgItem(hDlg, IDC_STOP), FALSE);
  1179. g_pSearch->m_hStatusBar = GetDlgItem(hDlg, IDC_STATUSBAR);
  1180. CSearch* pPresentSearch = (CSearch*)lParam;
  1181. g_hSearchDlg = hDlg;
  1182. g_hwndSearchList = GetDlgItem(hDlg, IDC_LIST);
  1183. ListView_SetExtendedListViewStyleEx(g_hwndSearchList,
  1184. 0,
  1185. LVS_EX_LABELTIP | LVS_EX_FULLROWSELECT);
  1186. //
  1187. // Add the columns that we are going to show in the list view
  1188. //
  1189. //
  1190. // Name of the fixed program file
  1191. //
  1192. InsertColumnIntoListView(g_hwndSearchList,
  1193. GetString(IDS_AFFECTED_FILE),
  1194. SEARCH_COL_AFFECTEDFILE,
  1195. 20);
  1196. //
  1197. // Path of the fixed program file
  1198. //
  1199. InsertColumnIntoListView(g_hwndSearchList,
  1200. GetString(IDS_PATH),
  1201. SEARCH_COL_PATH,
  1202. 30);
  1203. //
  1204. // App-Name of the fixed program file
  1205. //
  1206. InsertColumnIntoListView(g_hwndSearchList,
  1207. GetString(IDS_APP),
  1208. SEARCH_COL_APP,
  1209. 20);
  1210. //
  1211. // Action type. This column will show a concatenated string specifying
  1212. // whether fixes, layers and/or apphelp is used for this entry
  1213. //
  1214. InsertColumnIntoListView(g_hwndSearchList,
  1215. GetString(IDS_ACTION),
  1216. SEARCH_COL_ACTION,
  1217. 15);
  1218. //
  1219. // The database type of the database where the entry resides. One of Global or Local
  1220. //
  1221. InsertColumnIntoListView(g_hwndSearchList,
  1222. GetString(IDS_DATABASE),
  1223. SEARCH_COL_DBTYPE,
  1224. 15);
  1225. ListView_SetColumnWidth(g_hwndSearchList, TOT_COLS - 1, LVSCW_AUTOSIZE_USEHEADER);
  1226. RECT r;
  1227. GetWindowRect(hDlg, &r);
  1228. g_cWidthSrch = r.right - r.left;
  1229. g_cHeightSrch = r.bottom - r.top;
  1230. SHAutoComplete(GetDlgItem(hDlg, IDC_PATH), AUTOCOMPLETE);
  1231. if (*s_szPrevPath) {
  1232. //
  1233. // The user has invoked the search dialog previously, let us
  1234. // now show the directory/path that he searched for previously
  1235. //
  1236. SetDlgItemText(hDlg, IDC_PATH, s_szPrevPath);
  1237. } else {
  1238. //
  1239. // This is the first time that the user is using this search option.
  1240. // Default to the programs folder
  1241. //
  1242. LPITEMIDLIST lpIDL = NULL;
  1243. if (SUCCEEDED(SHGetFolderLocation(NULL,
  1244. CSIDL_PROGRAM_FILES,
  1245. NULL,
  1246. 0,
  1247. &lpIDL))) {
  1248. if (lpIDL == NULL) {
  1249. return;
  1250. }
  1251. if (SHGetPathFromIDList(lpIDL, s_szPath)) {
  1252. ADD_PATH_SEPARATOR(s_szPath, ARRAYSIZE(s_szPath));
  1253. StringCchCat(s_szPath, ARRAYSIZE(s_szPath), TEXT("*.exe"));
  1254. SetDlgItemText(hDlg, IDC_PATH, s_szPath);
  1255. //
  1256. // Free the pidl
  1257. //
  1258. LPMALLOC lpMalloc = NULL;
  1259. if (SUCCEEDED(SHGetMalloc(&lpMalloc)) && lpMalloc) {
  1260. lpMalloc->Free(lpIDL);
  1261. } else {
  1262. assert(FALSE);
  1263. }
  1264. }
  1265. }
  1266. }
  1267. return;
  1268. }
  1269. void
  1270. DoSearch(
  1271. IN HWND hDlg
  1272. )
  1273. /*++
  1274. DoSearch
  1275. Desc: Handle the pressing of the search button.
  1276. Params:
  1277. IN HWND hDlg: The search dialog box
  1278. Return:
  1279. void
  1280. --*/
  1281. {
  1282. if (hDlg == NULL) {
  1283. ASSERT(FALSE);
  1284. return;
  1285. }
  1286. DWORD dwReturn = 0;
  1287. HWND hwndList = GetDlgItem(hDlg, IDC_LIST);
  1288. if (GetFocus() == hwndList
  1289. && ListView_GetNextItem(hwndList, -1, LVNI_SELECTED) != -1) {
  1290. //
  1291. // We will get this message when we press enter in the list box,
  1292. // as IDC_SEARCH is the default button.
  1293. // So in this case we have to pretend as the user double clicked in the list
  1294. // view
  1295. //
  1296. SendNotifyMessage(hDlg, WM_COMMAND, (WPARAM)ID_VIEWCONTENTS , 0);
  1297. return;
  1298. }
  1299. //
  1300. // We need to get rid of the drop down list for the AUTOCOMPLETE text field.
  1301. //
  1302. SetFocus(GetDlgItem(hDlg, IDC_SEARCH));
  1303. SendMessage(GetDlgItem(hDlg, IDC_SEARCH),
  1304. WM_NEXTDLGCTL,
  1305. (WPARAM)TRUE,
  1306. (LPARAM)GetDlgItem(hDlg, IDC_SEARCH));
  1307. FlushCache();
  1308. GetCheckStatus(hDlg);
  1309. *s_szPath = 0;
  1310. *s_szPrevPath = 0;
  1311. GetDlgItemText(hDlg, IDC_PATH, s_szPath, ARRAYSIZE(s_szPath));
  1312. CSTRING::Trim(s_szPath);
  1313. SafeCpyN(s_szPrevPath, s_szPath, ARRAYSIZE(s_szPrevPath));
  1314. g_nIndex = 0;
  1315. //
  1316. // Clear the list view but do not remove the contents of the text field
  1317. //
  1318. ClearResults(hDlg, FALSE);
  1319. SetTimer(hDlg, 0, 100, NULL);
  1320. EnableWindow(GetDlgItem(hDlg, IDC_STOP), TRUE);
  1321. EnableWindow(GetDlgItem(hDlg, IDC_SEARCH), FALSE);
  1322. EnableWindow(GetDlgItem(hDlg, IDC_NEWSEARCH), FALSE);
  1323. EnableWindow(GetDlgItem(hDlg, IDC_SAVE), FALSE);
  1324. EnableWindow(GetDlgItem(hDlg, IDC_STATIC_CAPTION), FALSE);
  1325. EnableWindow(GetDlgItem(hDlg, IDC_CHKAPP), FALSE);
  1326. EnableWindow(GetDlgItem(hDlg, IDC_CHKLAY), FALSE);
  1327. EnableWindow(GetDlgItem(hDlg, IDC_CHKSHI), FALSE);
  1328. g_bAbort = FALSE;
  1329. *g_szPresentDir = 0;
  1330. dwReturn = GetCurrentDirectory(ARRAYSIZE(g_szPresentDir), g_szPresentDir);
  1331. if (dwReturn == 0 || dwReturn >= ARRAYSIZE(g_szPresentDir)) {
  1332. assert(FALSE);
  1333. Dbg(dlError, "DoSearch GetCurrentDirectory failed");
  1334. }
  1335. Search(hDlg, s_szPath);
  1336. }
  1337. BOOL
  1338. AddNewResult(
  1339. IN LPARAM lParam
  1340. )
  1341. /*++
  1342. AddNewResult
  1343. Desc: We found a new file that matches out search criteria, lets now add this
  1344. to the list view. This is the handler for WM_USER_NEWMATCH
  1345. Params:
  1346. IN LPARAM lParam: The lParam that comes with WM_USER_NEWMATCH. This is
  1347. a pointer to a MATCHEDENTRY
  1348. Notes: Please note that this routine will also free some members of MATCHEDENTRY that
  1349. we do not need except to populate the list view
  1350. Return:
  1351. TRUE: If we added the result fields in the list view
  1352. FALSE: Otherwise
  1353. --*/
  1354. {
  1355. PMATCHEDENTRY pmEntry = (PMATCHEDENTRY)lParam;
  1356. CSTRING strExeName;
  1357. int iImage;
  1358. HICON hIcon;
  1359. HIMAGELIST himl;
  1360. HIMAGELIST himlSm;
  1361. LVITEM lvi;
  1362. if (pmEntry == NULL) {
  1363. assert(FALSE);
  1364. return FALSE;
  1365. }
  1366. EnterCriticalSection(&g_CritSect);
  1367. strExeName = pmEntry->strPath;
  1368. strExeName.ShortFilename();
  1369. himl = ListView_GetImageList(g_hwndSearchList, LVSIL_NORMAL);
  1370. if (!himl) {
  1371. himl = ImageList_Create(16, 15, ILC_COLOR32 | ILC_MASK, 10, 1);
  1372. if (!himl) {
  1373. return FALSE;
  1374. }
  1375. hIcon = LoadIcon(0, MAKEINTRESOURCE(IDI_APPLICATION));
  1376. ImageList_AddIcon(himl, hIcon);
  1377. ListView_SetImageList(g_hwndSearchList, himl, LVSIL_NORMAL);
  1378. }
  1379. himlSm = ListView_GetImageList(g_hwndSearchList, LVSIL_SMALL);
  1380. if (!himlSm) {
  1381. himlSm = ImageList_Create(GetSystemMetrics(SM_CXSMICON),
  1382. GetSystemMetrics(SM_CYSMICON), ILC_COLOR | ILC_MASK, 0, 0);
  1383. if (!himlSm) {
  1384. return FALSE;
  1385. }
  1386. hIcon = LoadIcon(0, MAKEINTRESOURCE(IDI_APPLICATION));
  1387. ImageList_AddIcon(himlSm, hIcon);
  1388. ListView_SetImageList(g_hwndSearchList, himlSm, LVSIL_SMALL);
  1389. }
  1390. //
  1391. // Get the icon for the file
  1392. //
  1393. hIcon = ExtractIcon(g_hInstance, pmEntry->strPath, 0);
  1394. if (!hIcon) {
  1395. iImage = 0;
  1396. } else {
  1397. iImage = ImageList_AddIcon(himl, hIcon);
  1398. if (iImage == -1) {
  1399. iImage = 0;
  1400. }
  1401. int iImageSm = ImageList_AddIcon(himlSm, hIcon);
  1402. assert(iImage == iImageSm);
  1403. DestroyIcon(hIcon);
  1404. }
  1405. ZeroMemory(&lvi, sizeof(lvi));
  1406. lvi.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
  1407. lvi.pszText = strExeName;
  1408. lvi.iItem = g_nIndex;
  1409. lvi.iSubItem = SEARCH_COL_AFFECTEDFILE;
  1410. lvi.iImage = iImage;
  1411. lvi.lParam = (LPARAM)pmEntry;
  1412. INT iIndex = ListView_InsertItem(g_hwndSearchList, &lvi);
  1413. //
  1414. // Set the various result fields in the list view
  1415. //
  1416. ListView_SetItemText(g_hwndSearchList, iIndex, SEARCH_COL_PATH, pmEntry->strPath);
  1417. ListView_SetItemText(g_hwndSearchList, iIndex, SEARCH_COL_APP, pmEntry->strAppName);
  1418. ListView_SetItemText(g_hwndSearchList, iIndex, SEARCH_COL_ACTION, pmEntry->strAction);
  1419. ListView_SetItemText(g_hwndSearchList, iIndex, SEARCH_COL_DBTYPE, pmEntry->strDatabase);
  1420. //
  1421. // Remove the strings that are no longer going to be used.
  1422. // Keep the dbguid, this will be used for matching when we double click.
  1423. //
  1424. pmEntry->strAction.Release();
  1425. pmEntry->strDatabase.Release();
  1426. pmEntry->strPath.Release();
  1427. //
  1428. // Increment the index where we want to put in the next result
  1429. //
  1430. g_nIndex++;
  1431. LeaveCriticalSection(&g_CritSect);
  1432. return TRUE;
  1433. }
  1434. void
  1435. OnBrowse(
  1436. IN HWND hDlg
  1437. )
  1438. /*++
  1439. OnBrowse
  1440. Desc: Handles the pressing of the browse button
  1441. Params:
  1442. IN HWND hdlg: The handle to the search dialog
  1443. Return:
  1444. void
  1445. --*/
  1446. {
  1447. BROWSEINFO brInfo;
  1448. TCHAR szDir[MAX_PATH * 2] = TEXT("");
  1449. brInfo.hwndOwner = g_hwndSearchList;
  1450. brInfo.pidlRoot = NULL;
  1451. brInfo.pszDisplayName = szDir;
  1452. brInfo.lpszTitle = GetString(IDS_SELECTDIR);
  1453. brInfo.ulFlags = BIF_STATUSTEXT | BIF_RETURNONLYFSDIRS;
  1454. brInfo.lpfn = NULL;
  1455. brInfo.lParam = NULL;
  1456. LPITEMIDLIST lpIDL = SHBrowseForFolder(&brInfo);
  1457. *szDir = 0;
  1458. if (lpIDL == NULL) {
  1459. //
  1460. // The user pressed cancel
  1461. //
  1462. return;
  1463. }
  1464. //
  1465. // Get the actual path from the pidl and free it
  1466. //
  1467. if (SHGetPathFromIDList(lpIDL, szDir)) {
  1468. ADD_PATH_SEPARATOR(szDir, ARRAYSIZE(szDir));
  1469. StringCchCat(szDir, ARRAYSIZE(szDir), TEXT("*.exe"));
  1470. SetDlgItemText(hDlg, IDC_PATH, szDir);
  1471. //
  1472. // Free the pidl
  1473. //
  1474. LPMALLOC lpMalloc;
  1475. if (SUCCEEDED(SHGetMalloc(&lpMalloc))) {
  1476. lpMalloc->Free(lpIDL);
  1477. } else {
  1478. assert(FALSE);
  1479. }
  1480. } else {
  1481. assert(FALSE);
  1482. }
  1483. }
  1484. void
  1485. ShowContextMenu(
  1486. IN WPARAM wParam,
  1487. IN LPARAM lParam
  1488. )
  1489. /*++
  1490. ShowContextMenu
  1491. Desc: Shows the context menu. Handles WM_CONTEXTMENU
  1492. Params:
  1493. IN WPARAM wParam: The wParam that comes with WM_CONTEXTMENU.
  1494. Return:
  1495. --*/
  1496. {
  1497. HWND hWnd = (HWND)wParam;
  1498. if (hWnd == g_hwndSearchList) {
  1499. int iSelection = ListView_GetSelectionMark(g_hwndSearchList);
  1500. if (iSelection == -1) {
  1501. return;
  1502. }
  1503. LVITEM lvi = {0};
  1504. PMATCHEDENTRY pmMatched = NULL;
  1505. lvi.iItem = iSelection;
  1506. lvi.iSubItem = 0;
  1507. lvi.mask = LVIF_PARAM;
  1508. if (!ListView_GetItem(g_hwndSearchList, &lvi)) {
  1509. return;
  1510. }
  1511. pmMatched = (PMATCHEDENTRY)lvi.lParam;
  1512. if (pmMatched == NULL) {
  1513. assert(FALSE);
  1514. return;
  1515. }
  1516. UINT uX = LOWORD(lParam);
  1517. UINT uY = HIWORD(lParam);
  1518. HMENU hMenu = LoadMenu(g_hInstance, MAKEINTRESOURCE(IDR_CONTEXT));
  1519. HMENU hContext;
  1520. //
  1521. // Get the context menu for search
  1522. //
  1523. hContext = GetSubMenu(hMenu, 3);
  1524. if (hContext == NULL) {
  1525. goto End;
  1526. }
  1527. TrackPopupMenuEx(hContext,
  1528. TPM_LEFTALIGN | TPM_TOPALIGN,
  1529. uX,
  1530. uY,
  1531. g_hSearchDlg,
  1532. NULL);
  1533. End:
  1534. if (hMenu) {
  1535. DestroyMenu(hMenu);
  1536. hMenu = NULL;
  1537. }
  1538. }
  1539. }