xref: /reactos/dll/win32/syssetup/install.c (revision bbabe248)
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(szPath);
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     SERVICE_STATUS_PROCESS ServiceStatus;
490     BOOL bRet = FALSE;
491     DWORD BytesNeeded, WaitTime;
492 
493     hSCManager = OpenSCManagerW(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);
494     if (hSCManager == NULL)
495     {
496         DPRINT1("Unable to open the service control manager.\n");
497         DPRINT1("Last Error %d\n", GetLastError());
498         goto cleanup;
499     }
500 
501     hService = OpenServiceW(hSCManager,
502                             L"PlugPlay",
503                             SERVICE_CHANGE_CONFIG | SERVICE_START | SERVICE_QUERY_STATUS);
504     if (hService == NULL)
505     {
506         DPRINT1("Unable to open PlugPlay service\n");
507         goto cleanup;
508     }
509 
510     bRet = ChangeServiceConfigW(hService,
511                                 SERVICE_NO_CHANGE,
512                                 SERVICE_AUTO_START,
513                                 SERVICE_NO_CHANGE,
514                                 NULL, NULL, NULL,
515                                 NULL, NULL, NULL, NULL);
516     if (!bRet)
517     {
518         DPRINT1("Unable to change the service configuration\n");
519         goto cleanup;
520     }
521 
522     bRet = StartServiceW(hService, 0, NULL);
523     if (!bRet && (GetLastError() != ERROR_SERVICE_ALREADY_RUNNING))
524     {
525         DPRINT1("Unable to start service\n");
526         goto cleanup;
527     }
528 
529     while (TRUE)
530     {
531         bRet = QueryServiceStatusEx(hService,
532                                     SC_STATUS_PROCESS_INFO,
533                                     (LPBYTE)&ServiceStatus,
534                                     sizeof(ServiceStatus),
535                                     &BytesNeeded);
536         if (!bRet)
537         {
538             DPRINT1("QueryServiceStatusEx() failed for PlugPlay service (error 0x%x)\n", GetLastError());
539             goto cleanup;
540         }
541 
542         if (ServiceStatus.dwCurrentState != SERVICE_START_PENDING)
543             break;
544 
545         WaitTime = ServiceStatus.dwWaitHint / 10;
546         if (WaitTime < 1000) WaitTime = 1000;
547         else if (WaitTime > 10000) WaitTime = 10000;
548         Sleep(WaitTime);
549     };
550 
551     if (ServiceStatus.dwCurrentState != SERVICE_RUNNING)
552     {
553         bRet = FALSE;
554         DPRINT1("Failed to start PlugPlay service\n");
555         goto cleanup;
556     }
557 
558     bRet = TRUE;
559 
560 cleanup:
561     if (hService != NULL)
562         CloseServiceHandle(hService);
563     if (hSCManager != NULL)
564         CloseServiceHandle(hSCManager);
565     return bRet;
566 }
567 
568 static INT_PTR CALLBACK
569 StatusMessageWindowProc(
570     IN HWND hwndDlg,
571     IN UINT uMsg,
572     IN WPARAM wParam,
573     IN LPARAM lParam)
574 {
575     PDLG_DATA pDlgData;
576     UNREFERENCED_PARAMETER(wParam);
577 
578     pDlgData = (PDLG_DATA)GetWindowLongPtrW(hwndDlg, GWLP_USERDATA);
579 
580     /* pDlgData is required for each case except WM_INITDIALOG */
581     if (uMsg != WM_INITDIALOG && pDlgData == NULL) return FALSE;
582 
583     switch (uMsg)
584     {
585         case WM_INITDIALOG:
586         {
587             BITMAP bm;
588             WCHAR szMsg[256];
589 
590             /* Allocate pDlgData */
591             pDlgData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pDlgData));
592             if (pDlgData)
593             {
594                 /* Set pDlgData to GWLP_USERDATA, so we can get it for new messages */
595                 SetWindowLongPtrW(hwndDlg, GWLP_USERDATA, (LONG_PTR)pDlgData);
596 
597                 /* Load bitmaps */
598                 pDlgData->hLogoBitmap = LoadImageW(hDllInstance,
599                                                     MAKEINTRESOURCEW(IDB_REACTOS), IMAGE_BITMAP,
600                                                     0, 0, LR_DEFAULTCOLOR);
601 
602                 pDlgData->hBarBitmap = LoadImageW(hDllInstance, MAKEINTRESOURCEW(IDB_LINE),
603                                                 IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
604                 GetObject(pDlgData->hBarBitmap, sizeof(bm), &bm);
605                 pDlgData->BarWidth = bm.bmWidth;
606                 pDlgData->BarHeight = bm.bmHeight;
607 
608                 if (pDlgData->hLogoBitmap && pDlgData->hBarBitmap)
609                 {
610                     if (SetTimer(hwndDlg, IDT_BAR, 20, NULL) == 0)
611                     {
612                         DPRINT1("SetTimer(IDT_BAR) failed: %lu\n", GetLastError());
613                     }
614 
615                     /* Get the animation bar control */
616                     pDlgData->hWndBarCtrl = GetDlgItem(hwndDlg, IDC_BAR);
617                 }
618             }
619 
620             /* Get and set status text */
621             if (!LoadStringW(hDllInstance, IDS_STATUS_INSTALL_DEV, szMsg, ARRAYSIZE(szMsg)))
622                 return FALSE;
623             SetDlgItemTextW(hwndDlg, IDC_STATUSLABEL, szMsg);
624 
625             return TRUE;
626         }
627 
628         case WM_TIMER:
629         {
630             if (pDlgData->hBarBitmap)
631             {
632                 /*
633                  * Default rotation bar image width is 413 (same as logo)
634                  * We can divide 413 by 7 without remainder
635                  */
636                 pDlgData->BarCounter = (pDlgData->BarCounter + 7) % pDlgData->BarWidth;
637                 InvalidateRect(pDlgData->hWndBarCtrl, NULL, FALSE);
638                 UpdateWindow(pDlgData->hWndBarCtrl);
639             }
640             return TRUE;
641         }
642 
643         case WM_DRAWITEM:
644         {
645             LPDRAWITEMSTRUCT lpDis = (LPDRAWITEMSTRUCT)lParam;
646 
647             if (lpDis->CtlID != IDC_BAR)
648             {
649                 return FALSE;
650             }
651 
652             if (pDlgData->hBarBitmap)
653             {
654                 HDC hdcMem;
655                 HGDIOBJ hOld;
656                 DWORD off = pDlgData->BarCounter;
657                 DWORD iw = pDlgData->BarWidth;
658                 DWORD ih = pDlgData->BarHeight;
659 
660                 hdcMem = CreateCompatibleDC(lpDis->hDC);
661                 hOld = SelectObject(hdcMem, pDlgData->hBarBitmap);
662                 BitBlt(lpDis->hDC, off, 0, iw - off, ih, hdcMem, 0, 0, SRCCOPY);
663                 BitBlt(lpDis->hDC, 0, 0, off, ih, hdcMem, iw - off, 0, SRCCOPY);
664                 SelectObject(hdcMem, hOld);
665                 DeleteDC(hdcMem);
666                 return TRUE;
667             }
668             return FALSE;
669         }
670 
671         case WM_DESTROY:
672         {
673             if (pDlgData->hBarBitmap)
674             {
675                 KillTimer(hwndDlg, IDT_BAR);
676             }
677 
678             DeleteObject(pDlgData->hLogoBitmap);
679             DeleteObject(pDlgData->hBarBitmap);
680             HeapFree(GetProcessHeap(), 0, pDlgData);
681             return TRUE;
682         }
683     }
684     return FALSE;
685 }
686 
687 static DWORD WINAPI
688 ShowStatusMessageThread(
689     IN LPVOID lpParameter)
690 {
691     HWND hWnd;
692     MSG Msg;
693     UNREFERENCED_PARAMETER(lpParameter);
694 
695     hWnd = CreateDialogParam(hDllInstance,
696                              MAKEINTRESOURCE(IDD_STATUSWINDOW_DLG),
697                              GetDesktopWindow(),
698                              StatusMessageWindowProc,
699                              (LPARAM)NULL);
700     if (!hWnd)
701         return 0;
702 
703     ShowWindow(hWnd, SW_SHOW);
704 
705     /* Message loop for the Status window */
706     while (GetMessage(&Msg, NULL, 0, 0))
707     {
708         TranslateMessage(&Msg);
709         DispatchMessage(&Msg);
710     }
711 
712     EndDialog(hWnd, 0);
713 
714     return 0;
715 }
716 
717 static LONG
718 ReadRegSzKey(
719     IN HKEY hKey,
720     IN LPCWSTR pszKey,
721     OUT LPWSTR* pValue)
722 {
723     LONG rc;
724     DWORD dwType;
725     DWORD cbData = 0;
726     LPWSTR pwszValue;
727 
728     if (!pValue)
729         return ERROR_INVALID_PARAMETER;
730 
731     *pValue = NULL;
732     rc = RegQueryValueExW(hKey, pszKey, NULL, &dwType, NULL, &cbData);
733     if (rc != ERROR_SUCCESS)
734         return rc;
735     if (dwType != REG_SZ)
736         return ERROR_FILE_NOT_FOUND;
737     pwszValue = HeapAlloc(GetProcessHeap(), 0, cbData + sizeof(WCHAR));
738     if (!pwszValue)
739         return ERROR_NOT_ENOUGH_MEMORY;
740     rc = RegQueryValueExW(hKey, pszKey, NULL, NULL, (LPBYTE)pwszValue, &cbData);
741     if (rc != ERROR_SUCCESS)
742     {
743         HeapFree(GetProcessHeap(), 0, pwszValue);
744         return rc;
745     }
746     /* NULL-terminate the string */
747     pwszValue[cbData / sizeof(WCHAR)] = '\0';
748 
749     *pValue = pwszValue;
750     return ERROR_SUCCESS;
751 }
752 
753 static BOOL
754 IsConsoleBoot(VOID)
755 {
756     HKEY hControlKey = NULL;
757     LPWSTR pwszSystemStartOptions = NULL;
758     LPWSTR pwszCurrentOption, pwszNextOption; /* Pointers into SystemStartOptions */
759     BOOL bConsoleBoot = FALSE;
760     LONG rc;
761 
762     rc = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
763                        L"SYSTEM\\CurrentControlSet\\Control",
764                        0,
765                        KEY_QUERY_VALUE,
766                        &hControlKey);
767     if (rc != ERROR_SUCCESS)
768         goto cleanup;
769 
770     rc = ReadRegSzKey(hControlKey, L"SystemStartOptions", &pwszSystemStartOptions);
771     if (rc != ERROR_SUCCESS)
772         goto cleanup;
773 
774     /* Check for CONSOLE switch in SystemStartOptions */
775     pwszCurrentOption = pwszSystemStartOptions;
776     while (pwszCurrentOption)
777     {
778         pwszNextOption = wcschr(pwszCurrentOption, L' ');
779         if (pwszNextOption)
780             *pwszNextOption = L'\0';
781         if (wcsicmp(pwszCurrentOption, L"CONSOLE") == 0)
782         {
783             DPRINT("Found %S. Switching to console boot\n", pwszCurrentOption);
784             bConsoleBoot = TRUE;
785             goto cleanup;
786         }
787         pwszCurrentOption = pwszNextOption ? pwszNextOption + 1 : NULL;
788     }
789 
790 cleanup:
791     if (hControlKey != NULL)
792         RegCloseKey(hControlKey);
793     if (pwszSystemStartOptions)
794         HeapFree(GetProcessHeap(), 0, pwszSystemStartOptions);
795     return bConsoleBoot;
796 }
797 
798 static BOOL
799 CommonInstall(VOID)
800 {
801     HANDLE hThread = NULL;
802     BOOL bResult = FALSE;
803 
804     hSysSetupInf = SetupOpenInfFileW(L"syssetup.inf",
805                                      NULL,
806                                      INF_STYLE_WIN4,
807                                      NULL);
808     if (hSysSetupInf == INVALID_HANDLE_VALUE)
809     {
810         FatalError("SetupOpenInfFileW() failed to open 'syssetup.inf' (Error: %lu)\n", GetLastError());
811         return FALSE;
812     }
813 
814     if (!InstallSysSetupInfDevices())
815     {
816         FatalError("InstallSysSetupInfDevices() failed!\n");
817         goto Exit;
818     }
819 
820     if(!InstallSysSetupInfComponents())
821     {
822         FatalError("InstallSysSetupInfComponents() failed!\n");
823         goto Exit;
824     }
825 
826     if (!IsConsoleBoot())
827     {
828         hThread = CreateThread(NULL,
829                                0,
830                                ShowStatusMessageThread,
831                                NULL,
832                                0,
833                                NULL);
834     }
835 
836     if (!EnableUserModePnpManager())
837     {
838         FatalError("EnableUserModePnpManager() failed!\n");
839         goto Exit;
840     }
841 
842     if (CMP_WaitNoPendingInstallEvents(INFINITE) != WAIT_OBJECT_0)
843     {
844         FatalError("CMP_WaitNoPendingInstallEvents() failed!\n");
845         goto Exit;
846     }
847 
848     bResult = TRUE;
849 
850 Exit:
851 
852     if (bResult == FALSE)
853     {
854         SetupCloseInfFile(hSysSetupInf);
855     }
856 
857     if (hThread != NULL)
858     {
859         PostThreadMessage(GetThreadId(hThread), WM_QUIT, 0, 0);
860         WaitForSingleObject(hThread, INFINITE);
861         CloseHandle(hThread);
862     }
863 
864     return bResult;
865 }
866 
867 static
868 DWORD
869 InstallLiveCD(VOID)
870 {
871     STARTUPINFOW StartupInfo;
872     PROCESS_INFORMATION ProcessInformation;
873     BOOL bRes;
874 
875     if (!CommonInstall())
876         goto error;
877 
878     /* Install the TCP/IP protocol driver */
879     bRes = InstallNetworkComponent(L"MS_TCPIP");
880     if (!bRes && GetLastError() != ERROR_FILE_NOT_FOUND)
881     {
882         DPRINT("InstallNetworkComponent() failed with error 0x%lx\n", GetLastError());
883     }
884     else
885     {
886         /* Start the TCP/IP protocol driver */
887         SetupStartService(L"Tcpip", FALSE);
888         SetupStartService(L"Dhcp", FALSE);
889         SetupStartService(L"Dnscache", FALSE);
890     }
891 
892     /* Register components */
893     _SEH2_TRY
894     {
895         if (!SetupInstallFromInfSectionW(NULL,
896                                          hSysSetupInf, L"RegistrationPhase2",
897                                          SPINST_ALL,
898                                          0, NULL, 0, NULL, NULL, NULL, NULL))
899         {
900             DPRINT1("SetupInstallFromInfSectionW failed!\n");
901         }
902 
903         RegisterTypeLibraries(hSysSetupInf, L"TypeLibraries");
904     }
905     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
906     {
907         DPRINT1("Catching exception\n");
908     }
909     _SEH2_END;
910 
911     SetupCloseInfFile(hSysSetupInf);
912 
913     /* Run the shell */
914     ZeroMemory(&StartupInfo, sizeof(StartupInfo));
915     StartupInfo.cb = sizeof(StartupInfo);
916     bRes = CreateProcessW(L"userinit.exe",
917                           NULL,
918                           NULL,
919                           NULL,
920                           FALSE,
921                           0,
922                           NULL,
923                           NULL,
924                           &StartupInfo,
925                           &ProcessInformation);
926     if (!bRes)
927         goto error;
928 
929     CloseHandle(ProcessInformation.hThread);
930     CloseHandle(ProcessInformation.hProcess);
931 
932     return 0;
933 
934 error:
935     MessageBoxW(
936         NULL,
937         L"Failed to load LiveCD! You can shutdown your computer, or press ENTER to reboot.",
938         L"ReactOS LiveCD",
939         MB_OK);
940     return 0;
941 }
942 
943 
944 static BOOL
945 SetSetupType(DWORD dwSetupType)
946 {
947     DWORD dwError;
948     HKEY hKey;
949 
950     dwError = RegOpenKeyExW(
951         HKEY_LOCAL_MACHINE,
952         L"SYSTEM\\Setup",
953         0,
954         KEY_SET_VALUE,
955         &hKey);
956     if (dwError != ERROR_SUCCESS)
957         return FALSE;
958 
959     dwError = RegSetValueExW(
960         hKey,
961         L"SetupType",
962         0,
963         REG_DWORD,
964         (LPBYTE)&dwSetupType,
965         sizeof(DWORD));
966     RegCloseKey(hKey);
967     if (dwError != ERROR_SUCCESS)
968         return FALSE;
969 
970     return TRUE;
971 }
972 
973 static DWORD CALLBACK
974 HotkeyThread(LPVOID Parameter)
975 {
976     ATOM hotkey;
977     MSG msg;
978 
979     DPRINT("HotkeyThread start\n");
980 
981     hotkey = GlobalAddAtomW(L"Setup Shift+F10 Hotkey");
982 
983     if (!RegisterHotKey(NULL, hotkey, MOD_SHIFT, VK_F10))
984         DPRINT1("RegisterHotKey failed with %lu\n", GetLastError());
985 
986     while (GetMessage(&msg, NULL, 0, 0))
987     {
988         if (msg.hwnd == NULL && msg.message == WM_HOTKEY && msg.wParam == hotkey)
989         {
990             STARTUPINFOW si = { sizeof(si) };
991             PROCESS_INFORMATION pi;
992 
993             if (CreateProcessW(L"cmd.exe",
994                                NULL,
995                                NULL,
996                                NULL,
997                                FALSE,
998                                CREATE_NEW_CONSOLE,
999                                NULL,
1000                                NULL,
1001                                &si,
1002                                &pi))
1003             {
1004                 CloseHandle(pi.hProcess);
1005                 CloseHandle(pi.hThread);
1006             }
1007             else
1008             {
1009                 DPRINT1("Failed to launch command prompt: %lu\n", GetLastError());
1010             }
1011         }
1012     }
1013 
1014     UnregisterHotKey(NULL, hotkey);
1015     GlobalDeleteAtom(hotkey);
1016 
1017     DPRINT("HotkeyThread terminate\n");
1018     return 0;
1019 }
1020 
1021 
1022 static
1023 BOOL
1024 InitializeProgramFilesDir(VOID)
1025 {
1026     LONG Error;
1027     HKEY hKey;
1028     DWORD dwLength;
1029     WCHAR szProgramFilesDirPath[MAX_PATH];
1030     WCHAR szCommonFilesDirPath[MAX_PATH];
1031     WCHAR szBuffer[MAX_PATH];
1032 
1033     /* Load 'Program Files' location */
1034     if (!LoadStringW(hDllInstance,
1035                      IDS_PROGRAMFILES,
1036                      szBuffer,
1037                      ARRAYSIZE(szBuffer)))
1038     {
1039         DPRINT1("Error: %lu\n", GetLastError());
1040         return FALSE;
1041     }
1042 
1043     if (!LoadStringW(hDllInstance,
1044                      IDS_COMMONFILES,
1045                      szCommonFilesDirPath,
1046                      ARRAYSIZE(szCommonFilesDirPath)))
1047     {
1048         DPRINT1("Warning: %lu\n", GetLastError());
1049     }
1050 
1051     /* Expand it */
1052     if (!ExpandEnvironmentStringsW(szBuffer,
1053                                    szProgramFilesDirPath,
1054                                    ARRAYSIZE(szProgramFilesDirPath)))
1055     {
1056         DPRINT1("Error: %lu\n", GetLastError());
1057         return FALSE;
1058     }
1059 
1060     wcscpy(szBuffer, szProgramFilesDirPath);
1061     wcscat(szBuffer, L"\\");
1062     wcscat(szBuffer, szCommonFilesDirPath);
1063 
1064     if (!ExpandEnvironmentStringsW(szBuffer,
1065                                    szCommonFilesDirPath,
1066                                    ARRAYSIZE(szCommonFilesDirPath)))
1067     {
1068         DPRINT1("Warning: %lu\n", GetLastError());
1069     }
1070 
1071     /* Store it */
1072     Error = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1073                           L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion",
1074                           0,
1075                           KEY_SET_VALUE,
1076                           &hKey);
1077     if (Error != ERROR_SUCCESS)
1078     {
1079         DPRINT1("Error: %lu\n", Error);
1080         return FALSE;
1081     }
1082 
1083     dwLength = (wcslen(szProgramFilesDirPath) + 1) * sizeof(WCHAR);
1084     Error = RegSetValueExW(hKey,
1085                            L"ProgramFilesDir",
1086                            0,
1087                            REG_SZ,
1088                            (LPBYTE)szProgramFilesDirPath,
1089                            dwLength);
1090     if (Error != ERROR_SUCCESS)
1091     {
1092         DPRINT1("Error: %lu\n", Error);
1093         RegCloseKey(hKey);
1094         return FALSE;
1095     }
1096 
1097     dwLength = (wcslen(szCommonFilesDirPath) + 1) * sizeof(WCHAR);
1098     Error = RegSetValueExW(hKey,
1099                            L"CommonFilesDir",
1100                            0,
1101                            REG_SZ,
1102                            (LPBYTE)szCommonFilesDirPath,
1103                            dwLength);
1104     if (Error != ERROR_SUCCESS)
1105     {
1106         DPRINT1("Warning: %lu\n", Error);
1107     }
1108 
1109     RegCloseKey(hKey);
1110 
1111     /* Create directory */
1112     // FIXME: Security!
1113     if (!CreateDirectoryW(szProgramFilesDirPath, NULL))
1114     {
1115         if (GetLastError() != ERROR_ALREADY_EXISTS)
1116         {
1117             DPRINT1("Error: %lu\n", GetLastError());
1118             return FALSE;
1119         }
1120     }
1121 
1122     /* Create directory */
1123     // FIXME: Security!
1124     if (!CreateDirectoryW(szCommonFilesDirPath, NULL))
1125     {
1126         if (GetLastError() != ERROR_ALREADY_EXISTS)
1127         {
1128             DPRINT1("Warning: %lu\n", GetLastError());
1129             // return FALSE;
1130         }
1131     }
1132 
1133     return TRUE;
1134 }
1135 
1136 
1137 static
1138 VOID
1139 InitializeDefaultUserLocale(VOID)
1140 {
1141     WCHAR szBuffer[80];
1142     PWSTR ptr;
1143     HKEY hLocaleKey;
1144     DWORD ret;
1145     DWORD dwSize;
1146     LCID lcid;
1147     INT i;
1148 
1149     struct {LCTYPE LCType; PWSTR pValue;} LocaleData[] = {
1150         /* Number */
1151         {LOCALE_SDECIMAL, L"sDecimal"},
1152         {LOCALE_STHOUSAND, L"sThousand"},
1153         {LOCALE_SNEGATIVESIGN, L"sNegativeSign"},
1154         {LOCALE_SPOSITIVESIGN, L"sPositiveSign"},
1155         {LOCALE_SGROUPING, L"sGrouping"},
1156         {LOCALE_SLIST, L"sList"},
1157         {LOCALE_SNATIVEDIGITS, L"sNativeDigits"},
1158         {LOCALE_INEGNUMBER, L"iNegNumber"},
1159         {LOCALE_IDIGITS, L"iDigits"},
1160         {LOCALE_ILZERO, L"iLZero"},
1161         {LOCALE_IMEASURE, L"iMeasure"},
1162         {LOCALE_IDIGITSUBSTITUTION, L"NumShape"},
1163 
1164         /* Currency */
1165         {LOCALE_SCURRENCY, L"sCurrency"},
1166         {LOCALE_SMONDECIMALSEP, L"sMonDecimalSep"},
1167         {LOCALE_SMONTHOUSANDSEP, L"sMonThousandSep"},
1168         {LOCALE_SMONGROUPING, L"sMonGrouping"},
1169         {LOCALE_ICURRENCY, L"iCurrency"},
1170         {LOCALE_INEGCURR, L"iNegCurr"},
1171         {LOCALE_ICURRDIGITS, L"iCurrDigits"},
1172 
1173         /* Time */
1174         {LOCALE_STIMEFORMAT, L"sTimeFormat"},
1175         {LOCALE_STIME, L"sTime"},
1176         {LOCALE_S1159, L"s1159"},
1177         {LOCALE_S2359, L"s2359"},
1178         {LOCALE_ITIME, L"iTime"},
1179         {LOCALE_ITIMEMARKPOSN, L"iTimePrefix"},
1180         {LOCALE_ITLZERO, L"iTLZero"},
1181 
1182         /* Date */
1183         {LOCALE_SLONGDATE, L"sLongDate"},
1184         {LOCALE_SSHORTDATE, L"sShortDate"},
1185         {LOCALE_SDATE, L"sDate"},
1186         {LOCALE_IFIRSTDAYOFWEEK, L"iFirstDayOfWeek"},
1187         {LOCALE_IFIRSTWEEKOFYEAR, L"iFirstWeekOfYear"},
1188         {LOCALE_IDATE, L"iDate"},
1189         {LOCALE_ICALENDARTYPE, L"iCalendarType"},
1190 
1191         /* Misc */
1192         {LOCALE_SCOUNTRY, L"sCountry"},
1193         {LOCALE_SABBREVLANGNAME, L"sLanguage"},
1194         {LOCALE_ICOUNTRY, L"iCountry"},
1195         {0, NULL}};
1196 
1197     ret = RegOpenKeyExW(HKEY_USERS,
1198                         L".DEFAULT\\Control Panel\\International",
1199                         0,
1200                         KEY_READ | KEY_WRITE,
1201                         &hLocaleKey);
1202     if (ret != ERROR_SUCCESS)
1203     {
1204         return;
1205     }
1206 
1207     dwSize = 9 * sizeof(WCHAR);
1208     ret = RegQueryValueExW(hLocaleKey,
1209                            L"Locale",
1210                            NULL,
1211                            NULL,
1212                            (PBYTE)szBuffer,
1213                            &dwSize);
1214     if (ret != ERROR_SUCCESS)
1215         goto done;
1216 
1217     lcid = (LCID)wcstoul(szBuffer, &ptr, 16);
1218     if (lcid == 0)
1219         goto done;
1220 
1221     i = 0;
1222     while (LocaleData[i].pValue != NULL)
1223     {
1224         if (GetLocaleInfoW(lcid,
1225                            LocaleData[i].LCType | LOCALE_NOUSEROVERRIDE,
1226                            szBuffer,
1227                            ARRAYSIZE(szBuffer)))
1228         {
1229             RegSetValueExW(hLocaleKey,
1230                            LocaleData[i].pValue,
1231                            0,
1232                            REG_SZ,
1233                            (PBYTE)szBuffer,
1234                            (wcslen(szBuffer) + 1) * sizeof(WCHAR));
1235         }
1236 
1237         i++;
1238     }
1239 
1240 done:
1241     RegCloseKey(hLocaleKey);
1242 }
1243 
1244 
1245 static
1246 DWORD
1247 SaveDefaultUserHive(VOID)
1248 {
1249     WCHAR szDefaultUserHive[MAX_PATH];
1250     HKEY hUserKey = NULL;
1251     DWORD cchSize;
1252     DWORD dwError;
1253 
1254     DPRINT("SaveDefaultUserHive()\n");
1255 
1256     cchSize = ARRAYSIZE(szDefaultUserHive);
1257     GetDefaultUserProfileDirectoryW(szDefaultUserHive, &cchSize);
1258 
1259     wcscat(szDefaultUserHive, L"\\ntuser.dat");
1260 
1261     dwError = RegOpenKeyExW(HKEY_USERS,
1262                             L".DEFAULT",
1263                             0,
1264                             KEY_READ,
1265                             &hUserKey);
1266     if (dwError != ERROR_SUCCESS)
1267     {
1268         DPRINT1("RegOpenKeyExW() failed (Error %lu)\n", dwError);
1269         return dwError;
1270     }
1271 
1272     pSetupEnablePrivilege(L"SeBackupPrivilege", TRUE);
1273 
1274     /* Save the Default hive */
1275     dwError = RegSaveKeyExW(hUserKey,
1276                             szDefaultUserHive,
1277                             NULL,
1278                             REG_STANDARD_FORMAT);
1279     if (dwError == ERROR_ALREADY_EXISTS)
1280     {
1281         WCHAR szBackupHive[MAX_PATH];
1282 
1283         /* Build the backup hive file name by replacing the extension */
1284         wcscpy(szBackupHive, szDefaultUserHive);
1285         wcscpy(&szBackupHive[wcslen(szBackupHive) - 4], L".bak");
1286 
1287         /* Back up the existing default user hive by renaming it, replacing any possible existing old backup */
1288         if (!MoveFileExW(szDefaultUserHive,
1289                          szBackupHive,
1290                          MOVEFILE_REPLACE_EXISTING))
1291         {
1292             dwError = GetLastError();
1293             DPRINT1("Failed to create a default-user hive backup '%S', MoveFileExW failed (Error %lu)\n",
1294                     szBackupHive, dwError);
1295         }
1296         else
1297         {
1298             /* The backup has been done, retry saving the Default hive */
1299             dwError = RegSaveKeyExW(hUserKey,
1300                                     szDefaultUserHive,
1301                                     NULL,
1302                                     REG_STANDARD_FORMAT);
1303         }
1304     }
1305     if (dwError != ERROR_SUCCESS)
1306     {
1307         DPRINT1("RegSaveKeyExW() failed (Error %lu)\n", dwError);
1308     }
1309 
1310     pSetupEnablePrivilege(L"SeBackupPrivilege", FALSE);
1311 
1312     RegCloseKey(hUserKey);
1313 
1314     return dwError;
1315 }
1316 
1317 
1318 static
1319 DWORD
1320 InstallReactOS(VOID)
1321 {
1322     WCHAR szBuffer[MAX_PATH];
1323     HANDLE token;
1324     TOKEN_PRIVILEGES privs;
1325     HKEY hKey;
1326     HINF hShortcutsInf;
1327     HANDLE hHotkeyThread;
1328     BOOL ret;
1329 
1330     InitializeSetupActionLog(FALSE);
1331     LogItem(NULL, L"Installing ReactOS");
1332 
1333     CreateTempDir(L"TEMP");
1334     CreateTempDir(L"TMP");
1335 
1336     if (!InitializeProgramFilesDir())
1337     {
1338         FatalError("InitializeProgramFilesDir() failed");
1339         return 0;
1340     }
1341 
1342     if (!InitializeProfiles())
1343     {
1344         FatalError("InitializeProfiles() failed");
1345         return 0;
1346     }
1347 
1348     InitializeDefaultUserLocale();
1349 
1350     if (GetWindowsDirectoryW(szBuffer, ARRAYSIZE(szBuffer)))
1351     {
1352         if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1353                           L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
1354                           0,
1355                           KEY_WRITE,
1356                           &hKey) == ERROR_SUCCESS)
1357         {
1358             RegSetValueExW(hKey,
1359                            L"PathName",
1360                            0,
1361                            REG_SZ,
1362                            (LPBYTE)szBuffer,
1363                            (wcslen(szBuffer) + 1) * sizeof(WCHAR));
1364 
1365             RegSetValueExW(hKey,
1366                            L"SystemRoot",
1367                            0,
1368                            REG_SZ,
1369                            (LPBYTE)szBuffer,
1370                            (wcslen(szBuffer) + 1) * sizeof(WCHAR));
1371 
1372             RegCloseKey(hKey);
1373         }
1374 
1375         PathAddBackslash(szBuffer);
1376         wcscat(szBuffer, L"system");
1377         CreateDirectory(szBuffer, NULL);
1378     }
1379 
1380     if (SaveDefaultUserHive() != ERROR_SUCCESS)
1381     {
1382         FatalError("SaveDefaultUserHive() failed");
1383         return 0;
1384     }
1385 
1386     if (!CopySystemProfile(0))
1387     {
1388         FatalError("CopySystemProfile() failed");
1389         return 0;
1390     }
1391 
1392     hHotkeyThread = CreateThread(NULL, 0, HotkeyThread, NULL, 0, NULL);
1393 
1394     if (!CommonInstall())
1395         return 0;
1396 
1397     /* Install the TCP/IP protocol driver */
1398     ret = InstallNetworkComponent(L"MS_TCPIP");
1399     if (!ret && GetLastError() != ERROR_FILE_NOT_FOUND)
1400     {
1401         DPRINT("InstallNetworkComponent() failed with error 0x%lx\n", GetLastError());
1402     }
1403     else
1404     {
1405         /* Start the TCP/IP protocol driver */
1406         SetupStartService(L"Tcpip", FALSE);
1407         SetupStartService(L"Dhcp", FALSE);
1408         SetupStartService(L"Dnscache", FALSE);
1409     }
1410 
1411     InstallWizard();
1412 
1413     InstallSecurity();
1414 
1415     SetAutoAdminLogon();
1416 
1417     hShortcutsInf = SetupOpenInfFileW(L"shortcuts.inf",
1418                                       NULL,
1419                                       INF_STYLE_WIN4,
1420                                       NULL);
1421     if (hShortcutsInf == INVALID_HANDLE_VALUE)
1422     {
1423         FatalError("Failed to open shortcuts.inf");
1424         return 0;
1425     }
1426 
1427     if (!CreateShortcuts(hShortcutsInf, L"ShortcutFolders"))
1428     {
1429         FatalError("CreateShortcuts() failed");
1430         return 0;
1431     }
1432 
1433     SetupCloseInfFile(hShortcutsInf);
1434 
1435     hShortcutsInf = SetupOpenInfFileW(L"rosapps_shortcuts.inf",
1436                                        NULL,
1437                                        INF_STYLE_WIN4,
1438                                        NULL);
1439     if (hShortcutsInf != INVALID_HANDLE_VALUE)
1440     {
1441         if (!CreateShortcuts(hShortcutsInf, L"ShortcutFolders"))
1442         {
1443             FatalError("CreateShortcuts(rosapps) failed");
1444             return 0;
1445         }
1446         SetupCloseInfFile(hShortcutsInf);
1447     }
1448 
1449     SetupCloseInfFile(hSysSetupInf);
1450     SetSetupType(0);
1451 
1452     if (hHotkeyThread)
1453     {
1454         PostThreadMessage(GetThreadId(hHotkeyThread), WM_QUIT, 0, 0);
1455         CloseHandle(hHotkeyThread);
1456     }
1457 
1458     LogItem(NULL, L"Installing ReactOS done");
1459     TerminateSetupActionLog();
1460 
1461     if (AdminInfo.Name != NULL)
1462         RtlFreeHeap(RtlGetProcessHeap(), 0, AdminInfo.Name);
1463 
1464     if (AdminInfo.Domain != NULL)
1465         RtlFreeHeap(RtlGetProcessHeap(), 0, AdminInfo.Domain);
1466 
1467     if (AdminInfo.Password != NULL)
1468         RtlFreeHeap(RtlGetProcessHeap(), 0, AdminInfo.Password);
1469 
1470     /* Get shutdown privilege */
1471     if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token))
1472     {
1473         FatalError("OpenProcessToken() failed!");
1474         return 0;
1475     }
1476     if (!LookupPrivilegeValue(NULL,
1477                               SE_SHUTDOWN_NAME,
1478                               &privs.Privileges[0].Luid))
1479     {
1480         FatalError("LookupPrivilegeValue() failed!");
1481         return 0;
1482     }
1483     privs.PrivilegeCount = 1;
1484     privs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
1485     if (AdjustTokenPrivileges(token,
1486                               FALSE,
1487                               &privs,
1488                               0,
1489                               (PTOKEN_PRIVILEGES)NULL,
1490                               NULL) == 0)
1491     {
1492         FatalError("AdjustTokenPrivileges() failed!");
1493         return 0;
1494     }
1495 
1496     ExitWindowsEx(EWX_REBOOT, 0);
1497     return 0;
1498 }
1499 
1500 
1501 /*
1502  * Standard Windows-compatible export, which dispatches
1503  * to either 'InstallReactOS' or 'InstallLiveCD'.
1504  */
1505 INT
1506 WINAPI
1507 InstallWindowsNt(INT argc, WCHAR** argv)
1508 {
1509     INT i;
1510     PWSTR p;
1511 
1512     for (i = 0; i < argc; ++i)
1513     {
1514         p = argv[i];
1515         if (*p == L'-')
1516         {
1517             p++;
1518 
1519             // NOTE: On Windows, "mini" means "minimal UI", and can be used
1520             // in addition to "newsetup"; these options are not exclusive.
1521             if (_wcsicmp(p, L"newsetup") == 0)
1522                 return (INT)InstallReactOS();
1523             else if (_wcsicmp(p, L"mini") == 0)
1524                 return (INT)InstallLiveCD();
1525 
1526             /* Add support for other switches */
1527         }
1528     }
1529 
1530     return 0;
1531 }
1532 
1533 
1534 /*
1535  * @unimplemented
1536  */
1537 DWORD WINAPI
1538 SetupChangeFontSize(
1539     IN HANDLE hWnd,
1540     IN LPCWSTR lpszFontSize)
1541 {
1542     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1543     return FALSE;
1544 }
1545 
1546 /*
1547  * @unimplemented
1548  */
1549 DWORD WINAPI
1550 SetupChangeLocaleEx(HWND hWnd,
1551                     LCID Lcid,
1552                     LPCWSTR lpSrcRootPath,
1553                     char Unknown,
1554                     DWORD dwUnused1,
1555                     DWORD dwUnused2)
1556 {
1557     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1558     return FALSE;
1559 }
1560 
1561 /*
1562  * @implemented
1563  */
1564 DWORD WINAPI
1565 SetupChangeLocale(HWND hWnd, LCID Lcid)
1566 {
1567     return SetupChangeLocaleEx(hWnd, Lcid, NULL, 0, 0, 0);
1568 }
1569 
1570 
1571 DWORD
1572 WINAPI
1573 SetupStartService(
1574     LPCWSTR lpServiceName,
1575     BOOL bWait)
1576 {
1577     SC_HANDLE hManager = NULL;
1578     SC_HANDLE hService = NULL;
1579     DWORD dwError = ERROR_SUCCESS;
1580 
1581     hManager = OpenSCManagerW(NULL,
1582                               NULL,
1583                               SC_MANAGER_ALL_ACCESS);
1584     if (hManager == NULL)
1585     {
1586         dwError = GetLastError();
1587         goto done;
1588     }
1589 
1590     hService = OpenServiceW(hManager,
1591                             lpServiceName,
1592                             SERVICE_START);
1593     if (hService == NULL)
1594     {
1595         dwError = GetLastError();
1596         goto done;
1597     }
1598 
1599     if (!StartService(hService, 0, NULL))
1600     {
1601         dwError = GetLastError();
1602         goto done;
1603     }
1604 
1605 done:
1606     if (hService != NULL)
1607         CloseServiceHandle(hService);
1608 
1609     if (hManager != NULL)
1610         CloseServiceHandle(hManager);
1611 
1612     return dwError;
1613 }
1614