|
|
//*************************************************************
// 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 <objbase.h>
#include <strsafe.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")
#define MAX_MESSAGE_LENGTH 256
HINSTANCE hInst; HWND hwndMain; HWND g_hQuotaDlg = NULL; BOOL g_bHideSmallItems; BOOL g_bShowReg = FALSE; HANDLE g_hThread; HANDLE g_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 + 2]; // "User exclusion list;Policy exclusion list"
TCHAR* g_lpQuotaMessage = NULL; DWORD g_cbQuotaMessage = 0;
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, UINT cchBuffer, LPTSTR lpTop, HWND hLV, LPTSTR lpExcludeList); BOOL EnumerateProfile (HWND hLV); BOOL CheckSemicolon (LPTSTR lpDir, UINT cchBuffer); LPTSTR CheckSlash (LPTSTR lpDir, UINT cchBuffer, UINT* pcchRemaining); LPTSTR ConvertExclusionList (LPCTSTR lpSourceDir, LPCTSTR lpExclusionList); BOOL GetDisplayName(LPCTSTR lpDir, LPTSTR lpTop, LPTSTR lpDisplayName, DWORD cchDisplayName);
//*************************************************************
//
// 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 = NULL; int iRet = 0;
//
// 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..."))); goto Exit; }
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())); goto Exit; }
//
// Get the quota settings
//
if (!ReadRegistry()) { DebugMsg((DM_VERBOSE, TEXT("WinMain: ReadRegistry returned FALSE. Exiting..."))); goto Exit; }
//
// 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
//
__try { if(!InitializeCriticalSectionAndSpinCount(&g_cs, 0x80000000)) { DebugMsg((DM_WARNING, TEXT("WinMain: InitializeCriticalSectionAndSpinCount failed with %d"), GetLastError())); goto Exit; } } __except(EXCEPTION_EXECUTE_HANDLER) { DebugMsg((DM_WARNING, TEXT("WinMain: InitializeCriticalSection failed"))); goto Exit; }
InitCommonControls(); CoInitialize(NULL);
LoadString (hInst, IDS_SIZEFMT, szSizeFormat, ARRAYSIZE(szSizeFormat));
wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = 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())); goto Exit; }
//
// 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())); goto Exit; }
while (GetMessage (&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); }
iRet = (int)(msg.wParam);
Exit:
DebugMsg((DM_VERBOSE, TEXT("WinMain: Leaving...")));
if (hEvent) { CloseHandle (hEvent); }
if (g_hQuotaDlgEvent) { CloseHandle(g_hQuotaDlgEvent); }
if (g_lpQuotaMessage) { LocalFree(g_lpQuotaMessage); g_lpQuotaMessage = NULL; }
return iRet; }
//*************************************************************
//
// 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));
g_hExitEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
if (!g_hExitEvent) { DebugMsg((DM_WARNING, TEXT("ProQuotaWndProc: Failed to create exit event with error %d"), GetLastError())); return -1; }
g_hThread = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) QuotaThread, (LPVOID) hWnd, CREATE_SUSPENDED, &dwThreadId);
if (!g_hThread) { DebugMsg((DM_WARNING, TEXT("ProQuotaWndProc: Failed to create thread with error %d"), GetLastError())); CloseHandle (g_hExitEvent); return -1; }
SetThreadPriority (g_hThread, THREAD_PRIORITY_IDLE); ResumeThread (g_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, ARRAYSIZE(szTitle)); 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 (g_hExitEvent);
WaitForSingleObject (g_hThread, INFINITE);
CloseHandle (g_hExitEvent); CloseHandle (g_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[MAX_MESSAGE_LENGTH]; HANDLE hFileChange = INVALID_HANDLE_VALUE; HANDLE hRegChange = NULL; HANDLE hWaitHandles[4]; BOOL bFirst = TRUE; HICON hOk = NULL, hWarning = NULL, hBad = NULL; DWORD dwDelta; HKEY hKeySystem = NULL; LONG lResult; DWORD dwResult; HRESULT hr;
DebugMsg((DM_VERBOSE, TEXT("QuotaThread: Entering...")));
//
// Load the status icons
//
hOk = LoadImage (hInst, MAKEINTRESOURCE(IDI_ICON), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR); if (!hOk) { DebugMsg((DM_WARNING, TEXT("QuotaThread: Failed to load OK icon. Error %d"), GetLastError())); goto Exit; }
hWarning = LoadImage (hInst, MAKEINTRESOURCE(IDI_CAUTION), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR); if (!hWarning) { DebugMsg((DM_WARNING, TEXT("QuotaThread: Failed to load Warning icon. Error %d"), GetLastError())); goto Exit; }
hBad = LoadImage (hInst, MAKEINTRESOURCE(IDI_STOP), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR); if (!hBad) { DebugMsg((DM_WARNING, TEXT("QuotaThread: Failed to load stop icon. Error %d"), GetLastError())); goto Exit; }
//
// Get the profile directory
//
szProfile[0] = TEXT('\0'); GetEnvironmentVariable (TEXT("USERPROFILE"), szProfile, ARRAYSIZE(szProfile));
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())); goto Exit; }
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)); goto Exit; }
hRegChange = CreateEvent (NULL, FALSE, FALSE, NULL);
if (!hRegChange) { DebugMsg((DM_WARNING, TEXT("QuotaThread: Failed to setup reg event for change notification. %d"), GetLastError())); goto Exit; }
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)); goto Exit; }
hWaitHandles[0] = g_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, ARRAYSIZE(szMessage)); 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, ARRAYSIZE(szMessage)); 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, ARRAYSIZE(szMessage)); dwDelta = g_dwMaxProfileSize - g_dwProfileSize;
if (g_bWarnUser && g_bWarningTimerRunning) { KillTimer (hwndMain, 1); g_bWarningTimerRunning = FALSE; } }
hr = StringCchPrintf(nid.szTip, ARRAYSIZE(nid.szTip), szMessage, dwDelta); if (FAILED(hr)) { DebugMsg((DM_WARNING, TEXT("QuotaThread: Insufficient buffer for message. Error 0x%x"), hr)); continue; }
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:
if (hOk) { DestroyIcon(hOk); }
if (hWarning) { DestroyIcon(hWarning); }
if (hBad) { DestroyIcon(hBad); }
if (hKeySystem) { RegCloseKey (hKeySystem); }
if (hRegChange) { CloseHandle (hRegChange); } if (INVALID_HANDLE_VALUE != hFileChange) { 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+1]; TCHAR szExcludeList1[MAX_PATH+1]; HKEY hKey; DWORD dwSize, dwType; HRESULT hr;
//
// 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); if (RegQueryValueEx (hKey, TEXT("ExcludeProfileDirs"), NULL, &dwType, (LPBYTE) szExcludeList1, &dwSize) != ERROR_SUCCESS) {
// ignore user exclusion list
szExcludeList1[0] = TEXT('\0'); }
RegCloseKey (hKey); }
szExcludeList2[0] = TEXT('\0'); if (RegOpenKeyEx (HKEY_CURRENT_USER, SYSTEM_POLICIES_KEY, 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
dwSize = sizeof(szExcludeList2); if (RegQueryValueEx (hKey, TEXT("ExcludeProfileDirs"), NULL, &dwType, (LPBYTE) szExcludeList2, &dwSize) != ERROR_SUCCESS) {
// ignore policy exclusion list
szExcludeList2[0] = TEXT('\0'); }
RegCloseKey (hKey); }
//
// Merge the user preferences and policy together
//
g_szExcludeList[0] = TEXT('\0');
if (szExcludeList1[0] != TEXT('\0')) { hr = StringCchCopy(g_szExcludeList, ARRAYSIZE(g_szExcludeList), szExcludeList1); if (FAILED(hr)) { DebugMsg((DM_WARNING, TEXT("ReadExclusionList: Fail to copy user exclusion list. Error 0x%x"), hr)); return FALSE; } if (!CheckSemicolon(g_szExcludeList, ARRAYSIZE(g_szExcludeList))) { return FALSE; } }
if (szExcludeList2[0] != TEXT('\0')) { hr = StringCchCat(g_szExcludeList, ARRAYSIZE(g_szExcludeList), szExcludeList2); if (FAILED(hr)) { DebugMsg((DM_WARNING, TEXT("ReadExclusionList: Fail to copy policy exclusion list. Error 0x%x"), hr)); return FALSE; } }
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; BOOL bLoadDefault = FALSE;
if (!g_lpQuotaMessage) { g_cbQuotaMessage = MAX_PATH * sizeof(TCHAR); g_lpQuotaMessage = LocalAlloc (LPTR, g_cbQuotaMessage); if (!g_lpQuotaMessage) { g_cbQuotaMessage = 0; DebugMsg((DM_WARNING, TEXT("ReadQuotaMsg: Failed to allocate memory for msg with %d."), GetLastError())); return FALSE; } } //
// Query the size for quota message
//
dwErr = RegQueryValueEx (hKey, TEXT("ProfileQuotaMessage"), NULL, &dwType, NULL, &dwSize); if (dwErr != ERROR_SUCCESS) { //
// Load the default message otherwise
//
bLoadDefault = TRUE; goto Load_Default; }
// Ensure proper size
if (dwSize > g_cbQuotaMessage) { if (g_lpQuotaMessage) { LocalFree(g_lpQuotaMessage); }
g_cbQuotaMessage = dwSize; g_lpQuotaMessage = LocalAlloc(LPTR, g_cbQuotaMessage); if (!g_lpQuotaMessage) { g_cbQuotaMessage = 0; DebugMsg((DM_WARNING, TEXT("ReadQuotaMsg: Failed to allocate memory for msg with %d."), GetLastError())); return FALSE; } } dwSize = g_cbQuotaMessage; dwErr = RegQueryValueEx (hKey, TEXT("ProfileQuotaMessage"), NULL, &dwType, (LPBYTE) g_lpQuotaMessage, &dwSize); if (dwErr != ERROR_SUCCESS) { //
// Load the default message otherwise
//
bLoadDefault = TRUE; goto Load_Default; }
//
// if there is any message expand the environment variables in it.
//
if (*g_lpQuotaMessage) { DWORD cchSize; LPTSTR lpTemp;
//
// Get the size of expanded string buffer including NULL terminator
//
cchSize = ExpandEnvironmentStrings (g_lpQuotaMessage, NULL, 0); if (cchSize == 0) { //
// Load the default message otherwise
//
DebugMsg((DM_WARNING, TEXT("ReadQuotaMsg: Failed to expand env var"), GetLastError())); bLoadDefault = TRUE; goto Load_Default; }
lpTemp = LocalAlloc (LPTR, cchSize * sizeof(TCHAR)); if (lpTemp) { cchSize = ExpandEnvironmentStrings (g_lpQuotaMessage, lpTemp, cchSize); if (cchSize == 0) { //
// Load the default message otherwise
//
DebugMsg((DM_WARNING, TEXT("ReadQuotaMsg: Failed to expand env var"), GetLastError())); bLoadDefault = TRUE; goto Load_Default; }
if (cchSize * sizeof(TCHAR) > g_cbQuotaMessage) { LocalFree(g_lpQuotaMessage); g_lpQuotaMessage = lpTemp; g_cbQuotaMessage = cchSize * sizeof(TCHAR); } else { if (FAILED(StringCchCopy(g_lpQuotaMessage, g_cbQuotaMessage/sizeof(TCHAR), lpTemp))) { bLoadDefault = TRUE; }
LocalFree(lpTemp); } } else { DebugMsg((DM_WARNING, TEXT("ReadQuotaMsg: Failed to allocate memory for tmp buffer with %d.Not expanding env var"), GetLastError())); } }
Load_Default:
if (bLoadDefault) { //
// Load the default message in case of error
//
LoadString (hInst, IDS_DEFAULTMSG, g_lpQuotaMessage, g_cbQuotaMessage/sizeof(TCHAR)); } 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
// cchBuffer - Buffer size in char
// pcchRemaining - buffer remaining after adding '\',
// can be NULL if not required
//
// Return: Pointer to the end of the string
//
// Comments:
//
// History: Date Author Comment
// 6/19/95 ericflo Created
//
//*************************************************************
LPTSTR CheckSlash (LPTSTR lpDir, UINT cchBuffer, UINT* pcchRemaining) { UINT cchDir = lstrlen(lpDir); LPTSTR lpEnd;
lpEnd = lpDir + cchDir; if (pcchRemaining) { *pcchRemaining = cchBuffer - cchDir - 1; }
if (*(lpEnd - 1) != TEXT('\\')) { if (cchDir + 1 >= cchBuffer) { // No space to put \, should never happen
return NULL; } *lpEnd = TEXT('\\'); lpEnd++; *lpEnd = TEXT('\0'); if (pcchRemaining) *pcchRemaining -= 1; }
return lpEnd; }
//*************************************************************
//
// CheckSemicolon()
//
// Purpose: Checks for an ending slash and adds one if
// it is missing.
//
// Parameters: lpDir - directory
// cchSize - buffer size in character
//
// Return: TRUE - success
// FALSE - Insufficient buffer space
//
// Comments:
//
// History: Date Author Comment
// 6/19/95 ericlfo Created
//
//*************************************************************
BOOL CheckSemicolon (LPTSTR lpDir, UINT cchBuffer) { UINT cchDir = lstrlen(lpDir); LPTSTR lpEnd;
lpEnd = lpDir + cchDir;
if (*(lpEnd - 1) != TEXT(';')) { if (cchDir + 1 >= cchBuffer) { return FALSE; // No space to put ;, should never happen
} *lpEnd = TEXT(';'); lpEnd++; *lpEnd = TEXT('\0'); }
return TRUE; }
//*************************************************************
//
// RecurseDirectory()
//
// Purpose: Recurses through the subdirectories counting the size.
//
// Parameters: lpDir - Directory
// cchBuffer - Buffer size in char
// 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, UINT cchBuffer, LPTSTR lpTop, HWND hLV, LPTSTR lpExcludeList) { HANDLE hFile = INVALID_HANDLE_VALUE; WIN32_FIND_DATA fd; LPTSTR lpEnd, lpTemp; BOOL bResult = TRUE; BOOL bSkip; UINT cchRemaining; HRESULT hr;
//
// Setup the ending pointer
//
lpEnd = CheckSlash (lpDir, cchBuffer, &cchRemaining); if (!lpEnd) { return FALSE; }
//
// Append *.* to the source directory
//
hr = StringCchCopy(lpEnd, cchRemaining, TEXT("*.*")); if (FAILED(hr)) { bResult = FALSE; goto RecurseDir_Exit; }
//
// 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 ((UINT)(1+lstrlen(fd.cFileName)+lstrlen(lpDir)+lstrlen(TEXT("\\*.*"))) >= cchBuffer) { continue; }
hr = StringCchCopy(lpEnd, cchRemaining, fd.cFileName); if (FAILED(hr)) { bResult = FALSE; goto RecurseDir_Exit; }
if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
//
// Check for "." and ".."
//
if (!lstrcmpi(fd.cFileName, TEXT("."))) { continue; }
if (!lstrcmpi(fd.cFileName, TEXT(".."))) { continue; }
//
// Check for reparse point
//
if (fd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { DebugMsg((DM_WARNING, TEXT("RecurseDirectory: Found a reparse point <%s>, skip it!"), lpDir)); 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, cchBuffer, lpTop, hLV, lpExcludeList)) { // Ignore error and continue
DebugMsg((DM_VERBOSE, TEXT("RecurseDirectory: Skipping <%s> due to error."), lpDir)); }
} 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]; TCHAR szDisplayName[MAX_PATH*3]; DWORD dwFileSize; INT iItem;
if (fd.nFileSizeLow <= 1024) { dwFileSize = 1; } else { dwFileSize = fd.nFileSizeLow / 1024; }
hr = StringCchPrintf(szSize, ARRAYSIZE(szSize), szSizeFormat, dwFileSize); if (FAILED(hr)) { bResult = FALSE; goto RecurseDir_Exit; }
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 = GetDisplayName(lpDir, lpTop, szDisplayName, ARRAYSIZE(szDisplayName)) ? szDisplayName : lpTop; lvi.lParam = fd.nFileSizeLow;
iItem = ListView_InsertItem (hLV, &lvi);
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; HRESULT hr;
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, ARRAYSIZE(szBuffer));
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, ARRAYSIZE(szBuffer));
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
//
hr = StringCchPrintf(szSize, ARRAYSIZE(szSize), szSizeFormat, g_dwProfileSize); if (FAILED(hr)) break; SetDlgItemText (hDlg, IDC_QUOTA_SIZE, szSize);
hr = StringCchPrintf(szSize, ARRAYSIZE(szSize), szSizeFormat, g_dwMaxProfileSize); if (FAILED(hr)) break; 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); SetEvent(g_hQuotaDlgEvent); }
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; UINT cchRemaining; HRESULT hr;
//
// Setup a temp buffer to work with
//
hr = StringCchCopy(szTemp, ARRAYSIZE(szTemp), lpSourceDir); if (FAILED(hr)) { return NULL; }
lpEnd = CheckSlash (szTemp, ARRAYSIZE(szTemp), &cchRemaining); if (!lpEnd) { return NULL; }
//
// 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 && *lpDir == TEXT(' ')) { lpDir++; }
//
// Check whether the entry is empty
//
if (lpDir == lpTemp) { // 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; continue; } //
// Put the directory name on the temp buffer
//
*lpEnd = TEXT('\0'); hr = StringCchCatN(lpEnd, cchRemaining, lpDir, (int)(lpTemp - lpDir)); if (FAILED(hr)) { DebugMsg((DM_WARNING, TEXT("ConvertExclusionList: Failed to copy 0x%x"), hr)); LocalFree (lpExcludeList); lpExcludeList = NULL; goto Exit; }
//
// 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; hr = StringCchCopy(lpInsert, dwStrLen, szTemp); if (FAILED(hr)) { DebugMsg((DM_WARNING, TEXT("ConvertExclusionList: Failed to copy 0x%x"), hr)); LocalFree (lpExcludeList); lpExcludeList = NULL; goto Exit; }
} 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; }
hr = StringCchCopy(lpExcludeList, dwSize, szTemp); if (FAILED(hr)) { DebugMsg((DM_WARNING, TEXT("ConvertExclusionList: Failed to copy 0x%x"), hr)); LocalFree (lpExcludeList); lpExcludeList = NULL; goto Exit; } }
//
// 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, ARRAYSIZE(szProfile), NULL); if (!lpEnd) { ExitThread (0); }
//
// 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, ARRAYSIZE(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; }
//*************************************************************
//
// GetDisplayName()
//
// Purpose: Get display name from shell for specific directory
// to display on the dialog box list view
//
// Parameters: IN lpDir : full directory name which display name is required
// IN lpTop : relative directory name from %USERPROFILE%
// OUT lpDisplayName : buffer to retrieve the display name
// IN cchDisplayName : size of display name buffer
//
// Return: TRUE if success, else FALSE
//
// Remark: This function loops through each directory level of
// the lpDir and get the shell display name of it, append to the
// display name buffer.
//
//*************************************************************
BOOL GetDisplayName(LPCTSTR lpDir, LPTSTR lpTop, LPTSTR lpDisplayName, DWORD cchDisplayName) { SHFILEINFO Info; BOOL bFirstSlash = TRUE; HRESULT hr; hr = StringCchCopy(lpDisplayName, cchDisplayName, TEXT("")); if (FAILED(hr)) return FALSE;
for ( ; lpTop[0]; lpTop++) { if (lpTop[0] == TEXT('\\')) { lpTop[0] = TEXT('\0'); if (!SHGetFileInfo(lpDir, 0, &Info, sizeof(Info), SHGFI_DISPLAYNAME)) { DebugMsg((DM_WARNING, TEXT("SHGetFileInfo failed, err = %d"), GetLastError())); lpTop[0] = TEXT('\\'); return FALSE; } lpTop[0] = TEXT('\\'); if (bFirstSlash) { bFirstSlash = FALSE; } else { hr = StringCchCat(lpDisplayName, cchDisplayName, TEXT("\\")); if (FAILED(hr)) return FALSE; }
hr = StringCchCat(lpDisplayName, cchDisplayName, Info.szDisplayName); if (FAILED(hr)) return FALSE; } } if (!SHGetFileInfo(lpDir, 0, &Info, sizeof(Info), SHGFI_DISPLAYNAME)) { DebugMsg((DM_WARNING, TEXT("SHGetFileInfo failed, err = %d"), GetLastError())); return FALSE; }
hr = StringCchCat(lpDisplayName, cchDisplayName, TEXT("\\")); if (FAILED(hr)) return FALSE; hr = StringCchCat(lpDisplayName, cchDisplayName, Info.szDisplayName); if (FAILED(hr)) return FALSE;
return TRUE; }
|