|
|
//////////////////////////////////////////////////////////////////////////////
//
// 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 "fmifs.h"
// Internal global variable(s).
//
static BOOL g_bSuccess; static HWND g_hProgressDlg; static HICON g_hIconScan[3];
// External global variable(s).
//
extern HINSTANCE g_hInstance; extern DWORD g_dwFlags;
// Internal function prototype(s).
//
static DWORD WINAPI ThreadChkdsk(LPVOID); static BOOL CALLBACK FmifsCallback(FMIFS_PACKET_TYPE, ULONG, PVOID); static VOID UpdateStatus(LPSTR); static VOID SummaryDialog(HWND, LPTSTR, BOOL); static INT_PTR CALLBACK SummaryProc(HWND, UINT, WPARAM, LPARAM); static BOOL Summary_OnInitDialog(HWND, HWND, LPARAM); static FARPROC LoadDllFunction(LPTSTR, LPCSTR, HINSTANCE *);
HANDLE SpawnChkdsk(HWND hDlg, DWORD dwDrives) { DWORD dwThreadId;
// Set that we are scanning a drive currently.
//
g_dwFlags |= SCANDISK_SCANNING; g_dwFlags &= ~SCANDISK_CANCELSCAN;
// Set up the global variables needed.
//
g_bSuccess = FALSE; g_hProgressDlg = hDlg;
// Load the icons for the scanning animation.
//
g_hIconScan[0] = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_SCAN1)); g_hIconScan[1] = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_SCAN2)); g_hIconScan[2] = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_SCAN3));
// Create the thread that will run chkdsk.
//
return CreateThread(NULL, 0, ThreadChkdsk, (LPVOID)(ULONG_PTR)dwDrives, 0, &dwThreadId); }
static DWORD WINAPI ThreadChkdsk(LPVOID dwDrives) { HINSTANCE hFmifsDll; FARPROC Chkdsk; WCHAR szwFileSystem[16], szwDrive[] = L"A:\\"; TCHAR szBuffer[256]; INT nCount, nIndex; LPINT lpnSelected, lpnIndex; LPTSTR lpBuffer, lpCaption, lpCapPre; DWORD_PTR dwMask; BOOL bContinue, bSurface, bFix, bAllHappy = FALSE;
// Load and run the Chkdsk function.
//
if ( (Chkdsk = LoadDllFunction(_T("FMIFS.DLL"), "Chkdsk", &hFmifsDll)) == NULL ) return 0;
// Get the number of selected items and allocate a buffer to hold all the indexs.
//
if ( ( (nCount = (INT)SendDlgItemMessage(g_hProgressDlg, IDC_DRIVES, LB_GETSELCOUNT, 0, 0L)) > 0 ) && ( lpnSelected = (LPINT) MALLOC(nCount * sizeof(INT)) ) ) { // Now get the list of selected items.
//
if ( (nCount = (INT)SendDlgItemMessage(g_hProgressDlg, IDC_DRIVES, LB_GETSELITEMS, nCount, (LPARAM) lpnSelected)) > 0 ) { // Disable the controls.
//
EnableWindow(GetDlgItem(g_hProgressDlg, IDOK), FALSE); EnableWindow(GetDlgItem(g_hProgressDlg, IDC_DRIVESTEXT), FALSE); EnableWindow(GetDlgItem(g_hProgressDlg, IDC_DRIVES), FALSE); EnableWindow(GetDlgItem(g_hProgressDlg, IDC_SURFACE), FALSE); EnableWindow(GetDlgItem(g_hProgressDlg, IDC_AUTOFIX), FALSE);
// Change the text of the IDCANCEL button to Cancel (from Close).
//
if ( lpBuffer = AllocateString(NULL, IDS_CANCEL) ) { SetDlgItemText(g_hProgressDlg, IDCANCEL, lpBuffer); FREE(lpBuffer); }
// Get the scan options.
//
bSurface = IsDlgButtonChecked(g_hProgressDlg, IDC_SURFACE); bFix = IsDlgButtonChecked(g_hProgressDlg, IDC_AUTOFIX);
// Get the caption prefix.
//
lpCapPre = AllocateString(NULL, IDS_RESULTS);
// Loop through all the drives in the list box to see if they
// are selected.
//
lpnIndex = lpnSelected; nIndex = 0; bAllHappy = TRUE; for (dwMask = 1; ((DWORD_PTR) dwDrives & ~(dwMask - 1)) && ( !(g_dwFlags & SCANDISK_CANCELSCAN) ); dwMask <<= 1) { // Is this drive in the list box.
//
if ( (DWORD_PTR) dwDrives & dwMask ) { // Test to see if this item is the
// next selected one.
//
if ( *lpnIndex == nIndex ) { //
// Ok, try and run chkdsk on this drive.
//
// Get the file system type.
//
bContinue = TRUE; while ( bContinue && !GetVolumeInformationW(szwDrive, NULL, 0, NULL, NULL, NULL, szwFileSystem, sizeof(szwFileSystem)) ) { bContinue = FALSE; if ( ( GetLastError() == ERROR_NOT_READY ) && ( lpBuffer = AllocateString(NULL, IDS_NOTREADY) ) ) { if ( MessageBox(g_hProgressDlg, lpBuffer, NULL, MB_RETRYCANCEL | MB_ICONERROR) == IDRETRY ) bContinue = TRUE; FREE(lpBuffer); } }
if ( bContinue ) { // Now finally launch Chkdsk.
//
Chkdsk(szwDrive, szwFileSystem, FALSE, FALSE, FALSE, bSurface, NULL, FALSE, FmifsCallback);
// Make sure the user didn't cancel.
//
if ( !(g_dwFlags & SCANDISK_CANCELSCAN) ) { // Check to see if the scan on this drive returned with errors or not.
//
if ( g_bSuccess ) { // Get the text to use as the caption for the summary box.
//
if (lpCapPre) lstrcpy(szBuffer, lpCapPre); else szBuffer[0] = _T('\0'); if ( SendDlgItemMessage(g_hProgressDlg, IDC_DRIVES, LB_GETTEXT, *lpnIndex, (LPARAM) szBuffer + (lstrlen(szBuffer) * sizeof(TCHAR))) > 0 ) lpCaption = szBuffer; else lpCaption = NULL;
// Display the summary message for this drive.
//
SummaryDialog(g_hProgressDlg, NULL, g_bSuccess);
} else { bAllHappy = FALSE;
// If there were errors on this drive and the user
// wants to automatically fix them, we need to run
// the check disk function again with the fix error
// flag set (/F). We don't do this first because if
// the drive can't be locked it won't even scan the
// drive to see if there is an error before asking to
// check on reboot.
//
if ( bFix ) Chkdsk(szwDrive, szwFileSystem, TRUE, FALSE, FALSE, bSurface, NULL, FALSE, FmifsCallback); } }
// Make sure the memory for the summary dialog is freed.
//
SummaryDialog(NULL, NULL, FALSE);
// Reset the progress control.
//
SendDlgItemMessage(g_hProgressDlg, IDC_PROGRESS, PBM_SETPOS, 0, 0L); SetDlgItemText(g_hProgressDlg, IDC_STATUS, NULLSTR); } lpnIndex++; } // Keep an index of what list box
// item this should be.
//
nIndex++; }
// Go look at the next drive
//
szwDrive[0]++; }
// Free the caption prefix.
//
FREE(lpCapPre);
// Renable the controls.
//
EnableWindow(GetDlgItem(g_hProgressDlg, IDOK), TRUE); EnableWindow(GetDlgItem(g_hProgressDlg, IDC_DRIVES), TRUE); EnableWindow(GetDlgItem(g_hProgressDlg, IDC_DRIVESTEXT), TRUE); EnableWindow(GetDlgItem(g_hProgressDlg, IDC_SURFACE), TRUE); EnableWindow(GetDlgItem(g_hProgressDlg, IDC_AUTOFIX), TRUE);
// Change the text of the IDCANCEL button back to Close.
//
if ( lpBuffer = AllocateString(NULL, IDS_CLOSE) ) { SetDlgItemText(g_hProgressDlg, IDCANCEL, lpBuffer); FREE(lpBuffer); } }
FREE(lpnSelected); }
// Free the DLL library.
//
FreeLibrary(hFmifsDll);
// Reset the scaning bit.
//
g_dwFlags &= ~SCANDISK_SCANNING;
// If we are in SAGERUN mode, end the dialog now that
// we are finished scanning.
//
if ( g_dwFlags & SCANDISK_SAGERUN ) EndDialog(g_hProgressDlg, 0);
// Return the success or failure.
//
return (DWORD) bAllHappy; }
static BOOL CALLBACK FmifsCallback(FMIFS_PACKET_TYPE PacketType, ULONG PacketLength, PVOID PacketData) {
#ifdef _DEBUG
DWORD dwBytes; TCHAR szDebug[1024] = NULLSTR; HANDLE hFile = CreateFile(_T("C:\\SCANDISK.LOG"), GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
switch (PacketType) { case FmIfsPercentCompleted: wsprintf(szDebug, _T("DEBUG: FmifsCallback() - FmIfsPercentCompleted (%d%%)\r\n"), ((PFMIFS_PERCENT_COMPLETE_INFORMATION) PacketData)->PercentCompleted); break; case FmIfsFormatReport: wsprintf(szDebug, _T("DEBUG: FmifsCallback() - FmIfsFormatReport\r\n")); break; case FmIfsInsertDisk: wsprintf(szDebug, _T("DEBUG: FmifsCallback() - FmIfsInsertDisk\r\n")); break; case FmIfsIncompatibleFileSystem: wsprintf(szDebug, _T("DEBUG: FmifsCallback() - FmIfsIncompatibleFileSystem\r\n")); break; case FmIfsFormattingDestination: wsprintf(szDebug, _T("DEBUG: FmifsCallback() - FmIfsFormattingDestination\r\n")); break; case FmIfsIncompatibleMedia: wsprintf(szDebug, _T("DEBUG: FmifsCallback() - FmIfsIncompatibleMedia\r\n")); break; case FmIfsAccessDenied: wsprintf(szDebug, _T("DEBUG: FmifsCallback() - FmIfsAccessDenied\r\n")); break; case FmIfsMediaWriteProtected: wsprintf(szDebug, _T("DEBUG: FmifsCallback() - FmIfsMediaWriteProtected\r\n")); break; case FmIfsCantLock: wsprintf(szDebug, _T("DEBUG: FmifsCallback() - FmIfsCantLock\r\n")); break; case FmIfsCantQuickFormat: wsprintf(szDebug, _T("DEBUG: FmifsCallback() - FmIfsCantQuickFormat\r\n")); break; case FmIfsIoError: wsprintf(szDebug, _T("DEBUG: FmifsCallback() - FmIfsIoError\r\n")); break; case FmIfsFinished: wsprintf(szDebug, _T("DEBUG: FmifsCallback() - FmIfsFinished (%s)\r\n"), ((PFMIFS_FINISHED_INFORMATION) PacketData)->Success ? _T("TRUE") : _T("FALSE")); break; case FmIfsBadLabel: wsprintf(szDebug, _T("DEBUG: FmifsCallback() - FmIfsBadLabel\r\n")); break; case FmIfsCheckOnReboot: wsprintf(szDebug, _T("DEBUG: FmifsCallback() - FmIfsCheckOnReboot\r\n")); break; case FmIfsTextMessage: break; case FmIfsHiddenStatus: wsprintf(szDebug, _T("DEBUG: FmifsCallback() - FmIfsHiddenStatus\r\n")); break; case FmIfsClusterSizeTooSmall: wsprintf(szDebug, _T("DEBUG: FmifsCallback() - FmIfsClusterSizeTooSmall\r\n")); break; case FmIfsClusterSizeTooBig: wsprintf(szDebug, _T("DEBUG: FmifsCallback() - FmIfsClusterSizeTooBig\r\n")); break; case FmIfsVolumeTooSmall: wsprintf(szDebug, _T("DEBUG: FmifsCallback() - FmIfsVolumeTooSmall\r\n")); break; case FmIfsVolumeTooBig: wsprintf(szDebug, _T("DEBUG: FmifsCallback() - FmIfsVolumeTooBig\r\n")); break; case FmIfsNoMediaInDevice: wsprintf(szDebug, _T("DEBUG: FmifsCallback() - FmIfsNoMediaInDevice\r\n")); break; }
if ( hFile != INVALID_HANDLE_VALUE ) { if ( szDebug[0] ) { SetFilePointer(hFile, 0, 0, FILE_END); WriteFile(hFile, szDebug, lstrlen(szDebug) * sizeof(TCHAR), &dwBytes, NULL); } CloseHandle(hFile); } #endif // _DEBUG
switch (PacketType) { case FmIfsPercentCompleted: // Advance the current position of the progress bar
// to the percent returned.
//
SendDlgItemMessage(g_hProgressDlg, IDC_PROGRESS, PBM_SETPOS, ((PFMIFS_PERCENT_COMPLETE_INFORMATION) PacketData)->PercentCompleted, 0L); SendDlgItemMessage(g_hProgressDlg, IDC_SCANDISK, STM_SETIMAGE, IMAGE_ICON, (LPARAM) g_hIconScan[((PFMIFS_PERCENT_COMPLETE_INFORMATION) PacketData)->PercentCompleted % 3]); break;
case FmIfsFinished: g_bSuccess = !((PFMIFS_FINISHED_INFORMATION) PacketData)->Success; break;
case FmIfsTextMessage: UpdateStatus(((PFMIFS_TEXT_MESSAGE) PacketData)->Message); break;
case FmIfsCheckOnReboot: ((PFMIFS_CHECKONREBOOT_INFORMATION) PacketData)->QueryResult = (MessageBox(g_hProgressDlg, _T("This drive contains errors and must be checked on startup.\n\n") _T("Do you want this drive to be checked next time you restart you computer?"), _T("Scandisk"), MB_YESNO | MB_ICONERROR) == IDYES); break; }
return ( !(g_dwFlags & SCANDISK_CANCELSCAN) ); }
static VOID UpdateStatus(LPSTR lpText) { TCHAR szTextOut[256]; LPTSTR lpChkDsk = NULL, lpScanDisk = NULL, lpSearch, lpCopy, lpNewText; DWORD dwLen; HANDLE hFile = INVALID_HANDLE_VALUE; #ifdef _UNICODE
TCHAR wcHeader = 0x0000; TCHAR szNewText[256]; #endif // _UNICODE
#ifdef _UNICODE
if ( MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, lpText, -1, szNewText, sizeof(szNewText)) ) { // If this is unicode, make sure the poitner passed in points to a unicode string.
//
lpNewText = szNewText;
// See if we need to write the header bit so that notepad will
// see the file as unicode.
//
if ( (hFile = CreateFile(_T("C:\\SCANDISK.LOG"), GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE ) wcHeader = 0xFEFF; #else // _UNICODE
lpNewText = lpText; #endif // _UNICODE
// Write to the log file.
//
if ( ( hFile != INVALID_HANDLE_VALUE ) || ( (hFile = CreateFile(_T("C:\\SCANDISK.LOG"), GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE ) ) { #ifdef _UNICODE
if ( wcHeader ) WriteFile(hFile, &wcHeader, sizeof(WCHAR), &dwLen, NULL); #endif // _UNICODE
SetFilePointer(hFile, 0, 0, FILE_END); WriteFile(hFile, (LPTSTR) lpNewText, lstrlen((LPTSTR) lpNewText) * sizeof(TCHAR), &dwLen, NULL); CloseHandle(hFile); }
// Remove proceeding characters we don't want (space, \r, \n, \t).
//
for (lpSearch = (LPTSTR) lpNewText; (*lpSearch == _T(' ')) || (*lpSearch == _T('\r')) || (*lpSearch == _T('\n')) || (*lpSearch == _T('\t')); lpSearch++);
if ( ISNUM(*lpSearch) ) { // We want this info for the summary page.
//
SummaryDialog(g_hProgressDlg, lpSearch, FALSE); } else { if ( ( lpChkDsk = AllocateString(NULL, IDS_CHKDSK) ) && ( lpScanDisk = AllocateString(NULL, IDS_SCANDISK) ) ) { dwLen = lstrlen(lpChkDsk); lpCopy = szTextOut; while ( (*lpSearch != _T('\0')) && (*lpSearch != _T('\r')) ) { if ( _tcsncmp(lpSearch, lpChkDsk, dwLen) == 0 ) { lstrcpy(lpCopy, lpScanDisk); lpSearch += dwLen; lpCopy += lstrlen(lpScanDisk); } else *lpCopy++ = *lpSearch++; } *lpCopy = _T('\0'); SetDlgItemText(g_hProgressDlg, IDC_STATUS, szTextOut); } FREE(lpScanDisk); FREE(lpChkDsk); } #ifdef _UNICODE
} #endif // _UNICODE
}
static VOID SummaryDialog(HWND hWndParent, LPTSTR lpText, BOOL bSuccess) { static LPTSTR lpSumText[16]; static DWORD dwIndex = 0;
LPTSTR lpSearch;
// First check to make sure lpText is a valid pointer. If it is NULL
// then we must be showing the summary dialog and/or freeing the memory.
//
if ( lpText ) { // Make sure we don't already have 16 strings in our buffer.
//
if ( dwIndex < 16 ) { //
// lpText should already point to the first digit of the number
// part of the summary.
//
// We need a pointer to the text after the number. We will search
// for the first space, which should divide the number and the text.
//
for (lpSearch = lpText; (*lpSearch) && (*lpSearch != _T(' ')); lpSearch++);
// Now that we know where the number ends, we can allocate a buffer for it
// and copy the number into it.
//
if ( lpSumText[dwIndex++] = (LPTSTR) MALLOC((size_t)((lpSearch - lpText + 1) * sizeof(TCHAR))) ) lstrcpyn(lpSumText[dwIndex - 1], lpText, (size_t)(lpSearch - lpText + 1));
// We should advance lpSearch to point to the text description, because now
// it should point to a space (unless we hit the end of the string before the space).
//
if ( *lpSearch ) lpSearch++;
// Now we need to know where the text description ends. We just want to search
// for the first new line or line feed character.
//
for (lpText = lpSearch; (*lpSearch) && (*lpSearch != _T('\r')) && (*lpSearch != _T('\n')); lpSearch++);
// Now that we know where the text ends, we can allocate a buffer for it
// also and copy the text into it.
//
if ( lpSumText[dwIndex++] = (LPTSTR) MALLOC((size_t)((lpSearch - lpText + 1) * sizeof(TCHAR))) ) lstrcpyn(lpSumText[dwIndex - 1], lpText, (size_t)(lpSearch - lpText + 1)); } } else { // We check to make sure dwIndex still isn't zero, because if it is,
// there is no text to display in the summary dialog or to free.
//
if ( dwIndex > 0 ) { // If the hwnd is valid and the text is null, then we are
// going to display the summary box.
//
if ( hWndParent ) DialogBoxParam(g_hInstance, MAKEINTRESOURCE(IDD_SUMMARY), hWndParent, SummaryProc, (LPARAM) lpSumText);
//
// Now free the memory because eaither a NULL was passed in for the hwnd
// or we already displayed the dialog and now the memory needs to be freed.
//
// Loop through all the strings that may have
// been allocated by going back from where the index
// is now.
//
// Note that some of the pointers may contain NULL
// if a malloc failed, but the FREE() macro will check
// with that before freeing the memory.
//
while ( dwIndex-- > 0 ) FREE(lpSumText[dwIndex]);
// Reset the index so that it doesn't get messed up
// the next time we display a summary.
//
dwIndex = 0; } } }
static INT_PTR CALLBACK SummaryProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { HANDLE_MSG(hDlg, WM_INITDIALOG, Summary_OnInitDialog); case WM_COMMAND: if ( (INT) LOWORD(wParam) != IDOK ) return TRUE; case WM_CLOSE: EndDialog(hDlg, 0); return 0; } return FALSE; }
static BOOL Summary_OnInitDialog(HWND hDlg, HWND hwndFocus, LPARAM lParam) { INT nSumId[] = { IDC_SUM1A, IDC_SUM1B, IDC_SUM2A, IDC_SUM2B, IDC_SUM3A, IDC_SUM3B, IDC_SUM4A, IDC_SUM4B, IDC_SUM5A, IDC_SUM5B, IDC_SUM6A, IDC_SUM6B, IDC_SUM7A, IDC_SUM7B, IDC_SUM8A, IDC_SUM8B };
LPTSTR *lpStrings = (LPTSTR *) lParam; DWORD dwIndex;
for (dwIndex = 0; dwIndex < 16; dwIndex++) SetDlgItemText(hDlg, nSumId[dwIndex], *(lpStrings++));
return FALSE; }
static FARPROC LoadDllFunction(LPTSTR lpDll, LPCSTR lpFunction, HINSTANCE * lphDll) { FARPROC hFunc = NULL;
if ( (*lphDll) = LoadLibrary(lpDll) ) { if ( (hFunc = GetProcAddress(*lphDll, lpFunction)) == NULL ) { FreeLibrary(*lphDll); *lphDll = NULL; } } else *lphDll = NULL;
return hFunc; }
|