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