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