Implement the reading and writing of pagefile settings. We should not longer have...
[reactos.git] / reactos / dll / cpl / sysdm / virtmem.c
1 /*
2 * ReactOS
3 * Copyright (C) 2004 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id$
20 *
21 * PROJECT: ReactOS System Control Panel
22 * FILE: lib/cpl/sysdm/virtmem.c
23 * PURPOSE: pagefile settings
24 * PROGRAMMER: Christian Wallukat cwallukat(at)gmx(dot)at
25 */
26
27 #include <windows.h>
28 #include <commctrl.h>
29 #include <stdlib.h>
30 #include <tchar.h>
31 #include "resource.h"
32 #include "sysdm.h"
33 #include <stdio.h>
34 #include <winternl.h>
35
36
37
38 //
39 // An array of these structs will interally manage system page files
40 //
41 typedef struct _sPagefiles
42 {
43 WCHAR szDrive[10];
44 INT nMinValue;
45 INT nMaxValue;
46 INT nUsed;
47 } sPageFiles;
48
49
50
51 //
52 // At most there can be 32 drives, so only 32 page files
53 //
54 sPageFiles g_sPagefile[32];
55 //
56 // This is the number of drives that could have page files
57 //
58 INT g_nCount;
59 //
60 // Will save the user set action signal saving to the registry on exit
61 //
62 BOOL g_bSave;
63
64
65 //
66 // ReadRegSettings reads the page file settings from the regisrty
67 //
68 VOID ReadRegSettings(HWND hwndDlg);
69 //
70 // ParseMemSettings takes the regisrty string and create the internal page file array
71 //
72 VOID ParseMemSettings(TCHAR *szSettings, HWND hwndDlg);
73 //
74 // SaveSettings writes the paging file array to the registry
75 //
76 VOID SaveSettings(HWND hwndDlg);
77
78 //
79 // Callback function for messages for the windows
80 //
81 INT_PTR
82 CALLBACK
83 VirtMemDlgProc(HWND hwndDlg,
84 UINT uMsg,
85 WPARAM wParam,
86 LPARAM lParam)
87 {
88 SYSTEM_PROCESS_INFORMATION siSysPInfo;
89 TCHAR szTemp[255];
90 INT nIndex = 0;
91
92 //
93 // We dont need to look at this part of the message
94 //
95 UNREFERENCED_PARAMETER(lParam);
96
97 switch (uMsg)
98 {
99 case WM_INITDIALOG:
100 {
101 //
102 // We dont save the changes until set is clicked
103 //
104 g_bSave = FALSE;
105 //
106 // We start with no page files
107 //
108 g_nCount = 0;
109 //
110 // Clear out the file pagefile
111 //
112 g_sPagefile[0].nMaxValue = 0;
113 g_sPagefile[0].nMinValue = 0;
114 g_sPagefile[0].nUsed = 0;
115
116 //
117 // Grad the system stats to get some page file into
118 //
119 NtQuerySystemInformation(SystemProcessInformation, &siSysPInfo, sizeof(SYSTEM_PROCESS_INFORMATION), NULL);
120
121 //
122 // Convert the pagefile usage to a string
123 //
124 _itow(siSysPInfo.PeakPagefileUsage, szTemp, 10);
125
126 //
127 // Set pagefle useage to its label
128 //
129 SendDlgItemMessage(hwndDlg, IDC_CURRENT, WM_SETTEXT, (WPARAM)0, (LPARAM)szTemp);
130
131 //
132 // Load the pagefile systems from the reg
133 //
134 ReadRegSettings(hwndDlg);
135 };
136 break;
137
138 case WM_COMMAND:
139 {
140 switch (LOWORD(wParam))
141 {
142 case IDCANCEL:
143 {
144 //
145 // If the user hits cancel we just close and dont save
146 //
147 EndDialog(hwndDlg, 0);
148 return TRUE;
149 };
150 break;
151
152
153 case IDOK:
154 {
155 //
156 // Check to make sure that the user hit set and we will save the settings
157 //
158 if(g_bSave == TRUE)
159 {
160 SaveSettings(hwndDlg);
161 };
162
163 //
164 // Close out the window
165 //
166 EndDialog(hwndDlg, 0);
167 };
168 break;
169
170
171 case IDC_PAGEFILELIST:
172 {
173 switch(HIWORD(wParam))
174 {
175 case LBN_SELCHANGE:
176 {
177 //
178 // Get the currently selected page file from the list box
179 //
180 nIndex = (INT)SendDlgItemMessage(hwndDlg, IDC_PAGEFILELIST, LB_GETCURSEL, (WPARAM)0, (LPARAM)0);
181
182 //
183 // If the index is in our range then process that page file
184 //
185 if(nIndex < g_nCount)
186 {
187 //
188 // Convert the minvalue for the page file
189 //
190 _itow(g_sPagefile[nIndex].nMinValue, szTemp, 10);
191
192 //
193 // Set the min value to its textbox
194 //
195 SendDlgItemMessage(hwndDlg, IDC_INITIALSIZE, WM_SETTEXT, (WPARAM)0, (LPARAM)szTemp);
196
197 //
198 // Convert the max value of the page file to a string
199 //
200 _itow(g_sPagefile[nIndex].nMaxValue, szTemp, 10);
201
202 //
203 // Set the max value to its textbox
204 //
205 SendDlgItemMessage(hwndDlg, IDC_MAXSIZE, WM_SETTEXT, (WPARAM)0, (LPARAM)szTemp);
206
207 //
208 // Figure out what type of page file it is
209 //
210 if(g_sPagefile[nIndex].nMinValue == 0 && g_sPagefile[nIndex].nMaxValue == 0)
211 {
212 //
213 // There is either no page file or a system managed page file so we disable custom sizes
214 //
215 EnableWindow(GetDlgItem(hwndDlg, IDC_MAXSIZE), FALSE);
216 EnableWindow(GetDlgItem(hwndDlg, IDC_INITIALSIZE), FALSE);
217 //
218 // Check to see if that drive is used for paging
219 //
220 if(g_sPagefile[nIndex].nUsed == 1)
221 {
222 //
223 // This is a system managed page file
224 //
225 SendDlgItemMessage(hwndDlg, IDC_NOPAGEFILE, BM_SETCHECK, (WPARAM)0, (LPARAM)0);
226 SendDlgItemMessage(hwndDlg, IDC_SYSMANSIZE, BM_SETCHECK, (WPARAM)1, (LPARAM)0);
227 SendDlgItemMessage(hwndDlg, IDC_CUSTOM, BM_SETCHECK, (WPARAM)0, (LPARAM)0);
228 }
229 else
230 {
231 //
232 // There is no page file on this drive
233 //
234 SendDlgItemMessage(hwndDlg, IDC_NOPAGEFILE, BM_SETCHECK, (WPARAM)1, (LPARAM)0);
235 SendDlgItemMessage(hwndDlg, IDC_SYSMANSIZE, BM_SETCHECK, (WPARAM)0, (LPARAM)0);
236 SendDlgItemMessage(hwndDlg, IDC_CUSTOM, BM_SETCHECK, (WPARAM)0, (LPARAM)0);
237 }
238 }
239 else
240 {
241 //
242 // THis is a custom sized page file
243 //
244 SendDlgItemMessage(hwndDlg, IDC_NOPAGEFILE, BM_SETCHECK, (WPARAM)0, (LPARAM)0);
245 SendDlgItemMessage(hwndDlg, IDC_SYSMANSIZE, BM_SETCHECK, (WPARAM)0, (LPARAM)0);
246 SendDlgItemMessage(hwndDlg, IDC_CUSTOM, BM_SETCHECK, (WPARAM)1, (LPARAM)0);
247 //
248 // We need to allow the user to change the sizes
249 //
250 EnableWindow(GetDlgItem(hwndDlg, IDC_MAXSIZE), TRUE);
251 EnableWindow(GetDlgItem(hwndDlg, IDC_INITIALSIZE), TRUE);
252 }
253 };
254 };
255 break;
256 };
257 };
258 break;
259
260
261 case IDC_NOPAGEFILE:
262 {
263 //
264 // Set the pagefile to no page file
265 //
266 SendDlgItemMessage(hwndDlg, IDC_NOPAGEFILE, BM_SETCHECK, (WPARAM)1, (LPARAM)0);
267 SendDlgItemMessage(hwndDlg, IDC_SYSMANSIZE, BM_SETCHECK, (WPARAM)0, (LPARAM)0);
268 SendDlgItemMessage(hwndDlg, IDC_CUSTOM, BM_SETCHECK, (WPARAM)0, (LPARAM)0);
269
270 //
271 // Disable the page file custom size boxes
272 //
273 EnableWindow(GetDlgItem(hwndDlg, IDC_MAXSIZE), FALSE);
274 EnableWindow(GetDlgItem(hwndDlg, IDC_INITIALSIZE), FALSE);
275 };
276 break;
277
278 case IDC_SYSMANSIZE:
279 {
280 //
281 // User changed this to a system managed page file
282 //
283 SendDlgItemMessage(hwndDlg, IDC_NOPAGEFILE, BM_SETCHECK, (WPARAM)0, (LPARAM)0);
284 SendDlgItemMessage(hwndDlg, IDC_SYSMANSIZE, BM_SETCHECK, (WPARAM)1, (LPARAM)0);
285 SendDlgItemMessage(hwndDlg, IDC_CUSTOM, BM_SETCHECK, (WPARAM)0, (LPARAM)0);
286
287 //
288 // Disable the page file custom size boxes
289 //
290 EnableWindow(GetDlgItem(hwndDlg, IDC_MAXSIZE), FALSE);
291 EnableWindow(GetDlgItem(hwndDlg, IDC_INITIALSIZE), FALSE);
292 };
293 break;
294
295 case IDC_CUSTOM:
296 {
297 //
298 // User changed this to a cutom sized page file
299 //
300 SendDlgItemMessage(hwndDlg, IDC_NOPAGEFILE, BM_SETCHECK, (WPARAM)0, (LPARAM)0);
301 SendDlgItemMessage(hwndDlg, IDC_SYSMANSIZE, BM_SETCHECK, (WPARAM)0, (LPARAM)0);
302 SendDlgItemMessage(hwndDlg, IDC_CUSTOM, BM_SETCHECK, (WPARAM)1, (LPARAM)0);
303
304 //
305 // The user should be able to change the size of these files
306 //
307 EnableWindow(GetDlgItem(hwndDlg, IDC_MAXSIZE), TRUE);
308 EnableWindow(GetDlgItem(hwndDlg, IDC_INITIALSIZE), TRUE);
309 };
310 break;
311
312 case IDC_SET:
313 {
314 //
315 // The user hit set, so we are clear to save the settings when we are done
316 //
317 g_bSave = TRUE;
318
319 //
320 // Figure out which pagefile we are saving the settings too
321 //
322 nIndex = SendDlgItemMessage(hwndDlg, IDC_PAGEFILELIST, LB_GETCURSEL, (WPARAM)0, (LPARAM)0);
323
324 //
325 // Make sure it isnt out of our range
326 //
327 if(nIndex < g_nCount)
328 {
329 //
330 // Check to see what the current user input settings are
331 //
332 if(SendDlgItemMessage(hwndDlg, IDC_CUSTOM, BM_GETCHECK, (WPARAM)0, (LPARAM)0) == BST_CHECKED)
333 {
334 //
335 // If custom is checked we need to get the min size
336 //
337 SendDlgItemMessage(hwndDlg, IDC_INITIALSIZE, WM_GETTEXT, (WPARAM)254, (LPARAM)szTemp);
338
339 //
340 // Convert the size to an int and save it
341 //
342 g_sPagefile[nIndex].nMinValue = _wtoi(szTemp);
343
344 //
345 // If custom is checked we need to get the max size
346 //
347 SendDlgItemMessage(hwndDlg, IDC_MAXSIZE, WM_GETTEXT, (WPARAM)254, (LPARAM)szTemp);
348
349 //
350 // If custom is checked we need to get the max size
351 //
352 g_sPagefile[nIndex].nMaxValue = _wtoi(szTemp);
353
354 }
355 else
356 {
357 //
358 // If it is no paging file or system then we set the sizes to zero
359 //
360 g_sPagefile[nIndex].nMinValue = g_sPagefile[nIndex].nMaxValue = 0;
361 }
362
363 //
364 // We check to see if this drive is used for a paging file anymore
365 //
366 g_sPagefile[nIndex].nUsed = (SendDlgItemMessage(hwndDlg, IDC_NOPAGEFILE, BM_GETCHECK, (WPARAM)0, (LPARAM)0) == BST_UNCHECKED);
367
368
369 //
370 // FIXME: Rebuild the paging list
371 //
372 };
373 };
374 break;
375 };
376 };
377 break;
378
379 case WM_NOTIFY:
380 {
381 };
382 break;
383 };
384
385 return FALSE;
386 };
387
388
389 VOID
390 ReadRegSettings(HWND hwndDlg)
391 {
392 HKEY hk = NULL;
393 DWORD dwType = 0x0;
394 DWORD dwDataSize = 0x0;
395 TCHAR szValue[2048];
396
397
398 //
399 // Open or create this key to read our settings
400 //
401 if(RegCreateKeyEx(HKEY_LOCAL_MACHINE,
402 _T("SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Memory Management"),
403 0x0,
404 NULL,
405 REG_OPTION_NON_VOLATILE,
406 KEY_WRITE | KEY_READ,
407 NULL,
408 &hk,
409 NULL) == ERROR_SUCCESS)
410 {
411
412 //
413 // Get the size of the data
414 //
415 if(RegQueryValueEx(hk, _T("PagingFiles"), 0, &dwType, (PBYTE)NULL, &dwDataSize) == ERROR_SUCCESS)
416 {
417
418 //
419 // Read paging file settings from the regisrty
420 //
421 if(RegQueryValueEx(hk, _T("PagingFiles"), 0, &dwType, (PBYTE)(LPTSTR)szValue, &dwDataSize) == ERROR_SUCCESS)
422 {
423 //
424 // Parse our settings and set up controls accordingly
425 //
426 ParseMemSettings(szValue, hwndDlg);
427 }
428 else
429 {
430 //
431 // We had a problem :(
432 //
433 OutputDebugString(_T("Err read pagefile\n"));
434 };
435 }
436 else
437 {
438 //
439 // We had a problem :(
440 //
441 OutputDebugString(_T("Err open reg pagefile\n"));
442 };
443
444 //
445 // Close our key
446 //
447 RegCloseKey(hk);
448 };
449 };
450
451
452 VOID
453 ParseMemSettings(TCHAR *szSettings, HWND hwndDlg)
454 {
455 TCHAR szVolName[256];
456 TCHAR szDrive[25];
457 TCHAR szDrvLst[256];
458 TCHAR szTemp[256];
459 TCHAR szList[256];
460 INT nLastPos = 0;
461 INT nMinSize = 0;
462 INT nMaxSize = 0;
463 INT nTemp = 0;
464 BOOL bFound = FALSE;
465
466 g_nCount = 0;
467
468 //
469 // Clear out all our buffers
470 //
471 _wcsnset(szTemp, 0, sizeof(szTemp));
472 _wcsnset(szVolName, 0, sizeof(szVolName));
473 _wcsnset(szDrive, 0, sizeof(szDrive));
474 _wcsnset(szList, 0, sizeof(szList));
475
476 //
477 // Get a list of all the drives
478 //
479 GetLogicalDriveStrings(255, szDrvLst);
480
481 //
482 // Print out our drives and our reg string
483 //
484 OutputDebugString(szDrvLst);
485 OutputDebugString((TCHAR*)szSettings);
486
487 //
488 // Loop through all the drives
489 //
490 while(TRUE)
491 {
492 //
493 // Copy over the drive letter
494 //
495 wsprintf(szDrive, _T("%s"), szDrvLst + nLastPos);
496 nLastPos += 4;
497
498 //
499 // We should fixed and removeable drives, no network / cd
500 //
501 if(GetDriveType(szDrive) == DRIVE_FIXED || GetDriveType(szDrive) == DRIVE_REMOVABLE)
502 {
503 //
504 // Get some info about out drive
505 //
506 GetVolumeInformation(szDrive, (LPTSTR)szVolName, 255, NULL, NULL, NULL, NULL, 0);
507
508 //
509 // Cut off the Drive letter :
510 //
511 szDrive[2] = 0;
512
513 //
514 // Clear out our vars to prepare to walk page file setting string
515 //
516 nTemp = 0;
517 bFound = FALSE;
518
519 //
520 // Walk through the list of page files
521 //
522 while(TRUE)
523 {
524 //
525 // Copy over a page file setting for a drive skipping already processed ones
526 //
527 wsprintf(szTemp, _T("%s"), szSettings + nTemp);
528
529
530 //
531 // Check to see if the drive for the page file setting matches our current drive
532 //
533 if(!_tcsnicmp(szTemp,szDrive,1))
534 {
535 //
536 // Extract the min/max size from the string
537 //
538 nMinSize = (INT)(wcsstr(szTemp + 16, _T(" ")) - (szTemp + 16)) + 1;
539 nMaxSize = _wtoi(szTemp + 16 + nMinSize);
540 nMinSize = _wtoi(szTemp + 16);
541
542 //
543 // Fill in the page file settings in the internal array
544 //
545 g_sPagefile[g_nCount].nMaxValue = nMaxSize;
546 g_sPagefile[g_nCount].nMinValue = nMinSize;
547 g_sPagefile[g_nCount].nUsed = 1;
548 wsprintf(g_sPagefile[g_nCount].szDrive, _T("%s"), szDrive);
549
550 //
551 // Add up one more page file found
552 //
553 ++g_nCount;
554
555 //
556 // Indicate that we found a pagefile for this drive
557 //
558 bFound = TRUE;
559
560 break;
561 };
562
563 //
564 // Skip passed the just processed drive setting
565 //
566 nTemp += _tcslen(szSettings + nTemp) + 1;
567
568 //
569 // If we are done looking through the page file settings
570 // or found a matching setting then break out
571 //
572 if((_tcslen(szSettings + nTemp) <= 0) || (bFound == TRUE))
573 {
574 break;
575 };
576 };
577
578 //
579 // If we found a page file we make a string for the list box with the size
580 //
581 if(bFound == TRUE)
582 {
583 wsprintf(szList, _T("%s [%s] %i - %i"), szDrive, szVolName, nMinSize, nMaxSize);
584 }
585 else
586 {
587 //
588 // Otherwise we make a blank pagefile element to show no page file
589 //
590 g_sPagefile[g_nCount].nMaxValue = 0;
591 g_sPagefile[g_nCount].nMinValue = 0;
592 g_sPagefile[g_nCount].nUsed = 0;
593
594 //
595 // Copy over the drive for the blank page file element
596 //
597 wsprintf(g_sPagefile[g_nCount].szDrive, _T("%s"), szDrive);
598
599 //
600 // Add up one for the blank page file
601 //
602 ++g_nCount;
603
604 //
605 // We just show the name of the drive if there is no page file
606 //
607 wsprintf(szList, _T("%s [%s]"), szDrive, szVolName);
608 };
609
610 //
611 // Add our string to the page file list
612 //
613 SendDlgItemMessage(hwndDlg, IDC_PAGEFILELIST, LB_ADDSTRING, (WPARAM)NULL, (LPARAM)szList);
614
615 //
616 // Print out the newly added string
617 //
618 OutputDebugString(szList);
619 };
620
621 //
622 // Once all drive have finished being processed then we break out
623 //
624 if(_tcslen(szDrvLst + nLastPos) <= 0)
625 {
626 return;
627 };
628 };
629 };
630
631
632 void SaveSettings(HWND hwndDlg)
633 {
634 HKEY hk = NULL;
635 TCHAR szValue[2048];
636 TCHAR szTemp[512];
637 INT nCount = 0;
638 INT nPos = 0;
639
640 //
641 // Clear out our buffers
642 //
643 _wcsnset(szValue, 0, sizeof(szValue));
644 _wcsnset(szTemp, 0, sizeof(szTemp));
645
646 //
647 // Go through all our internal pagefile records
648 //
649 for(nCount = 0; nCount < g_nCount; ++nCount)
650 {
651 //
652 // We only save it to the regisrty if is used
653 //
654 if(g_sPagefile[nCount].nUsed == 1)
655 {
656 //
657 // Clear out our temp buffer
658 //
659 _wcsnset(szTemp, 0, sizeof(szTemp));
660 //
661 // Copy the path and sizes to our temp buffer for the page file
662 //
663 wsprintf(szTemp, _T("%s\\pagefile.sys %i %i"), g_sPagefile[nCount].szDrive, g_sPagefile[nCount].nMinValue, g_sPagefile[nCount].nMaxValue);
664
665 //
666 // Add it to our overall regisrty string
667 //
668 _tcscat(szValue+nPos,szTemp);
669
670 //
671 // Record the positioon where the next string will be placed in the buffer
672 //
673 nPos += _tcslen(szTemp) + 1;
674 // Add our null chars in to seperate the page files(REG_MULTI_SZ string)
675 szValue[nPos - 1] = 0;
676 szValue[nPos] = 0;
677 };
678 };
679
680 //
681 // Now that we have page file setting string we open up the key to save it
682 //
683 if(RegCreateKeyEx(HKEY_LOCAL_MACHINE,
684 _T("SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Memory Management"),
685 0x0,
686 NULL,
687 REG_OPTION_NON_VOLATILE,
688 KEY_ALL_ACCESS,
689 NULL,
690 &hk,
691 NULL) == ERROR_SUCCESS)
692 {
693 //
694 // We save our page file settings to the PagingFiles value
695 //
696 if (RegSetValueEx(hk,
697 _T("PagingFiles"),
698 0,
699 REG_MULTI_SZ,
700 (LPBYTE) szValue,
701 (DWORD) (nPos+2)*sizeof(TCHAR)))
702 {
703 //
704 // We had a problem, so print out a message
705 //
706 OutputDebugString(_T("Could not save"));
707
708 //
709 // Get the error for our last operation
710 //
711 _ltow(GetLastError(), szValue, 10);
712
713 //
714 // Print out the error code
715 //
716 OutputDebugString(szValue);
717
718 }
719
720 //
721 // Close up the regisrty
722 //
723 RegCloseKey(hk);
724 }
725 else
726 {
727 //
728 // Print out an error that we couldnt open(create) the registry key.
729 //
730 OutputDebugString(_T("Could not open key"));
731 };
732 };
733
734
735 /* EOF */