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 }
896