4603a4c910d704e8550b0898ad0ba05a0c887b6a
[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, nPos = 0;
210 BOOL bErr = TRUE;
211
212 for (i = 0; i < pVirtMem->Count; ++i)
213 {
214 if (pVirtMem->Pagefile[i].bUsed)
215 {
216 _stprintf(szText, _T("%s\\pagefile.sys %i %i"),
217 pVirtMem->Pagefile[i].szDrive,
218 pVirtMem->Pagefile[i].InitialSize,
219 pVirtMem->Pagefile[i].MaximumSize);
220
221 /* Add it to our overall registry string */
222 lstrcpy(szPagingFiles + nPos, szText);
223
224 /* Record the position where the next string will start */
225 nPos += (INT)lstrlen(szText) + 1;
226
227 /* Add another NULL for REG_MULTI_SZ */
228 szPagingFiles[nPos] = _T('\0');
229 nPos++;
230 }
231 }
232
233 if (RegCreateKeyEx(HKEY_LOCAL_MACHINE,
234 lpKey,
235 0,
236 NULL,
237 REG_OPTION_NON_VOLATILE,
238 KEY_WRITE,
239 NULL,
240 &hk,
241 NULL) == ERROR_SUCCESS)
242 {
243 if (RegSetValueEx(hk,
244 _T("PagingFiles"),
245 0,
246 REG_MULTI_SZ,
247 (LPBYTE) szPagingFiles,
248 (DWORD) nPos * sizeof(TCHAR)) == ERROR_SUCCESS)
249 {
250 bErr = FALSE;
251 }
252
253 RegCloseKey(hk);
254 }
255
256 if (bErr)
257 ShowLastWin32Error(pVirtMem->hSelf);
258 }
259
260
261 static VOID
262 SetListBoxColumns(HWND hwndListBox)
263 {
264 const INT tabs[2] = {30, 120};
265
266 SendMessage(hwndListBox, LB_SETTABSTOPS, (WPARAM)2, (LPARAM)&tabs[0]);
267 }
268
269
270 static VOID
271 OnNoPagingFile(PVIRTMEM pVirtMem)
272 {
273 /* Disable the page file custom size boxes */
274 EnableWindow(GetDlgItem(pVirtMem->hSelf, IDC_INITIALSIZE), FALSE);
275 EnableWindow(GetDlgItem(pVirtMem->hSelf, IDC_MAXSIZE), FALSE);
276 }
277
278
279 static VOID
280 OnSysManSize(PVIRTMEM pVirtMem)
281 {
282 /* Disable the page file custom size boxes */
283 EnableWindow(GetDlgItem(pVirtMem->hSelf, IDC_INITIALSIZE), FALSE);
284 EnableWindow(GetDlgItem(pVirtMem->hSelf, IDC_MAXSIZE), FALSE);
285 }
286
287
288 static VOID
289 OnCustom(PVIRTMEM pVirtMem)
290 {
291 /* Enable the page file custom size boxes */
292 EnableWindow(GetDlgItem(pVirtMem->hSelf, IDC_INITIALSIZE), TRUE);
293 EnableWindow(GetDlgItem(pVirtMem->hSelf, IDC_MAXSIZE), TRUE);
294 }
295
296
297 static VOID
298 OnSet(PVIRTMEM pVirtMem)
299 {
300 INT Index;
301 UINT InitialSize;
302 UINT MaximumSize;
303 BOOL bTranslated;
304 TCHAR szTitle[64];
305 TCHAR szMessage[256];
306
307 pVirtMem->bSave = TRUE;
308
309 Index = (INT)SendDlgItemMessage(pVirtMem->hSelf,
310 IDC_PAGEFILELIST,
311 LB_GETCURSEL,
312 0,
313 0);
314 if (Index >= 0 && Index < pVirtMem->Count)
315 {
316 /* Check if custom settings are checked */
317 if (IsDlgButtonChecked(pVirtMem->hSelf,
318 IDC_CUSTOM) == BST_CHECKED)
319 {
320 InitialSize = GetDlgItemInt(pVirtMem->hSelf,
321 IDC_INITIALSIZE,
322 &bTranslated,
323 FALSE);
324 if (!bTranslated)
325 {
326 if (LoadString(hApplet,
327 IDS_MESSAGEBOXTITLE,
328 szTitle,
329 sizeof(szTitle) / sizeof(szTitle[0])) == 0)
330 _tcscpy(szTitle, _T("System control panel applet"));
331
332 if (LoadString(hApplet,
333 IDS_WARNINITIALSIZE,
334 szMessage,
335 sizeof(szMessage) / sizeof(szMessage[0])) == 0)
336 _tcscpy(szMessage, _T("Enter a numeric value for the initial size of the paging file."));
337
338 MessageBox(NULL,
339 szMessage,
340 szTitle,
341 MB_ICONWARNING | MB_OK);
342 return;
343 }
344
345 MaximumSize = GetDlgItemInt(pVirtMem->hSelf,
346 IDC_MAXSIZE,
347 &bTranslated,
348 FALSE);
349 if (!bTranslated)
350 {
351 if (LoadString(hApplet,
352 IDS_MESSAGEBOXTITLE,
353 szTitle,
354 sizeof(szTitle) / sizeof(szTitle[0])) == 0)
355 _tcscpy(szTitle, _T("System control panel applet"));
356
357 if (LoadString(hApplet,
358 IDS_WARNMAXIMUMSIZE,
359 szMessage,
360 sizeof(szMessage) / sizeof(szMessage[0])) == 0)
361 _tcscpy(szMessage, _T("Enter a numeric value for the maximum size of the paging file."));
362
363 MessageBox(NULL,
364 szMessage,
365 szTitle,
366 MB_ICONWARNING | MB_OK);
367 return;
368 }
369
370 /* Check the valid range of the inial size */
371 if (InitialSize < 2 ||
372 InitialSize > pVirtMem->Pagefile[Index].FreeSize)
373 {
374 if (LoadString(hApplet,
375 IDS_MESSAGEBOXTITLE,
376 szTitle,
377 sizeof(szTitle) / sizeof(szTitle[0])) == 0)
378 _tcscpy(szTitle, _T("System control panel applet"));
379
380 LoadString(hApplet,
381 IDS_WARNINITIALRANGE,
382 szMessage,
383 sizeof(szMessage) / sizeof(szMessage[0]));
384
385 MessageBox(NULL,
386 szMessage,
387 szTitle,
388 MB_ICONWARNING | MB_OK);
389 return;
390 }
391
392 /* Check the valid range of the maximum size */
393 if (MaximumSize < InitialSize ||
394 MaximumSize > pVirtMem->Pagefile[Index].FreeSize)
395 {
396 if (LoadString(hApplet,
397 IDS_MESSAGEBOXTITLE,
398 szTitle,
399 sizeof(szTitle) / sizeof(szTitle[0])) == 0)
400 _tcscpy(szTitle, _T("System control panel applet"));
401
402 LoadString(hApplet,
403 IDS_WARNMAXIMUMRANGE,
404 szMessage,
405 sizeof(szMessage) / sizeof(szMessage[0]));
406
407 MessageBox(NULL,
408 szMessage,
409 szTitle,
410 MB_ICONWARNING | MB_OK);
411 return;
412 }
413
414 pVirtMem->Pagefile[Index].InitialSize = InitialSize;
415 pVirtMem->Pagefile[Index].MaximumSize = MaximumSize;
416 pVirtMem->Pagefile[Index].bUsed = TRUE;
417 }
418 else
419 {
420 /* Set sizes to 0 */
421 pVirtMem->Pagefile[Index].InitialSize = 0;
422 pVirtMem->Pagefile[Index].MaximumSize = 0;
423
424 // Check to see if this drive is used for a paging file
425 if (IsDlgButtonChecked(pVirtMem->hSelf,
426 IDC_NOPAGEFILE) == BST_UNCHECKED)
427 {
428 pVirtMem->Pagefile[Index].bUsed = TRUE;
429 }
430 else
431 {
432 pVirtMem->Pagefile[Index].bUsed = FALSE;
433 }
434 }
435 }
436 }
437
438
439 static BOOL
440 OnSelChange(HWND hwndDlg, PVIRTMEM pVirtMem)
441 {
442 TCHAR szBuffer[64];
443 MEMORYSTATUSEX MemoryStatus;
444 ULARGE_INTEGER FreeDiskSpace;
445 UINT i, FreeMemMb, PageFileSizeMb;
446 INT Index;
447
448 Index = (INT)SendDlgItemMessage(hwndDlg,
449 IDC_PAGEFILELIST,
450 LB_GETCURSEL,
451 0,
452 0);
453 if (Index >= 0 && Index < pVirtMem->Count)
454 {
455 /* Set drive letter */
456 SetDlgItemText(hwndDlg, IDC_DRIVE,
457 pVirtMem->Pagefile[Index].szDrive);
458
459 /* Set available disk space */
460 if (GetDiskFreeSpaceEx(pVirtMem->Pagefile[Index].szDrive,
461 NULL, NULL, &FreeDiskSpace))
462 {
463 pVirtMem->Pagefile[Index].FreeSize = (UINT)(FreeDiskSpace.QuadPart / (1024 * 1024));
464 _stprintf(szBuffer, _T("%u MB"), pVirtMem->Pagefile[Index].FreeSize);
465 SetDlgItemText(hwndDlg, IDC_SPACEAVAIL, szBuffer);
466 }
467
468 if (pVirtMem->Pagefile[Index].InitialSize != 0 &&
469 pVirtMem->Pagefile[Index].MaximumSize != 0)
470 {
471 /* Enable and fill the custom values */
472 EnableWindow(GetDlgItem(pVirtMem->hSelf, IDC_MAXSIZE), TRUE);
473 EnableWindow(GetDlgItem(pVirtMem->hSelf, IDC_INITIALSIZE), TRUE);
474
475 SetDlgItemInt(pVirtMem->hSelf,
476 IDC_INITIALSIZE,
477 pVirtMem->Pagefile[Index].InitialSize,
478 FALSE);
479
480 SetDlgItemInt(pVirtMem->hSelf,
481 IDC_MAXSIZE,
482 pVirtMem->Pagefile[Index].MaximumSize,
483 FALSE);
484
485 CheckDlgButton(pVirtMem->hSelf,
486 IDC_CUSTOM,
487 BST_CHECKED);
488 }
489 else
490 {
491 /* It's not a custom value */
492 EnableWindow(GetDlgItem(pVirtMem->hSelf, IDC_MAXSIZE), FALSE);
493 EnableWindow(GetDlgItem(pVirtMem->hSelf, IDC_INITIALSIZE), FALSE);
494
495 /* Is it system managed */
496 if (pVirtMem->Pagefile[Index].bUsed)
497 {
498 CheckDlgButton(pVirtMem->hSelf,
499 IDC_SYSMANSIZE,
500 BST_CHECKED);
501 }
502 else
503 {
504 CheckDlgButton(pVirtMem->hSelf,
505 IDC_NOPAGEFILE,
506 BST_CHECKED);
507 }
508 }
509
510 /* Set minimum pagefile size */
511 SetDlgItemText(hwndDlg, IDC_MINIMUM, _T("2 MB"));
512
513 /* Set recommended pagefile size */
514 MemoryStatus.dwLength = sizeof(MEMORYSTATUSEX);
515 if (GlobalMemoryStatusEx(&MemoryStatus))
516 {
517 FreeMemMb = (UINT)(MemoryStatus.ullTotalPhys / (1024 * 1024));
518 _stprintf(szBuffer, _T("%u MB"), FreeMemMb + (FreeMemMb / 2));
519 SetDlgItemText(hwndDlg, IDC_RECOMMENDED, szBuffer);
520 }
521
522 /* Set current pagefile size */
523 PageFileSizeMb = 0;
524 for (i = 0; i < 26; i++)
525 {
526 PageFileSizeMb += pVirtMem->Pagefile[i].InitialSize;
527 }
528 _stprintf(szBuffer, _T("%u MB"), PageFileSizeMb);
529 SetDlgItemText(hwndDlg, IDC_CURRENT, szBuffer);
530 }
531
532 return TRUE;
533 }
534
535
536 static VOID
537 OnOk(PVIRTMEM pVirtMem)
538 {
539 if (pVirtMem->bSave == TRUE)
540 {
541 WritePageFileSettings(pVirtMem);
542 }
543 }
544
545
546 static VOID
547 OnInitDialog(HWND hwnd, PVIRTMEM pVirtMem)
548 {
549 pVirtMem->hSelf = hwnd;
550 pVirtMem->hListBox = GetDlgItem(hwnd, IDC_PAGEFILELIST);
551 pVirtMem->bSave = FALSE;
552
553 SetListBoxColumns(pVirtMem->hListBox);
554
555 /* Load the pagefile systems from the reg */
556 if (ReadPageFileSettings(pVirtMem))
557 {
558 /* Parse our settings and set up dialog */
559 ParseMemSettings(pVirtMem);
560 }
561 }
562
563
564 INT_PTR CALLBACK
565 VirtMemDlgProc(HWND hwndDlg,
566 UINT uMsg,
567 WPARAM wParam,
568 LPARAM lParam)
569 {
570 PVIRTMEM pVirtMem;
571
572 UNREFERENCED_PARAMETER(lParam);
573
574 pVirtMem = (PVIRTMEM)GetWindowLongPtr(hwndDlg, DWLP_USER);
575
576 switch (uMsg)
577 {
578 case WM_INITDIALOG:
579 pVirtMem = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(VIRTMEM));
580 if (pVirtMem == NULL)
581 {
582 EndDialog(hwndDlg, 0);
583 return FALSE;
584 }
585
586 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pVirtMem);
587
588 OnInitDialog(hwndDlg, pVirtMem);
589 break;
590
591 case WM_DESTROY:
592 if (pVirtMem->szPagingFiles)
593 HeapFree(GetProcessHeap(), 0,
594 pVirtMem->szPagingFiles);
595 HeapFree(GetProcessHeap(), 0, pVirtMem);
596 break;
597
598 case WM_COMMAND:
599 switch (LOWORD(wParam))
600 {
601 case IDCANCEL:
602 EndDialog(hwndDlg, 0);
603 return TRUE;
604
605 case IDOK:
606 OnOk(pVirtMem);
607 EndDialog(hwndDlg, 0);
608 return TRUE;
609
610 case IDC_NOPAGEFILE:
611 OnNoPagingFile(pVirtMem);
612 return TRUE;
613
614 case IDC_SYSMANSIZE:
615 OnSysManSize(pVirtMem);
616 return TRUE;
617
618 case IDC_CUSTOM:
619 OnCustom(pVirtMem);
620 return TRUE;
621
622 case IDC_SET:
623 OnSet(pVirtMem);
624 return TRUE;
625
626 case IDC_PAGEFILELIST:
627 switch (HIWORD(wParam))
628 {
629 case LBN_SELCHANGE:
630 OnSelChange(hwndDlg, pVirtMem);
631 return TRUE;
632 }
633 break;
634 }
635 break;
636 }
637
638 return FALSE;
639 }