1805 lines
46 KiB
C
1805 lines
46 KiB
C
|
//*************************************************************
|
||
|
// File name: PROQUOTA.C
|
||
|
//
|
||
|
// Description: Profile quota management
|
||
|
//
|
||
|
// Microsoft Confidential
|
||
|
// Copyright (c) Microsoft Corporation 1996
|
||
|
// All rights reserved
|
||
|
//
|
||
|
//*************************************************************
|
||
|
|
||
|
#include <windows.h>
|
||
|
#include <wchar.h>
|
||
|
#include <aclapi.h>
|
||
|
#include <shellapi.h>
|
||
|
#include <commctrl.h>
|
||
|
#include "proquota.h"
|
||
|
#include "debug.h"
|
||
|
|
||
|
#define WINLOGON_KEY TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon")
|
||
|
#define SYSTEM_POLICIES_KEY TEXT("Software\\Policies\\Microsoft\\Windows\\System")
|
||
|
|
||
|
HINSTANCE hInst;
|
||
|
HWND hwndMain;
|
||
|
HWND g_hQuotaDlg = NULL;
|
||
|
BOOL g_bHideSmallItems;
|
||
|
BOOL g_bShowReg = FALSE;
|
||
|
HANDLE hThread;
|
||
|
HANDLE hExitEvent;
|
||
|
HANDLE g_hQuotaDlgEvent;
|
||
|
DWORD g_dwProfileSize = 0;
|
||
|
DWORD g_dwProfileSizeTemp = 0;
|
||
|
DWORD g_dwMaxProfileSize = 10240; //KB
|
||
|
CRITICAL_SECTION g_cs;
|
||
|
HICON hIconGood, hIconCaution, hIconStop;
|
||
|
BOOL g_bQueryEndSession;
|
||
|
TCHAR g_szExcludeList[2*MAX_PATH];
|
||
|
TCHAR *g_lpQuotaMessage=NULL;
|
||
|
|
||
|
TCHAR szClassName[] = TEXT("proquota");
|
||
|
TCHAR szEventName[] = TEXT("proquota instance event");
|
||
|
TCHAR szSizeFormat[40];
|
||
|
|
||
|
BOOL g_bWarnUser = FALSE;
|
||
|
DWORD g_dwWarnUserTimeout = 15; // minutes
|
||
|
BOOL g_bWarningTimerRunning = FALSE;
|
||
|
BOOL g_bWarningDisplayed = FALSE;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Function prototypes
|
||
|
//
|
||
|
|
||
|
LRESULT CALLBACK ProQuotaWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
|
||
|
LRESULT CALLBACK QuotaDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
|
||
|
BOOL SetSecurity (void);
|
||
|
BOOL ReadRegistry (void);
|
||
|
BOOL ReadExclusionList();
|
||
|
VOID QuotaThread(HWND hWnd);
|
||
|
BOOL RecurseDirectory (LPTSTR lpDir, LPTSTR lpTop, HWND hLV, LPTSTR lpExcludeList);
|
||
|
BOOL EnumerateProfile (HWND hLV);
|
||
|
LPTSTR CheckSemicolon (LPTSTR lpDir);
|
||
|
LPTSTR CheckSlash (LPTSTR lpDir);
|
||
|
LPTSTR ConvertExclusionList (LPCTSTR lpSourceDir, LPCTSTR lpExclusionList);
|
||
|
|
||
|
//*************************************************************
|
||
|
//
|
||
|
// WinMain()
|
||
|
//
|
||
|
// Purpose: Entry point
|
||
|
//
|
||
|
// Parameters: hInstance - Instance handle
|
||
|
// hPrevInstance - Previous Instance
|
||
|
// lpCmdLine - Command line
|
||
|
// nCmdShow - ShowWindow flag
|
||
|
//
|
||
|
// Return: int
|
||
|
//
|
||
|
//*************************************************************
|
||
|
|
||
|
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
|
||
|
LPSTR lpCmdLine, INT nCmdShow)
|
||
|
{
|
||
|
MSG msg;
|
||
|
WNDCLASS wc;
|
||
|
HANDLE hEvent;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Verbose output
|
||
|
//
|
||
|
|
||
|
#if DBG
|
||
|
InitDebugSupport();
|
||
|
DebugMsg((DM_VERBOSE, TEXT("WinMain: Entering...")));
|
||
|
#endif
|
||
|
|
||
|
hInst = hInstance;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Check if this app is already running
|
||
|
//
|
||
|
|
||
|
hEvent = OpenEvent (EVENT_ALL_ACCESS, FALSE, szEventName);
|
||
|
|
||
|
if (hEvent) {
|
||
|
DebugMsg((DM_VERBOSE, TEXT("WinMain: Proquota already running. Exiting...")));
|
||
|
CloseHandle (hEvent);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
hEvent = CreateEvent (NULL, TRUE, TRUE, szEventName);
|
||
|
|
||
|
|
||
|
g_hQuotaDlgEvent = CreateEvent (NULL, FALSE, TRUE, NULL);
|
||
|
|
||
|
if (!g_hQuotaDlgEvent) {
|
||
|
DebugMsg((DM_VERBOSE, TEXT("WinMain: Proquota Couldn't get prowquota dlg event, error %d..."), GetLastError()));
|
||
|
CloseHandle (hEvent);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Get the quota settings
|
||
|
//
|
||
|
|
||
|
if (!ReadRegistry()) {
|
||
|
DebugMsg((DM_VERBOSE, TEXT("WinMain: ReadRegistry returned FALSE. Exiting...")));
|
||
|
CloseHandle (hEvent);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Munge the access mask on the process token so taskmgr
|
||
|
// can't kill this app.
|
||
|
//
|
||
|
|
||
|
SetSecurity();
|
||
|
|
||
|
//
|
||
|
// Make sure proquota is the first one that is attempted to be shutdown
|
||
|
//
|
||
|
|
||
|
SetProcessShutdownParameters(0x3ff, 0);
|
||
|
|
||
|
//
|
||
|
// Initialize
|
||
|
//
|
||
|
|
||
|
InitializeCriticalSection (&g_cs);
|
||
|
InitCommonControls();
|
||
|
|
||
|
LoadString (hInst, IDS_SIZEFMT, szSizeFormat, 40);
|
||
|
|
||
|
wc.style = CS_HREDRAW | CS_VREDRAW;
|
||
|
wc.lpfnWndProc = (WNDPROC)ProQuotaWndProc;
|
||
|
wc.cbClsExtra = 0;
|
||
|
wc.cbWndExtra = 0;
|
||
|
wc.hInstance = hInstance;
|
||
|
wc.hIcon = NULL;
|
||
|
wc.hCursor = NULL;
|
||
|
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
|
||
|
wc.lpszMenuName = NULL;
|
||
|
wc.lpszClassName = szClassName;
|
||
|
|
||
|
if (!RegisterClass(&wc)) {
|
||
|
DebugMsg((DM_WARNING, TEXT("WinMain: RegisterClass failed with %d"), GetLastError()));
|
||
|
CloseHandle (hEvent);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Create a hidden top level window so we get
|
||
|
// broadcasted messages.
|
||
|
//
|
||
|
|
||
|
hwndMain = CreateWindow(szClassName, NULL, WS_OVERLAPPED, 0, 0, 0, 0,
|
||
|
NULL, NULL, hInstance, NULL);
|
||
|
|
||
|
if (!hwndMain) {
|
||
|
DebugMsg((DM_WARNING, TEXT("WinMain: CreateWindow failed with %d"), GetLastError()));
|
||
|
CloseHandle (hEvent);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
while (GetMessage (&msg, NULL, 0, 0)) {
|
||
|
TranslateMessage(&msg);
|
||
|
DispatchMessage(&msg);
|
||
|
}
|
||
|
|
||
|
DebugMsg((DM_VERBOSE, TEXT("WinMain: Leaving...")));
|
||
|
CloseHandle (hEvent);
|
||
|
|
||
|
if (g_lpQuotaMessage) {
|
||
|
LocalFree(g_lpQuotaMessage);
|
||
|
g_lpQuotaMessage = NULL;
|
||
|
}
|
||
|
return (int)(msg.wParam);
|
||
|
}
|
||
|
|
||
|
//*************************************************************
|
||
|
//
|
||
|
// ProQuotaWndProc()
|
||
|
//
|
||
|
// Purpose: Window procedure
|
||
|
//
|
||
|
// Parameters: hWnd - Window handle
|
||
|
// message - Window message
|
||
|
// wParam - WPARAM
|
||
|
// lParam - LPARAM
|
||
|
//
|
||
|
//
|
||
|
// Return: LRESULT
|
||
|
//
|
||
|
//*************************************************************
|
||
|
|
||
|
LRESULT CALLBACK ProQuotaWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
DWORD dwThreadId;
|
||
|
|
||
|
switch (message) {
|
||
|
case WM_CREATE:
|
||
|
|
||
|
hIconGood = LoadIcon (hInst, MAKEINTRESOURCE(IDI_ICON));
|
||
|
hIconCaution = LoadIcon (hInst, MAKEINTRESOURCE(IDI_CAUTION));
|
||
|
hIconStop = LoadIcon (hInst, MAKEINTRESOURCE(IDI_STOP));
|
||
|
|
||
|
hExitEvent = CreateEvent (NULL, FALSE, FALSE, TEXT("PROQUOTA Exit Event"));
|
||
|
|
||
|
if (!hExitEvent) {
|
||
|
DebugMsg((DM_WARNING, TEXT("ProQuotaWndProc: Failed to create exit event with error %d"), GetLastError()));
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
hThread = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) QuotaThread,
|
||
|
(LPVOID) hWnd, CREATE_SUSPENDED, &dwThreadId);
|
||
|
|
||
|
if (!hThread) {
|
||
|
DebugMsg((DM_WARNING, TEXT("ProQuotaWndProc: Failed to create thread with error %d"), GetLastError()));
|
||
|
CloseHandle (hExitEvent);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
SetThreadPriority (hThread, THREAD_PRIORITY_IDLE);
|
||
|
ResumeThread (hThread);
|
||
|
break;
|
||
|
|
||
|
case WM_USER:
|
||
|
|
||
|
if (lParam == WM_LBUTTONDBLCLK) {
|
||
|
PostMessage (hWnd, WM_QUOTADLG, 0, 0);
|
||
|
}
|
||
|
|
||
|
#if DBG
|
||
|
if (lParam == WM_RBUTTONUP) {
|
||
|
DestroyWindow (hWnd);
|
||
|
}
|
||
|
#endif
|
||
|
break;
|
||
|
|
||
|
case WM_QUERYENDSESSION:
|
||
|
{
|
||
|
BOOL bLogoff;
|
||
|
|
||
|
//EnterCriticalSection (&g_cs);
|
||
|
bLogoff = (g_dwProfileSize <= g_dwMaxProfileSize);
|
||
|
//LeaveCriticalSection (&g_cs);
|
||
|
|
||
|
//
|
||
|
// If it is zero assume that it has not yet finished enumerating..
|
||
|
//
|
||
|
|
||
|
if (g_dwProfileSize == 0) {
|
||
|
bLogoff = FALSE;
|
||
|
DebugMsg((DM_VERBOSE, TEXT("ProQuotaWndProc: Recd QueryEnd Message before enumerating.")));
|
||
|
}
|
||
|
|
||
|
DebugMsg((DM_VERBOSE, TEXT("ProQuotaWndProc: Recd QueryEnd Message. Returning %s"), bLogoff?TEXT("TRUE"):TEXT("FALSE")));
|
||
|
|
||
|
if (bLogoff) {
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
PostMessage (hWnd, WM_QUOTADLG, 1, 0);
|
||
|
}
|
||
|
return FALSE;
|
||
|
|
||
|
|
||
|
case WM_QUOTADLG:
|
||
|
if (!g_hQuotaDlg) {
|
||
|
|
||
|
if (wParam) {
|
||
|
g_bQueryEndSession = TRUE;
|
||
|
} else {
|
||
|
g_bQueryEndSession = FALSE;
|
||
|
}
|
||
|
|
||
|
DialogBox (hInst, MAKEINTRESOURCE(IDD_QUOTA), hwndMain, QuotaDlgProc);
|
||
|
g_hQuotaDlg = NULL;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case WM_WARNUSER:
|
||
|
if (!g_bWarningDisplayed) {
|
||
|
TCHAR szTitle[100];
|
||
|
|
||
|
g_bWarningDisplayed = TRUE;
|
||
|
|
||
|
LoadString (hInst, IDS_MSGTITLE, szTitle, 100);
|
||
|
MessageBox(hWnd, g_lpQuotaMessage, szTitle, MB_OK | MB_ICONSTOP | MB_SYSTEMMODAL);
|
||
|
|
||
|
g_bWarningDisplayed = FALSE;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case WM_TIMER:
|
||
|
if (g_dwWarnUserTimeout > 0) {
|
||
|
PostMessage (hWnd, WM_WARNUSER, 0, 0);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case WM_EXITWINDOWS:
|
||
|
ExitWindowsDialog(NULL);
|
||
|
break;
|
||
|
|
||
|
case WM_DESTROY:
|
||
|
{
|
||
|
NOTIFYICONDATA nid;
|
||
|
|
||
|
nid.cbSize = sizeof(nid);
|
||
|
nid.hWnd = hWnd;
|
||
|
nid.uID = 1;
|
||
|
|
||
|
Shell_NotifyIcon (NIM_DELETE, &nid);
|
||
|
|
||
|
SetEvent (hExitEvent);
|
||
|
|
||
|
WaitForSingleObject (hThread, INFINITE);
|
||
|
|
||
|
CloseHandle (hExitEvent);
|
||
|
CloseHandle (hThread);
|
||
|
PostQuitMessage(0);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
return (DefWindowProc(hWnd, message, wParam, lParam));
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//*************************************************************
|
||
|
//
|
||
|
// QuotaThread()
|
||
|
//
|
||
|
// Purpose: Initializes the tray icon
|
||
|
//
|
||
|
// Parameters: hWnd - main window handle
|
||
|
//
|
||
|
//
|
||
|
// Return: TRUE if successful
|
||
|
// FALSE if an error occurs
|
||
|
//
|
||
|
//*************************************************************
|
||
|
|
||
|
VOID QuotaThread (HWND hWnd)
|
||
|
{
|
||
|
NOTIFYICONDATA nid;
|
||
|
TCHAR szProfile[MAX_PATH];
|
||
|
TCHAR szMessage[64];
|
||
|
HANDLE hFileChange;
|
||
|
HANDLE hRegChange;
|
||
|
HANDLE hWaitHandles[4];
|
||
|
BOOL bFirst = TRUE;
|
||
|
HICON hOk, hWarning, hBad;
|
||
|
DWORD dwDelta;
|
||
|
HKEY hKeySystem;
|
||
|
LONG lResult;
|
||
|
DWORD dwResult;
|
||
|
|
||
|
|
||
|
DebugMsg((DM_VERBOSE, TEXT("QuotaThread: Entering...")));
|
||
|
|
||
|
//
|
||
|
// Load the status icons
|
||
|
//
|
||
|
|
||
|
hOk = LoadImage (hInst, MAKEINTRESOURCE(IDI_ICON), IMAGE_ICON,
|
||
|
16, 16, LR_DEFAULTCOLOR);
|
||
|
|
||
|
hWarning = LoadImage (hInst, MAKEINTRESOURCE(IDI_CAUTION), IMAGE_ICON,
|
||
|
16, 16, LR_DEFAULTCOLOR);
|
||
|
|
||
|
hBad = LoadImage (hInst, MAKEINTRESOURCE(IDI_STOP), IMAGE_ICON,
|
||
|
16, 16, LR_DEFAULTCOLOR);
|
||
|
|
||
|
|
||
|
//
|
||
|
// Get the profile directory
|
||
|
//
|
||
|
|
||
|
szProfile[0] = TEXT('\0');
|
||
|
GetEnvironmentVariable (TEXT("USERPROFILE"), szProfile, MAX_PATH);
|
||
|
|
||
|
if (szProfile[0] == TEXT('\0')) {
|
||
|
ExitThread (0);
|
||
|
}
|
||
|
DebugMsg((DM_VERBOSE, TEXT("QuotaThread: User's profile: <%s>"), szProfile));
|
||
|
|
||
|
|
||
|
//
|
||
|
// Setup change notify
|
||
|
//
|
||
|
|
||
|
hFileChange = FindFirstChangeNotification (szProfile, TRUE,
|
||
|
FILE_NOTIFY_CHANGE_FILE_NAME |
|
||
|
FILE_NOTIFY_CHANGE_DIR_NAME |
|
||
|
FILE_NOTIFY_CHANGE_SIZE);
|
||
|
|
||
|
if (hFileChange == INVALID_HANDLE_VALUE) {
|
||
|
DebugMsg((DM_WARNING, TEXT("QuotaThread: Failed to setup file change notification. %d"),
|
||
|
GetLastError()));
|
||
|
ExitThread (0);
|
||
|
}
|
||
|
|
||
|
|
||
|
lResult = RegOpenKeyEx (HKEY_CURRENT_USER,
|
||
|
TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System"),
|
||
|
0, KEY_READ, &hKeySystem);
|
||
|
|
||
|
if (lResult != ERROR_SUCCESS) {
|
||
|
DebugMsg((DM_WARNING, TEXT("QuotaThread: Failed to open registry key. %d"), lResult));
|
||
|
ExitThread (0);
|
||
|
}
|
||
|
|
||
|
|
||
|
hRegChange = CreateEvent (NULL, FALSE, FALSE, TEXT("PROQUOTA reg change event"));
|
||
|
|
||
|
if (!hRegChange) {
|
||
|
DebugMsg((DM_WARNING, TEXT("QuotaThread: Failed to setup reg event for change notification. %d"),
|
||
|
GetLastError()));
|
||
|
RegCloseKey (hKeySystem);
|
||
|
FindCloseChangeNotification (hFileChange);
|
||
|
ExitThread (0);
|
||
|
}
|
||
|
|
||
|
lResult = RegNotifyChangeKeyValue(hKeySystem, FALSE, REG_NOTIFY_CHANGE_LAST_SET,
|
||
|
hRegChange, TRUE);
|
||
|
|
||
|
if (lResult != ERROR_SUCCESS) {
|
||
|
DebugMsg((DM_WARNING, TEXT("QuotaThread: Failed to setup RegNotifyChangeKeyValue. %d"),
|
||
|
lResult));
|
||
|
CloseHandle (hRegChange);
|
||
|
RegCloseKey (hKeySystem);
|
||
|
FindCloseChangeNotification (hFileChange);
|
||
|
ExitThread (0);
|
||
|
}
|
||
|
|
||
|
|
||
|
hWaitHandles[0] = hExitEvent;
|
||
|
hWaitHandles[1] = hFileChange;
|
||
|
hWaitHandles[2] = hRegChange;
|
||
|
hWaitHandles[3] = g_hQuotaDlgEvent;
|
||
|
|
||
|
while (TRUE) {
|
||
|
|
||
|
//
|
||
|
// Calculate the profile size
|
||
|
//
|
||
|
|
||
|
if (g_hQuotaDlg) {
|
||
|
DebugMsg((DM_VERBOSE, TEXT("QuotaTHread: Enumerating profile and refreshing dialog")));
|
||
|
if (!EnumerateProfile (GetDlgItem (g_hQuotaDlg, IDC_QUOTA_FILELIST))) {
|
||
|
DebugMsg((DM_WARNING, TEXT("QuotaThread: EnumerateProfile failed with Dlg Item.")));
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
if (!EnumerateProfile (NULL)) {
|
||
|
DebugMsg((DM_WARNING, TEXT("QuotaThread: EnumerateProfile failed.")));
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Update the status icon
|
||
|
//
|
||
|
|
||
|
nid.cbSize = sizeof(nid);
|
||
|
nid.hWnd = hWnd;
|
||
|
nid.uID = 1;
|
||
|
nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
|
||
|
nid.uCallbackMessage = WM_USER;
|
||
|
szMessage[0] = TEXT('\0');
|
||
|
|
||
|
if (g_dwProfileSize > g_dwMaxProfileSize) {
|
||
|
DebugMsg((DM_VERBOSE, TEXT("QuotaThread: User has exceeded their profile quota.")));
|
||
|
nid.hIcon = hBad;
|
||
|
LoadString (hInst, IDS_SIZEBAD, szMessage, 64);
|
||
|
dwDelta = g_dwProfileSize - g_dwMaxProfileSize;
|
||
|
|
||
|
if (g_bWarnUser && !g_bWarningTimerRunning) {
|
||
|
g_bWarningTimerRunning = TRUE;
|
||
|
SetTimer (hwndMain, 1, g_dwWarnUserTimeout * 60000, NULL);
|
||
|
PostMessage (hwndMain, WM_WARNUSER, 0, 0);
|
||
|
}
|
||
|
|
||
|
} else if ( (g_dwMaxProfileSize - g_dwProfileSize) < (g_dwProfileSize * .10)) {
|
||
|
DebugMsg((DM_VERBOSE, TEXT("QuotaThread: User is within 10% of their profile quota.")));
|
||
|
nid.hIcon = hWarning;
|
||
|
LoadString (hInst, IDS_SIZEWARN, szMessage, 64);
|
||
|
dwDelta = g_dwMaxProfileSize - g_dwProfileSize;
|
||
|
|
||
|
if (g_bWarnUser && g_bWarningTimerRunning) {
|
||
|
KillTimer (hwndMain, 1);
|
||
|
g_bWarningTimerRunning = FALSE;
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
DebugMsg((DM_VERBOSE, TEXT("QuotaThread: User has space available in their profile quota.")));
|
||
|
nid.hIcon = hOk;
|
||
|
LoadString (hInst, IDS_SIZEOK, szMessage, 64);
|
||
|
dwDelta = g_dwMaxProfileSize - g_dwProfileSize;
|
||
|
|
||
|
if (g_bWarnUser && g_bWarningTimerRunning) {
|
||
|
KillTimer (hwndMain, 1);
|
||
|
g_bWarningTimerRunning = FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
_snwprintf (nid.szTip, ARRAYSIZE(nid.szTip), szMessage, dwDelta);
|
||
|
|
||
|
|
||
|
if (bFirst) {
|
||
|
if (Shell_NotifyIcon (NIM_ADD, &nid)) {
|
||
|
bFirst = FALSE;
|
||
|
}
|
||
|
} else {
|
||
|
Shell_NotifyIcon (NIM_MODIFY, &nid);
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Notify the dialog if it's present
|
||
|
//
|
||
|
|
||
|
if (g_hQuotaDlg) {
|
||
|
PostMessage (g_hQuotaDlg, WM_REFRESH, 0, 0);
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Clean up and wait for the next change
|
||
|
//
|
||
|
|
||
|
FindNextChangeNotification (hFileChange);
|
||
|
|
||
|
|
||
|
dwResult = WaitForMultipleObjects (4, hWaitHandles, FALSE, INFINITE);
|
||
|
|
||
|
|
||
|
if (dwResult == WAIT_FAILED) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
switch (dwResult - WAIT_OBJECT_0) {
|
||
|
|
||
|
case 0:
|
||
|
goto Exit;
|
||
|
break;
|
||
|
|
||
|
case 2:
|
||
|
|
||
|
EnterCriticalSection (&g_cs);
|
||
|
|
||
|
if (!ReadRegistry()) {
|
||
|
PostMessage (hwndMain, WM_DESTROY, 0, 0);
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
LeaveCriticalSection (&g_cs);
|
||
|
|
||
|
RegNotifyChangeKeyValue(hKeySystem, FALSE,
|
||
|
REG_NOTIFY_CHANGE_LAST_SET,
|
||
|
hRegChange, TRUE);
|
||
|
// fall through
|
||
|
|
||
|
case 1:
|
||
|
Sleep (2000);
|
||
|
DebugMsg((DM_VERBOSE, TEXT("QuotaThread: Running background enumeration.")));
|
||
|
break;
|
||
|
|
||
|
case 3:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
Exit:
|
||
|
|
||
|
RegCloseKey (hKeySystem);
|
||
|
CloseHandle (hRegChange);
|
||
|
FindCloseChangeNotification (hFileChange);
|
||
|
DebugMsg((DM_VERBOSE, TEXT("QuotaThread: Leaving...")));
|
||
|
ExitThread (0);
|
||
|
|
||
|
}
|
||
|
|
||
|
//*************************************************************
|
||
|
//
|
||
|
// SetSecurity()
|
||
|
//
|
||
|
// Purpose: Removes TERMINATE_PROCESS access to this process
|
||
|
// so taskman can't blow us away.
|
||
|
//
|
||
|
// Parameters:
|
||
|
//
|
||
|
// Return: TRUE if successful
|
||
|
// FALSE if an error occurs
|
||
|
//
|
||
|
//*************************************************************
|
||
|
|
||
|
BOOL SetSecurity (void)
|
||
|
{
|
||
|
HANDLE hProcess;
|
||
|
PACL pDACL;
|
||
|
PSECURITY_DESCRIPTOR pSD;
|
||
|
WORD wIndex;
|
||
|
ACE_HEADER * lpAceHeader;
|
||
|
ACCESS_ALLOWED_ACE * lpAce;
|
||
|
DWORD dwResult;
|
||
|
|
||
|
hProcess = GetCurrentProcess();
|
||
|
|
||
|
if (GetSecurityInfo (hProcess, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION,
|
||
|
NULL, NULL, &pDACL, NULL, &pSD) != ERROR_SUCCESS) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
for (wIndex = 0; wIndex < pDACL->AceCount; wIndex++) {
|
||
|
|
||
|
if (GetAce(pDACL, wIndex, &lpAceHeader)) {
|
||
|
|
||
|
if (lpAceHeader->AceType == ACCESS_ALLOWED_ACE_TYPE) {
|
||
|
lpAce = (ACCESS_ALLOWED_ACE *) lpAceHeader;
|
||
|
|
||
|
lpAce->Mask &= ~(PROCESS_TERMINATE | WRITE_DAC | WRITE_OWNER);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
dwResult = SetSecurityInfo (hProcess, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION,
|
||
|
NULL, NULL, pDACL, NULL);
|
||
|
|
||
|
LocalFree (pSD);
|
||
|
|
||
|
if (dwResult != ERROR_SUCCESS) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
//*************************************************************
|
||
|
//
|
||
|
// ReadExclusionList()
|
||
|
//
|
||
|
// Purpose: Checks if the profile quota policy is set,
|
||
|
// and if so gets the max profile size.
|
||
|
//
|
||
|
// Parameters: void
|
||
|
//
|
||
|
// Return: TRUE if profile quota is enabled
|
||
|
// FALSE if not
|
||
|
//
|
||
|
//*************************************************************
|
||
|
|
||
|
BOOL ReadExclusionList()
|
||
|
{
|
||
|
TCHAR szExcludeList2[MAX_PATH];
|
||
|
TCHAR szExcludeList1[MAX_PATH];
|
||
|
HKEY hKey;
|
||
|
DWORD dwSize, dwType;
|
||
|
|
||
|
//
|
||
|
// Check for a list of directories to exclude both user preferences
|
||
|
// and user policy
|
||
|
//
|
||
|
|
||
|
szExcludeList1[0] = TEXT('\0');
|
||
|
if (RegOpenKeyEx (HKEY_CURRENT_USER,
|
||
|
TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"),
|
||
|
0, KEY_READ, &hKey) == ERROR_SUCCESS) {
|
||
|
|
||
|
dwSize = sizeof(szExcludeList1);
|
||
|
RegQueryValueEx (hKey,
|
||
|
TEXT("ExcludeProfileDirs"),
|
||
|
NULL,
|
||
|
&dwType,
|
||
|
(LPBYTE) szExcludeList1,
|
||
|
&dwSize);
|
||
|
|
||
|
RegCloseKey (hKey);
|
||
|
}
|
||
|
|
||
|
szExcludeList2[0] = TEXT('\0');
|
||
|
if (RegOpenKeyEx (HKEY_CURRENT_USER,
|
||
|
SYSTEM_POLICIES_KEY,
|
||
|
0, KEY_READ, &hKey) == ERROR_SUCCESS) {
|
||
|
|
||
|
dwSize = sizeof(szExcludeList2);
|
||
|
RegQueryValueEx (hKey,
|
||
|
TEXT("ExcludeProfileDirs"),
|
||
|
NULL,
|
||
|
&dwType,
|
||
|
(LPBYTE) szExcludeList2,
|
||
|
&dwSize);
|
||
|
|
||
|
RegCloseKey (hKey);
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Merge the user preferences and policy together
|
||
|
//
|
||
|
|
||
|
g_szExcludeList[0] = TEXT('\0');
|
||
|
|
||
|
if (szExcludeList1[0] != TEXT('\0')) {
|
||
|
CheckSemicolon(szExcludeList1);
|
||
|
lstrcpy (g_szExcludeList, szExcludeList1);
|
||
|
}
|
||
|
|
||
|
if (szExcludeList2[0] != TEXT('\0')) {
|
||
|
lstrcat (g_szExcludeList, szExcludeList2);
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
//*************************************************************
|
||
|
//
|
||
|
// ReadQuotaMsg()
|
||
|
//
|
||
|
// Purpose: Reads the msg that needs to be displayed.
|
||
|
//
|
||
|
// Parameters: hKey - Handle to the open policy
|
||
|
//
|
||
|
// Return: TRUE if mesg could be read
|
||
|
// FALSE otherwise
|
||
|
//
|
||
|
//*************************************************************
|
||
|
BOOL ReadQuotaMsg(HKEY hKey)
|
||
|
{
|
||
|
DWORD dwType, dwSize, dwValue, dwErr;
|
||
|
|
||
|
if (g_lpQuotaMessage) {
|
||
|
LocalFree(g_lpQuotaMessage);
|
||
|
g_lpQuotaMessage = NULL;
|
||
|
}
|
||
|
|
||
|
dwSize = sizeof(TCHAR)*500;
|
||
|
g_lpQuotaMessage = LocalAlloc (LPTR, dwSize);
|
||
|
|
||
|
if (!g_lpQuotaMessage) {
|
||
|
DebugMsg((DM_WARNING, TEXT("ReadRegistry: Failed to allocate memory for msg with %d."), GetLastError()));
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
dwErr = RegQueryValueEx (hKey, TEXT("ProfileQuotaMessage"), NULL,
|
||
|
&dwType, (LPBYTE) g_lpQuotaMessage, &dwSize);
|
||
|
|
||
|
if (dwErr == ERROR_MORE_DATA) {
|
||
|
LPTSTR lpTemp1;
|
||
|
|
||
|
//
|
||
|
// Go in again with a larger buffer
|
||
|
//
|
||
|
|
||
|
lpTemp1 = LocalReAlloc(g_lpQuotaMessage, dwSize,
|
||
|
LMEM_MOVEABLE | LMEM_ZEROINIT);
|
||
|
|
||
|
if (!lpTemp1) {
|
||
|
DebugMsg((DM_WARNING, TEXT("ReadRegistry: Failed to reallocate memory for msg with %d."), GetLastError()));
|
||
|
LocalFree(g_lpQuotaMessage);
|
||
|
g_lpQuotaMessage = NULL;
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
g_lpQuotaMessage = lpTemp1;
|
||
|
|
||
|
dwErr = RegQueryValueEx (hKey, TEXT("ProfileQuotaMessage"), NULL,
|
||
|
&dwType, (LPBYTE) g_lpQuotaMessage, &dwSize);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Load the default message otherwise
|
||
|
//
|
||
|
|
||
|
if (dwErr != ERROR_SUCCESS) {
|
||
|
dwSize = sizeof(TCHAR)*500;
|
||
|
LoadString (hInst, IDS_DEFAULTMSG, g_lpQuotaMessage, 500);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// if there is any message expand the environment variables in it.
|
||
|
//
|
||
|
//
|
||
|
|
||
|
if (*g_lpQuotaMessage) {
|
||
|
LPTSTR lpTemp1, lpTemp2;
|
||
|
|
||
|
dwSize = sizeof(TCHAR)*500;
|
||
|
lpTemp1 = LocalAlloc (LPTR, dwSize);
|
||
|
|
||
|
if (lpTemp1) {
|
||
|
dwSize = ExpandEnvironmentStrings (g_lpQuotaMessage, lpTemp1, 500);
|
||
|
|
||
|
if (dwSize <= 500)
|
||
|
lstrcpy (g_lpQuotaMessage, lpTemp1);
|
||
|
else {
|
||
|
lpTemp2 = LocalReAlloc(lpTemp1, dwSize*sizeof(TCHAR),
|
||
|
LMEM_MOVEABLE | LMEM_ZEROINIT);
|
||
|
|
||
|
if (lpTemp2) {
|
||
|
lpTemp1 = lpTemp2;
|
||
|
|
||
|
//
|
||
|
// go in with a larger buffer
|
||
|
//
|
||
|
|
||
|
ExpandEnvironmentStrings (g_lpQuotaMessage, lpTemp1, dwSize);
|
||
|
|
||
|
lpTemp2 = LocalReAlloc(g_lpQuotaMessage, dwSize*sizeof(TCHAR),
|
||
|
LMEM_MOVEABLE | LMEM_ZEROINIT);
|
||
|
|
||
|
if (lpTemp2) {
|
||
|
g_lpQuotaMessage = lpTemp2;
|
||
|
lstrcpy (g_lpQuotaMessage, lpTemp1);
|
||
|
} else {
|
||
|
DebugMsg((DM_WARNING, TEXT("ReadRegistry: Failed to resize msg buffer with %d.Not expanding env var"), GetLastError()));
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
DebugMsg((DM_WARNING, TEXT("ReadRegistry: Failed to reallocate memory for tmp buffer with %d.Not expanding env var"), GetLastError()));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
LocalFree (lpTemp1);
|
||
|
} else {
|
||
|
DebugMsg((DM_WARNING, TEXT("ReadRegistry: Failed to allocate memory for tmp buffer with %d.Not expanding env var"), GetLastError()));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
|
||
|
}
|
||
|
|
||
|
//*************************************************************
|
||
|
//
|
||
|
// ReadRegistry()
|
||
|
//
|
||
|
// Purpose: Checks if the profile quota policy is set,
|
||
|
// and if so gets the max profile size.
|
||
|
//
|
||
|
// Parameters: void
|
||
|
//
|
||
|
// Return: TRUE if profile quota is enabled
|
||
|
// FALSE if not
|
||
|
//
|
||
|
//*************************************************************
|
||
|
BOOL ReadRegistry (void)
|
||
|
{
|
||
|
LONG lResult;
|
||
|
HKEY hKey;
|
||
|
DWORD dwType, dwSize, dwValue, dwErr;
|
||
|
|
||
|
lResult = RegOpenKeyEx (HKEY_CURRENT_USER,
|
||
|
TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System"),
|
||
|
0, KEY_READ, &hKey);
|
||
|
|
||
|
if (lResult == ERROR_SUCCESS) {
|
||
|
|
||
|
dwSize = sizeof(dwValue);
|
||
|
lResult = RegQueryValueEx (hKey, TEXT("EnableProfileQuota"), NULL,
|
||
|
&dwType, (LPBYTE) &dwValue, &dwSize);
|
||
|
|
||
|
if (lResult == ERROR_SUCCESS) {
|
||
|
|
||
|
if (dwValue) {
|
||
|
|
||
|
DebugMsg((DM_VERBOSE, TEXT("ReadRegistry: Profile quotas are enabled.")));
|
||
|
|
||
|
dwSize = sizeof(g_dwMaxProfileSize);
|
||
|
RegQueryValueEx (hKey, TEXT("MaxProfileSize"), NULL,
|
||
|
&dwType, (LPBYTE) &g_dwMaxProfileSize, &dwSize);
|
||
|
DebugMsg((DM_VERBOSE, TEXT("ReadRegistry: Max Profile Size: %d"), g_dwMaxProfileSize));
|
||
|
|
||
|
|
||
|
dwSize = sizeof(g_bShowReg);
|
||
|
RegQueryValueEx (hKey, TEXT("IncludeRegInProQuota"), NULL,
|
||
|
&dwType, (LPBYTE) &g_bShowReg, &dwSize);
|
||
|
DebugMsg((DM_VERBOSE, TEXT("ReadRegistry: Show registry in file list: %s"),
|
||
|
g_bShowReg ? TEXT("TRUE") : TEXT("FALSE")));
|
||
|
|
||
|
|
||
|
dwSize = sizeof(g_bWarnUser);
|
||
|
RegQueryValueEx (hKey, TEXT("WarnUser"), NULL,
|
||
|
&dwType, (LPBYTE) &g_bWarnUser, &dwSize);
|
||
|
DebugMsg((DM_VERBOSE, TEXT("ReadRegistry: Warn user when quota exceeded: %s"),
|
||
|
g_bWarnUser ? TEXT("TRUE") : TEXT("FALSE")));
|
||
|
|
||
|
|
||
|
if (g_bWarnUser) {
|
||
|
|
||
|
dwSize = sizeof(g_dwWarnUserTimeout);
|
||
|
if (RegQueryValueEx (hKey, TEXT("WarnUserTimeout"), NULL,
|
||
|
&dwType, (LPBYTE) &g_dwWarnUserTimeout, &dwSize) == ERROR_SUCCESS) {
|
||
|
|
||
|
if (g_dwWarnUserTimeout > 1440) {
|
||
|
g_dwWarnUserTimeout = 1440;
|
||
|
}
|
||
|
|
||
|
DebugMsg((DM_VERBOSE, TEXT("ReadRegistry: User warning reminder timeout: %d"), g_dwWarnUserTimeout));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Now read the message that needs to be displayed
|
||
|
//
|
||
|
|
||
|
if (!ReadQuotaMsg(hKey)) {
|
||
|
RegCloseKey (hKey);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
if (ReadExclusionList()) {
|
||
|
RegCloseKey (hKey);
|
||
|
return TRUE;
|
||
|
}
|
||
|
else {
|
||
|
DebugMsg((DM_VERBOSE, TEXT("ReadRegistry: Failed to read the ExclusionList")));
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
DebugMsg((DM_VERBOSE, TEXT("ReadRegistry: Profile quotas are DISABLED.")));
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
DebugMsg((DM_VERBOSE, TEXT("ReadRegistry: Failed to query EnableProfileQuota with error %d."), lResult));
|
||
|
}
|
||
|
|
||
|
RegCloseKey (hKey);
|
||
|
|
||
|
} else {
|
||
|
DebugMsg((DM_VERBOSE, TEXT("ReadRegistry: Failed to open System policy key with error %d."), lResult));
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
//*************************************************************
|
||
|
//
|
||
|
// CheckSlash()
|
||
|
//
|
||
|
// Purpose: Checks for an ending slash and adds one if
|
||
|
// it is missing.
|
||
|
//
|
||
|
// Parameters: lpDir - directory
|
||
|
//
|
||
|
// Return: Pointer to the end of the string
|
||
|
//
|
||
|
// Comments:
|
||
|
//
|
||
|
// History: Date Author Comment
|
||
|
// 6/19/95 ericflo Created
|
||
|
//
|
||
|
//*************************************************************
|
||
|
LPTSTR CheckSlash (LPTSTR lpDir)
|
||
|
{
|
||
|
DWORD dwStrLen;
|
||
|
LPTSTR lpEnd;
|
||
|
|
||
|
lpEnd = lpDir + lstrlen(lpDir);
|
||
|
|
||
|
if (*(lpEnd - 1) != TEXT('\\')) {
|
||
|
*lpEnd = TEXT('\\');
|
||
|
lpEnd++;
|
||
|
*lpEnd = TEXT('\0');
|
||
|
}
|
||
|
|
||
|
return lpEnd;
|
||
|
}
|
||
|
|
||
|
//*************************************************************
|
||
|
//
|
||
|
// CheckSemicolon()
|
||
|
//
|
||
|
// Purpose: Checks for an ending slash and adds one if
|
||
|
// it is missing.
|
||
|
//
|
||
|
// Parameters: lpDir - directory
|
||
|
//
|
||
|
// Return: Pointer to the end of the string
|
||
|
//
|
||
|
// Comments:
|
||
|
//
|
||
|
// History: Date Author Comment
|
||
|
// 6/19/95 ericlfo Created
|
||
|
//
|
||
|
//*************************************************************
|
||
|
LPTSTR CheckSemicolon (LPTSTR lpDir)
|
||
|
{
|
||
|
LPTSTR lpEnd;
|
||
|
|
||
|
lpEnd = lpDir + lstrlen(lpDir);
|
||
|
|
||
|
if (*(lpEnd - 1) != TEXT(';')) {
|
||
|
*lpEnd = TEXT(';');
|
||
|
lpEnd++;
|
||
|
*lpEnd = TEXT('\0');
|
||
|
}
|
||
|
|
||
|
return lpEnd;
|
||
|
}
|
||
|
|
||
|
//*************************************************************
|
||
|
//
|
||
|
// RecurseDirectory()
|
||
|
//
|
||
|
// Purpose: Recurses through the subdirectories counting the size.
|
||
|
//
|
||
|
// Parameters: lpDir - Directory
|
||
|
// lpTop - Top of the display name
|
||
|
// hLV - Listview window handle (optional)
|
||
|
// lpExcludeList - Null-termed list of dirs to be skipped (optional)
|
||
|
//
|
||
|
// Return: TRUE if successful
|
||
|
// FALSE if an error occurs
|
||
|
//
|
||
|
// Comments:
|
||
|
//
|
||
|
// History: Date Author Comment
|
||
|
// 1/30/96 ericflo Created
|
||
|
// 12/22/98 ushaji Added exclusionlist support
|
||
|
// Notes:
|
||
|
// The buffer size expected is MAX_PATH+4 for some internal processing
|
||
|
// We should fix this to be better post Win 2K.
|
||
|
//*************************************************************
|
||
|
|
||
|
BOOL RecurseDirectory (LPTSTR lpDir, LPTSTR lpTop, HWND hLV, LPTSTR lpExcludeList)
|
||
|
{
|
||
|
HANDLE hFile = INVALID_HANDLE_VALUE;
|
||
|
WIN32_FIND_DATA fd;
|
||
|
LPTSTR lpEnd, lpTemp;
|
||
|
BOOL bResult = TRUE;
|
||
|
BOOL bSkip;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Setup the ending pointer
|
||
|
//
|
||
|
|
||
|
lpEnd = CheckSlash (lpDir);
|
||
|
|
||
|
|
||
|
//
|
||
|
// Append *.* to the source directory
|
||
|
//
|
||
|
|
||
|
lstrcpy(lpEnd, TEXT("*.*"));
|
||
|
|
||
|
|
||
|
|
||
|
//
|
||
|
// Search through the source directory
|
||
|
//
|
||
|
|
||
|
hFile = FindFirstFile(lpDir, &fd);
|
||
|
|
||
|
if (hFile == INVALID_HANDLE_VALUE) {
|
||
|
|
||
|
if ( (GetLastError() == ERROR_FILE_NOT_FOUND) ||
|
||
|
(GetLastError() == ERROR_PATH_NOT_FOUND) ) {
|
||
|
|
||
|
//
|
||
|
// bResult is already initialized to TRUE, so
|
||
|
// just fall through.
|
||
|
//
|
||
|
|
||
|
} else {
|
||
|
|
||
|
DebugMsg((DM_WARNING, TEXT("RecurseDirectory: FindFirstFile for <%s> failed with %d."),
|
||
|
lpDir, GetLastError()));
|
||
|
bResult = FALSE;
|
||
|
}
|
||
|
|
||
|
goto RecurseDir_Exit;
|
||
|
}
|
||
|
|
||
|
|
||
|
do {
|
||
|
|
||
|
//
|
||
|
// Append the file / directory name to the working buffer
|
||
|
//
|
||
|
|
||
|
// skip the file if the path > MAX_PATH
|
||
|
|
||
|
if ((1+lstrlen(fd.cFileName)+lstrlen(lpDir)+lstrlen(TEXT("\\*.*"))) >= 2*MAX_PATH) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
lstrcpy (lpEnd, fd.cFileName);
|
||
|
|
||
|
|
||
|
if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||
|
|
||
|
//
|
||
|
// Check for "." and ".."
|
||
|
//
|
||
|
|
||
|
if (!lstrcmpi(fd.cFileName, TEXT("."))) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (!lstrcmpi(fd.cFileName, TEXT(".."))) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Check if this directory should be excluded
|
||
|
//
|
||
|
|
||
|
if (lpExcludeList) {
|
||
|
|
||
|
bSkip = FALSE;
|
||
|
lpTemp = lpExcludeList;
|
||
|
|
||
|
while (*lpTemp) {
|
||
|
|
||
|
if (lstrcmpi (lpTemp, lpDir) == 0) {
|
||
|
bSkip = TRUE;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
lpTemp += lstrlen (lpTemp) + 1;
|
||
|
}
|
||
|
|
||
|
if (bSkip) {
|
||
|
DebugMsg((DM_VERBOSE, TEXT("RecurseDirectory: Skipping <%s> due to exclusion list."),
|
||
|
lpDir));
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Found a directory.
|
||
|
//
|
||
|
// 1) Change into that subdirectory on the source drive.
|
||
|
// 2) Recurse down that tree.
|
||
|
// 3) Back up one level.
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// Recurse the subdirectory
|
||
|
//
|
||
|
|
||
|
if (!RecurseDirectory(lpDir, lpTop, hLV, lpExcludeList)) {
|
||
|
bResult = FALSE;
|
||
|
goto RecurseDir_Exit;
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
|
||
|
//
|
||
|
// Found a file, add the filesize and put in the listview
|
||
|
// if appropriate.
|
||
|
//
|
||
|
|
||
|
g_dwProfileSizeTemp += fd.nFileSizeLow;
|
||
|
DebugMsg((DM_VERBOSE, TEXT("RecurseDirectory: Profile Size <%d> after <%s> "), g_dwProfileSizeTemp,
|
||
|
fd.cFileName));
|
||
|
|
||
|
if (hLV) {
|
||
|
LV_ITEM lvi;
|
||
|
BOOL bAddItem = TRUE;
|
||
|
|
||
|
if ((lstrlen(fd.cFileName) >= 6) &&
|
||
|
(CompareString (LOCALE_USER_DEFAULT, NORM_IGNORECASE,
|
||
|
TEXT("ntuser"), 6,
|
||
|
fd.cFileName, 6) == 2)) {
|
||
|
bAddItem = (g_bShowReg ? TRUE : FALSE);
|
||
|
}
|
||
|
|
||
|
if (bAddItem && g_bHideSmallItems && (fd.nFileSizeLow <= 2048)) {
|
||
|
bAddItem = FALSE;
|
||
|
}
|
||
|
|
||
|
if (bAddItem) {
|
||
|
TCHAR szSize[40];
|
||
|
DWORD dwFileSize;
|
||
|
INT iItem;
|
||
|
|
||
|
lvi.mask = LVIF_TEXT | LVIF_STATE | LVIF_PARAM;
|
||
|
lvi.iItem = 0;
|
||
|
lvi.iSubItem = 0;
|
||
|
lvi.state = 0;
|
||
|
lvi.stateMask = LVIS_FOCUSED | LVIS_SELECTED;
|
||
|
lvi.pszText = lpTop;
|
||
|
lvi.lParam = fd.nFileSizeLow;
|
||
|
|
||
|
iItem = ListView_InsertItem (hLV, &lvi);
|
||
|
|
||
|
if (fd.nFileSizeLow <= 1024) {
|
||
|
dwFileSize = 1;
|
||
|
} else {
|
||
|
dwFileSize = fd.nFileSizeLow / 1024;
|
||
|
}
|
||
|
_snwprintf (szSize, ARRAYSIZE(szSize), szSizeFormat, dwFileSize);
|
||
|
|
||
|
lvi.mask = LVIF_TEXT | LVIF_STATE;
|
||
|
lvi.iItem = iItem;
|
||
|
lvi.iSubItem = 1;
|
||
|
lvi.state = 0;
|
||
|
lvi.stateMask = LVIS_FOCUSED | LVIS_SELECTED;
|
||
|
lvi.pszText = szSize;
|
||
|
lvi.lParam = fd.nFileSizeLow;
|
||
|
|
||
|
ListView_SetItem (hLV, &lvi);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Find the next entry
|
||
|
//
|
||
|
|
||
|
} while (FindNextFile(hFile, &fd));
|
||
|
|
||
|
|
||
|
RecurseDir_Exit:
|
||
|
|
||
|
//
|
||
|
// Remove the file / directory name appended above
|
||
|
//
|
||
|
|
||
|
*lpEnd = TEXT('\0');
|
||
|
|
||
|
|
||
|
//
|
||
|
// Close the search handle
|
||
|
//
|
||
|
|
||
|
if (hFile != INVALID_HANDLE_VALUE) {
|
||
|
FindClose(hFile);
|
||
|
}
|
||
|
|
||
|
return bResult;
|
||
|
}
|
||
|
|
||
|
//*************************************************************
|
||
|
//
|
||
|
// CenterWindow()
|
||
|
//
|
||
|
// Purpose: Centers a window on the screen
|
||
|
//
|
||
|
// Parameters: hwnd - window handle to center
|
||
|
//
|
||
|
// Return: void
|
||
|
//
|
||
|
// Comments:
|
||
|
//
|
||
|
// History: Date Author Comment
|
||
|
// 2/21/96 ericflo Ported
|
||
|
//
|
||
|
//*************************************************************
|
||
|
|
||
|
void CenterWindow (HWND hwnd)
|
||
|
{
|
||
|
RECT rect;
|
||
|
LONG dx, dy;
|
||
|
LONG dxParent, dyParent;
|
||
|
LONG Style;
|
||
|
|
||
|
//
|
||
|
// Get window rect
|
||
|
//
|
||
|
|
||
|
GetWindowRect(hwnd, &rect);
|
||
|
|
||
|
dx = rect.right - rect.left;
|
||
|
dy = rect.bottom - rect.top;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Get parent rect
|
||
|
//
|
||
|
|
||
|
Style = GetWindowLong(hwnd, GWL_STYLE);
|
||
|
if ((Style & WS_CHILD) == 0) {
|
||
|
|
||
|
//
|
||
|
// Return the desktop windows size (size of main screen)
|
||
|
//
|
||
|
|
||
|
dxParent = GetSystemMetrics(SM_CXSCREEN);
|
||
|
dyParent = GetSystemMetrics(SM_CYSCREEN);
|
||
|
} else {
|
||
|
HWND hwndParent;
|
||
|
RECT rectParent;
|
||
|
|
||
|
hwndParent = GetParent(hwnd);
|
||
|
if (hwndParent == NULL) {
|
||
|
hwndParent = GetDesktopWindow();
|
||
|
}
|
||
|
|
||
|
GetWindowRect(hwndParent, &rectParent);
|
||
|
|
||
|
dxParent = rectParent.right - rectParent.left;
|
||
|
dyParent = rectParent.bottom - rectParent.top;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Center the child in the parent
|
||
|
//
|
||
|
|
||
|
rect.left = (dxParent - dx) / 2;
|
||
|
rect.top = (dyParent - dy) / 3;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Move the child into position
|
||
|
//
|
||
|
|
||
|
SetWindowPos(hwnd, HWND_TOP, rect.left, rect.top, 0, 0, SWP_NOSIZE);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//*************************************************************
|
||
|
//
|
||
|
// QuotaDlgProc()
|
||
|
//
|
||
|
// Purpose: Quota dialog box
|
||
|
//
|
||
|
// Parameters: hDlg - Window handle
|
||
|
// message - Window message
|
||
|
// wParam - WPARAM
|
||
|
// lParam - LPARAM
|
||
|
//
|
||
|
// Return: TRUE if successful
|
||
|
// FALSE if an error occurs
|
||
|
//
|
||
|
//*************************************************************
|
||
|
|
||
|
LRESULT CALLBACK QuotaDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
TCHAR szBuffer[40];
|
||
|
TCHAR szSize[40];
|
||
|
HWND hLV;
|
||
|
LV_COLUMN col;
|
||
|
RECT rect;
|
||
|
INT cx;
|
||
|
HKEY hKey;
|
||
|
DWORD dwSize, dwType;
|
||
|
LPTSTR lpMessage;
|
||
|
|
||
|
|
||
|
switch (message) {
|
||
|
case WM_INITDIALOG:
|
||
|
|
||
|
hLV = GetDlgItem (hDlg, IDC_QUOTA_FILELIST);
|
||
|
|
||
|
|
||
|
//
|
||
|
// Add the columns to the listview
|
||
|
//
|
||
|
|
||
|
GetClientRect (hLV, &rect);
|
||
|
cx = (rect.right * 31) / 40;
|
||
|
|
||
|
LoadString (hInst, IDS_COLUMN1, szBuffer, 40);
|
||
|
|
||
|
col.mask = LVCF_FMT | LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH;
|
||
|
col.fmt = LVCFMT_LEFT;
|
||
|
col.cx = cx;
|
||
|
col.pszText = szBuffer;
|
||
|
col.iSubItem = 0;
|
||
|
ListView_InsertColumn (hLV, 0, &col);
|
||
|
|
||
|
LoadString (hInst, IDS_COLUMN2, szBuffer, 40);
|
||
|
|
||
|
col.cx = rect.right - cx - GetSystemMetrics(SM_CYHSCROLL);
|
||
|
col.fmt = LVCFMT_RIGHT;
|
||
|
col.iSubItem = 1;
|
||
|
ListView_InsertColumn (hLV, 1, &col);
|
||
|
|
||
|
|
||
|
//
|
||
|
// Hide small items by default
|
||
|
//
|
||
|
|
||
|
g_bHideSmallItems = TRUE;
|
||
|
CheckDlgButton (hDlg, IDC_QUOTA_HIDESMALL, BST_CHECKED);
|
||
|
|
||
|
|
||
|
CenterWindow (hDlg);
|
||
|
SetForegroundWindow (hDlg);
|
||
|
|
||
|
|
||
|
// EnumerateProfile (GetDlgItem (hDlg, IDC_QUOTA_FILELIST));
|
||
|
|
||
|
|
||
|
dwSize = 500 * sizeof(TCHAR);
|
||
|
lpMessage = LocalAlloc (LPTR, dwSize);
|
||
|
if (!lpMessage)
|
||
|
break;
|
||
|
|
||
|
LoadString (hInst ,IDS_QUOTAENUMMSG, lpMessage, 500);
|
||
|
|
||
|
SetDlgItemText (hDlg, IDC_QUOTA_TEXT, lpMessage);
|
||
|
|
||
|
|
||
|
if (g_dwProfileSize > g_dwMaxProfileSize) {
|
||
|
SendDlgItemMessage (hDlg, IDC_QUOTA_ICON, STM_SETICON, (WPARAM) hIconStop, 0);
|
||
|
|
||
|
} else if ( (g_dwMaxProfileSize - g_dwProfileSize) < (g_dwProfileSize * .10)) {
|
||
|
SendDlgItemMessage (hDlg, IDC_QUOTA_ICON, STM_SETICON, (WPARAM) hIconCaution, 0);
|
||
|
|
||
|
} else {
|
||
|
SendDlgItemMessage (hDlg, IDC_QUOTA_ICON, STM_SETICON, (WPARAM) hIconGood, 0);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Setting the global value at the end QuotaThread is not trying
|
||
|
// to refresh the dialog etc. at the same time.
|
||
|
//
|
||
|
|
||
|
g_hQuotaDlg = hDlg;
|
||
|
|
||
|
SetEvent(g_hQuotaDlgEvent);
|
||
|
|
||
|
LocalFree (lpMessage);
|
||
|
|
||
|
break;
|
||
|
|
||
|
case WM_REFRESH:
|
||
|
|
||
|
//
|
||
|
// Popuplate the listview
|
||
|
//
|
||
|
|
||
|
|
||
|
//
|
||
|
// Set the size information
|
||
|
//
|
||
|
|
||
|
_snwprintf (szSize, ARRAYSIZE(szSize), szSizeFormat, g_dwProfileSize);
|
||
|
SetDlgItemText (hDlg, IDC_QUOTA_SIZE, szSize);
|
||
|
|
||
|
_snwprintf (szSize, ARRAYSIZE(szSize), szSizeFormat, g_dwMaxProfileSize);
|
||
|
SetDlgItemText (hDlg, IDC_QUOTA_MAXSIZE, szSize);
|
||
|
|
||
|
|
||
|
dwSize = 500 * sizeof(TCHAR);
|
||
|
lpMessage = LocalAlloc (LPTR, dwSize);
|
||
|
|
||
|
if (!lpMessage) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (g_dwProfileSize > g_dwMaxProfileSize) {
|
||
|
|
||
|
//
|
||
|
// This messge is already read
|
||
|
//
|
||
|
|
||
|
SetDlgItemText (hDlg, IDC_QUOTA_TEXT, g_lpQuotaMessage);
|
||
|
SendDlgItemMessage (hDlg, IDC_QUOTA_ICON, STM_SETICON, (WPARAM) hIconStop, 0);
|
||
|
|
||
|
} else if ( (g_dwMaxProfileSize - g_dwProfileSize) < (g_dwProfileSize * .10)) {
|
||
|
|
||
|
LoadString (hInst, IDS_CAUTION, lpMessage, 500);
|
||
|
SetDlgItemText (hDlg, IDC_QUOTA_TEXT, lpMessage);
|
||
|
|
||
|
SendDlgItemMessage (hDlg, IDC_QUOTA_ICON, STM_SETICON, (WPARAM) hIconCaution, 0);
|
||
|
|
||
|
} else {
|
||
|
|
||
|
LoadString (hInst, IDS_LOGOFFOK, lpMessage, 500);
|
||
|
SetDlgItemText (hDlg, IDC_QUOTA_TEXT, lpMessage);
|
||
|
|
||
|
SendDlgItemMessage (hDlg, IDC_QUOTA_ICON, STM_SETICON, (WPARAM) hIconGood, 0);
|
||
|
}
|
||
|
|
||
|
LocalFree (lpMessage);
|
||
|
break;
|
||
|
|
||
|
|
||
|
case WM_COMMAND:
|
||
|
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {
|
||
|
g_hQuotaDlg = NULL;
|
||
|
if ((g_dwProfileSize < g_dwMaxProfileSize) && (g_bQueryEndSession) && (g_dwProfileSize != 0)) {
|
||
|
PostMessage (hwndMain, WM_EXITWINDOWS, 0, 0);
|
||
|
}
|
||
|
EndDialog(hDlg, TRUE);
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
if (LOWORD(wParam) == IDC_QUOTA_HIDESMALL) {
|
||
|
g_bHideSmallItems = IsDlgButtonChecked (hDlg, IDC_QUOTA_HIDESMALL);
|
||
|
EnumerateProfile (GetDlgItem(hDlg, IDC_QUOTA_FILELIST));
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//*************************************************************
|
||
|
//
|
||
|
// ListViewSortCallback()
|
||
|
//
|
||
|
// Purpose: List view callback function for sorting
|
||
|
//
|
||
|
// Parameters: lParam1 - lParam1
|
||
|
// lParam2 - lParam2
|
||
|
// lParamSort - Column id
|
||
|
//
|
||
|
// Return: -1, 0, 1
|
||
|
//
|
||
|
//*************************************************************
|
||
|
INT CALLBACK ListViewSortCallback (LPARAM lParam1, LPARAM lParam2,
|
||
|
LPARAM lParamSort)
|
||
|
{
|
||
|
|
||
|
if (lParam1 < lParam2) {
|
||
|
return 1;
|
||
|
|
||
|
} else if (lParam1 == lParam2) {
|
||
|
return 0;
|
||
|
|
||
|
} else {
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
//*************************************************************
|
||
|
//
|
||
|
// ConvertExclusionList()
|
||
|
//
|
||
|
// Purpose: Converts the semi-colon profile relative exclusion
|
||
|
// list to fully qualified null terminated exclusion
|
||
|
// list
|
||
|
//
|
||
|
// Parameters: lpSourceDir - Profile root directory
|
||
|
// lpExclusionList - List of directories to exclude
|
||
|
//
|
||
|
// Return: List if successful
|
||
|
// NULL if an error occurs
|
||
|
//
|
||
|
//*************************************************************
|
||
|
|
||
|
LPTSTR ConvertExclusionList (LPCTSTR lpSourceDir, LPCTSTR lpExclusionList)
|
||
|
{
|
||
|
LPTSTR lpExcludeList = NULL, lpInsert, lpEnd, lpTempList;
|
||
|
LPCTSTR lpTemp, lpDir;
|
||
|
TCHAR szTemp[MAX_PATH];
|
||
|
DWORD dwSize = 2; // double null terminator
|
||
|
DWORD dwStrLen;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Setup a temp buffer to work with
|
||
|
//
|
||
|
|
||
|
lstrcpy (szTemp, lpSourceDir);
|
||
|
lpEnd = CheckSlash (szTemp);
|
||
|
|
||
|
|
||
|
//
|
||
|
// Loop through the list
|
||
|
//
|
||
|
|
||
|
lpTemp = lpDir = lpExclusionList;
|
||
|
|
||
|
while (*lpTemp) {
|
||
|
|
||
|
//
|
||
|
// Look for the semicolon separator
|
||
|
//
|
||
|
|
||
|
while (*lpTemp && ((*lpTemp) != TEXT(';'))) {
|
||
|
lpTemp++;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Remove any leading spaces
|
||
|
//
|
||
|
|
||
|
while (*lpDir == TEXT(' ')) {
|
||
|
lpDir++;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Put the directory name on the temp buffer
|
||
|
//
|
||
|
|
||
|
lstrcpyn (lpEnd, lpDir, (int)(lpTemp - lpDir + 1));
|
||
|
|
||
|
|
||
|
//
|
||
|
// Add the string to the exclusion list
|
||
|
//
|
||
|
|
||
|
if (lpExcludeList) {
|
||
|
|
||
|
dwStrLen = lstrlen (szTemp) + 1;
|
||
|
dwSize += dwStrLen;
|
||
|
|
||
|
lpTempList = LocalReAlloc (lpExcludeList, dwSize * sizeof(TCHAR),
|
||
|
LMEM_MOVEABLE | LMEM_ZEROINIT);
|
||
|
|
||
|
if (!lpTempList) {
|
||
|
DebugMsg((DM_WARNING, TEXT("ConvertExclusionList: Failed to realloc memory with %d"), GetLastError()));
|
||
|
LocalFree (lpExcludeList);
|
||
|
lpExcludeList = NULL;
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
lpExcludeList = lpTempList;
|
||
|
|
||
|
lpInsert = lpExcludeList + dwSize - dwStrLen - 1;
|
||
|
lstrcpy (lpInsert, szTemp);
|
||
|
|
||
|
} else {
|
||
|
|
||
|
dwSize += lstrlen (szTemp);
|
||
|
lpExcludeList = LocalAlloc (LPTR, dwSize * sizeof(TCHAR));
|
||
|
|
||
|
if (!lpExcludeList) {
|
||
|
DebugMsg((DM_WARNING, TEXT("ConvertExclusionList: Failed to alloc memory with %d"), GetLastError()));
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
lstrcpy (lpExcludeList, szTemp);
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// If we are at the end of the exclusion list, we're done
|
||
|
//
|
||
|
|
||
|
if (!(*lpTemp)) {
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Prep for the next entry
|
||
|
//
|
||
|
|
||
|
lpTemp++;
|
||
|
lpDir = lpTemp;
|
||
|
}
|
||
|
|
||
|
Exit:
|
||
|
|
||
|
return lpExcludeList;
|
||
|
}
|
||
|
|
||
|
//*************************************************************
|
||
|
//
|
||
|
// EnumerateProfile()
|
||
|
//
|
||
|
// Purpose: Enumerates the profile for size and names
|
||
|
//
|
||
|
// Parameters: hLV - listview window handle (optional)
|
||
|
//
|
||
|
// Return: TRUE if successful
|
||
|
// FALSE if an error occurs
|
||
|
//
|
||
|
//*************************************************************
|
||
|
|
||
|
BOOL EnumerateProfile (HWND hLV)
|
||
|
{
|
||
|
TCHAR szProfile[2*MAX_PATH];
|
||
|
LPTSTR lpEnd;
|
||
|
BOOL bRetVal = FALSE;
|
||
|
LPTSTR lpExcludeList = NULL;
|
||
|
LVITEM item;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Get the profile directory
|
||
|
//
|
||
|
|
||
|
szProfile[0] = TEXT('\0');
|
||
|
GetEnvironmentVariable (TEXT("USERPROFILE"), szProfile, MAX_PATH);
|
||
|
|
||
|
if (szProfile[0] == TEXT('\0')) {
|
||
|
ExitThread (0);
|
||
|
}
|
||
|
|
||
|
lpEnd = CheckSlash (szProfile);
|
||
|
|
||
|
|
||
|
//
|
||
|
// Claim the critical section
|
||
|
//
|
||
|
|
||
|
EnterCriticalSection (&g_cs);
|
||
|
|
||
|
|
||
|
if (hLV) {
|
||
|
ListView_DeleteAllItems (hLV);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Get current profile size
|
||
|
//
|
||
|
|
||
|
g_dwProfileSizeTemp = 0;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Convert the exclusionlist read from the registry to a Null terminated list
|
||
|
// readable by recursedirectory.
|
||
|
//
|
||
|
|
||
|
if (g_szExcludeList[0] != TEXT('\0'))
|
||
|
lpExcludeList = ConvertExclusionList (szProfile, g_szExcludeList);
|
||
|
else
|
||
|
lpExcludeList = NULL;
|
||
|
|
||
|
|
||
|
if (!RecurseDirectory (szProfile, lpEnd, hLV, lpExcludeList)) {
|
||
|
SendMessage (hLV, WM_SETREDRAW, TRUE, 0);
|
||
|
goto Exit;
|
||
|
}
|
||
|
|
||
|
g_dwProfileSize = g_dwProfileSizeTemp;
|
||
|
|
||
|
//
|
||
|
// Sort by size
|
||
|
//
|
||
|
|
||
|
ListView_SortItems (hLV, ListViewSortCallback, 1);
|
||
|
|
||
|
|
||
|
//
|
||
|
// Select the next item
|
||
|
//
|
||
|
|
||
|
item.mask = LVIF_STATE;
|
||
|
item.iItem = 0;
|
||
|
item.iSubItem = 0;
|
||
|
item.state = LVIS_SELECTED | LVIS_FOCUSED;
|
||
|
item.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
|
||
|
|
||
|
SendMessage (hLV, LVM_SETITEMSTATE, 0, (LPARAM) &item);
|
||
|
|
||
|
|
||
|
//
|
||
|
// Convert to K
|
||
|
//
|
||
|
|
||
|
if (g_dwProfileSize < 1024) {
|
||
|
g_dwProfileSize = 1;
|
||
|
} else {
|
||
|
g_dwProfileSize /= 1024;
|
||
|
}
|
||
|
|
||
|
|
||
|
bRetVal = TRUE;
|
||
|
|
||
|
Exit:
|
||
|
//
|
||
|
// Release the critical section
|
||
|
//
|
||
|
|
||
|
LeaveCriticalSection (&g_cs);
|
||
|
|
||
|
return bRetVal;
|
||
|
}
|