Reintegrate header branch
[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 lstrcat(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 Value;
303 BOOL bTranslated;
304
305 pVirtMem->bSave = TRUE;
306
307 Index = (INT)SendDlgItemMessage(pVirtMem->hSelf,
308 IDC_PAGEFILELIST,
309 LB_GETCURSEL,
310 0,
311 0);
312 if (Index < pVirtMem->Count)
313 {
314 /* check if custom settings are checked */
315 if (IsDlgButtonChecked(pVirtMem->hSelf,
316 IDC_CUSTOM) == BST_CHECKED)
317 {
318 Value = GetDlgItemInt(pVirtMem->hSelf,
319 IDC_INITIALSIZE,
320 &bTranslated,
321 FALSE);
322 if (!bTranslated)
323 {
324 /* FIXME: Show error message instead of setting the edit
325 field to the previous value */
326 SetDlgItemInt(pVirtMem->hSelf,
327 IDC_INITIALSIZE,
328 pVirtMem->Pagefile[Index].InitialValue,
329 FALSE);
330 }
331 else
332 {
333 pVirtMem->Pagefile[Index].InitialValue = Value;
334 }
335
336 Value = GetDlgItemInt(pVirtMem->hSelf,
337 IDC_MAXSIZE,
338 &bTranslated,
339 FALSE);
340 if (!bTranslated)
341 {
342 /* FIXME: Show error message instead of setting the edit
343 field to the previous value */
344 SetDlgItemInt(pVirtMem->hSelf,
345 IDC_MAXSIZE,
346 pVirtMem->Pagefile[Index].MaxValue,
347 FALSE);
348 }
349 else
350 {
351 pVirtMem->Pagefile[Index].MaxValue = Value;
352 }
353 }
354 else
355 {
356 /* set sizes to 0 */
357 pVirtMem->Pagefile[Index].InitialValue = pVirtMem->Pagefile[Index].MaxValue = 0;
358
359 // check to see if this drive is used for a paging file
360 if (IsDlgButtonChecked(pVirtMem->hSelf,
361 IDC_NOPAGEFILE) == BST_UNCHECKED)
362 {
363 pVirtMem->Pagefile[Index].bUsed = TRUE;
364 }
365 else
366 {
367 pVirtMem->Pagefile[Index].bUsed = FALSE;
368 }
369 }
370 }
371 }
372
373
374 static BOOL
375 OnSelChange(HWND hwndDlg, PVIRTMEM pVirtMem)
376 {
377 TCHAR szBuffer[64];
378 MEMORYSTATUSEX MemoryStatus;
379 ULARGE_INTEGER FreeBytes;
380 DWORDLONG FreeMemory;
381 INT Index;
382 INT i;
383 INT FileSize;
384
385 Index = (INT)SendDlgItemMessage(hwndDlg,
386 IDC_PAGEFILELIST,
387 LB_GETCURSEL,
388 0,
389 0);
390 if (Index < pVirtMem->Count)
391 {
392 /* Set drive letter */
393 SetDlgItemText(hwndDlg, IDC_DRIVE,
394 pVirtMem->Pagefile[Index].szDrive);
395
396 /* Set available disk space */
397 if (GetDiskFreeSpaceEx(pVirtMem->Pagefile[Index].szDrive,
398 NULL, NULL, &FreeBytes))
399 {
400 _stprintf(szBuffer, _T("%I64u MB"), FreeBytes.QuadPart / (1024 * 1024));
401 SetDlgItemText(hwndDlg, IDC_SPACEAVAIL, szBuffer);
402 }
403
404 if (pVirtMem->Pagefile[Index].InitialValue != 0 &&
405 pVirtMem->Pagefile[Index].MaxValue != 0)
406 {
407 /* enable and fill the custom values */
408 EnableWindow(GetDlgItem(pVirtMem->hSelf, IDC_MAXSIZE), TRUE);
409 EnableWindow(GetDlgItem(pVirtMem->hSelf, IDC_INITIALSIZE), TRUE);
410
411 SetDlgItemInt(pVirtMem->hSelf,
412 IDC_INITIALSIZE,
413 pVirtMem->Pagefile[Index].InitialValue,
414 FALSE);
415
416 SetDlgItemInt(pVirtMem->hSelf,
417 IDC_MAXSIZE,
418 pVirtMem->Pagefile[Index].MaxValue,
419 FALSE);
420
421 CheckDlgButton(pVirtMem->hSelf,
422 IDC_CUSTOM,
423 BST_CHECKED);
424 }
425 else
426 {
427 /* It's not a custom value */
428 EnableWindow(GetDlgItem(pVirtMem->hSelf, IDC_MAXSIZE), FALSE);
429 EnableWindow(GetDlgItem(pVirtMem->hSelf, IDC_INITIALSIZE), FALSE);
430
431 /* is it system managed */
432 if (pVirtMem->Pagefile[Index].bUsed)
433 {
434 CheckDlgButton(pVirtMem->hSelf,
435 IDC_SYSMANSIZE,
436 BST_CHECKED);
437 }
438 else
439 {
440 CheckDlgButton(pVirtMem->hSelf,
441 IDC_NOPAGEFILE,
442 BST_CHECKED);
443 }
444 }
445
446 /* Set minimum pagefile size */
447 SetDlgItemText(hwndDlg, IDC_MINIMUM, _T("2 MB"));
448
449 /* Set recommended pagefile size */
450 MemoryStatus.dwLength = sizeof(MEMORYSTATUSEX);
451 if (GlobalMemoryStatusEx(&MemoryStatus))
452 {
453 FreeMemory = MemoryStatus.ullTotalPhys / (1024 * 1024);
454 _stprintf(szBuffer, _T("%I64u MB"), FreeMemory + (FreeMemory / 2));
455 SetDlgItemText(hwndDlg, IDC_RECOMMENDED, szBuffer);
456 }
457
458 /* Set current pagefile size */
459 FileSize = 0;
460 for (i = 0; i < 26; i++)
461 {
462 FileSize += pVirtMem->Pagefile[i].InitialValue;
463 }
464 _stprintf(szBuffer, _T("%u MB"), FileSize);
465 SetDlgItemText(hwndDlg, IDC_CURRENT, szBuffer);
466 }
467
468 return TRUE;
469 }
470
471
472 static VOID
473 OnOk(PVIRTMEM pVirtMem)
474 {
475 if (pVirtMem->bSave == TRUE)
476 {
477 WritePageFileSettings(pVirtMem);
478 }
479 }
480
481
482 static VOID
483 OnInitDialog(HWND hwnd, PVIRTMEM pVirtMem)
484 {
485 pVirtMem->hSelf = hwnd;
486 pVirtMem->hListBox = GetDlgItem(hwnd, IDC_PAGEFILELIST);
487 pVirtMem->bSave = FALSE;
488
489 SetListBoxColumns(pVirtMem->hListBox);
490
491 /* Load the pagefile systems from the reg */
492 if (ReadPageFileSettings(pVirtMem))
493 {
494 /* Parse our settings and set up dialog */
495 ParseMemSettings(pVirtMem);
496 }
497 }
498
499
500 INT_PTR CALLBACK
501 VirtMemDlgProc(HWND hwndDlg,
502 UINT uMsg,
503 WPARAM wParam,
504 LPARAM lParam)
505 {
506 PVIRTMEM pVirtMem;
507
508 UNREFERENCED_PARAMETER(lParam);
509
510 pVirtMem = (PVIRTMEM)GetWindowLongPtr(hwndDlg, DWLP_USER);
511
512 switch (uMsg)
513 {
514 case WM_INITDIALOG:
515 pVirtMem = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(VIRTMEM));
516 if (pVirtMem == NULL)
517 {
518 EndDialog(hwndDlg, 0);
519 return FALSE;
520 }
521
522 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pVirtMem);
523
524 OnInitDialog(hwndDlg, pVirtMem);
525 break;
526
527 case WM_DESTROY:
528 if (pVirtMem->szPagingFiles)
529 HeapFree(GetProcessHeap(), 0,
530 pVirtMem->szPagingFiles);
531 HeapFree(GetProcessHeap(), 0, pVirtMem);
532 break;
533
534 case WM_COMMAND:
535 switch (LOWORD(wParam))
536 {
537 case IDCANCEL:
538 EndDialog(hwndDlg, 0);
539 return TRUE;
540
541 case IDOK:
542 OnOk(pVirtMem);
543 EndDialog(hwndDlg, 0);
544 return TRUE;
545
546 case IDC_NOPAGEFILE:
547 OnNoPagingFile(pVirtMem);
548 return TRUE;
549
550 case IDC_SYSMANSIZE:
551 OnSysManSize(pVirtMem);
552 return TRUE;
553
554 case IDC_CUSTOM:
555 OnCustom(pVirtMem);
556 return TRUE;
557
558 case IDC_SET:
559 OnSet(pVirtMem);
560 return TRUE;
561
562 case IDC_PAGEFILELIST:
563 switch HIWORD(wParam)
564 {
565 case LBN_SELCHANGE:
566 OnSelChange(hwndDlg, pVirtMem);
567 return TRUE;
568 }
569 break;
570 }
571 break;
572 }
573
574 return FALSE;
575 }