fix a crash and the selchange notification code
[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(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 INT
71 GetPageFileSizes(LPTSTR lpPageFiles)
72 {
73 while (*lpPageFiles != _T('\0'))
74 {
75 if (*lpPageFiles == _T(' '))
76 {
77 lpPageFiles++;
78 return (INT)_ttoi(lpPageFiles);
79 }
80
81 lpPageFiles++;
82 }
83
84 return -1;
85 }
86
87
88 static VOID
89 ParseMemSettings(PVIRTMEM pVirtMem)
90 {
91 TCHAR szDrives[1024]; // all drives
92 LPTSTR DrivePtr = szDrives;
93 TCHAR szDrive[3]; // single drive
94 TCHAR szVolume[MAX_PATH];
95 TCHAR *szDisplayString;
96 INT InitialSize = 0;
97 INT MaxSize = 0;
98 INT DriveLen;
99 INT PgCnt = 0;
100
101 ZeroMemory(&szDrives, sizeof(szDrives) * sizeof(TCHAR));
102 DriveLen = GetLogicalDriveStrings(1023,
103 szDrives);
104
105 szDisplayString = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (MAX_PATH * 2 + 69) * sizeof(TCHAR));
106 if (szDisplayString == NULL)
107 return;
108
109 while (DriveLen != 0)
110 {
111 INT Len;
112
113 Len = lstrlen(DrivePtr) + 1;
114 DriveLen -= Len;
115
116 DrivePtr = _tcsupr(DrivePtr);
117
118 /* copy the 'X:' portion */
119 lstrcpyn(szDrive, DrivePtr, 3);
120
121 if(GetDriveType(DrivePtr) == DRIVE_FIXED)
122 {
123 /* does drive match the one in the registry ? */
124 if(!_tcsncmp(pVirtMem->szPagingFiles, szDrive, 2))
125 {
126 /* FIXME: we only check the first available pagefile in the reg */
127 InitialSize = GetPageFileSizes(pVirtMem->szPagingFiles);
128 MaxSize = GetPageFileSizes(pVirtMem->szPagingFiles);
129
130 pVirtMem->Pagefile[PgCnt].InitialValue = InitialSize;
131 pVirtMem->Pagefile[PgCnt].MaxValue = MaxSize;
132 pVirtMem->Pagefile[PgCnt].bUsed = TRUE;
133 lstrcpy(pVirtMem->Pagefile[PgCnt].szDrive, szDrive);
134 }
135 else
136 {
137 pVirtMem->Pagefile[PgCnt].InitialValue = 0;
138 pVirtMem->Pagefile[PgCnt].MaxValue = 0;
139 pVirtMem->Pagefile[PgCnt].bUsed = FALSE;
140 lstrcpy(pVirtMem->Pagefile[PgCnt].szDrive, szDrive);
141 }
142
143 _tcscpy(szDisplayString, szDrive);
144 _tcscat(szDisplayString, _T("\t"));
145
146 /* set a volume label if there is one */
147 if (GetVolumeInformation(DrivePtr,
148 szVolume,
149 255,
150 NULL,
151 NULL,
152 NULL,
153 NULL,
154 0))
155 {
156 if (szVolume[0] != _T('\0'))
157 {
158 TCHAR szVol[MAX_PATH + 2];
159 _stprintf(szVol, _T("[%s]"), szVolume);
160 _tcscat(szDisplayString, szVol);
161 }
162 }
163
164 if ((InitialSize != 0) || (MaxSize != 0))
165 {
166 TCHAR szSize[64];
167
168 _stprintf(szSize, _T("%i - %i"), InitialSize, MaxSize);
169 _tcscat(szDisplayString, _T("\t"));
170 _tcscat(szDisplayString, szSize);
171 }
172
173 SendMessage(pVirtMem->hListBox, LB_ADDSTRING, (WPARAM)0, (LPARAM)szDisplayString);
174 PgCnt++;
175 }
176
177 DrivePtr += Len;
178 }
179
180 SendMessage(pVirtMem->hListBox, LB_SETCURSEL, (WPARAM)0, (LPARAM)0);
181 HeapFree(GetProcessHeap(), 0, szDisplayString);
182 pVirtMem->Count = PgCnt;
183 OnSelChange(pVirtMem);
184 }
185
186
187 static VOID
188 WritePageFileSettings(PVIRTMEM pVirtMem)
189 {
190 HKEY hk = NULL;
191 TCHAR szPagingFiles[2048];
192 INT i;
193 INT nPos = 0;
194 BOOL bErr = TRUE;
195
196 for(i = 0; i < pVirtMem->Count; ++i)
197 {
198 if(pVirtMem->Pagefile[i].bUsed)
199 {
200 TCHAR szText[256];
201
202 _stprintf(szText, _T("%s\\pagefile.sys %i %i"),
203 pVirtMem->Pagefile[i].szDrive,
204 pVirtMem->Pagefile[i].InitialValue,
205 pVirtMem->Pagefile[i].MaxValue);
206
207 /* Add it to our overall registry string */
208 lstrcat(szPagingFiles + nPos, szText);
209
210 /* Record the position where the next string will start */
211 nPos += (INT)lstrlen(szText) + 1;
212
213 /* add another NULL for REG_MULTI_SZ */
214 szPagingFiles[nPos] = _T('\0');
215 nPos++;
216 }
217 }
218
219 if(RegCreateKeyEx(HKEY_LOCAL_MACHINE,
220 lpKey,
221 0,
222 NULL,
223 REG_OPTION_NON_VOLATILE,
224 KEY_WRITE,
225 NULL,
226 &hk,
227 NULL) == ERROR_SUCCESS)
228 {
229 if (RegSetValueEx(hk,
230 _T("PagingFiles"),
231 0,
232 REG_MULTI_SZ,
233 (LPBYTE) szPagingFiles,
234 (DWORD) nPos * sizeof(TCHAR)) == ERROR_SUCCESS)
235 {
236 bErr = FALSE;
237 }
238
239 RegCloseKey(hk);
240 }
241
242 if (bErr)
243 ShowLastWin32Error(pVirtMem->hSelf);
244 }
245
246
247 static VOID
248 SetListBoxColumns(HWND hwndListBox)
249 {
250 INT tabs[2] = {30, 170};
251 SendMessage(hwndListBox, LB_SETTABSTOPS, (WPARAM)2, (LPARAM)(LPINT) &tabs[0]);
252 }
253
254
255 static VOID
256 OnNoPagingFile(PVIRTMEM pVirtMem)
257 {
258 /* Disable the page file custom size boxes */
259 EnableWindow(GetDlgItem(pVirtMem->hSelf, IDC_INITIALSIZE), FALSE);
260 EnableWindow(GetDlgItem(pVirtMem->hSelf, IDC_MAXSIZE), FALSE);
261 }
262
263
264 static VOID
265 OnSysManSize(PVIRTMEM pVirtMem)
266 {
267 /* Disable the page file custom size boxes */
268 EnableWindow(GetDlgItem(pVirtMem->hSelf, IDC_INITIALSIZE), FALSE);
269 EnableWindow(GetDlgItem(pVirtMem->hSelf, IDC_MAXSIZE), FALSE);
270 }
271
272
273 static VOID
274 OnCustom(PVIRTMEM pVirtMem)
275 {
276 /* Enable the page file custom size boxes */
277 EnableWindow(GetDlgItem(pVirtMem->hSelf, IDC_INITIALSIZE), TRUE);
278 EnableWindow(GetDlgItem(pVirtMem->hSelf, IDC_MAXSIZE), TRUE);
279 }
280
281
282 static VOID
283 OnSet(PVIRTMEM pVirtMem)
284 {
285 INT Index;
286
287 pVirtMem->bSave = TRUE;
288
289 Index = (INT)SendDlgItemMessage(pVirtMem->hSelf,
290 IDC_PAGEFILELIST,
291 LB_GETCURSEL,
292 0,
293 0);
294
295 if(Index < pVirtMem->Count)
296 {
297 TCHAR szText[255];
298
299 /* check if custom settings are checked */
300 if(SendDlgItemMessage(pVirtMem->hSelf,
301 IDC_CUSTOM,
302 BM_GETCHECK,
303 0,
304 0) == BST_CHECKED)
305 {
306 SendDlgItemMessage(pVirtMem->hSelf,
307 IDC_INITIALSIZE,
308 WM_GETTEXT,
309 254,
310 (LPARAM)szText);
311 pVirtMem->Pagefile[Index].InitialValue = _ttoi(szText);
312
313 SendDlgItemMessage(pVirtMem->hSelf,
314 IDC_MAXSIZE,
315 WM_GETTEXT,
316 254,
317 (LPARAM)szText);
318 pVirtMem->Pagefile[Index].MaxValue = _ttoi(szText);
319 }
320 else
321 {
322 /* set sizes to 0 */
323 pVirtMem->Pagefile[Index].InitialValue = pVirtMem->Pagefile[Index].MaxValue = 0;
324
325 // check to see if this drive is used for a paging file
326 if (SendDlgItemMessage(pVirtMem->hSelf,
327 IDC_NOPAGEFILE,
328 BM_GETCHECK,
329 0,
330 0) == BST_UNCHECKED)
331 {
332 pVirtMem->Pagefile[Index].bUsed = TRUE;
333 }
334 else
335 {
336 pVirtMem->Pagefile[Index].bUsed = FALSE;
337 }
338 }
339 }
340 }
341
342
343 static BOOL
344 OnSelChange(PVIRTMEM pVirtMem)
345 {
346 TCHAR szCustVals[255];
347 INT Index;
348
349 Index = (INT)SendDlgItemMessage(pVirtMem->hSelf,
350 IDC_PAGEFILELIST,
351 LB_GETCURSEL,
352 0,
353 0);
354
355 if(Index < pVirtMem->Count)
356 {
357
358 if(pVirtMem->Pagefile[Index].InitialValue != 0 &&
359 pVirtMem->Pagefile[Index].MaxValue != 0)
360 {
361 /* enable and fill the custom values */
362 EnableWindow(GetDlgItem(pVirtMem->hSelf, IDC_MAXSIZE), TRUE);
363 EnableWindow(GetDlgItem(pVirtMem->hSelf, IDC_INITIALSIZE), TRUE);
364
365 _itot(pVirtMem->Pagefile[Index].InitialValue , szCustVals, 10);
366 SendDlgItemMessage(pVirtMem->hSelf,
367 IDC_INITIALSIZE,
368 WM_SETTEXT,
369 0,
370 (LPARAM)szCustVals);
371
372 _itot(pVirtMem->Pagefile[Index].MaxValue, szCustVals, 10);
373 SendDlgItemMessage(pVirtMem->hSelf,
374 IDC_MAXSIZE,
375 WM_SETTEXT,
376 0,
377 (LPARAM)szCustVals);
378
379 SendDlgItemMessage(pVirtMem->hSelf,
380 IDC_CUSTOM,
381 BM_SETCHECK,
382 1,
383 0);
384 }
385 else
386 {
387 /* It's not a custom value */
388 EnableWindow(GetDlgItem(pVirtMem->hSelf, IDC_MAXSIZE), FALSE);
389 EnableWindow(GetDlgItem(pVirtMem->hSelf, IDC_INITIALSIZE), FALSE);
390
391 /* is it system managed */
392 if(pVirtMem->Pagefile[Index].bUsed)
393 {
394 SendDlgItemMessage(pVirtMem->hSelf,
395 IDC_SYSMANSIZE,
396 BM_SETCHECK,
397 1,
398 0);
399 }
400 else
401 {
402 SendDlgItemMessage(pVirtMem->hSelf,
403 IDC_NOPAGEFILE,
404 BM_SETCHECK,
405 1,
406 0);
407 }
408 }
409 }
410
411 return TRUE;
412 }
413
414
415 static VOID
416 OnOk(PVIRTMEM pVirtMem)
417 {
418 if(pVirtMem->bSave == TRUE)
419 {
420 WritePageFileSettings(pVirtMem);
421 }
422
423 if (pVirtMem->szPagingFiles)
424 HeapFree(GetProcessHeap(),
425 0,
426 pVirtMem->szPagingFiles);
427
428 HeapFree(GetProcessHeap(),
429 0,
430 pVirtMem);
431 }
432
433
434 static VOID
435 OnCancel(PVIRTMEM pVirtMem)
436 {
437 if (pVirtMem->szPagingFiles)
438 HeapFree(GetProcessHeap(),
439 0,
440 pVirtMem->szPagingFiles);
441
442 HeapFree(GetProcessHeap(),
443 0,
444 pVirtMem);
445 }
446
447
448 static PVIRTMEM
449 OnInitDialog(HWND hwnd)
450 {
451 PVIRTMEM pVirtMem = (PVIRTMEM)HeapAlloc(GetProcessHeap(),
452 HEAP_ZERO_MEMORY,
453 sizeof(VIRTMEM));
454 if (pVirtMem == NULL)
455 {
456 EndDialog(hwnd, 0);
457 }
458
459 pVirtMem->hSelf = hwnd;
460 pVirtMem->hListBox = GetDlgItem(hwnd, IDC_PAGEFILELIST);
461 pVirtMem->bSave = FALSE;
462
463 SetListBoxColumns(pVirtMem->hListBox);
464
465 /* Load the pagefile systems from the reg */
466 if (ReadPageFileSettings(pVirtMem))
467 {
468 /* Parse our settings and set up dialog */
469 ParseMemSettings(pVirtMem);
470 }
471
472 return pVirtMem;
473 }
474
475
476 INT_PTR CALLBACK
477 VirtMemDlgProc(HWND hwndDlg,
478 UINT uMsg,
479 WPARAM wParam,
480 LPARAM lParam)
481 {
482 /* there can only be one instance of this dialog */
483 static PVIRTMEM pVirtMem = NULL;
484
485 UNREFERENCED_PARAMETER(lParam);
486
487 switch (uMsg)
488 {
489 case WM_INITDIALOG:
490 pVirtMem = OnInitDialog(hwndDlg);
491 break;
492
493 case WM_COMMAND:
494 {
495 switch (LOWORD(wParam))
496 {
497 case IDCANCEL:
498 OnCancel(pVirtMem);
499 EndDialog(hwndDlg, 0);
500 return TRUE;
501
502 case IDOK:
503 OnOk(pVirtMem);
504 EndDialog(hwndDlg, 0);
505 return TRUE;
506
507 case IDC_NOPAGEFILE:
508 OnNoPagingFile(pVirtMem);
509 return TRUE;
510
511 case IDC_SYSMANSIZE:
512 OnSysManSize(pVirtMem);
513 return TRUE;
514
515 case IDC_CUSTOM:
516 OnCustom(pVirtMem);
517 return TRUE;
518
519 case IDC_SET:
520 OnSet(pVirtMem);
521 return TRUE;
522
523 case IDC_PAGEFILELIST:
524 switch HIWORD(wParam)
525 {
526 case LBN_SELCHANGE:
527 OnSelChange(pVirtMem);
528 return TRUE;
529 }
530 break;
531 }
532 }
533 break;
534 }
535
536 return FALSE;
537 }