[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 MaximumSize = 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 &MaximumSize);
145
146 pVirtMem->Pagefile[PgCnt].InitialSize = InitialSize;
147 pVirtMem->Pagefile[PgCnt].MaximumSize = MaximumSize;
148 pVirtMem->Pagefile[PgCnt].bUsed = TRUE;
149 lstrcpy(pVirtMem->Pagefile[PgCnt].szDrive, szDrive);
150 }
151 else
152 {
153 pVirtMem->Pagefile[PgCnt].InitialSize = 0;
154 pVirtMem->Pagefile[PgCnt].MaximumSize = 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) || (MaximumSize != 0))
181 {
182 TCHAR szSize[64];
183
184 _stprintf(szSize, _T("%i - %i"), InitialSize, MaximumSize);
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].InitialSize,
220 pVirtMem->Pagefile[i].MaximumSize);
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 InitialSize;
303 UINT MaximumSize;
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 InitialSize = 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 MaximumSize = 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 /* Check the valid range of the inial size */
372 if (InitialSize < 2 ||
373 InitialSize > pVirtMem->Pagefile[Index].FreeSize)
374 {
375 if (LoadString(hApplet,
376 IDS_MESSAGEBOXTITLE,
377 szTitle,
378 sizeof(szTitle) / sizeof(szTitle[0])) == 0)
379 _tcscpy(szTitle, _T("System control panel applet"));
380
381 LoadString(hApplet,
382 IDS_WARNINITIALRANGE,
383 szMessage,
384 sizeof(szMessage) / sizeof(szMessage[0]));
385
386 MessageBox(NULL,
387 szMessage,
388 szTitle,
389 MB_ICONWARNING | MB_OK);
390 return;
391 }
392
393 /* Check the valid range of the maximum size */
394 if (MaximumSize < InitialSize ||
395 MaximumSize > pVirtMem->Pagefile[Index].FreeSize)
396 {
397 if (LoadString(hApplet,
398 IDS_MESSAGEBOXTITLE,
399 szTitle,
400 sizeof(szTitle) / sizeof(szTitle[0])) == 0)
401 _tcscpy(szTitle, _T("System control panel applet"));
402
403 LoadString(hApplet,
404 IDS_WARNMAXIMUMRANGE,
405 szMessage,
406 sizeof(szMessage) / sizeof(szMessage[0]));
407
408 MessageBox(NULL,
409 szMessage,
410 szTitle,
411 MB_ICONWARNING | MB_OK);
412 return;
413 }
414
415 pVirtMem->Pagefile[Index].InitialSize = InitialSize;
416 pVirtMem->Pagefile[Index].MaximumSize = MaximumSize;
417 pVirtMem->Pagefile[Index].bUsed = TRUE;
418 }
419 else
420 {
421 /* set sizes to 0 */
422 pVirtMem->Pagefile[Index].InitialSize = 0;
423 pVirtMem->Pagefile[Index].MaximumSize = 0;
424
425 // check to see if this drive is used for a paging file
426 if (IsDlgButtonChecked(pVirtMem->hSelf,
427 IDC_NOPAGEFILE) == BST_UNCHECKED)
428 {
429 pVirtMem->Pagefile[Index].bUsed = TRUE;
430 }
431 else
432 {
433 pVirtMem->Pagefile[Index].bUsed = FALSE;
434 }
435 }
436 }
437 }
438
439
440 static BOOL
441 OnSelChange(HWND hwndDlg, PVIRTMEM pVirtMem)
442 {
443 TCHAR szBuffer[64];
444 MEMORYSTATUSEX MemoryStatus;
445 ULARGE_INTEGER FreeBytes;
446 DWORDLONG FreeMemory;
447 INT Index;
448 INT i;
449 INT FileSize;
450
451 Index = (INT)SendDlgItemMessage(hwndDlg,
452 IDC_PAGEFILELIST,
453 LB_GETCURSEL,
454 0,
455 0);
456 if (Index < pVirtMem->Count)
457 {
458 /* Set drive letter */
459 SetDlgItemText(hwndDlg, IDC_DRIVE,
460 pVirtMem->Pagefile[Index].szDrive);
461
462 /* Set available disk space */
463 if (GetDiskFreeSpaceEx(pVirtMem->Pagefile[Index].szDrive,
464 NULL, NULL, &FreeBytes))
465 {
466 pVirtMem->Pagefile[Index].FreeSize = FreeBytes.QuadPart >> 20;
467 _stprintf(szBuffer, _T("%I64u MB"), FreeBytes.QuadPart / (1024 * 1024));
468 SetDlgItemText(hwndDlg, IDC_SPACEAVAIL, szBuffer);
469 }
470
471 if (pVirtMem->Pagefile[Index].InitialSize != 0 &&
472 pVirtMem->Pagefile[Index].MaximumSize != 0)
473 {
474 /* enable and fill the custom values */
475 EnableWindow(GetDlgItem(pVirtMem->hSelf, IDC_MAXSIZE), TRUE);
476 EnableWindow(GetDlgItem(pVirtMem->hSelf, IDC_INITIALSIZE), TRUE);
477
478 SetDlgItemInt(pVirtMem->hSelf,
479 IDC_INITIALSIZE,
480 pVirtMem->Pagefile[Index].InitialSize,
481 FALSE);
482
483 SetDlgItemInt(pVirtMem->hSelf,
484 IDC_MAXSIZE,
485 pVirtMem->Pagefile[Index].MaximumSize,
486 FALSE);
487
488 CheckDlgButton(pVirtMem->hSelf,
489 IDC_CUSTOM,
490 BST_CHECKED);
491 }
492 else
493 {
494 /* It's not a custom value */
495 EnableWindow(GetDlgItem(pVirtMem->hSelf, IDC_MAXSIZE), FALSE);
496 EnableWindow(GetDlgItem(pVirtMem->hSelf, IDC_INITIALSIZE), FALSE);
497
498 /* is it system managed */
499 if (pVirtMem->Pagefile[Index].bUsed)
500 {
501 CheckDlgButton(pVirtMem->hSelf,
502 IDC_SYSMANSIZE,
503 BST_CHECKED);
504 }
505 else
506 {
507 CheckDlgButton(pVirtMem->hSelf,
508 IDC_NOPAGEFILE,
509 BST_CHECKED);
510 }
511 }
512
513 /* Set minimum pagefile size */
514 SetDlgItemText(hwndDlg, IDC_MINIMUM, _T("2 MB"));
515
516 /* Set recommended pagefile size */
517 MemoryStatus.dwLength = sizeof(MEMORYSTATUSEX);
518 if (GlobalMemoryStatusEx(&MemoryStatus))
519 {
520 FreeMemory = MemoryStatus.ullTotalPhys / (1024 * 1024);
521 _stprintf(szBuffer, _T("%I64u MB"), FreeMemory + (FreeMemory / 2));
522 SetDlgItemText(hwndDlg, IDC_RECOMMENDED, szBuffer);
523 }
524
525 /* Set current pagefile size */
526 FileSize = 0;
527 for (i = 0; i < 26; i++)
528 {
529 FileSize += pVirtMem->Pagefile[i].InitialSize;
530 }
531 _stprintf(szBuffer, _T("%u MB"), FileSize);
532 SetDlgItemText(hwndDlg, IDC_CURRENT, szBuffer);
533 }
534
535 return TRUE;
536 }
537
538
539 static VOID
540 OnOk(PVIRTMEM pVirtMem)
541 {
542 if (pVirtMem->bSave == TRUE)
543 {
544 WritePageFileSettings(pVirtMem);
545 }
546 }
547
548
549 static VOID
550 OnInitDialog(HWND hwnd, PVIRTMEM pVirtMem)
551 {
552 pVirtMem->hSelf = hwnd;
553 pVirtMem->hListBox = GetDlgItem(hwnd, IDC_PAGEFILELIST);
554 pVirtMem->bSave = FALSE;
555
556 SetListBoxColumns(pVirtMem->hListBox);
557
558 /* Load the pagefile systems from the reg */
559 if (ReadPageFileSettings(pVirtMem))
560 {
561 /* Parse our settings and set up dialog */
562 ParseMemSettings(pVirtMem);
563 }
564 }
565
566
567 INT_PTR CALLBACK
568 VirtMemDlgProc(HWND hwndDlg,
569 UINT uMsg,
570 WPARAM wParam,
571 LPARAM lParam)
572 {
573 PVIRTMEM pVirtMem;
574
575 UNREFERENCED_PARAMETER(lParam);
576
577 pVirtMem = (PVIRTMEM)GetWindowLongPtr(hwndDlg, DWLP_USER);
578
579 switch (uMsg)
580 {
581 case WM_INITDIALOG:
582 pVirtMem = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(VIRTMEM));
583 if (pVirtMem == NULL)
584 {
585 EndDialog(hwndDlg, 0);
586 return FALSE;
587 }
588
589 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pVirtMem);
590
591 OnInitDialog(hwndDlg, pVirtMem);
592 break;
593
594 case WM_DESTROY:
595 if (pVirtMem->szPagingFiles)
596 HeapFree(GetProcessHeap(), 0,
597 pVirtMem->szPagingFiles);
598 HeapFree(GetProcessHeap(), 0, pVirtMem);
599 break;
600
601 case WM_COMMAND:
602 switch (LOWORD(wParam))
603 {
604 case IDCANCEL:
605 EndDialog(hwndDlg, 0);
606 return TRUE;
607
608 case IDOK:
609 OnOk(pVirtMem);
610 EndDialog(hwndDlg, 0);
611 return TRUE;
612
613 case IDC_NOPAGEFILE:
614 OnNoPagingFile(pVirtMem);
615 return TRUE;
616
617 case IDC_SYSMANSIZE:
618 OnSysManSize(pVirtMem);
619 return TRUE;
620
621 case IDC_CUSTOM:
622 OnCustom(pVirtMem);
623 return TRUE;
624
625 case IDC_SET:
626 OnSet(pVirtMem);
627 return TRUE;
628
629 case IDC_PAGEFILELIST:
630 switch HIWORD(wParam)
631 {
632 case LBN_SELCHANGE:
633 OnSelChange(hwndDlg, pVirtMem);
634 return TRUE;
635 }
636 break;
637 }
638 break;
639 }
640
641 return FALSE;
642 }