[CLASS2]
[reactos.git] / base / applications / msconfig_new / systempage.cpp
1 /*
2 * PROJECT: ReactOS Applications
3 * LICENSE: LGPL - See COPYING in the top level directory
4 * FILE: base/applications/msconfig_new/systempage.c
5 * PURPOSE: System page message handler
6 * COPYRIGHT: Copyright 2005-2006 Christoph von Wittich <Christoph@ApiViewer.de>
7 * 2011 Gregor Schneider <Gregor.Schneider@reactos.org>
8 * Copyright 2011-2012 Hermes BELUSCA - MAITO <hermes.belusca@sfr.fr>
9 */
10
11 #include "precomp.h"
12 #include <share.h>
13
14 #include "treeview.h"
15 #include "uxthemesupp.h"
16
17 #include "regutils.h"
18 #include "utils.h"
19
20
21 extern "C" {
22
23 LPCWSTR lpszSystemIni = L"%SystemRoot%\\system.ini"; // or: %windir%\\... ?
24 LPCWSTR lpszWinIni = L"%SystemRoot%\\win.ini"; // or: %windir%\\... ?
25
26 }
27
28 static LPCWSTR szMSConfigTok = L";msconfig "; // Note the trailing whitespace
29 static const size_t MSConfigTokLen = 10;
30
31
32 extern "C" {
33
34 DWORD GetSystemIniActivation(VOID)
35 {
36 DWORD dwSystemIni = 0;
37 RegGetDWORDValue(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Shared Tools\\MSConfig\\state", L"system.ini", &dwSystemIni);
38 return dwSystemIni;
39 }
40
41 DWORD GetWinIniActivation(VOID)
42 {
43 DWORD dwWinIni = 0;
44 RegGetDWORDValue(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Shared Tools\\MSConfig\\state", L"win.ini", &dwWinIni);
45 return dwWinIni;
46 }
47
48 }
49
50
51
52 static HWND hTree = NULL;
53 static WCHAR szSearchString[MAX_VALUE_NAME] = L"";
54 static BOOL bMatchExactText = FALSE;
55 static BOOL bSearchSense = TRUE; // TRUE == down, FALSE == up.
56 static BOOL bCaseSensitive = FALSE;
57
58 static void
59 ToLower(LPWSTR lpszString)
60 {
61 if (!lpszString)
62 return;
63
64 while (*lpszString)
65 {
66 *lpszString = towlower(*lpszString);
67 ++lpszString;
68 }
69 }
70
71 INT_PTR CALLBACK
72 FindDialogWndProc(HWND hDlg,
73 UINT message,
74 WPARAM wParam,
75 LPARAM lParam)
76 {
77 UNREFERENCED_PARAMETER(lParam);
78
79 switch (message)
80 {
81 case WM_INITDIALOG:
82 {
83 hTree = (HWND)lParam;
84
85 Button_SetCheck(GetDlgItem(hDlg, IDC_CBX_FIND_WHOLE_WORD_ONLY), (bMatchExactText ? BST_CHECKED : BST_UNCHECKED));
86 Button_SetCheck(GetDlgItem(hDlg, IDC_RB_FIND_DOWN), (bSearchSense ? BST_CHECKED : BST_UNCHECKED)); // TRUE == down, FALSE == up.
87 Button_SetCheck(GetDlgItem(hDlg, IDC_RB_FIND_UP ), (bSearchSense ? BST_UNCHECKED : BST_CHECKED )); // TRUE == down, FALSE == up.
88 Button_SetCheck(GetDlgItem(hDlg, IDC_CBX_FIND_MATCH_CASE), (bCaseSensitive ? BST_CHECKED : BST_UNCHECKED));
89
90 Edit_SetText(GetDlgItem(hDlg, IDC_TXT_FIND_TEXT), szSearchString);
91 SetFocus(GetDlgItem(hDlg, IDC_TXT_FIND_TEXT));
92 Edit_SetSel(GetDlgItem(hDlg, IDC_TXT_FIND_TEXT), 0, -1);
93
94 return TRUE;
95 }
96
97 case WM_COMMAND:
98 {
99 switch (LOWORD(wParam))
100 {
101 case IDOK:
102 {
103 TVITEMEXW tvItemEx;
104 HTREEITEM htiIterator;
105 WCHAR label[MAX_VALUE_NAME] = L"";
106 WCHAR szTemp[MAX_VALUE_NAME];
107
108 bMatchExactText = (Button_GetCheck(GetDlgItem(hDlg, IDC_CBX_FIND_WHOLE_WORD_ONLY)) == BST_CHECKED);
109 bSearchSense = ((Button_GetCheck(GetDlgItem(hDlg, IDC_RB_FIND_DOWN)) == BST_CHECKED) &&
110 (Button_GetCheck(GetDlgItem(hDlg, IDC_RB_FIND_UP )) == BST_UNCHECKED)); // TRUE == down, FALSE == up.
111 bCaseSensitive = (Button_GetCheck(GetDlgItem(hDlg, IDC_CBX_FIND_MATCH_CASE)) == BST_CHECKED);
112
113 Edit_GetText(GetDlgItem(hDlg, IDC_TXT_FIND_TEXT), szSearchString, _ARRAYSIZE(szSearchString));
114 wcscpy(szTemp, szSearchString);
115 if (!bCaseSensitive)
116 ToLower(szTemp);
117
118 for (htiIterator = ((Button_GetCheck(GetDlgItem(hDlg, IDC_CBX_FIND_FROM_BEGINNING)) == BST_CHECKED) ? (bSearchSense ? TreeView_GetFirst(hTree)
119 : TreeView_GetLast(hTree))
120 : (bSearchSense ? TreeView_GetNext(hTree, TreeView_GetSelection(hTree))
121 : TreeView_GetPrev(hTree, TreeView_GetSelection(hTree))));
122 htiIterator ;
123 htiIterator = (bSearchSense ? TreeView_GetNext(hTree, htiIterator)
124 : TreeView_GetPrev(hTree, htiIterator)))
125 {
126 SecureZeroMemory(&tvItemEx, sizeof(tvItemEx));
127
128 tvItemEx.hItem = htiIterator; // Handle of the item to be retrieved
129 tvItemEx.mask = TVIF_HANDLE | TVIF_TEXT;
130 tvItemEx.pszText = label;
131 tvItemEx.cchTextMax = MAX_VALUE_NAME;
132 TreeView_GetItem(hTree, &tvItemEx);
133 if (!bCaseSensitive)
134 ToLower(label);
135
136 if (bMatchExactText ? (_tcscmp(label, szTemp) == 0) : !!_tcsstr(label, szTemp)) // <-- hackish. A arranger.
137 {
138 TreeView_SelectItem(hTree, htiIterator);
139 EndDialog(hDlg, LOWORD(wParam));
140 return TRUE;
141 }
142 //MessageBox(NULL, label, _T("Info"), MB_ICONINFORMATION | MB_OK);
143 }
144
145 // FIXME: Localize!
146 MessageBoxW(hDlg, L"No correspondence found.", szAppName, MB_ICONINFORMATION | MB_OK);
147 SetFocus(GetDlgItem(hDlg, IDC_TXT_FIND_TEXT));
148 Edit_SetSel(GetDlgItem(hDlg, IDC_TXT_FIND_TEXT), 0, -1);
149 //EndDialog(hDlg, LOWORD(wParam));
150 return TRUE;
151 }
152
153 case IDCANCEL:
154 EndDialog(hDlg, LOWORD(wParam));
155 return TRUE;
156
157 default:
158 //break;
159 return FALSE;
160 }
161 }
162 }
163
164 return FALSE;
165 }
166
167
168
169 static void
170 TreeView_SetBOOLCheck(HWND hTree, HTREEITEM htiItem, BOOL bState, BOOL bPropagateStateToParent)
171 {
172 if (!hTree || !htiItem)
173 return;
174
175 TreeView_SetCheckState(hTree, htiItem, bState);
176
177 /*
178 * Add or remove the token for tree leaves only.
179 */
180 if (!TreeView_GetChild(hTree, htiItem))
181 {
182 /* 1- Retrieve properties */
183 TVITEMEXW tvItemEx;
184 SecureZeroMemory(&tvItemEx, sizeof(tvItemEx));
185
186 tvItemEx.hItem = htiItem; // Handle of the item to be retrieved.
187 tvItemEx.mask = TVIF_HANDLE | TVIF_TEXT;
188 WCHAR label[MAX_VALUE_NAME] = L"";
189 tvItemEx.pszText = label;
190 tvItemEx.cchTextMax = MAX_VALUE_NAME;
191 TreeView_GetItem(hTree, &tvItemEx);
192
193 if (!bState)
194 {
195 /* 2- Add the token IF NEEDED */
196 if ((wcslen(tvItemEx.pszText) < MSConfigTokLen) || (_wcsnicmp(tvItemEx.pszText, szMSConfigTok, MSConfigTokLen) != 0))
197 {
198 LPWSTR newLabel = (LPWSTR)MemAlloc(0, (_tcslen(tvItemEx.pszText) + MSConfigTokLen + 1) * sizeof(WCHAR));
199 wcscpy(newLabel, szMSConfigTok);
200 wcscat(newLabel, tvItemEx.pszText);
201 tvItemEx.pszText = newLabel;
202
203 TreeView_SetItem(hTree, &tvItemEx);
204
205 MemFree(newLabel);
206 }
207 }
208 else
209 {
210 /* 2- Remove the token IF NEEDED */
211 if ((wcslen(tvItemEx.pszText) >= MSConfigTokLen) && (_wcsnicmp(tvItemEx.pszText, szMSConfigTok, MSConfigTokLen) == 0))
212 {
213 LPWSTR newLabel = (LPWSTR)MemAlloc(0, (_tcslen(tvItemEx.pszText) - MSConfigTokLen + 1) * sizeof(WCHAR));
214 wcscpy(newLabel, tvItemEx.pszText + MSConfigTokLen);
215 tvItemEx.pszText = newLabel;
216
217 TreeView_SetItem(hTree, &tvItemEx);
218
219 // TODO: if one finds tvItemEx.pszText == L"", one can
220 // directly remove the item (cf. message TVN_ENDLABELEDIT).
221
222 MemFree(newLabel);
223 }
224 }
225 }
226 ////////////////////////
227
228 for (HTREEITEM htiIterator = TreeView_GetChild(hTree, htiItem) ; htiIterator ; htiIterator = TreeView_GetNextSibling(hTree, htiIterator))
229 TreeView_SetBOOLCheck(hTree, htiIterator, bState, FALSE);
230
231 if (bPropagateStateToParent)
232 TreeView_PropagateStateOfItemToParent(hTree, htiItem);
233
234 return;
235 }
236
237 static void
238 LoadIniFile(HWND hTree, LPCWSTR lpszIniFile)
239 {
240 // Ouverture en lecture (sans création de fichier si celui-ci n'esistait pas déjà)
241 // d'un flux en mode texte, avec permission de lecture seule.
242 DWORD dwNumOfChars = ExpandEnvironmentStringsW(lpszIniFile, NULL, 0);
243 LPWSTR lpszFileName = (LPWSTR)MemAlloc(0, dwNumOfChars * sizeof(WCHAR));
244 ExpandEnvironmentStringsW(lpszIniFile, lpszFileName, dwNumOfChars);
245
246 FILE* ini_file = _wfsopen(lpszFileName, L"rt", _SH_DENYWR); // r+t <-- read write text ; rt <-- read text
247 MemFree(lpszFileName);
248
249 if (!ini_file)
250 return; // error
251
252 WCHAR szLine[MAX_VALUE_NAME] = L"";
253 TVINSERTSTRUCT tvis;
254 HTREEITEM hParent = TVI_ROOT;
255 BOOL bIsSection = FALSE;
256 LPWSTR lpsz1 = NULL;
257 LPWSTR lpsz2 = NULL;
258
259 while (!feof(ini_file) && fgetws(szLine, _ARRAYSIZE(szLine), ini_file))
260 {
261 /* Skip hypothetical starting spaces or newline characters */
262 lpsz1 = szLine;
263 while (*lpsz1 == L' ' || *lpsz1 == L'\r' || *lpsz1 == L'\n')
264 ++lpsz1;
265
266 /* Skip empty lines */
267 if (!*lpsz1)
268 continue;
269
270 /* Find the last newline character (if exists) and replace it by the NULL terminator */
271 lpsz2 = lpsz1;
272 while (*lpsz2)
273 {
274 if (*lpsz2 == L'\r' || *lpsz2 == L'\n')
275 {
276 *lpsz2 = L'\0';
277 break;
278 }
279
280 ++lpsz2;
281 }
282
283 /* Check for new sections. They should be parent of ROOT. */
284 if (*lpsz1 == L'[')
285 {
286 bIsSection = TRUE;
287 hParent = TVI_ROOT;
288 }
289
290 SecureZeroMemory(&tvis, sizeof(tvis));
291 tvis.hParent = hParent;
292 tvis.hInsertAfter = TVI_LAST;
293 tvis.itemex.mask = TVIF_TEXT; // TVIF_HANDLE | TVIF_TEXT;
294 tvis.itemex.pszText = lpsz1;
295 tvis.itemex.hItem = TreeView_InsertItem(hTree, &tvis);
296
297 /* The special ";msconfig " token disables the line */
298 if (!bIsSection && _wcsnicmp(lpsz1, szMSConfigTok, MSConfigTokLen) == 0)
299 TreeView_SetBOOLCheck(hTree, tvis.itemex.hItem, FALSE, TRUE);
300 else
301 TreeView_SetBOOLCheck(hTree, tvis.itemex.hItem, TRUE, TRUE);
302
303 /*
304 * Now, all the elements will be children of this section,
305 * until we create a new one.
306 */
307 if (bIsSection)
308 {
309 bIsSection = FALSE;
310 hParent = tvis.itemex.hItem;
311 }
312 }
313
314 fclose(ini_file);
315 return;
316
317 //// Test code for the TreeView ////
318 /*
319 HTREEITEM hItem[16];
320
321 hItem[0] = InsertItem(hTree, _T("B"),TVI_ROOT,TVI_LAST);
322 hItem[1] = InsertItem(hTree, _T("C"),TVI_ROOT,TVI_LAST);
323 hItem[2] = InsertItem(hTree, _T("A"),TVI_ROOT,TVI_LAST);
324 hItem[3] = InsertItem(hTree, _T("D"),TVI_ROOT,TVI_LAST);
325 hItem[4] = InsertItem(hTree, _T("D-1"),hItem[3] ,TVI_LAST);
326 hItem[5] = InsertItem(hTree, _T("D-2"),hItem[3] ,TVI_LAST);
327 hItem[9] = InsertItem(hTree, _T("D-2-1"),hItem[5],TVI_LAST);
328 hItem[6] = InsertItem(hTree, _T("D-3"),hItem[3] ,TVI_LAST);
329 hItem[7] = InsertItem(hTree, _T("D-3-1"),hItem[6],TVI_LAST);
330 hItem[10] = InsertItem(hTree, _T("D-3-1-1"),hItem[7],TVI_LAST);
331 hItem[11] = InsertItem(hTree, _T("D-3-1-2"),hItem[7],TVI_LAST);
332 hItem[12] = InsertItem(hTree, _T("D-3-1-3"),hItem[7],TVI_LAST);
333 hItem[13] = InsertItem(hTree, _T("D-3-1-4"),hItem[7],TVI_LAST);
334 hItem[14] = InsertItem(hTree, _T("D-3-1-5"),hItem[7],TVI_LAST);
335 hItem[15] = InsertItem(hTree, _T("D-3-1-6"),hItem[7],TVI_LAST);
336 hItem[13] = InsertItem(hTree, _T("E"),TVI_ROOT,TVI_LAST);
337 */
338 ////////////////////////////////////
339
340 }
341
342 static void
343 WriteIniFile(HWND hTree, LPCWSTR lpszIniFile)
344 {
345 // Ouverture en écriture (avec création de fichier si celui-ci n'esistait pas déjà)
346 // d'un flux en mode texte, avec permission de lecture seule.
347 #if 0
348 DWORD dwNumOfChars = ExpandEnvironmentStringsW(lpszIniFile, NULL, 0);
349 LPWSTR lpszFileName = MemAlloc(0, dwNumOfChars * sizeof(WCHAR));
350 ExpandEnvironmentStringsW(lpszIniFile, lpszFileName, dwNumOfChars);
351 #else
352 // HACK: delete these following lines when the program will be ready.
353 DWORD dwNumOfChars = ExpandEnvironmentStringsW(lpszIniFile, NULL, 0) + 11;
354 LPWSTR lpszFileName = (LPWSTR)MemAlloc(0, dwNumOfChars * sizeof(WCHAR));
355 ExpandEnvironmentStringsW(lpszIniFile, lpszFileName, dwNumOfChars);
356 wcscat(lpszFileName, L"__tests.ini");
357 // END HACK.
358 #endif
359
360 FILE* ini_file = _wfsopen(lpszFileName, L"wt", _SH_DENYRW); // w+t <-- write read text ; wt <-- write text
361 MemFree(lpszFileName);
362
363 if (!ini_file)
364 return; // error
365
366
367 TVITEMEXW tvItemEx;
368 WCHAR label[MAX_VALUE_NAME] = L"";
369 // WCHAR szLine[MAX_VALUE_NAME] = L"";
370
371 // for (HTREEITEM htiIterator = TreeView_GetRoot(hTree) ; htiIterator ; htiIterator = TreeView_GetNextSibling(hTree, htiIterator))
372 for (HTREEITEM htiIterator = TreeView_GetFirst(hTree) ; htiIterator ; htiIterator = TreeView_GetNext(hTree, htiIterator))
373 {
374 SecureZeroMemory(&tvItemEx, sizeof(tvItemEx));
375
376 tvItemEx.hItem = htiIterator; // Handle of the item to be retrieved.
377 tvItemEx.mask = TVIF_HANDLE | TVIF_TEXT;
378 tvItemEx.pszText = label;
379 tvItemEx.cchTextMax = MAX_VALUE_NAME;
380 TreeView_GetItem(hTree, &tvItemEx);
381
382 // Write into the file.
383 wcscat(label, L"\n");
384 fputws(label, ini_file);
385 }
386
387 fclose(ini_file);
388 return;
389 }
390
391 static void
392 Update_Btn_States(HWND hDlg)
393 {
394 HWND hTree = GetDlgItem(hDlg, IDC_SYSTEM_TREE);
395
396 HTREEITEM hti = TreeView_GetSelection(hTree);
397 HTREEITEM htiPrev = TreeView_GetPrevSibling(hTree, hti);
398 HTREEITEM htiNext = TreeView_GetNextSibling(hTree, hti);
399
400 //
401 // "Up" / "Down" buttons.
402 //
403 if (htiPrev)
404 EnableWindow(GetDlgItem(hDlg, IDC_BTN_SYSTEM_UP), TRUE);
405 else
406 EnableWindow(GetDlgItem(hDlg, IDC_BTN_SYSTEM_UP), FALSE);
407
408 if (htiNext)
409 EnableWindow(GetDlgItem(hDlg, IDC_BTN_SYSTEM_DOWN), TRUE);
410 else
411 EnableWindow(GetDlgItem(hDlg, IDC_BTN_SYSTEM_DOWN), FALSE);
412
413 //
414 // "Enable" / "Disable" buttons.
415 //
416 UINT uCheckState = TreeView_GetCheckState(hTree, hti);
417 if (uCheckState == 0)
418 {
419 EnableWindow(GetDlgItem(hDlg, IDC_BTN_SYSTEM_ENABLE) , TRUE);
420 EnableWindow(GetDlgItem(hDlg, IDC_BTN_SYSTEM_DISABLE), FALSE);
421 }
422 else if (uCheckState == 1)
423 {
424 EnableWindow(GetDlgItem(hDlg, IDC_BTN_SYSTEM_ENABLE) , FALSE);
425 EnableWindow(GetDlgItem(hDlg, IDC_BTN_SYSTEM_DISABLE), TRUE);
426 }
427 else if (uCheckState == 2)
428 {
429 EnableWindow(GetDlgItem(hDlg, IDC_BTN_SYSTEM_ENABLE) , TRUE);
430 EnableWindow(GetDlgItem(hDlg, IDC_BTN_SYSTEM_DISABLE), TRUE);
431 }
432 else
433 {
434 EnableWindow(GetDlgItem(hDlg, IDC_BTN_SYSTEM_ENABLE) , FALSE);
435 EnableWindow(GetDlgItem(hDlg, IDC_BTN_SYSTEM_DISABLE), FALSE);
436 }
437
438 //
439 // "Enable all" / "Disable all" buttons.
440 //
441 UINT uRootCheckState = TreeView_GetRealSubtreeState(hTree, TVI_ROOT);
442 if (uRootCheckState == 0)
443 {
444 EnableWindow(GetDlgItem(hDlg, IDC_BTN_SYSTEM_ENABLE_ALL) , TRUE);
445 EnableWindow(GetDlgItem(hDlg, IDC_BTN_SYSTEM_DISABLE_ALL), FALSE);
446 }
447 else if (uRootCheckState == 1)
448 {
449 EnableWindow(GetDlgItem(hDlg, IDC_BTN_SYSTEM_ENABLE_ALL) , FALSE);
450 EnableWindow(GetDlgItem(hDlg, IDC_BTN_SYSTEM_DISABLE_ALL), TRUE);
451 }
452 else if (uRootCheckState == 2)
453 {
454 EnableWindow(GetDlgItem(hDlg, IDC_BTN_SYSTEM_ENABLE_ALL) , TRUE);
455 EnableWindow(GetDlgItem(hDlg, IDC_BTN_SYSTEM_DISABLE_ALL), TRUE);
456 }
457 else
458 {
459 EnableWindow(GetDlgItem(hDlg, IDC_BTN_SYSTEM_ENABLE_ALL) , FALSE);
460 EnableWindow(GetDlgItem(hDlg, IDC_BTN_SYSTEM_DISABLE_ALL), FALSE);
461 }
462
463 //
464 // "Search" / "Edit" / "Delete" buttons.
465 //
466 if (TreeView_GetRoot(hTree))
467 {
468 EnableWindow(GetDlgItem(hDlg, IDC_BTN_SYSTEM_FIND) , TRUE);
469 EnableWindow(GetDlgItem(hDlg, IDC_BTN_SYSTEM_EDIT) , TRUE);
470 EnableWindow(GetDlgItem(hDlg, IDC_BTN_SYSTEM_DELETE), TRUE);
471 }
472 else
473 {
474 EnableWindow(GetDlgItem(hDlg, IDC_BTN_SYSTEM_FIND) , FALSE);
475 EnableWindow(GetDlgItem(hDlg, IDC_BTN_SYSTEM_EDIT) , FALSE);
476 EnableWindow(GetDlgItem(hDlg, IDC_BTN_SYSTEM_DELETE), FALSE);
477 }
478
479 return;
480 }
481
482
483 INT_PTR
484 CommonWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
485 {
486 UNREFERENCED_PARAMETER(lParam);
487 UNREFERENCED_PARAMETER(wParam);
488
489 switch (message)
490 {
491 case WM_INITDIALOG:
492 {
493 HWND hSystemTree = GetDlgItem(hDlg, IDC_SYSTEM_TREE);
494
495 //
496 // Initialize the styles.
497 //
498 TreeView_Set3StateCheck(hSystemTree);
499 SetWindowTheme(hSystemTree, L"Explorer", NULL);
500
501 TreeView_SetIndent(hSystemTree, TreeView_GetIndent(hSystemTree) + 2);
502
503 /* Load data */
504 LoadIniFile(hSystemTree, (LPCWSTR)((LPPROPSHEETPAGE)lParam)->lParam);
505
506 /* Select the first item */
507 TreeView_SelectItem(hSystemTree, TreeView_GetRoot(hSystemTree)); // Is it really necessary?
508 SetFocus(hSystemTree);
509
510 Update_Btn_States(hDlg);
511
512 return TRUE;
513 }
514
515 case WM_DESTROY:
516 {
517 TreeView_Cleanup(GetDlgItem(hDlg, IDC_SYSTEM_TREE));
518 return FALSE;
519 }
520
521 case WM_COMMAND:
522 {
523 HWND hSystemTree = GetDlgItem(hDlg, IDC_SYSTEM_TREE);
524
525 switch (LOWORD(wParam))
526 {
527 case IDC_BTN_SYSTEM_UP:
528 {
529 TreeView_UpItem(hSystemTree, TreeView_GetSelection(hSystemTree));
530 PropSheet_Changed(GetParent(hDlg), hDlg);
531 return TRUE;
532 }
533
534 case IDC_BTN_SYSTEM_DOWN:
535 {
536 TreeView_DownItem(hSystemTree, TreeView_GetSelection(hSystemTree));
537 PropSheet_Changed(GetParent(hDlg), hDlg);
538 return TRUE;
539 }
540
541 case IDC_BTN_SYSTEM_ENABLE:
542 {
543 HTREEITEM hItem = TreeView_GetSelection(hSystemTree);
544 TreeView_SetBOOLCheck(hSystemTree, hItem, TRUE, TRUE);
545 TreeView_SelectItem(hSystemTree, hItem);
546 Update_Btn_States(hDlg);
547
548 PropSheet_Changed(GetParent(hDlg), hDlg);
549
550 return TRUE;
551 }
552
553 case IDC_BTN_SYSTEM_ENABLE_ALL:
554 {
555 for (HTREEITEM htiIterator = TreeView_GetRoot(hSystemTree) ; htiIterator ; htiIterator = TreeView_GetNextSibling(hSystemTree, htiIterator))
556 TreeView_SetBOOLCheck(hSystemTree, htiIterator, TRUE, TRUE);
557
558 Update_Btn_States(hDlg);
559
560 PropSheet_Changed(GetParent(hDlg), hDlg);
561
562 return TRUE;
563 }
564
565 case IDC_BTN_SYSTEM_DISABLE:
566 {
567 HTREEITEM hItem = TreeView_GetSelection(hSystemTree);
568 TreeView_SetBOOLCheck(hSystemTree, hItem, FALSE, TRUE);
569 TreeView_SelectItem(hSystemTree, hItem);
570
571 Update_Btn_States(hDlg);
572
573 PropSheet_Changed(GetParent(hDlg), hDlg);
574
575 return TRUE;
576 }
577
578 case IDC_BTN_SYSTEM_DISABLE_ALL:
579 {
580 for (HTREEITEM htiIterator = TreeView_GetRoot(hSystemTree) ; htiIterator ; htiIterator = TreeView_GetNextSibling(hSystemTree, htiIterator))
581 TreeView_SetBOOLCheck(hSystemTree, htiIterator, FALSE, TRUE);
582
583 Update_Btn_States(hDlg);
584
585 PropSheet_Changed(GetParent(hDlg), hDlg);
586
587 return TRUE;
588 }
589
590 case IDC_BTN_SYSTEM_FIND:
591 {
592 DialogBoxParamW(hInst, MAKEINTRESOURCEW(IDD_FIND_DIALOG), hDlg /* hMainWnd */, FindDialogWndProc, (LPARAM)hSystemTree);
593 return TRUE;
594 }
595
596 case IDC_BTN_SYSTEM_NEW:
597 {
598 HTREEITEM hInsertAfter = TreeView_GetSelection(hSystemTree);
599 HTREEITEM hNewItem = InsertItem(hSystemTree, L"", TreeView_GetParent(hSystemTree, hInsertAfter), hInsertAfter);
600 TreeView_EditLabel(hSystemTree, hNewItem);
601 TreeView_SelectItem(hSystemTree, hNewItem);
602
603 PropSheet_Changed(GetParent(hDlg), hDlg);
604
605 return TRUE;
606 }
607
608 case IDC_BTN_SYSTEM_EDIT:
609 {
610 TreeView_EditLabel(hSystemTree, TreeView_GetSelection(hSystemTree));
611 return TRUE;
612 }
613
614 case IDC_BTN_SYSTEM_DELETE:
615 {
616 TreeView_DeleteItem(hSystemTree, TreeView_GetSelection(hSystemTree));
617 Update_Btn_States(hDlg);
618 PropSheet_Changed(GetParent(hDlg), hDlg);
619 return TRUE;
620 }
621
622 default:
623 return FALSE;
624 }
625 // return FALSE;
626 }
627
628 case UM_CHECKSTATECHANGE:
629 {
630 HWND hSystemTree = GetDlgItem(hDlg, IDC_SYSTEM_TREE);
631
632 /* Retrieve the new checked state of the item and handle the notification */
633 HTREEITEM hItemChanged = (HTREEITEM)lParam;
634
635 //
636 // State before | State after
637 // -------------------------------
638 // 0 (unchecked) | 1 (checked)
639 // 1 (checked) | 0 (unchecked)
640 // 2 (grayed) | 1 (checked) --> this case corresponds to the former
641 // | with 0 == 2 mod 2.
642 //
643 UINT uiCheckState = TreeView_GetCheckState(hSystemTree, hItemChanged) % 2;
644 TreeView_SetBOOLCheck(hSystemTree, hItemChanged, uiCheckState ? FALSE : TRUE, TRUE);
645 TreeView_SelectItem(hSystemTree, hItemChanged);
646 Update_Btn_States(hDlg);
647
648 PropSheet_Changed(GetParent(hDlg), hDlg);
649
650 return TRUE;
651 }
652
653 case WM_NOTIFY:
654 {
655 if (((LPNMHDR)lParam)->idFrom == IDC_SYSTEM_TREE)
656 {
657 switch (((LPNMHDR)lParam)->code)
658 {
659 case NM_CLICK:
660 {
661 HWND hSystemTree = GetDlgItem(hDlg, IDC_SYSTEM_TREE);
662
663 DWORD dwpos = GetMessagePos();
664 TVHITTESTINFO ht = {};
665 ht.pt.x = GET_X_LPARAM(dwpos);
666 ht.pt.y = GET_Y_LPARAM(dwpos);
667 MapWindowPoints(HWND_DESKTOP /*NULL*/, hSystemTree, &ht.pt, 1);
668
669 TreeView_HitTest(hSystemTree, &ht);
670
671 if (TVHT_ONITEMSTATEICON & ht.flags)
672 {
673 PostMessage(hDlg, UM_CHECKSTATECHANGE, 0, (LPARAM)ht.hItem);
674
675 // Disable default behaviour. Needed for the UM_CHECKSTATECHANGE
676 // custom notification to work as expected.
677 SetWindowLongPtr(hDlg, DWLP_MSGRESULT, TRUE);
678 }
679 /*
680 else
681 SetWindowLongPtr(hDlg, DWLP_MSGRESULT, FALSE);
682 */
683
684 return TRUE;
685 }
686
687 case TVN_KEYDOWN:
688 {
689 if (((LPNMTVKEYDOWN)lParam)->wVKey == VK_SPACE)
690 {
691 HWND hSystemTree = GetDlgItem(hDlg, IDC_SYSTEM_TREE);
692
693 HTREEITEM hti = TreeView_GetSelection(hSystemTree);
694
695 // Hack the tree item state. This is needed because whether or not
696 // TRUE is being returned, the default implementation of SysTreeView32
697 // is always being processed for a key down !
698 if (GetWindowLongPtr(hSystemTree, GWL_STYLE) & TVS_CHECKBOXES)
699 {
700 TreeView_SetItemState(hSystemTree, hti, INDEXTOSTATEIMAGEMASK(TreeView_GetCheckState(hSystemTree, hti)), TVIS_STATEIMAGEMASK);
701 }
702
703 PostMessage(hDlg, UM_CHECKSTATECHANGE, 0, (LPARAM)hti);
704
705 // Disable default behaviour. Needed for the UM_CHECKSTATECHANGE
706 // custom notification to work as expected.
707 SetWindowLongPtr(hDlg, DWLP_MSGRESULT, TRUE);
708 }
709
710 return TRUE;
711 }
712
713 case TVN_ENDLABELEDIT:
714 {
715 HWND hSystemTree = GetDlgItem(hDlg, IDC_SYSTEM_TREE);
716
717 /*
718 * Ehh yes, we have to deal with a "dialog proc", which is quite different from a "window proc":
719 *
720 * (excerpt from: MSDN library http://msdn.microsoft.com/en-us/library/ms645469(VS.85).aspx)
721 *
722 * Return Value
723 * ============
724 * INT_PTR
725 *
726 * Typically, the dialog box procedure should return TRUE if it processed the message, and FALSE if it did not.
727 * If the dialog box procedure returns FALSE, the dialog manager performs the default dialog operation in response
728 * to the message.
729 *
730 * If the dialog box procedure processes a message that requires a specific return value, the dialog box procedure
731 * should set the desired return value by calling SetWindowLong(hwndDlg, DWL_MSGRESULT, lResult) immediately before
732 * returning TRUE. Note that you must call SetWindowLong immediately before returning TRUE; doing so earlier may result
733 * in the DWL_MSGRESULT value being overwritten by a nested dialog box message.
734 *
735 * [...]
736 *
737 * Remarks
738 * =======
739 * You should use the dialog box procedure only if you use the dialog box class for the dialog box. This is the default
740 * class and is used when no explicit class is specified in the dialog box template. Although the dialog box procedure
741 * is similar to a window procedure, it must not call the DefWindowProc function to process unwanted messages. Unwanted
742 * messages are processed internally by the dialog box window procedure.
743 *
744 */
745
746 // A arranger un peu ???? Certainement.
747 TVITEMW truc = ((LPNMTVDISPINFO)lParam)->item;
748 if (truc.pszText)
749 {
750 if (!*truc.pszText)
751 TreeView_DeleteItem(hSystemTree, truc.hItem);
752
753 PropSheet_Changed(GetParent(hDlg), hDlg);
754
755 SetWindowLongPtr(hDlg, DWLP_MSGRESULT, TRUE);
756 }
757 else
758 SetWindowLongPtr(hDlg, DWLP_MSGRESULT, FALSE);
759
760 Update_Btn_States(hDlg);
761 return TRUE;
762 }
763
764 case TVN_SELCHANGED:
765 Update_Btn_States(hDlg);
766 return TRUE;
767
768 default:
769 return FALSE;
770 }
771 }
772 else
773 {
774 switch (((LPNMHDR)lParam)->code)
775 {
776 case PSN_APPLY:
777 {
778 // TODO: Enum the items.
779 // HWND hSystemTree = GetDlgItem(hDlg, IDC_SYSTEM_TREE);
780 //
781 PropSheet_CancelToClose(GetParent(hDlg));
782
783 /* TODO: see :
784 *
785 * dll/win32/devmgr/advprop.c: PropSheet_RebootSystem(hwndDlg);
786 * include/psdk/prsht.h:#define PropSheet_RebootSystem(d) SendMessage(d,PSM_REBOOTSYSTEM,0,0)
787 *
788 * dll/shellext/deskadp/deskadp.c: PropSheet_RestartWindows(GetParent(This->hwndDlg));
789 * dll/shellext/deskmon/deskmon.c: PropSheet_RestartWindows(GetParent(This->hwndDlg));
790 * include/psdk/prsht.h:#define PropSheet_RestartWindows(d) SendMessage(d,PSM_RESTARTWINDOWS,0,0)
791 *
792 * for their usage.
793 */
794 PropSheet_RebootSystem(GetParent(hDlg));
795 //PropSheet_RestartWindows(GetParent(hDlg));
796
797 WriteIniFile(GetDlgItem(hDlg, IDC_SYSTEM_TREE), (LPCWSTR)wParam);
798
799 // Since there are nothing to modify, applying modifications
800 // cannot return any error.
801 SetWindowLongPtr(hDlg, DWLP_MSGRESULT, PSNRET_NOERROR);
802 //PropSheet_UnChanged(GetParent(hDlg) /*hMainWnd*/, hDlg);
803 return TRUE;
804 }
805
806 case PSN_HELP:
807 {
808 MessageBox(hDlg, _T("Help not implemented yet!"), _T("Help"), MB_ICONINFORMATION | MB_OK);
809 return TRUE;
810 }
811
812 case PSN_KILLACTIVE: // Is going to lose activation.
813 {
814 // Changes are always valid of course.
815 SetWindowLongPtr(hDlg, DWLP_MSGRESULT, FALSE);
816 return TRUE;
817 }
818
819 case PSN_QUERYCANCEL:
820 {
821 // Allows cancellation since there are nothing to cancel...
822 SetWindowLongPtr(hDlg, DWLP_MSGRESULT, FALSE);
823 return TRUE;
824 }
825
826 case PSN_QUERYINITIALFOCUS:
827 {
828 HWND hSystemTree = GetDlgItem(hDlg, IDC_SYSTEM_TREE);
829
830 // Give the focus on and select the first item.
831 ListView_SetItemState(hSystemTree, 0, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED);
832
833 SetWindowLongPtr(hDlg, DWLP_MSGRESULT, (LONG_PTR)hSystemTree);
834 return TRUE;
835 }
836
837 //
838 // DO NOT TOUCH THESE NEXT MESSAGES, THEY ARE OK LIKE THIS...
839 //
840 case PSN_RESET: // Perform final cleaning, called before WM_DESTROY.
841 return TRUE;
842
843 case PSN_SETACTIVE: // Is going to gain activation.
844 {
845 SetWindowLongPtr(hDlg, DWLP_MSGRESULT, 0);
846 return TRUE;
847 }
848
849 default:
850 break;
851 }
852 }
853
854 return FALSE;
855 }
856
857 default:
858 return FALSE;
859 }
860
861 // return FALSE;
862 }
863
864
865 extern "C" {
866
867 INT_PTR CALLBACK
868 SystemPageWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
869 {
870 static LPCWSTR lpszIniFile = NULL;
871
872 if (message == WM_INITDIALOG)
873 lpszIniFile = (LPCWSTR)((LPPROPSHEETPAGE)lParam)->lParam;
874
875 if ( (message == WM_NOTIFY) && (((LPNMHDR)lParam)->code == PSN_APPLY) )
876 wParam = (WPARAM)lpszIniFile;
877
878 return CommonWndProc(hDlg, message, wParam, lParam);
879 }
880
881 INT_PTR CALLBACK
882 WinPageWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
883 {
884 static LPCWSTR lpszIniFile = NULL;
885
886 if (message == WM_INITDIALOG)
887 lpszIniFile = (LPCWSTR)((LPPROPSHEETPAGE)lParam)->lParam;
888
889 if ( (message == WM_NOTIFY) && (((LPNMHDR)lParam)->code == PSN_APPLY) )
890 wParam = (WPARAM)lpszIniFile;
891
892 return CommonWndProc(hDlg, message, wParam, lParam);
893 }
894
895 }