Implement CMP_WaitNoPendingInstallEvents
[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
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /*
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS system libraries
22 * PURPOSE: System setup
23 * FILE: lib/syssetup/install.c
24 * PROGRAMER: Eric Kohl
25 */
26
27 /* INCLUDES *****************************************************************/
28
29 #define WIN32_NO_STATUS
30 #include <windows.h>
31 #define NTOS_MODE_USER
32 #include <ndk/ntndk.h>
33
34 #include <commctrl.h>
35 #include <stdio.h>
36 #include <io.h>
37 #include <tchar.h>
38 #include <stdlib.h>
39
40 #include <samlib/samlib.h>
41 #include <syssetup/syssetup.h>
42 #include <userenv.h>
43 #include <setupapi.h>
44
45 #include <shlobj.h>
46 #include <objidl.h>
47 #include <shlwapi.h>
48
49 #include "globals.h"
50 #include "resource.h"
51
52 DWORD WINAPI
53 CMP_WaitNoPendingInstallEvents(DWORD dwTimeout);
54
55 /* GLOBALS ******************************************************************/
56
57 PSID DomainSid = NULL;
58 PSID AdminSid = NULL;
59
60 HINF hSysSetupInf = INVALID_HANDLE_VALUE;
61
62 /* FUNCTIONS ****************************************************************/
63
64 void
65 DebugPrint(char* fmt,...)
66 {
67 char buffer[512];
68 va_list ap;
69
70 va_start(ap, fmt);
71 vsprintf(buffer, fmt, ap);
72 va_end(ap);
73
74 strcat(buffer, "\nRebooting now!");
75 MessageBoxA(NULL,
76 buffer,
77 "ReactOS Setup",
78 MB_OK);
79 }
80
81
82 HRESULT CreateShellLink(LPCTSTR linkPath, LPCTSTR cmd, LPCTSTR arg, LPCTSTR dir, LPCTSTR iconPath, int icon_nr, LPCTSTR comment)
83 {
84 IShellLink* psl;
85 IPersistFile* ppf;
86 #ifndef _UNICODE
87 WCHAR buffer[MAX_PATH];
88 #endif /* _UNICODE */
89
90 HRESULT hr = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLink, (LPVOID*)&psl);
91
92 if (SUCCEEDED(hr))
93 {
94 hr = psl->lpVtbl->SetPath(psl, cmd);
95
96 if (arg)
97 {
98 hr = psl->lpVtbl->SetArguments(psl, arg);
99 }
100
101 if (dir)
102 {
103 hr = psl->lpVtbl->SetWorkingDirectory(psl, dir);
104 }
105
106 if (iconPath)
107 {
108 hr = psl->lpVtbl->SetIconLocation(psl, iconPath, icon_nr);
109 }
110
111 if (comment)
112 {
113 hr = psl->lpVtbl->SetDescription(psl, comment);
114 }
115
116 hr = psl->lpVtbl->QueryInterface(psl, &IID_IPersistFile, (LPVOID*)&ppf);
117
118 if (SUCCEEDED(hr))
119 {
120 #ifdef _UNICODE
121 hr = ppf->lpVtbl->Save(ppf, linkPath, TRUE);
122 #else /* _UNICODE */
123 MultiByteToWideChar(CP_ACP, 0, linkPath, -1, buffer, MAX_PATH);
124
125 hr = ppf->lpVtbl->Save(ppf, buffer, TRUE);
126 #endif /* _UNICODE */
127
128 ppf->lpVtbl->Release(ppf);
129 }
130
131 psl->lpVtbl->Release(psl);
132 }
133
134 return hr;
135 }
136
137
138 static BOOL
139 CreateShortcut(int csidl, LPCTSTR folder, LPCTSTR linkName, LPCTSTR command, UINT nIdTitle)
140 {
141 TCHAR path[MAX_PATH];
142 TCHAR title[256];
143 LPTSTR p = path;
144
145 if (!SHGetSpecialFolderPath(0, path, csidl, TRUE))
146 return FALSE;
147
148 if (folder)
149 {
150 p = PathAddBackslash(p);
151 _tcscpy(p, folder);
152 }
153
154 p = PathAddBackslash(p);
155 _tcscpy(p, linkName);
156
157 if (!LoadString(hDllInstance, nIdTitle, title, 256))
158 return FALSE;
159
160 return SUCCEEDED(CreateShellLink(path, command, _T(""), NULL, NULL, 0, title));
161 }
162
163
164 static BOOL
165 CreateShortcutFolder(int csidl, UINT nID, LPTSTR name, int nameLen)
166 {
167 TCHAR path[MAX_PATH];
168 LPTSTR p;
169
170 if (!SHGetSpecialFolderPath(0, path, csidl, TRUE))
171 return FALSE;
172
173 if (!LoadString(hDllInstance, nID, name, nameLen))
174 return FALSE;
175
176 p = PathAddBackslash(path);
177 _tcscpy(p, name);
178
179 return CreateDirectory(path, NULL) || GetLastError()==ERROR_ALREADY_EXISTS;
180 }
181
182
183 static VOID
184 CreateRandomSid (PSID *Sid)
185 {
186 SID_IDENTIFIER_AUTHORITY SystemAuthority = {SECURITY_NT_AUTHORITY};
187 LARGE_INTEGER SystemTime;
188 PULONG Seed;
189
190 NtQuerySystemTime (&SystemTime);
191 Seed = &SystemTime.u.LowPart;
192
193 RtlAllocateAndInitializeSid (&SystemAuthority,
194 4,
195 SECURITY_NT_NON_UNIQUE,
196 RtlUniform (Seed),
197 RtlUniform (Seed),
198 RtlUniform (Seed),
199 SECURITY_NULL_RID,
200 SECURITY_NULL_RID,
201 SECURITY_NULL_RID,
202 SECURITY_NULL_RID,
203 Sid);
204 }
205
206
207 static VOID
208 AppendRidToSid (PSID *Dst,
209 PSID Src,
210 ULONG NewRid)
211 {
212 ULONG Rid[8] = {0, 0, 0, 0, 0, 0, 0, 0};
213 UCHAR RidCount;
214 ULONG i;
215
216 RidCount = *RtlSubAuthorityCountSid (Src);
217
218 for (i = 0; i < RidCount; i++)
219 Rid[i] = *RtlSubAuthoritySid (Src, i);
220
221 if (RidCount < 8)
222 {
223 Rid[RidCount] = NewRid;
224 RidCount++;
225 }
226
227 RtlAllocateAndInitializeSid (RtlIdentifierAuthoritySid (Src),
228 RidCount,
229 Rid[0],
230 Rid[1],
231 Rid[2],
232 Rid[3],
233 Rid[4],
234 Rid[5],
235 Rid[6],
236 Rid[7],
237 Dst);
238 }
239
240
241 static VOID
242 CreateTempDir(LPCWSTR VarName)
243 {
244 TCHAR szTempDir[MAX_PATH];
245 TCHAR szBuffer[MAX_PATH];
246 DWORD dwLength;
247 HKEY hKey;
248
249 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
250 _T("SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment"),
251 0,
252 KEY_ALL_ACCESS,
253 &hKey))
254 {
255 DebugPrint("Error: %lu\n", GetLastError());
256 return;
257 }
258
259 /* Get temp dir */
260 dwLength = MAX_PATH * sizeof(TCHAR);
261 if (RegQueryValueEx(hKey,
262 VarName,
263 NULL,
264 NULL,
265 (LPBYTE)szBuffer,
266 &dwLength))
267 {
268 DebugPrint("Error: %lu\n", GetLastError());
269 RegCloseKey(hKey);
270 return;
271 }
272
273 /* Expand it */
274 if (!ExpandEnvironmentStrings(szBuffer,
275 szTempDir,
276 MAX_PATH))
277 {
278 DebugPrint("Error: %lu\n", GetLastError());
279 RegCloseKey(hKey);
280 return;
281 }
282
283 /* Create profiles directory */
284 if (!CreateDirectory(szTempDir, NULL))
285 {
286 if (GetLastError() != ERROR_ALREADY_EXISTS)
287 {
288 DebugPrint("Error: %lu\n", GetLastError());
289 RegCloseKey(hKey);
290 return;
291 }
292 }
293
294 RegCloseKey(hKey);
295 }
296
297
298 BOOL
299 ProcessSysSetupInf(VOID)
300 {
301 INFCONTEXT InfContext;
302 TCHAR LineBuffer[256];
303 DWORD LineLength;
304
305 if (!SetupFindFirstLine(hSysSetupInf,
306 _T("DeviceInfsToInstall"),
307 NULL,
308 &InfContext))
309 {
310 return FALSE;
311 }
312
313 do
314 {
315 if (!SetupGetStringField(&InfContext,
316 0,
317 LineBuffer,
318 256,
319 &LineLength))
320 {
321 return FALSE;
322 }
323
324 if (!SetupDiInstallClass(NULL, LineBuffer, DI_QUIETINSTALL, NULL))
325 {
326 return FALSE;
327 }
328 }
329 while (SetupFindNextLine(&InfContext, &InfContext));
330
331 return TRUE;
332 }
333
334
335 static BOOL
336 EnableUserModePnpManager(VOID)
337 {
338 SC_HANDLE hSCManager = NULL;
339 SC_HANDLE hService = NULL;
340 BOOL ret = FALSE;
341
342 hSCManager = OpenSCManager(NULL, NULL, 0);
343 if (hSCManager == NULL)
344 goto cleanup;
345
346 hService = OpenService(hSCManager, _T("PlugPlay"), SERVICE_CHANGE_CONFIG | SERVICE_START);
347 if (hService == NULL)
348 goto cleanup;
349
350 ret = ChangeServiceConfig(
351 hService,
352 SERVICE_NO_CHANGE, SERVICE_AUTO_START, SERVICE_NO_CHANGE,
353 NULL, NULL, NULL, NULL, NULL, NULL, NULL);
354 if (!ret)
355 goto cleanup;
356
357 ret = StartService(hService, 0, NULL);
358 if (!ret)
359 goto cleanup;
360
361 ret = TRUE;
362
363 cleanup:
364 if (hSCManager != NULL)
365 CloseServiceHandle(hSCManager);
366 if (hService != NULL)
367 CloseServiceHandle(hService);
368 return ret;
369 }
370
371
372 DWORD STDCALL
373 InstallLiveCD (HINSTANCE hInstance)
374 {
375 LONG rc;
376 HKEY hKey = NULL;
377 DWORD dwType;
378 DWORD requiredSize;
379 LPTSTR Shell = NULL;
380 TCHAR CommandLine[MAX_PATH];
381 STARTUPINFO StartupInfo;
382 PROCESS_INFORMATION ProcessInformation;
383 BOOL res;
384
385 hSysSetupInf = SetupOpenInfFileW(
386 L"syssetup.inf",
387 NULL,
388 INF_STYLE_WIN4,
389 NULL);
390 if (hSysSetupInf == INVALID_HANDLE_VALUE)
391 {
392 DebugPrint("SetupOpenInfFileW() failed to open 'syssetup.inf' (Error: %lu)\n", GetLastError());
393 return 0;
394 }
395
396 if (!ProcessSysSetupInf())
397 {
398 DebugPrint("ProcessSysSetupInf() failed!\n");
399 return 0;
400 }
401
402 SetupCloseInfFile(hSysSetupInf);
403
404 if (!EnableUserModePnpManager())
405 {
406 DebugPrint("EnableUserModePnpManager() failed!\n");
407 return 0;
408 }
409
410 /* Load the default shell */
411 rc = RegOpenKeyEx(
412 HKEY_LOCAL_MACHINE,
413 TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"), /* FIXME: should be REGSTR_PATH_WINLOGON */
414 0,
415 KEY_QUERY_VALUE,
416 &hKey);
417 if (rc != ERROR_SUCCESS)
418 goto cleanup;
419 rc = RegQueryValueEx(
420 hKey,
421 TEXT("Shell"),
422 NULL,
423 &dwType,
424 NULL,
425 &requiredSize);
426 if (rc != ERROR_SUCCESS)
427 goto cleanup;
428 else if (dwType != REG_SZ && dwType != REG_EXPAND_SZ)
429 goto cleanup;
430 else if (requiredSize > (MAX_PATH - 1) * sizeof(TCHAR))
431 goto cleanup;
432 Shell = HeapAlloc(GetProcessHeap(), 0, requiredSize + sizeof(TCHAR));
433 if (!Shell)
434 goto cleanup;
435 Shell[requiredSize / sizeof(WCHAR)] = '\0';
436 rc = RegQueryValueEx(
437 hKey,
438 TEXT("Shell"),
439 NULL,
440 NULL,
441 (LPBYTE)Shell,
442 &requiredSize);
443 if (rc != ERROR_SUCCESS)
444 goto cleanup;
445 if (dwType == REG_EXPAND_SZ)
446 ExpandEnvironmentStrings(Shell, CommandLine, MAX_PATH);
447 else if (dwType == REG_SZ)
448 _tcscpy(CommandLine, Shell);
449
450 /* Run the shell */
451 StartupInfo.cb = sizeof(StartupInfo);
452 StartupInfo.lpReserved = NULL;
453 StartupInfo.lpDesktop = NULL;
454 StartupInfo.lpTitle = NULL;
455 StartupInfo.dwFlags = 0;
456 StartupInfo.cbReserved2 = 0;
457 StartupInfo.lpReserved2 = 0;
458 res = CreateProcess(
459 CommandLine,
460 NULL,
461 NULL,
462 NULL,
463 FALSE,
464 0,
465 NULL,
466 NULL,
467 &StartupInfo,
468 &ProcessInformation);
469 if (!res)
470 goto cleanup;
471
472 /* Wait for process termination */
473 WaitForSingleObject(ProcessInformation.hProcess, INFINITE);
474
475 cleanup:
476 if (hKey != NULL)
477 RegCloseKey(hKey);
478 HeapFree(GetProcessHeap(), 0, Shell);
479 MessageBoxA(
480 NULL,
481 "You can shutdown your computer, or press ENTER to reboot",
482 "ReactOS LiveCD",
483 MB_OK);
484 return 0;
485 }
486
487
488 DWORD STDCALL
489 InstallReactOS (HINSTANCE hInstance)
490 {
491 TCHAR sAccessories[256];
492 TCHAR sGames[256];
493 TCHAR szBuffer[MAX_PATH];
494
495 # if 0
496 OutputDebugStringA ("InstallReactOS() called\n");
497
498 if (!InitializeSetupActionLog (FALSE))
499 {
500 OutputDebugStringA ("InitializeSetupActionLog() failed\n");
501 }
502
503 LogItem (SYSSETUP_SEVERITY_INFORMATION,
504 L"ReactOS Setup starting");
505
506 LogItem (SYSSETUP_SEVERITY_FATAL_ERROR,
507 L"Buuuuuuaaaah!");
508
509 LogItem (SYSSETUP_SEVERITY_INFORMATION,
510 L"ReactOS Setup finished");
511
512 TerminateSetupActionLog ();
513 #endif
514 #if 0
515 UNICODE_STRING SidString;
516 #endif
517 ULONG LastError;
518
519 if (!InitializeProfiles ())
520 {
521 DebugPrint ("InitializeProfiles() failed\n");
522 return 0;
523 }
524
525 CoInitialize(NULL);
526
527 /* create desktop shortcuts */
528 CreateShortcut(CSIDL_DESKTOP, NULL, _T("Command Prompt.lnk"), _T("cmd.exe"), IDS_CMT_CMD);
529
530 /* create program startmenu shortcuts */
531 CreateShortcut(CSIDL_PROGRAMS, NULL, _T("winefile.lnk"), _T("winefile.exe"), IDS_CMT_WINEFILE);
532 CreateShortcut(CSIDL_PROGRAMS, NULL, _T("ibrowser.lnk"), _T("ibrowser.exe"), IDS_CMT_IBROWSER);
533 CreateShortcut(CSIDL_PROGRAMS, NULL, _T("Get Firefox.lnk"), _T("getfirefox.exe"), IDS_CMT_GETFIREFOX);
534
535 /* create administritive tools startmenu shortcuts */
536 CreateShortcut(CSIDL_ADMINTOOLS, NULL, _T("Services.lnk"), _T("servman.exe"), IDS_CMT_SERVMAN);
537
538 /* create and fill Accessories subfolder */
539 if (CreateShortcutFolder(CSIDL_PROGRAMS, IDS_ACCESSORIES, sAccessories, 256))
540 {
541 CreateShortcut(CSIDL_PROGRAMS, sAccessories, _T("Calculator.lnk"), _T("calc.exe"), IDS_CMT_CALC);
542 CreateShortcut(CSIDL_PROGRAMS, sAccessories, _T("Command Prompt.lnk"), _T("cmd.exe"), IDS_CMT_CMD);
543 CreateShortcut(CSIDL_PROGRAMS, sAccessories, _T("Notepad.lnk"), _T("notepad.exe"), IDS_CMT_NOTEPAD);
544 CreateShortcut(CSIDL_PROGRAMS, sAccessories, _T("ReactOS Explorer.lnk"), _T("explorer.exe"), IDS_CMT_EXPLORER);
545 CreateShortcut(CSIDL_PROGRAMS, sAccessories, _T("Regedit.lnk"), _T("regedit.exe"), IDS_CMT_REGEDIT);
546 CreateShortcut(CSIDL_PROGRAMS, sAccessories, _T("WordPad.lnk"), _T("wordpad.exe"), IDS_CMT_WORDPAD);
547 CreateShortcut(CSIDL_PROGRAMS, sAccessories, _T("SnapShot.lnk"), _T("screenshot.exe"), IDS_CMT_SCREENSHOT);
548 }
549
550
551 /* create Games subfolder and fill if the exe is available */
552 if (CreateShortcutFolder(CSIDL_PROGRAMS, IDS_GAMES, sGames, 256))
553 {
554 CreateShortcut(CSIDL_PROGRAMS, sGames, _T("Solitaire.lnk"), _T("sol.exe"), IDS_CMT_SOLITAIRE);
555 CreateShortcut(CSIDL_PROGRAMS, sGames, _T("WineMine.lnk"), _T("winemine.exe"), IDS_CMT_WINEMINE);
556 }
557
558 CoUninitialize();
559
560 /* Create the semi-random Domain-SID */
561 CreateRandomSid (&DomainSid);
562 if (DomainSid == NULL)
563 {
564 DebugPrint ("Domain-SID creation failed!\n");
565 return 0;
566 }
567
568 #if 0
569 RtlConvertSidToUnicodeString (&SidString, DomainSid, TRUE);
570 DebugPrint ("Domain-SID: %wZ\n", &SidString);
571 RtlFreeUnicodeString (&SidString);
572 #endif
573
574 /* Initialize the Security Account Manager (SAM) */
575 if (!SamInitializeSAM ())
576 {
577 DebugPrint ("SamInitializeSAM() failed!\n");
578 RtlFreeSid (DomainSid);
579 return 0;
580 }
581
582 /* Set the Domain SID (aka Computer SID) */
583 if (!SamSetDomainSid (DomainSid))
584 {
585 DebugPrint ("SamSetDomainSid() failed!\n");
586 RtlFreeSid (DomainSid);
587 return 0;
588 }
589
590 /* Append the Admin-RID */
591 AppendRidToSid(&AdminSid, DomainSid, DOMAIN_USER_RID_ADMIN);
592
593 #if 0
594 RtlConvertSidToUnicodeString (&SidString, DomainSid, TRUE);
595 DebugPrint ("Admin-SID: %wZ\n", &SidString);
596 RtlFreeUnicodeString (&SidString);
597 #endif
598
599 /* Create the Administrator account */
600 if (!SamCreateUser(L"Administrator", L"", AdminSid))
601 {
602 /* Check what the error was.
603 * If the Admin Account already exists, then it means Setup
604 * wasn't allowed to finish properly. Instead of rebooting
605 * and not completing it, let it restart instead
606 */
607 LastError = GetLastError();
608 if (LastError != ERROR_USER_EXISTS)
609 {
610 DebugPrint("SamCreateUser() failed!\n");
611 RtlFreeSid(AdminSid);
612 RtlFreeSid(DomainSid);
613 return 0;
614 }
615 }
616
617 /* Create the Administrator profile */
618 if (!CreateUserProfileW(AdminSid, L"Administrator"))
619 {
620 DebugPrint("CreateUserProfileW() failed!\n");
621 RtlFreeSid(AdminSid);
622 RtlFreeSid(DomainSid);
623 return 0;
624 }
625
626 RtlFreeSid(AdminSid);
627 RtlFreeSid(DomainSid);
628
629 CreateTempDir(L"TEMP");
630 CreateTempDir(L"TMP");
631
632 if (GetWindowsDirectory(szBuffer, sizeof(szBuffer) / sizeof(TCHAR)))
633 {
634 PathAddBackslash(szBuffer);
635 _tcscat(szBuffer, _T("system"));
636 CreateDirectory(szBuffer, NULL);
637 }
638
639 hSysSetupInf = SetupOpenInfFileW(L"syssetup.inf",
640 NULL,
641 INF_STYLE_WIN4,
642 NULL);
643 if (hSysSetupInf == INVALID_HANDLE_VALUE)
644 {
645 DebugPrint("SetupOpenInfFileW() failed to open 'syssetup.inf' (Error: %lu)\n", GetLastError());
646 return 0;
647 }
648
649 if (!ProcessSysSetupInf())
650 {
651 DebugPrint("ProcessSysSetupInf() failed!\n");
652 return 0;
653 }
654
655 if (!EnableUserModePnpManager())
656 {
657 DebugPrint("EnableUserModePnpManager() failed!\n");
658 return 0;
659 }
660
661 if (CMP_WaitNoPendingInstallEvents(INFINITE) != WAIT_OBJECT_0)
662 {
663 DebugPrint("CMP_WaitNoPendingInstallEvents() failed!\n");
664 return 0;
665 }
666
667 InstallWizard();
668
669 SetupCloseInfFile(hSysSetupInf);
670
671 return 0;
672 }
673
674
675 /*
676 * @unimplemented
677 */
678 DWORD STDCALL
679 SetupChangeFontSize(HANDLE hWnd,
680 LPCWSTR lpszFontSize)
681 {
682 return FALSE;
683 }