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