4b5ebca16ba39106b8b39a70f831638a7c1a9dd5
[reactos.git] / reactos / base / applications / msconfig_new / msconfig.c
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 "utils.h"
11
12 #include "toolspage.h"
13 #include "srvpage.h"
14 #include "startuppage.h"
15 #include "freeldrpage.h"
16 #include "systempage.h"
17 #include "generalpage.h"
18
19 /* Allow only for a single instance of MSConfig */
20 #ifdef _MSC_VER
21 #pragma data_seg("MSConfigInstance")
22 HWND hSingleWnd = NULL;
23 #pragma data_seg()
24 #pragma comment(linker, "/SECTION:MSConfigInstance,RWS")
25 #else
26 HWND hSingleWnd __attribute__((section ("MSConfigInstance"), shared)) = NULL;
27 #endif
28
29 /* Defaults for ReactOS */
30 BOOL bIsWindows = FALSE;
31 BOOL bIsOSVersionLessThanVista = TRUE;
32
33 HINSTANCE hInst = NULL;
34 LPWSTR szAppName = NULL;
35 HWND hMainWnd; /* Main Window */
36
37 HWND hTabWnd; /* Tab Control Window */
38 // HICON hDialogIcon = NULL;
39 HICON hIcon = NULL;
40 WNDPROC wpOrigEditProc = NULL;
41
42
43 ////////////////////////////////////////////////////////////////////////////////
44 // Taken from WinSpy++ 1.7
45 // http://www.catch22.net/software/winspy
46 // Copyright (c) 2002 by J Brown
47 //
48
49 //
50 // Copied from uxtheme.h
51 // If you have this new header, then delete these and
52 // #include <uxtheme.h> instead!
53 //
54 #define ETDT_DISABLE 0x00000001
55 #define ETDT_ENABLE 0x00000002
56 #define ETDT_USETABTEXTURE 0x00000004
57 #define ETDT_ENABLETAB (ETDT_ENABLE | ETDT_USETABTEXTURE)
58
59 //
60 typedef HRESULT (WINAPI * ETDTProc) (HWND, DWORD);
61
62 //
63 // Try to call EnableThemeDialogTexture, if uxtheme.dll is present
64 //
65 BOOL EnableDialogTheme(HWND hwnd)
66 {
67 HMODULE hUXTheme;
68 ETDTProc fnEnableThemeDialogTexture;
69
70 hUXTheme = LoadLibrary(_T("uxtheme.dll"));
71
72 if(hUXTheme)
73 {
74 fnEnableThemeDialogTexture =
75 (ETDTProc)GetProcAddress(hUXTheme, "EnableThemeDialogTexture");
76
77 if(fnEnableThemeDialogTexture)
78 {
79 fnEnableThemeDialogTexture(hwnd, ETDT_ENABLETAB);
80
81 FreeLibrary(hUXTheme);
82 return TRUE;
83 }
84 else
85 {
86 // Failed to locate API!
87 FreeLibrary(hUXTheme);
88 return FALSE;
89 }
90 }
91 else
92 {
93 // Not running under XP? Just fail gracefully
94 return FALSE;
95 }
96 }
97
98 /* About Box dialog */
99 INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
100 {
101 UNREFERENCED_PARAMETER(lParam);
102 switch (message)
103 {
104 case WM_INITDIALOG:
105 return (INT_PTR)TRUE;
106
107 case WM_COMMAND:
108 if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
109 {
110 EndDialog(hDlg, LOWORD(wParam));
111 return (INT_PTR)TRUE;
112 }
113 break;
114 }
115 return (INT_PTR)FALSE;
116 }
117
118
119 /* Message handler for dialog box. */
120 LRESULT CALLBACK MainWndProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
121 {
122 switch (uMessage)
123 {
124 case WM_SYSCOMMAND:
125 {
126 switch (LOWORD(wParam) /*GET_WM_COMMAND_ID(wParam, lParam)*/)
127 {
128 case IDM_ABOUT:
129 DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
130 // break;
131 return TRUE;
132 }
133
134 // break;
135 return FALSE;
136 }
137
138 case WM_COMMAND:
139 {
140 switch (LOWORD(wParam) /*GET_WM_COMMAND_ID(wParam, lParam)*/)
141 {
142 case IDM_ABOUT:
143 DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
144 // break;
145 return TRUE;
146 }
147
148 break;
149 // return FALSE;
150 }
151
152 #if 0
153 case WM_SYSCOLORCHANGE:
154 /* Forward WM_SYSCOLORCHANGE to common controls */
155 SendMessage(hServicesListCtrl, WM_SYSCOLORCHANGE, 0, 0);
156 SendMessage(hStartupListCtrl, WM_SYSCOLORCHANGE, 0, 0);
157 SendMessage(hToolsListCtrl, WM_SYSCOLORCHANGE, 0, 0);
158 break;
159 #endif
160
161 case WM_DESTROY:
162 {
163 if (hIcon)
164 DestroyIcon(hIcon);
165
166 if (wpOrigEditProc)
167 SetWindowLongPtr(hWnd, DWLP_DLGPROC, (LONG_PTR)wpOrigEditProc);
168 }
169
170 default:
171 break;
172 }
173
174 /* Return */
175 if (wpOrigEditProc)
176 return CallWindowProc(wpOrigEditProc, hWnd, uMessage, wParam, lParam);
177 else
178 return FALSE;
179 }
180
181
182 #include <pshpack1.h>
183 typedef struct DLGTEMPLATEEX
184 {
185 WORD dlgVer;
186 WORD signature;
187 DWORD helpID;
188 DWORD exStyle;
189 DWORD style;
190 WORD cDlgItems;
191 short x;
192 short y;
193 short cx;
194 short cy;
195 } DLGTEMPLATEEX, *LPDLGTEMPLATEEX;
196 #include <poppack.h>
197
198
199 VOID ModifySystemMenu(HWND hWnd)
200 {
201 WCHAR szMenuString[255];
202
203 /* Customize the window's system menu, add items before the "Close" item */
204 HMENU hSysMenu = GetSystemMenu(hWnd, FALSE);
205 assert(hSysMenu);
206
207 /* New entries... */
208 if (LoadStringW(hInst,
209 IDS_ABOUT,
210 szMenuString,
211 ARRAYSIZE(szMenuString)) > 0)
212 {
213 /* "About" menu */
214 InsertMenuW(hSysMenu, SC_CLOSE, MF_BYCOMMAND | MF_ENABLED | MF_STRING, IDM_ABOUT, szMenuString);
215 /* Separator */
216 InsertMenuW(hSysMenu, SC_CLOSE, MF_BYCOMMAND | MF_SEPARATOR , 0 , NULL);
217 }
218
219 DrawMenuBar(hWnd);
220 return;
221 }
222
223 int CALLBACK PropSheetCallback(HWND hDlg, UINT message, LPARAM lParam)
224 {
225 switch (message)
226 {
227 case PSCB_PRECREATE:
228 {
229 LPDLGTEMPLATE dlgTemplate = (LPDLGTEMPLATE)lParam;
230 LPDLGTEMPLATEEX dlgTemplateEx = (LPDLGTEMPLATEEX)lParam;
231
232 /* Set the styles of the property sheet dialog */
233 if (dlgTemplateEx->signature == 0xFFFF)
234 {
235 //// MFC : DS_MODALFRAME | DS_3DLOOK | DS_CONTEXTHELP | DS_SETFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION;
236
237 dlgTemplateEx->style = DS_SHELLFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU;
238 // dlgTemplateEx->style = DS_SHELLFONT | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME;
239 dlgTemplateEx->exStyle = WS_EX_CONTROLPARENT | WS_EX_APPWINDOW;
240 }
241 else
242 {
243 dlgTemplate->style = DS_SHELLFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU;
244 // dlgTemplate->style = DS_SHELLFONT | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME;
245 dlgTemplate->dwExtendedStyle = WS_EX_CONTROLPARENT | WS_EX_APPWINDOW;
246 }
247
248 break;
249 }
250
251 case PSCB_INITIALIZED:
252 {
253 /* Modify the system menu of the property sheet dialog */
254 ModifySystemMenu(hDlg);
255
256 /* Set the dialog icons */
257 hIcon = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_APPICON), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE);
258 SendMessage(hDlg, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
259 SendMessage(hDlg, WM_SETICON, ICON_SMALL, (LPARAM)hIcon);
260
261 /* Sub-class the property sheet window procedure */
262 wpOrigEditProc = (WNDPROC)SetWindowLongPtr(hDlg, DWLP_DLGPROC, (LONG_PTR)MainWndProc);
263
264 break;
265 }
266
267 default:
268 break;
269 }
270
271 return FALSE;
272 }
273
274 HWND CreatePropSheet(HINSTANCE hInstance, HWND hwndOwner, LPCTSTR lpszTitle)
275 {
276 HWND hPropSheet;
277 PROPSHEETHEADER psh;
278 PROPSHEETPAGE psp[7];
279 unsigned int nPages = 0;
280
281 /* Header */
282 psh.dwSize = sizeof(PROPSHEETHEADER);
283 psh.dwFlags = PSH_PROPSHEETPAGE | PSH_MODELESS | /*PSH_USEICONID |*/ PSH_HASHELP | /*PSH_NOCONTEXTHELP |*/ PSH_USECALLBACK;
284 psh.hInstance = hInstance;
285 psh.hwndParent = hwndOwner;
286 //psh.pszIcon = MAKEINTRESOURCE(IDI_APPICON); // It's crap... Only works for the small icon and not the big...
287 psh.pszCaption = lpszTitle;
288 psh.nStartPage = 0;
289 psh.ppsp = psp;
290 psh.pfnCallback = (PFNPROPSHEETCALLBACK)PropSheetCallback;
291
292 /* General page */
293 psp[nPages].dwSize = sizeof(PROPSHEETPAGE);
294 psp[nPages].dwFlags = PSP_HASHELP;
295 psp[nPages].hInstance = hInstance;
296 psp[nPages].pszTemplate = MAKEINTRESOURCE(IDD_GENERAL_PAGE);
297 psp[nPages].pfnDlgProc = (DLGPROC)GeneralPageWndProc;
298 ++nPages;
299
300 #if 0
301 if (bIsWindows && bIsOSVersionLessThanVista)
302 {
303 /* SYSTEM.INI page */
304 if (MyFileExists(lpszSystemIni, NULL))
305 {
306 psp[nPages].dwSize = sizeof(PROPSHEETPAGE);
307 psp[nPages].dwFlags = PSP_HASHELP | PSP_USETITLE;
308 psp[nPages].hInstance = hInstance;
309 psp[nPages].pszTitle = MAKEINTRESOURCE(IDS_TAB_SYSTEM);
310 psp[nPages].pszTemplate = MAKEINTRESOURCE(IDD_SYSTEM_PAGE);
311 psp[nPages].pfnDlgProc = (DLGPROC)SystemPageWndProc;
312 psp[nPages].lParam = (LPARAM)lpszSystemIni;
313 ++nPages;
314
315 BackupIniFile(lpszSystemIni);
316 }
317
318 /* WIN.INI page */
319 if (MyFileExists(lpszWinIni, NULL))
320 {
321 psp[nPages].dwSize = sizeof(PROPSHEETPAGE);
322 psp[nPages].dwFlags = PSP_HASHELP | PSP_USETITLE;
323 psp[nPages].hInstance = hInstance;
324 psp[nPages].pszTitle = MAKEINTRESOURCE(IDS_TAB_WIN);
325 psp[nPages].pszTemplate = MAKEINTRESOURCE(IDD_SYSTEM_PAGE);
326 psp[nPages].pfnDlgProc = (DLGPROC)WinPageWndProc;
327 psp[nPages].lParam = (LPARAM)lpszWinIni;
328 ++nPages;
329
330 BackupIniFile(lpszWinIni);
331 }
332 }
333
334 /* FreeLdr page */
335 // TODO: Program the interface for Vista : "light" BCD editor...
336 if (!bIsWindows || (bIsWindows && bIsOSVersionLessThanVista))
337 {
338 LPCTSTR lpszLoaderIniFile = NULL;
339 DWORD dwTabNameId = 0;
340 if (bIsWindows)
341 {
342 lpszLoaderIniFile = lpszBootIni;
343 dwTabNameId = IDS_TAB_BOOT;
344 }
345 else
346 {
347 lpszLoaderIniFile = lpszFreeLdrIni;
348 dwTabNameId = IDS_TAB_FREELDR;
349 }
350
351 if (MyFileExists(lpszLoaderIniFile, NULL))
352 {
353 psp[nPages].dwSize = sizeof(PROPSHEETPAGE);
354 psp[nPages].dwFlags = PSP_HASHELP | PSP_USETITLE;
355 psp[nPages].hInstance = hInstance;
356 psp[nPages].pszTitle = MAKEINTRESOURCE(dwTabNameId);
357 psp[nPages].pszTemplate = MAKEINTRESOURCE(IDD_FREELDR_PAGE);
358 psp[nPages].pfnDlgProc = (DLGPROC)FreeLdrPageWndProc;
359 psp[nPages].lParam = (LPARAM)lpszLoaderIniFile;
360 ++nPages;
361
362 BackupIniFile(lpszLoaderIniFile);
363 }
364 }
365
366 /* Services page */
367 psp[nPages].dwSize = sizeof(PROPSHEETPAGE);
368 psp[nPages].dwFlags = PSP_HASHELP;
369 psp[nPages].hInstance = hInstance;
370 psp[nPages].pszTemplate = MAKEINTRESOURCE(IDD_SERVICES_PAGE);
371 psp[nPages].pfnDlgProc = (DLGPROC)ServicesPageWndProc;
372 ++nPages;
373
374 /* Startup page */
375 psp[nPages].dwSize = sizeof(PROPSHEETPAGE);
376 psp[nPages].dwFlags = PSP_HASHELP;
377 psp[nPages].hInstance = hInstance;
378 psp[nPages].pszTemplate = MAKEINTRESOURCE(IDD_STARTUP_PAGE);
379 psp[nPages].pfnDlgProc = (DLGPROC)StartupPageWndProc;
380 ++nPages;
381 #endif
382
383 /* Tools page */
384 psp[nPages].dwSize = sizeof(PROPSHEETPAGE);
385 psp[nPages].dwFlags = PSP_HASHELP;
386 psp[nPages].hInstance = hInstance;
387 psp[nPages].pszTemplate = MAKEINTRESOURCE(IDD_TOOLS_PAGE);
388 psp[nPages].pfnDlgProc = (DLGPROC)ToolsPageWndProc;
389 ++nPages;
390
391 /* Set the total number of created pages */
392 psh.nPages = nPages;
393
394 /* Create the property sheet */
395 hPropSheet = (HWND)PropertySheet(&psh);
396 if (hPropSheet)
397 {
398 /* Center the property sheet on the desktop */
399 //ShowWindow(hPropSheet, SW_HIDE);
400 ClipOrCenterWindowToMonitor(hPropSheet, MONITOR_WORKAREA | MONITOR_CENTER);
401 //ShowWindow(hPropSheet, SW_SHOWNORMAL);
402 }
403
404 return hPropSheet;
405 }
406
407 BOOL Initialize(HINSTANCE hInstance)
408 {
409 BOOL Success = TRUE;
410 LPWSTR lpszVistaAppName = NULL;
411 HANDLE hSemaphore;
412 INITCOMMONCONTROLSEX InitControls;
413
414 /* Initialize our global version flags */
415 bIsWindows = TRUE; /* IsWindowsOS(); */ // TODO: Commented for testing purposes...
416 bIsOSVersionLessThanVista = TRUE; /* IsOSVersionLessThanVista(); */ // TODO: Commented for testing purposes...
417
418 /* Initialize global strings */
419 szAppName = LoadResourceString(hInstance, IDS_MSCONFIG);
420 if (!bIsOSVersionLessThanVista)
421 lpszVistaAppName = LoadResourceString(hInstance, IDS_MSCONFIG_2);
422
423 /* We use a semaphore in order to have a single-instance application */
424 hSemaphore = CreateSemaphoreW(NULL, 0, 1, L"MSConfigRunning");
425 if (!hSemaphore || GetLastError() == ERROR_ALREADY_EXISTS)
426 {
427 CloseHandle(hSemaphore);
428
429 /*
430 * A semaphore with the same name already exist. It should have been
431 * created by another instance of MSConfig. Try to find its window
432 * and bring it to front.
433 */
434 if ( (hSingleWnd && IsWindow(hSingleWnd)) ||
435 ( (hSingleWnd = FindWindowW(L"#32770", szAppName)) != NULL ) ||
436 (!bIsOSVersionLessThanVista ? ( (hSingleWnd = FindWindowW(L"#32770", lpszVistaAppName)) != NULL ) : FALSE) )
437 {
438 /* Found it. Show the window. */
439 ShowWindow(hSingleWnd, SW_SHOWNORMAL);
440 SetForegroundWindow(hSingleWnd);
441 }
442
443 /* Quit this instance of MSConfig */
444 Success = FALSE;
445 }
446 if (!bIsOSVersionLessThanVista) MemFree(lpszVistaAppName);
447
448 /* Quit now if we failed */
449 if (!Success)
450 {
451 MemFree(szAppName);
452 return FALSE;
453 }
454
455 /* Initialize the common controls */
456 InitControls.dwSize = sizeof(INITCOMMONCONTROLSEX);
457 InitControls.dwICC = ICC_LISTVIEW_CLASSES | ICC_TREEVIEW_CLASSES | ICC_UPDOWN_CLASS /* | ICC_PROGRESS_CLASS | ICC_HOTKEY_CLASS*/;
458 InitCommonControlsEx(&InitControls);
459
460 hInst = hInstance;
461
462 return Success;
463 }
464
465 VOID Cleanup(VOID)
466 {
467 MemFree(szAppName);
468
469 // // Close the sentry semaphore.
470 // CloseHandle(hSemaphore);
471 }
472
473 int APIENTRY _tWinMain(HINSTANCE hInstance,
474 HINSTANCE hPrevInstance,
475 LPTSTR lpCmdLine,
476 int nCmdShow)
477 {
478 MSG msg;
479 HACCEL hAccelTable;
480
481 UNREFERENCED_PARAMETER(hPrevInstance);
482 UNREFERENCED_PARAMETER(lpCmdLine);
483 UNREFERENCED_PARAMETER(nCmdShow);
484
485 /*
486 * Initialize this instance of MSConfig. Quit if we have
487 * another instance already running.
488 */
489 if (!Initialize(hInstance))
490 return -1;
491
492 // hInst = hInstance;
493
494 hMainWnd = CreatePropSheet(hInstance, NULL, szAppName);
495 if (!hMainWnd)
496 {
497 /* We failed, cleanup and bail out */
498 Cleanup();
499 return -1;
500 }
501
502 hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_MSCONFIG));
503
504 /* Message loop */
505 while (IsWindow(hMainWnd) && GetMessage(&msg, NULL, 0, 0))
506 {
507 /*
508 * PropSheet_GetCurrentPageHwnd returns NULL when the user clicks the OK or Cancel button
509 * and after all of the pages have been notified. Apply button doesn't cause this to happen.
510 * We can then use the DestroyWindow function to destroy the property sheet.
511 */
512 if (PropSheet_GetCurrentPageHwnd(hMainWnd) == NULL)
513 break;
514
515 /* Process the accelerator table */
516 if (!TranslateAccelerator(hMainWnd, hAccelTable, &msg))
517 {
518 /*
519 * If e.g. an item on the tree view is being edited,
520 * we cannot pass the event to PropSheet_IsDialogMessage.
521 * Doing so causes the property sheet to be closed at Enter press
522 * (instead of completing edit operation).
523 */
524 if (/*g_bDisableDialogDispatch ||*/ !PropSheet_IsDialogMessage(hMainWnd, &msg))
525 {
526 TranslateMessage(&msg);
527 DispatchMessage(&msg);
528 }
529 }
530 }
531
532 // FIXME: Process the results of MSConfig !!
533
534 /* Destroy the accelerator table and the window */
535 if (hAccelTable != NULL)
536 DestroyAcceleratorTable(hAccelTable);
537
538 DestroyWindow(hMainWnd);
539
540 /* Finish cleanup and return */
541 Cleanup();
542 return (int)msg.wParam;
543 }
544
545 /* EOF */