[SYSSETUP] Add marquee progress bar to show setup is alive (#262)
[reactos.git] / dll / win32 / syssetup / install.c
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 }