600 lines
17 KiB
C
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;
|
|
}
|