Source code of Windows XP (NT5)
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.

1804 lines
46 KiB

  1. //*************************************************************
  2. // File name: PROQUOTA.C
  3. //
  4. // Description: Profile quota management
  5. //
  6. // Microsoft Confidential
  7. // Copyright (c) Microsoft Corporation 1996
  8. // All rights reserved
  9. //
  10. //*************************************************************
  11. #include <windows.h>
  12. #include <wchar.h>
  13. #include <aclapi.h>
  14. #include <shellapi.h>
  15. #include <commctrl.h>
  16. #include "proquota.h"
  17. #include "debug.h"
  18. #define WINLOGON_KEY TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon")
  19. #define SYSTEM_POLICIES_KEY TEXT("Software\\Policies\\Microsoft\\Windows\\System")
  20. HINSTANCE hInst;
  21. HWND hwndMain;
  22. HWND g_hQuotaDlg = NULL;
  23. BOOL g_bHideSmallItems;
  24. BOOL g_bShowReg = FALSE;
  25. HANDLE hThread;
  26. HANDLE hExitEvent;
  27. HANDLE g_hQuotaDlgEvent;
  28. DWORD g_dwProfileSize = 0;
  29. DWORD g_dwProfileSizeTemp = 0;
  30. DWORD g_dwMaxProfileSize = 10240; //KB
  31. CRITICAL_SECTION g_cs;
  32. HICON hIconGood, hIconCaution, hIconStop;
  33. BOOL g_bQueryEndSession;
  34. TCHAR g_szExcludeList[2*MAX_PATH];
  35. TCHAR *g_lpQuotaMessage=NULL;
  36. TCHAR szClassName[] = TEXT("proquota");
  37. TCHAR szEventName[] = TEXT("proquota instance event");
  38. TCHAR szSizeFormat[40];
  39. BOOL g_bWarnUser = FALSE;
  40. DWORD g_dwWarnUserTimeout = 15; // minutes
  41. BOOL g_bWarningTimerRunning = FALSE;
  42. BOOL g_bWarningDisplayed = FALSE;
  43. //
  44. // Function prototypes
  45. //
  46. LRESULT CALLBACK ProQuotaWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
  47. LRESULT CALLBACK QuotaDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
  48. BOOL SetSecurity (void);
  49. BOOL ReadRegistry (void);
  50. BOOL ReadExclusionList();
  51. VOID QuotaThread(HWND hWnd);
  52. BOOL RecurseDirectory (LPTSTR lpDir, LPTSTR lpTop, HWND hLV, LPTSTR lpExcludeList);
  53. BOOL EnumerateProfile (HWND hLV);
  54. LPTSTR CheckSemicolon (LPTSTR lpDir);
  55. LPTSTR CheckSlash (LPTSTR lpDir);
  56. LPTSTR ConvertExclusionList (LPCTSTR lpSourceDir, LPCTSTR lpExclusionList);
  57. //*************************************************************
  58. //
  59. // WinMain()
  60. //
  61. // Purpose: Entry point
  62. //
  63. // Parameters: hInstance - Instance handle
  64. // hPrevInstance - Previous Instance
  65. // lpCmdLine - Command line
  66. // nCmdShow - ShowWindow flag
  67. //
  68. // Return: int
  69. //
  70. //*************************************************************
  71. int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  72. LPSTR lpCmdLine, INT nCmdShow)
  73. {
  74. MSG msg;
  75. WNDCLASS wc;
  76. HANDLE hEvent;
  77. //
  78. // Verbose output
  79. //
  80. #if DBG
  81. InitDebugSupport();
  82. DebugMsg((DM_VERBOSE, TEXT("WinMain: Entering...")));
  83. #endif
  84. hInst = hInstance;
  85. //
  86. // Check if this app is already running
  87. //
  88. hEvent = OpenEvent (EVENT_ALL_ACCESS, FALSE, szEventName);
  89. if (hEvent) {
  90. DebugMsg((DM_VERBOSE, TEXT("WinMain: Proquota already running. Exiting...")));
  91. CloseHandle (hEvent);
  92. return 0;
  93. }
  94. hEvent = CreateEvent (NULL, TRUE, TRUE, szEventName);
  95. g_hQuotaDlgEvent = CreateEvent (NULL, FALSE, TRUE, NULL);
  96. if (!g_hQuotaDlgEvent) {
  97. DebugMsg((DM_VERBOSE, TEXT("WinMain: Proquota Couldn't get prowquota dlg event, error %d..."), GetLastError()));
  98. CloseHandle (hEvent);
  99. return 0;
  100. }
  101. //
  102. // Get the quota settings
  103. //
  104. if (!ReadRegistry()) {
  105. DebugMsg((DM_VERBOSE, TEXT("WinMain: ReadRegistry returned FALSE. Exiting...")));
  106. CloseHandle (hEvent);
  107. return 0;
  108. }
  109. //
  110. // Munge the access mask on the process token so taskmgr
  111. // can't kill this app.
  112. //
  113. SetSecurity();
  114. //
  115. // Make sure proquota is the first one that is attempted to be shutdown
  116. //
  117. SetProcessShutdownParameters(0x3ff, 0);
  118. //
  119. // Initialize
  120. //
  121. InitializeCriticalSection (&g_cs);
  122. InitCommonControls();
  123. LoadString (hInst, IDS_SIZEFMT, szSizeFormat, 40);
  124. wc.style = CS_HREDRAW | CS_VREDRAW;
  125. wc.lpfnWndProc = (WNDPROC)ProQuotaWndProc;
  126. wc.cbClsExtra = 0;
  127. wc.cbWndExtra = 0;
  128. wc.hInstance = hInstance;
  129. wc.hIcon = NULL;
  130. wc.hCursor = NULL;
  131. wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
  132. wc.lpszMenuName = NULL;
  133. wc.lpszClassName = szClassName;
  134. if (!RegisterClass(&wc)) {
  135. DebugMsg((DM_WARNING, TEXT("WinMain: RegisterClass failed with %d"), GetLastError()));
  136. CloseHandle (hEvent);
  137. return 0;
  138. }
  139. //
  140. // Create a hidden top level window so we get
  141. // broadcasted messages.
  142. //
  143. hwndMain = CreateWindow(szClassName, NULL, WS_OVERLAPPED, 0, 0, 0, 0,
  144. NULL, NULL, hInstance, NULL);
  145. if (!hwndMain) {
  146. DebugMsg((DM_WARNING, TEXT("WinMain: CreateWindow failed with %d"), GetLastError()));
  147. CloseHandle (hEvent);
  148. return 0;
  149. }
  150. while (GetMessage (&msg, NULL, 0, 0)) {
  151. TranslateMessage(&msg);
  152. DispatchMessage(&msg);
  153. }
  154. DebugMsg((DM_VERBOSE, TEXT("WinMain: Leaving...")));
  155. CloseHandle (hEvent);
  156. if (g_lpQuotaMessage) {
  157. LocalFree(g_lpQuotaMessage);
  158. g_lpQuotaMessage = NULL;
  159. }
  160. return (int)(msg.wParam);
  161. }
  162. //*************************************************************
  163. //
  164. // ProQuotaWndProc()
  165. //
  166. // Purpose: Window procedure
  167. //
  168. // Parameters: hWnd - Window handle
  169. // message - Window message
  170. // wParam - WPARAM
  171. // lParam - LPARAM
  172. //
  173. //
  174. // Return: LRESULT
  175. //
  176. //*************************************************************
  177. LRESULT CALLBACK ProQuotaWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
  178. {
  179. DWORD dwThreadId;
  180. switch (message) {
  181. case WM_CREATE:
  182. hIconGood = LoadIcon (hInst, MAKEINTRESOURCE(IDI_ICON));
  183. hIconCaution = LoadIcon (hInst, MAKEINTRESOURCE(IDI_CAUTION));
  184. hIconStop = LoadIcon (hInst, MAKEINTRESOURCE(IDI_STOP));
  185. hExitEvent = CreateEvent (NULL, FALSE, FALSE, TEXT("PROQUOTA Exit Event"));
  186. if (!hExitEvent) {
  187. DebugMsg((DM_WARNING, TEXT("ProQuotaWndProc: Failed to create exit event with error %d"), GetLastError()));
  188. return -1;
  189. }
  190. hThread = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) QuotaThread,
  191. (LPVOID) hWnd, CREATE_SUSPENDED, &dwThreadId);
  192. if (!hThread) {
  193. DebugMsg((DM_WARNING, TEXT("ProQuotaWndProc: Failed to create thread with error %d"), GetLastError()));
  194. CloseHandle (hExitEvent);
  195. return -1;
  196. }
  197. SetThreadPriority (hThread, THREAD_PRIORITY_IDLE);
  198. ResumeThread (hThread);
  199. break;
  200. case WM_USER:
  201. if (lParam == WM_LBUTTONDBLCLK) {
  202. PostMessage (hWnd, WM_QUOTADLG, 0, 0);
  203. }
  204. #if DBG
  205. if (lParam == WM_RBUTTONUP) {
  206. DestroyWindow (hWnd);
  207. }
  208. #endif
  209. break;
  210. case WM_QUERYENDSESSION:
  211. {
  212. BOOL bLogoff;
  213. //EnterCriticalSection (&g_cs);
  214. bLogoff = (g_dwProfileSize <= g_dwMaxProfileSize);
  215. //LeaveCriticalSection (&g_cs);
  216. //
  217. // If it is zero assume that it has not yet finished enumerating..
  218. //
  219. if (g_dwProfileSize == 0) {
  220. bLogoff = FALSE;
  221. DebugMsg((DM_VERBOSE, TEXT("ProQuotaWndProc: Recd QueryEnd Message before enumerating.")));
  222. }
  223. DebugMsg((DM_VERBOSE, TEXT("ProQuotaWndProc: Recd QueryEnd Message. Returning %s"), bLogoff?TEXT("TRUE"):TEXT("FALSE")));
  224. if (bLogoff) {
  225. return TRUE;
  226. }
  227. PostMessage (hWnd, WM_QUOTADLG, 1, 0);
  228. }
  229. return FALSE;
  230. case WM_QUOTADLG:
  231. if (!g_hQuotaDlg) {
  232. if (wParam) {
  233. g_bQueryEndSession = TRUE;
  234. } else {
  235. g_bQueryEndSession = FALSE;
  236. }
  237. DialogBox (hInst, MAKEINTRESOURCE(IDD_QUOTA), hwndMain, QuotaDlgProc);
  238. g_hQuotaDlg = NULL;
  239. }
  240. break;
  241. case WM_WARNUSER:
  242. if (!g_bWarningDisplayed) {
  243. TCHAR szTitle[100];
  244. g_bWarningDisplayed = TRUE;
  245. LoadString (hInst, IDS_MSGTITLE, szTitle, 100);
  246. MessageBox(hWnd, g_lpQuotaMessage, szTitle, MB_OK | MB_ICONSTOP | MB_SYSTEMMODAL);
  247. g_bWarningDisplayed = FALSE;
  248. }
  249. break;
  250. case WM_TIMER:
  251. if (g_dwWarnUserTimeout > 0) {
  252. PostMessage (hWnd, WM_WARNUSER, 0, 0);
  253. }
  254. break;
  255. case WM_EXITWINDOWS:
  256. ExitWindowsDialog(NULL);
  257. break;
  258. case WM_DESTROY:
  259. {
  260. NOTIFYICONDATA nid;
  261. nid.cbSize = sizeof(nid);
  262. nid.hWnd = hWnd;
  263. nid.uID = 1;
  264. Shell_NotifyIcon (NIM_DELETE, &nid);
  265. SetEvent (hExitEvent);
  266. WaitForSingleObject (hThread, INFINITE);
  267. CloseHandle (hExitEvent);
  268. CloseHandle (hThread);
  269. PostQuitMessage(0);
  270. }
  271. break;
  272. default:
  273. return (DefWindowProc(hWnd, message, wParam, lParam));
  274. }
  275. return FALSE;
  276. }
  277. //*************************************************************
  278. //
  279. // QuotaThread()
  280. //
  281. // Purpose: Initializes the tray icon
  282. //
  283. // Parameters: hWnd - main window handle
  284. //
  285. //
  286. // Return: TRUE if successful
  287. // FALSE if an error occurs
  288. //
  289. //*************************************************************
  290. VOID QuotaThread (HWND hWnd)
  291. {
  292. NOTIFYICONDATA nid;
  293. TCHAR szProfile[MAX_PATH];
  294. TCHAR szMessage[64];
  295. HANDLE hFileChange;
  296. HANDLE hRegChange;
  297. HANDLE hWaitHandles[4];
  298. BOOL bFirst = TRUE;
  299. HICON hOk, hWarning, hBad;
  300. DWORD dwDelta;
  301. HKEY hKeySystem;
  302. LONG lResult;
  303. DWORD dwResult;
  304. DebugMsg((DM_VERBOSE, TEXT("QuotaThread: Entering...")));
  305. //
  306. // Load the status icons
  307. //
  308. hOk = LoadImage (hInst, MAKEINTRESOURCE(IDI_ICON), IMAGE_ICON,
  309. 16, 16, LR_DEFAULTCOLOR);
  310. hWarning = LoadImage (hInst, MAKEINTRESOURCE(IDI_CAUTION), IMAGE_ICON,
  311. 16, 16, LR_DEFAULTCOLOR);
  312. hBad = LoadImage (hInst, MAKEINTRESOURCE(IDI_STOP), IMAGE_ICON,
  313. 16, 16, LR_DEFAULTCOLOR);
  314. //
  315. // Get the profile directory
  316. //
  317. szProfile[0] = TEXT('\0');
  318. GetEnvironmentVariable (TEXT("USERPROFILE"), szProfile, MAX_PATH);
  319. if (szProfile[0] == TEXT('\0')) {
  320. ExitThread (0);
  321. }
  322. DebugMsg((DM_VERBOSE, TEXT("QuotaThread: User's profile: <%s>"), szProfile));
  323. //
  324. // Setup change notify
  325. //
  326. hFileChange = FindFirstChangeNotification (szProfile, TRUE,
  327. FILE_NOTIFY_CHANGE_FILE_NAME |
  328. FILE_NOTIFY_CHANGE_DIR_NAME |
  329. FILE_NOTIFY_CHANGE_SIZE);
  330. if (hFileChange == INVALID_HANDLE_VALUE) {
  331. DebugMsg((DM_WARNING, TEXT("QuotaThread: Failed to setup file change notification. %d"),
  332. GetLastError()));
  333. ExitThread (0);
  334. }
  335. lResult = RegOpenKeyEx (HKEY_CURRENT_USER,
  336. TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System"),
  337. 0, KEY_READ, &hKeySystem);
  338. if (lResult != ERROR_SUCCESS) {
  339. DebugMsg((DM_WARNING, TEXT("QuotaThread: Failed to open registry key. %d"), lResult));
  340. ExitThread (0);
  341. }
  342. hRegChange = CreateEvent (NULL, FALSE, FALSE, TEXT("PROQUOTA reg change event"));
  343. if (!hRegChange) {
  344. DebugMsg((DM_WARNING, TEXT("QuotaThread: Failed to setup reg event for change notification. %d"),
  345. GetLastError()));
  346. RegCloseKey (hKeySystem);
  347. FindCloseChangeNotification (hFileChange);
  348. ExitThread (0);
  349. }
  350. lResult = RegNotifyChangeKeyValue(hKeySystem, FALSE, REG_NOTIFY_CHANGE_LAST_SET,
  351. hRegChange, TRUE);
  352. if (lResult != ERROR_SUCCESS) {
  353. DebugMsg((DM_WARNING, TEXT("QuotaThread: Failed to setup RegNotifyChangeKeyValue. %d"),
  354. lResult));
  355. CloseHandle (hRegChange);
  356. RegCloseKey (hKeySystem);
  357. FindCloseChangeNotification (hFileChange);
  358. ExitThread (0);
  359. }
  360. hWaitHandles[0] = hExitEvent;
  361. hWaitHandles[1] = hFileChange;
  362. hWaitHandles[2] = hRegChange;
  363. hWaitHandles[3] = g_hQuotaDlgEvent;
  364. while (TRUE) {
  365. //
  366. // Calculate the profile size
  367. //
  368. if (g_hQuotaDlg) {
  369. DebugMsg((DM_VERBOSE, TEXT("QuotaTHread: Enumerating profile and refreshing dialog")));
  370. if (!EnumerateProfile (GetDlgItem (g_hQuotaDlg, IDC_QUOTA_FILELIST))) {
  371. DebugMsg((DM_WARNING, TEXT("QuotaThread: EnumerateProfile failed with Dlg Item.")));
  372. break;
  373. }
  374. }
  375. else {
  376. if (!EnumerateProfile (NULL)) {
  377. DebugMsg((DM_WARNING, TEXT("QuotaThread: EnumerateProfile failed.")));
  378. break;
  379. }
  380. }
  381. //
  382. // Update the status icon
  383. //
  384. nid.cbSize = sizeof(nid);
  385. nid.hWnd = hWnd;
  386. nid.uID = 1;
  387. nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
  388. nid.uCallbackMessage = WM_USER;
  389. szMessage[0] = TEXT('\0');
  390. if (g_dwProfileSize > g_dwMaxProfileSize) {
  391. DebugMsg((DM_VERBOSE, TEXT("QuotaThread: User has exceeded their profile quota.")));
  392. nid.hIcon = hBad;
  393. LoadString (hInst, IDS_SIZEBAD, szMessage, 64);
  394. dwDelta = g_dwProfileSize - g_dwMaxProfileSize;
  395. if (g_bWarnUser && !g_bWarningTimerRunning) {
  396. g_bWarningTimerRunning = TRUE;
  397. SetTimer (hwndMain, 1, g_dwWarnUserTimeout * 60000, NULL);
  398. PostMessage (hwndMain, WM_WARNUSER, 0, 0);
  399. }
  400. } else if ( (g_dwMaxProfileSize - g_dwProfileSize) < (g_dwProfileSize * .10)) {
  401. DebugMsg((DM_VERBOSE, TEXT("QuotaThread: User is within 10% of their profile quota.")));
  402. nid.hIcon = hWarning;
  403. LoadString (hInst, IDS_SIZEWARN, szMessage, 64);
  404. dwDelta = g_dwMaxProfileSize - g_dwProfileSize;
  405. if (g_bWarnUser && g_bWarningTimerRunning) {
  406. KillTimer (hwndMain, 1);
  407. g_bWarningTimerRunning = FALSE;
  408. }
  409. } else {
  410. DebugMsg((DM_VERBOSE, TEXT("QuotaThread: User has space available in their profile quota.")));
  411. nid.hIcon = hOk;
  412. LoadString (hInst, IDS_SIZEOK, szMessage, 64);
  413. dwDelta = g_dwMaxProfileSize - g_dwProfileSize;
  414. if (g_bWarnUser && g_bWarningTimerRunning) {
  415. KillTimer (hwndMain, 1);
  416. g_bWarningTimerRunning = FALSE;
  417. }
  418. }
  419. _snwprintf (nid.szTip, ARRAYSIZE(nid.szTip), szMessage, dwDelta);
  420. if (bFirst) {
  421. if (Shell_NotifyIcon (NIM_ADD, &nid)) {
  422. bFirst = FALSE;
  423. }
  424. } else {
  425. Shell_NotifyIcon (NIM_MODIFY, &nid);
  426. }
  427. //
  428. // Notify the dialog if it's present
  429. //
  430. if (g_hQuotaDlg) {
  431. PostMessage (g_hQuotaDlg, WM_REFRESH, 0, 0);
  432. }
  433. //
  434. // Clean up and wait for the next change
  435. //
  436. FindNextChangeNotification (hFileChange);
  437. dwResult = WaitForMultipleObjects (4, hWaitHandles, FALSE, INFINITE);
  438. if (dwResult == WAIT_FAILED) {
  439. break;
  440. }
  441. switch (dwResult - WAIT_OBJECT_0) {
  442. case 0:
  443. goto Exit;
  444. break;
  445. case 2:
  446. EnterCriticalSection (&g_cs);
  447. if (!ReadRegistry()) {
  448. PostMessage (hwndMain, WM_DESTROY, 0, 0);
  449. goto Exit;
  450. }
  451. LeaveCriticalSection (&g_cs);
  452. RegNotifyChangeKeyValue(hKeySystem, FALSE,
  453. REG_NOTIFY_CHANGE_LAST_SET,
  454. hRegChange, TRUE);
  455. // fall through
  456. case 1:
  457. Sleep (2000);
  458. DebugMsg((DM_VERBOSE, TEXT("QuotaThread: Running background enumeration.")));
  459. break;
  460. case 3:
  461. break;
  462. }
  463. }
  464. Exit:
  465. RegCloseKey (hKeySystem);
  466. CloseHandle (hRegChange);
  467. FindCloseChangeNotification (hFileChange);
  468. DebugMsg((DM_VERBOSE, TEXT("QuotaThread: Leaving...")));
  469. ExitThread (0);
  470. }
  471. //*************************************************************
  472. //
  473. // SetSecurity()
  474. //
  475. // Purpose: Removes TERMINATE_PROCESS access to this process
  476. // so taskman can't blow us away.
  477. //
  478. // Parameters:
  479. //
  480. // Return: TRUE if successful
  481. // FALSE if an error occurs
  482. //
  483. //*************************************************************
  484. BOOL SetSecurity (void)
  485. {
  486. HANDLE hProcess;
  487. PACL pDACL;
  488. PSECURITY_DESCRIPTOR pSD;
  489. WORD wIndex;
  490. ACE_HEADER * lpAceHeader;
  491. ACCESS_ALLOWED_ACE * lpAce;
  492. DWORD dwResult;
  493. hProcess = GetCurrentProcess();
  494. if (GetSecurityInfo (hProcess, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION,
  495. NULL, NULL, &pDACL, NULL, &pSD) != ERROR_SUCCESS) {
  496. return FALSE;
  497. }
  498. for (wIndex = 0; wIndex < pDACL->AceCount; wIndex++) {
  499. if (GetAce(pDACL, wIndex, &lpAceHeader)) {
  500. if (lpAceHeader->AceType == ACCESS_ALLOWED_ACE_TYPE) {
  501. lpAce = (ACCESS_ALLOWED_ACE *) lpAceHeader;
  502. lpAce->Mask &= ~(PROCESS_TERMINATE | WRITE_DAC | WRITE_OWNER);
  503. }
  504. }
  505. }
  506. dwResult = SetSecurityInfo (hProcess, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION,
  507. NULL, NULL, pDACL, NULL);
  508. LocalFree (pSD);
  509. if (dwResult != ERROR_SUCCESS) {
  510. return FALSE;
  511. }
  512. return TRUE;
  513. }
  514. //*************************************************************
  515. //
  516. // ReadExclusionList()
  517. //
  518. // Purpose: Checks if the profile quota policy is set,
  519. // and if so gets the max profile size.
  520. //
  521. // Parameters: void
  522. //
  523. // Return: TRUE if profile quota is enabled
  524. // FALSE if not
  525. //
  526. //*************************************************************
  527. BOOL ReadExclusionList()
  528. {
  529. TCHAR szExcludeList2[MAX_PATH];
  530. TCHAR szExcludeList1[MAX_PATH];
  531. HKEY hKey;
  532. DWORD dwSize, dwType;
  533. //
  534. // Check for a list of directories to exclude both user preferences
  535. // and user policy
  536. //
  537. szExcludeList1[0] = TEXT('\0');
  538. if (RegOpenKeyEx (HKEY_CURRENT_USER,
  539. TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"),
  540. 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
  541. dwSize = sizeof(szExcludeList1);
  542. RegQueryValueEx (hKey,
  543. TEXT("ExcludeProfileDirs"),
  544. NULL,
  545. &dwType,
  546. (LPBYTE) szExcludeList1,
  547. &dwSize);
  548. RegCloseKey (hKey);
  549. }
  550. szExcludeList2[0] = TEXT('\0');
  551. if (RegOpenKeyEx (HKEY_CURRENT_USER,
  552. SYSTEM_POLICIES_KEY,
  553. 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
  554. dwSize = sizeof(szExcludeList2);
  555. RegQueryValueEx (hKey,
  556. TEXT("ExcludeProfileDirs"),
  557. NULL,
  558. &dwType,
  559. (LPBYTE) szExcludeList2,
  560. &dwSize);
  561. RegCloseKey (hKey);
  562. }
  563. //
  564. // Merge the user preferences and policy together
  565. //
  566. g_szExcludeList[0] = TEXT('\0');
  567. if (szExcludeList1[0] != TEXT('\0')) {
  568. CheckSemicolon(szExcludeList1);
  569. lstrcpy (g_szExcludeList, szExcludeList1);
  570. }
  571. if (szExcludeList2[0] != TEXT('\0')) {
  572. lstrcat (g_szExcludeList, szExcludeList2);
  573. }
  574. return TRUE;
  575. }
  576. //*************************************************************
  577. //
  578. // ReadQuotaMsg()
  579. //
  580. // Purpose: Reads the msg that needs to be displayed.
  581. //
  582. // Parameters: hKey - Handle to the open policy
  583. //
  584. // Return: TRUE if mesg could be read
  585. // FALSE otherwise
  586. //
  587. //*************************************************************
  588. BOOL ReadQuotaMsg(HKEY hKey)
  589. {
  590. DWORD dwType, dwSize, dwValue, dwErr;
  591. if (g_lpQuotaMessage) {
  592. LocalFree(g_lpQuotaMessage);
  593. g_lpQuotaMessage = NULL;
  594. }
  595. dwSize = sizeof(TCHAR)*500;
  596. g_lpQuotaMessage = LocalAlloc (LPTR, dwSize);
  597. if (!g_lpQuotaMessage) {
  598. DebugMsg((DM_WARNING, TEXT("ReadRegistry: Failed to allocate memory for msg with %d."), GetLastError()));
  599. return FALSE;
  600. }
  601. dwErr = RegQueryValueEx (hKey, TEXT("ProfileQuotaMessage"), NULL,
  602. &dwType, (LPBYTE) g_lpQuotaMessage, &dwSize);
  603. if (dwErr == ERROR_MORE_DATA) {
  604. LPTSTR lpTemp1;
  605. //
  606. // Go in again with a larger buffer
  607. //
  608. lpTemp1 = LocalReAlloc(g_lpQuotaMessage, dwSize,
  609. LMEM_MOVEABLE | LMEM_ZEROINIT);
  610. if (!lpTemp1) {
  611. DebugMsg((DM_WARNING, TEXT("ReadRegistry: Failed to reallocate memory for msg with %d."), GetLastError()));
  612. LocalFree(g_lpQuotaMessage);
  613. g_lpQuotaMessage = NULL;
  614. return FALSE;
  615. }
  616. g_lpQuotaMessage = lpTemp1;
  617. dwErr = RegQueryValueEx (hKey, TEXT("ProfileQuotaMessage"), NULL,
  618. &dwType, (LPBYTE) g_lpQuotaMessage, &dwSize);
  619. }
  620. //
  621. // Load the default message otherwise
  622. //
  623. if (dwErr != ERROR_SUCCESS) {
  624. dwSize = sizeof(TCHAR)*500;
  625. LoadString (hInst, IDS_DEFAULTMSG, g_lpQuotaMessage, 500);
  626. }
  627. //
  628. // if there is any message expand the environment variables in it.
  629. //
  630. //
  631. if (*g_lpQuotaMessage) {
  632. LPTSTR lpTemp1, lpTemp2;
  633. dwSize = sizeof(TCHAR)*500;
  634. lpTemp1 = LocalAlloc (LPTR, dwSize);
  635. if (lpTemp1) {
  636. dwSize = ExpandEnvironmentStrings (g_lpQuotaMessage, lpTemp1, 500);
  637. if (dwSize <= 500)
  638. lstrcpy (g_lpQuotaMessage, lpTemp1);
  639. else {
  640. lpTemp2 = LocalReAlloc(lpTemp1, dwSize*sizeof(TCHAR),
  641. LMEM_MOVEABLE | LMEM_ZEROINIT);
  642. if (lpTemp2) {
  643. lpTemp1 = lpTemp2;
  644. //
  645. // go in with a larger buffer
  646. //
  647. ExpandEnvironmentStrings (g_lpQuotaMessage, lpTemp1, dwSize);
  648. lpTemp2 = LocalReAlloc(g_lpQuotaMessage, dwSize*sizeof(TCHAR),
  649. LMEM_MOVEABLE | LMEM_ZEROINIT);
  650. if (lpTemp2) {
  651. g_lpQuotaMessage = lpTemp2;
  652. lstrcpy (g_lpQuotaMessage, lpTemp1);
  653. } else {
  654. DebugMsg((DM_WARNING, TEXT("ReadRegistry: Failed to resize msg buffer with %d.Not expanding env var"), GetLastError()));
  655. }
  656. }
  657. else {
  658. DebugMsg((DM_WARNING, TEXT("ReadRegistry: Failed to reallocate memory for tmp buffer with %d.Not expanding env var"), GetLastError()));
  659. }
  660. }
  661. LocalFree (lpTemp1);
  662. } else {
  663. DebugMsg((DM_WARNING, TEXT("ReadRegistry: Failed to allocate memory for tmp buffer with %d.Not expanding env var"), GetLastError()));
  664. }
  665. }
  666. return TRUE;
  667. }
  668. //*************************************************************
  669. //
  670. // ReadRegistry()
  671. //
  672. // Purpose: Checks if the profile quota policy is set,
  673. // and if so gets the max profile size.
  674. //
  675. // Parameters: void
  676. //
  677. // Return: TRUE if profile quota is enabled
  678. // FALSE if not
  679. //
  680. //*************************************************************
  681. BOOL ReadRegistry (void)
  682. {
  683. LONG lResult;
  684. HKEY hKey;
  685. DWORD dwType, dwSize, dwValue, dwErr;
  686. lResult = RegOpenKeyEx (HKEY_CURRENT_USER,
  687. TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System"),
  688. 0, KEY_READ, &hKey);
  689. if (lResult == ERROR_SUCCESS) {
  690. dwSize = sizeof(dwValue);
  691. lResult = RegQueryValueEx (hKey, TEXT("EnableProfileQuota"), NULL,
  692. &dwType, (LPBYTE) &dwValue, &dwSize);
  693. if (lResult == ERROR_SUCCESS) {
  694. if (dwValue) {
  695. DebugMsg((DM_VERBOSE, TEXT("ReadRegistry: Profile quotas are enabled.")));
  696. dwSize = sizeof(g_dwMaxProfileSize);
  697. RegQueryValueEx (hKey, TEXT("MaxProfileSize"), NULL,
  698. &dwType, (LPBYTE) &g_dwMaxProfileSize, &dwSize);
  699. DebugMsg((DM_VERBOSE, TEXT("ReadRegistry: Max Profile Size: %d"), g_dwMaxProfileSize));
  700. dwSize = sizeof(g_bShowReg);
  701. RegQueryValueEx (hKey, TEXT("IncludeRegInProQuota"), NULL,
  702. &dwType, (LPBYTE) &g_bShowReg, &dwSize);
  703. DebugMsg((DM_VERBOSE, TEXT("ReadRegistry: Show registry in file list: %s"),
  704. g_bShowReg ? TEXT("TRUE") : TEXT("FALSE")));
  705. dwSize = sizeof(g_bWarnUser);
  706. RegQueryValueEx (hKey, TEXT("WarnUser"), NULL,
  707. &dwType, (LPBYTE) &g_bWarnUser, &dwSize);
  708. DebugMsg((DM_VERBOSE, TEXT("ReadRegistry: Warn user when quota exceeded: %s"),
  709. g_bWarnUser ? TEXT("TRUE") : TEXT("FALSE")));
  710. if (g_bWarnUser) {
  711. dwSize = sizeof(g_dwWarnUserTimeout);
  712. if (RegQueryValueEx (hKey, TEXT("WarnUserTimeout"), NULL,
  713. &dwType, (LPBYTE) &g_dwWarnUserTimeout, &dwSize) == ERROR_SUCCESS) {
  714. if (g_dwWarnUserTimeout > 1440) {
  715. g_dwWarnUserTimeout = 1440;
  716. }
  717. DebugMsg((DM_VERBOSE, TEXT("ReadRegistry: User warning reminder timeout: %d"), g_dwWarnUserTimeout));
  718. }
  719. }
  720. //
  721. // Now read the message that needs to be displayed
  722. //
  723. if (!ReadQuotaMsg(hKey)) {
  724. RegCloseKey (hKey);
  725. return FALSE;
  726. }
  727. if (ReadExclusionList()) {
  728. RegCloseKey (hKey);
  729. return TRUE;
  730. }
  731. else {
  732. DebugMsg((DM_VERBOSE, TEXT("ReadRegistry: Failed to read the ExclusionList")));
  733. }
  734. } else {
  735. DebugMsg((DM_VERBOSE, TEXT("ReadRegistry: Profile quotas are DISABLED.")));
  736. }
  737. } else {
  738. DebugMsg((DM_VERBOSE, TEXT("ReadRegistry: Failed to query EnableProfileQuota with error %d."), lResult));
  739. }
  740. RegCloseKey (hKey);
  741. } else {
  742. DebugMsg((DM_VERBOSE, TEXT("ReadRegistry: Failed to open System policy key with error %d."), lResult));
  743. }
  744. return FALSE;
  745. }
  746. //*************************************************************
  747. //
  748. // CheckSlash()
  749. //
  750. // Purpose: Checks for an ending slash and adds one if
  751. // it is missing.
  752. //
  753. // Parameters: lpDir - directory
  754. //
  755. // Return: Pointer to the end of the string
  756. //
  757. // Comments:
  758. //
  759. // History: Date Author Comment
  760. // 6/19/95 ericflo Created
  761. //
  762. //*************************************************************
  763. LPTSTR CheckSlash (LPTSTR lpDir)
  764. {
  765. DWORD dwStrLen;
  766. LPTSTR lpEnd;
  767. lpEnd = lpDir + lstrlen(lpDir);
  768. if (*(lpEnd - 1) != TEXT('\\')) {
  769. *lpEnd = TEXT('\\');
  770. lpEnd++;
  771. *lpEnd = TEXT('\0');
  772. }
  773. return lpEnd;
  774. }
  775. //*************************************************************
  776. //
  777. // CheckSemicolon()
  778. //
  779. // Purpose: Checks for an ending slash and adds one if
  780. // it is missing.
  781. //
  782. // Parameters: lpDir - directory
  783. //
  784. // Return: Pointer to the end of the string
  785. //
  786. // Comments:
  787. //
  788. // History: Date Author Comment
  789. // 6/19/95 ericlfo Created
  790. //
  791. //*************************************************************
  792. LPTSTR CheckSemicolon (LPTSTR lpDir)
  793. {
  794. LPTSTR lpEnd;
  795. lpEnd = lpDir + lstrlen(lpDir);
  796. if (*(lpEnd - 1) != TEXT(';')) {
  797. *lpEnd = TEXT(';');
  798. lpEnd++;
  799. *lpEnd = TEXT('\0');
  800. }
  801. return lpEnd;
  802. }
  803. //*************************************************************
  804. //
  805. // RecurseDirectory()
  806. //
  807. // Purpose: Recurses through the subdirectories counting the size.
  808. //
  809. // Parameters: lpDir - Directory
  810. // lpTop - Top of the display name
  811. // hLV - Listview window handle (optional)
  812. // lpExcludeList - Null-termed list of dirs to be skipped (optional)
  813. //
  814. // Return: TRUE if successful
  815. // FALSE if an error occurs
  816. //
  817. // Comments:
  818. //
  819. // History: Date Author Comment
  820. // 1/30/96 ericflo Created
  821. // 12/22/98 ushaji Added exclusionlist support
  822. // Notes:
  823. // The buffer size expected is MAX_PATH+4 for some internal processing
  824. // We should fix this to be better post Win 2K.
  825. //*************************************************************
  826. BOOL RecurseDirectory (LPTSTR lpDir, LPTSTR lpTop, HWND hLV, LPTSTR lpExcludeList)
  827. {
  828. HANDLE hFile = INVALID_HANDLE_VALUE;
  829. WIN32_FIND_DATA fd;
  830. LPTSTR lpEnd, lpTemp;
  831. BOOL bResult = TRUE;
  832. BOOL bSkip;
  833. //
  834. // Setup the ending pointer
  835. //
  836. lpEnd = CheckSlash (lpDir);
  837. //
  838. // Append *.* to the source directory
  839. //
  840. lstrcpy(lpEnd, TEXT("*.*"));
  841. //
  842. // Search through the source directory
  843. //
  844. hFile = FindFirstFile(lpDir, &fd);
  845. if (hFile == INVALID_HANDLE_VALUE) {
  846. if ( (GetLastError() == ERROR_FILE_NOT_FOUND) ||
  847. (GetLastError() == ERROR_PATH_NOT_FOUND) ) {
  848. //
  849. // bResult is already initialized to TRUE, so
  850. // just fall through.
  851. //
  852. } else {
  853. DebugMsg((DM_WARNING, TEXT("RecurseDirectory: FindFirstFile for <%s> failed with %d."),
  854. lpDir, GetLastError()));
  855. bResult = FALSE;
  856. }
  857. goto RecurseDir_Exit;
  858. }
  859. do {
  860. //
  861. // Append the file / directory name to the working buffer
  862. //
  863. // skip the file if the path > MAX_PATH
  864. if ((1+lstrlen(fd.cFileName)+lstrlen(lpDir)+lstrlen(TEXT("\\*.*"))) >= 2*MAX_PATH) {
  865. continue;
  866. }
  867. lstrcpy (lpEnd, fd.cFileName);
  868. if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  869. //
  870. // Check for "." and ".."
  871. //
  872. if (!lstrcmpi(fd.cFileName, TEXT("."))) {
  873. continue;
  874. }
  875. if (!lstrcmpi(fd.cFileName, TEXT(".."))) {
  876. continue;
  877. }
  878. //
  879. // Check if this directory should be excluded
  880. //
  881. if (lpExcludeList) {
  882. bSkip = FALSE;
  883. lpTemp = lpExcludeList;
  884. while (*lpTemp) {
  885. if (lstrcmpi (lpTemp, lpDir) == 0) {
  886. bSkip = TRUE;
  887. break;
  888. }
  889. lpTemp += lstrlen (lpTemp) + 1;
  890. }
  891. if (bSkip) {
  892. DebugMsg((DM_VERBOSE, TEXT("RecurseDirectory: Skipping <%s> due to exclusion list."),
  893. lpDir));
  894. continue;
  895. }
  896. }
  897. //
  898. // Found a directory.
  899. //
  900. // 1) Change into that subdirectory on the source drive.
  901. // 2) Recurse down that tree.
  902. // 3) Back up one level.
  903. //
  904. //
  905. // Recurse the subdirectory
  906. //
  907. if (!RecurseDirectory(lpDir, lpTop, hLV, lpExcludeList)) {
  908. bResult = FALSE;
  909. goto RecurseDir_Exit;
  910. }
  911. } else {
  912. //
  913. // Found a file, add the filesize and put in the listview
  914. // if appropriate.
  915. //
  916. g_dwProfileSizeTemp += fd.nFileSizeLow;
  917. DebugMsg((DM_VERBOSE, TEXT("RecurseDirectory: Profile Size <%d> after <%s> "), g_dwProfileSizeTemp,
  918. fd.cFileName));
  919. if (hLV) {
  920. LV_ITEM lvi;
  921. BOOL bAddItem = TRUE;
  922. if ((lstrlen(fd.cFileName) >= 6) &&
  923. (CompareString (LOCALE_USER_DEFAULT, NORM_IGNORECASE,
  924. TEXT("ntuser"), 6,
  925. fd.cFileName, 6) == 2)) {
  926. bAddItem = (g_bShowReg ? TRUE : FALSE);
  927. }
  928. if (bAddItem && g_bHideSmallItems && (fd.nFileSizeLow <= 2048)) {
  929. bAddItem = FALSE;
  930. }
  931. if (bAddItem) {
  932. TCHAR szSize[40];
  933. DWORD dwFileSize;
  934. INT iItem;
  935. lvi.mask = LVIF_TEXT | LVIF_STATE | LVIF_PARAM;
  936. lvi.iItem = 0;
  937. lvi.iSubItem = 0;
  938. lvi.state = 0;
  939. lvi.stateMask = LVIS_FOCUSED | LVIS_SELECTED;
  940. lvi.pszText = lpTop;
  941. lvi.lParam = fd.nFileSizeLow;
  942. iItem = ListView_InsertItem (hLV, &lvi);
  943. if (fd.nFileSizeLow <= 1024) {
  944. dwFileSize = 1;
  945. } else {
  946. dwFileSize = fd.nFileSizeLow / 1024;
  947. }
  948. _snwprintf (szSize, ARRAYSIZE(szSize), szSizeFormat, dwFileSize);
  949. lvi.mask = LVIF_TEXT | LVIF_STATE;
  950. lvi.iItem = iItem;
  951. lvi.iSubItem = 1;
  952. lvi.state = 0;
  953. lvi.stateMask = LVIS_FOCUSED | LVIS_SELECTED;
  954. lvi.pszText = szSize;
  955. lvi.lParam = fd.nFileSizeLow;
  956. ListView_SetItem (hLV, &lvi);
  957. }
  958. }
  959. }
  960. //
  961. // Find the next entry
  962. //
  963. } while (FindNextFile(hFile, &fd));
  964. RecurseDir_Exit:
  965. //
  966. // Remove the file / directory name appended above
  967. //
  968. *lpEnd = TEXT('\0');
  969. //
  970. // Close the search handle
  971. //
  972. if (hFile != INVALID_HANDLE_VALUE) {
  973. FindClose(hFile);
  974. }
  975. return bResult;
  976. }
  977. //*************************************************************
  978. //
  979. // CenterWindow()
  980. //
  981. // Purpose: Centers a window on the screen
  982. //
  983. // Parameters: hwnd - window handle to center
  984. //
  985. // Return: void
  986. //
  987. // Comments:
  988. //
  989. // History: Date Author Comment
  990. // 2/21/96 ericflo Ported
  991. //
  992. //*************************************************************
  993. void CenterWindow (HWND hwnd)
  994. {
  995. RECT rect;
  996. LONG dx, dy;
  997. LONG dxParent, dyParent;
  998. LONG Style;
  999. //
  1000. // Get window rect
  1001. //
  1002. GetWindowRect(hwnd, &rect);
  1003. dx = rect.right - rect.left;
  1004. dy = rect.bottom - rect.top;
  1005. //
  1006. // Get parent rect
  1007. //
  1008. Style = GetWindowLong(hwnd, GWL_STYLE);
  1009. if ((Style & WS_CHILD) == 0) {
  1010. //
  1011. // Return the desktop windows size (size of main screen)
  1012. //
  1013. dxParent = GetSystemMetrics(SM_CXSCREEN);
  1014. dyParent = GetSystemMetrics(SM_CYSCREEN);
  1015. } else {
  1016. HWND hwndParent;
  1017. RECT rectParent;
  1018. hwndParent = GetParent(hwnd);
  1019. if (hwndParent == NULL) {
  1020. hwndParent = GetDesktopWindow();
  1021. }
  1022. GetWindowRect(hwndParent, &rectParent);
  1023. dxParent = rectParent.right - rectParent.left;
  1024. dyParent = rectParent.bottom - rectParent.top;
  1025. }
  1026. //
  1027. // Center the child in the parent
  1028. //
  1029. rect.left = (dxParent - dx) / 2;
  1030. rect.top = (dyParent - dy) / 3;
  1031. //
  1032. // Move the child into position
  1033. //
  1034. SetWindowPos(hwnd, HWND_TOP, rect.left, rect.top, 0, 0, SWP_NOSIZE);
  1035. }
  1036. //*************************************************************
  1037. //
  1038. // QuotaDlgProc()
  1039. //
  1040. // Purpose: Quota dialog box
  1041. //
  1042. // Parameters: hDlg - Window handle
  1043. // message - Window message
  1044. // wParam - WPARAM
  1045. // lParam - LPARAM
  1046. //
  1047. // Return: TRUE if successful
  1048. // FALSE if an error occurs
  1049. //
  1050. //*************************************************************
  1051. LRESULT CALLBACK QuotaDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  1052. {
  1053. TCHAR szBuffer[40];
  1054. TCHAR szSize[40];
  1055. HWND hLV;
  1056. LV_COLUMN col;
  1057. RECT rect;
  1058. INT cx;
  1059. HKEY hKey;
  1060. DWORD dwSize, dwType;
  1061. LPTSTR lpMessage;
  1062. switch (message) {
  1063. case WM_INITDIALOG:
  1064. hLV = GetDlgItem (hDlg, IDC_QUOTA_FILELIST);
  1065. //
  1066. // Add the columns to the listview
  1067. //
  1068. GetClientRect (hLV, &rect);
  1069. cx = (rect.right * 31) / 40;
  1070. LoadString (hInst, IDS_COLUMN1, szBuffer, 40);
  1071. col.mask = LVCF_FMT | LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH;
  1072. col.fmt = LVCFMT_LEFT;
  1073. col.cx = cx;
  1074. col.pszText = szBuffer;
  1075. col.iSubItem = 0;
  1076. ListView_InsertColumn (hLV, 0, &col);
  1077. LoadString (hInst, IDS_COLUMN2, szBuffer, 40);
  1078. col.cx = rect.right - cx - GetSystemMetrics(SM_CYHSCROLL);
  1079. col.fmt = LVCFMT_RIGHT;
  1080. col.iSubItem = 1;
  1081. ListView_InsertColumn (hLV, 1, &col);
  1082. //
  1083. // Hide small items by default
  1084. //
  1085. g_bHideSmallItems = TRUE;
  1086. CheckDlgButton (hDlg, IDC_QUOTA_HIDESMALL, BST_CHECKED);
  1087. CenterWindow (hDlg);
  1088. SetForegroundWindow (hDlg);
  1089. // EnumerateProfile (GetDlgItem (hDlg, IDC_QUOTA_FILELIST));
  1090. dwSize = 500 * sizeof(TCHAR);
  1091. lpMessage = LocalAlloc (LPTR, dwSize);
  1092. if (!lpMessage)
  1093. break;
  1094. LoadString (hInst ,IDS_QUOTAENUMMSG, lpMessage, 500);
  1095. SetDlgItemText (hDlg, IDC_QUOTA_TEXT, lpMessage);
  1096. if (g_dwProfileSize > g_dwMaxProfileSize) {
  1097. SendDlgItemMessage (hDlg, IDC_QUOTA_ICON, STM_SETICON, (WPARAM) hIconStop, 0);
  1098. } else if ( (g_dwMaxProfileSize - g_dwProfileSize) < (g_dwProfileSize * .10)) {
  1099. SendDlgItemMessage (hDlg, IDC_QUOTA_ICON, STM_SETICON, (WPARAM) hIconCaution, 0);
  1100. } else {
  1101. SendDlgItemMessage (hDlg, IDC_QUOTA_ICON, STM_SETICON, (WPARAM) hIconGood, 0);
  1102. }
  1103. //
  1104. // Setting the global value at the end QuotaThread is not trying
  1105. // to refresh the dialog etc. at the same time.
  1106. //
  1107. g_hQuotaDlg = hDlg;
  1108. SetEvent(g_hQuotaDlgEvent);
  1109. LocalFree (lpMessage);
  1110. break;
  1111. case WM_REFRESH:
  1112. //
  1113. // Popuplate the listview
  1114. //
  1115. //
  1116. // Set the size information
  1117. //
  1118. _snwprintf (szSize, ARRAYSIZE(szSize), szSizeFormat, g_dwProfileSize);
  1119. SetDlgItemText (hDlg, IDC_QUOTA_SIZE, szSize);
  1120. _snwprintf (szSize, ARRAYSIZE(szSize), szSizeFormat, g_dwMaxProfileSize);
  1121. SetDlgItemText (hDlg, IDC_QUOTA_MAXSIZE, szSize);
  1122. dwSize = 500 * sizeof(TCHAR);
  1123. lpMessage = LocalAlloc (LPTR, dwSize);
  1124. if (!lpMessage) {
  1125. break;
  1126. }
  1127. if (g_dwProfileSize > g_dwMaxProfileSize) {
  1128. //
  1129. // This messge is already read
  1130. //
  1131. SetDlgItemText (hDlg, IDC_QUOTA_TEXT, g_lpQuotaMessage);
  1132. SendDlgItemMessage (hDlg, IDC_QUOTA_ICON, STM_SETICON, (WPARAM) hIconStop, 0);
  1133. } else if ( (g_dwMaxProfileSize - g_dwProfileSize) < (g_dwProfileSize * .10)) {
  1134. LoadString (hInst, IDS_CAUTION, lpMessage, 500);
  1135. SetDlgItemText (hDlg, IDC_QUOTA_TEXT, lpMessage);
  1136. SendDlgItemMessage (hDlg, IDC_QUOTA_ICON, STM_SETICON, (WPARAM) hIconCaution, 0);
  1137. } else {
  1138. LoadString (hInst, IDS_LOGOFFOK, lpMessage, 500);
  1139. SetDlgItemText (hDlg, IDC_QUOTA_TEXT, lpMessage);
  1140. SendDlgItemMessage (hDlg, IDC_QUOTA_ICON, STM_SETICON, (WPARAM) hIconGood, 0);
  1141. }
  1142. LocalFree (lpMessage);
  1143. break;
  1144. case WM_COMMAND:
  1145. if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {
  1146. g_hQuotaDlg = NULL;
  1147. if ((g_dwProfileSize < g_dwMaxProfileSize) && (g_bQueryEndSession) && (g_dwProfileSize != 0)) {
  1148. PostMessage (hwndMain, WM_EXITWINDOWS, 0, 0);
  1149. }
  1150. EndDialog(hDlg, TRUE);
  1151. return TRUE;
  1152. }
  1153. if (LOWORD(wParam) == IDC_QUOTA_HIDESMALL) {
  1154. g_bHideSmallItems = IsDlgButtonChecked (hDlg, IDC_QUOTA_HIDESMALL);
  1155. EnumerateProfile (GetDlgItem(hDlg, IDC_QUOTA_FILELIST));
  1156. }
  1157. break;
  1158. }
  1159. return FALSE;
  1160. }
  1161. //*************************************************************
  1162. //
  1163. // ListViewSortCallback()
  1164. //
  1165. // Purpose: List view callback function for sorting
  1166. //
  1167. // Parameters: lParam1 - lParam1
  1168. // lParam2 - lParam2
  1169. // lParamSort - Column id
  1170. //
  1171. // Return: -1, 0, 1
  1172. //
  1173. //*************************************************************
  1174. INT CALLBACK ListViewSortCallback (LPARAM lParam1, LPARAM lParam2,
  1175. LPARAM lParamSort)
  1176. {
  1177. if (lParam1 < lParam2) {
  1178. return 1;
  1179. } else if (lParam1 == lParam2) {
  1180. return 0;
  1181. } else {
  1182. return -1;
  1183. }
  1184. }
  1185. //*************************************************************
  1186. //
  1187. // ConvertExclusionList()
  1188. //
  1189. // Purpose: Converts the semi-colon profile relative exclusion
  1190. // list to fully qualified null terminated exclusion
  1191. // list
  1192. //
  1193. // Parameters: lpSourceDir - Profile root directory
  1194. // lpExclusionList - List of directories to exclude
  1195. //
  1196. // Return: List if successful
  1197. // NULL if an error occurs
  1198. //
  1199. //*************************************************************
  1200. LPTSTR ConvertExclusionList (LPCTSTR lpSourceDir, LPCTSTR lpExclusionList)
  1201. {
  1202. LPTSTR lpExcludeList = NULL, lpInsert, lpEnd, lpTempList;
  1203. LPCTSTR lpTemp, lpDir;
  1204. TCHAR szTemp[MAX_PATH];
  1205. DWORD dwSize = 2; // double null terminator
  1206. DWORD dwStrLen;
  1207. //
  1208. // Setup a temp buffer to work with
  1209. //
  1210. lstrcpy (szTemp, lpSourceDir);
  1211. lpEnd = CheckSlash (szTemp);
  1212. //
  1213. // Loop through the list
  1214. //
  1215. lpTemp = lpDir = lpExclusionList;
  1216. while (*lpTemp) {
  1217. //
  1218. // Look for the semicolon separator
  1219. //
  1220. while (*lpTemp && ((*lpTemp) != TEXT(';'))) {
  1221. lpTemp++;
  1222. }
  1223. //
  1224. // Remove any leading spaces
  1225. //
  1226. while (*lpDir == TEXT(' ')) {
  1227. lpDir++;
  1228. }
  1229. //
  1230. // Put the directory name on the temp buffer
  1231. //
  1232. lstrcpyn (lpEnd, lpDir, (int)(lpTemp - lpDir + 1));
  1233. //
  1234. // Add the string to the exclusion list
  1235. //
  1236. if (lpExcludeList) {
  1237. dwStrLen = lstrlen (szTemp) + 1;
  1238. dwSize += dwStrLen;
  1239. lpTempList = LocalReAlloc (lpExcludeList, dwSize * sizeof(TCHAR),
  1240. LMEM_MOVEABLE | LMEM_ZEROINIT);
  1241. if (!lpTempList) {
  1242. DebugMsg((DM_WARNING, TEXT("ConvertExclusionList: Failed to realloc memory with %d"), GetLastError()));
  1243. LocalFree (lpExcludeList);
  1244. lpExcludeList = NULL;
  1245. goto Exit;
  1246. }
  1247. lpExcludeList = lpTempList;
  1248. lpInsert = lpExcludeList + dwSize - dwStrLen - 1;
  1249. lstrcpy (lpInsert, szTemp);
  1250. } else {
  1251. dwSize += lstrlen (szTemp);
  1252. lpExcludeList = LocalAlloc (LPTR, dwSize * sizeof(TCHAR));
  1253. if (!lpExcludeList) {
  1254. DebugMsg((DM_WARNING, TEXT("ConvertExclusionList: Failed to alloc memory with %d"), GetLastError()));
  1255. goto Exit;
  1256. }
  1257. lstrcpy (lpExcludeList, szTemp);
  1258. }
  1259. //
  1260. // If we are at the end of the exclusion list, we're done
  1261. //
  1262. if (!(*lpTemp)) {
  1263. goto Exit;
  1264. }
  1265. //
  1266. // Prep for the next entry
  1267. //
  1268. lpTemp++;
  1269. lpDir = lpTemp;
  1270. }
  1271. Exit:
  1272. return lpExcludeList;
  1273. }
  1274. //*************************************************************
  1275. //
  1276. // EnumerateProfile()
  1277. //
  1278. // Purpose: Enumerates the profile for size and names
  1279. //
  1280. // Parameters: hLV - listview window handle (optional)
  1281. //
  1282. // Return: TRUE if successful
  1283. // FALSE if an error occurs
  1284. //
  1285. //*************************************************************
  1286. BOOL EnumerateProfile (HWND hLV)
  1287. {
  1288. TCHAR szProfile[2*MAX_PATH];
  1289. LPTSTR lpEnd;
  1290. BOOL bRetVal = FALSE;
  1291. LPTSTR lpExcludeList = NULL;
  1292. LVITEM item;
  1293. //
  1294. // Get the profile directory
  1295. //
  1296. szProfile[0] = TEXT('\0');
  1297. GetEnvironmentVariable (TEXT("USERPROFILE"), szProfile, MAX_PATH);
  1298. if (szProfile[0] == TEXT('\0')) {
  1299. ExitThread (0);
  1300. }
  1301. lpEnd = CheckSlash (szProfile);
  1302. //
  1303. // Claim the critical section
  1304. //
  1305. EnterCriticalSection (&g_cs);
  1306. if (hLV) {
  1307. ListView_DeleteAllItems (hLV);
  1308. }
  1309. //
  1310. // Get current profile size
  1311. //
  1312. g_dwProfileSizeTemp = 0;
  1313. //
  1314. // Convert the exclusionlist read from the registry to a Null terminated list
  1315. // readable by recursedirectory.
  1316. //
  1317. if (g_szExcludeList[0] != TEXT('\0'))
  1318. lpExcludeList = ConvertExclusionList (szProfile, g_szExcludeList);
  1319. else
  1320. lpExcludeList = NULL;
  1321. if (!RecurseDirectory (szProfile, lpEnd, hLV, lpExcludeList)) {
  1322. SendMessage (hLV, WM_SETREDRAW, TRUE, 0);
  1323. goto Exit;
  1324. }
  1325. g_dwProfileSize = g_dwProfileSizeTemp;
  1326. //
  1327. // Sort by size
  1328. //
  1329. ListView_SortItems (hLV, ListViewSortCallback, 1);
  1330. //
  1331. // Select the next item
  1332. //
  1333. item.mask = LVIF_STATE;
  1334. item.iItem = 0;
  1335. item.iSubItem = 0;
  1336. item.state = LVIS_SELECTED | LVIS_FOCUSED;
  1337. item.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
  1338. SendMessage (hLV, LVM_SETITEMSTATE, 0, (LPARAM) &item);
  1339. //
  1340. // Convert to K
  1341. //
  1342. if (g_dwProfileSize < 1024) {
  1343. g_dwProfileSize = 1;
  1344. } else {
  1345. g_dwProfileSize /= 1024;
  1346. }
  1347. bRetVal = TRUE;
  1348. Exit:
  1349. //
  1350. // Release the critical section
  1351. //
  1352. LeaveCriticalSection (&g_cs);
  1353. return bRetVal;
  1354. }