make more robust by calling GetSystemDirectory
[reactos.git] / reactos / lib / 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 /* $Id$
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS system libraries
23 * PURPOSE: System setup
24 * FILE: lib/syssetup/install.c
25 * PROGRAMER: Eric Kohl
26 */
27
28 /* INCLUDES *****************************************************************/
29
30 #define WIN32_NO_STATUS
31 #include <windows.h>
32 #define NTOS_MODE_USER
33 #include <ndk/ntndk.h>
34
35 #include <commctrl.h>
36 #include <stdio.h>
37 #include <io.h>
38 #include <tchar.h>
39 #include <stdlib.h>
40
41 #include <samlib/samlib.h>
42 #include <syssetup/syssetup.h>
43 #include <userenv.h>
44 #include <setupapi.h>
45
46 #include <shlobj.h>
47 #include <objidl.h>
48 #include <shlwapi.h>
49
50 #include "globals.h"
51 #include "resource.h"
52
53 #define VMWINST
54
55
56 /* GLOBALS ******************************************************************/
57
58 PSID DomainSid = NULL;
59 PSID AdminSid = NULL;
60
61 HINF hSysSetupInf = INVALID_HANDLE_VALUE;
62
63 /* FUNCTIONS ****************************************************************/
64
65 void
66 DebugPrint(char* fmt,...)
67 {
68 char buffer[512];
69 va_list ap;
70
71 va_start(ap, fmt);
72 vsprintf(buffer, fmt, ap);
73 va_end(ap);
74
75 strcat(buffer, "\nRebooting now!");
76 MessageBoxA(NULL,
77 buffer,
78 "ReactOS Setup",
79 MB_OK);
80 }
81
82
83 #ifdef VMWINST
84 static BOOL
85 RunVMWInstall(VOID)
86 {
87 PROCESS_INFORMATION ProcInfo;
88 STARTUPINFO si;
89 WCHAR InstallName[] = L"vmwinst.exe";
90
91 ZeroMemory(&si, sizeof(STARTUPINFO));
92 si.cb = sizeof(STARTUPINFO);
93
94 if(CreateProcess(NULL, InstallName, NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS,
95 NULL, NULL, &si, &ProcInfo))
96 {
97 WaitForSingleObject(ProcInfo.hProcess, INFINITE);
98 CloseHandle(ProcInfo.hThread);
99 CloseHandle(ProcInfo.hProcess);
100 return TRUE;
101 }
102 return FALSE;
103 }
104 #endif
105
106
107 HRESULT CreateShellLink(LPCTSTR linkPath, LPCTSTR cmd, LPCTSTR arg, LPCTSTR dir, LPCTSTR iconPath, int icon_nr, LPCTSTR comment)
108 {
109 IShellLink* psl;
110 IPersistFile* ppf;
111 #ifndef _UNICODE
112 WCHAR buffer[MAX_PATH];
113 #endif /* _UNICODE */
114
115 HRESULT hr = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLink, (LPVOID*)&psl);
116
117 if (SUCCEEDED(hr))
118 {
119 hr = psl->lpVtbl->SetPath(psl, cmd);
120
121 if (arg)
122 {
123 hr = psl->lpVtbl->SetArguments(psl, arg);
124 }
125
126 if (dir)
127 {
128 hr = psl->lpVtbl->SetWorkingDirectory(psl, dir);
129 }
130
131 if (iconPath)
132 {
133 hr = psl->lpVtbl->SetIconLocation(psl, iconPath, icon_nr);
134 }
135
136 if (comment)
137 {
138 hr = psl->lpVtbl->SetDescription(psl, comment);
139 }
140
141 hr = psl->lpVtbl->QueryInterface(psl, &IID_IPersistFile, (LPVOID*)&ppf);
142
143 if (SUCCEEDED(hr))
144 {
145 #ifdef _UNICODE
146 hr = ppf->lpVtbl->Save(ppf, linkPath, TRUE);
147 #else /* _UNICODE */
148 MultiByteToWideChar(CP_ACP, 0, linkPath, -1, buffer, MAX_PATH);
149
150 hr = ppf->lpVtbl->Save(ppf, buffer, TRUE);
151 #endif /* _UNICODE */
152
153 ppf->lpVtbl->Release(ppf);
154 }
155
156 psl->lpVtbl->Release(psl);
157 }
158
159 return hr;
160 }
161
162
163 static BOOL
164 CreateShortcut(int csidl, LPCTSTR folder, LPCTSTR linkName, LPCTSTR command, UINT nIdTitle)
165 {
166 TCHAR path[MAX_PATH];
167 TCHAR title[256];
168 LPTSTR p = path;
169
170 if (!SHGetSpecialFolderPath(0, path, csidl, TRUE))
171 return FALSE;
172
173 if (folder)
174 {
175 p = PathAddBackslash(p);
176 _tcscpy(p, folder);
177 }
178
179 p = PathAddBackslash(p);
180 _tcscpy(p, linkName);
181
182 if (!LoadString(hDllInstance, nIdTitle, title, 256))
183 return FALSE;
184
185 return SUCCEEDED(CreateShellLink(path, command, _T(""), NULL, NULL, 0, title));
186 }
187
188
189 static BOOL
190 CreateShortcutFolder(int csidl, UINT nID, LPTSTR name, int nameLen)
191 {
192 TCHAR path[MAX_PATH];
193 LPTSTR p;
194
195 if (!SHGetSpecialFolderPath(0, path, csidl, TRUE))
196 return FALSE;
197
198 if (!LoadString(hDllInstance, nID, name, nameLen))
199 return FALSE;
200
201 p = PathAddBackslash(path);
202 _tcscpy(p, name);
203
204 return CreateDirectory(path, NULL) || GetLastError()==ERROR_ALREADY_EXISTS;
205 }
206
207
208 static VOID
209 CreateRandomSid (PSID *Sid)
210 {
211 SID_IDENTIFIER_AUTHORITY SystemAuthority = {SECURITY_NT_AUTHORITY};
212 LARGE_INTEGER SystemTime;
213 PULONG Seed;
214
215 NtQuerySystemTime (&SystemTime);
216 Seed = &SystemTime.u.LowPart;
217
218 RtlAllocateAndInitializeSid (&SystemAuthority,
219 4,
220 SECURITY_NT_NON_UNIQUE_RID,
221 RtlUniform (Seed),
222 RtlUniform (Seed),
223 RtlUniform (Seed),
224 SECURITY_NULL_RID,
225 SECURITY_NULL_RID,
226 SECURITY_NULL_RID,
227 SECURITY_NULL_RID,
228 Sid);
229 }
230
231
232 static VOID
233 AppendRidToSid (PSID *Dst,
234 PSID Src,
235 ULONG NewRid)
236 {
237 ULONG Rid[8] = {0, 0, 0, 0, 0, 0, 0, 0};
238 UCHAR RidCount;
239 ULONG i;
240
241 RidCount = *RtlSubAuthorityCountSid (Src);
242
243 for (i = 0; i < RidCount; i++)
244 Rid[i] = *RtlSubAuthoritySid (Src, i);
245
246 if (RidCount < 8)
247 {
248 Rid[RidCount] = NewRid;
249 RidCount++;
250 }
251
252 RtlAllocateAndInitializeSid (RtlIdentifierAuthoritySid (Src),
253 RidCount,
254 Rid[0],
255 Rid[1],
256 Rid[2],
257 Rid[3],
258 Rid[4],
259 Rid[5],
260 Rid[6],
261 Rid[7],
262 Dst);
263 }
264
265 INT_PTR CALLBACK
266 RestartDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
267 {
268 switch(msg)
269 {
270 case WM_INITDIALOG:
271 SendDlgItemMessage(hWnd, IDC_RESTART_PROGRESS, PBM_SETRANGE, 0,
272 MAKELPARAM(0, 300));
273 SetTimer(hWnd, 1, 50, NULL);
274 return TRUE;
275
276 case WM_TIMER:
277 {
278 INT Position;
279 HWND hWndProgress;
280
281 hWndProgress = GetDlgItem(hWnd, IDC_RESTART_PROGRESS);
282 Position = SendMessage(hWndProgress, PBM_GETPOS, 0, 0);
283 if (Position == 300)
284 EndDialog(hWnd, 0);
285 else
286 SendMessage(hWndProgress, PBM_SETPOS, Position + 1, 0);
287 }
288 return TRUE;
289
290 case WM_COMMAND:
291 switch (wParam)
292 {
293 case IDOK:
294 case IDCANCEL:
295 EndDialog(hWnd, 0);
296 return TRUE;
297 }
298 break;
299 }
300
301 return FALSE;
302 }
303
304 static VOID
305 CreateTempDir(LPCWSTR VarName)
306 {
307 TCHAR szTempDir[MAX_PATH];
308 TCHAR szBuffer[MAX_PATH];
309 DWORD dwLength;
310 HKEY hKey;
311
312 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
313 _T("SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment"),
314 0,
315 KEY_ALL_ACCESS,
316 &hKey))
317 {
318 DebugPrint("Error: %lu\n", GetLastError());
319 return;
320 }
321
322 /* Get temp dir */
323 dwLength = MAX_PATH * sizeof(TCHAR);
324 if (RegQueryValueEx(hKey,
325 VarName,
326 NULL,
327 NULL,
328 (LPBYTE)szBuffer,
329 &dwLength))
330 {
331 DebugPrint("Error: %lu\n", GetLastError());
332 RegCloseKey(hKey);
333 return;
334 }
335
336 /* Expand it */
337 if (!ExpandEnvironmentStrings(szBuffer,
338 szTempDir,
339 MAX_PATH))
340 {
341 DebugPrint("Error: %lu\n", GetLastError());
342 RegCloseKey(hKey);
343 return;
344 }
345
346 /* Create profiles directory */
347 if (!CreateDirectory(szTempDir, NULL))
348 {
349 if (GetLastError() != ERROR_ALREADY_EXISTS)
350 {
351 DebugPrint("Error: %lu\n", GetLastError());
352 RegCloseKey(hKey);
353 return;
354 }
355 }
356
357 RegCloseKey(hKey);
358 }
359
360
361 BOOL
362 ProcessSysSetupInf(VOID)
363 {
364 INFCONTEXT InfContext;
365 TCHAR LineBuffer[256];
366 DWORD LineLength;
367
368 if (!SetupFindFirstLine(hSysSetupInf,
369 _T("DeviceInfsToInstall"),
370 NULL,
371 &InfContext))
372 {
373 return FALSE;
374 }
375
376 do
377 {
378 if (!SetupGetStringField(&InfContext,
379 0,
380 LineBuffer,
381 256,
382 &LineLength))
383 {
384 return FALSE;
385 }
386
387 if (!SetupDiInstallClass(NULL, LineBuffer, DI_QUIETINSTALL, NULL))
388 {
389 return FALSE;
390 }
391 }
392 while (SetupFindNextLine(&InfContext, &InfContext));
393
394 return TRUE;
395 }
396
397
398 DWORD STDCALL
399 InstallReactOS (HINSTANCE hInstance)
400 {
401 TCHAR sAccessories[256];
402 TCHAR sGames[256];
403 TCHAR Sys[_MAX_PATH];
404
405
406 # if 0
407 OutputDebugStringA ("InstallReactOS() called\n");
408
409 if (!InitializeSetupActionLog (FALSE))
410 {
411 OutputDebugStringA ("InitializeSetupActionLog() failed\n");
412 }
413
414 LogItem (SYSSETUP_SEVERITY_INFORMATION,
415 L"ReactOS Setup starting");
416
417 LogItem (SYSSETUP_SEVERITY_FATAL_ERROR,
418 L"Buuuuuuaaaah!");
419
420 LogItem (SYSSETUP_SEVERITY_INFORMATION,
421 L"ReactOS Setup finished");
422
423 TerminateSetupActionLog ();
424 #endif
425 #if 0
426 UNICODE_STRING SidString;
427 #endif
428 ULONG LastError;
429
430 if (!InitializeProfiles ())
431 {
432 DebugPrint ("InitializeProfiles() failed\n");
433 return 0;
434 }
435
436 CoInitialize(NULL);
437
438 /* create desktop shortcuts */
439 CreateShortcut(CSIDL_DESKTOP, NULL, _T("Command Prompt.lnk"), _T("cmd.exe"), IDS_CMT_CMD);
440
441 /* create program startmenu shortcuts */
442 CreateShortcut(CSIDL_PROGRAMS, NULL, _T("winefile.lnk"), _T("winefile.exe"), IDS_CMT_WINEFILE);
443
444 /* create and fill Accessories subfolder */
445 if (CreateShortcutFolder(CSIDL_PROGRAMS, IDS_ACCESSORIES, sAccessories, 256)) {
446 CreateShortcut(CSIDL_PROGRAMS, sAccessories, _T("Command Prompt.lnk"), _T("cmd.exe"), IDS_CMT_CMD);
447 CreateShortcut(CSIDL_PROGRAMS, sAccessories, _T("notepad.lnk"), _T("notepad.exe"), IDS_CMT_NOTEPAD);
448 CreateShortcut(CSIDL_PROGRAMS, sAccessories, _T("explorer.lnk"), _T("explorer.exe"), IDS_CMT_EXPLORER);
449 CreateShortcut(CSIDL_PROGRAMS, sAccessories, _T("regedit.lnk"), _T("regedit.exe"), IDS_CMT_REGEDIT);
450 }
451
452 if(!GetSystemDirectory(Sys, _MAX_PATH))
453 Sys[0] = L'\0';
454
455 /* create Games subfolder and fill if the exe is available */
456 if (CreateShortcutFolder(CSIDL_PROGRAMS, IDS_GAMES, sGames, 256)) {
457 if (Sys[0] != L'\0') {
458 if((_taccess(_tcscat(Sys, _T("\\sol.exe")), 0 )) != -1)
459 CreateShortcut(CSIDL_PROGRAMS, sGames, _T("Solitaire.lnk"), _T("sol.exe"), IDS_CMT_SOLITAIRE);
460
461 /* winemine etc .... */
462 }
463 }
464
465 CoUninitialize();
466
467 /* Create the semi-random Domain-SID */
468 CreateRandomSid (&DomainSid);
469 if (DomainSid == NULL)
470 {
471 DebugPrint ("Domain-SID creation failed!\n");
472 return 0;
473 }
474
475 #if 0
476 RtlConvertSidToUnicodeString (&SidString, DomainSid, TRUE);
477 DebugPrint ("Domain-SID: %wZ\n", &SidString);
478 RtlFreeUnicodeString (&SidString);
479 #endif
480
481 /* Initialize the Security Account Manager (SAM) */
482 if (!SamInitializeSAM ())
483 {
484 DebugPrint ("SamInitializeSAM() failed!\n");
485 RtlFreeSid (DomainSid);
486 return 0;
487 }
488
489 /* Set the Domain SID (aka Computer SID) */
490 if (!SamSetDomainSid (DomainSid))
491 {
492 DebugPrint ("SamSetDomainSid() failed!\n");
493 RtlFreeSid (DomainSid);
494 return 0;
495 }
496
497 /* Append the Admin-RID */
498 AppendRidToSid(&AdminSid, DomainSid, DOMAIN_USER_RID_ADMIN);
499
500 #if 0
501 RtlConvertSidToUnicodeString (&SidString, DomainSid, TRUE);
502 DebugPrint ("Admin-SID: %wZ\n", &SidString);
503 RtlFreeUnicodeString (&SidString);
504 #endif
505
506 /* Create the Administrator account */
507 if (!SamCreateUser(L"Administrator", L"", AdminSid))
508 {
509 /* Check what the error was.
510 * If the Admin Account already exists, then it means Setup
511 * wasn't allowed to finish properly. Instead of rebooting
512 * and not completing it, let it restart instead
513 */
514 LastError = GetLastError();
515 if (LastError != ERROR_USER_EXISTS)
516 {
517 DebugPrint("SamCreateUser() failed!\n");
518 RtlFreeSid(AdminSid);
519 RtlFreeSid(DomainSid);
520 return 0;
521 }
522 }
523
524 /* Create the Administrator profile */
525 if (!CreateUserProfileW(AdminSid, L"Administrator"))
526 {
527 DebugPrint("CreateUserProfileW() failed!\n");
528 RtlFreeSid(AdminSid);
529 RtlFreeSid(DomainSid);
530 return 0;
531 }
532
533 RtlFreeSid(AdminSid);
534 RtlFreeSid(DomainSid);
535
536 CreateTempDir(L"TEMP");
537 CreateTempDir(L"TMP");
538
539 hSysSetupInf = SetupOpenInfFileW(L"syssetup.inf",
540 NULL,
541 INF_STYLE_WIN4,
542 NULL);
543 if (hSysSetupInf == INVALID_HANDLE_VALUE)
544 {
545 DebugPrint("SetupOpenInfFileW() failed to open 'syssetup.inf' (Error: %lu)\n", GetLastError());
546 return 0;
547 }
548
549 if (!ProcessSysSetupInf())
550 {
551 DebugPrint("ProcessSysSetupInf() failed!\n");
552 return 0;
553 }
554
555 InstallWizard();
556
557 SetupCloseInfFile(hSysSetupInf);
558
559 #ifdef VMWINST
560 RunVMWInstall();
561 #endif
562
563 DialogBox(hDllInstance,
564 MAKEINTRESOURCE(IDD_RESTART),
565 NULL,
566 RestartDlgProc);
567
568 return 0;
569 }
570
571
572 /*
573 * @unimplemented
574 */
575 DWORD STDCALL
576 SetupChangeFontSize(HANDLE hWnd,
577 LPCWSTR lpszFontSize)
578 {
579 return FALSE;
580 }