Leaked source code of windows server 2003
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.

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