2 * PROJECT: ReactOS system properties, control panel applet
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll/cpl/sysdm/virtmem.c
5 * PURPOSE: Virtual memory control dialog
6 * COPYRIGHT: Copyright 2006 Ged Murphy <gedmurphy@gmail.com>
15 static BOOL
OnSelChange(HWND hwndDlg
, PVIRTMEM pVirtMem
);
16 static LPCTSTR lpKey
= _T("SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Memory Management");
19 ReadPageFileSettings(PVIRTMEM pVirtMem
)
26 if (RegCreateKeyEx(HKEY_LOCAL_MACHINE
,
30 REG_OPTION_NON_VOLATILE
,
34 NULL
) == ERROR_SUCCESS
)
36 if (RegQueryValueEx(hkey
,
41 &dwDataSize
) == ERROR_SUCCESS
)
43 pVirtMem
->szPagingFiles
= (LPTSTR
)HeapAlloc(GetProcessHeap(),
46 if (pVirtMem
->szPagingFiles
!= NULL
)
48 ZeroMemory(pVirtMem
->szPagingFiles
,
50 if (RegQueryValueEx(hkey
,
54 (PBYTE
)pVirtMem
->szPagingFiles
,
55 &dwDataSize
) == ERROR_SUCCESS
)
64 ShowLastWin32Error(pVirtMem
->hSelf
);
74 GetPageFileSizes(LPTSTR lpPageFiles
,
83 while (*lpPageFiles
!= _T('\0'))
85 if (*lpPageFiles
== _T(' '))
92 *lpInitialSize
= (INT
)_ttoi(lpPageFiles
);
97 *lpMaximumSize
= (INT
)_ttoi(lpPageFiles
);
108 ParseMemSettings(PVIRTMEM pVirtMem
)
110 TCHAR szDrives
[1024]; // All drives
111 LPTSTR DrivePtr
= szDrives
;
112 TCHAR szDrive
[3]; // Single drive
113 TCHAR szVolume
[MAX_PATH
+ 1];
120 DriveLen
= GetLogicalDriveStrings(1023,
123 while (DriveLen
!= 0)
125 Len
= lstrlen(DrivePtr
) + 1;
128 DrivePtr
= _tcsupr(DrivePtr
);
130 /* Copy the 'X:' portion */
131 lstrcpyn(szDrive
, DrivePtr
, sizeof(szDrive
) / sizeof(TCHAR
));
133 if (GetDriveType(DrivePtr
) == DRIVE_FIXED
)
138 /* Does drive match the one in the registry ? */
139 if (!_tcsncmp(pVirtMem
->szPagingFiles
, szDrive
, 2))
141 GetPageFileSizes(pVirtMem
->szPagingFiles
,
146 pVirtMem
->Pagefile
[PgCnt
].OldMinSize
= MinSize
;
147 pVirtMem
->Pagefile
[PgCnt
].OldMaxSize
= MaxSize
;
148 pVirtMem
->Pagefile
[PgCnt
].NewMinSize
= MinSize
;
149 pVirtMem
->Pagefile
[PgCnt
].NewMaxSize
= MaxSize
;
150 pVirtMem
->Pagefile
[PgCnt
].bUsed
= TRUE
;
151 lstrcpy(pVirtMem
->Pagefile
[PgCnt
].szDrive
, szDrive
);
154 /* Get the volume label if there is one */
155 if (GetVolumeInformation(DrivePtr
,
164 pVirtMem
->Pagefile
[PgCnt
].pszVolume
= HeapAlloc(GetProcessHeap(),
166 (_tcslen(szVolume
) + 1) * sizeof(TCHAR
));
167 if (pVirtMem
->Pagefile
[PgCnt
].pszVolume
!= NULL
)
168 _tcscpy(pVirtMem
->Pagefile
[PgCnt
].pszVolume
, szVolume
);
177 pVirtMem
->Count
= PgCnt
;
182 WritePageFileSettings(PVIRTMEM pVirtMem
)
185 TCHAR szPagingFiles
[2048];
190 for (i
= 0; i
< pVirtMem
->Count
; ++i
)
192 if (pVirtMem
->Pagefile
[i
].bUsed
&&
193 pVirtMem
->Pagefile
[i
].NewMinSize
!= -1 &&
194 pVirtMem
->Pagefile
[i
].NewMaxSize
!= -1)
197 _T("%s\\pagefile.sys %i %i"),
198 pVirtMem
->Pagefile
[i
].szDrive
,
199 pVirtMem
->Pagefile
[i
].NewMinSize
,
200 pVirtMem
->Pagefile
[i
].NewMaxSize
);
202 /* Add it to our overall registry string */
203 lstrcpy(szPagingFiles
+ nPos
, szText
);
205 /* Record the position where the next string will start */
206 nPos
+= (INT
)lstrlen(szText
) + 1;
208 /* Add another NULL for REG_MULTI_SZ */
209 szPagingFiles
[nPos
] = _T('\0');
214 if (RegCreateKeyEx(HKEY_LOCAL_MACHINE
,
218 REG_OPTION_NON_VOLATILE
,
222 NULL
) == ERROR_SUCCESS
)
224 if (RegSetValueEx(hk
,
228 (LPBYTE
) szPagingFiles
,
229 (DWORD
) nPos
* sizeof(TCHAR
)) == ERROR_SUCCESS
)
239 /* Delete obsolete paging files on the next boot */
240 for (i
= 0; i
< 26; i
++)
242 if (pVirtMem
->Pagefile
[i
].OldMinSize
!= -1 &&
243 pVirtMem
->Pagefile
[i
].NewMinSize
== -1)
246 _T("%s\\pagefile.sys"),
247 pVirtMem
->Pagefile
[i
].szDrive
);
249 MoveFileEx(szText
, NULL
, MOVEFILE_DELAY_UNTIL_REBOOT
);
255 ShowLastWin32Error(pVirtMem
->hSelf
);
261 SetListBoxColumns(HWND hwndListBox
)
263 RECT rect
= {0, 0, 103, 0};
264 MapDialogRect(hwndListBox
, &rect
);
266 SendMessage(hwndListBox
, LB_SETTABSTOPS
, (WPARAM
)1, (LPARAM
)&rect
.right
);
271 OnNoPagingFile(PVIRTMEM pVirtMem
)
273 /* Disable the page file custom size boxes */
274 EnableWindow(GetDlgItem(pVirtMem
->hSelf
, IDC_INITIALSIZE
), FALSE
);
275 EnableWindow(GetDlgItem(pVirtMem
->hSelf
, IDC_MAXSIZE
), FALSE
);
280 OnSysManSize(PVIRTMEM pVirtMem
)
282 /* Disable the page file custom size boxes */
283 EnableWindow(GetDlgItem(pVirtMem
->hSelf
, IDC_INITIALSIZE
), FALSE
);
284 EnableWindow(GetDlgItem(pVirtMem
->hSelf
, IDC_MAXSIZE
), FALSE
);
289 OnCustom(PVIRTMEM pVirtMem
)
291 /* Enable the page file custom size boxes */
292 EnableWindow(GetDlgItem(pVirtMem
->hSelf
, IDC_INITIALSIZE
), TRUE
);
293 EnableWindow(GetDlgItem(pVirtMem
->hSelf
, IDC_MAXSIZE
), TRUE
);
298 InitPagefileList(PVIRTMEM pVirtMem
)
300 TCHAR szDisplayString
[256];
305 for (i
= 0; i
< 26; i
++)
307 if (pVirtMem
->Pagefile
[i
].bUsed
)
309 if ((pVirtMem
->Pagefile
[i
].NewMinSize
== -1) &&
310 (pVirtMem
->Pagefile
[i
].NewMaxSize
== -1))
315 sizeof(szSize
) / sizeof(szSize
[0]));
317 else if ((pVirtMem
->Pagefile
[i
].NewMinSize
== 0) &&
318 (pVirtMem
->Pagefile
[i
].NewMaxSize
== 0))
323 sizeof(szSize
) / sizeof(szSize
[0]));
327 _stprintf(szSize
, _T("%d - %d"),
328 pVirtMem
->Pagefile
[i
].NewMinSize
,
329 pVirtMem
->Pagefile
[i
].NewMaxSize
);
332 _stprintf(szDisplayString
,
334 pVirtMem
->Pagefile
[i
].szDrive
,
335 pVirtMem
->Pagefile
[i
].pszVolume
? pVirtMem
->Pagefile
[i
].pszVolume
: _T(""),
338 Index
= SendMessage(pVirtMem
->hListBox
, LB_ADDSTRING
, (WPARAM
)0, (LPARAM
)szDisplayString
);
339 SendMessage(pVirtMem
->hListBox
, LB_SETITEMDATA
, Index
, i
);
343 SendMessage(pVirtMem
->hListBox
, LB_SETCURSEL
, (WPARAM
)0, (LPARAM
)0);
345 OnSelChange(pVirtMem
->hSelf
, pVirtMem
);
350 UpdatePagefileEntry(PVIRTMEM pVirtMem
,
354 TCHAR szDisplayString
[256];
357 if ((pVirtMem
->Pagefile
[DriveIndex
].NewMinSize
== -1) &&
358 (pVirtMem
->Pagefile
[DriveIndex
].NewMaxSize
== -1))
363 sizeof(szSize
) / sizeof(szSize
[0]));
365 else if ((pVirtMem
->Pagefile
[DriveIndex
].NewMinSize
== 0) &&
366 (pVirtMem
->Pagefile
[DriveIndex
].NewMaxSize
== 0))
371 sizeof(szSize
) / sizeof(szSize
[0]));
377 pVirtMem
->Pagefile
[DriveIndex
].NewMinSize
,
378 pVirtMem
->Pagefile
[DriveIndex
].NewMaxSize
);
381 _stprintf(szDisplayString
,
383 pVirtMem
->Pagefile
[DriveIndex
].szDrive
,
384 pVirtMem
->Pagefile
[DriveIndex
].pszVolume
? pVirtMem
->Pagefile
[DriveIndex
].pszVolume
: L
"",
387 SendMessage(pVirtMem
->hListBox
, LB_DELETESTRING
, (WPARAM
)ListIndex
, 0);
388 SendMessage(pVirtMem
->hListBox
, LB_INSERTSTRING
, (WPARAM
)ListIndex
, (LPARAM
)szDisplayString
);
389 SendMessage(pVirtMem
->hListBox
, LB_SETCURSEL
, (WPARAM
)ListIndex
, 0);
394 OnSet(PVIRTMEM pVirtMem
)
402 Index
= (INT
)SendDlgItemMessage(pVirtMem
->hSelf
,
407 if (Index
>= 0 && Index
< pVirtMem
->Count
)
409 DriveIndex
= SendDlgItemMessage(pVirtMem
->hSelf
,
415 /* Check if custom settings are checked */
416 if (IsDlgButtonChecked(pVirtMem
->hSelf
,
417 IDC_CUSTOM
) == BST_CHECKED
)
419 MinSize
= GetDlgItemInt(pVirtMem
->hSelf
,
425 ResourceMessageBox(hApplet
,
427 MB_ICONWARNING
| MB_OK
,
429 IDS_WARNINITIALSIZE
);
433 MaxSize
= GetDlgItemInt(pVirtMem
->hSelf
,
439 ResourceMessageBox(hApplet
,
441 MB_ICONWARNING
| MB_OK
,
443 IDS_WARNMAXIMUMSIZE
);
447 /* Check the valid range of the minimum size */
449 MinSize
> pVirtMem
->Pagefile
[DriveIndex
].FreeSize
||
452 ResourceMessageBox(hApplet
,
454 MB_ICONWARNING
| MB_OK
,
456 IDS_WARNINITIALRANGE
);
460 /* Check the valid range of the maximum size */
461 if (MaxSize
< MinSize
||
462 MaxSize
> pVirtMem
->Pagefile
[DriveIndex
].FreeSize
||
465 ResourceMessageBox(hApplet
,
467 MB_ICONWARNING
| MB_OK
,
469 IDS_WARNMAXIMUMRANGE
);
473 pVirtMem
->Pagefile
[DriveIndex
].NewMinSize
= MinSize
;
474 pVirtMem
->Pagefile
[DriveIndex
].NewMaxSize
= MaxSize
;
475 pVirtMem
->Pagefile
[DriveIndex
].bUsed
= TRUE
;
477 else if (IsDlgButtonChecked(pVirtMem
->hSelf
,
478 IDC_NOPAGEFILE
) == BST_CHECKED
)
481 pVirtMem
->Pagefile
[DriveIndex
].NewMinSize
= -1;
482 pVirtMem
->Pagefile
[DriveIndex
].NewMaxSize
= -1;
483 pVirtMem
->Pagefile
[DriveIndex
].bUsed
= TRUE
;
487 /* System managed size*/
488 pVirtMem
->Pagefile
[DriveIndex
].NewMinSize
= 0;
489 pVirtMem
->Pagefile
[DriveIndex
].NewMaxSize
= 0;
490 pVirtMem
->Pagefile
[DriveIndex
].bUsed
= TRUE
;
493 /* Set the modified flag if min or max size has changed */
494 if ((pVirtMem
->Pagefile
[DriveIndex
].OldMinSize
!= pVirtMem
->Pagefile
[DriveIndex
].NewMinSize
) ||
495 (pVirtMem
->Pagefile
[DriveIndex
].OldMaxSize
!= pVirtMem
->Pagefile
[DriveIndex
].NewMaxSize
))
496 pVirtMem
->bModified
= TRUE
;
498 UpdatePagefileEntry(pVirtMem
, Index
, DriveIndex
);
504 OnSelChange(HWND hwndDlg
, PVIRTMEM pVirtMem
)
507 MEMORYSTATUSEX MemoryStatus
;
508 ULARGE_INTEGER FreeDiskSpace
;
509 UINT i
, FreeMemMb
, RecoMemMb
, PageFileSizeMb
;
511 TCHAR szText
[MAX_PATH
], szMegabytes
[8];
512 WIN32_FIND_DATAW fdata
= {0};
514 ULARGE_INTEGER pfSize
;
516 Index
= (INT
)SendDlgItemMessage(hwndDlg
,
521 if (Index
>= 0 && Index
< pVirtMem
->Count
)
526 ARRAYSIZE(szMegabytes
));
528 /* Set drive letter */
529 SetDlgItemText(hwndDlg
, IDC_DRIVE
,
530 pVirtMem
->Pagefile
[Index
].szDrive
);
532 /* Set available disk space */
533 if (GetDiskFreeSpaceEx(pVirtMem
->Pagefile
[Index
].szDrive
,
534 NULL
, NULL
, &FreeDiskSpace
))
536 pVirtMem
->Pagefile
[Index
].FreeSize
= (UINT
)(FreeDiskSpace
.QuadPart
/ (1024 * 1024));
537 _stprintf(szBuffer
, szMegabytes
, pVirtMem
->Pagefile
[Index
].FreeSize
);
538 SetDlgItemText(hwndDlg
, IDC_SPACEAVAIL
, szBuffer
);
541 if (pVirtMem
->Pagefile
[Index
].NewMinSize
== -1 &&
542 pVirtMem
->Pagefile
[Index
].NewMaxSize
== -1)
546 EnableWindow(GetDlgItem(pVirtMem
->hSelf
, IDC_MAXSIZE
), FALSE
);
547 EnableWindow(GetDlgItem(pVirtMem
->hSelf
, IDC_INITIALSIZE
), FALSE
);
549 CheckDlgButton(pVirtMem
->hSelf
, IDC_NOPAGEFILE
, BST_CHECKED
);
551 else if (pVirtMem
->Pagefile
[Index
].NewMinSize
== 0 &&
552 pVirtMem
->Pagefile
[Index
].NewMaxSize
== 0)
554 /* System managed size*/
556 EnableWindow(GetDlgItem(pVirtMem
->hSelf
, IDC_MAXSIZE
), FALSE
);
557 EnableWindow(GetDlgItem(pVirtMem
->hSelf
, IDC_INITIALSIZE
), FALSE
);
559 CheckDlgButton(pVirtMem
->hSelf
, IDC_SYSMANSIZE
, BST_CHECKED
);
565 /* Enable and fill the custom values */
566 EnableWindow(GetDlgItem(pVirtMem
->hSelf
, IDC_MAXSIZE
), TRUE
);
567 EnableWindow(GetDlgItem(pVirtMem
->hSelf
, IDC_INITIALSIZE
), TRUE
);
569 SetDlgItemInt(pVirtMem
->hSelf
,
571 pVirtMem
->Pagefile
[Index
].NewMinSize
,
574 SetDlgItemInt(pVirtMem
->hSelf
,
576 pVirtMem
->Pagefile
[Index
].NewMaxSize
,
579 CheckDlgButton(pVirtMem
->hSelf
,
584 /* Set minimum pagefile size (2 MB) */
585 _stprintf(szBuffer
, szMegabytes
, 2);
586 SetDlgItemText(hwndDlg
, IDC_MINIMUM
, szBuffer
);
588 /* Set recommended pagefile size */
589 MemoryStatus
.dwLength
= sizeof(MEMORYSTATUSEX
);
590 if (GlobalMemoryStatusEx(&MemoryStatus
))
592 FreeMemMb
= (UINT
)(MemoryStatus
.ullTotalPhys
/ (1024 * 1024));
593 RecoMemMb
= FreeMemMb
+ (FreeMemMb
/ 2); /* The recommended VM size is 150% of free memory. */
594 if (RecoMemMb
> 4096)
596 _stprintf(szBuffer
, szMegabytes
, RecoMemMb
);
597 SetDlgItemText(hwndDlg
, IDC_RECOMMENDED
, szBuffer
);
600 /* Set current pagefile size */
603 for (i
= 0; i
< pVirtMem
->Count
; i
++)
606 _T("%c:\\pagefile.sys"),
607 pVirtMem
->Pagefile
[i
].szDrive
[0]);
609 hFind
= FindFirstFileW(szText
, &fdata
);
610 if (hFind
== INVALID_HANDLE_VALUE
)
612 DPRINT1("Unable to read PageFile size : %ls due to error %d\n", szText
,GetLastError());
616 pfSize
.LowPart
= fdata
.nFileSizeLow
;
617 pfSize
.HighPart
= fdata
.nFileSizeHigh
;
618 PageFileSizeMb
+= pfSize
.QuadPart
/ (1024*1024);
623 _stprintf(szBuffer
, szMegabytes
, PageFileSizeMb
);
624 SetDlgItemText(hwndDlg
, IDC_CURRENT
, szBuffer
);
632 OnVirtMemDialogOk(PVIRTMEM pVirtMem
)
634 if (pVirtMem
->bModified
!= FALSE
)
636 ResourceMessageBox(hApplet
,
638 MB_ICONINFORMATION
| MB_OK
,
642 WritePageFileSettings(pVirtMem
);
648 OnInitVirtMemDialog(HWND hwnd
, PVIRTMEM pVirtMem
)
652 pVirtMem
->hSelf
= hwnd
;
653 pVirtMem
->hListBox
= GetDlgItem(hwnd
, IDC_PAGEFILELIST
);
654 pVirtMem
->bModified
= FALSE
;
656 SetListBoxColumns(pVirtMem
->hListBox
);
658 for (i
= 0; i
< 26; i
++)
660 pVirtMem
->Pagefile
[i
].bUsed
= FALSE
;
661 pVirtMem
->Pagefile
[i
].OldMinSize
= -1;
662 pVirtMem
->Pagefile
[i
].OldMaxSize
= -1;
663 pVirtMem
->Pagefile
[i
].NewMinSize
= -1;
664 pVirtMem
->Pagefile
[i
].NewMaxSize
= -1;
667 /* Load the pagefile systems from the reg */
668 ReadPageFileSettings(pVirtMem
);
670 /* Parse our settings and set up dialog */
671 ParseMemSettings(pVirtMem
);
673 InitPagefileList(pVirtMem
);
678 OnDestroy(PVIRTMEM pVirtMem
)
682 for (i
= 0; i
< 26; i
++)
684 if (pVirtMem
->Pagefile
[i
].pszVolume
!= NULL
)
685 HeapFree(GetProcessHeap(), 0, pVirtMem
->Pagefile
[i
].pszVolume
);
688 if (pVirtMem
->szPagingFiles
)
689 HeapFree(GetProcessHeap(), 0, pVirtMem
->szPagingFiles
);
691 HeapFree(GetProcessHeap(), 0, pVirtMem
);
696 VirtMemDlgProc(HWND hwndDlg
,
703 UNREFERENCED_PARAMETER(lParam
);
705 pVirtMem
= (PVIRTMEM
)GetWindowLongPtr(hwndDlg
, DWLP_USER
);
710 pVirtMem
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(VIRTMEM
));
711 if (pVirtMem
== NULL
)
713 EndDialog(hwndDlg
, 0);
717 SetWindowLongPtr(hwndDlg
, DWLP_USER
, (LONG_PTR
)pVirtMem
);
719 OnInitVirtMemDialog(hwndDlg
, pVirtMem
);
727 switch (LOWORD(wParam
))
730 EndDialog(hwndDlg
, 0);
734 OnVirtMemDialogOk(pVirtMem
);
735 EndDialog(hwndDlg
, pVirtMem
->bModified
);
739 OnNoPagingFile(pVirtMem
);
743 OnSysManSize(pVirtMem
);
754 case IDC_PAGEFILELIST
:
755 switch (HIWORD(wParam
))
758 OnSelChange(hwndDlg
, pVirtMem
);