26235e1a5b61125234c39c162c335b6662c740ef
[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 }
838
839 if (!CommonInstall())
840 goto error;
841
842 /* Register components */
843 _SEH2_TRY
844 {
845 if (!SetupInstallFromInfSectionW(NULL,
846 hSysSetupInf, L"RegistrationPhase2",
847 SPINST_ALL,
848 0, NULL, 0, NULL, NULL, NULL, NULL))
849 {
850 DPRINT1("SetupInstallFromInfSectionW failed!\n");
851 }
852
853 RegisterTypeLibraries(hSysSetupInf, L"TypeLibraries");
854 }
855 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
856 {
857 DPRINT1("Catching exception\n");
858 }
859 _SEH2_END;
860
861 SetupCloseInfFile(hSysSetupInf);
862
863 /* Run the shell */
864 ZeroMemory(&StartupInfo, sizeof(StartupInfo));
865 StartupInfo.cb = sizeof(StartupInfo);
866 bRes = CreateProcessW(L"userinit.exe",
867 NULL,
868 NULL,
869 NULL,
870 FALSE,
871 0,
872 NULL,
873 NULL,
874 &StartupInfo,
875 &ProcessInformation);
876 if (!bRes)
877 goto error;
878
879 CloseHandle(ProcessInformation.hThread);
880 CloseHandle(ProcessInformation.hProcess);
881
882 return 0;
883
884 error:
885 MessageBoxW(
886 NULL,
887 L"Failed to load LiveCD! You can shutdown your computer, or press ENTER to reboot.",
888 L"ReactOS LiveCD",
889 MB_OK);
890 return 0;
891 }
892
893
894 static BOOL
895 SetSetupType(DWORD dwSetupType)
896 {
897 DWORD dwError;
898 HKEY hKey;
899
900 dwError = RegOpenKeyExW(
901 HKEY_LOCAL_MACHINE,
902 L"SYSTEM\\Setup",
903 0,
904 KEY_SET_VALUE,
905 &hKey);
906 if (dwError != ERROR_SUCCESS)
907 return FALSE;
908
909 dwError = RegSetValueExW(
910 hKey,
911 L"SetupType",
912 0,
913 REG_DWORD,
914 (LPBYTE)&dwSetupType,
915 sizeof(DWORD));
916 RegCloseKey(hKey);
917 if (dwError != ERROR_SUCCESS)
918 return FALSE;
919
920 return TRUE;
921 }
922
923 static DWORD CALLBACK
924 HotkeyThread(LPVOID Parameter)
925 {
926 ATOM hotkey;
927 MSG msg;
928
929 DPRINT("HotkeyThread start\n");
930
931 hotkey = GlobalAddAtomW(L"Setup Shift+F10 Hotkey");
932
933 if (!RegisterHotKey(NULL, hotkey, MOD_SHIFT, VK_F10))
934 DPRINT1("RegisterHotKey failed with %lu\n", GetLastError());
935
936 while (GetMessage(&msg, NULL, 0, 0))
937 {
938 if (msg.hwnd == NULL && msg.message == WM_HOTKEY && msg.wParam == hotkey)
939 {
940 STARTUPINFOW si = { sizeof(si) };
941 PROCESS_INFORMATION pi;
942
943 if (CreateProcessW(L"cmd.exe",
944 NULL,
945 NULL,
946 NULL,
947 FALSE,
948 CREATE_NEW_CONSOLE,
949 NULL,
950 NULL,
951 &si,
952 &pi))
953 {
954 CloseHandle(pi.hProcess);
955 CloseHandle(pi.hThread);
956 }
957 else
958 {
959 DPRINT1("Failed to launch command prompt: %lu\n", GetLastError());
960 }
961 }
962 }
963
964 UnregisterHotKey(NULL, hotkey);
965 GlobalDeleteAtom(hotkey);
966
967 DPRINT("HotkeyThread terminate\n");
968 return 0;
969 }
970
971
972 static
973 VOID
974 InitializeDefaultUserLocale(VOID)
975 {
976 WCHAR szBuffer[80];
977 PWSTR ptr;
978 HKEY hLocaleKey;
979 DWORD ret;
980 DWORD dwSize;
981 LCID lcid;
982 INT i;
983
984 struct {LCTYPE LCType; PWSTR pValue;} LocaleData[] = {
985 /* Number */
986 {LOCALE_SDECIMAL, L"sDecimal"},
987 {LOCALE_STHOUSAND, L"sThousand"},
988 {LOCALE_SNEGATIVESIGN, L"sNegativeSign"},
989 {LOCALE_SPOSITIVESIGN, L"sPositiveSign"},
990 {LOCALE_SGROUPING, L"sGrouping"},
991 {LOCALE_SLIST, L"sList"},
992 {LOCALE_SNATIVEDIGITS, L"sNativeDigits"},
993 {LOCALE_INEGNUMBER, L"iNegNumber"},
994 {LOCALE_IDIGITS, L"iDigits"},
995 {LOCALE_ILZERO, L"iLZero"},
996 {LOCALE_IMEASURE, L"iMeasure"},
997 {LOCALE_IDIGITSUBSTITUTION, L"NumShape"},
998
999 /* Currency */
1000 {LOCALE_SCURRENCY, L"sCurrency"},
1001 {LOCALE_SMONDECIMALSEP, L"sMonDecimalSep"},
1002 {LOCALE_SMONTHOUSANDSEP, L"sMonThousandSep"},
1003 {LOCALE_SMONGROUPING, L"sMonGrouping"},
1004 {LOCALE_ICURRENCY, L"iCurrency"},
1005 {LOCALE_INEGCURR, L"iNegCurr"},
1006 {LOCALE_ICURRDIGITS, L"iCurrDigits"},
1007
1008 /* Time */
1009 {LOCALE_STIMEFORMAT, L"sTimeFormat"},
1010 {LOCALE_STIME, L"sTime"},
1011 {LOCALE_S1159, L"s1159"},
1012 {LOCALE_S2359, L"s2359"},
1013 {LOCALE_ITIME, L"iTime"},
1014 {LOCALE_ITIMEMARKPOSN, L"iTimePrefix"},
1015 {LOCALE_ITLZERO, L"iTLZero"},
1016
1017 /* Date */
1018 {LOCALE_SLONGDATE, L"sLongDate"},
1019 {LOCALE_SSHORTDATE, L"sShortDate"},
1020 {LOCALE_SDATE, L"sDate"},
1021 {LOCALE_IFIRSTDAYOFWEEK, L"iFirstDayOfWeek"},
1022 {LOCALE_IFIRSTWEEKOFYEAR, L"iFirstWeekOfYear"},
1023 {LOCALE_IDATE, L"iDate"},
1024 {LOCALE_ICALENDARTYPE, L"iCalendarType"},
1025
1026 /* Misc */
1027 {LOCALE_SCOUNTRY, L"sCountry"},
1028 {LOCALE_SLANGUAGE, L"sLanguage"},
1029 {LOCALE_ICOUNTRY, L"iCountry"},
1030 {0, NULL}};
1031
1032 ret = RegOpenKeyExW(HKEY_USERS,
1033 L".DEFAULT\\Control Panel\\International",
1034 0,
1035 KEY_READ | KEY_WRITE,
1036 &hLocaleKey);
1037 if (ret != ERROR_SUCCESS)
1038 {
1039 return;
1040 }
1041
1042 dwSize = 9 * sizeof(WCHAR);
1043 ret = RegQueryValueExW(hLocaleKey,
1044 L"Locale",
1045 NULL,
1046 NULL,
1047 (PBYTE)szBuffer,
1048 &dwSize);
1049 if (ret != ERROR_SUCCESS)
1050 goto done;
1051
1052 lcid = (LCID)wcstoul(szBuffer, &ptr, 16);
1053 if (lcid == 0)
1054 goto done;
1055
1056 i = 0;
1057 while (LocaleData[i].pValue != NULL)
1058 {
1059 if (GetLocaleInfoW(lcid,
1060 LocaleData[i].LCType | LOCALE_NOUSEROVERRIDE,
1061 szBuffer,
1062 ARRAYSIZE(szBuffer)))
1063 {
1064 RegSetValueExW(hLocaleKey,
1065 LocaleData[i].pValue,
1066 0,
1067 REG_SZ,
1068 (PBYTE)szBuffer,
1069 (wcslen(szBuffer) + 1) * sizeof(WCHAR));
1070 }
1071
1072 i++;
1073 }
1074
1075 done:
1076 RegCloseKey(hLocaleKey);
1077 }
1078
1079
1080 DWORD
1081 WINAPI
1082 InstallReactOS(HINSTANCE hInstance)
1083 {
1084 WCHAR szBuffer[MAX_PATH];
1085 HANDLE token;
1086 TOKEN_PRIVILEGES privs;
1087 HKEY hKey;
1088 HINF hShortcutsInf;
1089 HANDLE hHotkeyThread;
1090 BOOL ret;
1091
1092 InitializeSetupActionLog(FALSE);
1093 LogItem(NULL, L"Installing ReactOS");
1094
1095 if (!InitializeProfiles())
1096 {
1097 FatalError("InitializeProfiles() failed");
1098 return 0;
1099 }
1100
1101 CreateTempDir(L"TEMP");
1102 CreateTempDir(L"TMP");
1103
1104 InitializeDefaultUserLocale();
1105
1106 if (GetWindowsDirectoryW(szBuffer, ARRAYSIZE(szBuffer)))
1107 {
1108 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1109 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
1110 0,
1111 KEY_WRITE,
1112 &hKey) == ERROR_SUCCESS)
1113 {
1114 RegSetValueExW(hKey,
1115 L"PathName",
1116 0,
1117 REG_SZ,
1118 (LPBYTE)szBuffer,
1119 (wcslen(szBuffer) + 1) * sizeof(WCHAR));
1120
1121 RegSetValueExW(hKey,
1122 L"SystemRoot",
1123 0,
1124 REG_SZ,
1125 (LPBYTE)szBuffer,
1126 (wcslen(szBuffer) + 1) * sizeof(WCHAR));
1127
1128 RegCloseKey(hKey);
1129 }
1130
1131 PathAddBackslash(szBuffer);
1132 wcscat(szBuffer, L"system");
1133 CreateDirectory(szBuffer, NULL);
1134 }
1135
1136 hHotkeyThread = CreateThread(NULL, 0, HotkeyThread, NULL, 0, NULL);
1137
1138 /* Hack: Install TCP/IP protocol driver */
1139 ret = InstallInfSection(NULL,
1140 L"nettcpip.inf",
1141 L"MS_TCPIP.PrimaryInstall",
1142 L"MS_TCPIP.PrimaryInstall.Services");
1143 if (!ret && GetLastError() != ERROR_FILE_NOT_FOUND)
1144 {
1145 DPRINT("InstallInfSection() failed with error 0x%lx\n", GetLastError());
1146 }
1147 else
1148 {
1149 /* Start the TCP/IP protocol driver */
1150 SetupStartService(L"Tcpip", FALSE);
1151 }
1152
1153
1154 if (!CommonInstall())
1155 return 0;
1156
1157 InstallWizard();
1158
1159 InstallSecurity();
1160
1161 SetAutoAdminLogon();
1162
1163 hShortcutsInf = SetupOpenInfFileW(L"shortcuts.inf",
1164 NULL,
1165 INF_STYLE_WIN4,
1166 NULL);
1167 if (hShortcutsInf == INVALID_HANDLE_VALUE)
1168 {
1169 FatalError("Failed to open shortcuts.inf");
1170 return 0;
1171 }
1172
1173 if (!CreateShortcuts(hShortcutsInf, L"ShortcutFolders"))
1174 {
1175 FatalError("CreateShortcuts() failed");
1176 return 0;
1177 }
1178
1179 SetupCloseInfFile(hShortcutsInf);
1180
1181 SetupCloseInfFile(hSysSetupInf);
1182 SetSetupType(0);
1183
1184 if (hHotkeyThread)
1185 {
1186 PostThreadMessage(GetThreadId(hHotkeyThread), WM_QUIT, 0, 0);
1187 CloseHandle(hHotkeyThread);
1188 }
1189
1190 LogItem(NULL, L"Installing ReactOS done");
1191 TerminateSetupActionLog();
1192
1193 if (AdminInfo.Name != NULL)
1194 RtlFreeHeap(RtlGetProcessHeap(), 0, AdminInfo.Name);
1195
1196 if (AdminInfo.Domain != NULL)
1197 RtlFreeHeap(RtlGetProcessHeap(), 0, AdminInfo.Domain);
1198
1199 if (AdminInfo.Password != NULL)
1200 RtlFreeHeap(RtlGetProcessHeap(), 0, AdminInfo.Password);
1201
1202 /* Get shutdown privilege */
1203 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token))
1204 {
1205 FatalError("OpenProcessToken() failed!");
1206 return 0;
1207 }
1208 if (!LookupPrivilegeValue(NULL,
1209 SE_SHUTDOWN_NAME,
1210 &privs.Privileges[0].Luid))
1211 {
1212 FatalError("LookupPrivilegeValue() failed!");
1213 return 0;
1214 }
1215 privs.PrivilegeCount = 1;
1216 privs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
1217 if (AdjustTokenPrivileges(token,
1218 FALSE,
1219 &privs,
1220 0,
1221 (PTOKEN_PRIVILEGES)NULL,
1222 NULL) == 0)
1223 {
1224 FatalError("AdjustTokenPrivileges() failed!");
1225 return 0;
1226 }
1227
1228 ExitWindowsEx(EWX_REBOOT, 0);
1229 return 0;
1230 }
1231
1232
1233 /*
1234 * @unimplemented
1235 */
1236 DWORD WINAPI
1237 SetupChangeFontSize(
1238 IN HANDLE hWnd,
1239 IN LPCWSTR lpszFontSize)
1240 {
1241 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1242 return FALSE;
1243 }
1244
1245 /*
1246 * @unimplemented
1247 */
1248 DWORD WINAPI
1249 SetupChangeLocaleEx(HWND hWnd,
1250 LCID Lcid,
1251 LPCWSTR lpSrcRootPath,
1252 char Unknown,
1253 DWORD dwUnused1,
1254 DWORD dwUnused2)
1255 {
1256 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1257 return FALSE;
1258 }
1259
1260 /*
1261 * @implemented
1262 */
1263 DWORD WINAPI
1264 SetupChangeLocale(HWND hWnd, LCID Lcid)
1265 {
1266 return SetupChangeLocaleEx(hWnd, Lcid, NULL, 0, 0, 0);
1267 }
1268
1269
1270 DWORD
1271 WINAPI
1272 SetupStartService(
1273 LPCWSTR lpServiceName,
1274 BOOL bWait)
1275 {
1276 SC_HANDLE hManager = NULL;
1277 SC_HANDLE hService = NULL;
1278 DWORD dwError = ERROR_SUCCESS;
1279
1280 hManager = OpenSCManagerW(NULL,
1281 NULL,
1282 SC_MANAGER_ALL_ACCESS);
1283 if (hManager == NULL)
1284 {
1285 dwError = GetLastError();
1286 goto done;
1287 }
1288
1289 hService = OpenServiceW(hManager,
1290 lpServiceName,
1291 SERVICE_START);
1292 if (hService == NULL)
1293 {
1294 dwError = GetLastError();
1295 goto done;
1296 }
1297
1298 if (!StartService(hService, 0, NULL))
1299 {
1300 dwError = GetLastError();
1301 goto done;
1302 }
1303
1304 done:
1305 if (hService != NULL)
1306 CloseServiceHandle(hService);
1307
1308 if (hManager != NULL)
1309 CloseServiceHandle(hManager);
1310
1311 return dwError;
1312 }