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.

485 lines
17 KiB

  1. //
  2. // LISTVIEW.C
  3. //
  4. #include "sigverif.h"
  5. HWND g_hListView = NULL;
  6. HWND g_hStatus = NULL;
  7. BOOL g_bSortOrder[] = { FALSE, FALSE, FALSE, FALSE, FALSE};
  8. RECT g_Rect;
  9. // Initialize the image lists for the icons in the listview control.
  10. BOOL WINAPI ListView_SetImageLists(HWND hwndList)
  11. {
  12. SHFILEINFO sfi;
  13. HIMAGELIST himlSmall;
  14. HIMAGELIST himlLarge;
  15. BOOL bSuccess = TRUE;
  16. TCHAR szDriveRoot[MAX_PATH];
  17. MyGetWindowsDirectory(szDriveRoot, cA(szDriveRoot));
  18. szDriveRoot[3] = 0;
  19. himlSmall = (HIMAGELIST)SHGetFileInfo((LPCTSTR)szDriveRoot,
  20. 0,
  21. &sfi,
  22. sizeof(SHFILEINFO),
  23. SHGFI_SYSICONINDEX | SHGFI_SMALLICON);
  24. himlLarge = (HIMAGELIST)SHGetFileInfo((LPCTSTR)szDriveRoot,
  25. 0,
  26. &sfi,
  27. sizeof(SHFILEINFO),
  28. SHGFI_SYSICONINDEX | SHGFI_LARGEICON);
  29. if (himlSmall && himlLarge) {
  30. ListView_SetImageList(hwndList, himlSmall, LVSIL_SMALL);
  31. ListView_SetImageList(hwndList, himlLarge, LVSIL_NORMAL);
  32. } else bSuccess = FALSE;
  33. return bSuccess;
  34. }
  35. //
  36. // Insert everything from the g_App.lpFileList into the listview control.
  37. //
  38. void ListView_InsertItems(void)
  39. {
  40. LPFILENODE lpFileNode;
  41. LV_ITEM lvi;
  42. TCHAR szBuffer[MAX_PATH];
  43. LPTSTR lpString;
  44. int iRet;
  45. for (lpFileNode=g_App.lpFileList;lpFileNode;lpFileNode=lpFileNode->next) {
  46. if (lpFileNode->bScanned &&
  47. !lpFileNode->bSigned &&
  48. SetCurrentDirectory(lpFileNode->lpDirName)) {
  49. // Initialize lvi and insert the filename and icon into the first column.
  50. ZeroMemory(&lvi, sizeof(LV_ITEM));
  51. lvi.mask = LVIF_TEXT;
  52. lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;
  53. lvi.iImage = lpFileNode->iIcon;
  54. lvi.lParam = (LPARAM) lpFileNode;
  55. lvi.iSubItem = 0;
  56. lvi.pszText = lpFileNode->lpFileName;
  57. lvi.iItem = MAX_INT;
  58. lvi.iItem = ListView_InsertItem(g_hListView, &lvi);
  59. // Insert the directory name into the second column.
  60. lvi.mask = LVIF_TEXT;
  61. lvi.iSubItem = 1;
  62. lvi.pszText = lpFileNode->lpDirName;
  63. ListView_SetItem(g_hListView, &lvi);
  64. // Get the date format, so we are localizable...
  65. MyLoadString(szBuffer, IDS_UNKNOWN);
  66. iRet = GetDateFormat( LOCALE_SYSTEM_DEFAULT,
  67. DATE_SHORTDATE,
  68. &lpFileNode->LastModified,
  69. NULL,
  70. NULL,
  71. 0);
  72. if (iRet) {
  73. lpString = MALLOC((iRet + 1) * sizeof(TCHAR));
  74. if (lpString) {
  75. iRet = GetDateFormat( LOCALE_SYSTEM_DEFAULT,
  76. DATE_SHORTDATE,
  77. &lpFileNode->LastModified,
  78. NULL,
  79. lpString,
  80. iRet);
  81. if (iRet) {
  82. lstrcpy(szBuffer, lpString);
  83. }
  84. FREE(lpString);
  85. }
  86. }
  87. lvi.mask = LVIF_TEXT;
  88. lvi.iSubItem = 2;
  89. lvi.pszText = szBuffer;
  90. ListView_SetItem(g_hListView, &lvi);
  91. // Insert the filetype string into the fourth column.
  92. if (lpFileNode->lpTypeName) {
  93. lstrcpy(szBuffer, lpFileNode->lpTypeName);
  94. } else MyLoadString(szBuffer, IDS_UNKNOWN);
  95. lvi.mask = LVIF_TEXT;
  96. lvi.iSubItem = 3;
  97. lvi.pszText = szBuffer;
  98. ListView_SetItem(g_hListView, &lvi);
  99. // Insert the version string into the fifth column.
  100. if (lpFileNode->lpVersion) {
  101. lstrcpy(szBuffer, lpFileNode->lpVersion);
  102. } else MyLoadString(szBuffer, IDS_NOVERSION);
  103. lvi.mask = LVIF_TEXT;
  104. lvi.iSubItem = 4;
  105. lvi.pszText = szBuffer;
  106. ListView_SetItem(g_hListView, &lvi);
  107. }
  108. }
  109. }
  110. //
  111. // Initialize the listview dialog. First, we are going to load the global icon resource.
  112. // Then we are going to create a status window and the actual listview control.
  113. // Then we need to add the four columns and work out their default widths.
  114. //
  115. BOOL ListView_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam)
  116. {
  117. LV_COLUMN lvc;
  118. RECT rect, rect2, rect3, rect4, rect5;
  119. TCHAR szBuffer[MAX_PATH];
  120. TCHAR szBuffer2[MAX_PATH];
  121. INT iCol = 0, iWidth = 0;
  122. // Load the global icon resource
  123. if (g_App.hIcon) {
  124. SetClassLongPtr(hwnd, GCLP_HICON, (LONG_PTR) g_App.hIcon);
  125. }
  126. // Create the status window at the bottom of the dialog
  127. g_hStatus = CreateStatusWindow( WS_CHILD | WS_VISIBLE,
  128. NULL,
  129. hwnd,
  130. (UINT) IDC_STATUSWINDOW);
  131. // Load the status string and fill it in with the correct values.
  132. MyLoadString(szBuffer, IDS_NUMFILES);
  133. wsprintf(szBuffer2, szBuffer, g_App.dwFiles, g_App.dwSigned, g_App.dwUnsigned,
  134. g_App.dwFiles - g_App.dwSigned - g_App.dwUnsigned);
  135. SendMessage(g_hStatus, WM_SETTEXT, (WPARAM) 0, (LPARAM) szBuffer2);
  136. GetWindowRect(hwnd, &g_Rect);
  137. // Get the windows RECT values for the dialog, the static text, and the status window.
  138. // We will use these values to figure out where to put the listview and the columns.
  139. GetWindowRect(hwnd, &rect);
  140. GetWindowRect(GetDlgItem(hwnd, IDC_RESULTSTEXT), &rect2);
  141. GetWindowRect(g_hStatus, &rect3);
  142. GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rect4);
  143. MoveWindow( GetDlgItem(hwnd, IDCANCEL),
  144. rect.right - rect2.left - (rect4.right - rect4.left) - (( 2 * (rect2.left - rect.left)) / 3),
  145. rect.bottom - rect.top - (( 7 * (rect4.bottom - rect4.top)) / 2),
  146. rect4.right - rect4.left,
  147. rect4.bottom - rect4.top,
  148. TRUE);
  149. //
  150. // Create the listview window! I am using some really screwey logic to figure out how
  151. // big to make the listview and where to put it, but it seems to work.
  152. //
  153. g_hListView = CreateWindowEx( WS_EX_CLIENTEDGE,
  154. WC_LISTVIEW, TEXT(""),
  155. WS_TABSTOP | WS_VSCROLL | WS_VISIBLE | WS_CHILD | WS_BORDER |
  156. LVS_SINGLESEL | LVS_REPORT | LVS_AUTOARRANGE | LVS_SHAREIMAGELISTS,
  157. ((rect2.left - rect.left) * 2) / 3,
  158. (rect2.bottom - rect2.top) * 2,
  159. (rect.right - rect.left) - 2 * (rect2.left - rect.left),
  160. (rect.bottom - rect2.bottom) - (rect4 .bottom - rect4.top) - 3 * (rect3.bottom - rect3.top),
  161. hwnd,
  162. (HMENU) IDC_LISTVIEW,
  163. g_App.hInstance,
  164. NULL);
  165. // If the CreateWindowEx failed, then bail.
  166. if (!g_hListView)
  167. return FALSE;
  168. GetWindowRect(g_hListView, &rect5);
  169. // Initialize the icon lists
  170. ListView_SetImageLists(g_hListView);
  171. // Create the first listview column for the icon and the file name.
  172. lvc.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
  173. lvc.fmt = LVCFMT_LEFT;
  174. lvc.cx = (rect2.right - rect2.left) / 5;
  175. lvc.pszText = szBuffer;
  176. MyLoadString(szBuffer, IDS_COL_NAME);
  177. lvc.cchTextMax = MAX_PATH;
  178. ListView_InsertColumn(g_hListView, iCol++, &lvc);
  179. // Create the second listview column for the directory name.
  180. iWidth += lvc.cx;
  181. lvc.cx = (rect2.right - rect2.left) / 4;
  182. MyLoadString(szBuffer, IDS_COL_FOLDER);
  183. ListView_InsertColumn(g_hListView, iCol++, &lvc);
  184. // Create the third listview column for the date name.
  185. iWidth += lvc.cx;
  186. lvc.cx = (rect2.right - rect2.left) / 6;
  187. lvc.fmt = LVCFMT_CENTER;
  188. MyLoadString(szBuffer, IDS_COL_DATE);
  189. ListView_InsertColumn(g_hListView, iCol++, &lvc);
  190. // Create the fourth listview column for the filetype string.
  191. iWidth += lvc.cx;
  192. lvc.cx = (rect2.right - rect2.left) / 6;
  193. lvc.fmt = LVCFMT_CENTER;
  194. MyLoadString(szBuffer, IDS_COL_TYPE);
  195. ListView_InsertColumn(g_hListView, iCol++, &lvc);
  196. // Create the fifth listview column for the version string.
  197. iWidth += lvc.cx;
  198. lvc.cx = (rect2.right - rect2.left) - iWidth - 5;
  199. lvc.fmt = LVCFMT_CENTER;
  200. MyLoadString(szBuffer, IDS_COL_VERSION);
  201. ListView_InsertColumn(g_hListView, iCol++, &lvc);
  202. // Now that the columns are set up, insert all the files in g_App.lpFileList!
  203. ListView_InsertItems();
  204. // Initialize the sorting order array to all FALSE.
  205. g_bSortOrder[0] = FALSE;
  206. g_bSortOrder[1] = FALSE;
  207. g_bSortOrder[2] = FALSE;
  208. g_bSortOrder[3] = FALSE;
  209. SetForegroundWindow(g_App.hDlg);
  210. SetForegroundWindow(hwnd);
  211. SetFocus(GetDlgItem(hwnd, IDCANCEL));
  212. return TRUE;
  213. }
  214. //
  215. // This function checks to see how big the sizing rectangle will be. If the user is trying
  216. // to size the dialog to less than the values in g_Rect, then we will fix the rectangle values
  217. //
  218. BOOL ListView_OnSizing(HWND hwnd, WPARAM wParam, LPARAM lParam)
  219. {
  220. RECT rect;
  221. LPRECT lpRect = (LPRECT) lParam;
  222. BOOL bRet = FALSE;
  223. GetWindowRect(hwnd, &rect);
  224. if ((lpRect->right - lpRect->left) < (g_Rect.right - g_Rect.left)) {
  225. lpRect->left = rect.left;
  226. lpRect->right = lpRect->left + (g_Rect.right - g_Rect.left);
  227. bRet = TRUE;
  228. }
  229. if ((lpRect->bottom - lpRect->top) < (g_Rect.bottom - g_Rect.top)) {
  230. lpRect->top = rect.top;
  231. lpRect->bottom = lpRect->top + (g_Rect.bottom - g_Rect.top);
  232. bRet = TRUE;
  233. }
  234. return bRet;
  235. }
  236. //
  237. // This function allows us to resize the listview control and status windows when the
  238. // user resizes the results dialog. Thankfully, we can make everything relative using
  239. // the RECT values for the main dialog, the static text, and the status window.
  240. //
  241. void ListView_ResizeWindow(HWND hwnd)
  242. {
  243. RECT rect, rect2, rect3, rect4;
  244. GetWindowRect(hwnd, &rect);
  245. if ((rect.right - rect.left) < (g_Rect.right - g_Rect.left)) {
  246. MoveWindow(hwnd,
  247. rect.left,
  248. rect.top,
  249. g_Rect.right - g_Rect.left,
  250. rect.bottom - rect.top,
  251. TRUE);
  252. }
  253. if ((rect.bottom - rect.top) < (g_Rect.bottom - g_Rect.top)) {
  254. MoveWindow(hwnd,
  255. rect.left,
  256. rect.top,
  257. rect.right - rect.left,
  258. g_Rect.bottom - g_Rect.top,
  259. TRUE);
  260. }
  261. GetWindowRect(GetDlgItem(hwnd, IDC_RESULTSTEXT), &rect2);
  262. GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rect4);
  263. GetWindowRect(g_hStatus, &rect3);
  264. MoveWindow(g_hListView,
  265. ((rect2.left - rect.left) * 2) / 3,
  266. (rect2.bottom - rect2.top) * 2,
  267. (rect.right - rect.left) - 2 * (rect2.left - rect.left),
  268. (rect.bottom - rect2.bottom) - (rect4 .bottom - rect4.top) - 3 * (rect3.bottom - rect3.top),
  269. TRUE);
  270. MoveWindow(g_hStatus,
  271. 0,
  272. (rect.bottom - rect.top) - (rect3.bottom - rect3.top),
  273. rect.right - rect.left,
  274. rect3.bottom - rect3.top,
  275. TRUE);
  276. MoveWindow(GetDlgItem(hwnd, IDCANCEL),
  277. rect.right - rect2.left - (rect4.right - rect4.left) - (( 2 * (rect2.left - rect.left)) / 3),
  278. rect.bottom - rect.top - ((7 * (rect4.bottom - rect4.top)) / 2),
  279. rect4.right - rect4.left,
  280. rect4.bottom - rect4.top,
  281. TRUE);
  282. }
  283. //
  284. // This function is a callback that returns a value for ListView_SortItems.
  285. // ListView_SortItems wants a negative, zero, or positive number.
  286. // Since CompareString returns 1,2,3 we just subtract 2 from the return value.
  287. //
  288. // We use the g_bSortOrder array to figure out which way we have sorted in the past.
  289. //
  290. // Warning: we don't check for error values from CompareString
  291. //
  292. int CALLBACK ListView_CompareNames(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
  293. {
  294. LPFILENODE lpFileNode1;
  295. LPFILENODE lpFileNode2;
  296. FILETIME FileTime1, FileTime2;
  297. int iResult = 2;
  298. //
  299. // Depending on the sort order, we swap the order of comparison
  300. //
  301. if (g_bSortOrder[lParamSort]) {
  302. lpFileNode2 = (LPFILENODE) lParam1;
  303. lpFileNode1 = (LPFILENODE) lParam2;
  304. } else {
  305. lpFileNode1 = (LPFILENODE) lParam1;
  306. lpFileNode2 = (LPFILENODE) lParam2;
  307. }
  308. switch (lParamSort) {
  309. // We are comparing the file names
  310. case 0: iResult = CompareString(LOCALE_SYSTEM_DEFAULT,
  311. NORM_IGNORECASE | NORM_IGNOREWIDTH,
  312. lpFileNode1->lpFileName,
  313. -1,
  314. lpFileNode2->lpFileName,
  315. -1);
  316. break;
  317. // We are comparing the directory names
  318. case 1: iResult = CompareString(LOCALE_SYSTEM_DEFAULT,
  319. NORM_IGNORECASE | NORM_IGNOREWIDTH,
  320. lpFileNode1->lpDirName,
  321. -1,
  322. lpFileNode2->lpDirName,
  323. -1);
  324. break;
  325. // We are comparing the LastWriteTime's between the two files.
  326. case 2: SystemTimeToFileTime(&lpFileNode1->LastModified, &FileTime1);
  327. SystemTimeToFileTime(&lpFileNode2->LastModified, &FileTime2);
  328. iResult = CompareFileTime(&FileTime1, &FileTime2);
  329. return iResult;
  330. break;
  331. // We are comparing the filetype strings
  332. case 3: iResult = CompareString(LOCALE_SYSTEM_DEFAULT,
  333. NORM_IGNORECASE | NORM_IGNOREWIDTH,
  334. lpFileNode1->lpTypeName,
  335. -1,
  336. lpFileNode2->lpTypeName,
  337. -1);
  338. break;
  339. // We are comparing the version strings
  340. case 4: iResult = CompareString(LOCALE_SYSTEM_DEFAULT,
  341. NORM_IGNORECASE | NORM_IGNOREWIDTH,
  342. lpFileNode1->lpVersion,
  343. -1,
  344. lpFileNode2->lpVersion,
  345. -1);
  346. break;
  347. }
  348. return(iResult - 2);
  349. }
  350. //
  351. // This function handles the clicks on the column headers and calls ListView_SortItems with the
  352. // ListView_CompareNames callback previously defined. It then toggles the sortorder for that column.
  353. //
  354. LRESULT ListView_NotifyHandler(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  355. {
  356. NMHDR *lpnmhdr = (NMHDR *) lParam;
  357. NM_LISTVIEW *lpnmlv = (NM_LISTVIEW *) lParam;
  358. switch (lpnmhdr->code) {
  359. case LVN_COLUMNCLICK:
  360. switch (lpnmlv->iSubItem) {
  361. case 0:
  362. case 1:
  363. case 2:
  364. case 3:
  365. case 4: ListView_SortItems(lpnmlv->hdr.hwndFrom, ListView_CompareNames, (LPARAM) lpnmlv->iSubItem);
  366. g_bSortOrder[lpnmlv->iSubItem] = !(g_bSortOrder[lpnmlv->iSubItem]);
  367. break;
  368. }
  369. break;
  370. }
  371. return 0;
  372. }
  373. //
  374. // The only thing we look for here is the IDCANCEL if the user hit ESCAPE
  375. //
  376. void ListView_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
  377. {
  378. switch (id) {
  379. case IDCANCEL:
  380. SendMessage(hwnd, WM_CLOSE, 0, 0);
  381. break;
  382. }
  383. }
  384. INT_PTR CALLBACK ListView_DlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  385. {
  386. BOOL fProcessed = TRUE;
  387. switch (uMsg) {
  388. HANDLE_MSG(hwnd, WM_INITDIALOG, ListView_OnInitDialog);
  389. HANDLE_MSG(hwnd, WM_COMMAND, ListView_OnCommand);
  390. case WM_NOTIFY:
  391. return ListView_NotifyHandler(hwnd, uMsg, wParam, lParam);
  392. case WM_CLOSE:
  393. if (g_hStatus) {
  394. DestroyWindow(g_hStatus);
  395. g_hStatus = NULL;
  396. }
  397. if (g_hListView) {
  398. DestroyWindow(g_hListView);
  399. g_hListView = NULL;
  400. }
  401. EndDialog(hwnd, ID_CLOSE);
  402. break;
  403. case WM_SIZING:
  404. fProcessed = ListView_OnSizing(hwnd, wParam, lParam);
  405. break;
  406. case WM_SIZE:
  407. ListView_ResizeWindow(hwnd);
  408. break;
  409. default: fProcessed = FALSE;
  410. }
  411. return fProcessed;
  412. }