mirror of https://github.com/tongzx/nt5src
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.
760 lines
21 KiB
760 lines
21 KiB
/*
|
|
**------------------------------------------------------------------------------
|
|
** Module: Disk Cleanup Applet
|
|
** File: cleanmgr.cpp
|
|
**
|
|
** Purpose: WinMain for the Disk Cleanup applet.
|
|
** Notes:
|
|
** Mod Log: Created by Jason Cobb (2/97)
|
|
**
|
|
** Copyright (c)1997 Microsoft Corporation, All Rights Reserved
|
|
**------------------------------------------------------------------------------
|
|
*/
|
|
|
|
/*
|
|
**------------------------------------------------------------------------------
|
|
** Project include files
|
|
**------------------------------------------------------------------------------
|
|
*/
|
|
#include "common.h"
|
|
|
|
#define CPP_FUNCTIONS
|
|
#include "crtfree.h"
|
|
|
|
#include "dmgrinfo.h"
|
|
|
|
#include "diskguid.h"
|
|
#include "resource.h"
|
|
#include "textout.h"
|
|
#include "dmgrdlg.h"
|
|
#include "msprintf.h"
|
|
#include "diskutil.h"
|
|
#include "seldrive.h"
|
|
#include "drivlist.h"
|
|
|
|
/*
|
|
**------------------------------------------------------------------------------
|
|
** Global Defines
|
|
**------------------------------------------------------------------------------
|
|
*/
|
|
#define SWITCH_HIDEUI 'N'
|
|
#define SWITCH_HIDEMOREOPTIONS 'M'
|
|
#define SWITCH_DRIVE 'D'
|
|
|
|
#define SZ_SAGESET TEXT("/SAGESET")
|
|
#define SZ_SAGERUN TEXT("/SAGERUN")
|
|
#define SZ_TUNEUP TEXT("/TUNEUP")
|
|
#define SZ_SETUP TEXT("/SETUP")
|
|
|
|
#define SZ_LOWDISK TEXT("/LOWDISK")
|
|
#define SZ_VERYLOWDISK TEXT("/VERYLOWDISK")
|
|
|
|
/*
|
|
**------------------------------------------------------------------------------
|
|
** Global variables
|
|
**------------------------------------------------------------------------------
|
|
*/
|
|
HINSTANCE g_hInstance = NULL;
|
|
HWND g_hDlg = NULL;
|
|
BOOL g_bAlreadyRunning = FALSE;
|
|
|
|
/*
|
|
**------------------------------------------------------------------------------
|
|
** ParseCommandLine
|
|
**
|
|
** Purpose: Parses command line for switches
|
|
** Parameters:
|
|
** lpCmdLine command line string
|
|
** pdwFlags pointer to flags DWORD
|
|
** pDrive pointer to a character that the drive letter
|
|
** is returned in
|
|
** Return: TRUE if command line contains /SAGESET or
|
|
** /SAGERUN
|
|
** FALSE on failure
|
|
** Notes;
|
|
** Mod Log: Created by Jason Cobb (7/97)
|
|
**------------------------------------------------------------------------------
|
|
*/
|
|
BOOL
|
|
ParseCommandLine(
|
|
LPTSTR lpCmdLine,
|
|
PDWORD pdwFlags,
|
|
PULONG pulProfile
|
|
)
|
|
{
|
|
LPTSTR lpStr = lpCmdLine;
|
|
BOOL bRet = FALSE;
|
|
int i;
|
|
TCHAR szProfile[4];
|
|
|
|
*pulProfile = 0;
|
|
|
|
//
|
|
//Look for /SAGESET:n on the command line
|
|
//
|
|
if ((lpStr = StrStrI(lpCmdLine, SZ_SAGESET)) != NULL)
|
|
{
|
|
lpStr += lstrlen(SZ_SAGESET);
|
|
if (*lpStr && *lpStr == ':')
|
|
{
|
|
lpStr++;
|
|
i = 0;
|
|
while (*lpStr && *lpStr != ' ' && i < 4)
|
|
{
|
|
szProfile[i] = *lpStr;
|
|
lpStr++;
|
|
i++;
|
|
}
|
|
|
|
*pulProfile = StrToInt(szProfile);
|
|
}
|
|
|
|
*pdwFlags = FLAG_SAGESET;
|
|
bRet = TRUE;
|
|
}
|
|
|
|
//
|
|
//Look for /SAGERUN:n on the command line
|
|
//
|
|
else if ((lpStr = StrStrI(lpCmdLine, SZ_SAGERUN)) != NULL)
|
|
{
|
|
lpStr += lstrlen(SZ_SAGERUN);
|
|
if (*lpStr && *lpStr == ':')
|
|
{
|
|
lpStr++;
|
|
i = 0;
|
|
while (*lpStr && *lpStr != ' ' && i < 4)
|
|
{
|
|
szProfile[i] = *lpStr;
|
|
lpStr++;
|
|
i++;
|
|
}
|
|
|
|
*pulProfile = StrToInt(szProfile);
|
|
}
|
|
|
|
*pdwFlags = FLAG_SAGERUN;
|
|
bRet = TRUE;
|
|
}
|
|
|
|
//
|
|
//Look for /TUNEUP:n
|
|
//
|
|
else if ((lpStr = StrStrI(lpCmdLine, SZ_TUNEUP)) != NULL)
|
|
{
|
|
lpStr += lstrlen(SZ_TUNEUP);
|
|
if (*lpStr && *lpStr == ':')
|
|
{
|
|
lpStr++;
|
|
i = 0;
|
|
while (*lpStr && *lpStr != ' ' && i < 4)
|
|
{
|
|
szProfile[i] = *lpStr;
|
|
lpStr++;
|
|
i++;
|
|
}
|
|
|
|
*pulProfile = StrToInt(szProfile);
|
|
}
|
|
|
|
*pdwFlags = FLAG_TUNEUP | FLAG_SAGESET;
|
|
bRet = TRUE;
|
|
}
|
|
|
|
//
|
|
//Look for /LOWDISK
|
|
//
|
|
else if ((lpStr = StrStrI(lpCmdLine, SZ_LOWDISK)) != NULL)
|
|
{
|
|
lpStr += lstrlen(SZ_LOWDISK);
|
|
*pdwFlags = FLAG_LOWDISK;
|
|
bRet = TRUE;
|
|
}
|
|
|
|
//
|
|
//Look for /VERYLOWDISK
|
|
//
|
|
else if ((lpStr = StrStrI(lpCmdLine, SZ_VERYLOWDISK)) != NULL)
|
|
{
|
|
lpStr += lstrlen(SZ_VERYLOWDISK);
|
|
*pdwFlags = FLAG_VERYLOWDISK | FLAG_SAGERUN;
|
|
bRet = TRUE;
|
|
}
|
|
|
|
//
|
|
//Look for /SETUP
|
|
//
|
|
else if ((lpStr = StrStrI(lpCmdLine, SZ_SETUP)) != NULL)
|
|
{
|
|
lpStr += lstrlen(SZ_SETUP);
|
|
*pdwFlags = FLAG_SETUP | FLAG_SAGERUN;
|
|
bRet = TRUE;
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
/*
|
|
**------------------------------------------------------------------------------
|
|
** ParseForDrive
|
|
**
|
|
** Purpose: Parses command line for switches
|
|
** Parameters:
|
|
** lpCmdLine command line string
|
|
** pDrive Buffer that the drive string will be returned
|
|
** in, the format will be x:\
|
|
** Return: TRUE on sucess
|
|
** FALSE on failure
|
|
** Notes;
|
|
** Mod Log: Created by Jason Cobb (7/97)
|
|
**------------------------------------------------------------------------------
|
|
*/
|
|
BOOL
|
|
ParseForDrive(
|
|
LPTSTR lpCmdLine,
|
|
PTCHAR pDrive
|
|
)
|
|
{
|
|
LPTSTR lpStr = lpCmdLine;
|
|
|
|
GetBootDrive(pDrive, 4);
|
|
|
|
while (*lpStr)
|
|
{
|
|
//
|
|
//Did we find a '-' or a '/'?
|
|
//
|
|
if ((*lpStr == '-') || (*lpStr == '/'))
|
|
{
|
|
lpStr++;
|
|
|
|
//
|
|
//Is this the Drive switch?
|
|
//
|
|
if (*lpStr && (toupper(*lpStr) == SWITCH_DRIVE))
|
|
{
|
|
//
|
|
//Skip any white space
|
|
//
|
|
lpStr++;
|
|
while (*lpStr && *lpStr == ' ')
|
|
lpStr++;
|
|
|
|
//
|
|
//The next character is the driver letter
|
|
//
|
|
if (*lpStr)
|
|
{
|
|
pDrive[0] = (TCHAR)toupper(*lpStr);
|
|
pDrive[1] = ':';
|
|
pDrive[2] = '\\';
|
|
pDrive[3] = '\0';
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
lpStr++;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL CALLBACK EnumWindowsProc(
|
|
HWND hWnd,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
TCHAR szWindowTitle[260];
|
|
|
|
GetWindowText(hWnd, szWindowTitle, ARRAYSIZE(szWindowTitle));
|
|
if (StrCmp(szWindowTitle, (LPTSTR)lParam) == 0)
|
|
{
|
|
MiDebugMsg((0, "There is already an instance of cleanmgr.exe running on this drive!"));
|
|
SetForegroundWindow(hWnd);
|
|
g_bAlreadyRunning = TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
**------------------------------------------------------------------------------
|
|
**
|
|
** ProcessMessagesUntilEvent() - This does a message loop until an event or a
|
|
** timeout occurs.
|
|
**
|
|
**------------------------------------------------------------------------------
|
|
*/
|
|
|
|
DWORD ProcessMessagesUntilEvent(HWND hwnd, HANDLE hEvent, DWORD dwTimeout)
|
|
{
|
|
MSG msg;
|
|
DWORD dwEndTime = GetTickCount() + dwTimeout;
|
|
LONG lWait = (LONG)dwTimeout;
|
|
DWORD dwReturn;
|
|
|
|
for (;;)
|
|
{
|
|
dwReturn = MsgWaitForMultipleObjects(1, &hEvent,
|
|
FALSE, lWait, QS_ALLINPUT);
|
|
|
|
// were we signalled or did we time out?
|
|
if (dwReturn != (WAIT_OBJECT_0 + 1))
|
|
{
|
|
break;
|
|
}
|
|
|
|
// we woke up because of messages.
|
|
while (PeekMessage(&msg, hwnd, 0, 0, PM_REMOVE))
|
|
{
|
|
TranslateMessage(&msg);
|
|
if (msg.message == WM_SETCURSOR)
|
|
{
|
|
SetCursor(LoadCursor(NULL, IDC_WAIT));
|
|
}
|
|
else
|
|
{
|
|
DispatchMessage(&msg);
|
|
}
|
|
}
|
|
|
|
// calculate new timeout value
|
|
if (dwTimeout != INFINITE)
|
|
{
|
|
lWait = (LONG)dwEndTime - GetTickCount();
|
|
}
|
|
}
|
|
|
|
return dwReturn;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
**------------------------------------------------------------------------------
|
|
**
|
|
** WaitForARP() - Waits for the "Add/Remove Programs" Control Panel applet to
|
|
** be closed by the user.
|
|
**
|
|
**------------------------------------------------------------------------------
|
|
*/
|
|
|
|
void WaitForARP()
|
|
{
|
|
HWND hwndARP = NULL;
|
|
HANDLE hProcessARP = NULL;
|
|
DWORD dwProcId = 0;
|
|
TCHAR szARPTitle[128];
|
|
|
|
// We want to wait until the user closes "Add/Remove Programs" to continue.
|
|
// To do this, we must first get an HWND to the dialog window. This is
|
|
// accomplished by trying to find the window by its title for no more than
|
|
// about 5 seconds (looping 10 times with a 0.5 second delay between attempts).
|
|
LoadString(g_hInstance, IDS_ADDREMOVE_TITLE, szARPTitle, ARRAYSIZE(szARPTitle));
|
|
for (int i = 0; (i < 10) && (!hwndARP); i++)
|
|
{
|
|
hwndARP = FindWindow(NULL, szARPTitle);
|
|
Sleep(500);
|
|
}
|
|
|
|
// If we got the HWND, then we can get the process handle, and wait
|
|
// until the Add/Remove process goes away to continue.
|
|
if (hwndARP)
|
|
{
|
|
GetWindowThreadProcessId(hwndARP, &dwProcId);
|
|
hProcessARP = OpenProcess(SYNCHRONIZE, FALSE, dwProcId);
|
|
if (hProcessARP)
|
|
{
|
|
ProcessMessagesUntilEvent(hwndARP, hProcessARP, INFINITE);
|
|
CloseHandle(hProcessARP);
|
|
}
|
|
}
|
|
}
|
|
|
|
int APIENTRY WinMainT(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
|
|
{
|
|
DWORD dwFlags = 0;
|
|
CleanupMgrInfo *pcmi = NULL;
|
|
TCHAR szDrive[4];
|
|
TCHAR szSageDrive[4];
|
|
TCHAR szCaption[64];
|
|
TCHAR szInitialMessage[812];
|
|
TCHAR szFinalMessage[830];
|
|
ULONG ulProfile = 0;
|
|
WNDCLASS cls = {0};
|
|
TCHAR *psz;
|
|
TCHAR szVolumeName[MAX_PATH];
|
|
int RetCode = RETURN_SUCCESS;
|
|
int nDoAgain = IDYES;
|
|
ULARGE_INTEGER ulFreeBytesAvailable,
|
|
ulTotalNumberOfBytes,
|
|
ulTotalNumberOfFreeBytes;
|
|
UINT uiTotalFreeMB;
|
|
STARTUPINFO si;
|
|
PROCESS_INFORMATION pi;
|
|
BOOL fFirstInstance = TRUE;
|
|
HWND hwnd = NULL;
|
|
HANDLE hEvent = NULL;
|
|
|
|
|
|
//
|
|
// Decide if this is the first instance
|
|
//
|
|
|
|
hEvent = CreateEvent (NULL, FALSE, FALSE, TEXT("Cleanmgr: Instance event"));
|
|
|
|
if (hEvent)
|
|
{
|
|
if (GetLastError() == ERROR_ALREADY_EXISTS)
|
|
{
|
|
fFirstInstance = FALSE;
|
|
}
|
|
}
|
|
|
|
g_hInstance = hInstance;
|
|
|
|
InitCommonControls();
|
|
|
|
//
|
|
//Initialize support classes
|
|
//
|
|
CleanupMgrInfo::Register(hInstance);
|
|
|
|
cls.lpszClassName = SZ_CLASSNAME;
|
|
cls.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
cls.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(ICON_CLEANMGR));
|
|
cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
|
|
cls.hInstance = hInstance;
|
|
cls.style = CS_HREDRAW | CS_VREDRAW;
|
|
cls.lpfnWndProc = DefDlgProc;
|
|
cls.cbWndExtra = DLGWINDOWEXTRA;
|
|
RegisterClass(&cls);
|
|
|
|
//
|
|
//Parse the command line
|
|
//
|
|
ParseCommandLine(lpCmdLine, &dwFlags, &ulProfile);
|
|
|
|
if (!ParseForDrive(lpCmdLine, szDrive) &&
|
|
!(dwFlags & FLAG_SAGESET) &&
|
|
!(dwFlags & FLAG_SAGERUN))
|
|
{
|
|
PromptForDisk:
|
|
if (!SelectDrive(szDrive))
|
|
goto Cleanup_Exit;
|
|
}
|
|
|
|
//
|
|
//Create window title for comparison
|
|
//
|
|
if (dwFlags & FLAG_SAGESET)
|
|
{
|
|
psz = SHFormatMessage( MSG_APP_SETTINGS_TITLE );
|
|
}
|
|
else
|
|
{
|
|
GetVolumeInformation(szDrive, szVolumeName, ARRAYSIZE(szVolumeName), NULL, NULL, NULL, NULL, 0);
|
|
psz = SHFormatMessage( MSG_APP_TITLE, szVolumeName, szDrive[0] );
|
|
}
|
|
|
|
if (psz)
|
|
{
|
|
EnumWindows(EnumWindowsProc, (LPARAM)psz);
|
|
LocalFree(psz);
|
|
}
|
|
|
|
// Also check for any of the final series of dialogs which may display after the main UI has gone away
|
|
if (!g_bAlreadyRunning)
|
|
{
|
|
LoadString(g_hInstance, IDS_LOWDISK_CAPTION, szCaption, ARRAYSIZE(szCaption));
|
|
EnumWindows(EnumWindowsProc, (LPARAM)szCaption);
|
|
|
|
LoadString(g_hInstance, IDS_LOWDISK_SUCCESS_CAPTION, szCaption, ARRAYSIZE(szCaption));
|
|
EnumWindows(EnumWindowsProc, (LPARAM)szCaption);
|
|
}
|
|
|
|
// If we didn't catch another instance of cleanmgr via EnumWindows(), we catch it with a
|
|
// named event. We wait until now to do it so EnumWindows() can bring the other instance's
|
|
// window to the foreground if it is up.
|
|
if (!fFirstInstance)
|
|
{
|
|
g_bAlreadyRunning = TRUE;
|
|
}
|
|
|
|
if (g_bAlreadyRunning)
|
|
{
|
|
RetCode = FALSE;
|
|
goto Cleanup_Exit;
|
|
}
|
|
|
|
if (dwFlags & FLAG_SAGERUN)
|
|
{
|
|
szSageDrive[1] = TCHAR(':');
|
|
szSageDrive[2] = TCHAR('\\');
|
|
szSageDrive[3] = TCHAR('\0');
|
|
|
|
for (TCHAR c = 'A'; c <= 'Z'; c++)
|
|
{
|
|
szSageDrive[0] = c;
|
|
|
|
//
|
|
//Create CleanupMgrInfo object for this drive
|
|
//
|
|
pcmi = new CleanupMgrInfo(szSageDrive, dwFlags, ulProfile);
|
|
if (pcmi != NULL && pcmi->isAbortScan() == FALSE && pcmi->isValid())
|
|
{
|
|
pcmi->purgeClients();
|
|
}
|
|
|
|
// Keep the latest scan window handle (but hide the window)
|
|
if (pcmi && pcmi->hAbortScanWnd)
|
|
{
|
|
hwnd = pcmi->hAbortScanWnd;
|
|
ShowWindow(hwnd, SW_HIDE);
|
|
}
|
|
|
|
//
|
|
//Destroy the CleanupMgrInfo object for this drive
|
|
//
|
|
if (pcmi)
|
|
{
|
|
RetCode = pcmi->dwReturnCode;
|
|
delete pcmi;
|
|
pcmi = NULL;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
//Create CleanupMgrInfo object
|
|
//
|
|
pcmi = new CleanupMgrInfo(szDrive, dwFlags, ulProfile);
|
|
if (pcmi != NULL && pcmi->isAbortScan() == FALSE)
|
|
{
|
|
//
|
|
//User specified an invalid drive letter
|
|
//
|
|
if (!(pcmi->isValid()))
|
|
{
|
|
// dismiss the dialog first
|
|
if ( pcmi->hAbortScanWnd )
|
|
{
|
|
pcmi->bAbortScan = TRUE;
|
|
|
|
//
|
|
//Wait for scan thread to finish
|
|
//
|
|
WaitForSingleObject(pcmi->hAbortScanThread, INFINITE);
|
|
|
|
pcmi->bAbortScan = FALSE;
|
|
}
|
|
|
|
TCHAR szWarningTitle[256];
|
|
TCHAR *pszWarning;
|
|
pszWarning = SHFormatMessage( MSG_BAD_DRIVE_LETTER, szDrive );
|
|
LoadString(g_hInstance, IDS_TITLE, szWarningTitle, ARRAYSIZE(szWarningTitle));
|
|
|
|
MessageBox(NULL, pszWarning, szWarningTitle, MB_OK | MB_SETFOREGROUND);
|
|
LocalFree(pszWarning);
|
|
|
|
if (pcmi)
|
|
{
|
|
delete pcmi;
|
|
pcmi = NULL;
|
|
goto PromptForDisk;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//Bring up the main dialog
|
|
int nResult = DisplayCleanMgrProperties(NULL, (LPARAM)pcmi);
|
|
if (nResult)
|
|
{
|
|
pcmi->dwUIFlags |= FLAG_SAVE_STATE;
|
|
|
|
//
|
|
//Need to purge the clients if we are NOT
|
|
//in the SAGE settings mode.
|
|
//
|
|
if (!(dwFlags & FLAG_SAGESET) && !(dwFlags & FLAG_TUNEUP) && pcmi->bPurgeFiles)
|
|
pcmi->purgeClients();
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
//Destroy the CleanupMgrInfo object
|
|
//
|
|
if (pcmi)
|
|
{
|
|
RetCode = pcmi->dwReturnCode;
|
|
delete pcmi;
|
|
pcmi = NULL;
|
|
}
|
|
}
|
|
|
|
GetStartupInfo(&si);
|
|
|
|
// If we were called on a low free disk space case, we want to inform the user of how much space remains,
|
|
// and encourage them to free up space via Add/Remove programs until they reach 200MB free in the /LOWDISK
|
|
// case, or 50MB free in the /VERYLOWDISK case.
|
|
while (nDoAgain == IDYES)
|
|
{
|
|
BOOL bFinalTime = FALSE;
|
|
|
|
nDoAgain = IDNO;
|
|
|
|
// Bring up the Low Disk message box
|
|
if (dwFlags & FLAG_LOWDISK)
|
|
{
|
|
GetDiskFreeSpaceEx(szDrive, &ulFreeBytesAvailable, &ulTotalNumberOfBytes, &ulTotalNumberOfFreeBytes);
|
|
uiTotalFreeMB = (UINT) (ulTotalNumberOfFreeBytes.QuadPart / (NUM_BYTES_IN_MB));
|
|
if (uiTotalFreeMB < 200)
|
|
{
|
|
if (uiTotalFreeMB < 80)
|
|
{
|
|
LoadString(g_hInstance, IDS_LOWDISK_MESSAGE2, szInitialMessage, ARRAYSIZE(szInitialMessage));
|
|
}
|
|
else
|
|
{
|
|
LoadString(g_hInstance, IDS_LOWDISK_MESSAGE, szInitialMessage, ARRAYSIZE(szInitialMessage));
|
|
}
|
|
|
|
LoadString(g_hInstance, IDS_LOWDISK_CAPTION, szCaption, ARRAYSIZE(szCaption));
|
|
wsprintf(szFinalMessage, szInitialMessage, uiTotalFreeMB);
|
|
nDoAgain = MessageBox(hwnd, szFinalMessage, szCaption, MB_YESNO | MB_ICONWARNING | MB_TOPMOST);
|
|
}
|
|
else
|
|
{
|
|
LoadString(g_hInstance, IDS_LOWDISK_SUCCESS_CAPTION, szCaption, ARRAYSIZE(szCaption));
|
|
LoadString(g_hInstance, IDS_LOWDISK_SUCCESS_MESSAGE, szInitialMessage, ARRAYSIZE(szInitialMessage));
|
|
wsprintf(szFinalMessage, szInitialMessage, uiTotalFreeMB);
|
|
nDoAgain = MessageBox(hwnd, szFinalMessage, szCaption, MB_YESNO | MB_ICONQUESTION | MB_DEFBUTTON2 | MB_TOPMOST);
|
|
bFinalTime = TRUE;
|
|
}
|
|
}
|
|
else if (dwFlags & FLAG_VERYLOWDISK)
|
|
{
|
|
// Bring up the Very Low Disk message box
|
|
GetDiskFreeSpaceEx(szDrive, &ulFreeBytesAvailable, &ulTotalNumberOfBytes, &ulTotalNumberOfFreeBytes);
|
|
uiTotalFreeMB = (UINT) (ulTotalNumberOfFreeBytes.QuadPart / (NUM_BYTES_IN_MB));
|
|
if (uiTotalFreeMB < 50)
|
|
{
|
|
LoadString(g_hInstance, IDS_LOWDISK_CAPTION, szCaption, ARRAYSIZE(szCaption));
|
|
LoadString(g_hInstance, IDS_VERYLOWDISK_MESSAGE, szInitialMessage, ARRAYSIZE(szInitialMessage));
|
|
wsprintf(szFinalMessage, szInitialMessage, uiTotalFreeMB);
|
|
nDoAgain = MessageBox(hwnd, szFinalMessage, szCaption, MB_YESNO | MB_ICONSTOP | MB_TOPMOST);
|
|
}
|
|
else
|
|
{
|
|
LoadString(g_hInstance, IDS_LOWDISK_SUCCESS_CAPTION, szCaption, ARRAYSIZE(szCaption));
|
|
LoadString(g_hInstance, IDS_LOWDISK_SUCCESS_MESSAGE, szInitialMessage, ARRAYSIZE(szInitialMessage));
|
|
wsprintf(szFinalMessage, szInitialMessage, uiTotalFreeMB);
|
|
nDoAgain = MessageBox(hwnd, szFinalMessage, szCaption, MB_YESNO | MB_ICONQUESTION | MB_DEFBUTTON2 | MB_TOPMOST);
|
|
bFinalTime = TRUE;
|
|
}
|
|
}
|
|
|
|
if (nDoAgain == IDYES)
|
|
{
|
|
// Launch the Add/Remove Programs dialog
|
|
lstrcpy(szInitialMessage, SZ_RUN_INSTALLED_PROGRAMS);
|
|
if (CreateProcess(NULL, szInitialMessage, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi))
|
|
{
|
|
CloseHandle(pi.hProcess);
|
|
CloseHandle(pi.hThread);
|
|
|
|
// Only bother to wait around if it is not our final time through
|
|
if (! bFinalTime)
|
|
{
|
|
WaitForARP();
|
|
}
|
|
else
|
|
{
|
|
// If this was our final time through, then set the flag
|
|
// to break out of the loop
|
|
nDoAgain = IDNO;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// If we cannot launch Add/Remove programs for some reason, we break
|
|
// out of the loop
|
|
nDoAgain = IDNO;
|
|
}
|
|
}
|
|
}
|
|
|
|
Cleanup_Exit:
|
|
|
|
if (hEvent)
|
|
{
|
|
CloseHandle (hEvent);
|
|
}
|
|
|
|
CleanupMgrInfo::Unregister();
|
|
|
|
return RetCode;
|
|
}
|
|
|
|
|
|
STDAPI_(int) ModuleEntry(void)
|
|
{
|
|
int i;
|
|
STARTUPINFOA si;
|
|
LPTSTR pszCmdLine = GetCommandLine();
|
|
|
|
//
|
|
// We don't want the "No disk in drive X:" requesters, so we set
|
|
// the critical error mask such that calls will just silently fail
|
|
//
|
|
|
|
SetErrorMode(SEM_FAILCRITICALERRORS);
|
|
|
|
if ( *pszCmdLine == TEXT('\"') ) {
|
|
/*
|
|
* Scan, and skip over, subsequent characters until
|
|
* another double-quote or a null is encountered.
|
|
*/
|
|
while ( *++pszCmdLine && (*pszCmdLine
|
|
!= TEXT('\"')) );
|
|
/*
|
|
* If we stopped on a double-quote (usual case), skip
|
|
* over it.
|
|
*/
|
|
if ( *pszCmdLine == TEXT('\"') )
|
|
pszCmdLine++;
|
|
}
|
|
else {
|
|
while (*pszCmdLine > TEXT(' '))
|
|
pszCmdLine++;
|
|
}
|
|
|
|
/*
|
|
* Skip past any white space preceeding the second token.
|
|
*/
|
|
while (*pszCmdLine && (*pszCmdLine <= TEXT(' '))) {
|
|
pszCmdLine++;
|
|
}
|
|
|
|
si.dwFlags = 0;
|
|
GetStartupInfoA(&si);
|
|
|
|
i = WinMainT(GetModuleHandle(NULL), NULL, pszCmdLine,
|
|
si.dwFlags & STARTF_USESHOWWINDOW ? si.wShowWindow : SW_SHOWDEFAULT);
|
|
|
|
// Since we now have a way for an extension to tell us when it is finished,
|
|
// we will terminate all processes when the main thread goes away.
|
|
|
|
return i;
|
|
}
|
|
|
|
void _cdecl main()
|
|
{
|
|
ModuleEntry();
|
|
}
|