xref: /reactos/dll/cpl/sysdm/virtmem.c (revision 04b2d35f)
1 /*
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>
7  *
8  */
9 
10 #include "precomp.h"
11 
12 #ifdef _M_IX86
13 /* Used for SharedUserData by GetMaxPageFileSize() in the PAE case */
14 #define NTOS_MODE_USER
15 #include <ndk/pstypes.h>
16 #endif
17 
18 #define NDEBUG
19 #include <debug.h>
20 
21 // #define MAX_PAGING_FILES     16  // See also ntoskrnl/include/internal/mm.h
22 #define MEGABYTE                        (1024 * 1024)
23 
24 /* Values adapted from smss/pagefile.c, converted in megabytes and rounded-down.
25  * Compare to the more "accurate" values from SMSS (and NTOS) in bytes. */
26 
27 /* Minimum pagefile size: 2 MB, instead of 256 pages (1 MB) */
28 #define MINIMUM_PAGEFILE_SIZE           2
29 
30 /* Maximum pagefile sizes for different architectures */
31 #define MAXIMUM_PAGEFILE_SIZE32         (4UL * 1024 - 1)
32 #define MAXIMUM_PAGEFILE_SIZE64         (16UL * 1024 * 1024 - 1)
33 
34 #if defined(_M_IX86)
35 /* 4095 MB */
36     #define MAXIMUM_PAGEFILE_SIZE       MAXIMUM_PAGEFILE_SIZE32
37 /* PAE uses the same size as x64 */
38     #define MAXIMUM_PAGEFILE_SIZE_PAE   MAXIMUM_PAGEFILE_SIZE64
39 #elif defined (_M_AMD64) || defined(_M_ARM64)
40 /* Around 16 TB */
41     #define MAXIMUM_PAGEFILE_SIZE       MAXIMUM_PAGEFILE_SIZE64
42 #elif defined (_M_IA64)
43 /* Around 32 TB */
44     #define MAXIMUM_PAGEFILE_SIZE       (32UL * 1024 * 1024 - 1)
45 #elif defined(_M_ARM)
46 /* Around 2 GB */
47     #if (NTDDI_VERSION >= NTDDI_WINBLUE) // NTDDI_WIN81
48     #define MAXIMUM_PAGEFILE_SIZE       (2UL * 1024 - 1)
49     #else
50 /* Around 4 GB */
51     #define MAXIMUM_PAGEFILE_SIZE       MAXIMUM_PAGEFILE_SIZE32
52     #endif
53 #else
54 /* On unknown architectures, default to either one of the 32 or 64 bit sizes */
55 #pragma message("Unknown architecture")
56     #ifdef _WIN64
57     #define MAXIMUM_PAGEFILE_SIZE       MAXIMUM_PAGEFILE_SIZE64
58     #else
59     #define MAXIMUM_PAGEFILE_SIZE       MAXIMUM_PAGEFILE_SIZE32
60     #endif
61 #endif
62 
63 typedef struct _PAGEFILE
64 {
65     TCHAR  szDrive[3];
66     LPTSTR pszVolume;
67     INT    OldMinSize;
68     INT    OldMaxSize;
69     INT    NewMinSize;
70     INT    NewMaxSize;
71     UINT   FreeSize;
72     BOOL   bIsNotFAT;
73     BOOL   bUsed;
74 } PAGEFILE, *PPAGEFILE;
75 
76 typedef struct _VIRTMEM
77 {
78     HWND   hSelf;
79     HWND   hListBox;
80     LPTSTR szPagingFiles;
81     UINT   Count;
82     BOOL   bModified;
83     PAGEFILE PageFile[26];
84 } VIRTMEM, *PVIRTMEM;
85 
86 
87 static __inline
88 UINT
GetMaxPageFileSize(_In_ PPAGEFILE PageFile)89 GetMaxPageFileSize(
90     _In_ PPAGEFILE PageFile)
91 {
92 #ifdef _M_IX86
93     /* For x86 PAE-enabled systems, where the maximum pagefile size is
94      * greater than 4 GB, verify also that the drive's filesystem on which
95      * the pagefile is stored can support it. */
96     if (SharedUserData->ProcessorFeatures[PF_PAE_ENABLED] && PageFile->bIsNotFAT)
97         return min(PageFile->FreeSize, MAXIMUM_PAGEFILE_SIZE_PAE);
98 #endif
99     return min(PageFile->FreeSize, MAXIMUM_PAGEFILE_SIZE);
100 }
101 
102 static LPCTSTR lpKey = _T("SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Memory Management");
103 
104 static BOOL
ReadPageFileSettings(PVIRTMEM pVirtMem)105 ReadPageFileSettings(PVIRTMEM pVirtMem)
106 {
107     BOOL bRet = FALSE;
108     HKEY hkey = NULL;
109     DWORD dwType;
110     DWORD dwDataSize;
111 
112     if (RegCreateKeyEx(HKEY_LOCAL_MACHINE,
113                        lpKey,
114                        0,
115                        NULL,
116                        REG_OPTION_NON_VOLATILE,
117                        KEY_QUERY_VALUE,
118                        NULL,
119                        &hkey,
120                        NULL) == ERROR_SUCCESS)
121     {
122         if (RegQueryValueEx(hkey,
123                             _T("PagingFiles"),
124                             NULL,
125                             &dwType,
126                             NULL,
127                             &dwDataSize) == ERROR_SUCCESS)
128         {
129             pVirtMem->szPagingFiles = (LPTSTR)HeapAlloc(GetProcessHeap(),
130                                                         HEAP_ZERO_MEMORY,
131                                                         dwDataSize);
132             if (pVirtMem->szPagingFiles != NULL)
133             {
134                 if (RegQueryValueEx(hkey,
135                                     _T("PagingFiles"),
136                                     NULL,
137                                     &dwType,
138                                     (PBYTE)pVirtMem->szPagingFiles,
139                                     &dwDataSize) == ERROR_SUCCESS)
140                 {
141                     bRet = TRUE;
142                 }
143             }
144         }
145     }
146 
147     if (!bRet)
148         ShowLastWin32Error(pVirtMem->hSelf);
149 
150     if (hkey != NULL)
151         RegCloseKey(hkey);
152 
153     return bRet;
154 }
155 
156 
157 static VOID
GetPageFileSizes(LPTSTR lpPageFiles,LPINT lpInitialSize,LPINT lpMaximumSize)158 GetPageFileSizes(LPTSTR lpPageFiles,
159                  LPINT lpInitialSize,
160                  LPINT lpMaximumSize)
161 {
162     UINT i = 0;
163 
164     *lpInitialSize = -1;
165     *lpMaximumSize = -1;
166 
167     while (*lpPageFiles != _T('\0'))
168     {
169         if (*lpPageFiles == _T(' '))
170         {
171             lpPageFiles++;
172 
173             switch (i)
174             {
175                 case 0:
176                     *lpInitialSize = (INT)_ttoi(lpPageFiles);
177                     i = 1;
178                     break;
179 
180                 case 1:
181                     *lpMaximumSize = (INT)_ttoi(lpPageFiles);
182                     return;
183             }
184         }
185 
186         lpPageFiles++;
187     }
188 }
189 
190 
191 static VOID
ParseMemSettings(PVIRTMEM pVirtMem)192 ParseMemSettings(PVIRTMEM pVirtMem)
193 {
194     TCHAR szDrives[1024];    // All drives
195     LPTSTR DrivePtr = szDrives;
196     TCHAR szDrive[3];        // Single drive
197     TCHAR szVolume[MAX_PATH + 1];
198     TCHAR szFSName[MAX_PATH + 1];
199     INT MinSize;
200     INT MaxSize;
201     INT DriveLen;
202     INT Len;
203     UINT PgCnt = 0;
204     PPAGEFILE PageFile;
205 
206     DriveLen = GetLogicalDriveStrings(_countof(szDrives) - 1,
207                                       szDrives);
208 
209     while (DriveLen != 0)
210     {
211         Len = lstrlen(DrivePtr) + 1;
212         DriveLen -= Len;
213 
214         DrivePtr = _tcsupr(DrivePtr);
215 
216         /* Copy the 'X:' portion */
217         lstrcpyn(szDrive, DrivePtr, _countof(szDrive));
218 
219         if (GetDriveType(DrivePtr) == DRIVE_FIXED)
220         {
221             MinSize = -1;
222             MaxSize = -1;
223 
224             /* Does drive match the one in the registry ? */
225             if (_tcsnicmp(pVirtMem->szPagingFiles, szDrive, 2) == 0)
226             {
227                 GetPageFileSizes(pVirtMem->szPagingFiles,
228                                  &MinSize,
229                                  &MaxSize);
230             }
231 
232             PageFile = &pVirtMem->PageFile[PgCnt];
233             PageFile->OldMinSize = MinSize;
234             PageFile->OldMaxSize = MaxSize;
235             PageFile->NewMinSize = MinSize;
236             PageFile->NewMaxSize = MaxSize;
237             PageFile->bIsNotFAT  = TRUE; /* Suppose this is not a FAT volume */
238             PageFile->bUsed = TRUE;
239             lstrcpy(PageFile->szDrive, szDrive);
240 
241             /* Get the volume label if there is one */
242             if (GetVolumeInformation(DrivePtr,
243                                      szVolume, _countof(szVolume),
244                                      NULL, NULL, NULL,
245                                      szFSName, _countof(szFSName)))
246             {
247                 PageFile->pszVolume = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
248                                                 (_tcslen(szVolume) + 1) * sizeof(TCHAR));
249                 if (PageFile->pszVolume != NULL)
250                     _tcscpy(PageFile->pszVolume, szVolume);
251 
252                 /*
253                  * Check whether the volume is FAT, which cannot support files
254                  * larger than 4GB (for FAT32 and FATX, and less for FAT16).
255                  * This will limit the maximum size of the pagefile this volume
256                  * can contain (see GetMaxPageFileSize()).
257                  */
258                 PageFile->bIsNotFAT = (_tcsnicmp(szFSName, _T("FAT"), 3) != 0);
259             }
260 
261             PgCnt++;
262         }
263 
264         DrivePtr += Len;
265     }
266 
267     pVirtMem->Count = PgCnt;
268 }
269 
270 
271 static VOID
WritePageFileSettings(PVIRTMEM pVirtMem)272 WritePageFileSettings(PVIRTMEM pVirtMem)
273 {
274     BOOL bErr = TRUE;
275     HKEY hk = NULL;
276     TCHAR szText[256];
277     TCHAR szPagingFiles[2048];
278     UINT i, nPos = 0;
279     PPAGEFILE PageFile;
280 
281     for (i = 0; i < pVirtMem->Count; ++i)
282     {
283         PageFile = &pVirtMem->PageFile[i];
284 
285         if (PageFile->bUsed &&
286             PageFile->NewMinSize != -1 &&
287             PageFile->NewMaxSize != -1)
288         {
289             _stprintf(szText,
290                       _T("%s\\pagefile.sys %i %i"),
291                       PageFile->szDrive,
292                       PageFile->NewMinSize,
293                       PageFile->NewMaxSize);
294 
295             /* Add it to our overall registry string */
296             lstrcpy(szPagingFiles + nPos, szText);
297 
298             /* Record the position where the next string will start */
299             nPos += (UINT)lstrlen(szText) + 1;
300 
301             /* Add another NULL for REG_MULTI_SZ */
302             szPagingFiles[nPos] = _T('\0');
303             nPos++;
304         }
305     }
306 
307     if (RegCreateKeyEx(HKEY_LOCAL_MACHINE,
308                        lpKey,
309                        0,
310                        NULL,
311                        REG_OPTION_NON_VOLATILE,
312                        KEY_WRITE,
313                        NULL,
314                        &hk,
315                        NULL) == ERROR_SUCCESS)
316     {
317         if (RegSetValueEx(hk,
318                           _T("PagingFiles"),
319                           0,
320                           REG_MULTI_SZ,
321                           (LPBYTE)szPagingFiles,
322                           (DWORD)nPos * sizeof(TCHAR)) == ERROR_SUCCESS)
323         {
324             bErr = FALSE;
325         }
326 
327         RegCloseKey(hk);
328     }
329 
330     if (bErr == FALSE)
331     {
332         /* Delete obsolete paging files on the next boot */
333         for (i = 0; i < _countof(pVirtMem->PageFile); i++)
334         {
335             if (pVirtMem->PageFile[i].OldMinSize != -1 &&
336                 pVirtMem->PageFile[i].NewMinSize == -1)
337             {
338                 _stprintf(szText,
339                           _T("%s\\pagefile.sys"),
340                           pVirtMem->PageFile[i].szDrive);
341 
342                 MoveFileEx(szText, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
343             }
344         }
345     }
346 
347     if (bErr)
348         ShowLastWin32Error(pVirtMem->hSelf);
349 }
350 
351 
352 static VOID
SetListBoxColumns(HWND hwndListBox)353 SetListBoxColumns(HWND hwndListBox)
354 {
355     RECT rect = {0, 0, 103, 0};
356     MapDialogRect(hwndListBox, &rect);
357 
358     SendMessage(hwndListBox, LB_SETTABSTOPS, (WPARAM)1, (LPARAM)&rect.right);
359 }
360 
361 
362 static VOID
OnNoPagingFile(PVIRTMEM pVirtMem)363 OnNoPagingFile(PVIRTMEM pVirtMem)
364 {
365     /* Disable the page file custom size boxes */
366     EnableWindow(GetDlgItem(pVirtMem->hSelf, IDC_INITIALSIZE), FALSE);
367     EnableWindow(GetDlgItem(pVirtMem->hSelf, IDC_MAXSIZE), FALSE);
368 }
369 
370 
371 static VOID
OnSysManSize(PVIRTMEM pVirtMem)372 OnSysManSize(PVIRTMEM pVirtMem)
373 {
374     /* Disable the page file custom size boxes */
375     EnableWindow(GetDlgItem(pVirtMem->hSelf, IDC_INITIALSIZE), FALSE);
376     EnableWindow(GetDlgItem(pVirtMem->hSelf, IDC_MAXSIZE), FALSE);
377 }
378 
379 
380 static VOID
OnCustom(PVIRTMEM pVirtMem)381 OnCustom(PVIRTMEM pVirtMem)
382 {
383     /* Enable the page file custom size boxes */
384     EnableWindow(GetDlgItem(pVirtMem->hSelf, IDC_INITIALSIZE), TRUE);
385     EnableWindow(GetDlgItem(pVirtMem->hSelf, IDC_MAXSIZE), TRUE);
386 }
387 
388 
389 static BOOL OnSelChange(PVIRTMEM pVirtMem);
390 
391 static VOID
InitPagefileList(PVIRTMEM pVirtMem)392 InitPagefileList(PVIRTMEM pVirtMem)
393 {
394     INT Index;
395     UINT i;
396     PPAGEFILE PageFile;
397     TCHAR szSize[64];
398     TCHAR szDisplayString[256];
399 
400     for (i = 0; i < _countof(pVirtMem->PageFile); i++)
401     {
402         PageFile = &pVirtMem->PageFile[i];
403 
404         if (PageFile->bUsed)
405         {
406             if ((PageFile->NewMinSize == -1) &&
407                 (PageFile->NewMaxSize == -1))
408             {
409                 LoadString(hApplet,
410                            IDS_PAGEFILE_NONE,
411                            szSize,
412                            _countof(szSize));
413             }
414             else if ((PageFile->NewMinSize == 0) &&
415                      (PageFile->NewMaxSize == 0))
416             {
417                 LoadString(hApplet,
418                            IDS_PAGEFILE_SYSTEM,
419                            szSize,
420                            _countof(szSize));
421             }
422             else
423             {
424                 _stprintf(szSize, _T("%d - %d"),
425                           PageFile->NewMinSize,
426                           PageFile->NewMaxSize);
427             }
428 
429             _stprintf(szDisplayString,
430                       _T("%s  [%s]\t%s"),
431                       PageFile->szDrive,
432                       PageFile->pszVolume ? PageFile->pszVolume : _T(""),
433                       szSize);
434 
435             Index = SendMessage(pVirtMem->hListBox, LB_ADDSTRING, (WPARAM)0, (LPARAM)szDisplayString);
436             SendMessage(pVirtMem->hListBox, LB_SETITEMDATA, Index, i);
437         }
438     }
439 
440     SendMessage(pVirtMem->hListBox, LB_SETCURSEL, (WPARAM)0, (LPARAM)0);
441 
442     OnSelChange(pVirtMem);
443 }
444 
445 
446 static VOID
UpdatePagefileEntry(PVIRTMEM pVirtMem,INT ListIndex,INT DriveIndex)447 UpdatePagefileEntry(PVIRTMEM pVirtMem,
448                     INT ListIndex,
449                     INT DriveIndex)
450 {
451     PPAGEFILE PageFile = &pVirtMem->PageFile[DriveIndex];
452     TCHAR szSize[64];
453     TCHAR szDisplayString[256];
454 
455     if ((PageFile->NewMinSize == -1) &&
456         (PageFile->NewMaxSize == -1))
457     {
458         LoadString(hApplet,
459                    IDS_PAGEFILE_NONE,
460                    szSize,
461                    _countof(szSize));
462     }
463     else if ((PageFile->NewMinSize == 0) &&
464              (PageFile->NewMaxSize == 0))
465     {
466         LoadString(hApplet,
467                    IDS_PAGEFILE_SYSTEM,
468                    szSize,
469                    _countof(szSize));
470     }
471     else
472     {
473         _stprintf(szSize,
474                   _T("%d - %d"),
475                   PageFile->NewMinSize,
476                   PageFile->NewMaxSize);
477     }
478 
479     _stprintf(szDisplayString,
480               _T("%s  [%s]\t%s"),
481               PageFile->szDrive,
482               PageFile->pszVolume ? PageFile->pszVolume : _T(""),
483               szSize);
484 
485     SendMessage(pVirtMem->hListBox, LB_DELETESTRING, (WPARAM)ListIndex, 0);
486     SendMessage(pVirtMem->hListBox, LB_INSERTSTRING, (WPARAM)ListIndex, (LPARAM)szDisplayString);
487     SendMessage(pVirtMem->hListBox, LB_SETCURSEL, (WPARAM)ListIndex, 0);
488 }
489 
490 
491 static VOID
OnSet(PVIRTMEM pVirtMem)492 OnSet(PVIRTMEM pVirtMem)
493 {
494     INT Index;
495     UINT MinSize = -1;
496     UINT MaxSize = -1;
497     BOOL bTranslated;
498     UINT DriveIndex;
499     PPAGEFILE PageFile;
500 
501     Index = (INT)SendDlgItemMessage(pVirtMem->hSelf,
502                                     IDC_PAGEFILELIST,
503                                     LB_GETCURSEL,
504                                     0,
505                                     0);
506     if (Index >= 0 && Index < pVirtMem->Count)
507     {
508         DriveIndex = SendDlgItemMessage(pVirtMem->hSelf,
509                                         IDC_PAGEFILELIST,
510                                         LB_GETITEMDATA,
511                                         (WPARAM)Index,
512                                         0);
513 
514         PageFile = &pVirtMem->PageFile[DriveIndex];
515 
516         /* Check if custom settings are checked */
517         if (IsDlgButtonChecked(pVirtMem->hSelf,
518                                IDC_CUSTOM) == BST_CHECKED)
519         {
520             UINT maxPageFileSize;
521 
522             MinSize = GetDlgItemInt(pVirtMem->hSelf,
523                                     IDC_INITIALSIZE,
524                                     &bTranslated,
525                                     FALSE);
526             if (!bTranslated)
527             {
528                 ResourceMessageBox(hApplet,
529                                    NULL,
530                                    MB_ICONWARNING | MB_OK,
531                                    IDS_MESSAGEBOXTITLE,
532                                    IDS_WARNINITIALSIZE);
533                 return;
534             }
535 
536             MaxSize = GetDlgItemInt(pVirtMem->hSelf,
537                                     IDC_MAXSIZE,
538                                     &bTranslated,
539                                     FALSE);
540             if (!bTranslated)
541             {
542                 ResourceMessageBox(hApplet,
543                                    NULL,
544                                    MB_ICONWARNING | MB_OK,
545                                    IDS_MESSAGEBOXTITLE,
546                                    IDS_WARNMAXIMUMSIZE);
547                 return;
548             }
549 
550             maxPageFileSize = GetMaxPageFileSize(PageFile);
551 
552             /* Check the valid range of the minimum size */
553             if ((MinSize < MINIMUM_PAGEFILE_SIZE) ||
554                 (MinSize > maxPageFileSize))
555             {
556                 ResourceMessageBox(hApplet,
557                                    NULL,
558                                    MB_ICONWARNING | MB_OK,
559                                    IDS_MESSAGEBOXTITLE,
560                                    IDS_WARNINITIALRANGE,
561                                    maxPageFileSize);
562                 return;
563             }
564 
565             /* Check the valid range of the maximum size */
566             if ((MaxSize < MinSize) ||
567                 (MaxSize > maxPageFileSize))
568             {
569                 ResourceMessageBox(hApplet,
570                                    NULL,
571                                    MB_ICONWARNING | MB_OK,
572                                    IDS_MESSAGEBOXTITLE,
573                                    IDS_WARNMAXIMUMRANGE,
574                                    maxPageFileSize);
575                 return;
576             }
577 
578             // TODO: Check how much disk space would remain after
579             // storing a pagefile of a certain size. Warn/error out
580             // if less than 5 MB would remain.
581 
582             PageFile->NewMinSize = MinSize;
583             PageFile->NewMaxSize = MaxSize;
584             PageFile->bUsed = TRUE;
585         }
586         else if (IsDlgButtonChecked(pVirtMem->hSelf,
587                                     IDC_NOPAGEFILE) == BST_CHECKED)
588         {
589             /* No pagefile */
590             PageFile->NewMinSize = -1;
591             PageFile->NewMaxSize = -1;
592             PageFile->bUsed = TRUE;
593         }
594         else
595         {
596             /* System managed size*/
597             PageFile->NewMinSize = 0;
598             PageFile->NewMaxSize = 0;
599             PageFile->bUsed = TRUE;
600         }
601 
602         /* Set the modified flag if min or max size has changed */
603         if ((PageFile->OldMinSize != PageFile->NewMinSize) ||
604             (PageFile->OldMaxSize != PageFile->NewMaxSize))
605         {
606             pVirtMem->bModified = TRUE;
607         }
608 
609         UpdatePagefileEntry(pVirtMem, Index, DriveIndex);
610     }
611 }
612 
613 
614 static BOOL
OnSelChange(PVIRTMEM pVirtMem)615 OnSelChange(PVIRTMEM pVirtMem)
616 {
617     INT Index;
618     UINT DriveIndex;
619     PPAGEFILE PageFile;
620     MEMORYSTATUSEX MemoryStatus;
621     ULARGE_INTEGER FreeDiskSpace;
622     UINT i, PageFileSizeMb;
623     TCHAR szMegabytes[8];
624     TCHAR szBuffer[64];
625     TCHAR szText[MAX_PATH];
626     WIN32_FIND_DATA fdata = {0};
627     HANDLE hFind;
628     ULARGE_INTEGER pfSize;
629 
630     Index = (INT)SendDlgItemMessage(pVirtMem->hSelf,
631                                     IDC_PAGEFILELIST,
632                                     LB_GETCURSEL,
633                                     0,
634                                     0);
635     if (Index >= 0 && Index < pVirtMem->Count)
636     {
637         DriveIndex = SendDlgItemMessage(pVirtMem->hSelf,
638                                         IDC_PAGEFILELIST,
639                                         LB_GETITEMDATA,
640                                         (WPARAM)Index,
641                                         0);
642 
643         PageFile = &pVirtMem->PageFile[DriveIndex];
644 
645         LoadString(hApplet,
646                    IDS_PAGEFILE_MB,
647                    szMegabytes,
648                    _countof(szMegabytes));
649 
650         /* Set drive letter */
651         SetDlgItemText(pVirtMem->hSelf, IDC_DRIVE,
652                        PageFile->szDrive);
653 
654         /* Set available disk space */
655         if (GetDiskFreeSpaceEx(PageFile->szDrive,
656                                NULL, NULL, &FreeDiskSpace))
657         {
658             PageFile->FreeSize = (UINT)(FreeDiskSpace.QuadPart / MEGABYTE);
659             _stprintf(szBuffer, szMegabytes, PageFile->FreeSize);
660             SetDlgItemText(pVirtMem->hSelf, IDC_SPACEAVAIL, szBuffer);
661         }
662 
663         if (PageFile->NewMinSize == -1 &&
664             PageFile->NewMaxSize == -1)
665         {
666             /* No pagefile */
667             OnNoPagingFile(pVirtMem);
668             CheckDlgButton(pVirtMem->hSelf, IDC_NOPAGEFILE, BST_CHECKED);
669         }
670         else if (PageFile->NewMinSize == 0 &&
671                  PageFile->NewMaxSize == 0)
672         {
673             /* System managed size */
674             OnSysManSize(pVirtMem);
675             CheckDlgButton(pVirtMem->hSelf, IDC_SYSMANSIZE, BST_CHECKED);
676         }
677         else
678         {
679             /* Custom size */
680 
681             /* Enable and fill the custom values */
682             OnCustom(pVirtMem);
683 
684             SetDlgItemInt(pVirtMem->hSelf,
685                           IDC_INITIALSIZE,
686                           PageFile->NewMinSize,
687                           FALSE);
688 
689             SetDlgItemInt(pVirtMem->hSelf,
690                           IDC_MAXSIZE,
691                           PageFile->NewMaxSize,
692                           FALSE);
693 
694             CheckDlgButton(pVirtMem->hSelf,
695                            IDC_CUSTOM,
696                            BST_CHECKED);
697         }
698 
699         /* Set minimum pagefile size */
700         _stprintf(szBuffer, szMegabytes, MINIMUM_PAGEFILE_SIZE);
701         SetDlgItemText(pVirtMem->hSelf, IDC_MINIMUM, szBuffer);
702 
703         /* Set recommended pagefile size */
704         MemoryStatus.dwLength = sizeof(MemoryStatus);
705         if (GlobalMemoryStatusEx(&MemoryStatus))
706         {
707             UINT FreeMemMb, RecoMemMb;
708             UINT maxPageFileSize = GetMaxPageFileSize(PageFile);
709 
710             FreeMemMb = (UINT)(MemoryStatus.ullTotalPhys / MEGABYTE);
711             /* The recommended VM size is 150% of free memory */
712             RecoMemMb = FreeMemMb + (FreeMemMb / 2);
713             if (RecoMemMb > maxPageFileSize)
714                 RecoMemMb = maxPageFileSize;
715             _stprintf(szBuffer, szMegabytes, RecoMemMb);
716             SetDlgItemText(pVirtMem->hSelf, IDC_RECOMMENDED, szBuffer);
717         }
718 
719         /* Set current pagefile size */
720         PageFileSizeMb = 0;
721 
722         for (i = 0; i < pVirtMem->Count; i++)
723         {
724             _stprintf(szText,
725                       _T("%c:\\pagefile.sys"),
726                       pVirtMem->PageFile[i].szDrive[0]);
727 
728             hFind = FindFirstFile(szText, &fdata);
729             if (hFind == INVALID_HANDLE_VALUE)
730             {
731                 // FIXME: MsgBox error?
732                 DPRINT1("Unable to read PageFile size: %ls due to error %d\n",
733                         szText, GetLastError());
734             }
735             else
736             {
737                 pfSize.LowPart = fdata.nFileSizeLow;
738                 pfSize.HighPart = fdata.nFileSizeHigh;
739                 PageFileSizeMb += pfSize.QuadPart / MEGABYTE;
740                 FindClose(hFind);
741             }
742         }
743 
744         _stprintf(szBuffer, szMegabytes, PageFileSizeMb);
745         SetDlgItemText(pVirtMem->hSelf, IDC_CURRENT, szBuffer);
746     }
747 
748     return TRUE;
749 }
750 
751 
752 static VOID
OnVirtMemDialogOk(PVIRTMEM pVirtMem)753 OnVirtMemDialogOk(PVIRTMEM pVirtMem)
754 {
755     if (pVirtMem->bModified != FALSE)
756     {
757         ResourceMessageBox(hApplet,
758                            NULL,
759                            MB_ICONINFORMATION | MB_OK,
760                            IDS_MESSAGEBOXTITLE,
761                            IDS_INFOREBOOT);
762 
763         WritePageFileSettings(pVirtMem);
764     }
765 }
766 
767 
768 static VOID
OnInitVirtMemDialog(HWND hwnd,PVIRTMEM pVirtMem)769 OnInitVirtMemDialog(HWND hwnd, PVIRTMEM pVirtMem)
770 {
771     UINT i;
772     PPAGEFILE PageFile;
773 
774     pVirtMem->hSelf = hwnd;
775     pVirtMem->hListBox = GetDlgItem(hwnd, IDC_PAGEFILELIST);
776     pVirtMem->bModified = FALSE;
777 
778     SetListBoxColumns(pVirtMem->hListBox);
779 
780     for (i = 0; i < _countof(pVirtMem->PageFile); i++)
781     {
782         PageFile = &pVirtMem->PageFile[i];
783         PageFile->bUsed = FALSE;
784         PageFile->OldMinSize = -1;
785         PageFile->OldMaxSize = -1;
786         PageFile->NewMinSize = -1;
787         PageFile->NewMaxSize = -1;
788         PageFile->FreeSize   = 0;
789         PageFile->bIsNotFAT  = TRUE; /* Suppose this is not a FAT volume */
790     }
791 
792     /* Load the pagefile systems from the reg */
793     ReadPageFileSettings(pVirtMem);
794 
795     /* Parse our settings and set up dialog */
796     ParseMemSettings(pVirtMem);
797 
798     InitPagefileList(pVirtMem);
799 }
800 
801 
802 static VOID
OnDestroy(PVIRTMEM pVirtMem)803 OnDestroy(PVIRTMEM pVirtMem)
804 {
805     UINT i;
806 
807     for (i = 0; i < _countof(pVirtMem->PageFile); i++)
808     {
809         if (pVirtMem->PageFile[i].pszVolume != NULL)
810             HeapFree(GetProcessHeap(), 0, pVirtMem->PageFile[i].pszVolume);
811     }
812 
813     if (pVirtMem->szPagingFiles)
814         HeapFree(GetProcessHeap(), 0, pVirtMem->szPagingFiles);
815 
816     HeapFree(GetProcessHeap(), 0, pVirtMem);
817 }
818 
819 
820 INT_PTR CALLBACK
VirtMemDlgProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)821 VirtMemDlgProc(HWND hwndDlg,
822                UINT uMsg,
823                WPARAM wParam,
824                LPARAM lParam)
825 {
826     PVIRTMEM pVirtMem;
827 
828     UNREFERENCED_PARAMETER(lParam);
829 
830     pVirtMem = (PVIRTMEM)GetWindowLongPtr(hwndDlg, DWLP_USER);
831 
832     switch (uMsg)
833     {
834         case WM_INITDIALOG:
835         {
836             pVirtMem = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(VIRTMEM));
837             if (pVirtMem == NULL)
838             {
839                 EndDialog(hwndDlg, 0);
840                 return FALSE;
841             }
842 
843             SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pVirtMem);
844 
845             OnInitVirtMemDialog(hwndDlg, pVirtMem);
846             break;
847         }
848 
849         case WM_DESTROY:
850             OnDestroy(pVirtMem);
851             break;
852 
853         case WM_COMMAND:
854             switch (LOWORD(wParam))
855             {
856                 case IDCANCEL:
857                     EndDialog(hwndDlg, 0);
858                     return TRUE;
859 
860                 case IDOK:
861                     OnVirtMemDialogOk(pVirtMem);
862                     EndDialog(hwndDlg, pVirtMem->bModified);
863                     return TRUE;
864 
865                 case IDC_NOPAGEFILE:
866                     OnNoPagingFile(pVirtMem);
867                     return TRUE;
868 
869                 case IDC_SYSMANSIZE:
870                     OnSysManSize(pVirtMem);
871                     return TRUE;
872 
873                 case IDC_CUSTOM:
874                     OnCustom(pVirtMem);
875                     return TRUE;
876 
877                 case IDC_SET:
878                     OnSet(pVirtMem);
879                     return TRUE;
880 
881                 case IDC_PAGEFILELIST:
882                     switch (HIWORD(wParam))
883                     {
884                         case LBN_SELCHANGE:
885                             OnSelChange(pVirtMem);
886                             return TRUE;
887                     }
888                     break;
889             }
890             break;
891     }
892 
893     return FALSE;
894 }
895