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.
 
 
 
 
 
 

661 lines
22 KiB

//
// 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;
BOOL bMirroredApp;
HRESULT hr;
bMirroredApp = (GetWindowLong(g_App.hDlg, GWL_EXSTYLE) & WS_EX_LAYOUTRTL);
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, cA(szBuffer), IDS_UNKNOWN);
iRet = GetDateFormat(LOCALE_SYSTEM_DEFAULT,
bMirroredApp ?
DATE_RTLREADING | DATE_SHORTDATE :
DATE_SHORTDATE,
&lpFileNode->LastModified,
NULL,
NULL,
0);
if (iRet) {
lpString = MALLOC((iRet + 1) * sizeof(TCHAR));
if (lpString) {
iRet = GetDateFormat(LOCALE_SYSTEM_DEFAULT,
bMirroredApp ?
DATE_RTLREADING | DATE_SHORTDATE :
DATE_SHORTDATE,
&lpFileNode->LastModified,
NULL,
lpString,
iRet);
if (iRet) {
hr = StringCchCopy(szBuffer, cA(szBuffer), lpString);
if (FAILED(hr) && (hr != STRSAFE_E_INSUFFICIENT_BUFFER)) {
//
// If we failed to copy the date into our buffer for
// some reason other than insufficient buffer space,
// then set the date to the empty string.
//
szBuffer[0] = TEXT('\0');
}
}
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) {
//
// Since this string is just being displayed in the UI, it
// is OK if it gets truncated.
//
hr = StringCchCopy(szBuffer, cA(szBuffer), lpFileNode->lpTypeName);
if (FAILED(hr) &&
(hr != STRSAFE_E_INSUFFICIENT_BUFFER)) {
//
// We encountered some error other than insufficient
// buffer, so just set the buffer to the empty string,
// since it value is not determined with this type of
// failure.
//
szBuffer[0] = TEXT('\0');
}
} else {
MyLoadString(szBuffer, cA(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) {
//
// Since this string is just being displayed in the UI, it
// is OK if it gets truncated.
//
hr = StringCchCopy(szBuffer, cA(szBuffer), lpFileNode->lpVersion);
if (FAILED(hr) &&
(hr != STRSAFE_E_INSUFFICIENT_BUFFER)) {
//
// We encountered some error other than insufficient
// buffer, so just set the buffer to the empty string,
// since it value is not determined with this type of
// failure.
//
szBuffer[0] = TEXT('\0');
}
} else {
MyLoadString(szBuffer, cA(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, rectResultsText, rectStatusBar, rectCancelButton, rectClient;
TCHAR szBuffer[MAX_PATH];
TCHAR szBuffer2[MAX_PATH];
INT iCol = 0, iWidth = 0;
HRESULT hr;
UNREFERENCED_PARAMETER(hwndFocus);
UNREFERENCED_PARAMETER(lParam);
//
// 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, cA(szBuffer), IDS_NUMFILES);
hr = StringCchPrintf(szBuffer2,
cA(szBuffer2),
szBuffer,
g_App.dwFiles,
g_App.dwSigned,
g_App.dwUnsigned,
g_App.dwFiles - g_App.dwSigned - g_App.dwUnsigned);
if (FAILED(hr) &&
(hr != STRSAFE_E_INSUFFICIENT_BUFFER)) {
//
// We encountered some error other than insufficient
// buffer, so just set the buffer to the empty string,
// since it value is not determined with this type of
// failure.
//
szBuffer2[0] = TEXT('\0');
}
SendMessage(g_hStatus, WM_SETTEXT, (WPARAM) 0, (LPARAM) szBuffer2);
GetWindowRect(hwnd, &g_Rect);
GetClientRect(hwnd, &rectClient);
//
// 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), &rectResultsText);
GetWindowRect(g_hStatus, &rectStatusBar);
GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancelButton);
MoveWindow(GetDlgItem(hwnd, IDCANCEL),
(GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_LAYOUTRTL)
? (rect.right - rect.left) - (rectCancelButton.right - rectCancelButton.left) - (rect.right - rectResultsText.right)
: (rect.right - rectResultsText.left) - (rectCancelButton.right - rectCancelButton.left) - (( 2 * (rectResultsText.left - rect.left)) / 3),
(rectClient.bottom - rectClient.top) - (rectStatusBar.bottom - rectStatusBar.top) - (rectCancelButton.bottom - rectCancelButton.top) - 10,
rectCancelButton.right - rectCancelButton.left,
rectCancelButton.bottom - rectCancelButton.top,
TRUE);
GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancelButton);
//
// 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,
((rectResultsText.left - rect.left) * 2) / 3,
(rectResultsText.bottom - rectResultsText.top) * 2,
(rect.right - rect.left) - 2 * (rectResultsText.left - rect.left),
rectCancelButton.top - rectResultsText.bottom - 20,
hwnd,
(HMENU) IDC_LISTVIEW,
g_App.hInstance,
NULL);
//
// If the CreateWindowEx failed, then bail.
//
if (!g_hListView) {
return FALSE;
}
//
// 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 = (rectResultsText.right - rectResultsText.left) / 5;
lvc.pszText = szBuffer;
MyLoadString(szBuffer, cA(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 = (rectResultsText.right - rectResultsText.left) / 4;
MyLoadString(szBuffer, cA(szBuffer), IDS_COL_FOLDER);
ListView_InsertColumn(g_hListView, iCol++, &lvc);
//
// Create the third listview column for the date name.
//
iWidth += lvc.cx;
lvc.cx = (rectResultsText.right - rectResultsText.left) / 6;
lvc.fmt = LVCFMT_CENTER;
MyLoadString(szBuffer, cA(szBuffer), IDS_COL_DATE);
ListView_InsertColumn(g_hListView, iCol++, &lvc);
//
// Create the fourth listview column for the filetype string.
//
iWidth += lvc.cx;
lvc.cx = (rectResultsText.right - rectResultsText.left) / 6;
lvc.fmt = LVCFMT_CENTER;
MyLoadString(szBuffer, cA(szBuffer), IDS_COL_TYPE);
ListView_InsertColumn(g_hListView, iCol++, &lvc);
//
// Create the fifth listview column for the version string.
//
iWidth += lvc.cx;
lvc.cx = (rectResultsText.right - rectResultsText.left) - iWidth - 5;
lvc.fmt = LVCFMT_CENTER;
MyLoadString(szBuffer, cA(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;
UNREFERENCED_PARAMETER(wParam);
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, rectResultsText, rectStatusBar, rectCancelButton, rectClient;
BOOL bMirroredApp;
bMirroredApp = (GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_LAYOUTRTL);
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);
}
GetClientRect(hwnd, &rectClient);
GetWindowRect(GetDlgItem(hwnd, IDC_RESULTSTEXT), &rectResultsText);
GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancelButton);
GetWindowRect(g_hStatus, &rectStatusBar);
MoveWindow(g_hStatus,
0,
(rect.bottom - rect.top) - (rectStatusBar.bottom - rectStatusBar.top),
rect.right - rect.left,
rectStatusBar.bottom - rectStatusBar.top,
TRUE);
MoveWindow(GetDlgItem(hwnd, IDCANCEL),
(GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_LAYOUTRTL)
? (rect.right - rect.left) - (rectCancelButton.right - rectCancelButton.left) - (rect.right - rectResultsText.right)
: (rect.right - rectResultsText.left) - (rectCancelButton.right - rectCancelButton.left) - (( 2 * (rectResultsText.left - rect.left)) / 3),
(rectClient.bottom - rectClient.top) - (rectStatusBar.bottom - rectStatusBar.top) - (rectCancelButton.bottom - rectCancelButton.top) - 10,
rectCancelButton.right - rectCancelButton.left,
rectCancelButton.bottom - rectCancelButton.top,
TRUE);
GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancelButton);
MoveWindow(g_hListView,
bMirroredApp
? ((rect.right - rectResultsText.right) * 2) / 3
: ((rectResultsText.left - rect.left) * 2) / 3,
(rectResultsText.bottom - rectResultsText.top) * 2,
bMirroredApp
? (rect.right - rect.left) - 2 * (rect.right - rectResultsText.right)
: (rect.right - rect.left) - 2 * (rectResultsText.left - rect.left),
rectCancelButton.top - rectResultsText.bottom - 20,
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) {
case 0:
//
// We are comparing the file names
//
iResult = CompareString(LOCALE_SYSTEM_DEFAULT,
NORM_IGNORECASE | NORM_IGNOREWIDTH,
lpFileNode1->lpFileName,
-1,
lpFileNode2->lpFileName,
-1);
break;
case 1:
//
// We are comparing the directory names
//
iResult = CompareString(LOCALE_SYSTEM_DEFAULT,
NORM_IGNORECASE | NORM_IGNOREWIDTH,
lpFileNode1->lpDirName,
-1,
lpFileNode2->lpDirName,
-1);
break;
case 2:
//
// We are comparing the LastWriteTime's between the two files.
//
SystemTimeToFileTime(&lpFileNode1->LastModified, &FileTime1);
SystemTimeToFileTime(&lpFileNode2->LastModified, &FileTime2);
iResult = CompareFileTime(&FileTime1, &FileTime2);
return iResult;
break;
case 3:
//
// We are comparing the filetype strings
//
iResult = CompareString(LOCALE_SYSTEM_DEFAULT,
NORM_IGNORECASE | NORM_IGNOREWIDTH,
lpFileNode1->lpTypeName,
-1,
lpFileNode2->lpTypeName,
-1);
break;
case 4:
//
// We are comparing the version strings
//
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;
UNREFERENCED_PARAMETER(hwnd);
UNREFERENCED_PARAMETER(uMsg);
UNREFERENCED_PARAMETER(wParam);
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)
{
UNREFERENCED_PARAMETER(hwndCtl);
UNREFERENCED_PARAMETER(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;
}