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