1 /*
2  * PROJECT:     ReactOS Applications
3  * LICENSE:     LGPL - See COPYING in the top level directory
4  * FILE:        base/applications/msconfig_new/msconfig.c
5  * PURPOSE:     MSConfig main dialog
6  * COPYRIGHT:   Copyright 2005-2006 Christoph von Wittich <Christoph@ApiViewer.de>
7  */
8 
9 #include "precomp.h"
10 #include "fileutils.h"
11 #include "utils.h"
12 
13 #include "generalpage.h"
14 #include "systempage.h"
15 #include "freeldrpage.h"
16 #include "srvpage.h"
17 // #include "startuppage.h"
18 #include "toolspage.h"
19 
20 /* Allow only for a single instance of MSConfig */
21 #ifdef _MSC_VER
22     #pragma data_seg("MSConfigInstance")
23     HWND hSingleWnd = NULL;
24     #pragma data_seg()
25     #pragma comment(linker, "/SECTION:MSConfigInstance,RWS")
26 #else
27     HWND hSingleWnd __attribute__((section ("MSConfigInstance"), shared)) = NULL;
28 #endif
29 
30 /* Defaults for ReactOS */
31 BOOL bIsWindows = FALSE;
32 BOOL bIsPreVistaOSVersion = TRUE;
33 
34 /* Language-independent Vendor strings */
35 const LPCWSTR IDS_REACTOS   = L"ReactOS";
36 const LPCWSTR IDS_MICROSOFT = L"Microsoft";
37 const LPCWSTR IDS_WINDOWS   = L"Windows";
38 
39 HINSTANCE hInst = NULL;
40 LPWSTR szAppName = NULL;
41 HWND hMainWnd;                   /* Main Window */
42 
43 HWND  hTabWnd;                   /* Tab Control Window */
44 HICON hIcon = NULL, hIconSm = NULL;
45 WNDPROC wpOrigEditProc = NULL;
46 
47 
48 /* About Box dialog */
49 INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
50 {
51     UNREFERENCED_PARAMETER(lParam);
52     switch (message)
53     {
54         case WM_INITDIALOG:
55             return (INT_PTR)TRUE;
56 
57         case WM_COMMAND:
58             if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
59             {
60                 EndDialog(hDlg, LOWORD(wParam));
61                 return (INT_PTR)TRUE;
62             }
63             break;
64     }
65     return (INT_PTR)FALSE;
66 }
67 
68 
69 /* Message handler for dialog box */
70 LRESULT CALLBACK MainWndProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
71 {
72     switch (uMessage)
73     {
74         case WM_SYSCOMMAND:
75         {
76             switch (LOWORD(wParam) /*GET_WM_COMMAND_ID(wParam, lParam)*/)
77             {
78                 case IDM_ABOUT:
79                     DialogBoxW(hInst, MAKEINTRESOURCEW(IDD_ABOUTBOX), hWnd, About);
80                     // break;
81                     return TRUE;
82             }
83 
84             // break;
85             return FALSE;
86         }
87 
88         case WM_COMMAND:
89         {
90             switch (LOWORD(wParam) /*GET_WM_COMMAND_ID(wParam, lParam)*/)
91             {
92                 case IDM_ABOUT:
93                     DialogBoxW(hInst, MAKEINTRESOURCEW(IDD_ABOUTBOX), hWnd, About);
94                     // break;
95                     return TRUE;
96             }
97 
98             break;
99             // return FALSE;
100         }
101 
102         case WM_DESTROY:
103         {
104             if (wpOrigEditProc)
105                 SetWindowLongPtr(hWnd, DWLP_DLGPROC, (LONG_PTR)wpOrigEditProc);
106 
107             if (hIcon)   DestroyIcon(hIcon);
108             if (hIconSm) DestroyIcon(hIconSm);
109         }
110 
111         default:
112             break;
113     }
114 
115     /* Return */
116     if (wpOrigEditProc)
117         return CallWindowProc(wpOrigEditProc, hWnd, uMessage, wParam, lParam);
118     else
119         return FALSE;
120 }
121 
122 
123 #include <pshpack1.h>
124 typedef struct DLGTEMPLATEEX
125 {
126     WORD dlgVer;
127     WORD signature;
128     DWORD helpID;
129     DWORD exStyle;
130     DWORD style;
131     WORD cDlgItems;
132     short x;
133     short y;
134     short cx;
135     short cy;
136 } DLGTEMPLATEEX, *LPDLGTEMPLATEEX;
137 #include <poppack.h>
138 
139 int CALLBACK PropSheetCallback(HWND hDlg, UINT message, LPARAM lParam)
140 {
141     switch (message)
142     {
143         case PSCB_PRECREATE:
144         {
145             LPDLGTEMPLATE   dlgTemplate   =   (LPDLGTEMPLATE)lParam;
146             LPDLGTEMPLATEEX dlgTemplateEx = (LPDLGTEMPLATEEX)lParam;
147 
148             // MFC : DS_MODALFRAME | DS_3DLOOK | DS_CONTEXTHELP | DS_SETFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION;
149             DWORD style   = DS_SHELLFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU;
150                          // DS_SHELLFONT | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME;
151             DWORD exStyle = WS_EX_CONTROLPARENT | WS_EX_APPWINDOW;
152 
153             /* Hide the dialog by default; we will center it on screen later, and then show it */
154             style &= ~WS_VISIBLE;
155 
156             /* Set the styles of the property sheet dialog */
157             if (dlgTemplateEx->signature == 0xFFFF)
158             {
159                 dlgTemplateEx->style   = style;
160                 dlgTemplateEx->exStyle = exStyle;
161             }
162             else
163             {
164                 dlgTemplate->style           = style;
165                 dlgTemplate->dwExtendedStyle = exStyle;
166             }
167 
168             break;
169         }
170 
171         case PSCB_INITIALIZED:
172         {
173             /* Customize the window's system menu, add items before the "Close" item */
174             LPWSTR szMenuString;
175             HMENU hSysMenu = GetSystemMenu(hDlg, FALSE);
176             assert(hSysMenu);
177 
178             szMenuString = LoadResourceString(hInst, IDS_ABOUT);
179             if (szMenuString)
180             {
181                 /* "About" menu */
182                 InsertMenuW(hSysMenu, SC_CLOSE, MF_BYCOMMAND | MF_ENABLED | MF_STRING, IDM_ABOUT, szMenuString);
183                 /* Separator */
184                 InsertMenuW(hSysMenu, SC_CLOSE, MF_BYCOMMAND | MF_SEPARATOR          , 0 , NULL);
185 
186                 MemFree(szMenuString);
187             }
188             DrawMenuBar(hDlg);
189 
190             /* Set the dialog icons */
191             hIcon   = (HICON)LoadImageW(hInst, MAKEINTRESOURCEW(IDI_APPICON), IMAGE_ICON, 0, 0, LR_SHARED | LR_DEFAULTSIZE);
192             hIconSm = (HICON)CopyImage(hIcon, IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_COPYFROMRESOURCE);
193             SendMessageW(hDlg, WM_SETICON, ICON_BIG,   (LPARAM)hIcon);
194             SendMessageW(hDlg, WM_SETICON, ICON_SMALL, (LPARAM)hIconSm);
195 
196             /* Sub-class the property sheet window procedure */
197             wpOrigEditProc = (WNDPROC)SetWindowLongPtr(hDlg, DWLP_DLGPROC, (LONG_PTR)MainWndProc);
198 
199             break;
200         }
201 
202         default:
203             break;
204     }
205 
206     return FALSE;
207 }
208 
209 HWND CreatePropSheet(HINSTANCE hInstance, HWND hwndOwner, LPCTSTR lpszTitle)
210 {
211     HWND hPropSheet;
212     PROPSHEETHEADERW psh;
213     PROPSHEETPAGEW   psp[7];
214     unsigned int nPages = 0;
215 
216     /* Header */
217     psh.dwSize      = sizeof(psh);
218     psh.dwFlags     = PSH_PROPSHEETPAGE | PSH_MODELESS | /*PSH_USEICONID |*/ PSH_HASHELP | /*PSH_NOCONTEXTHELP |*/ PSH_USECALLBACK;
219     psh.hInstance   = hInstance;
220     psh.hwndParent  = hwndOwner;
221     // psh.pszIcon     = MAKEINTRESOURCEW(IDI_APPICON); // Disabled because it only sets the small icon; the big icon is a stretched version of the small one.
222     psh.pszCaption  = lpszTitle;
223     psh.nStartPage  = 0;
224     psh.ppsp        = psp;
225     psh.pfnCallback = PropSheetCallback;
226 
227     /* General page */
228     psp[nPages].dwSize      = sizeof(PROPSHEETPAGEW);
229     psp[nPages].dwFlags     = PSP_HASHELP;
230     psp[nPages].hInstance   = hInstance;
231     psp[nPages].pszTemplate = MAKEINTRESOURCEW(IDD_GENERAL_PAGE);
232     psp[nPages].pfnDlgProc  = GeneralPageWndProc;
233     ++nPages;
234 
235     // if (bIsPreVistaOSVersion)
236     {
237         /* SYSTEM.INI page */
238         if (MyFileExists(lpszSystemIni, NULL))
239         {
240             psp[nPages].dwSize      = sizeof(PROPSHEETPAGEW);
241             psp[nPages].dwFlags     = PSP_HASHELP | PSP_USETITLE;
242             psp[nPages].hInstance   = hInstance;
243             psp[nPages].pszTitle    = MAKEINTRESOURCEW(IDS_TAB_SYSTEM);
244             psp[nPages].pszTemplate = MAKEINTRESOURCEW(IDD_SYSTEM_PAGE);
245             psp[nPages].pfnDlgProc  = SystemPageWndProc;
246             psp[nPages].lParam      = (LPARAM)lpszSystemIni;
247             ++nPages;
248 
249             BackupIniFile(lpszSystemIni);
250         }
251 
252         /* WIN.INI page */
253         if (MyFileExists(lpszWinIni, NULL))
254         {
255             psp[nPages].dwSize      = sizeof(PROPSHEETPAGEW);
256             psp[nPages].dwFlags     = PSP_HASHELP | PSP_USETITLE;
257             psp[nPages].hInstance   = hInstance;
258             psp[nPages].pszTitle    = MAKEINTRESOURCEW(IDS_TAB_WIN);
259             psp[nPages].pszTemplate = MAKEINTRESOURCEW(IDD_SYSTEM_PAGE);
260             psp[nPages].pfnDlgProc  = WinPageWndProc;
261             psp[nPages].lParam      = (LPARAM)lpszWinIni;
262             ++nPages;
263 
264             BackupIniFile(lpszWinIni);
265         }
266     }
267 
268     /* FreeLdr page */
269     // TODO: Program the interface for Vista: "light" BCD editor...
270     if (!bIsWindows || (bIsWindows && bIsPreVistaOSVersion))
271     {
272         LPCWSTR lpszLoaderIniFile = NULL;
273         DWORD   dwTabNameId       = 0;
274         if (bIsWindows)
275         {
276             lpszLoaderIniFile = lpszBootIni;
277             dwTabNameId       = IDS_TAB_BOOT;
278         }
279         else
280         {
281             lpszLoaderIniFile = lpszFreeLdrIni;
282             dwTabNameId       = IDS_TAB_FREELDR;
283         }
284 
285         if (MyFileExists(lpszLoaderIniFile, NULL))
286         {
287             psp[nPages].dwSize      = sizeof(PROPSHEETPAGEW);
288             psp[nPages].dwFlags     = PSP_HASHELP | PSP_USETITLE;
289             psp[nPages].hInstance   = hInstance;
290             psp[nPages].pszTitle    = MAKEINTRESOURCEW(dwTabNameId);
291             psp[nPages].pszTemplate = MAKEINTRESOURCEW(IDD_FREELDR_PAGE);
292             psp[nPages].pfnDlgProc  = FreeLdrPageWndProc;
293             psp[nPages].lParam      = (LPARAM)lpszLoaderIniFile;
294             ++nPages;
295 
296             BackupIniFile(lpszLoaderIniFile);
297         }
298     }
299 
300     /* Services page */
301     psp[nPages].dwSize      = sizeof(PROPSHEETPAGEW);
302     psp[nPages].dwFlags     = PSP_HASHELP;
303     psp[nPages].hInstance   = hInstance;
304     psp[nPages].pszTemplate = MAKEINTRESOURCEW(IDD_SERVICES_PAGE);
305     psp[nPages].pfnDlgProc  = ServicesPageWndProc;
306     ++nPages;
307 
308 #if 0
309     /* Startup page */
310     psp[nPages].dwSize      = sizeof(PROPSHEETPAGEW);
311     psp[nPages].dwFlags     = PSP_HASHELP;
312     psp[nPages].hInstance   = hInstance;
313     psp[nPages].pszTemplate = MAKEINTRESOURCEW(IDD_STARTUP_PAGE);
314     psp[nPages].pfnDlgProc  = StartupPageWndProc;
315     ++nPages;
316 #endif
317 
318     /* Tools page */
319     psp[nPages].dwSize      = sizeof(PROPSHEETPAGEW);
320     psp[nPages].dwFlags     = PSP_HASHELP;
321     psp[nPages].hInstance   = hInstance;
322     psp[nPages].pszTemplate = MAKEINTRESOURCEW(IDD_TOOLS_PAGE);
323     psp[nPages].pfnDlgProc  = ToolsPageWndProc;
324     ++nPages;
325 
326     /* Set the total number of created pages */
327     psh.nPages = nPages;
328 
329     /* Create the property sheet */
330     hPropSheet = (HWND)PropertySheetW(&psh);
331     if (hPropSheet)
332     {
333         /* Center the property sheet on the desktop and show it */
334         ClipOrCenterWindowToMonitor(hPropSheet, MONITOR_WORKAREA | MONITOR_CENTER);
335         ShowWindow(hPropSheet, SW_SHOWNORMAL);
336     }
337 
338     return hPropSheet;
339 }
340 
341 BOOL Initialize(HINSTANCE hInstance)
342 {
343     BOOL Success = TRUE;
344     LPWSTR lpszVistaAppName = NULL;
345     HANDLE hSemaphore;
346     INITCOMMONCONTROLSEX InitControls;
347 
348     /* Initialize our global version flags */
349     bIsWindows = IsWindowsOS();
350     bIsPreVistaOSVersion = IsPreVistaOSVersion();
351 
352     /* Initialize global strings */
353     szAppName = LoadResourceString(hInstance, IDS_MSCONFIG);
354     if (!bIsPreVistaOSVersion)
355         lpszVistaAppName = LoadResourceString(hInstance, IDS_MSCONFIG_2);
356 
357     /* We use a semaphore in order to have a single-instance application */
358     hSemaphore = CreateSemaphoreW(NULL, 0, 1, L"MSConfigRunning");
359     if (!hSemaphore || GetLastError() == ERROR_ALREADY_EXISTS)
360     {
361         CloseHandle(hSemaphore);
362 
363         /*
364          * A semaphore with the same name already exist. It should have been
365          * created by another instance of MSConfig. Try to find its window
366          * and bring it to front.
367          */
368         if ( (hSingleWnd && IsWindow(hSingleWnd))                         ||
369              ( (hSingleWnd = FindWindowW(L"#32770", szAppName)) != NULL ) ||
370              (!bIsPreVistaOSVersion ? ( (hSingleWnd = FindWindowW(L"#32770", lpszVistaAppName)) != NULL ) : FALSE) )
371         {
372             /* Found it. Show the window. */
373             ShowWindow(hSingleWnd, SW_SHOWNORMAL);
374             SetForegroundWindow(hSingleWnd);
375         }
376 
377         /* Quit this instance of MSConfig */
378         Success = FALSE;
379     }
380     if (!bIsPreVistaOSVersion) MemFree(lpszVistaAppName);
381 
382     /* Quit now if we failed */
383     if (!Success)
384     {
385         MemFree(szAppName);
386         return FALSE;
387     }
388 
389     /* Initialize the common controls */
390     InitControls.dwSize = sizeof(INITCOMMONCONTROLSEX);
391     InitControls.dwICC  = ICC_LISTVIEW_CLASSES | ICC_TREEVIEW_CLASSES | ICC_UPDOWN_CLASS /* | ICC_PROGRESS_CLASS | ICC_HOTKEY_CLASS*/;
392     InitCommonControlsEx(&InitControls);
393 
394     hInst = hInstance;
395 
396     return Success;
397 }
398 
399 VOID Cleanup(VOID)
400 {
401     MemFree(szAppName);
402 
403     // // Close the sentry semaphore.
404     // CloseHandle(hSemaphore);
405 }
406 
407 int APIENTRY _tWinMain(HINSTANCE hInstance,
408                        HINSTANCE hPrevInstance,
409                        LPTSTR    lpCmdLine,
410                        int       nCmdShow)
411 {
412     MSG msg;
413     HACCEL hAccelTable;
414 
415     UNREFERENCED_PARAMETER(hPrevInstance);
416     UNREFERENCED_PARAMETER(lpCmdLine);
417     UNREFERENCED_PARAMETER(nCmdShow);
418 
419     /*
420      * Initialize this instance of MSConfig. Quit if we have
421      * another instance already running.
422      */
423     if (!Initialize(hInstance))
424         return -1;
425 
426     // hInst = hInstance;
427 
428     hMainWnd = CreatePropSheet(hInstance, NULL, szAppName);
429     if (!hMainWnd)
430     {
431         /* We failed, cleanup and bail out */
432         Cleanup();
433         return -1;
434     }
435 
436     hAccelTable = LoadAcceleratorsW(hInstance, MAKEINTRESOURCEW(IDR_MSCONFIG));
437 
438     /* Message loop */
439     while (IsWindow(hMainWnd) && GetMessageW(&msg, NULL, 0, 0))
440     {
441         /*
442          * PropSheet_GetCurrentPageHwnd returns NULL when the user clicks the OK or Cancel button
443          * and after all of the pages have been notified. Apply button doesn't cause this to happen.
444          * We can then use the DestroyWindow function to destroy the property sheet.
445          */
446         if (PropSheet_GetCurrentPageHwnd(hMainWnd) == NULL)
447             break;
448 
449         /* Process the accelerator table */
450         if (!TranslateAcceleratorW(hMainWnd, hAccelTable, &msg))
451         {
452             /*
453              * If e.g. an item on the tree view is being edited,
454              * we cannot pass the event to PropSheet_IsDialogMessage.
455              * Doing so causes the property sheet to be closed at Enter press
456              * (instead of completing edit operation).
457              */
458             if (/*g_bDisableDialogDispatch ||*/ !PropSheet_IsDialogMessage(hMainWnd, &msg))
459             {
460                 TranslateMessage(&msg);
461                 DispatchMessageW(&msg);
462             }
463         }
464     }
465 
466     // FIXME: Process the results of MSConfig !!
467 
468     /* Destroy the accelerator table and the window */
469     if (hAccelTable != NULL)
470         DestroyAcceleratorTable(hAccelTable);
471 
472     DestroyWindow(hMainWnd);
473 
474     /* Finish cleanup and return */
475     Cleanup();
476     return (int)msg.wParam;
477 }
478 
479 /* EOF */
480