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.

1607 lines
46 KiB

  1. // AppSearch
  2. //
  3. // Tool for searching a user's hard drives and locating
  4. // applications that can be patched
  5. //
  6. // Author: t-michkr (9 June 2000)
  7. //
  8. // AppSearch.cpp
  9. // User-interface
  10. // We make use of some Win2K/IE5 common controls
  11. #include <windows.h>
  12. #include <commctrl.h>
  13. #include <comdef.h>
  14. #include <shlwapi.h>
  15. #include <shlobj.h>
  16. #include <shellapi.h>
  17. #include <assert.h>
  18. #include "main.h"
  19. #include "searchdb.h"
  20. #include "filebrowser.h"
  21. #include "resource.h"
  22. // Compare data, used for sorting listview items.
  23. struct SCompareParam
  24. {
  25. HWND hwList;
  26. int iSubItem;
  27. };
  28. // Size of some static controls
  29. const int c_nStaticLineHeight = 2;
  30. const int c_nResultFrameWidth = 2;
  31. // Minimum height of the result window
  32. const int c_nResultListHeight = 201;
  33. // ID's of controls we create ourselves
  34. const int c_iStaticLineID = 50;
  35. const int c_iResultListID = 51;
  36. const int c_iResultFrameID = 52;
  37. const int c_iStatusBarID = 53;
  38. const int c_iFindAnimID = 54;
  39. // Positions of menu items (these will be needed to be changed
  40. // if the menu is altered)
  41. const int c_iViewMenuPos = 2;
  42. const int c_iArrangeIconsPos = 5;
  43. // List view column info
  44. const int c_nListColumnWidth = 250;
  45. const int c_nNumListColumns = 2;
  46. const int c_iListColumnNameIDS[c_nNumListColumns] = {
  47. IDS_LISTNAME, IDS_LISTPATH};
  48. // Number of children that need to be adjusted on resize
  49. const int c_nChildren = 6;
  50. // ID's of children that need to be adjusted on resize
  51. int g_aiChildrenIDs[c_nChildren] = {IDC_BROWSE, IDC_FINDNOW, IDC_STOP, IDC_CLEARALL,
  52. IDC_DRIVELIST, c_iFindAnimID};
  53. // Margins of those children, determined from dialog box in HandleInitDialog().
  54. int g_aiChildrenMargins[c_nChildren];
  55. // Minimum window width and window height, determined from dialog box
  56. // in HandleInitDialog().
  57. int g_nMinWindowWidth;
  58. int g_nWindowHeight;
  59. // Whether or not the user is browsing through menus, used for displaying
  60. // menu help text.
  61. BOOL g_fInMenu = FALSE;
  62. // Instance of this app.
  63. HINSTANCE g_hinst = 0;
  64. // Original window proc for the list view control.
  65. WNDPROC pfnLVOrgWndProc = 0;
  66. // Subclassed window proc for list view, intercepts WM_PAINT messages
  67. // and writes "No items in view" if empty.
  68. LRESULT CALLBACK LVWndProc(HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam);
  69. // Dialog proc for main application dialog.
  70. BOOL CALLBACK DialogProc(HWND hwndDlg, UINT uiMsg, WPARAM wParam, LPARAM lParam);
  71. // Display shimming information for specified exe.
  72. void ShowShimInfo(HWND hwnd, TCHAR* szAppPath);
  73. // Returns an allocated string with resource ID id, or 0 on failure.
  74. TCHAR* LoadStringResource(UINT id);
  75. // Print an error box with message in string resource uiMsg.
  76. void Error(HWND hwnd, UINT uiMsg);
  77. // Compare entries in the listview, used for sorting.
  78. int CALLBACK CompareListEntries(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
  79. // Start searching the AppCompat database.
  80. void StartSearch(HWND hwnd);
  81. // Terminate the current search, does nothing if no search is active.
  82. void StopSearch(HWND hwnd);
  83. // Remove all results shown
  84. void ClearResults(HWND hwnd);
  85. // Update the status bar with the new message.
  86. void UpdateStatus(HWND hwnd, PTSTR szMsg);
  87. // Add a new app to the list
  88. void AddApp(SMatchedExe* pme, HWND hwList);
  89. // Message Handlers.
  90. BOOL HandleInitDialog(HWND hwnd);
  91. void HandleBrowse(HWND hwnd);
  92. void HandleCommand(HWND hwnd, int iCtrlID, HWND hwChild);
  93. void HandleEnterMenuLoop(HWND hwnd);
  94. void HandleExitMenuLoop(HWND hwnd);
  95. void HandleGetMinMaxInfo(HWND hwnd, LPMINMAXINFO pmmi);
  96. void HandleMenuSelect(HWND hwnd, HMENU hMenu, UINT uiMenuID, UINT uiFlags);
  97. void HandleNotify(HWND hwnd, int iCtrlID, void* pvArg);
  98. void HandleSearchAddApp(HWND hwnd);
  99. void HandleSearchUpdate(HWND hwnd, PTSTR szMsg);
  100. void HandleSize(HWND hwnd, int iWidth, int iHeight);
  101. void HandleSizing(HWND hwnd, int iEdge, LPRECT pRect);
  102. // Program entry point.
  103. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, PSTR, int)
  104. {
  105. // Save our global instance handle.
  106. g_hinst = hInstance;
  107. // Make sure the common controls DLL is loaded.
  108. INITCOMMONCONTROLSEX icc;
  109. icc.dwSize = sizeof(icc);
  110. // We use the list view, status bar, tree control, animate,
  111. // tooltip, and comboboxex classes
  112. icc.dwICC = ICC_USEREX_CLASSES | ICC_LISTVIEW_CLASSES | ICC_BAR_CLASSES
  113. | ICC_TREEVIEW_CLASSES | ICC_ANIMATE_CLASS | ICC_TAB_CLASSES ;
  114. if(InitCommonControlsEx(&icc) == FALSE)
  115. return 0;
  116. // Run the actual dialog for the application
  117. return DialogBox(g_hinst, MAKEINTRESOURCE(IDD_MAINDIALOG),
  118. 0, DialogProc);
  119. }
  120. // Dialog proc for main dialog.
  121. BOOL CALLBACK DialogProc(HWND hwndDlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
  122. {
  123. switch(uiMsg)
  124. {
  125. // Do basic initialization, return FALSE means do not continue
  126. // creating the window.
  127. case WM_INITDIALOG:
  128. return HandleInitDialog(hwndDlg);
  129. break;
  130. // Control sizing, to maintain a minimum dialog size.
  131. case WM_SIZE:
  132. HandleSize(hwndDlg, LOWORD(lParam), HIWORD(lParam));
  133. break;
  134. // Control sizing, to maintain a minimum dialog box size.
  135. case WM_SIZING:
  136. HandleSizing(hwndDlg, wParam, reinterpret_cast<LPRECT>(lParam));
  137. break;
  138. // Control maximizing, to maintain dialog size.
  139. case WM_GETMINMAXINFO:
  140. HandleGetMinMaxInfo(hwndDlg, reinterpret_cast<LPMINMAXINFO>(lParam));
  141. break;
  142. // Handle child control messages
  143. case WM_COMMAND:
  144. HandleCommand(hwndDlg, LOWORD(wParam), reinterpret_cast<HWND>(lParam));
  145. break;
  146. // Handle notifications from child controls
  147. case WM_NOTIFY:
  148. HandleNotify(hwndDlg, static_cast<int>(wParam),
  149. reinterpret_cast<void*>(lParam));
  150. break;
  151. // Print help messages when user goes over a menu item.
  152. case WM_MENUSELECT:
  153. HandleMenuSelect(hwndDlg, reinterpret_cast<HMENU>(lParam),
  154. LOWORD(wParam), HIWORD(wParam));
  155. break;
  156. // Note when user starts browsing through a menu.
  157. case WM_ENTERMENULOOP:
  158. HandleEnterMenuLoop(hwndDlg);
  159. break;
  160. // Note when user exits a menu.
  161. case WM_EXITMENULOOP:
  162. HandleExitMenuLoop(hwndDlg);
  163. break;
  164. // Search thread just found another app.
  165. case WM_SEARCHDB_ADDAPP:
  166. HandleSearchAddApp(hwndDlg);
  167. break;
  168. // Search thread is looking through a new directory
  169. case WM_SEARCHDB_UPDATE:
  170. HandleSearchUpdate(hwndDlg, reinterpret_cast<PTSTR>(lParam));
  171. break;
  172. // Search thread is complete.
  173. case WM_SEARCHDB_DONE:
  174. // Cleanup any leftover apps (just in case this message
  175. // is received before WM_SEARCHDB_ADDAPP)
  176. HandleSearchAddApp(hwndDlg);
  177. // Terminate search
  178. StopSearch(hwndDlg);
  179. break;
  180. // User wants to close this dialog
  181. case WM_CLOSE:
  182. // Terminate search
  183. StopSearch(hwndDlg);
  184. EndDialog(hwndDlg, TRUE);
  185. break;
  186. default:
  187. return FALSE;
  188. }
  189. return TRUE;
  190. }
  191. // Do basic dialog box initialization.
  192. BOOL HandleInitDialog(HWND hwnd)
  193. {
  194. // Change the application icon
  195. HICON hIcon;
  196. hIcon = LoadIcon(g_hinst, MAKEINTRESOURCE(IDI_APP));
  197. if(!hIcon)
  198. return FALSE;
  199. // For SetClassLongPtr(), a return value of zero may not be an
  200. // error, if the previous value was not set. Setting the
  201. // last error to 0 and checking for that value indicates
  202. // success.
  203. // BUGBUG
  204. // In Whistler, SetClassLongPtr returns an error, but still
  205. // sets the correct icon. No error is returned for Win2K.
  206. SetClassLongPtr(hwnd, GCLP_HICON, reinterpret_cast<LONG_PTR>(hIcon));
  207. SetClassLongPtr(hwnd, GCLP_HICONSM, reinterpret_cast<LONG_PTR>(hIcon));
  208. // Get minimum dimensions of dialog
  209. RECT rcWindow;
  210. if(!GetWindowRect(hwnd, &rcWindow))
  211. return FALSE;
  212. g_nMinWindowWidth = rcWindow.right - rcWindow.left;
  213. g_nWindowHeight = rcWindow.bottom - rcWindow.top;
  214. // Add a static line across the top (We can't put this in the resource template)
  215. RECT rectCl;
  216. if(!GetClientRect(hwnd, &rectCl))
  217. return FALSE;
  218. HWND hwStaticLine = CreateWindow(TEXT("static"),TEXT(""),
  219. SS_ETCHEDHORZ | WS_CHILD | WS_VISIBLE, rectCl.top, rectCl.left,
  220. rectCl.right - rectCl.left, c_nStaticLineHeight, hwnd,
  221. reinterpret_cast<HMENU>(c_iStaticLineID), g_hinst, 0);
  222. if(!hwStaticLine)
  223. return FALSE;
  224. // Fill the combobox.
  225. HWND hwComboBox = GetDlgItem(hwnd, IDC_DRIVELIST);
  226. if(!hwComboBox)
  227. return FALSE;
  228. SHFILEINFO sfi;
  229. HIMAGELIST himagelist = reinterpret_cast<HIMAGELIST>(SHGetFileInfo(TEXT("C:\\"), 0, &sfi, sizeof(sfi),
  230. SHGFI_SYSICONINDEX | SHGFI_SMALLICON));
  231. LRESULT lr = SendMessage(hwComboBox, CBEM_SETIMAGELIST, 0,
  232. reinterpret_cast<LPARAM>(himagelist));
  233. assert(lr == NULL);
  234. COMBOBOXEXITEM cbitem;
  235. ZeroMemory(&cbitem, sizeof(cbitem));
  236. cbitem.mask = CBEIF_TEXT | CBEIF_INDENT | CBEIF_IMAGE
  237. | CBEIF_SELECTEDIMAGE;
  238. cbitem.iItem = -1;
  239. cbitem.pszText = LoadStringResource(IDS_ALLDRIVES);
  240. if(!cbitem.pszText)
  241. return FALSE;
  242. cbitem.cchTextMax = lstrlen(cbitem.pszText) + 1;
  243. cbitem.iIndent = 0;
  244. LPITEMIDLIST pidl;
  245. SHGetFolderLocation(0, CSIDL_DRIVES, 0, 0, &pidl);
  246. SHGetFileInfo(reinterpret_cast<PTSTR>(pidl), 0, &sfi, sizeof(sfi),
  247. SHGFI_SYSICONINDEX | SHGFI_PIDL);
  248. cbitem.iImage = sfi.iIcon;
  249. cbitem.iSelectedImage = sfi.iIcon;
  250. if(SendMessage(hwComboBox, CBEM_INSERTITEM, 0,
  251. reinterpret_cast<LPARAM>(&cbitem)))
  252. {
  253. delete cbitem.pszText;
  254. return FALSE;
  255. }
  256. delete cbitem.pszText;
  257. LPMALLOC pMalloc;
  258. SHGetMalloc(&pMalloc);
  259. pMalloc->Free(pidl);
  260. pMalloc->Release();
  261. TCHAR* szDrives = 0;
  262. DWORD dwLen = GetLogicalDriveStrings(0, 0);
  263. if(dwLen != 0)
  264. {
  265. szDrives = new TCHAR[dwLen+1];
  266. if(!szDrives)
  267. {
  268. Error(hwnd, IDS_NOMEMSTOPPROG);
  269. return FALSE;
  270. }
  271. }
  272. else
  273. return FALSE;
  274. if(!GetLogicalDriveStrings(dwLen, szDrives))
  275. {
  276. delete szDrives;
  277. return FALSE;
  278. }
  279. TCHAR* szCurrDrive = szDrives;
  280. while(*szCurrDrive)
  281. {
  282. if(GetDriveType(szCurrDrive)==DRIVE_FIXED)
  283. {
  284. SHGetFileInfo(szCurrDrive, 0, &sfi, sizeof(sfi), SHGFI_SYSICONINDEX);
  285. cbitem.pszText = szCurrDrive;
  286. cbitem.cchTextMax = lstrlen(cbitem.pszText) + 1;
  287. cbitem.iIndent = 1;
  288. cbitem.iImage = sfi.iIcon;
  289. cbitem.iSelectedImage = sfi.iIcon;
  290. SendMessage(hwComboBox, CBEM_INSERTITEM, 0,
  291. reinterpret_cast<LPARAM>(&cbitem));
  292. }
  293. szCurrDrive += lstrlen(szCurrDrive)+1;
  294. }
  295. delete szDrives;
  296. if(SendMessage(hwComboBox, CB_SETCURSEL, 0, 0)== -1)
  297. return FALSE;
  298. // Add the animation control.
  299. HWND hwChild;
  300. RECT rcChild;
  301. POINT pt;
  302. HWND hwAnim = Animate_Create(hwnd, c_iFindAnimID,
  303. WS_CHILD | ACS_CENTER | ACS_TRANSPARENT, g_hinst);
  304. hwChild = GetDlgItem(hwnd, IDC_ANIMSPACEHOLDER);
  305. GetWindowRect(hwChild, &rcChild);
  306. DestroyWindow(hwChild);
  307. pt.x = rcChild.left;
  308. pt.y = rcChild.top;
  309. ScreenToClient(hwnd, &pt);
  310. SetWindowPos(hwAnim, 0, pt.x, pt.y, rcChild.right-rcChild.left,
  311. rcChild.bottom - rcChild.top, SWP_NOZORDER);
  312. Animate_Open(hwAnim, MAKEINTRESOURCE(IDR_FINDAVI));
  313. ShowWindow(hwAnim, SW_SHOW);
  314. // Get margins of all child window controls
  315. pt.x = 0;
  316. pt.y = 0;
  317. for(int i = 0; i < c_nChildren; i++)
  318. {
  319. hwChild = GetDlgItem(hwnd, g_aiChildrenIDs[i]);
  320. if(!hwChild)
  321. return FALSE;
  322. if(!GetWindowRect(hwChild, &rcChild))
  323. return FALSE;
  324. pt.x = rcChild.right;
  325. if(!ScreenToClient(hwnd, &pt))
  326. return FALSE;
  327. g_aiChildrenMargins[i] = rectCl.right - pt.x;
  328. }
  329. // Setup default checked state
  330. HMENU hMenu = GetMenu(hwnd);
  331. if(!hMenu)
  332. return FALSE;
  333. CheckMenuRadioItem(hMenu, ID_VIEW_LARGEICONS,
  334. ID_VIEW_ASDETAILS, ID_VIEW_ASDETAILS, MF_BYCOMMAND);
  335. if(InitSearchDB() == FALSE)
  336. return FALSE;
  337. return TRUE;
  338. }
  339. // Display a browse dialog box, so that the user can select
  340. // a specific path to search in.
  341. void HandleBrowse(HWND hwnd)
  342. {
  343. // Show the browse dialog box, and get user response.
  344. TCHAR* szPath = BrowseForFolder(hwnd, 0,
  345. BF_SELECTDIRECTORIES | BF_HARDDRIVES);
  346. // If they didn't select cancel . . .
  347. if(szPath)
  348. {
  349. HWND hwDirSelBox = GetDlgItem(hwnd, IDC_DRIVELIST);
  350. if(!hwDirSelBox)
  351. {
  352. DestroyWindow(hwnd);
  353. return;
  354. }
  355. // For some reason, SHGetFileInfo doesn't work
  356. // properly if the drive isn't terminated with '\'
  357. if(szPath[lstrlen(szPath)-1] == TEXT(':'))
  358. lstrcat(szPath, TEXT("\\"));
  359. // Insert this item into the edit control of the combo box.
  360. SHFILEINFO sfi;
  361. COMBOBOXEXITEM cbim;
  362. cbim.mask = CBEIF_IMAGE | CBEIF_TEXT | CBEIF_SELECTEDIMAGE;
  363. cbim.iItem = -1;
  364. cbim.pszText = szPath;
  365. cbim.cchTextMax = lstrlen(szPath);
  366. SHGetFileInfo(szPath, 0, &sfi, sizeof(sfi),
  367. SHGFI_SYSICONINDEX);
  368. cbim.iImage = sfi.iIcon;
  369. cbim.iSelectedImage = sfi.iIcon;
  370. if(!SendMessage(hwDirSelBox, CBEM_SETITEM, 0,
  371. reinterpret_cast<LPARAM>(&cbim)))
  372. {
  373. DestroyWindow(hwnd);
  374. return;
  375. }
  376. // For some reason, the icon in the edit box isn't updated
  377. // unless the box is selected, loses focus, and then regains
  378. // focus, so do that here.
  379. if(!SetFocus(hwDirSelBox))
  380. {
  381. DestroyWindow(hwnd);
  382. return;
  383. }
  384. if(!SetFocus(GetDlgItem(hwnd, IDC_BROWSE)))
  385. {
  386. DestroyWindow(hwnd);
  387. return;
  388. }
  389. if(!SetFocus(hwDirSelBox))
  390. {
  391. DestroyWindow(hwnd);
  392. return;
  393. }
  394. }
  395. }
  396. // Handle a command from a child input control.
  397. void HandleCommand(HWND hwnd, int iCtrlID, HWND)
  398. {
  399. HMENU hMenu;
  400. HWND hwList;
  401. DWORD dwStyle, dwExStyle;
  402. SHELLEXECUTEINFO shExecInfo;
  403. SCompareParam cp;
  404. switch(iCtrlID)
  405. {
  406. // MENU COMMANDS
  407. case ID_APPSELECT_SHOWSHIMINFO:
  408. case ID_FILE_SHOWSHIMINFO:
  409. // Get list view control
  410. hwList = GetDlgItem(hwnd, c_iResultListID);
  411. if(hwList)
  412. {
  413. int nCount = ListView_GetItemCount(hwList);
  414. int i;
  415. // Loop through all items finding a selected one.
  416. for(i = 0; i < nCount; i++)
  417. {
  418. if(ListView_GetItemState(hwList, i, LVIS_SELECTED)
  419. & LVIS_SELECTED)
  420. break;
  421. }
  422. // None found, we're done.
  423. if(i == nCount)
  424. break;
  425. TCHAR szBuffer[c_nMaxStringLength];
  426. ListView_GetItemText(hwList, i, 1,
  427. szBuffer, c_nMaxStringLength);
  428. ShowShimInfo(hwnd, szBuffer);
  429. }
  430. break;
  431. // Use selected properties
  432. case ID_APPSELECT_PROPERTIES:
  433. case ID_FILE_PROPERTIES:
  434. // Get list view control
  435. hwList = GetDlgItem(hwnd, c_iResultListID);
  436. if(hwList)
  437. {
  438. int nCount = ListView_GetItemCount(hwList);
  439. int i;
  440. // Loop through all items finding a selected one.
  441. for(i = 0; i < nCount; i++)
  442. {
  443. if(ListView_GetItemState(hwList, i, LVIS_SELECTED)
  444. & LVIS_SELECTED)
  445. break;
  446. }
  447. // None found, we're done.
  448. if(i == nCount)
  449. break;
  450. TCHAR szBuffer[c_nMaxStringLength];
  451. ListView_GetItemText(hwList, i, 1,
  452. szBuffer, c_nMaxStringLength);
  453. ZeroMemory(&shExecInfo, sizeof(shExecInfo));
  454. shExecInfo.cbSize = sizeof(shExecInfo);
  455. shExecInfo.lpFile = szBuffer;
  456. shExecInfo.lpVerb = TEXT("properties");
  457. shExecInfo.fMask = SEE_MASK_INVOKEIDLIST;
  458. ShellExecuteEx(&shExecInfo);
  459. }
  460. break;
  461. case ID_FILE_EXIT:
  462. EndDialog(hwnd, TRUE);
  463. break;
  464. case ID_EDIT_SELECTALL:
  465. hwList = GetDlgItem(hwnd, c_iResultListID);
  466. if(hwList)
  467. {
  468. int nCount = ListView_GetItemCount(hwList);
  469. for(int i = 0; i < nCount; i++)
  470. ListView_SetItemState(hwList, i, LVIS_SELECTED, LVIS_SELECTED);
  471. }
  472. break;
  473. case ID_EDIT_INVERTSELECTION:
  474. hwList = GetDlgItem(hwnd, c_iResultListID);
  475. if(hwList)
  476. {
  477. int nCount = ListView_GetItemCount(hwList);
  478. for(int i = 0; i < nCount; i++)
  479. ListView_SetItemState(hwList, i,
  480. LVIS_SELECTED ^ ListView_GetItemState(hwList, i, LVIS_SELECTED),
  481. LVIS_SELECTED);
  482. }
  483. break;
  484. case ID_VIEW_LARGEICONS:
  485. case ID_VIEW_SMALLICONS:
  486. case ID_VIEW_ASLIST:
  487. case ID_VIEW_ASDETAILS:
  488. hMenu = GetMenu(hwnd);
  489. CheckMenuRadioItem(hMenu, ID_VIEW_LARGEICONS,
  490. ID_VIEW_ASDETAILS, iCtrlID, MF_BYCOMMAND);
  491. dwStyle = WS_CHILD | WS_VISIBLE | LVS_SHOWSELALWAYS;
  492. dwExStyle = LVS_EX_LABELTIP;
  493. switch(iCtrlID)
  494. {
  495. case ID_VIEW_LARGEICONS:
  496. dwStyle |= LVS_ICON;
  497. break;
  498. case ID_VIEW_SMALLICONS:
  499. dwStyle |= LVS_SMALLICON;
  500. break;
  501. case ID_VIEW_ASLIST:
  502. dwStyle |= LVS_LIST;
  503. break;
  504. case ID_VIEW_ASDETAILS:
  505. dwStyle |= LVS_REPORT;
  506. dwExStyle |= LVS_EX_FULLROWSELECT;
  507. break;
  508. }
  509. hwList = GetDlgItem(hwnd, c_iResultListID);
  510. if(hwList)
  511. {
  512. SetWindowLongPtr(hwList, GWL_STYLE, dwStyle);
  513. ListView_SetExtendedListViewStyleEx(hwList, 0, dwExStyle);
  514. }
  515. break;
  516. case ID_VIEW_ARRANGEICONS_BYNAME:
  517. hwList = GetDlgItem(hwnd, c_iResultListID);
  518. cp.hwList = hwList;
  519. cp.iSubItem = 0;
  520. if(hwList)
  521. ListView_SortItemsEx(hwList, CompareListEntries, &cp);
  522. break;
  523. case ID_VIEW_ARRANGEICONS_BYPATH:
  524. hwList = GetDlgItem(hwnd, c_iResultListID);
  525. cp.hwList = hwList;
  526. cp.iSubItem = 1;
  527. if(hwList)
  528. ListView_SortItemsEx(hwList, CompareListEntries, &cp);
  529. break;
  530. case ID_VIEW_CHOOSECOLUMNS:
  531. break;
  532. case ID_VIEW_REFRESH:
  533. StartSearch(hwnd);
  534. break;
  535. // PUSH BUTTON COMMANDS
  536. case IDC_BROWSE:
  537. HandleBrowse(hwnd);
  538. break;
  539. case IDC_FINDNOW:
  540. StartSearch(hwnd);
  541. break;
  542. case IDC_STOP:
  543. StopSearch(hwnd);
  544. break;
  545. case IDC_CLEARALL:
  546. ClearResults(hwnd);
  547. break;
  548. }
  549. }
  550. void HandleSize(HWND hwnd, int /*nWidth*/, int /*nHeight*/)
  551. {
  552. RECT rectCl;
  553. GetClientRect(hwnd, &rectCl);
  554. HWND hwStatic = GetDlgItem(hwnd, c_iStaticLineID);
  555. if(!hwStatic)
  556. {
  557. DestroyWindow(hwnd);
  558. return;
  559. }
  560. MoveWindow(hwStatic,rectCl.left, rectCl.top, rectCl.right-rectCl.left,
  561. c_nStaticLineHeight, TRUE);
  562. // Adjust list box and status bar at the bottom of the window
  563. HWND hwListBox, hwStatusBar, hwListFrame;
  564. hwListFrame = GetDlgItem(hwnd, c_iResultFrameID);
  565. hwListBox = GetDlgItem(hwnd, c_iResultListID);
  566. hwStatusBar= GetDlgItem(hwnd, c_iStatusBarID);
  567. assert(hwListBox == 0 ? !hwStatusBar && !hwListFrame : true);
  568. if(hwListBox && hwStatusBar && hwListFrame)
  569. {
  570. RECT rectWnd;
  571. GetWindowRect(hwnd, &rectWnd);
  572. POINT ptListTop;
  573. ptListTop.x = 0;
  574. ptListTop.y = rectWnd.top + g_nWindowHeight;
  575. ScreenToClient(hwnd, &ptListTop);
  576. RECT rectSB;
  577. GetClientRect(hwStatusBar, &rectSB);
  578. POINT ptStatusTop;
  579. ptStatusTop.x = 0;
  580. ptStatusTop.y = rectWnd.bottom - (rectSB.bottom - rectSB.top);
  581. ScreenToClient(hwnd, &ptStatusTop);
  582. MoveWindow(hwListFrame, rectCl.left, ptListTop.y, rectCl.right - rectCl.left,
  583. ptStatusTop.y - ptListTop.y, TRUE);
  584. MoveWindow(hwListBox, rectCl.left + c_nResultFrameWidth,
  585. ptListTop.y + c_nResultFrameWidth,
  586. rectCl.right - rectCl.left - 2 * c_nResultFrameWidth,
  587. ptStatusTop.y - ptListTop.y - 2 * c_nResultFrameWidth,
  588. TRUE);
  589. MoveWindow(hwStatusBar, rectCl.left, ptStatusTop.y,
  590. rectCl.right - rectCl.left, rectSB.bottom - rectSB.top, TRUE);
  591. }
  592. // Adjust all controls
  593. RECT rcChild;
  594. HWND hwChild;
  595. POINT ptTop;
  596. int iWidth, iHeight;
  597. for(int i = 0; i < c_nChildren; i++)
  598. {
  599. hwChild = GetDlgItem(hwnd, g_aiChildrenIDs[i]);
  600. if(!hwChild)
  601. {
  602. DestroyWindow(hwnd);
  603. return;
  604. }
  605. GetClientRect(hwChild, &rcChild);
  606. iWidth = rcChild.right - rcChild.left;
  607. iHeight = rcChild.bottom - rcChild.top;
  608. ptTop.x = rcChild.left;
  609. ptTop.y = rcChild.top;
  610. ClientToScreen(hwChild, &ptTop);
  611. ScreenToClient(hwnd, &ptTop);
  612. if(g_aiChildrenIDs[i] == IDC_DRIVELIST)
  613. iWidth = rectCl.right - g_aiChildrenMargins[i] - ptTop.x;
  614. if(g_aiChildrenIDs[i] == IDC_DRIVELIST)
  615. MoveWindow(hwChild, ptTop.x, ptTop.y, iWidth, iHeight, TRUE);
  616. else
  617. MoveWindow(hwChild, rectCl.right - g_aiChildrenMargins[i] - iWidth,
  618. ptTop.y, iWidth, iHeight, TRUE);
  619. }
  620. for(i = 0; i < c_nChildren; i++)
  621. InvalidateRect(GetDlgItem(hwnd, g_aiChildrenIDs[i]), 0, TRUE);
  622. }
  623. void HandleSizing(HWND hwnd, int iEdge, LPRECT pRect)
  624. {
  625. if((pRect->right - pRect->left) < g_nMinWindowWidth)
  626. {
  627. if(iEdge == WMSZ_BOTTOMLEFT || iEdge == WMSZ_LEFT
  628. || iEdge == WMSZ_TOPLEFT)
  629. {
  630. pRect->left = pRect->right - g_nMinWindowWidth;
  631. }
  632. else if(iEdge == WMSZ_BOTTOMRIGHT || iEdge == WMSZ_RIGHT
  633. || iEdge == WMSZ_TOPRIGHT)
  634. {
  635. pRect->right = pRect->left + g_nMinWindowWidth;
  636. }
  637. // Should never get here
  638. else
  639. {
  640. OutputDebugString(TEXT("Weird sizing stuff in HandleSizing\n"));
  641. }
  642. }
  643. if(GetDlgItem(hwnd, c_iResultListID))
  644. {
  645. HWND hwStatusBar = GetDlgItem(hwnd, c_iStatusBarID);
  646. RECT rectStatus;
  647. GetClientRect(hwStatusBar, &rectStatus);
  648. if((pRect->bottom - pRect->top) < (g_nWindowHeight +
  649. c_nResultListHeight))
  650. {
  651. if(iEdge == WMSZ_BOTTOM || iEdge == WMSZ_BOTTOMLEFT ||
  652. iEdge == WMSZ_BOTTOMRIGHT)
  653. {
  654. pRect->bottom = pRect->top + (g_nWindowHeight +
  655. c_nResultListHeight);
  656. }
  657. else if((iEdge == WMSZ_TOP) || (iEdge == WMSZ_TOPLEFT)
  658. || (iEdge == WMSZ_TOPRIGHT))
  659. {
  660. pRect->top = pRect->bottom - (g_nWindowHeight +
  661. c_nResultListHeight);
  662. }
  663. // Should never get here
  664. else
  665. {
  666. OutputDebugString(TEXT("Weird sizing stuff in HandleSizing\n"));
  667. }
  668. }
  669. }
  670. else
  671. {
  672. if((pRect->bottom - pRect->top) != g_nWindowHeight)
  673. {
  674. if(iEdge == WMSZ_BOTTOM || iEdge == WMSZ_BOTTOMLEFT ||
  675. iEdge == WMSZ_BOTTOMRIGHT)
  676. {
  677. pRect->bottom = pRect->top + g_nWindowHeight;
  678. }
  679. else if((iEdge == WMSZ_TOP) || (iEdge == WMSZ_TOPLEFT)
  680. || (iEdge == WMSZ_TOPRIGHT))
  681. {
  682. pRect->top = pRect->bottom - g_nWindowHeight;
  683. }
  684. // Should never get here
  685. else
  686. {
  687. OutputDebugString(TEXT("Weird sizing stuff in HandleSizing\n"));
  688. }
  689. }
  690. }
  691. }
  692. void HandleGetMinMaxInfo(HWND hwnd, LPMINMAXINFO pmmi)
  693. {
  694. // Maximize normally if we have the result list box
  695. if(GetDlgItem(hwnd, c_iResultListID))
  696. return;
  697. pmmi->ptMaxSize.y = g_nWindowHeight;
  698. }
  699. void HandleNotify(HWND hwnd, int iCtrlID, void* pvArg)
  700. {
  701. LPNMHDR pHdr = reinterpret_cast<LPNMHDR>(pvArg);
  702. LPNMLISTVIEW pnmlvItem = reinterpret_cast<LPNMLISTVIEW>(pvArg);
  703. HWND hwList;
  704. HMENU hMenu;
  705. switch(iCtrlID)
  706. {
  707. case c_iResultListID:
  708. hwList = GetDlgItem(hwnd, c_iResultListID);
  709. switch(pHdr->code)
  710. {
  711. case NM_RCLICK:
  712. // Check if the click is on any row
  713. if(pnmlvItem->iItem != -1)
  714. {
  715. // Create a context sensitive menu.
  716. HMENU hmContext = LoadMenu(g_hinst,
  717. MAKEINTRESOURCE(IDM_APPSELECT));
  718. hmContext = GetSubMenu(hmContext, 0);
  719. ClientToScreen(GetDlgItem(hwnd, c_iResultListID),
  720. &pnmlvItem->ptAction);
  721. TrackPopupMenuEx(hmContext, 0,
  722. pnmlvItem->ptAction.x,
  723. pnmlvItem->ptAction.y, hwnd, 0);
  724. }
  725. else
  726. {
  727. // FIXME
  728. // Create the shortcut menu
  729. }
  730. break;
  731. case LVN_ITEMCHANGED:
  732. hwList = GetDlgItem(hwnd, c_iResultListID);
  733. if(hwList)
  734. {
  735. int nCount = ListView_GetItemCount(hwList);
  736. int i;
  737. for(i = 0; i < nCount; i++)
  738. {
  739. if(ListView_GetItemState(hwList, i, LVIS_SELECTED)
  740. & LVIS_SELECTED)
  741. break;
  742. }
  743. hMenu = GetMenu(hwnd);
  744. if(i == nCount)
  745. {
  746. EnableMenuItem(hMenu, ID_FILE_SHOWSHIMINFO,
  747. MF_BYCOMMAND | MF_GRAYED);
  748. EnableMenuItem(hMenu, ID_FILE_PROPERTIES,
  749. MF_BYCOMMAND | MF_GRAYED);
  750. }
  751. else
  752. {
  753. EnableMenuItem(hMenu, ID_FILE_SHOWSHIMINFO,
  754. MF_BYCOMMAND | MF_ENABLED);
  755. EnableMenuItem(hMenu, ID_FILE_PROPERTIES,
  756. MF_BYCOMMAND | MF_ENABLED);
  757. }
  758. }
  759. break;
  760. }
  761. default:
  762. break;
  763. }
  764. }
  765. void HandleMenuSelect(HWND hwnd, HMENU hMenu, UINT uiMenuID, UINT uiFlags)
  766. {
  767. HWND hwStatusBar = GetDlgItem(hwnd,c_iStatusBarID);
  768. if(!hwStatusBar)
  769. return;
  770. TCHAR* szText = 0;
  771. if(uiFlags & MF_POPUP)
  772. {
  773. if(hMenu != GetMenu(hwnd))
  774. {
  775. // Not a top-level menu
  776. // Go through all lower-level submenus
  777. // Right now only submenu is Arrange Icons
  778. szText = LoadStringResource(IDS_VIEW_ARRANGEICONS);
  779. }
  780. }
  781. else
  782. {
  783. switch(uiMenuID)
  784. {
  785. case ID_FILE_SHOWSHIMINFO:
  786. szText = LoadStringResource(IDS_FILE_SHOWSHIM);
  787. break;
  788. case ID_FILE_DOWNLOADPATCH:
  789. szText = LoadStringResource(IDS_FILE_DOWNLOADPATCH);
  790. break;
  791. case ID_FILE_PROPERTIES:
  792. szText = LoadStringResource(IDS_FILE_PROPERTIES);
  793. break;
  794. case ID_FILE_SAVESEARCH:
  795. szText = LoadStringResource(IDS_FILE_SAVESEARCH);
  796. break;
  797. case ID_FILE_EXIT:
  798. szText = LoadStringResource(IDS_FILE_EXIT);
  799. break;
  800. case ID_EDIT_SELECTALL:
  801. szText = LoadStringResource(IDS_EDIT_SELECTALL);
  802. break;
  803. case ID_EDIT_INVERTSELECTION:
  804. szText = LoadStringResource(IDS_EDIT_INVERTSELECTION);
  805. break;
  806. case ID_VIEW_LARGEICONS:
  807. szText = LoadStringResource(IDS_VIEW_LARGEICONS);
  808. break;
  809. case ID_VIEW_SMALLICONS:
  810. szText = LoadStringResource(IDS_VIEW_SMALLICONS);
  811. break;
  812. case ID_VIEW_ASLIST:
  813. szText = LoadStringResource(IDS_VIEW_ASLIST);
  814. break;
  815. case ID_VIEW_ASDETAILS:
  816. szText = LoadStringResource(IDS_VIEW_ASDETAILS);
  817. break;
  818. case ID_VIEW_ARRANGEICONS_BYNAME:
  819. szText = LoadStringResource(IDS_VIEW_ARRANGEICONS_BYNAME);
  820. break;
  821. case ID_VIEW_ARRANGEICONS_BYPATH:
  822. szText = LoadStringResource(IDS_VIEW_ARRANGEICONS_BYPATH);
  823. break;
  824. case ID_VIEW_CHOOSECOLUMNS:
  825. szText = LoadStringResource(IDS_VIEW_CHOOSECOLUMNS);
  826. break;
  827. case ID_VIEW_REFRESH:
  828. szText = LoadStringResource(IDS_VIEW_REFRESH);
  829. break;
  830. case ID_HELP_HELPTOPICS:
  831. szText = LoadStringResource(IDS_HELP_HELPTOPICS);
  832. break;
  833. case ID_HELP_WHATSTHIS:
  834. szText = LoadStringResource(IDS_HELP_WHATSTHIS);
  835. break;
  836. }
  837. }
  838. if(szText)
  839. {
  840. SetWindowText(hwStatusBar, szText);
  841. delete szText;
  842. }
  843. else
  844. SetWindowText(hwStatusBar, TEXT(""));
  845. }
  846. void HandleEnterMenuLoop(HWND hwnd)
  847. {
  848. UpdateStatus(hwnd, TEXT(""));
  849. g_fInMenu = TRUE;
  850. }
  851. void HandleExitMenuLoop(HWND hwnd)
  852. {
  853. UpdateStatus(hwnd, LoadStringResource(IDS_SEARCHDONE));
  854. g_fInMenu = FALSE;
  855. }
  856. void HandleSearchAddApp(HWND hwnd)
  857. {
  858. HWND hwList = GetDlgItem(hwnd, c_iResultListID);
  859. if(!hwList)
  860. return;
  861. SMatchedExe* pme;
  862. while( (pme = GetMatchedExe()) != 0)
  863. AddApp(pme, hwList);
  864. delete pme;
  865. }
  866. void HandleSearchUpdate(HWND hwnd, PTSTR szMsg)
  867. {
  868. if(g_fInMenu == FALSE)
  869. UpdateStatus(hwnd, szMsg);
  870. delete szMsg;
  871. }
  872. int CALLBACK CompareListEntries(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
  873. {
  874. SCompareParam* pCompParam = reinterpret_cast<SCompareParam*>(lParamSort);
  875. TCHAR szBuffer1[c_nMaxStringLength];
  876. TCHAR szBuffer2[c_nMaxStringLength];
  877. ListView_GetItemText(pCompParam->hwList, lParam1, pCompParam->iSubItem,
  878. szBuffer1, c_nMaxStringLength);
  879. ListView_GetItemText(pCompParam->hwList, lParam2, pCompParam->iSubItem,
  880. szBuffer2, c_nMaxStringLength);
  881. return lstrcmp(szBuffer1, szBuffer2);
  882. }
  883. void UpdateStatus(HWND hwnd, PTSTR szMsg)
  884. {
  885. HWND hwStatus = GetDlgItem(hwnd, c_iStatusBarID);
  886. if(!hwStatus)
  887. return;
  888. SetWindowText(hwStatus, szMsg);
  889. }
  890. void AddApp(SMatchedExe* pme, HWND hwList)
  891. {
  892. int iItem, iImage;
  893. HICON hIcon;
  894. HIMAGELIST himl = ListView_GetImageList(hwList, LVSIL_NORMAL);
  895. if(!himl)
  896. {
  897. himl = ImageList_Create(GetSystemMetrics(SM_CXICON),
  898. GetSystemMetrics(SM_CYICON), ILC_COLOR | ILC_MASK, 0, 0);
  899. if(!himl)
  900. {
  901. DestroyWindow(GetParent(hwList));
  902. return;
  903. }
  904. hIcon = LoadIcon(0, MAKEINTRESOURCE(IDI_APPLICATION));
  905. ImageList_AddIcon(himl, hIcon);
  906. ListView_SetImageList(hwList, himl, LVSIL_NORMAL);
  907. }
  908. HIMAGELIST himlSm = ListView_GetImageList(hwList, LVSIL_SMALL);
  909. if(!himlSm)
  910. {
  911. himlSm = ImageList_Create(GetSystemMetrics(SM_CXSMICON),
  912. GetSystemMetrics(SM_CYSMICON), ILC_COLOR | ILC_MASK, 0, 0);
  913. if(!himlSm)
  914. {
  915. DestroyWindow(GetParent(hwList));
  916. return;
  917. }
  918. hIcon = LoadIcon(0, MAKEINTRESOURCE(IDI_APPLICATION));
  919. ImageList_AddIcon(himlSm, hIcon);
  920. ListView_SetImageList(hwList, himlSm, LVSIL_SMALL);
  921. }
  922. hIcon = ExtractIcon(g_hinst, pme->szPath, 0);
  923. if(!hIcon)
  924. {
  925. iImage = 0;
  926. }
  927. else
  928. {
  929. iImage = ImageList_AddIcon(himl, hIcon);
  930. if(iImage == -1)
  931. iImage = 0;
  932. int iImageSm = ImageList_AddIcon(himlSm, hIcon);
  933. assert(iImage == iImageSm);
  934. DestroyIcon(hIcon);
  935. }
  936. iItem = ListView_GetItemCount(hwList);
  937. // Add app to the list view.
  938. LVITEM lvItem;
  939. lvItem.mask = LVIF_IMAGE | LVIF_TEXT;
  940. lvItem.iItem = iItem;
  941. lvItem.iSubItem = 0;
  942. lvItem.pszText = pme->szAppName;
  943. lvItem.cchTextMax = lstrlen(pme->szAppName);
  944. lvItem.iImage = iImage;
  945. ListView_InsertItem(hwList, &lvItem);
  946. lvItem.mask = LVIF_TEXT;
  947. lvItem.iItem = iItem;
  948. lvItem.iSubItem = 1;
  949. lvItem.pszText = pme->szPath;
  950. lvItem.cchTextMax = lstrlen(pme->szPath);
  951. ListView_SetItem(hwList, &lvItem);
  952. // If no items were in view prior, refresh view
  953. //(otherwise "There are no items . . ." message will stay in listview.
  954. if(iItem == 0)
  955. RedrawWindow(hwList, 0, 0, RDW_ERASE | RDW_INVALIDATE | RDW_ERASENOW);
  956. }
  957. // Start searching the database
  958. void StartSearch(HWND hwnd)
  959. {
  960. HWND hwList, hwStatus, hwResultFrame;
  961. hwList = GetDlgItem(hwnd, c_iResultListID);
  962. hwStatus = GetDlgItem(hwnd, c_iStatusBarID);
  963. hwResultFrame = GetDlgItem(hwnd, c_iResultFrameID);
  964. // Both should be NULL or both non-NULL
  965. assert( (hwList == 0) ? (hwStatus == 0 && hwResultFrame == 0) : true);
  966. if(!hwList)
  967. {
  968. // Expand the window to encompass the new lsitview.
  969. RECT rectWnd;
  970. GetWindowRect(hwnd, &rectWnd);
  971. MoveWindow(hwnd, rectWnd.left, rectWnd.top,
  972. rectWnd.right - rectWnd.left,
  973. c_nResultListHeight + g_nWindowHeight, TRUE);
  974. // See if use has checked show small icons, large icons, etc.,
  975. // and set appropriate listview style.
  976. MENUITEMINFO mii;
  977. HMENU hMenu = GetMenu(hwnd);
  978. ZeroMemory(&mii, sizeof(mii));
  979. mii.cbSize = sizeof(mii);
  980. mii.fMask = MIIM_STATE;
  981. DWORD dwStyle = WS_CHILD | WS_VISIBLE | LVS_SHOWSELALWAYS;
  982. DWORD dwExStyle = LVS_EX_LABELTIP;
  983. GetMenuItemInfo(hMenu, ID_VIEW_LARGEICONS, FALSE, &mii);
  984. if(mii.fState & MFS_CHECKED)
  985. dwStyle |= LVS_ICON;
  986. ZeroMemory(&mii, sizeof(mii));
  987. mii.cbSize = sizeof(mii);
  988. mii.fMask = MIIM_STATE;
  989. GetMenuItemInfo(hMenu, ID_VIEW_SMALLICONS, FALSE, &mii);
  990. if(mii.fState & MFS_CHECKED)
  991. dwStyle |= LVS_SMALLICON;
  992. ZeroMemory(&mii, sizeof(mii));
  993. mii.cbSize = sizeof(mii);
  994. mii.fMask = MIIM_STATE;
  995. GetMenuItemInfo(hMenu, ID_VIEW_ASLIST, FALSE, &mii);
  996. if(mii.fState & MFS_CHECKED)
  997. dwStyle |= LVS_LIST;
  998. ZeroMemory(&mii, sizeof(mii));
  999. mii.cbSize = sizeof(mii);
  1000. mii.fMask = MIIM_STATE;
  1001. GetMenuItemInfo(hMenu, ID_VIEW_ASDETAILS, FALSE, &mii);
  1002. if(mii.fState & MFS_CHECKED)
  1003. {
  1004. dwStyle |= LVS_REPORT;
  1005. dwExStyle |= LVS_EX_FULLROWSELECT;
  1006. }
  1007. // Create the status bar.
  1008. TCHAR* szCaption = LoadStringResource(IDS_SEARCHING);
  1009. if(!szCaption)
  1010. {
  1011. DestroyWindow(hwnd);
  1012. return;
  1013. }
  1014. hwStatus = CreateStatusWindow(WS_CHILD | WS_VISIBLE,
  1015. szCaption, hwnd, c_iStatusBarID);
  1016. if(!hwStatus)
  1017. {
  1018. DestroyWindow(hwnd);
  1019. return;
  1020. }
  1021. delete szCaption;
  1022. RECT rectCl;
  1023. RECT rectSB;
  1024. GetClientRect(hwnd, &rectCl);
  1025. GetClientRect(hwnd, &rectSB);
  1026. // Round about way of getting top coordinate of
  1027. // status bar to a client coordinate in main window
  1028. POINT ptStatusTop;
  1029. ptStatusTop.x = 0;
  1030. ptStatusTop.y = rectSB.top;
  1031. ClientToScreen(hwStatus, &ptStatusTop);
  1032. ScreenToClient(hwnd, &ptStatusTop);
  1033. // Bottom of window prior to resizing
  1034. POINT ptListTop;
  1035. ptListTop.x = 0;
  1036. ptListTop.y = rectWnd.bottom;
  1037. ScreenToClient(hwnd, &ptListTop);
  1038. // Create static frame around listview.
  1039. hwResultFrame = CreateWindowEx(0, TEXT("static"), TEXT(""),
  1040. WS_VISIBLE | WS_CHILD | SS_BLACKRECT | SS_SUNKEN,
  1041. rectCl.left, ptListTop.y, rectCl.right-rectCl.left,
  1042. ptStatusTop.y - ptListTop.y,
  1043. hwnd, reinterpret_cast<HMENU>(c_iResultFrameID), g_hinst, 0);
  1044. if(!hwResultFrame)
  1045. {
  1046. DestroyWindow(hwnd);
  1047. return;
  1048. }
  1049. // Create the listview window.
  1050. hwList = CreateWindowEx(0, WC_LISTVIEW, TEXT(""),
  1051. dwStyle, rectCl.left + c_nResultFrameWidth,
  1052. ptListTop.y + c_nResultFrameWidth,
  1053. rectCl.right - rectCl.left - 2 * c_nResultFrameWidth,
  1054. ptStatusTop.y - ptListTop.y - c_nResultFrameWidth,
  1055. hwnd,reinterpret_cast<HMENU>(c_iResultListID), g_hinst, 0);
  1056. if(!hwList)
  1057. {
  1058. DestroyWindow(hwnd);
  1059. return;
  1060. }
  1061. // Subclass the window
  1062. pfnLVOrgWndProc =
  1063. reinterpret_cast<WNDPROC>(GetWindowLongPtr(hwList, GWL_WNDPROC));
  1064. SetWindowLongPtr(hwList, GWL_WNDPROC,
  1065. reinterpret_cast<UINT_PTR>(LVWndProc));
  1066. ListView_SetExtendedListViewStyleEx(hwList, 0, dwExStyle);
  1067. // Insert listview columns.
  1068. for(int i = 0; i < c_nNumListColumns; i++)
  1069. {
  1070. LVCOLUMN lvCol;
  1071. lvCol.mask = LVCF_FMT | LVCF_TEXT | LVCF_ORDER | LVCF_WIDTH |
  1072. LVCF_SUBITEM;
  1073. lvCol.fmt = LVCFMT_LEFT;
  1074. lvCol.pszText = LoadStringResource(c_iListColumnNameIDS[i]);
  1075. lvCol.cchTextMax = lstrlen(lvCol.pszText);
  1076. lvCol.iSubItem = i;
  1077. lvCol.iOrder = i;
  1078. lvCol.cx = c_nListColumnWidth;
  1079. ListView_InsertColumn(hwList, i, &lvCol);
  1080. delete lvCol.pszText;
  1081. }
  1082. // "Remaximize" if it is already maximized
  1083. if(GetWindowLongPtr(hwnd, GWL_STYLE) & WS_MAXIMIZE)
  1084. {
  1085. HWND hwDesktop = GetDesktopWindow();
  1086. RECT rcDesktop;
  1087. GetClientRect(hwDesktop, &rcDesktop);
  1088. MoveWindow(hwnd, rcDesktop.left, rcDesktop.top,
  1089. rcDesktop.right - rcDesktop.left, rcDesktop.bottom - rcDesktop.top,
  1090. TRUE);
  1091. // Set correct restore position
  1092. WINDOWPLACEMENT wndpl;
  1093. GetWindowPlacement(hwnd, &wndpl);
  1094. wndpl.rcNormalPosition.bottom = wndpl.rcNormalPosition.top +
  1095. g_nWindowHeight + c_nResultListHeight;
  1096. SetWindowPlacement(hwnd, &wndpl);
  1097. }
  1098. }
  1099. // If it exists, just reset the content
  1100. else
  1101. {
  1102. TCHAR* szMsg;
  1103. TCHAR* szCaption;
  1104. szMsg = LoadStringResource(IDS_CLRALLMSG);
  1105. szCaption = LoadStringResource(IDS_CLRALLCAPTION);
  1106. if(!szMsg || !szCaption)
  1107. {
  1108. DestroyWindow(hwnd);
  1109. return;
  1110. }
  1111. if(MessageBox(hwnd, szMsg, szCaption, MB_ICONINFORMATION |
  1112. MB_OKCANCEL) == IDOK)
  1113. ListView_DeleteAllItems(GetDlgItem(hwnd, c_iResultListID));
  1114. else
  1115. return;
  1116. }
  1117. // Enable the view options related to the result list
  1118. HMENU hMenu;
  1119. hMenu = GetMenu(hwnd);
  1120. HMENU hmView = GetSubMenu(hMenu, c_iViewMenuPos);
  1121. EnableMenuItem(hmView, c_iArrangeIconsPos, MF_BYPOSITION | MF_ENABLED);
  1122. EnableMenuItem(hMenu, ID_VIEW_ARRANGEICONS_BYPATH, MF_BYCOMMAND | MF_ENABLED);
  1123. EnableMenuItem(hMenu, ID_VIEW_CHOOSECOLUMNS, MF_BYCOMMAND | MF_ENABLED);
  1124. EnableMenuItem(hMenu, ID_VIEW_REFRESH, MF_BYCOMMAND | MF_ENABLED);
  1125. EnableWindow(GetDlgItem(hwnd, IDC_STOP), TRUE);
  1126. EnableWindow(GetDlgItem(hwnd, IDC_CLEARALL), TRUE);
  1127. // Find out what to search for
  1128. HWND hwComboBox = GetDlgItem(hwnd, IDC_DRIVELIST);
  1129. // If zero is selected, search for everything.
  1130. if(SendMessage(hwComboBox, CB_GETCURSEL, 0, 0)==0)
  1131. SearchDB(0, hwnd);
  1132. else
  1133. {
  1134. TCHAR szBuffer[MAX_PATH+1];
  1135. COMBOBOXEXITEM cbim;
  1136. cbim.mask = CBEIF_TEXT;
  1137. cbim.iItem = -1;
  1138. cbim.pszText = szBuffer;
  1139. cbim.cchTextMax = MAX_PATH;
  1140. SendMessage(hwComboBox, CBEM_GETITEM, 0,
  1141. reinterpret_cast<LPARAM>(&cbim));
  1142. if(szBuffer[lstrlen(szBuffer)-1] != TEXT('\\'))
  1143. lstrcat(szBuffer, TEXT("\\"));
  1144. SearchDB(szBuffer, hwnd);
  1145. }
  1146. // Start animating the icon.
  1147. HWND hwAnim = GetDlgItem(hwnd, c_iFindAnimID);
  1148. Animate_Play(hwAnim, 0, -1, -1);
  1149. }
  1150. // Terminate the search.
  1151. void StopSearch(HWND hwnd)
  1152. {
  1153. // Stop searching the database.
  1154. StopSearchDB();
  1155. // Can't click "STOP" or anymore.
  1156. EnableWindow(GetDlgItem(hwnd, IDC_STOP), FALSE);
  1157. // Update with a search complete if not in menu.
  1158. if(g_fInMenu == FALSE)
  1159. UpdateStatus(hwnd, LoadStringResource(IDS_SEARCHDONE));
  1160. // Stop animating the icon.
  1161. HWND hwAnim = GetDlgItem(hwnd, c_iFindAnimID);
  1162. Animate_Stop(hwAnim);
  1163. }
  1164. // Remove result window.
  1165. void ClearResults(HWND hwnd)
  1166. {
  1167. TCHAR* szMsg;
  1168. TCHAR* szCaption;
  1169. szMsg = LoadStringResource(IDS_CLRALLMSG);
  1170. szCaption = LoadStringResource(IDS_CLRALLCAPTION);
  1171. if(!szMsg || !szCaption)
  1172. {
  1173. DestroyWindow(hwnd);
  1174. return;
  1175. }
  1176. if(MessageBox(hwnd, szMsg, szCaption, MB_ICONINFORMATION |
  1177. MB_OKCANCEL) == IDCANCEL)
  1178. return;
  1179. // Stop the search
  1180. StopSearch(hwnd);
  1181. // Get rid of all result-related windows.
  1182. HWND hwCtrl;
  1183. if( (hwCtrl = GetDlgItem(hwnd, c_iResultListID)) != 0)
  1184. DestroyWindow(hwCtrl);
  1185. if( (hwCtrl = GetDlgItem(hwnd, c_iStatusBarID)) != 0)
  1186. DestroyWindow(hwCtrl);
  1187. if( (hwCtrl = GetDlgItem(hwnd, c_iResultFrameID)) != 0)
  1188. DestroyWindow(hwCtrl);
  1189. // Restore original window size.
  1190. RECT rect;
  1191. GetWindowRect(hwnd, &rect);
  1192. MoveWindow(hwnd, rect.left, rect.top, rect.right - rect.left,
  1193. g_nWindowHeight, TRUE);
  1194. // Do cleanup if we were maximized
  1195. if(GetWindowLongPtr(hwnd, GWL_STYLE) & WS_MAXIMIZE)
  1196. {
  1197. // Set correct restore position
  1198. WINDOWPLACEMENT wndpl;
  1199. GetWindowPlacement(hwnd, &wndpl);
  1200. wndpl.rcNormalPosition.bottom = wndpl.rcNormalPosition.top +
  1201. g_nWindowHeight;
  1202. SetWindowPlacement(hwnd, &wndpl);
  1203. }
  1204. // Disable the view options related to the result list
  1205. HMENU hMenu;
  1206. hMenu = GetMenu(hwnd);
  1207. EnableMenuItem(hMenu, ID_FILE_DOWNLOADPATCH, MF_BYCOMMAND | MF_GRAYED);
  1208. EnableMenuItem(hMenu, ID_FILE_PROPERTIES, MF_BYCOMMAND | MF_GRAYED);
  1209. HMENU hmView = GetSubMenu(hMenu, c_iViewMenuPos);
  1210. EnableMenuItem(hmView, c_iArrangeIconsPos, MF_BYPOSITION | MF_GRAYED);
  1211. EnableMenuItem(hMenu, ID_VIEW_ARRANGEICONS_BYPATH, MF_BYCOMMAND | MF_GRAYED);
  1212. EnableMenuItem(hMenu, ID_VIEW_CHOOSECOLUMNS, MF_BYCOMMAND | MF_GRAYED);
  1213. EnableMenuItem(hMenu, ID_VIEW_REFRESH, MF_BYCOMMAND | MF_GRAYED);
  1214. EnableWindow(GetDlgItem(hwnd, IDC_CLEARALL), FALSE);
  1215. }
  1216. // Subclass for listview, customize painting.
  1217. LRESULT CALLBACK LVWndProc(HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
  1218. {
  1219. // Only bother if it's a PAINT message and no items are in listbox.
  1220. if((uiMsg == WM_PAINT) && (ListView_GetItemCount(hwnd) == 0))
  1221. {
  1222. // Get rectangle for text.
  1223. RECT rc;
  1224. GetWindowRect(hwnd, &rc);
  1225. POINT pt;
  1226. pt.x = rc.left;
  1227. pt.y = rc.top;
  1228. ScreenToClient(hwnd, &pt);
  1229. rc.left = pt.x;
  1230. rc.top = pt.y;
  1231. pt.x = rc.right;
  1232. pt.y = rc.bottom;
  1233. ScreenToClient(hwnd, &pt);
  1234. rc.right = pt.x;
  1235. rc.bottom = pt.y;
  1236. HWND hwHeader = ListView_GetHeader(hwnd);
  1237. if(hwHeader)
  1238. {
  1239. RECT rcHeader;
  1240. Header_GetItemRect(hwHeader, 0, &rcHeader);
  1241. rc.top += rcHeader.bottom;
  1242. }
  1243. rc.top += 10;
  1244. // Do the default painting of the listview paint.
  1245. InvalidateRect(hwnd, &rc, TRUE);
  1246. CallWindowProc(pfnLVOrgWndProc, hwnd, uiMsg, wParam, lParam);
  1247. HDC hdc = GetDC(hwnd);
  1248. SaveDC(hdc);
  1249. SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));
  1250. SetBkColor(hdc, GetSysColor(COLOR_WINDOW));
  1251. HFONT hFont = static_cast<HFONT>(GetStockObject(ANSI_VAR_FONT));
  1252. SelectObject(hdc, hFont);
  1253. // Get message to print.
  1254. TCHAR* szMsg = LoadStringResource(IDS_EMPTYLIST);
  1255. DrawText(hdc, szMsg, -1, &rc, DT_CENTER | DT_WORDBREAK
  1256. | DT_NOPREFIX | DT_NOCLIP);
  1257. RestoreDC(hdc, -1);
  1258. ReleaseDC(hwnd, hdc);
  1259. delete szMsg;
  1260. return 0;
  1261. } else if(uiMsg == WM_NOTIFY)
  1262. {
  1263. HWND hwHeader = ListView_GetHeader(hwnd);
  1264. if(hwHeader)
  1265. {
  1266. if(static_cast<int>(wParam) == GetDlgCtrlID(hwHeader))
  1267. {
  1268. LPNMHEADER pHdr = reinterpret_cast<LPNMHEADER>(lParam);
  1269. if(pHdr->hdr.code == HDN_ITEMCHANGED)
  1270. {
  1271. RECT rc;
  1272. GetClientRect(hwHeader, &rc);
  1273. POINT pt;
  1274. pt.y = rc.bottom;
  1275. ClientToScreen(hwHeader, &pt);
  1276. ScreenToClient(hwnd, &pt);
  1277. GetClientRect(hwnd, &rc);
  1278. rc.top = pt.y;
  1279. InvalidateRect(hwnd, &rc, TRUE);
  1280. }
  1281. }
  1282. }
  1283. return CallWindowProc(pfnLVOrgWndProc, hwnd, uiMsg, wParam, lParam);
  1284. }
  1285. else
  1286. return CallWindowProc(pfnLVOrgWndProc, hwnd, uiMsg, wParam, lParam);
  1287. }
  1288. // Allocate a new string and copy a string resource into it.
  1289. TCHAR* LoadStringResource(UINT uID)
  1290. {
  1291. TCHAR szBuffer[c_nMaxStringLength];
  1292. TCHAR* szRet = 0;
  1293. if(LoadString(g_hinst, uID, szBuffer, c_nMaxStringLength))
  1294. {
  1295. szRet = new TCHAR[lstrlen(szBuffer)+1];
  1296. if(szRet)
  1297. lstrcpy(szRet, szBuffer);
  1298. }
  1299. return szRet;
  1300. }
  1301. // Print an error message box in hwnd, with string resource with id as
  1302. // message.
  1303. void Error(HWND hwnd, UINT id)
  1304. {
  1305. PTSTR szMsg = LoadStringResource(id);
  1306. PTSTR szCaption = LoadStringResource(IDS_ERROR);
  1307. if(szMsg && szCaption)
  1308. MessageBox(hwnd, szMsg, szCaption, MB_OK | MB_ICONERROR);
  1309. if(szMsg)
  1310. delete szMsg;
  1311. if(szCaption)
  1312. delete szCaption;
  1313. }