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