[SYSDM]
[reactos.git] / reactos / dll / cpl / sysdm / virtmem.c
1 /*
2 * PROJECT: ReactOS system properties, control panel applet
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll/cpl/sysdm/virtual.c
5 * PURPOSE: Virtual memory control dialog
6 * COPYRIGHT: Copyright 2006 Ged Murphy <gedmurphy@gmail.com>
7 *
8 */
9
10 #include "precomp.h"
11
12 static BOOL OnSelChange(HWND hwndDlg, PVIRTMEM pVirtMem);
13 static LPCTSTR lpKey = _T("SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Memory Management");
14
15 static BOOL
16 ReadPageFileSettings(PVIRTMEM pVirtMem)
17 {
18 HKEY hkey = NULL;
19 DWORD dwType;
20 DWORD dwDataSize;
21 BOOL bRet = FALSE;
22
23 if (RegCreateKeyEx(HKEY_LOCAL_MACHINE,
24 lpKey,
25 0,
26 NULL,
27 REG_OPTION_NON_VOLATILE,
28 KEY_QUERY_VALUE,
29 NULL,
30 &hkey,
31 NULL) == ERROR_SUCCESS)
32 {
33 if (RegQueryValueEx(hkey,
34 _T("PagingFiles"),
35 NULL,
36 &dwType,
37 NULL,
38 &dwDataSize) == ERROR_SUCCESS)
39 {
40 pVirtMem->szPagingFiles = (LPTSTR)HeapAlloc(GetProcessHeap(),
41 0,
42 dwDataSize);
43 if (pVirtMem->szPagingFiles != NULL)
44 {
45 ZeroMemory(pVirtMem->szPagingFiles,
46 dwDataSize);
47 if (RegQueryValueEx(hkey,
48 _T("PagingFiles"),
49 NULL,
50 &dwType,
51 (PBYTE)pVirtMem->szPagingFiles,
52 &dwDataSize) == ERROR_SUCCESS)
53 {
54 bRet = TRUE;
55 }
56 }
57 }
58 }
59
60 if (!bRet)
61 ShowLastWin32Error(pVirtMem->hSelf);
62
63 if (hkey != NULL)
64 RegCloseKey(hkey);
65
66 return bRet;
67 }
68
69
70 static VOID
71 GetPageFileSizes(LPTSTR lpPageFiles,
72 LPINT lpInitialSize,
73 LPINT lpMaximumSize)
74 {
75 INT i = 0;
76
77 *lpInitialSize = -1;
78 *lpMaximumSize = -1;
79
80 while (*lpPageFiles != _T('\0'))
81 {
82 if (*lpPageFiles == _T(' '))
83 {
84 lpPageFiles++;
85
86 switch (i)
87 {
88 case 0:
89 *lpInitialSize = (INT)_ttoi(lpPageFiles);
90 i = 1;
91 break;
92
93 case 1:
94 *lpMaximumSize = (INT)_ttoi(lpPageFiles);
95 return;
96 }
97 }
98
99 lpPageFiles++;
100 }
101 }
102
103
104 static VOID
105 ParseMemSettings(PVIRTMEM pVirtMem)
106 {
107 TCHAR szDrives[1024]; // all drives
108 LPTSTR DrivePtr = szDrives;
109 TCHAR szDrive[3]; // single drive
110 TCHAR szVolume[MAX_PATH];
111 TCHAR *szDisplayString;
112 INT InitialSize = 0;
113 INT MaxSize = 0;
114 INT DriveLen;
115 INT PgCnt = 0;
116
117 DriveLen = GetLogicalDriveStrings(1023,
118 szDrives);
119
120 szDisplayString = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (MAX_PATH * 2 + 69) * sizeof(TCHAR));
121 if (szDisplayString == NULL)
122 return;
123
124 while (DriveLen != 0)
125 {
126 INT Len;
127
128 Len = lstrlen(DrivePtr) + 1;
129 DriveLen -= Len;
130
131 DrivePtr = _tcsupr(DrivePtr);
132
133 /* copy the 'X:' portion */
134 lstrcpyn(szDrive, DrivePtr, sizeof(szDrive) / sizeof(TCHAR));
135
136 if (GetDriveType(DrivePtr) == DRIVE_FIXED)
137 {
138 /* does drive match the one in the registry ? */
139 if (!_tcsncmp(pVirtMem->szPagingFiles, szDrive, 2))
140 {
141 /* FIXME: we only check the first available pagefile in the reg */
142 GetPageFileSizes(pVirtMem->szPagingFiles,
143 &InitialSize,
144 &MaxSize);
145
146 pVirtMem->Pagefile[PgCnt].InitialValue = InitialSize;
147 pVirtMem->Pagefile[PgCnt].MaxValue = MaxSize;
148 pVirtMem->Pagefile[PgCnt].bUsed = TRUE;
149 lstrcpy(pVirtMem->Pagefile[PgCnt].szDrive, szDrive);
150 }
151 else
152 {
153 pVirtMem->Pagefile[PgCnt].InitialValue = 0;
154 pVirtMem->Pagefile[PgCnt].MaxValue = 0;
155 pVirtMem->Pagefile[PgCnt].bUsed = FALSE;
156 lstrcpy(pVirtMem->Pagefile[PgCnt].szDrive, szDrive);
157 }
158
159 _tcscpy(szDisplayString, szDrive);
160 _tcscat(szDisplayString, _T("\t"));
161
162 /* set a volume label if there is one */
163 if (GetVolumeInformation(DrivePtr,
164 szVolume,
165 255,
166 NULL,
167 NULL,
168 NULL,
169 NULL,
170 0))
171 {
172 if (szVolume[0] != _T('\0'))
173 {
174 TCHAR szVol[MAX_PATH + 2];
175 _stprintf(szVol, _T("[%s]"), szVolume);
176 _tcscat(szDisplayString, szVol);
177 }
178 }
179
180 if ((InitialSize != 0) || (MaxSize != 0))
181 {
182 TCHAR szSize[64];
183
184 _stprintf(szSize, _T("%i - %i"), InitialSize, MaxSize);
185 _tcscat(szDisplayString, _T("\t"));
186 _tcscat(szDisplayString, szSize);
187 }
188
189 SendMessage(pVirtMem->hListBox, LB_ADDSTRING, (WPARAM)0, (LPARAM)szDisplayString);
190 PgCnt++;
191 }
192
193 DrivePtr += Len;
194 }
195
196 SendMessage(pVirtMem->hListBox, LB_SETCURSEL, (WPARAM)0, (LPARAM)0);
197 HeapFree(GetProcessHeap(), 0, szDisplayString);
198 pVirtMem->Count = PgCnt;
199 OnSelChange(pVirtMem->hSelf, pVirtMem);
200 }
201
202
203 static VOID
204 WritePageFileSettings(PVIRTMEM pVirtMem)
205 {
206 HKEY hk = NULL;
207 TCHAR szPagingFiles[2048];
208 TCHAR szText[256];
209 INT i;
210 INT nPos = 0;
211 BOOL bErr = TRUE;
212
213 for (i = 0; i < pVirtMem->Count; ++i)
214 {
215 if (pVirtMem->Pagefile[i].bUsed)
216 {
217 _stprintf(szText, _T("%s\\pagefile.sys %i %i"),
218 pVirtMem->Pagefile[i].szDrive,
219 pVirtMem->Pagefile[i].InitialValue,
220 pVirtMem->Pagefile[i].MaxValue);
221
222 /* Add it to our overall registry string */
223 lstrcpy(szPagingFiles + nPos, szText);
224
225 /* Record the position where the next string will start */
226 nPos += (INT)lstrlen(szText) + 1;
227
228 /* add another NULL for REG_MULTI_SZ */
229 szPagingFiles[nPos] = _T('\0');
230 nPos++;
231 }
232 }
233
234 if (RegCreateKeyEx(HKEY_LOCAL_MACHINE,
235 lpKey,
236 0,
237 NULL,
238 REG_OPTION_NON_VOLATILE,
239 KEY_WRITE,
240 NULL,
241 &hk,
242 NULL) == ERROR_SUCCESS)
243 {
244 if (RegSetValueEx(hk,
245 _T("PagingFiles"),
246 0,
247 REG_MULTI_SZ,
248 (LPBYTE) szPagingFiles,
249 (DWORD) nPos * sizeof(TCHAR)) == ERROR_SUCCESS)
250 {
251 bErr = FALSE;
252 }
253
254 RegCloseKey(hk);
255 }
256
257 if (bErr)
258 ShowLastWin32Error(pVirtMem->hSelf);
259 }
260
261
262 static VOID
263 SetListBoxColumns(HWND hwndListBox)
264 {
265 const INT tabs[2] = {30, 120};
266
267 SendMessage(hwndListBox, LB_SETTABSTOPS, (WPARAM)2, (LPARAM)&tabs[0]);
268 }
269
270
271 static VOID
272 OnNoPagingFile(PVIRTMEM pVirtMem)
273 {
274 /* Disable the page file custom size boxes */
275 EnableWindow(GetDlgItem(pVirtMem->hSelf, IDC_INITIALSIZE), FALSE);
276 EnableWindow(GetDlgItem(pVirtMem->hSelf, IDC_MAXSIZE), FALSE);
277 }
278
279
280 static VOID
281 OnSysManSize(PVIRTMEM pVirtMem)
282 {
283 /* Disable the page file custom size boxes */
284 EnableWindow(GetDlgItem(pVirtMem->hSelf, IDC_INITIALSIZE), FALSE);
285 EnableWindow(GetDlgItem(pVirtMem->hSelf, IDC_MAXSIZE), FALSE);
286 }
287
288
289 static VOID
290 OnCustom(PVIRTMEM pVirtMem)
291 {
292 /* Enable the page file custom size boxes */
293 EnableWindow(GetDlgItem(pVirtMem->hSelf, IDC_INITIALSIZE), TRUE);
294 EnableWindow(GetDlgItem(pVirtMem->hSelf, IDC_MAXSIZE), TRUE);
295 }
296
297
298 static VOID
299 OnSet(PVIRTMEM pVirtMem)
300 {
301 INT Index;
302 UINT InitValue;
303 UINT MaxValue;
304 BOOL bTranslated;
305 TCHAR szTitle[64];
306 TCHAR szMessage[256];
307
308 pVirtMem->bSave = TRUE;
309
310 Index = (INT)SendDlgItemMessage(pVirtMem->hSelf,
311 IDC_PAGEFILELIST,
312 LB_GETCURSEL,
313 0,
314 0);
315 if (Index < pVirtMem->Count)
316 {
317 /* check if custom settings are checked */
318 if (IsDlgButtonChecked(pVirtMem->hSelf,
319 IDC_CUSTOM) == BST_CHECKED)
320 {
321 InitValue = GetDlgItemInt(pVirtMem->hSelf,
322 IDC_INITIALSIZE,
323 &bTranslated,
324 FALSE);
325 if (!bTranslated)
326 {
327 if (LoadString(hApplet,
328 IDS_MESSAGEBOXTITLE,
329 szTitle,
330 sizeof(szTitle) / sizeof(szTitle[0])) == 0)
331 _tcscpy(szTitle, _T("System control panel applet"));
332
333 if (LoadString(hApplet,
334 IDS_WARNINITIALSIZE,
335 szMessage,
336 sizeof(szMessage) / sizeof(szMessage[0])) == 0)
337 _tcscpy(szMessage, _T("Enter a numeric value for the initial size of the paging file."));
338
339 MessageBox(NULL,
340 szMessage,
341 szTitle,
342 MB_ICONWARNING | MB_OK);
343 return;
344 }
345
346 MaxValue = GetDlgItemInt(pVirtMem->hSelf,
347 IDC_MAXSIZE,
348 &bTranslated,
349 FALSE);
350 if (!bTranslated)
351 {
352 if (LoadString(hApplet,
353 IDS_MESSAGEBOXTITLE,
354 szTitle,
355 sizeof(szTitle) / sizeof(szTitle[0])) == 0)
356 _tcscpy(szTitle, _T("System control panel applet"));
357
358 if (LoadString(hApplet,
359 IDS_WARNMAXIMUMSIZE,
360 szMessage,
361 sizeof(szMessage) / sizeof(szMessage[0])) == 0)
362 _tcscpy(szMessage, _T("Enter a numeric value for the maximum size of the paging file."));
363
364 MessageBox(NULL,
365 szMessage,
366 szTitle,
367 MB_ICONWARNING | MB_OK);
368 return;
369 }
370
371 /* FIXME: Add more file size checks! */
372
373 pVirtMem->Pagefile[Index].InitialValue = InitValue;
374 pVirtMem->Pagefile[Index].MaxValue = MaxValue;
375 pVirtMem->Pagefile[Index].bUsed = TRUE;
376 }
377 else
378 {
379 /* set sizes to 0 */
380 pVirtMem->Pagefile[Index].InitialValue = pVirtMem->Pagefile[Index].MaxValue = 0;
381
382 // check to see if this drive is used for a paging file
383 if (IsDlgButtonChecked(pVirtMem->hSelf,
384 IDC_NOPAGEFILE) == BST_UNCHECKED)
385 {
386 pVirtMem->Pagefile[Index].bUsed = TRUE;
387 }
388 else
389 {
390 pVirtMem->Pagefile[Index].bUsed = FALSE;
391 }
392 }
393 }
394 }
395
396
397 static BOOL
398 OnSelChange(HWND hwndDlg, PVIRTMEM pVirtMem)
399 {
400 TCHAR szBuffer[64];
401 MEMORYSTATUSEX MemoryStatus;
402 ULARGE_INTEGER FreeBytes;
403 DWORDLONG FreeMemory;
404 INT Index;
405 INT i;
406 INT FileSize;
407
408 Index = (INT)SendDlgItemMessage(hwndDlg,
409 IDC_PAGEFILELIST,
410 LB_GETCURSEL,
411 0,
412 0);
413 if (Index < pVirtMem->Count)
414 {
415 /* Set drive letter */
416 SetDlgItemText(hwndDlg, IDC_DRIVE,
417 pVirtMem->Pagefile[Index].szDrive);
418
419 /* Set available disk space */
420 if (GetDiskFreeSpaceEx(pVirtMem->Pagefile[Index].szDrive,
421 NULL, NULL, &FreeBytes))
422 {
423 _stprintf(szBuffer, _T("%I64u MB"), FreeBytes.QuadPart / (1024 * 1024));
424 SetDlgItemText(hwndDlg, IDC_SPACEAVAIL, szBuffer);
425 }
426
427 if (pVirtMem->Pagefile[Index].InitialValue != 0 &&
428 pVirtMem->Pagefile[Index].MaxValue != 0)
429 {
430 /* enable and fill the custom values */
431 EnableWindow(GetDlgItem(pVirtMem->hSelf, IDC_MAXSIZE), TRUE);
432 EnableWindow(GetDlgItem(pVirtMem->hSelf, IDC_INITIALSIZE), TRUE);
433
434 SetDlgItemInt(pVirtMem->hSelf,
435 IDC_INITIALSIZE,
436 pVirtMem->Pagefile[Index].InitialValue,
437 FALSE);
438
439 SetDlgItemInt(pVirtMem->hSelf,
440 IDC_MAXSIZE,
441 pVirtMem->Pagefile[Index].MaxValue,
442 FALSE);
443
444 CheckDlgButton(pVirtMem->hSelf,
445 IDC_CUSTOM,
446 BST_CHECKED);
447 }
448 else
449 {
450 /* It's not a custom value */
451 EnableWindow(GetDlgItem(pVirtMem->hSelf, IDC_MAXSIZE), FALSE);
452 EnableWindow(GetDlgItem(pVirtMem->hSelf, IDC_INITIALSIZE), FALSE);
453
454 /* is it system managed */
455 if (pVirtMem->Pagefile[Index].bUsed)
456 {
457 CheckDlgButton(pVirtMem->hSelf,
458 IDC_SYSMANSIZE,
459 BST_CHECKED);
460 }
461 else
462 {
463 CheckDlgButton(pVirtMem->hSelf,
464 IDC_NOPAGEFILE,
465 BST_CHECKED);
466 }
467 }
468
469 /* Set minimum pagefile size */
470 SetDlgItemText(hwndDlg, IDC_MINIMUM, _T("2 MB"));
471
472 /* Set recommended pagefile size */
473 MemoryStatus.dwLength = sizeof(MEMORYSTATUSEX);
474 if (GlobalMemoryStatusEx(&MemoryStatus))
475 {
476 FreeMemory = MemoryStatus.ullTotalPhys / (1024 * 1024);
477 _stprintf(szBuffer, _T("%I64u MB"), FreeMemory + (FreeMemory / 2));
478 SetDlgItemText(hwndDlg, IDC_RECOMMENDED, szBuffer);
479 }
480
481 /* Set current pagefile size */
482 FileSize = 0;
483 for (i = 0; i < 26; i++)
484 {
485 FileSize += pVirtMem->Pagefile[i].InitialValue;
486 }
487 _stprintf(szBuffer, _T("%u MB"), FileSize);
488 SetDlgItemText(hwndDlg, IDC_CURRENT, szBuffer);
489 }
490
491 return TRUE;
492 }
493
494
495 static VOID
496 OnOk(PVIRTMEM pVirtMem)
497 {
498 if (pVirtMem->bSave == TRUE)
499 {
500 WritePageFileSettings(pVirtMem);
501 }
502 }
503
504
505 static VOID
506 OnInitDialog(HWND hwnd, PVIRTMEM pVirtMem)
507 {
508 pVirtMem->hSelf = hwnd;
509 pVirtMem->hListBox = GetDlgItem(hwnd, IDC_PAGEFILELIST);
510 pVirtMem->bSave = FALSE;
511
512 SetListBoxColumns(pVirtMem->hListBox);
513
514 /* Load the pagefile systems from the reg */
515 if (ReadPageFileSettings(pVirtMem))
516 {
517 /* Parse our settings and set up dialog */
518 ParseMemSettings(pVirtMem);
519 }
520 }
521
522
523 INT_PTR CALLBACK
524 VirtMemDlgProc(HWND hwndDlg,
525 UINT uMsg,
526 WPARAM wParam,
527 LPARAM lParam)
528 {
529 PVIRTMEM pVirtMem;
530
531 UNREFERENCED_PARAMETER(lParam);
532
533 pVirtMem = (PVIRTMEM)GetWindowLongPtr(hwndDlg, DWLP_USER);
534
535 switch (uMsg)
536 {
537 case WM_INITDIALOG:
538 pVirtMem = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(VIRTMEM));
539 if (pVirtMem == NULL)
540 {
541 EndDialog(hwndDlg, 0);
542 return FALSE;
543 }
544
545 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pVirtMem);
546
547 OnInitDialog(hwndDlg, pVirtMem);
548 break;
549
550 case WM_DESTROY:
551 if (pVirtMem->szPagingFiles)
552 HeapFree(GetProcessHeap(), 0,
553 pVirtMem->szPagingFiles);
554 HeapFree(GetProcessHeap(), 0, pVirtMem);
555 break;
556
557 case WM_COMMAND:
558 switch (LOWORD(wParam))
559 {
560 case IDCANCEL:
561 EndDialog(hwndDlg, 0);
562 return TRUE;
563
564 case IDOK:
565 OnOk(pVirtMem);
566 EndDialog(hwndDlg, 0);
567 return TRUE;
568
569 case IDC_NOPAGEFILE:
570 OnNoPagingFile(pVirtMem);
571 return TRUE;
572
573 case IDC_SYSMANSIZE:
574 OnSysManSize(pVirtMem);
575 return TRUE;
576
577 case IDC_CUSTOM:
578 OnCustom(pVirtMem);
579 return TRUE;
580
581 case IDC_SET:
582 OnSet(pVirtMem);
583 return TRUE;
584
585 case IDC_PAGEFILELIST:
586 switch HIWORD(wParam)
587 {
588 case LBN_SELCHANGE:
589 OnSelChange(hwndDlg, pVirtMem);
590 return TRUE;
591 }
592 break;
593 }
594 break;
595 }
596
597 return FALSE;
598 }