windows-nt/Source/XPSP1/NT/base/fs/utils/scandisk/main.c
2020-09-26 16:20:57 +08:00

600 lines
17 KiB
C

//////////////////////////////////////////////////////////////////////////////
//
// MAIN.C / ChkDskW
//
// Microsoft Confidential
// Copyright (c) Microsoft Corporation 1998
// All rights reserved
//
// 8/98 - Jason Cohen (JCOHEN)
//
//////////////////////////////////////////////////////////////////////////////
// Include file(s).
//
#include "main.h"
#include <stdlib.h>
#include <shellapi.h>
// Global variable(s).
//
HINSTANCE g_hInstance;
DWORD g_dwDrives;
DWORD g_dwFlags;
TCHAR g_cSageId;
// Internal function prototype(s).
//
static INT_PTR CALLBACK Dlg_Proc(HWND, UINT, WPARAM, LPARAM);
static BOOL Dlg_OnInitDialog(HWND, HWND, LPARAM);
static VOID Dlg_OnCommand(HWND, INT, HWND, UINT);
static BOOL Dlg_OnDrawItem(HWND, const DRAWITEMSTRUCT *);
static VOID SetSageSettings(HWND, TCHAR);
static VOID RunSageSettings(HWND, TCHAR);
static DWORD GetSelectedDrives(HWND, DWORD);
static BOOL TanslateCommandLine(LPTSTR);
static VOID ProcessCommandLine(VOID);
static DWORD GetCommandLineOptions(LPTSTR **);
// External function prototype(s).
//
HANDLE SpawnChkdsk(HWND, DWORD);
WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT nCmdShow)
{
INT nReturn;
g_hInstance = hInstance;
g_dwFlags = 0;
g_dwDrives = 0;
ProcessCommandLine();
nReturn = (INT)DialogBox(hInstance, MAKEINTRESOURCE(IDD_MAIN), NULL, (DLGPROC) Dlg_Proc);
return nReturn;
}
static INT_PTR CALLBACK Dlg_Proc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
// Message cracking macros.
//
HANDLE_MSG(hDlg, WM_INITDIALOG, Dlg_OnInitDialog);
HANDLE_MSG(hDlg, WM_COMMAND, Dlg_OnCommand);
case WM_DRAWITEM:
return Dlg_OnDrawItem(hDlg, (const DRAWITEMSTRUCT *) lParam);
case WM_CLOSE:
if ( g_dwFlags & SCANDISK_SCANNING )
g_dwFlags |= SCANDISK_CANCELSCAN;
else
EndDialog(hDlg, 0);
default:
return FALSE;
}
return TRUE;
}
static BOOL Dlg_OnInitDialog(HWND hDlg, HWND hwndFocus, LPARAM lParam)
{
TCHAR szBuffer[256];
LPTSTR lpBuffer;
INT nIndex;
UINT uDriveType;
DWORD dwMask,
dwDefault;
TCHAR chDrive[] = _T("A:\\");
SHFILEINFO SHFileInfo;
// Init the common control library (for the progress bar).
//
InitCommonControls();
// Set the icon for the dialog.
//
SetClassLongPtr(hDlg, GCLP_HICON, (LONG_PTR) LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_MAIN)));
// Load any SAGERUN settings.
//
if ( g_dwFlags & SCANDISK_SAGERUN )
RunSageSettings(hDlg, g_cSageId);
// Get the system drive so we know what to default to if there
// are not already default drives specified in g_dwDrives.
//
if ( g_dwDrives )
dwDefault = g_dwDrives;
else
{
szBuffer[0] = _T('\0');
if ( GetEnvironmentVariable(_T("SystemDrive"), szBuffer, sizeof(szBuffer)) && szBuffer[0] )
dwDefault = 1 << (UPPER(szBuffer[0]) - _T('A'));
else
dwDefault = 4; // Default to the C: drive.
}
// Populate the list box with the drives to scan.
//
g_dwDrives = GetLogicalDrives();
for (dwMask = 1; g_dwDrives & ~(dwMask - 1); dwMask <<= 1)
{
// Is there a logical drive?
//
if ( g_dwDrives & dwMask )
{
// Reset this bit, we will or it back in if it gets
// added to the list box.
//
g_dwDrives &= ~dwMask;
// Check the drive type and it is
// removable or fixed, add it to the
// list box along with the icon.
//
uDriveType = GetDriveType(chDrive);
if ( ( uDriveType == DRIVE_FIXED ) ||
( uDriveType == DRIVE_REMOVABLE ) )
{
SHGetFileInfo(chDrive, 0, &SHFileInfo, sizeof(SHFILEINFO), SHGFI_ICON | SHGFI_SMALLICON | SHGFI_DISPLAYNAME | SHGFI_TYPENAME);
if ( (nIndex = (INT)SendDlgItemMessage(hDlg, IDC_DRIVES, LB_ADDSTRING, 0, (LPARAM) (LPCTSTR) SHFileInfo.szDisplayName)) >= 0 )
{
// Or back in this bit because we successfully added
// the drive to the list box.
//
g_dwDrives |= dwMask;
SendDlgItemMessage(hDlg, IDC_DRIVES, LB_SETITEMDATA, nIndex, (LPARAM) SHFileInfo.hIcon);
// If this is the boot drive, we want to selecte it.
//
if (dwMask & dwDefault)
SendDlgItemMessage(hDlg, IDC_DRIVES, LB_SETSEL, TRUE, (LPARAM) nIndex);
}
}
}
// Go look at the next drive
//
chDrive[0]++;
}
// Check for if we are in the SAGESET mode.
//
if ( g_dwFlags & SCANDISK_SAGESET )
{
if ( lpBuffer = AllocateString(NULL, IDS_OK) )
{
SetDlgItemText(hDlg, IDOK, lpBuffer);
FREE(lpBuffer);
}
if ( lpBuffer = AllocateString(NULL, IDS_CANCEL) )
{
SetDlgItemText(hDlg, IDCANCEL, lpBuffer);
FREE(lpBuffer);
}
ShowWindow(GetDlgItem(hDlg, IDC_PROGRESS), SW_HIDE);
}
// Set the estimated time.
//
srand(GetTickCount());
wsprintf(szBuffer, _T("%d hour(s) %d minute(s)"), RANDOM(0, 1), RANDOM(1, 59));
SetDlgItemText(hDlg, IDC_ESTIMATED, szBuffer);
// Set the default option.
//
CheckRadioButton(hDlg, IDC_FIX, IDC_REMIND, IDC_FIX);
EnableWindow(GetDlgItem(hDlg, IDC_TIME), FALSE);
// Set the default remind time.
//
SetDlgItemText(hDlg, IDC_TIME, _T("5:00 PM"));
// Set the focus to the default button.
//
SetFocus(GetDlgItem(hDlg, IDOK));
// If we are in SAGERUN mode, start the scan automatically.
//
if ( g_dwFlags & SCANDISK_SAGERUN )
{
if ( SpawnChkdsk(hDlg, g_dwDrives) == NULL )
EndDialog(hDlg, 0);
}
return FALSE;
}
static VOID Dlg_OnCommand(HWND hDlg, INT id, HWND hwndCtl, UINT codeNotify)
{
switch (id)
{
case IDOK:
if ( g_dwFlags & SCANDISK_SAGESET )
{
// Just save the settings and end the dialog.
//
SetSageSettings(hDlg, g_cSageId);
EndDialog(hDlg, 0);
}
else
{
// Run chkdsk on the drive(s).
//
if ( SpawnChkdsk(hDlg, g_dwDrives) == NULL )
EndDialog(hDlg, 0);
}
break;
case IDCANCEL:
if ( g_dwFlags & SCANDISK_SCANNING )
g_dwFlags |= SCANDISK_CANCELSCAN;
else
EndDialog(hDlg, 0);
break;
case IDC_RESTART:
case IDC_SKIP:
case IDC_REMIND:
EnableWindow(GetDlgItem(hDlg, IDC_TIME), id == IDC_REMIND);
break;
}
}
static BOOL Dlg_OnDrawItem(HWND hWnd, const DRAWITEMSTRUCT * lpDrawItem)
{
HICON hIcon;
TCHAR szBuffer[MAX_PATH];
BOOL bRestore = FALSE;
COLORREF crText,
crBk;
DWORD dwColor;
RECT rect;
HBRUSH hbrBack;
// Make sure we are drawing the right control and an item.
//
if ( lpDrawItem->CtlID != IDC_DRIVES )
return FALSE;
switch ( lpDrawItem->itemAction )
{
case ODA_SELECT:
case ODA_DRAWENTIRE:
if (lpDrawItem->itemState & ODS_SELECTED)
{
// Set new text/background colors and store the old ones away.
//
crText = SetTextColor(lpDrawItem->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
crBk = SetBkColor(lpDrawItem->hDC, GetSysColor(COLOR_HIGHLIGHT));
// Restore the text and background colors when we are finished.
//
bRestore = TRUE;
// Get the hightlight color to fill in the listbox item.
//
dwColor = GetSysColor(COLOR_HIGHLIGHT);
}
else
{
// Get the window color so we can clear the listbox item.
//
dwColor = GetSysColor(COLOR_WINDOW);
}
// Fill entire item rectangle with the appropriate color
//
hbrBack = CreateSolidBrush(dwColor);
FillRect(lpDrawItem->hDC, &(lpDrawItem->rcItem), hbrBack);
DeleteObject(hbrBack);
// Display the icon associated with the item.
//
if ( hIcon = (HICON) SendMessage(lpDrawItem->hwndItem, LB_GETITEMDATA, lpDrawItem->itemID, (LPARAM) 0) )
{
DrawIconEx( lpDrawItem->hDC,
lpDrawItem->rcItem.left + 2,
lpDrawItem->rcItem.top,
hIcon,
lpDrawItem->rcItem.bottom - lpDrawItem->rcItem.top,
lpDrawItem->rcItem.bottom - lpDrawItem->rcItem.top,
0,
0,
DI_NORMAL);
}
// Display the text associated with the item.
//
if ( SendMessage(lpDrawItem->hwndItem, LB_GETTEXT, lpDrawItem->itemID, (LPARAM) szBuffer) >= 0 )
{
TextOut( lpDrawItem->hDC,
lpDrawItem->rcItem.left + lpDrawItem->rcItem.bottom - lpDrawItem->rcItem.top + 4,
lpDrawItem->rcItem.top + 1,
szBuffer,
lstrlen(szBuffer));
}
if (bRestore)
{
// Restore original text and background colors.
//
SetTextColor(lpDrawItem->hDC, crText);
SetBkColor(lpDrawItem->hDC, crBk);
}
break;
case ODA_FOCUS:
// Get rectangle coordinates for listbox item.
//
SendMessage(lpDrawItem->hwndItem, LB_GETITEMRECT, lpDrawItem->itemID, (LPARAM) &rect);
DrawFocusRect(lpDrawItem->hDC, &rect);
break;
}
return TRUE;
}
static VOID SetSageSettings(HWND hDlg, TCHAR cSageId)
{
TCHAR szRegKey[MAX_PATH + 1];
wsprintf(szRegKey, _T("%s\\%c"), SCANDISK_REGKEY_SAGE, cSageId);
RegSetDword(HKCU, szRegKey, SCANDISK_REGVAL_DRIVES, GetSelectedDrives(hDlg, g_dwDrives));
RegSetString(HKCU, szRegKey, SCANDISK_REGVAL_FIX, IsDlgButtonChecked(hDlg, IDC_AUTOFIX) ? _T("1") : _T("0"));
RegSetString(HKCU, szRegKey, SCANDISK_REGVAL_SURFACE, IsDlgButtonChecked(hDlg, IDC_SURFACE) ? _T("1") : _T("0"));
}
static VOID RunSageSettings(HWND hDlg, TCHAR cSageId)
{
TCHAR szRegKey[MAX_PATH + 1];
wsprintf(szRegKey, _T("%s\\%c"), SCANDISK_REGKEY_SAGE, cSageId);
g_dwDrives = RegGetDword(HKCU, szRegKey, SCANDISK_REGVAL_DRIVES);
CheckDlgButton(hDlg, IDC_AUTOFIX, RegCheck(HKCU, szRegKey, SCANDISK_REGVAL_FIX) ? BST_CHECKED : BST_UNCHECKED);
CheckDlgButton(hDlg, IDC_SURFACE, RegCheck(HKCU, szRegKey, SCANDISK_REGVAL_SURFACE) ? BST_CHECKED : BST_UNCHECKED);
}
static DWORD GetSelectedDrives(HWND hDlg, DWORD dwDrives)
{
TCHAR szDrive[] = _T("A:\\");
INT nCount,
nIndex;
LPINT lpnSelected,
lpnIndex;
DWORD dwMask;
// Get the number of selected items and allocate a buffer to hold all the indexs.
//
if ( ( (nCount = (INT)SendDlgItemMessage(hDlg, IDC_DRIVES, LB_GETSELCOUNT, 0, 0L)) > 0 ) &&
( lpnSelected = (LPINT) MALLOC(nCount * sizeof(INT)) ) )
{
// Now get the list of selected items.
//
if ( (nCount = (INT)SendDlgItemMessage(hDlg, IDC_DRIVES, LB_GETSELITEMS, nCount, (LPARAM) lpnSelected)) > 0 )
{
// Loop through all the drives in the list box to see if they
// are selected.
//
lpnIndex = lpnSelected;
nIndex = 0;
for (dwMask = 1; (DWORD) dwDrives & ~(dwMask - 1); dwMask <<= 1)
{
// Is this drive in the list box.
//
if ( (DWORD) dwDrives & dwMask )
{
// Test to see if this item is the
// next selected one.
//
if ( *lpnIndex == nIndex )
lpnIndex++;
else
// It isn't selected so set
// the bit to zero.
//
dwDrives &= ~dwMask;
// Keep an index of what list box
// item this should be.
//
nIndex++;
}
// Go look at the next drive
//
szDrive[0]++;
}
}
else
dwDrives = 0;
FREE(lpnSelected);
}
else
dwDrives = 0;
// Return drives selected (zero of failure).
//
return dwDrives;
}
static BOOL TanslateCommandLine(LPTSTR lpArg)
{
DWORD dwStrLen = lstrlen(lpArg);
BOOL bTranslated = TRUE;
// First check for the slash options.
//
if ( *lpArg == _T('/') )
{
// Get rid of the slash.
//
lpArg++;
// Check for /SAGESET:#
//
if ( _tcsncicmp(_T("SAGESET:"), lpArg, 8) == 0 )
{
if ( !(g_dwFlags & (SCANDISK_SAGESET | SCANDISK_SAGERUN) ) )
{
g_dwFlags |= SCANDISK_SAGESET;
g_cSageId = *(lpArg + 8);
}
}
// Check for /SAGERUN:#
//
else if ( _tcsncicmp(_T("SAGERUN:"), lpArg, 8) == 0 )
{
if ( !(g_dwFlags & (SCANDISK_SAGESET | SCANDISK_SAGERUN) ) )
{
g_dwFlags |= SCANDISK_SAGERUN;
g_cSageId = *(lpArg + 8);
}
}
// Unknown option.
//
else
bTranslated = FALSE;
}
else
{
// Check to see if it is a drive letter to auto select.
//
if ( ( UPPER(*lpArg) >= _T('A') ) && ( UPPER(*lpArg) <= _T('Z') ) && // Make sure the first character is a letter.
( ( dwStrLen == 1) || ( ( dwStrLen > 1 ) && ( *(lpArg + 1) == _T(':') ) ) ) ) // Make sure it is one character or the second is a colon.
{
g_dwDrives |= 1 << (UPPER(*lpArg) - _T('A'));
}
// Unknown option.
//
else
bTranslated = FALSE;
}
return bTranslated;
}
static VOID ProcessCommandLine()
{
LPTSTR *lpArgs = NULL;
DWORD dwArgs,
dwIndex;
dwArgs = GetCommandLineOptions(&lpArgs);
for (dwIndex = 1; dwIndex < dwArgs; dwIndex++)
TanslateCommandLine((LPTSTR) *(lpArgs + dwIndex));
FREE(lpArgs);
}
static DWORD GetCommandLineOptions(LPTSTR **lpArgs)
{
TCHAR cParse;
LPTSTR lpSearch,
lpCommandLine;
DWORD dwArgs = 0,
dwMaxArgs = 0xFFFFFFFF;
// Make sure we get the command line.
//
if ( (lpSearch = lpCommandLine = GetCommandLine()) == NULL )
return 0;
// Get the number of arguments so we can allocate
// the memory for the array of command line options.
//
if ( lpArgs )
{
if ( (dwMaxArgs = GetCommandLineOptions(NULL)) == 0 )
return 0;
if ( (*lpArgs = (LPTSTR *) MALLOC(sizeof(LPTSTR) * dwMaxArgs)) == NULL )
return 0;
}
// Now lets parse the arguments.
//
while ( *lpSearch && (dwArgs < dwMaxArgs) )
{
// Eat all preceeding spaces.
//
while ( *lpSearch == _T(' ') )
lpSearch++;
// Check to see if we need to look for a space or a quote
// to separate the next argument.
//
if ( *lpSearch == _T('"') )
cParse = *lpSearch++;
else
cParse = _T(' ');
// This is be the beginning of the next argument, but
// it isn't NULL terminated yet.
//
if ( lpArgs )
*(*lpArgs + dwArgs) = lpSearch;
dwArgs++;
// Go through all the characters until we hit a separator.
//
do
{
// Once we get to a quote, we just want to keep going
// until we get to a space.
//
if ( *lpSearch == _T('"') )
cParse = _T(' ');
// Only end when we reach the parsing character, which will
// always be the space by this time (but the space won't trigger
// the end until we hit a quote, if that is what we were originally
// looking for). We also need to make sure that we don't increment
// past the NULL terminator.
//
}
while ( ( *lpSearch != cParse ) && ( *lpSearch ) && ( *lpSearch++ ) );
// If the preceeding character is a quote, that is were we want to
// place the NULL terminator.
//
if ( ( lpSearch > lpCommandLine ) &&
( *(lpSearch - 1) == _T('"') ) )
lpSearch--;
// Set and increment past the NULL terminator only if we aren't already at
// the end if the string.
//
if ( lpArgs && *lpSearch )
*lpSearch++ = _T('\0');
else
if ( *lpSearch ) lpSearch++;
}
return dwArgs;
}