xref: /reactos/base/system/userinit/userinit.c (revision 03422451)
1 /*
2  *  ReactOS applications
3  *  Copyright (C) 2001, 2002 ReactOS Team
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License along
16  *  with this program; if not, write to the Free Software Foundation, Inc.,
17  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 /*
20  * COPYRIGHT:   See COPYING in the top level directory
21  * PROJECT:     ReactOS Userinit Logon Application
22  * FILE:        base/system/userinit/userinit.c
23  * PROGRAMMERS: Thomas Weidenmueller (w3seek@users.sourceforge.net)
24  *              Herv� Poussineau (hpoussin@reactos.org)
25  */
26 
27 #include "userinit.h"
28 
29 #define CMP_MAGIC  0x01234567
30 
31 /* GLOBALS ******************************************************************/
32 
33 HINSTANCE hInstance;
34 
35 
36 /* FUNCTIONS ****************************************************************/
37 
38 LONG
ReadRegSzKey(IN HKEY hKey,IN LPCWSTR pszKey,OUT LPWSTR * pValue)39 ReadRegSzKey(
40     IN HKEY hKey,
41     IN LPCWSTR pszKey,
42     OUT LPWSTR *pValue)
43 {
44     LONG rc;
45     DWORD dwType;
46     DWORD cbData = 0;
47     LPWSTR Value;
48 
49     TRACE("(%p, %s, %p)\n", hKey, debugstr_w(pszKey), pValue);
50 
51     rc = RegQueryValueExW(hKey, pszKey, NULL, &dwType, NULL, &cbData);
52     if (rc != ERROR_SUCCESS)
53     {
54         WARN("RegQueryValueEx(%s) failed with error %lu\n", debugstr_w(pszKey), rc);
55         return rc;
56     }
57     if (dwType != REG_SZ)
58     {
59         WARN("Wrong registry data type (%u vs %u)\n", dwType, REG_SZ);
60         return ERROR_FILE_NOT_FOUND;
61     }
62     Value = (WCHAR*) HeapAlloc(GetProcessHeap(), 0, cbData + sizeof(WCHAR));
63     if (!Value)
64     {
65         WARN("No memory\n");
66         return ERROR_NOT_ENOUGH_MEMORY;
67     }
68     rc = RegQueryValueExW(hKey, pszKey, NULL, NULL, (LPBYTE)Value, &cbData);
69     if (rc != ERROR_SUCCESS)
70     {
71         WARN("RegQueryValueEx(%s) failed with error %lu\n", debugstr_w(pszKey), rc);
72         HeapFree(GetProcessHeap(), 0, Value);
73         return rc;
74     }
75     /* NULL-terminate the string */
76     Value[cbData / sizeof(WCHAR)] = L'\0';
77 
78     *pValue = Value;
79     return ERROR_SUCCESS;
80 }
81 
82 static BOOL
IsConsoleShell(VOID)83 IsConsoleShell(VOID)
84 {
85     HKEY ControlKey = NULL;
86     LPWSTR SystemStartOptions = NULL;
87     LPWSTR CurrentOption, NextOption; /* Pointers into SystemStartOptions */
88     LONG rc;
89     BOOL ret = FALSE;
90 
91     TRACE("()\n");
92 
93     rc = RegOpenKeyEx(
94         HKEY_LOCAL_MACHINE,
95         REGSTR_PATH_CURRENT_CONTROL_SET,
96         0,
97         KEY_QUERY_VALUE,
98         &ControlKey);
99     if (rc != ERROR_SUCCESS)
100     {
101         WARN("RegOpenKeyEx() failed with error %lu\n", rc);
102         goto cleanup;
103     }
104 
105     rc = ReadRegSzKey(ControlKey, L"SystemStartOptions", &SystemStartOptions);
106     if (rc != ERROR_SUCCESS)
107     {
108         WARN("ReadRegSzKey() failed with error %lu\n", rc);
109         goto cleanup;
110     }
111 
112     /* Check for CONSOLE switch in SystemStartOptions */
113     CurrentOption = SystemStartOptions;
114     while (CurrentOption)
115     {
116         NextOption = wcschr(CurrentOption, L' ');
117         if (NextOption)
118             *NextOption = L'\0';
119         if (_wcsicmp(CurrentOption, L"CONSOLE") == 0)
120         {
121             TRACE("Found 'CONSOLE' boot option\n");
122             ret = TRUE;
123             goto cleanup;
124         }
125         CurrentOption = NextOption ? NextOption + 1 : NULL;
126     }
127 
128 cleanup:
129     if (ControlKey != NULL)
130         RegCloseKey(ControlKey);
131     HeapFree(GetProcessHeap(), 0, SystemStartOptions);
132     TRACE("IsConsoleShell() returning %d\n", ret);
133     return ret;
134 }
135 
136 static BOOL
GetShell(OUT WCHAR * CommandLine,IN HKEY hRootKey)137 GetShell(
138     OUT WCHAR *CommandLine, /* must be at least MAX_PATH long */
139     IN HKEY hRootKey)
140 {
141     HKEY hKey;
142     DWORD Type, Size;
143     WCHAR Shell[MAX_PATH];
144     BOOL ConsoleShell = IsConsoleShell();
145     LONG rc;
146 
147     TRACE("(%p, %p)\n", CommandLine, hRootKey);
148 
149     rc = RegOpenKeyExW(hRootKey, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
150                        0, KEY_QUERY_VALUE, &hKey);
151     if (rc != ERROR_SUCCESS)
152     {
153         WARN("RegOpenKeyEx() failed with error %lu\n", rc);
154         return FALSE;
155     }
156 
157     Size = sizeof(Shell);
158     rc = RegQueryValueExW(hKey,
159                           ConsoleShell ? L"ConsoleShell" : L"Shell",
160                           NULL,
161                           &Type,
162                           (LPBYTE)Shell,
163                           &Size);
164     RegCloseKey(hKey);
165 
166     if (rc != ERROR_SUCCESS)
167     {
168         WARN("RegQueryValueEx() failed with error %lu\n", rc);
169         return FALSE;
170     }
171 
172     if ((Type == REG_SZ) || (Type == REG_EXPAND_SZ))
173     {
174         TRACE("Found command line %s\n", debugstr_w(Shell));
175         wcscpy(CommandLine, Shell);
176         return TRUE;
177     }
178     else
179     {
180         WARN("Wrong type %lu (expected %u or %u)\n", Type, REG_SZ, REG_EXPAND_SZ);
181         return FALSE;
182     }
183 }
184 
185 static BOOL
StartProcess(IN LPCWSTR CommandLine)186 StartProcess(
187     IN LPCWSTR CommandLine)
188 {
189     STARTUPINFO si;
190     PROCESS_INFORMATION pi;
191     WCHAR ExpandedCmdLine[MAX_PATH];
192 
193     TRACE("(%s)\n", debugstr_w(CommandLine));
194 
195     ExpandEnvironmentStringsW(CommandLine, ExpandedCmdLine, ARRAYSIZE(ExpandedCmdLine));
196 
197     ZeroMemory(&si, sizeof(si));
198     si.cb = sizeof(si);
199     si.dwFlags = STARTF_USESHOWWINDOW;
200     si.wShowWindow = SW_SHOWNORMAL;
201     ZeroMemory(&pi, sizeof(pi));
202 
203     if (!CreateProcessW(NULL,
204                         ExpandedCmdLine,
205                         NULL,
206                         NULL,
207                         FALSE,
208                         NORMAL_PRIORITY_CLASS,
209                         NULL,
210                         NULL,
211                         &si,
212                         &pi))
213     {
214         WARN("CreateProcessW() failed with error %lu\n", GetLastError());
215         return FALSE;
216     }
217 
218     CloseHandle(pi.hProcess);
219     CloseHandle(pi.hThread);
220     return TRUE;
221 }
222 
223 static BOOL
StartShell(VOID)224 StartShell(VOID)
225 {
226     WCHAR Shell[MAX_PATH];
227     WCHAR szMsg[RC_STRING_MAX_SIZE];
228     DWORD Type, Size;
229     DWORD Value = 0;
230     LONG rc;
231     HKEY hKey;
232 
233     TRACE("()\n");
234 
235     /* Safe Mode shell run */
236     rc = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
237                        L"SYSTEM\\CurrentControlSet\\Control\\SafeBoot\\Option",
238                        0, KEY_QUERY_VALUE, &hKey);
239     if (rc == ERROR_SUCCESS)
240     {
241         Size = sizeof(Value);
242         rc = RegQueryValueExW(hKey, L"UseAlternateShell", NULL,
243                               &Type, (LPBYTE)&Value, &Size);
244         RegCloseKey(hKey);
245 
246         if (rc == ERROR_SUCCESS)
247         {
248             if (Type == REG_DWORD)
249             {
250                 if (Value)
251                 {
252                     /* Safe Mode Alternate Shell required */
253                     rc = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
254                                        L"SYSTEM\\CurrentControlSet\\Control\\SafeBoot",
255                                        0, KEY_READ, &hKey);
256                     if (rc == ERROR_SUCCESS)
257                     {
258                         Size = sizeof(Shell);
259                         rc = RegQueryValueExW(hKey, L"AlternateShell", NULL,
260                                               &Type, (LPBYTE)Shell, &Size);
261                         RegCloseKey(hKey);
262 
263                         if (rc == ERROR_SUCCESS)
264                         {
265                             if ((Type == REG_SZ) || (Type == REG_EXPAND_SZ))
266                             {
267                                 TRACE("Key located - %s\n", debugstr_w(Shell));
268 
269                                 /* Try to run alternate shell */
270                                 if (StartProcess(Shell))
271                                 {
272                                     TRACE("Alternate shell started (Safe Mode)\n");
273                                     return TRUE;
274                                 }
275                             }
276                             else
277                             {
278                                 WARN("Wrong type %lu (expected %u or %u)\n",
279                                      Type, REG_SZ, REG_EXPAND_SZ);
280                             }
281                         }
282                         else
283                         {
284                             WARN("Alternate shell in Safe Mode required but not specified.\n");
285                         }
286                     }
287                 }
288             }
289             else
290             {
291                 WARN("Wrong type %lu (expected %u)\n", Type, REG_DWORD);
292             }
293         }
294     }
295 
296     /* Try to run shell in user key */
297     if (GetShell(Shell, HKEY_CURRENT_USER) && StartProcess(Shell))
298     {
299         TRACE("Started shell from HKEY_CURRENT_USER\n");
300         return TRUE;
301     }
302 
303     /* Try to run shell in local machine key */
304     if (GetShell(Shell, HKEY_LOCAL_MACHINE) && StartProcess(Shell))
305     {
306         TRACE("Started shell from HKEY_LOCAL_MACHINE\n");
307         return TRUE;
308     }
309 
310     /* Try default shell */
311     if (IsConsoleShell())
312     {
313         *Shell = UNICODE_NULL;
314         if (GetSystemDirectoryW(Shell, ARRAYSIZE(Shell) - 8))
315             StringCchCatW(Shell, ARRAYSIZE(Shell), L"\\");
316         StringCchCatW(Shell, ARRAYSIZE(Shell), L"cmd.exe");
317     }
318     else
319     {
320         *Shell = UNICODE_NULL;
321         if (GetSystemWindowsDirectoryW(Shell, ARRAYSIZE(Shell) - 13))
322             StringCchCatW(Shell, ARRAYSIZE(Shell), L"\\");
323         StringCchCatW(Shell, ARRAYSIZE(Shell), L"explorer.exe");
324     }
325 
326     if (!StartProcess(Shell))
327     {
328         WARN("Failed to start default shell '%s'\n", debugstr_w(Shell));
329         LoadStringW(GetModuleHandle(NULL), IDS_SHELL_FAIL, szMsg, ARRAYSIZE(szMsg));
330         MessageBoxW(NULL, szMsg, NULL, MB_OK);
331         return FALSE;
332     }
333     return TRUE;
334 }
335 
336 const WCHAR g_RegColorNames[][32] = {
337     L"Scrollbar",             /* 00 = COLOR_SCROLLBAR */
338     L"Background",            /* 01 = COLOR_DESKTOP */
339     L"ActiveTitle",           /* 02 = COLOR_ACTIVECAPTION  */
340     L"InactiveTitle",         /* 03 = COLOR_INACTIVECAPTION */
341     L"Menu",                  /* 04 = COLOR_MENU */
342     L"Window",                /* 05 = COLOR_WINDOW */
343     L"WindowFrame",           /* 06 = COLOR_WINDOWFRAME */
344     L"MenuText",              /* 07 = COLOR_MENUTEXT */
345     L"WindowText",            /* 08 = COLOR_WINDOWTEXT */
346     L"TitleText",             /* 09 = COLOR_CAPTIONTEXT */
347     L"ActiveBorder",          /* 10 = COLOR_ACTIVEBORDER */
348     L"InactiveBorder",        /* 11 = COLOR_INACTIVEBORDER */
349     L"AppWorkSpace",          /* 12 = COLOR_APPWORKSPACE */
350     L"Hilight",               /* 13 = COLOR_HIGHLIGHT */
351     L"HilightText",           /* 14 = COLOR_HIGHLIGHTTEXT */
352     L"ButtonFace",            /* 15 = COLOR_BTNFACE */
353     L"ButtonShadow",          /* 16 = COLOR_BTNSHADOW */
354     L"GrayText",              /* 17 = COLOR_GRAYTEXT */
355     L"ButtonText",            /* 18 = COLOR_BTNTEXT */
356     L"InactiveTitleText",     /* 19 = COLOR_INACTIVECAPTIONTEXT */
357     L"ButtonHilight",         /* 20 = COLOR_BTNHIGHLIGHT */
358     L"ButtonDkShadow",        /* 21 = COLOR_3DDKSHADOW */
359     L"ButtonLight",           /* 22 = COLOR_3DLIGHT */
360     L"InfoText",              /* 23 = COLOR_INFOTEXT */
361     L"InfoWindow",            /* 24 = COLOR_INFOBK */
362     L"ButtonAlternateFace",   /* 25 = COLOR_ALTERNATEBTNFACE */
363     L"HotTrackingColor",      /* 26 = COLOR_HOTLIGHT */
364     L"GradientActiveTitle",   /* 27 = COLOR_GRADIENTACTIVECAPTION */
365     L"GradientInactiveTitle", /* 28 = COLOR_GRADIENTINACTIVECAPTION */
366     L"MenuHilight",           /* 29 = COLOR_MENUHILIGHT */
367     L"MenuBar"                /* 30 = COLOR_MENUBAR */
368 };
369 
370 static COLORREF
StrToColorref(IN LPWSTR lpszCol)371 StrToColorref(
372     IN LPWSTR lpszCol)
373 {
374     BYTE rgb[3];
375 
376     TRACE("(%s)\n", debugstr_w(lpszCol));
377 
378     rgb[0] = (BYTE)wcstoul(lpszCol, &lpszCol, 10);
379     rgb[1] = (BYTE)wcstoul(lpszCol, &lpszCol, 10);
380     rgb[2] = (BYTE)wcstoul(lpszCol, &lpszCol, 10);
381     return RGB(rgb[0], rgb[1], rgb[2]);
382 }
383 
384 static VOID
SetUserSysColors(VOID)385 SetUserSysColors(VOID)
386 {
387     HKEY hKey;
388     INT i;
389     WCHAR szColor[25];
390     DWORD Type, Size;
391     COLORREF crColor;
392     LONG rc;
393 
394     TRACE("()\n");
395 
396     rc = RegOpenKeyExW(HKEY_CURRENT_USER, REGSTR_PATH_COLORS,
397                        0, KEY_QUERY_VALUE, &hKey);
398     if (rc != ERROR_SUCCESS)
399     {
400         WARN("RegOpenKeyEx() failed with error %lu\n", rc);
401         return;
402     }
403 
404     for (i = 0; i < ARRAYSIZE(g_RegColorNames); i++)
405     {
406         Size = sizeof(szColor);
407         rc = RegQueryValueExW(hKey, g_RegColorNames[i], NULL, &Type,
408                               (LPBYTE)szColor, &Size);
409         if (rc == ERROR_SUCCESS && Type == REG_SZ)
410         {
411             crColor = StrToColorref(szColor);
412             SetSysColors(1, &i, &crColor);
413         }
414         else
415         {
416             WARN("RegQueryValueEx(%s) failed with error %lu\n",
417                 debugstr_w(g_RegColorNames[i]), rc);
418         }
419     }
420 
421     RegCloseKey(hKey);
422 }
423 
424 static VOID
SetUserWallpaper(VOID)425 SetUserWallpaper(VOID)
426 {
427     HKEY hKey;
428     DWORD Type, Size;
429     WCHAR szWallpaper[MAX_PATH + 1];
430     LONG rc;
431 
432     TRACE("()\n");
433 
434     rc = RegOpenKeyExW(HKEY_CURRENT_USER, REGSTR_PATH_DESKTOP,
435                        0, KEY_QUERY_VALUE, &hKey);
436     if (rc != ERROR_SUCCESS)
437     {
438         WARN("RegOpenKeyEx() failed with error %lu\n", rc);
439         return;
440     }
441 
442     Size = sizeof(szWallpaper);
443     rc = RegQueryValueExW(hKey,
444                           L"Wallpaper",
445                           NULL,
446                           &Type,
447                           (LPBYTE)szWallpaper,
448                           &Size);
449     RegCloseKey(hKey);
450 
451     if (rc == ERROR_SUCCESS && Type == REG_SZ)
452     {
453         ExpandEnvironmentStringsW(szWallpaper, szWallpaper, ARRAYSIZE(szWallpaper));
454         TRACE("Using wallpaper %s\n", debugstr_w(szWallpaper));
455 
456         /* Load and change the wallpaper */
457         SystemParametersInfoW(SPI_SETDESKWALLPAPER, 0, szWallpaper, SPIF_SENDCHANGE);
458     }
459     else
460     {
461         /* Remove the wallpaper */
462         TRACE("No wallpaper set in registry (error %lu)\n", rc);
463         SystemParametersInfoW(SPI_SETDESKWALLPAPER, 0, NULL, SPIF_SENDCHANGE);
464     }
465 }
466 
467 static VOID
SetUserSettings(VOID)468 SetUserSettings(VOID)
469 {
470     TRACE("()\n");
471 
472     UpdatePerUserSystemParameters(1, TRUE);
473     SetUserSysColors();
474     SetUserWallpaper();
475 }
476 
477 typedef DWORD (WINAPI *PCMP_REPORT_LOGON)(DWORD, DWORD);
478 
479 static VOID
NotifyLogon(VOID)480 NotifyLogon(VOID)
481 {
482     HINSTANCE hModule;
483     PCMP_REPORT_LOGON CMP_Report_LogOn;
484 
485     TRACE("()\n");
486 
487     hModule = LoadLibraryW(L"setupapi.dll");
488     if (!hModule)
489     {
490         WARN("LoadLibrary() failed with error %lu\n", GetLastError());
491         return;
492     }
493 
494     CMP_Report_LogOn = (PCMP_REPORT_LOGON)GetProcAddress(hModule, "CMP_Report_LogOn");
495     if (CMP_Report_LogOn)
496         CMP_Report_LogOn(CMP_MAGIC, GetCurrentProcessId());
497     else
498         WARN("GetProcAddress() failed\n");
499 
500     FreeLibrary(hModule);
501 }
502 
503 static BOOL
StartInstaller(IN LPCTSTR lpInstallerName)504 StartInstaller(IN LPCTSTR lpInstallerName)
505 {
506     SYSTEM_INFO SystemInfo;
507     SIZE_T cchInstallerNameLen;
508     PWSTR ptr;
509     DWORD dwAttribs;
510     WCHAR Installer[MAX_PATH];
511     WCHAR szMsg[RC_STRING_MAX_SIZE];
512 
513     cchInstallerNameLen = wcslen(lpInstallerName);
514     if (ARRAYSIZE(Installer) < cchInstallerNameLen)
515     {
516         /* The buffer is not large enough to contain the installer file name */
517         return FALSE;
518     }
519 
520     /*
521      * First, try to find the installer using the default drive, under
522      * the directory whose name corresponds to the currently-running
523      * CPU architecture.
524      */
525     GetSystemInfo(&SystemInfo);
526 
527     *Installer = UNICODE_NULL;
528     /* Alternatively one can use SharedUserData->NtSystemRoot */
529     GetSystemWindowsDirectoryW(Installer, ARRAYSIZE(Installer) - cchInstallerNameLen - 1);
530     ptr = wcschr(Installer, L'\\');
531     if (ptr)
532         *++ptr = UNICODE_NULL;
533     else
534         *Installer = UNICODE_NULL;
535 
536     /* Append the corresponding CPU architecture */
537     switch (SystemInfo.wProcessorArchitecture)
538     {
539         case PROCESSOR_ARCHITECTURE_INTEL:
540             StringCchCatW(Installer, ARRAYSIZE(Installer), L"I386");
541             break;
542 
543         case PROCESSOR_ARCHITECTURE_MIPS:
544             StringCchCatW(Installer, ARRAYSIZE(Installer), L"MIPS");
545             break;
546 
547         case PROCESSOR_ARCHITECTURE_ALPHA:
548             StringCchCatW(Installer, ARRAYSIZE(Installer), L"ALPHA");
549             break;
550 
551         case PROCESSOR_ARCHITECTURE_PPC:
552             StringCchCatW(Installer, ARRAYSIZE(Installer), L"PPC");
553             break;
554 
555         case PROCESSOR_ARCHITECTURE_SHX:
556             StringCchCatW(Installer, ARRAYSIZE(Installer), L"SHX");
557             break;
558 
559         case PROCESSOR_ARCHITECTURE_ARM:
560             StringCchCatW(Installer, ARRAYSIZE(Installer), L"ARM");
561             break;
562 
563         case PROCESSOR_ARCHITECTURE_IA64:
564             StringCchCatW(Installer, ARRAYSIZE(Installer), L"IA64");
565             break;
566 
567         case PROCESSOR_ARCHITECTURE_ALPHA64:
568             StringCchCatW(Installer, ARRAYSIZE(Installer), L"ALPHA64");
569             break;
570 
571         case PROCESSOR_ARCHITECTURE_AMD64:
572             StringCchCatW(Installer, ARRAYSIZE(Installer), L"AMD64");
573             break;
574 
575         // case PROCESSOR_ARCHITECTURE_MSIL: /* .NET CPU-independent code */
576         case PROCESSOR_ARCHITECTURE_UNKNOWN:
577         default:
578             WARN("Unknown processor architecture %lu\n", SystemInfo.wProcessorArchitecture);
579             SystemInfo.wProcessorArchitecture = PROCESSOR_ARCHITECTURE_UNKNOWN;
580             break;
581     }
582 
583     if (SystemInfo.wProcessorArchitecture != PROCESSOR_ARCHITECTURE_UNKNOWN)
584         StringCchCatW(Installer, ARRAYSIZE(Installer), L"\\");
585     StringCchCatW(Installer, ARRAYSIZE(Installer), lpInstallerName);
586 
587     dwAttribs = GetFileAttributesW(Installer);
588     if ((dwAttribs != INVALID_FILE_ATTRIBUTES) &&
589         !(dwAttribs & FILE_ATTRIBUTE_DIRECTORY))
590     {
591         /* We have found the installer */
592         if (StartProcess(Installer))
593             return TRUE;
594     }
595 
596     ERR("Failed to start the installer '%s', trying alternative.\n", debugstr_w(Installer));
597 
598     /*
599      * We failed. Try to find the installer from either the current
600      * ReactOS installation directory, or from our current directory.
601      */
602     *Installer = UNICODE_NULL;
603     /* Alternatively one can use SharedUserData->NtSystemRoot */
604     if (GetSystemWindowsDirectoryW(Installer, ARRAYSIZE(Installer) - cchInstallerNameLen - 1))
605         StringCchCatW(Installer, ARRAYSIZE(Installer), L"\\");
606     StringCchCatW(Installer, ARRAYSIZE(Installer), lpInstallerName);
607 
608     dwAttribs = GetFileAttributesW(Installer);
609     if ((dwAttribs != INVALID_FILE_ATTRIBUTES) &&
610         !(dwAttribs & FILE_ATTRIBUTE_DIRECTORY))
611     {
612         /* We have found the installer */
613         if (StartProcess(Installer))
614             return TRUE;
615     }
616 
617     /* We failed. Display an error message and quit. */
618     ERR("Failed to start the installer '%s'.\n", debugstr_w(Installer));
619     LoadStringW(GetModuleHandle(NULL), IDS_INSTALLER_FAIL, szMsg, ARRAYSIZE(szMsg));
620     MessageBoxW(NULL, szMsg, NULL, MB_OK);
621     return FALSE;
622 }
623 
624 /* Used to get the shutdown privilege */
625 static BOOL
EnablePrivilege(LPCWSTR lpszPrivilegeName,BOOL bEnablePrivilege)626 EnablePrivilege(LPCWSTR lpszPrivilegeName, BOOL bEnablePrivilege)
627 {
628     BOOL   Success;
629     HANDLE hToken;
630     TOKEN_PRIVILEGES tp;
631 
632     Success = OpenProcessToken(GetCurrentProcess(),
633                                TOKEN_ADJUST_PRIVILEGES,
634                                &hToken);
635     if (!Success) return Success;
636 
637     Success = LookupPrivilegeValueW(NULL,
638                                     lpszPrivilegeName,
639                                     &tp.Privileges[0].Luid);
640     if (!Success) goto Quit;
641 
642     tp.PrivilegeCount = 1;
643     tp.Privileges[0].Attributes = (bEnablePrivilege ? SE_PRIVILEGE_ENABLED : 0);
644 
645     Success = AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL);
646 
647 Quit:
648     CloseHandle(hToken);
649     return Success;
650 }
651 
652 
653 int WINAPI
wWinMain(IN HINSTANCE hInst,IN HINSTANCE hPrevInstance,IN LPWSTR lpszCmdLine,IN int nCmdShow)654 wWinMain(IN HINSTANCE hInst,
655          IN HINSTANCE hPrevInstance,
656          IN LPWSTR lpszCmdLine,
657          IN int nCmdShow)
658 {
659     BOOL bIsLiveCD, Success = TRUE;
660     STATE State;
661 
662     hInstance = hInst;
663 
664     bIsLiveCD = IsLiveCD();
665 
666 Restart:
667     SetUserSettings();
668 
669     if (bIsLiveCD)
670     {
671         State.NextPage = LOCALEPAGE;
672         State.Run = SHELL;
673     }
674     else
675     {
676         State.NextPage = DONE;
677         State.Run = SHELL;
678     }
679 
680     if (State.NextPage != DONE) // && bIsLiveCD
681     {
682         RunLiveCD(&State);
683     }
684 
685     switch (State.Run)
686     {
687         case SHELL:
688             Success = StartShell();
689             if (Success)
690                 NotifyLogon();
691             break;
692 
693         case INSTALLER:
694             Success = StartInstaller(L"reactos.exe");
695             break;
696 
697         case REBOOT:
698         {
699             EnablePrivilege(SE_SHUTDOWN_NAME, TRUE);
700             ExitWindowsEx(EWX_REBOOT, 0);
701             EnablePrivilege(SE_SHUTDOWN_NAME, FALSE);
702             Success = TRUE;
703             break;
704         }
705 
706         default:
707             Success = FALSE;
708             break;
709     }
710 
711     /*
712      * In LiveCD mode, go back to the main menu if we failed
713      * to either start the shell or the installer.
714      */
715     if (bIsLiveCD && !Success)
716         goto Restart;
717 
718     return 0;
719 }
720 
721 /* EOF */
722