xref: /reactos/dll/win32/syssetup/install.c (revision 2b933529)
1 /*
2  * COPYRIGHT:         See COPYING in the top level directory
3  * PROJECT:           ReactOS system libraries
4  * PURPOSE:           System setup
5  * FILE:              dll/win32/syssetup/install.c
6  * PROGRAMER:         Eric Kohl
7  */
8 
9 /* INCLUDES *****************************************************************/
10 
11 #include "precomp.h"
12 
13 #define COBJMACROS
14 
15 #include <io.h>
16 #include <wincon.h>
17 #include <winnls.h>
18 #include <winsvc.h>
19 #include <userenv.h>
20 #include <shlobj.h>
21 #include <shlwapi.h>
22 #include <shobjidl.h>
23 #include <rpcproxy.h>
24 #include <ndk/cmfuncs.h>
25 
26 #define NDEBUG
27 #include <debug.h>
28 
29 //DWORD WINAPI
30 //CMP_WaitNoPendingInstallEvents(DWORD dwTimeout);
31 
32 DWORD WINAPI
33 SetupStartService(LPCWSTR lpServiceName, BOOL bWait);
34 
35 /* GLOBALS ******************************************************************/
36 
37 HINF hSysSetupInf = INVALID_HANDLE_VALUE;
38 ADMIN_INFO AdminInfo;
39 
40 typedef struct _DLG_DATA
41 {
42     HBITMAP hLogoBitmap;
43     HBITMAP hBarBitmap;
44     HWND hWndBarCtrl;
45     DWORD BarCounter;
46     DWORD BarWidth;
47     DWORD BarHeight;
48 } DLG_DATA, *PDLG_DATA;
49 
50 /* FUNCTIONS ****************************************************************/
51 
52 static VOID
53 FatalError(char *pszFmt,...)
54 {
55     char szBuffer[512];
56     va_list ap;
57 
58     va_start(ap, pszFmt);
59     vsprintf(szBuffer, pszFmt, ap);
60     va_end(ap);
61 
62     LogItem(NULL, L"Failed");
63 
64     strcat(szBuffer, "\nRebooting now!");
65     MessageBoxA(NULL,
66                 szBuffer,
67                 "ReactOS Setup",
68                 MB_OK);
69 }
70 
71 static HRESULT
72 CreateShellLink(
73     LPCWSTR pszLinkPath,
74     LPCWSTR pszCmd,
75     LPCWSTR pszArg,
76     LPCWSTR pszDir,
77     LPCWSTR pszIconPath,
78     INT iIconNr,
79     LPCWSTR pszComment)
80 {
81     IShellLinkW *psl;
82     IPersistFile *ppf;
83 
84     HRESULT hr = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLink, (LPVOID*)&psl);
85 
86     if (SUCCEEDED(hr))
87     {
88         hr = IShellLinkW_SetPath(psl, pszCmd);
89 
90         if (pszArg)
91             hr = IShellLinkW_SetArguments(psl, pszArg);
92 
93         if (pszDir)
94             hr = IShellLinkW_SetWorkingDirectory(psl, pszDir);
95 
96         if (pszIconPath)
97             hr = IShellLinkW_SetIconLocation(psl, pszIconPath, iIconNr);
98 
99         if (pszComment)
100             hr = IShellLinkW_SetDescription(psl, pszComment);
101 
102         hr = IShellLinkW_QueryInterface(psl, &IID_IPersistFile, (LPVOID*)&ppf);
103 
104         if (SUCCEEDED(hr))
105         {
106             hr = IPersistFile_Save(ppf, pszLinkPath, TRUE);
107             IPersistFile_Release(ppf);
108         }
109 
110         IShellLinkW_Release(psl);
111     }
112 
113     return hr;
114 }
115 
116 
117 static BOOL
118 CreateShortcut(
119     LPCWSTR pszFolder,
120     LPCWSTR pszName,
121     LPCWSTR pszCommand,
122     LPCWSTR pszDescription,
123     INT iIconNr,
124     LPCWSTR pszWorkingDir)
125 {
126     DWORD dwLen;
127     LPWSTR Ptr;
128     LPWSTR lpFilePart;
129     WCHAR szPath[MAX_PATH];
130     WCHAR szWorkingDirBuf[MAX_PATH];
131 
132     /* If no working directory is provided, try to compute a default one */
133     if (pszWorkingDir == NULL || pszWorkingDir[0] == L'\0')
134     {
135         if (ExpandEnvironmentStringsW(pszCommand, szPath, ARRAYSIZE(szPath)) == 0)
136             wcscpy(szPath, pszCommand);
137 
138         dwLen = GetFullPathNameW(szPath,
139                                  ARRAYSIZE(szWorkingDirBuf),
140                                  szWorkingDirBuf,
141                                  &lpFilePart);
142         if (dwLen != 0 && dwLen <= ARRAYSIZE(szWorkingDirBuf))
143         {
144             /* Since those should only be called with (.exe) files,
145                lpFilePart has not to be NULL */
146             ASSERT(lpFilePart != NULL);
147 
148             /* We're only interested in the path. Cut the file name off.
149                Also remove the trailing backslash unless the working directory
150                is only going to be a drive, i.e. C:\ */
151             *(lpFilePart--) = L'\0';
152             if (!(lpFilePart - szWorkingDirBuf == 2 &&
153                   szWorkingDirBuf[1] == L':' && szWorkingDirBuf[2] == L'\\'))
154             {
155                 *lpFilePart = L'\0';
156             }
157             pszWorkingDir = szWorkingDirBuf;
158         }
159     }
160 
161     /* If we failed to compute a working directory, just do not use one */
162     if (pszWorkingDir && pszWorkingDir[0] == L'\0')
163         pszWorkingDir = NULL;
164 
165     /* Build the shortcut file name */
166     wcscpy(szPath, pszFolder);
167     Ptr = PathAddBackslash(szPath);
168     wcscpy(Ptr, pszName);
169 
170     /* Create the shortcut */
171     return SUCCEEDED(CreateShellLink(szPath,
172                                      pszCommand,
173                                      L"",
174                                      pszWorkingDir,
175                                      /* Special value to indicate no icon */
176                                      (iIconNr != -1 ? pszCommand : NULL),
177                                      iIconNr,
178                                      pszDescription));
179 }
180 
181 
182 static BOOL CreateShortcutsFromSection(HINF hinf, LPWSTR pszSection, LPCWSTR pszFolder)
183 {
184     INFCONTEXT Context;
185     DWORD dwFieldCount;
186     INT iIconNr;
187     WCHAR szCommand[MAX_PATH];
188     WCHAR szName[MAX_PATH];
189     WCHAR szDescription[MAX_PATH];
190     WCHAR szDirectory[MAX_PATH];
191 
192     if (!SetupFindFirstLine(hinf, pszSection, NULL, &Context))
193         return FALSE;
194 
195     do
196     {
197         dwFieldCount = SetupGetFieldCount(&Context);
198         if (dwFieldCount < 3)
199             continue;
200 
201         if (!SetupGetStringFieldW(&Context, 1, szCommand, ARRAYSIZE(szCommand), NULL))
202             continue;
203 
204         if (!SetupGetStringFieldW(&Context, 2, szName, ARRAYSIZE(szName), NULL))
205             continue;
206 
207         if (!SetupGetStringFieldW(&Context, 3, szDescription, ARRAYSIZE(szDescription), NULL))
208             continue;
209 
210         if (dwFieldCount < 4 || !SetupGetIntField(&Context, 4, &iIconNr))
211             iIconNr = -1; /* Special value to indicate no icon */
212 
213         if (dwFieldCount < 5 || !SetupGetStringFieldW(&Context, 5, szDirectory, ARRAYSIZE(szDirectory), NULL))
214             szDirectory[0] = L'\0';
215 
216         wcscat(szName, L".lnk");
217 
218         CreateShortcut(pszFolder, szName, szCommand, szDescription, iIconNr, szDirectory);
219 
220     } while (SetupFindNextLine(&Context, &Context));
221 
222     return TRUE;
223 }
224 
225 static BOOL CreateShortcuts(HINF hinf, LPCWSTR szSection)
226 {
227     INFCONTEXT Context;
228     WCHAR szPath[MAX_PATH];
229     WCHAR szFolder[MAX_PATH];
230     WCHAR szFolderSection[MAX_PATH];
231     INT csidl;
232 
233     CoInitialize(NULL);
234 
235     if (!SetupFindFirstLine(hinf, szSection, NULL, &Context))
236         return FALSE;
237 
238     do
239     {
240         if (SetupGetFieldCount(&Context) < 2)
241             continue;
242 
243         if (!SetupGetStringFieldW(&Context, 0, szFolderSection, ARRAYSIZE(szFolderSection), NULL))
244             continue;
245 
246         if (!SetupGetIntField(&Context, 1, &csidl))
247             continue;
248 
249         if (!SetupGetStringFieldW(&Context, 2, szFolder, ARRAYSIZE(szFolder), NULL))
250             continue;
251 
252         if (FAILED(SHGetFolderPathAndSubDirW(NULL, csidl|CSIDL_FLAG_CREATE, (HANDLE)-1, SHGFP_TYPE_DEFAULT, szFolder, szPath)))
253             continue;
254 
255         CreateShortcutsFromSection(hinf, szFolderSection, szPath);
256 
257     } while (SetupFindNextLine(&Context, &Context));
258 
259     CoUninitialize();
260 
261     return TRUE;
262 }
263 
264 static VOID
265 CreateTempDir(
266     IN LPCWSTR VarName)
267 {
268     WCHAR szTempDir[MAX_PATH];
269     WCHAR szBuffer[MAX_PATH];
270     DWORD dwLength;
271     HKEY hKey;
272 
273     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
274                       L"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment",
275                       0,
276                       KEY_QUERY_VALUE,
277                       &hKey) != ERROR_SUCCESS)
278     {
279         FatalError("Error: %lu\n", GetLastError());
280         return;
281     }
282 
283     /* Get temp dir */
284     dwLength = sizeof(szBuffer);
285     if (RegQueryValueExW(hKey,
286                          VarName,
287                          NULL,
288                          NULL,
289                          (LPBYTE)szBuffer,
290                          &dwLength) != ERROR_SUCCESS)
291     {
292         FatalError("Error: %lu\n", GetLastError());
293         goto cleanup;
294     }
295 
296     /* Expand it */
297     if (!ExpandEnvironmentStringsW(szBuffer, szTempDir, ARRAYSIZE(szTempDir)))
298     {
299         FatalError("Error: %lu\n", GetLastError());
300         goto cleanup;
301     }
302 
303     /* Create profiles directory */
304     if (!CreateDirectoryW(szTempDir, NULL))
305     {
306         if (GetLastError() != ERROR_ALREADY_EXISTS)
307         {
308             FatalError("Error: %lu\n", GetLastError());
309             goto cleanup;
310         }
311     }
312 
313 cleanup:
314     RegCloseKey(hKey);
315 }
316 
317 static BOOL
318 InstallSysSetupInfDevices(VOID)
319 {
320     INFCONTEXT InfContext;
321     WCHAR szLineBuffer[256];
322     DWORD dwLineLength;
323 
324     if (!SetupFindFirstLineW(hSysSetupInf,
325                             L"DeviceInfsToInstall",
326                             NULL,
327                             &InfContext))
328     {
329         return FALSE;
330     }
331 
332     do
333     {
334         if (!SetupGetStringFieldW(&InfContext,
335                                   0,
336                                   szLineBuffer,
337                                   ARRAYSIZE(szLineBuffer),
338                                   &dwLineLength))
339         {
340             return FALSE;
341         }
342 
343         if (!SetupDiInstallClassW(NULL, szLineBuffer, DI_QUIETINSTALL, NULL))
344         {
345             return FALSE;
346         }
347     }
348     while (SetupFindNextLine(&InfContext, &InfContext));
349 
350     return TRUE;
351 }
352 
353 static BOOL
354 InstallSysSetupInfComponents(VOID)
355 {
356     INFCONTEXT InfContext;
357     WCHAR szNameBuffer[256];
358     WCHAR szSectionBuffer[256];
359     HINF hComponentInf = INVALID_HANDLE_VALUE;
360 
361     if (!SetupFindFirstLineW(hSysSetupInf,
362                              L"Infs.Always",
363                              NULL,
364                              &InfContext))
365     {
366         DPRINT("No Inf.Always section found\n");
367     }
368     else
369     {
370         do
371         {
372             if (!SetupGetStringFieldW(&InfContext,
373                                       1, // Get the component name
374                                       szNameBuffer,
375                                       ARRAYSIZE(szNameBuffer),
376                                       NULL))
377             {
378                 FatalError("Error while trying to get component name \n");
379                 return FALSE;
380             }
381 
382             if (!SetupGetStringFieldW(&InfContext,
383                                       2, // Get the component install section
384                                       szSectionBuffer,
385                                       ARRAYSIZE(szSectionBuffer),
386                                       NULL))
387             {
388                 FatalError("Error while trying to get component install section \n");
389                 return FALSE;
390             }
391 
392             DPRINT("Trying to execute install section '%S' from '%S' \n", szSectionBuffer, szNameBuffer);
393 
394             hComponentInf = SetupOpenInfFileW(szNameBuffer,
395                                               NULL,
396                                               INF_STYLE_WIN4,
397                                               NULL);
398 
399             if (hComponentInf == INVALID_HANDLE_VALUE)
400             {
401                 FatalError("SetupOpenInfFileW() failed to open '%S' (Error: %lu)\n", szNameBuffer, GetLastError());
402                 return FALSE;
403             }
404 
405             if (!SetupInstallFromInfSectionW(NULL,
406                                              hComponentInf,
407                                              szSectionBuffer,
408                                              SPINST_ALL,
409                                              NULL,
410                                              NULL,
411                                              SP_COPY_NEWER,
412                                              SetupDefaultQueueCallbackW,
413                                              NULL,
414                                              NULL,
415                                              NULL))
416            {
417                 FatalError("Error while trying to install : %S (Error: %lu)\n", szNameBuffer, GetLastError());
418                 SetupCloseInfFile(hComponentInf);
419                 return FALSE;
420            }
421 
422            SetupCloseInfFile(hComponentInf);
423         }
424         while (SetupFindNextLine(&InfContext, &InfContext));
425     }
426 
427     return TRUE;
428 }
429 
430 
431 
432 BOOL
433 RegisterTypeLibraries(HINF hinf, LPCWSTR szSection)
434 {
435     INFCONTEXT InfContext;
436     BOOL res;
437     WCHAR szName[MAX_PATH];
438     WCHAR szPath[MAX_PATH];
439     INT csidl;
440     LPWSTR p;
441     HMODULE hmod;
442     HRESULT hret;
443 
444     /* Begin iterating the entries in the inf section */
445     res = SetupFindFirstLine(hinf, szSection, NULL, &InfContext);
446     if (!res) return FALSE;
447 
448     do
449     {
450         /* Get the name of the current type library */
451         if (!SetupGetStringFieldW(&InfContext, 1, szName, ARRAYSIZE(szName), NULL))
452         {
453             FatalError("SetupGetStringFieldW failed\n");
454             continue;
455         }
456 
457         if (!SetupGetIntField(&InfContext, 2, &csidl))
458             csidl = CSIDL_SYSTEM;
459 
460         hret = SHGetFolderPathW(NULL, csidl, NULL, 0, szPath);
461         if (FAILED(hret))
462         {
463             FatalError("SHGetFolderPathW failed hret=0x%lx\n", hret);
464             continue;
465         }
466 
467         p = PathAddBackslash(szPath);
468         wcscpy(p, szName);
469 
470         hmod = LoadLibraryW(szName);
471         if (hmod == NULL)
472         {
473             FatalError("LoadLibraryW failed\n");
474             continue;
475         }
476 
477         __wine_register_resources(hmod);
478 
479     } while (SetupFindNextLine(&InfContext, &InfContext));
480 
481     return TRUE;
482 }
483 
484 static BOOL
485 EnableUserModePnpManager(VOID)
486 {
487     SC_HANDLE hSCManager = NULL;
488     SC_HANDLE hService = NULL;
489     BOOL bRet = FALSE;
490 
491     hSCManager = OpenSCManagerW(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);
492     if (hSCManager == NULL)
493     {
494         DPRINT1("Unable to open the service control manager.\n");
495         DPRINT1("Last Error %d\n", GetLastError());
496         goto cleanup;
497     }
498 
499     hService = OpenServiceW(hSCManager,
500                             L"PlugPlay",
501                             SERVICE_CHANGE_CONFIG | SERVICE_START);
502     if (hService == NULL)
503     {
504         DPRINT1("Unable to open PlugPlay service\n");
505         goto cleanup;
506     }
507 
508     bRet = ChangeServiceConfigW(hService,
509                                 SERVICE_NO_CHANGE,
510                                 SERVICE_AUTO_START,
511                                 SERVICE_NO_CHANGE,
512                                 NULL, NULL, NULL,
513                                 NULL, NULL, NULL, NULL);
514     if (!bRet)
515     {
516         DPRINT1("Unable to change the service configuration\n");
517         goto cleanup;
518     }
519 
520     bRet = StartServiceW(hService, 0, NULL);
521     if (!bRet && (GetLastError() != ERROR_SERVICE_ALREADY_RUNNING))
522     {
523         DPRINT1("Unable to start service\n");
524         goto cleanup;
525     }
526 
527     bRet = TRUE;
528 
529 cleanup:
530     if (hService != NULL)
531         CloseServiceHandle(hService);
532     if (hSCManager != NULL)
533         CloseServiceHandle(hSCManager);
534     return bRet;
535 }
536 
537 static INT_PTR CALLBACK
538 StatusMessageWindowProc(
539     IN HWND hwndDlg,
540     IN UINT uMsg,
541     IN WPARAM wParam,
542     IN LPARAM lParam)
543 {
544     PDLG_DATA pDlgData;
545     UNREFERENCED_PARAMETER(wParam);
546 
547     pDlgData = (PDLG_DATA)GetWindowLongPtrW(hwndDlg, GWLP_USERDATA);
548 
549     /* pDlgData is required for each case except WM_INITDIALOG */
550     if (uMsg != WM_INITDIALOG && pDlgData == NULL) return FALSE;
551 
552     switch (uMsg)
553     {
554         case WM_INITDIALOG:
555         {
556             BITMAP bm;
557             WCHAR szMsg[256];
558 
559             /* Allocate pDlgData */
560             pDlgData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pDlgData));
561             if (pDlgData)
562             {
563                 /* Set pDlgData to GWLP_USERDATA, so we can get it for new messages */
564                 SetWindowLongPtrW(hwndDlg, GWLP_USERDATA, (LONG_PTR)pDlgData);
565 
566                 /* Load bitmaps */
567                 pDlgData->hLogoBitmap = LoadImageW(hDllInstance,
568                                                     MAKEINTRESOURCEW(IDB_REACTOS), IMAGE_BITMAP,
569                                                     0, 0, LR_DEFAULTCOLOR);
570 
571                 pDlgData->hBarBitmap = LoadImageW(hDllInstance, MAKEINTRESOURCEW(IDB_LINE),
572                                                 IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
573                 GetObject(pDlgData->hBarBitmap, sizeof(bm), &bm);
574                 pDlgData->BarWidth = bm.bmWidth;
575                 pDlgData->BarHeight = bm.bmHeight;
576 
577                 if (pDlgData->hLogoBitmap && pDlgData->hBarBitmap)
578                 {
579                     if (SetTimer(hwndDlg, IDT_BAR, 20, NULL) == 0)
580                     {
581                         DPRINT1("SetTimer(IDT_BAR) failed: %lu\n", GetLastError());
582                     }
583 
584                     /* Get the animation bar control */
585                     pDlgData->hWndBarCtrl = GetDlgItem(hwndDlg, IDC_BAR);
586                 }
587             }
588 
589             /* Get and set status text */
590             if (!LoadStringW(hDllInstance, IDS_STATUS_INSTALL_DEV, szMsg, ARRAYSIZE(szMsg)))
591                 return FALSE;
592             SetDlgItemTextW(hwndDlg, IDC_STATUSLABEL, szMsg);
593 
594             return TRUE;
595         }
596 
597         case WM_TIMER:
598         {
599             if (pDlgData->hBarBitmap)
600             {
601                 /*
602                  * Default rotation bar image width is 413 (same as logo)
603                  * We can divide 413 by 7 without remainder
604                  */
605                 pDlgData->BarCounter = (pDlgData->BarCounter + 7) % pDlgData->BarWidth;
606                 InvalidateRect(pDlgData->hWndBarCtrl, NULL, FALSE);
607                 UpdateWindow(pDlgData->hWndBarCtrl);
608             }
609             return TRUE;
610         }
611 
612         case WM_DRAWITEM:
613         {
614             LPDRAWITEMSTRUCT lpDis = (LPDRAWITEMSTRUCT)lParam;
615 
616             if (lpDis->CtlID != IDC_BAR)
617             {
618                 return FALSE;
619             }
620 
621             if (pDlgData->hBarBitmap)
622             {
623                 HDC hdcMem;
624                 HGDIOBJ hOld;
625                 DWORD off = pDlgData->BarCounter;
626                 DWORD iw = pDlgData->BarWidth;
627                 DWORD ih = pDlgData->BarHeight;
628 
629                 hdcMem = CreateCompatibleDC(lpDis->hDC);
630                 hOld = SelectObject(hdcMem, pDlgData->hBarBitmap);
631                 BitBlt(lpDis->hDC, off, 0, iw - off, ih, hdcMem, 0, 0, SRCCOPY);
632                 BitBlt(lpDis->hDC, 0, 0, off, ih, hdcMem, iw - off, 0, SRCCOPY);
633                 SelectObject(hdcMem, hOld);
634                 DeleteDC(hdcMem);
635                 return TRUE;
636             }
637             return FALSE;
638         }
639 
640         case WM_DESTROY:
641         {
642             if (pDlgData->hBarBitmap)
643             {
644                 KillTimer(hwndDlg, IDT_BAR);
645             }
646 
647             DeleteObject(pDlgData->hLogoBitmap);
648             DeleteObject(pDlgData->hBarBitmap);
649             HeapFree(GetProcessHeap(), 0, pDlgData);
650             return TRUE;
651         }
652     }
653     return FALSE;
654 }
655 
656 static DWORD WINAPI
657 ShowStatusMessageThread(
658     IN LPVOID lpParameter)
659 {
660     HWND hWnd;
661     MSG Msg;
662     UNREFERENCED_PARAMETER(lpParameter);
663 
664     hWnd = CreateDialogParam(hDllInstance,
665                              MAKEINTRESOURCE(IDD_STATUSWINDOW_DLG),
666                              GetDesktopWindow(),
667                              StatusMessageWindowProc,
668                              (LPARAM)NULL);
669     if (!hWnd)
670         return 0;
671 
672     ShowWindow(hWnd, SW_SHOW);
673 
674     /* Message loop for the Status window */
675     while (GetMessage(&Msg, NULL, 0, 0))
676     {
677         TranslateMessage(&Msg);
678         DispatchMessage(&Msg);
679     }
680 
681     EndDialog(hWnd, 0);
682 
683     return 0;
684 }
685 
686 static LONG
687 ReadRegSzKey(
688     IN HKEY hKey,
689     IN LPCWSTR pszKey,
690     OUT LPWSTR* pValue)
691 {
692     LONG rc;
693     DWORD dwType;
694     DWORD cbData = 0;
695     LPWSTR pwszValue;
696 
697     if (!pValue)
698         return ERROR_INVALID_PARAMETER;
699 
700     *pValue = NULL;
701     rc = RegQueryValueExW(hKey, pszKey, NULL, &dwType, NULL, &cbData);
702     if (rc != ERROR_SUCCESS)
703         return rc;
704     if (dwType != REG_SZ)
705         return ERROR_FILE_NOT_FOUND;
706     pwszValue = HeapAlloc(GetProcessHeap(), 0, cbData + sizeof(WCHAR));
707     if (!pwszValue)
708         return ERROR_NOT_ENOUGH_MEMORY;
709     rc = RegQueryValueExW(hKey, pszKey, NULL, NULL, (LPBYTE)pwszValue, &cbData);
710     if (rc != ERROR_SUCCESS)
711     {
712         HeapFree(GetProcessHeap(), 0, pwszValue);
713         return rc;
714     }
715     /* NULL-terminate the string */
716     pwszValue[cbData / sizeof(WCHAR)] = '\0';
717 
718     *pValue = pwszValue;
719     return ERROR_SUCCESS;
720 }
721 
722 static BOOL
723 IsConsoleBoot(VOID)
724 {
725     HKEY hControlKey = NULL;
726     LPWSTR pwszSystemStartOptions = NULL;
727     LPWSTR pwszCurrentOption, pwszNextOption; /* Pointers into SystemStartOptions */
728     BOOL bConsoleBoot = FALSE;
729     LONG rc;
730 
731     rc = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
732                        L"SYSTEM\\CurrentControlSet\\Control",
733                        0,
734                        KEY_QUERY_VALUE,
735                        &hControlKey);
736     if (rc != ERROR_SUCCESS)
737         goto cleanup;
738 
739     rc = ReadRegSzKey(hControlKey, L"SystemStartOptions", &pwszSystemStartOptions);
740     if (rc != ERROR_SUCCESS)
741         goto cleanup;
742 
743     /* Check for CONSOLE switch in SystemStartOptions */
744     pwszCurrentOption = pwszSystemStartOptions;
745     while (pwszCurrentOption)
746     {
747         pwszNextOption = wcschr(pwszCurrentOption, L' ');
748         if (pwszNextOption)
749             *pwszNextOption = L'\0';
750         if (wcsicmp(pwszCurrentOption, L"CONSOLE") == 0)
751         {
752             DPRINT("Found %S. Switching to console boot\n", pwszCurrentOption);
753             bConsoleBoot = TRUE;
754             goto cleanup;
755         }
756         pwszCurrentOption = pwszNextOption ? pwszNextOption + 1 : NULL;
757     }
758 
759 cleanup:
760     if (hControlKey != NULL)
761         RegCloseKey(hControlKey);
762     if (pwszSystemStartOptions)
763         HeapFree(GetProcessHeap(), 0, pwszSystemStartOptions);
764     return bConsoleBoot;
765 }
766 
767 static BOOL
768 CommonInstall(VOID)
769 {
770     HANDLE hThread = NULL;
771     BOOL bResult = FALSE;
772 
773     hSysSetupInf = SetupOpenInfFileW(L"syssetup.inf",
774                                      NULL,
775                                      INF_STYLE_WIN4,
776                                      NULL);
777     if (hSysSetupInf == INVALID_HANDLE_VALUE)
778     {
779         FatalError("SetupOpenInfFileW() failed to open 'syssetup.inf' (Error: %lu)\n", GetLastError());
780         return FALSE;
781     }
782 
783     if (!InstallSysSetupInfDevices())
784     {
785         FatalError("InstallSysSetupInfDevices() failed!\n");
786         goto Exit;
787     }
788 
789     if(!InstallSysSetupInfComponents())
790     {
791         FatalError("InstallSysSetupInfComponents() failed!\n");
792         goto Exit;
793     }
794 
795     if (!IsConsoleBoot())
796     {
797         hThread = CreateThread(NULL,
798                                0,
799                                ShowStatusMessageThread,
800                                NULL,
801                                0,
802                                NULL);
803     }
804 
805     if (!EnableUserModePnpManager())
806     {
807         FatalError("EnableUserModePnpManager() failed!\n");
808         goto Exit;
809     }
810 
811     if (CMP_WaitNoPendingInstallEvents(INFINITE) != WAIT_OBJECT_0)
812     {
813         FatalError("CMP_WaitNoPendingInstallEvents() failed!\n");
814         goto Exit;
815     }
816 
817     bResult = TRUE;
818 
819 Exit:
820 
821     if (bResult == FALSE)
822     {
823         SetupCloseInfFile(hSysSetupInf);
824     }
825 
826     if (hThread != NULL)
827     {
828         PostThreadMessage(GetThreadId(hThread), WM_QUIT, 0, 0);
829         WaitForSingleObject(hThread, INFINITE);
830         CloseHandle(hThread);
831     }
832 
833     return bResult;
834 }
835 
836 static
837 DWORD
838 InstallLiveCD(VOID)
839 {
840     STARTUPINFOW StartupInfo;
841     PROCESS_INFORMATION ProcessInformation;
842     BOOL bRes;
843 
844     if (!CommonInstall())
845         goto error;
846 
847     /* Install the TCP/IP protocol driver */
848     bRes = InstallNetworkComponent(L"MS_TCPIP");
849     if (!bRes && GetLastError() != ERROR_FILE_NOT_FOUND)
850     {
851         DPRINT("InstallNetworkComponent() failed with error 0x%lx\n", GetLastError());
852     }
853     else
854     {
855         /* Start the TCP/IP protocol driver */
856         SetupStartService(L"Tcpip", FALSE);
857         SetupStartService(L"Dhcp", FALSE);
858         SetupStartService(L"Dnscache", FALSE);
859     }
860 
861     /* Register components */
862     _SEH2_TRY
863     {
864         if (!SetupInstallFromInfSectionW(NULL,
865                                          hSysSetupInf, L"RegistrationPhase2",
866                                          SPINST_ALL,
867                                          0, NULL, 0, NULL, NULL, NULL, NULL))
868         {
869             DPRINT1("SetupInstallFromInfSectionW failed!\n");
870         }
871 
872         RegisterTypeLibraries(hSysSetupInf, L"TypeLibraries");
873     }
874     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
875     {
876         DPRINT1("Catching exception\n");
877     }
878     _SEH2_END;
879 
880     SetupCloseInfFile(hSysSetupInf);
881 
882     /* Run the shell */
883     ZeroMemory(&StartupInfo, sizeof(StartupInfo));
884     StartupInfo.cb = sizeof(StartupInfo);
885     bRes = CreateProcessW(L"userinit.exe",
886                           NULL,
887                           NULL,
888                           NULL,
889                           FALSE,
890                           0,
891                           NULL,
892                           NULL,
893                           &StartupInfo,
894                           &ProcessInformation);
895     if (!bRes)
896         goto error;
897 
898     CloseHandle(ProcessInformation.hThread);
899     CloseHandle(ProcessInformation.hProcess);
900 
901     return 0;
902 
903 error:
904     MessageBoxW(
905         NULL,
906         L"Failed to load LiveCD! You can shutdown your computer, or press ENTER to reboot.",
907         L"ReactOS LiveCD",
908         MB_OK);
909     return 0;
910 }
911 
912 
913 static BOOL
914 SetSetupType(DWORD dwSetupType)
915 {
916     DWORD dwError;
917     HKEY hKey;
918 
919     dwError = RegOpenKeyExW(
920         HKEY_LOCAL_MACHINE,
921         L"SYSTEM\\Setup",
922         0,
923         KEY_SET_VALUE,
924         &hKey);
925     if (dwError != ERROR_SUCCESS)
926         return FALSE;
927 
928     dwError = RegSetValueExW(
929         hKey,
930         L"SetupType",
931         0,
932         REG_DWORD,
933         (LPBYTE)&dwSetupType,
934         sizeof(DWORD));
935     RegCloseKey(hKey);
936     if (dwError != ERROR_SUCCESS)
937         return FALSE;
938 
939     return TRUE;
940 }
941 
942 static DWORD CALLBACK
943 HotkeyThread(LPVOID Parameter)
944 {
945     ATOM hotkey;
946     MSG msg;
947 
948     DPRINT("HotkeyThread start\n");
949 
950     hotkey = GlobalAddAtomW(L"Setup Shift+F10 Hotkey");
951 
952     if (!RegisterHotKey(NULL, hotkey, MOD_SHIFT, VK_F10))
953         DPRINT1("RegisterHotKey failed with %lu\n", GetLastError());
954 
955     while (GetMessage(&msg, NULL, 0, 0))
956     {
957         if (msg.hwnd == NULL && msg.message == WM_HOTKEY && msg.wParam == hotkey)
958         {
959             STARTUPINFOW si = { sizeof(si) };
960             PROCESS_INFORMATION pi;
961 
962             if (CreateProcessW(L"cmd.exe",
963                                NULL,
964                                NULL,
965                                NULL,
966                                FALSE,
967                                CREATE_NEW_CONSOLE,
968                                NULL,
969                                NULL,
970                                &si,
971                                &pi))
972             {
973                 CloseHandle(pi.hProcess);
974                 CloseHandle(pi.hThread);
975             }
976             else
977             {
978                 DPRINT1("Failed to launch command prompt: %lu\n", GetLastError());
979             }
980         }
981     }
982 
983     UnregisterHotKey(NULL, hotkey);
984     GlobalDeleteAtom(hotkey);
985 
986     DPRINT("HotkeyThread terminate\n");
987     return 0;
988 }
989 
990 
991 static
992 BOOL
993 InitializeProgramFilesDir(VOID)
994 {
995     LONG Error;
996     HKEY hKey;
997     DWORD dwLength;
998     WCHAR szProgramFilesDirPath[MAX_PATH];
999     WCHAR szCommonFilesDirPath[MAX_PATH];
1000     WCHAR szBuffer[MAX_PATH];
1001 
1002     /* Load 'Program Files' location */
1003     if (!LoadStringW(hDllInstance,
1004                      IDS_PROGRAMFILES,
1005                      szBuffer,
1006                      ARRAYSIZE(szBuffer)))
1007     {
1008         DPRINT1("Error: %lu\n", GetLastError());
1009         return FALSE;
1010     }
1011 
1012     if (!LoadStringW(hDllInstance,
1013                      IDS_COMMONFILES,
1014                      szCommonFilesDirPath,
1015                      ARRAYSIZE(szCommonFilesDirPath)))
1016     {
1017         DPRINT1("Warning: %lu\n", GetLastError());
1018     }
1019 
1020     /* Expand it */
1021     if (!ExpandEnvironmentStringsW(szBuffer,
1022                                    szProgramFilesDirPath,
1023                                    ARRAYSIZE(szProgramFilesDirPath)))
1024     {
1025         DPRINT1("Error: %lu\n", GetLastError());
1026         return FALSE;
1027     }
1028 
1029     wcscpy(szBuffer, szProgramFilesDirPath);
1030     wcscat(szBuffer, L"\\");
1031     wcscat(szBuffer, szCommonFilesDirPath);
1032 
1033     if (!ExpandEnvironmentStringsW(szBuffer,
1034                                    szCommonFilesDirPath,
1035                                    ARRAYSIZE(szCommonFilesDirPath)))
1036     {
1037         DPRINT1("Warning: %lu\n", GetLastError());
1038     }
1039 
1040     /* Store it */
1041     Error = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1042                           L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion",
1043                           0,
1044                           KEY_SET_VALUE,
1045                           &hKey);
1046     if (Error != ERROR_SUCCESS)
1047     {
1048         DPRINT1("Error: %lu\n", Error);
1049         return FALSE;
1050     }
1051 
1052     dwLength = (wcslen(szProgramFilesDirPath) + 1) * sizeof(WCHAR);
1053     Error = RegSetValueExW(hKey,
1054                            L"ProgramFilesDir",
1055                            0,
1056                            REG_SZ,
1057                            (LPBYTE)szProgramFilesDirPath,
1058                            dwLength);
1059     if (Error != ERROR_SUCCESS)
1060     {
1061         DPRINT1("Error: %lu\n", Error);
1062         RegCloseKey(hKey);
1063         return FALSE;
1064     }
1065 
1066     dwLength = (wcslen(szCommonFilesDirPath) + 1) * sizeof(WCHAR);
1067     Error = RegSetValueExW(hKey,
1068                            L"CommonFilesDir",
1069                            0,
1070                            REG_SZ,
1071                            (LPBYTE)szCommonFilesDirPath,
1072                            dwLength);
1073     if (Error != ERROR_SUCCESS)
1074     {
1075         DPRINT1("Warning: %lu\n", Error);
1076     }
1077 
1078     RegCloseKey(hKey);
1079 
1080     /* Create directory */
1081     // FIXME: Security!
1082     if (!CreateDirectoryW(szProgramFilesDirPath, NULL))
1083     {
1084         if (GetLastError() != ERROR_ALREADY_EXISTS)
1085         {
1086             DPRINT1("Error: %lu\n", GetLastError());
1087             return FALSE;
1088         }
1089     }
1090 
1091     /* Create directory */
1092     // FIXME: Security!
1093     if (!CreateDirectoryW(szCommonFilesDirPath, NULL))
1094     {
1095         if (GetLastError() != ERROR_ALREADY_EXISTS)
1096         {
1097             DPRINT1("Warning: %lu\n", GetLastError());
1098             // return FALSE;
1099         }
1100     }
1101 
1102     return TRUE;
1103 }
1104 
1105 
1106 static
1107 VOID
1108 InitializeDefaultUserLocale(VOID)
1109 {
1110     WCHAR szBuffer[80];
1111     PWSTR ptr;
1112     HKEY hLocaleKey;
1113     DWORD ret;
1114     DWORD dwSize;
1115     LCID lcid;
1116     INT i;
1117 
1118     struct {LCTYPE LCType; PWSTR pValue;} LocaleData[] = {
1119         /* Number */
1120         {LOCALE_SDECIMAL, L"sDecimal"},
1121         {LOCALE_STHOUSAND, L"sThousand"},
1122         {LOCALE_SNEGATIVESIGN, L"sNegativeSign"},
1123         {LOCALE_SPOSITIVESIGN, L"sPositiveSign"},
1124         {LOCALE_SGROUPING, L"sGrouping"},
1125         {LOCALE_SLIST, L"sList"},
1126         {LOCALE_SNATIVEDIGITS, L"sNativeDigits"},
1127         {LOCALE_INEGNUMBER, L"iNegNumber"},
1128         {LOCALE_IDIGITS, L"iDigits"},
1129         {LOCALE_ILZERO, L"iLZero"},
1130         {LOCALE_IMEASURE, L"iMeasure"},
1131         {LOCALE_IDIGITSUBSTITUTION, L"NumShape"},
1132 
1133         /* Currency */
1134         {LOCALE_SCURRENCY, L"sCurrency"},
1135         {LOCALE_SMONDECIMALSEP, L"sMonDecimalSep"},
1136         {LOCALE_SMONTHOUSANDSEP, L"sMonThousandSep"},
1137         {LOCALE_SMONGROUPING, L"sMonGrouping"},
1138         {LOCALE_ICURRENCY, L"iCurrency"},
1139         {LOCALE_INEGCURR, L"iNegCurr"},
1140         {LOCALE_ICURRDIGITS, L"iCurrDigits"},
1141 
1142         /* Time */
1143         {LOCALE_STIMEFORMAT, L"sTimeFormat"},
1144         {LOCALE_STIME, L"sTime"},
1145         {LOCALE_S1159, L"s1159"},
1146         {LOCALE_S2359, L"s2359"},
1147         {LOCALE_ITIME, L"iTime"},
1148         {LOCALE_ITIMEMARKPOSN, L"iTimePrefix"},
1149         {LOCALE_ITLZERO, L"iTLZero"},
1150 
1151         /* Date */
1152         {LOCALE_SLONGDATE, L"sLongDate"},
1153         {LOCALE_SSHORTDATE, L"sShortDate"},
1154         {LOCALE_SDATE, L"sDate"},
1155         {LOCALE_IFIRSTDAYOFWEEK, L"iFirstDayOfWeek"},
1156         {LOCALE_IFIRSTWEEKOFYEAR, L"iFirstWeekOfYear"},
1157         {LOCALE_IDATE, L"iDate"},
1158         {LOCALE_ICALENDARTYPE, L"iCalendarType"},
1159 
1160         /* Misc */
1161         {LOCALE_SCOUNTRY, L"sCountry"},
1162         {LOCALE_SABBREVLANGNAME, L"sLanguage"},
1163         {LOCALE_ICOUNTRY, L"iCountry"},
1164         {0, NULL}};
1165 
1166     ret = RegOpenKeyExW(HKEY_USERS,
1167                         L".DEFAULT\\Control Panel\\International",
1168                         0,
1169                         KEY_READ | KEY_WRITE,
1170                         &hLocaleKey);
1171     if (ret != ERROR_SUCCESS)
1172     {
1173         return;
1174     }
1175 
1176     dwSize = 9 * sizeof(WCHAR);
1177     ret = RegQueryValueExW(hLocaleKey,
1178                            L"Locale",
1179                            NULL,
1180                            NULL,
1181                            (PBYTE)szBuffer,
1182                            &dwSize);
1183     if (ret != ERROR_SUCCESS)
1184         goto done;
1185 
1186     lcid = (LCID)wcstoul(szBuffer, &ptr, 16);
1187     if (lcid == 0)
1188         goto done;
1189 
1190     i = 0;
1191     while (LocaleData[i].pValue != NULL)
1192     {
1193         if (GetLocaleInfoW(lcid,
1194                            LocaleData[i].LCType | LOCALE_NOUSEROVERRIDE,
1195                            szBuffer,
1196                            ARRAYSIZE(szBuffer)))
1197         {
1198             RegSetValueExW(hLocaleKey,
1199                            LocaleData[i].pValue,
1200                            0,
1201                            REG_SZ,
1202                            (PBYTE)szBuffer,
1203                            (wcslen(szBuffer) + 1) * sizeof(WCHAR));
1204         }
1205 
1206         i++;
1207     }
1208 
1209 done:
1210     RegCloseKey(hLocaleKey);
1211 }
1212 
1213 
1214 static
1215 DWORD
1216 SaveDefaultUserHive(VOID)
1217 {
1218     WCHAR szDefaultUserHive[MAX_PATH];
1219     HKEY hUserKey = NULL;
1220     DWORD cchSize;
1221     DWORD dwError;
1222 
1223     DPRINT("SaveDefaultUserHive()\n");
1224 
1225     cchSize = ARRAYSIZE(szDefaultUserHive);
1226     GetDefaultUserProfileDirectoryW(szDefaultUserHive, &cchSize);
1227 
1228     wcscat(szDefaultUserHive, L"\\ntuser.dat");
1229 
1230     dwError = RegOpenKeyExW(HKEY_USERS,
1231                             L".DEFAULT",
1232                             0,
1233                             KEY_READ,
1234                             &hUserKey);
1235     if (dwError != ERROR_SUCCESS)
1236     {
1237         DPRINT1("RegOpenKeyExW() failed (Error %lu)\n", dwError);
1238         return dwError;
1239     }
1240 
1241     pSetupEnablePrivilege(L"SeBackupPrivilege", TRUE);
1242 
1243     /* Save the Default hive */
1244     dwError = RegSaveKeyExW(hUserKey,
1245                             szDefaultUserHive,
1246                             NULL,
1247                             REG_STANDARD_FORMAT);
1248     if (dwError == ERROR_ALREADY_EXISTS)
1249     {
1250         WCHAR szBackupHive[MAX_PATH];
1251 
1252         /* Build the backup hive file name by replacing the extension */
1253         wcscpy(szBackupHive, szDefaultUserHive);
1254         wcscpy(&szBackupHive[wcslen(szBackupHive) - 4], L".bak");
1255 
1256         /* Back up the existing default user hive by renaming it, replacing any possible existing old backup */
1257         if (!MoveFileExW(szDefaultUserHive,
1258                          szBackupHive,
1259                          MOVEFILE_REPLACE_EXISTING))
1260         {
1261             dwError = GetLastError();
1262             DPRINT1("Failed to create a default-user hive backup '%S', MoveFileExW failed (Error %lu)\n",
1263                     szBackupHive, dwError);
1264         }
1265         else
1266         {
1267             /* The backup has been done, retry saving the Default hive */
1268             dwError = RegSaveKeyExW(hUserKey,
1269                                     szDefaultUserHive,
1270                                     NULL,
1271                                     REG_STANDARD_FORMAT);
1272         }
1273     }
1274     if (dwError != ERROR_SUCCESS)
1275     {
1276         DPRINT1("RegSaveKeyExW() failed (Error %lu)\n", dwError);
1277     }
1278 
1279     pSetupEnablePrivilege(L"SeBackupPrivilege", FALSE);
1280 
1281     RegCloseKey(hUserKey);
1282 
1283     return dwError;
1284 }
1285 
1286 
1287 static
1288 DWORD
1289 InstallReactOS(VOID)
1290 {
1291     WCHAR szBuffer[MAX_PATH];
1292     HANDLE token;
1293     TOKEN_PRIVILEGES privs;
1294     HKEY hKey;
1295     HINF hShortcutsInf;
1296     HANDLE hHotkeyThread;
1297     BOOL ret;
1298 
1299     InitializeSetupActionLog(FALSE);
1300     LogItem(NULL, L"Installing ReactOS");
1301 
1302     CreateTempDir(L"TEMP");
1303     CreateTempDir(L"TMP");
1304 
1305     if (!InitializeProgramFilesDir())
1306     {
1307         FatalError("InitializeProgramFilesDir() failed");
1308         return 0;
1309     }
1310 
1311     if (!InitializeProfiles())
1312     {
1313         FatalError("InitializeProfiles() failed");
1314         return 0;
1315     }
1316 
1317     InitializeDefaultUserLocale();
1318 
1319     if (GetWindowsDirectoryW(szBuffer, ARRAYSIZE(szBuffer)))
1320     {
1321         if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1322                           L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
1323                           0,
1324                           KEY_WRITE,
1325                           &hKey) == ERROR_SUCCESS)
1326         {
1327             RegSetValueExW(hKey,
1328                            L"PathName",
1329                            0,
1330                            REG_SZ,
1331                            (LPBYTE)szBuffer,
1332                            (wcslen(szBuffer) + 1) * sizeof(WCHAR));
1333 
1334             RegSetValueExW(hKey,
1335                            L"SystemRoot",
1336                            0,
1337                            REG_SZ,
1338                            (LPBYTE)szBuffer,
1339                            (wcslen(szBuffer) + 1) * sizeof(WCHAR));
1340 
1341             RegCloseKey(hKey);
1342         }
1343 
1344         PathAddBackslash(szBuffer);
1345         wcscat(szBuffer, L"system");
1346         CreateDirectory(szBuffer, NULL);
1347     }
1348 
1349     if (SaveDefaultUserHive() != ERROR_SUCCESS)
1350     {
1351         FatalError("SaveDefaultUserHive() failed");
1352         return 0;
1353     }
1354 
1355     if (!CopySystemProfile(0))
1356     {
1357         FatalError("CopySystemProfile() failed");
1358         return 0;
1359     }
1360 
1361     hHotkeyThread = CreateThread(NULL, 0, HotkeyThread, NULL, 0, NULL);
1362 
1363     if (!CommonInstall())
1364         return 0;
1365 
1366     /* Install the TCP/IP protocol driver */
1367     ret = InstallNetworkComponent(L"MS_TCPIP");
1368     if (!ret && GetLastError() != ERROR_FILE_NOT_FOUND)
1369     {
1370         DPRINT("InstallNetworkComponent() failed with error 0x%lx\n", GetLastError());
1371     }
1372     else
1373     {
1374         /* Start the TCP/IP protocol driver */
1375         SetupStartService(L"Tcpip", FALSE);
1376         SetupStartService(L"Dhcp", FALSE);
1377         SetupStartService(L"Dnscache", FALSE);
1378     }
1379 
1380     InstallWizard();
1381 
1382     InstallSecurity();
1383 
1384     SetAutoAdminLogon();
1385 
1386     hShortcutsInf = SetupOpenInfFileW(L"shortcuts.inf",
1387                                       NULL,
1388                                       INF_STYLE_WIN4,
1389                                       NULL);
1390     if (hShortcutsInf == INVALID_HANDLE_VALUE)
1391     {
1392         FatalError("Failed to open shortcuts.inf");
1393         return 0;
1394     }
1395 
1396     if (!CreateShortcuts(hShortcutsInf, L"ShortcutFolders"))
1397     {
1398         FatalError("CreateShortcuts() failed");
1399         return 0;
1400     }
1401 
1402     SetupCloseInfFile(hShortcutsInf);
1403 
1404     hShortcutsInf = SetupOpenInfFileW(L"rosapps_shortcuts.inf",
1405                                        NULL,
1406                                        INF_STYLE_WIN4,
1407                                        NULL);
1408     if (hShortcutsInf != INVALID_HANDLE_VALUE)
1409     {
1410         if (!CreateShortcuts(hShortcutsInf, L"ShortcutFolders"))
1411         {
1412             FatalError("CreateShortcuts(rosapps) failed");
1413             return 0;
1414         }
1415         SetupCloseInfFile(hShortcutsInf);
1416     }
1417 
1418     SetupCloseInfFile(hSysSetupInf);
1419     SetSetupType(0);
1420 
1421     if (hHotkeyThread)
1422     {
1423         PostThreadMessage(GetThreadId(hHotkeyThread), WM_QUIT, 0, 0);
1424         CloseHandle(hHotkeyThread);
1425     }
1426 
1427     LogItem(NULL, L"Installing ReactOS done");
1428     TerminateSetupActionLog();
1429 
1430     if (AdminInfo.Name != NULL)
1431         RtlFreeHeap(RtlGetProcessHeap(), 0, AdminInfo.Name);
1432 
1433     if (AdminInfo.Domain != NULL)
1434         RtlFreeHeap(RtlGetProcessHeap(), 0, AdminInfo.Domain);
1435 
1436     if (AdminInfo.Password != NULL)
1437         RtlFreeHeap(RtlGetProcessHeap(), 0, AdminInfo.Password);
1438 
1439     /* Get shutdown privilege */
1440     if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token))
1441     {
1442         FatalError("OpenProcessToken() failed!");
1443         return 0;
1444     }
1445     if (!LookupPrivilegeValue(NULL,
1446                               SE_SHUTDOWN_NAME,
1447                               &privs.Privileges[0].Luid))
1448     {
1449         FatalError("LookupPrivilegeValue() failed!");
1450         return 0;
1451     }
1452     privs.PrivilegeCount = 1;
1453     privs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
1454     if (AdjustTokenPrivileges(token,
1455                               FALSE,
1456                               &privs,
1457                               0,
1458                               (PTOKEN_PRIVILEGES)NULL,
1459                               NULL) == 0)
1460     {
1461         FatalError("AdjustTokenPrivileges() failed!");
1462         return 0;
1463     }
1464 
1465     ExitWindowsEx(EWX_REBOOT, 0);
1466     return 0;
1467 }
1468 
1469 
1470 /*
1471  * Standard Windows-compatible export, which dispatches
1472  * to either 'InstallReactOS' or 'InstallLiveCD'.
1473  */
1474 INT
1475 WINAPI
1476 InstallWindowsNt(INT argc, WCHAR** argv)
1477 {
1478     INT i;
1479     PWSTR p;
1480 
1481     for (i = 0; i < argc; ++i)
1482     {
1483         p = argv[i];
1484         if (*p == L'-')
1485         {
1486             p++;
1487 
1488             // NOTE: On Windows, "mini" means "minimal UI", and can be used
1489             // in addition to "newsetup"; these options are not exclusive.
1490             if (_wcsicmp(p, L"newsetup") == 0)
1491                 return (INT)InstallReactOS();
1492             else if (_wcsicmp(p, L"mini") == 0)
1493                 return (INT)InstallLiveCD();
1494 
1495             /* Add support for other switches */
1496         }
1497     }
1498 
1499     return 0;
1500 }
1501 
1502 
1503 /*
1504  * @unimplemented
1505  */
1506 DWORD WINAPI
1507 SetupChangeFontSize(
1508     IN HANDLE hWnd,
1509     IN LPCWSTR lpszFontSize)
1510 {
1511     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1512     return FALSE;
1513 }
1514 
1515 /*
1516  * @unimplemented
1517  */
1518 DWORD WINAPI
1519 SetupChangeLocaleEx(HWND hWnd,
1520                     LCID Lcid,
1521                     LPCWSTR lpSrcRootPath,
1522                     char Unknown,
1523                     DWORD dwUnused1,
1524                     DWORD dwUnused2)
1525 {
1526     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1527     return FALSE;
1528 }
1529 
1530 /*
1531  * @implemented
1532  */
1533 DWORD WINAPI
1534 SetupChangeLocale(HWND hWnd, LCID Lcid)
1535 {
1536     return SetupChangeLocaleEx(hWnd, Lcid, NULL, 0, 0, 0);
1537 }
1538 
1539 
1540 DWORD
1541 WINAPI
1542 SetupStartService(
1543     LPCWSTR lpServiceName,
1544     BOOL bWait)
1545 {
1546     SC_HANDLE hManager = NULL;
1547     SC_HANDLE hService = NULL;
1548     DWORD dwError = ERROR_SUCCESS;
1549 
1550     hManager = OpenSCManagerW(NULL,
1551                               NULL,
1552                               SC_MANAGER_ALL_ACCESS);
1553     if (hManager == NULL)
1554     {
1555         dwError = GetLastError();
1556         goto done;
1557     }
1558 
1559     hService = OpenServiceW(hManager,
1560                             lpServiceName,
1561                             SERVICE_START);
1562     if (hService == NULL)
1563     {
1564         dwError = GetLastError();
1565         goto done;
1566     }
1567 
1568     if (!StartService(hService, 0, NULL))
1569     {
1570         dwError = GetLastError();
1571         goto done;
1572     }
1573 
1574 done:
1575     if (hService != NULL)
1576         CloseServiceHandle(hService);
1577 
1578     if (hManager != NULL)
1579         CloseServiceHandle(hManager);
1580 
1581     return dwError;
1582 }
1583