486 lines
17 KiB
C
486 lines
17 KiB
C
|
//
|
||
|
// LISTVIEW.C
|
||
|
//
|
||
|
#include "sigverif.h"
|
||
|
|
||
|
HWND g_hListView = NULL;
|
||
|
HWND g_hStatus = NULL;
|
||
|
BOOL g_bSortOrder[] = { FALSE, FALSE, FALSE, FALSE, FALSE};
|
||
|
RECT g_Rect;
|
||
|
|
||
|
// Initialize the image lists for the icons in the listview control.
|
||
|
BOOL WINAPI ListView_SetImageLists(HWND hwndList)
|
||
|
{
|
||
|
SHFILEINFO sfi;
|
||
|
HIMAGELIST himlSmall;
|
||
|
HIMAGELIST himlLarge;
|
||
|
BOOL bSuccess = TRUE;
|
||
|
TCHAR szDriveRoot[MAX_PATH];
|
||
|
|
||
|
MyGetWindowsDirectory(szDriveRoot, cA(szDriveRoot));
|
||
|
szDriveRoot[3] = 0;
|
||
|
himlSmall = (HIMAGELIST)SHGetFileInfo((LPCTSTR)szDriveRoot,
|
||
|
0,
|
||
|
&sfi,
|
||
|
sizeof(SHFILEINFO),
|
||
|
SHGFI_SYSICONINDEX | SHGFI_SMALLICON);
|
||
|
|
||
|
himlLarge = (HIMAGELIST)SHGetFileInfo((LPCTSTR)szDriveRoot,
|
||
|
0,
|
||
|
&sfi,
|
||
|
sizeof(SHFILEINFO),
|
||
|
SHGFI_SYSICONINDEX | SHGFI_LARGEICON);
|
||
|
|
||
|
if (himlSmall && himlLarge) {
|
||
|
ListView_SetImageList(hwndList, himlSmall, LVSIL_SMALL);
|
||
|
ListView_SetImageList(hwndList, himlLarge, LVSIL_NORMAL);
|
||
|
} else bSuccess = FALSE;
|
||
|
|
||
|
return bSuccess;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Insert everything from the g_App.lpFileList into the listview control.
|
||
|
//
|
||
|
void ListView_InsertItems(void)
|
||
|
{
|
||
|
LPFILENODE lpFileNode;
|
||
|
LV_ITEM lvi;
|
||
|
TCHAR szBuffer[MAX_PATH];
|
||
|
LPTSTR lpString;
|
||
|
int iRet;
|
||
|
|
||
|
for (lpFileNode=g_App.lpFileList;lpFileNode;lpFileNode=lpFileNode->next) {
|
||
|
if (lpFileNode->bScanned &&
|
||
|
!lpFileNode->bSigned &&
|
||
|
SetCurrentDirectory(lpFileNode->lpDirName)) {
|
||
|
// Initialize lvi and insert the filename and icon into the first column.
|
||
|
ZeroMemory(&lvi, sizeof(LV_ITEM));
|
||
|
lvi.mask = LVIF_TEXT;
|
||
|
lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;
|
||
|
lvi.iImage = lpFileNode->iIcon;
|
||
|
lvi.lParam = (LPARAM) lpFileNode;
|
||
|
lvi.iSubItem = 0;
|
||
|
lvi.pszText = lpFileNode->lpFileName;
|
||
|
lvi.iItem = MAX_INT;
|
||
|
lvi.iItem = ListView_InsertItem(g_hListView, &lvi);
|
||
|
|
||
|
// Insert the directory name into the second column.
|
||
|
lvi.mask = LVIF_TEXT;
|
||
|
lvi.iSubItem = 1;
|
||
|
lvi.pszText = lpFileNode->lpDirName;
|
||
|
ListView_SetItem(g_hListView, &lvi);
|
||
|
|
||
|
// Get the date format, so we are localizable...
|
||
|
MyLoadString(szBuffer, IDS_UNKNOWN);
|
||
|
iRet = GetDateFormat( LOCALE_SYSTEM_DEFAULT,
|
||
|
DATE_SHORTDATE,
|
||
|
&lpFileNode->LastModified,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
0);
|
||
|
if (iRet) {
|
||
|
lpString = MALLOC((iRet + 1) * sizeof(TCHAR));
|
||
|
|
||
|
if (lpString) {
|
||
|
|
||
|
iRet = GetDateFormat( LOCALE_SYSTEM_DEFAULT,
|
||
|
DATE_SHORTDATE,
|
||
|
&lpFileNode->LastModified,
|
||
|
NULL,
|
||
|
lpString,
|
||
|
iRet);
|
||
|
|
||
|
if (iRet) {
|
||
|
lstrcpy(szBuffer, lpString);
|
||
|
}
|
||
|
|
||
|
FREE(lpString);
|
||
|
}
|
||
|
}
|
||
|
lvi.mask = LVIF_TEXT;
|
||
|
lvi.iSubItem = 2;
|
||
|
lvi.pszText = szBuffer;
|
||
|
ListView_SetItem(g_hListView, &lvi);
|
||
|
|
||
|
// Insert the filetype string into the fourth column.
|
||
|
if (lpFileNode->lpTypeName) {
|
||
|
lstrcpy(szBuffer, lpFileNode->lpTypeName);
|
||
|
} else MyLoadString(szBuffer, IDS_UNKNOWN);
|
||
|
lvi.mask = LVIF_TEXT;
|
||
|
lvi.iSubItem = 3;
|
||
|
lvi.pszText = szBuffer;
|
||
|
ListView_SetItem(g_hListView, &lvi);
|
||
|
|
||
|
// Insert the version string into the fifth column.
|
||
|
if (lpFileNode->lpVersion) {
|
||
|
lstrcpy(szBuffer, lpFileNode->lpVersion);
|
||
|
} else MyLoadString(szBuffer, IDS_NOVERSION);
|
||
|
lvi.mask = LVIF_TEXT;
|
||
|
lvi.iSubItem = 4;
|
||
|
lvi.pszText = szBuffer;
|
||
|
ListView_SetItem(g_hListView, &lvi);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Initialize the listview dialog. First, we are going to load the global icon resource.
|
||
|
// Then we are going to create a status window and the actual listview control.
|
||
|
// Then we need to add the four columns and work out their default widths.
|
||
|
//
|
||
|
BOOL ListView_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam)
|
||
|
{
|
||
|
LV_COLUMN lvc;
|
||
|
RECT rect, rect2, rect3, rect4, rect5;
|
||
|
TCHAR szBuffer[MAX_PATH];
|
||
|
TCHAR szBuffer2[MAX_PATH];
|
||
|
INT iCol = 0, iWidth = 0;
|
||
|
|
||
|
// Load the global icon resource
|
||
|
if (g_App.hIcon) {
|
||
|
SetClassLongPtr(hwnd, GCLP_HICON, (LONG_PTR) g_App.hIcon);
|
||
|
}
|
||
|
|
||
|
// Create the status window at the bottom of the dialog
|
||
|
g_hStatus = CreateStatusWindow( WS_CHILD | WS_VISIBLE,
|
||
|
NULL,
|
||
|
hwnd,
|
||
|
(UINT) IDC_STATUSWINDOW);
|
||
|
|
||
|
// Load the status string and fill it in with the correct values.
|
||
|
MyLoadString(szBuffer, IDS_NUMFILES);
|
||
|
wsprintf(szBuffer2, szBuffer, g_App.dwFiles, g_App.dwSigned, g_App.dwUnsigned,
|
||
|
g_App.dwFiles - g_App.dwSigned - g_App.dwUnsigned);
|
||
|
SendMessage(g_hStatus, WM_SETTEXT, (WPARAM) 0, (LPARAM) szBuffer2);
|
||
|
|
||
|
GetWindowRect(hwnd, &g_Rect);
|
||
|
|
||
|
// Get the windows RECT values for the dialog, the static text, and the status window.
|
||
|
// We will use these values to figure out where to put the listview and the columns.
|
||
|
GetWindowRect(hwnd, &rect);
|
||
|
GetWindowRect(GetDlgItem(hwnd, IDC_RESULTSTEXT), &rect2);
|
||
|
GetWindowRect(g_hStatus, &rect3);
|
||
|
GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rect4);
|
||
|
|
||
|
MoveWindow( GetDlgItem(hwnd, IDCANCEL),
|
||
|
rect.right - rect2.left - (rect4.right - rect4.left) - (( 2 * (rect2.left - rect.left)) / 3),
|
||
|
rect.bottom - rect.top - (( 7 * (rect4.bottom - rect4.top)) / 2),
|
||
|
rect4.right - rect4.left,
|
||
|
rect4.bottom - rect4.top,
|
||
|
TRUE);
|
||
|
|
||
|
//
|
||
|
// Create the listview window! I am using some really screwey logic to figure out how
|
||
|
// big to make the listview and where to put it, but it seems to work.
|
||
|
//
|
||
|
g_hListView = CreateWindowEx( WS_EX_CLIENTEDGE,
|
||
|
WC_LISTVIEW, TEXT(""),
|
||
|
WS_TABSTOP | WS_VSCROLL | WS_VISIBLE | WS_CHILD | WS_BORDER |
|
||
|
LVS_SINGLESEL | LVS_REPORT | LVS_AUTOARRANGE | LVS_SHAREIMAGELISTS,
|
||
|
((rect2.left - rect.left) * 2) / 3,
|
||
|
(rect2.bottom - rect2.top) * 2,
|
||
|
(rect.right - rect.left) - 2 * (rect2.left - rect.left),
|
||
|
(rect.bottom - rect2.bottom) - (rect4 .bottom - rect4.top) - 3 * (rect3.bottom - rect3.top),
|
||
|
hwnd,
|
||
|
(HMENU) IDC_LISTVIEW,
|
||
|
g_App.hInstance,
|
||
|
NULL);
|
||
|
|
||
|
// If the CreateWindowEx failed, then bail.
|
||
|
if (!g_hListView)
|
||
|
return FALSE;
|
||
|
|
||
|
GetWindowRect(g_hListView, &rect5);
|
||
|
|
||
|
// Initialize the icon lists
|
||
|
ListView_SetImageLists(g_hListView);
|
||
|
|
||
|
// Create the first listview column for the icon and the file name.
|
||
|
lvc.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
|
||
|
lvc.fmt = LVCFMT_LEFT;
|
||
|
lvc.cx = (rect2.right - rect2.left) / 5;
|
||
|
lvc.pszText = szBuffer;
|
||
|
MyLoadString(szBuffer, IDS_COL_NAME);
|
||
|
lvc.cchTextMax = MAX_PATH;
|
||
|
ListView_InsertColumn(g_hListView, iCol++, &lvc);
|
||
|
|
||
|
// Create the second listview column for the directory name.
|
||
|
iWidth += lvc.cx;
|
||
|
lvc.cx = (rect2.right - rect2.left) / 4;
|
||
|
MyLoadString(szBuffer, IDS_COL_FOLDER);
|
||
|
ListView_InsertColumn(g_hListView, iCol++, &lvc);
|
||
|
|
||
|
// Create the third listview column for the date name.
|
||
|
iWidth += lvc.cx;
|
||
|
lvc.cx = (rect2.right - rect2.left) / 6;
|
||
|
lvc.fmt = LVCFMT_CENTER;
|
||
|
MyLoadString(szBuffer, IDS_COL_DATE);
|
||
|
ListView_InsertColumn(g_hListView, iCol++, &lvc);
|
||
|
|
||
|
// Create the fourth listview column for the filetype string.
|
||
|
iWidth += lvc.cx;
|
||
|
lvc.cx = (rect2.right - rect2.left) / 6;
|
||
|
lvc.fmt = LVCFMT_CENTER;
|
||
|
MyLoadString(szBuffer, IDS_COL_TYPE);
|
||
|
ListView_InsertColumn(g_hListView, iCol++, &lvc);
|
||
|
|
||
|
// Create the fifth listview column for the version string.
|
||
|
iWidth += lvc.cx;
|
||
|
lvc.cx = (rect2.right - rect2.left) - iWidth - 5;
|
||
|
lvc.fmt = LVCFMT_CENTER;
|
||
|
MyLoadString(szBuffer, IDS_COL_VERSION);
|
||
|
ListView_InsertColumn(g_hListView, iCol++, &lvc);
|
||
|
|
||
|
// Now that the columns are set up, insert all the files in g_App.lpFileList!
|
||
|
ListView_InsertItems();
|
||
|
|
||
|
// Initialize the sorting order array to all FALSE.
|
||
|
g_bSortOrder[0] = FALSE;
|
||
|
g_bSortOrder[1] = FALSE;
|
||
|
g_bSortOrder[2] = FALSE;
|
||
|
g_bSortOrder[3] = FALSE;
|
||
|
|
||
|
SetForegroundWindow(g_App.hDlg);
|
||
|
SetForegroundWindow(hwnd);
|
||
|
SetFocus(GetDlgItem(hwnd, IDCANCEL));
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// This function checks to see how big the sizing rectangle will be. If the user is trying
|
||
|
// to size the dialog to less than the values in g_Rect, then we will fix the rectangle values
|
||
|
//
|
||
|
BOOL ListView_OnSizing(HWND hwnd, WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
RECT rect;
|
||
|
LPRECT lpRect = (LPRECT) lParam;
|
||
|
BOOL bRet = FALSE;
|
||
|
|
||
|
GetWindowRect(hwnd, &rect);
|
||
|
|
||
|
if ((lpRect->right - lpRect->left) < (g_Rect.right - g_Rect.left)) {
|
||
|
lpRect->left = rect.left;
|
||
|
lpRect->right = lpRect->left + (g_Rect.right - g_Rect.left);
|
||
|
bRet = TRUE;
|
||
|
}
|
||
|
|
||
|
if ((lpRect->bottom - lpRect->top) < (g_Rect.bottom - g_Rect.top)) {
|
||
|
lpRect->top = rect.top;
|
||
|
lpRect->bottom = lpRect->top + (g_Rect.bottom - g_Rect.top);
|
||
|
bRet = TRUE;
|
||
|
}
|
||
|
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// This function allows us to resize the listview control and status windows when the
|
||
|
// user resizes the results dialog. Thankfully, we can make everything relative using
|
||
|
// the RECT values for the main dialog, the static text, and the status window.
|
||
|
//
|
||
|
void ListView_ResizeWindow(HWND hwnd)
|
||
|
{
|
||
|
RECT rect, rect2, rect3, rect4;
|
||
|
|
||
|
GetWindowRect(hwnd, &rect);
|
||
|
|
||
|
if ((rect.right - rect.left) < (g_Rect.right - g_Rect.left)) {
|
||
|
MoveWindow(hwnd,
|
||
|
rect.left,
|
||
|
rect.top,
|
||
|
g_Rect.right - g_Rect.left,
|
||
|
rect.bottom - rect.top,
|
||
|
TRUE);
|
||
|
}
|
||
|
|
||
|
if ((rect.bottom - rect.top) < (g_Rect.bottom - g_Rect.top)) {
|
||
|
MoveWindow(hwnd,
|
||
|
rect.left,
|
||
|
rect.top,
|
||
|
rect.right - rect.left,
|
||
|
g_Rect.bottom - g_Rect.top,
|
||
|
TRUE);
|
||
|
}
|
||
|
|
||
|
GetWindowRect(GetDlgItem(hwnd, IDC_RESULTSTEXT), &rect2);
|
||
|
GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rect4);
|
||
|
GetWindowRect(g_hStatus, &rect3);
|
||
|
|
||
|
|
||
|
MoveWindow(g_hListView,
|
||
|
((rect2.left - rect.left) * 2) / 3,
|
||
|
(rect2.bottom - rect2.top) * 2,
|
||
|
(rect.right - rect.left) - 2 * (rect2.left - rect.left),
|
||
|
(rect.bottom - rect2.bottom) - (rect4 .bottom - rect4.top) - 3 * (rect3.bottom - rect3.top),
|
||
|
TRUE);
|
||
|
|
||
|
MoveWindow(g_hStatus,
|
||
|
0,
|
||
|
(rect.bottom - rect.top) - (rect3.bottom - rect3.top),
|
||
|
rect.right - rect.left,
|
||
|
rect3.bottom - rect3.top,
|
||
|
TRUE);
|
||
|
|
||
|
MoveWindow(GetDlgItem(hwnd, IDCANCEL),
|
||
|
rect.right - rect2.left - (rect4.right - rect4.left) - (( 2 * (rect2.left - rect.left)) / 3),
|
||
|
rect.bottom - rect.top - ((7 * (rect4.bottom - rect4.top)) / 2),
|
||
|
rect4.right - rect4.left,
|
||
|
rect4.bottom - rect4.top,
|
||
|
TRUE);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// This function is a callback that returns a value for ListView_SortItems.
|
||
|
// ListView_SortItems wants a negative, zero, or positive number.
|
||
|
// Since CompareString returns 1,2,3 we just subtract 2 from the return value.
|
||
|
//
|
||
|
// We use the g_bSortOrder array to figure out which way we have sorted in the past.
|
||
|
//
|
||
|
// Warning: we don't check for error values from CompareString
|
||
|
//
|
||
|
int CALLBACK ListView_CompareNames(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
|
||
|
{
|
||
|
LPFILENODE lpFileNode1;
|
||
|
LPFILENODE lpFileNode2;
|
||
|
FILETIME FileTime1, FileTime2;
|
||
|
int iResult = 2;
|
||
|
|
||
|
//
|
||
|
// Depending on the sort order, we swap the order of comparison
|
||
|
//
|
||
|
if (g_bSortOrder[lParamSort]) {
|
||
|
lpFileNode2 = (LPFILENODE) lParam1;
|
||
|
lpFileNode1 = (LPFILENODE) lParam2;
|
||
|
} else {
|
||
|
lpFileNode1 = (LPFILENODE) lParam1;
|
||
|
lpFileNode2 = (LPFILENODE) lParam2;
|
||
|
}
|
||
|
|
||
|
switch (lParamSort) {
|
||
|
// We are comparing the file names
|
||
|
case 0: iResult = CompareString(LOCALE_SYSTEM_DEFAULT,
|
||
|
NORM_IGNORECASE | NORM_IGNOREWIDTH,
|
||
|
lpFileNode1->lpFileName,
|
||
|
-1,
|
||
|
lpFileNode2->lpFileName,
|
||
|
-1);
|
||
|
break;
|
||
|
|
||
|
// We are comparing the directory names
|
||
|
case 1: iResult = CompareString(LOCALE_SYSTEM_DEFAULT,
|
||
|
NORM_IGNORECASE | NORM_IGNOREWIDTH,
|
||
|
lpFileNode1->lpDirName,
|
||
|
-1,
|
||
|
lpFileNode2->lpDirName,
|
||
|
-1);
|
||
|
break;
|
||
|
|
||
|
// We are comparing the LastWriteTime's between the two files.
|
||
|
case 2: SystemTimeToFileTime(&lpFileNode1->LastModified, &FileTime1);
|
||
|
SystemTimeToFileTime(&lpFileNode2->LastModified, &FileTime2);
|
||
|
iResult = CompareFileTime(&FileTime1, &FileTime2);
|
||
|
return iResult;
|
||
|
|
||
|
break;
|
||
|
|
||
|
// We are comparing the filetype strings
|
||
|
case 3: iResult = CompareString(LOCALE_SYSTEM_DEFAULT,
|
||
|
NORM_IGNORECASE | NORM_IGNOREWIDTH,
|
||
|
lpFileNode1->lpTypeName,
|
||
|
-1,
|
||
|
lpFileNode2->lpTypeName,
|
||
|
-1);
|
||
|
break;
|
||
|
|
||
|
// We are comparing the version strings
|
||
|
case 4: iResult = CompareString(LOCALE_SYSTEM_DEFAULT,
|
||
|
NORM_IGNORECASE | NORM_IGNOREWIDTH,
|
||
|
lpFileNode1->lpVersion,
|
||
|
-1,
|
||
|
lpFileNode2->lpVersion,
|
||
|
-1);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return(iResult - 2);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// This function handles the clicks on the column headers and calls ListView_SortItems with the
|
||
|
// ListView_CompareNames callback previously defined. It then toggles the sortorder for that column.
|
||
|
//
|
||
|
LRESULT ListView_NotifyHandler(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
NMHDR *lpnmhdr = (NMHDR *) lParam;
|
||
|
NM_LISTVIEW *lpnmlv = (NM_LISTVIEW *) lParam;
|
||
|
|
||
|
switch (lpnmhdr->code) {
|
||
|
case LVN_COLUMNCLICK:
|
||
|
switch (lpnmlv->iSubItem) {
|
||
|
case 0:
|
||
|
case 1:
|
||
|
case 2:
|
||
|
case 3:
|
||
|
case 4: ListView_SortItems(lpnmlv->hdr.hwndFrom, ListView_CompareNames, (LPARAM) lpnmlv->iSubItem);
|
||
|
g_bSortOrder[lpnmlv->iSubItem] = !(g_bSortOrder[lpnmlv->iSubItem]);
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// The only thing we look for here is the IDCANCEL if the user hit ESCAPE
|
||
|
//
|
||
|
void ListView_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
|
||
|
{
|
||
|
switch (id) {
|
||
|
case IDCANCEL:
|
||
|
SendMessage(hwnd, WM_CLOSE, 0, 0);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
INT_PTR CALLBACK ListView_DlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
BOOL fProcessed = TRUE;
|
||
|
|
||
|
switch (uMsg) {
|
||
|
HANDLE_MSG(hwnd, WM_INITDIALOG, ListView_OnInitDialog);
|
||
|
HANDLE_MSG(hwnd, WM_COMMAND, ListView_OnCommand);
|
||
|
|
||
|
case WM_NOTIFY:
|
||
|
return ListView_NotifyHandler(hwnd, uMsg, wParam, lParam);
|
||
|
|
||
|
case WM_CLOSE:
|
||
|
if (g_hStatus) {
|
||
|
DestroyWindow(g_hStatus);
|
||
|
g_hStatus = NULL;
|
||
|
}
|
||
|
|
||
|
if (g_hListView) {
|
||
|
DestroyWindow(g_hListView);
|
||
|
g_hListView = NULL;
|
||
|
}
|
||
|
|
||
|
EndDialog(hwnd, ID_CLOSE);
|
||
|
break;
|
||
|
|
||
|
case WM_SIZING:
|
||
|
fProcessed = ListView_OnSizing(hwnd, wParam, lParam);
|
||
|
break;
|
||
|
|
||
|
case WM_SIZE:
|
||
|
ListView_ResizeWindow(hwnd);
|
||
|
break;
|
||
|
|
||
|
default: fProcessed = FALSE;
|
||
|
}
|
||
|
|
||
|
return fProcessed;
|
||
|
}
|