d154f5b32360ac3fae61e68231824c680c89ebc0
[reactos.git] / reactos / base / system / userinit / userinit.c
1 /*
2 * ReactOS applications
3 * Copyright (C) 2001, 2002 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 Userinit Logon Application
22 * FILE: base/system/userinit/userinit.c
23 * PROGRAMMERS: Thomas Weidenmueller (w3seek@users.sourceforge.net)
24 * Hervé Poussineau (hpoussin@reactos.org)
25 */
26
27 #include "userinit.h"
28
29 #define CMP_MAGIC 0x01234567
30
31 /* GLOBALS ******************************************************************/
32
33 HINSTANCE hInstance;
34
35
36 /* FUNCTIONS ****************************************************************/
37
38 LONG
39 ReadRegSzKey(
40 IN HKEY hKey,
41 IN LPCWSTR pszKey,
42 OUT LPWSTR *pValue)
43 {
44 LONG rc;
45 DWORD dwType;
46 DWORD cbData = 0;
47 LPWSTR Value;
48
49 TRACE("(%p, %s, %p)\n", hKey, debugstr_w(pszKey), pValue);
50
51 rc = RegQueryValueExW(hKey, pszKey, NULL, &dwType, NULL, &cbData);
52 if (rc != ERROR_SUCCESS)
53 {
54 WARN("RegQueryValueEx(%s) failed with error %lu\n", debugstr_w(pszKey), rc);
55 return rc;
56 }
57 if (dwType != REG_SZ)
58 {
59 WARN("Wrong registry data type (%u vs %u)\n", dwType, REG_SZ);
60 return ERROR_FILE_NOT_FOUND;
61 }
62 Value = (WCHAR*) HeapAlloc(GetProcessHeap(), 0, cbData + sizeof(WCHAR));
63 if (!Value)
64 {
65 WARN("No memory\n");
66 return ERROR_NOT_ENOUGH_MEMORY;
67 }
68 rc = RegQueryValueExW(hKey, pszKey, NULL, NULL, (LPBYTE)Value, &cbData);
69 if (rc != ERROR_SUCCESS)
70 {
71 WARN("RegQueryValueEx(%s) failed with error %lu\n", debugstr_w(pszKey), rc);
72 HeapFree(GetProcessHeap(), 0, Value);
73 return rc;
74 }
75 /* NULL-terminate the string */
76 Value[cbData / sizeof(WCHAR)] = L'\0';
77
78 *pValue = Value;
79 return ERROR_SUCCESS;
80 }
81
82 static BOOL
83 IsConsoleShell(VOID)
84 {
85 HKEY ControlKey = NULL;
86 LPWSTR SystemStartOptions = NULL;
87 LPWSTR CurrentOption, NextOption; /* Pointers into SystemStartOptions */
88 LONG rc;
89 BOOL ret = FALSE;
90
91 TRACE("()\n");
92
93 rc = RegOpenKeyEx(
94 HKEY_LOCAL_MACHINE,
95 REGSTR_PATH_CURRENT_CONTROL_SET,
96 0,
97 KEY_QUERY_VALUE,
98 &ControlKey);
99 if (rc != ERROR_SUCCESS)
100 {
101 WARN("RegOpenKeyEx() failed with error %lu\n", rc);
102 goto cleanup;
103 }
104
105 rc = ReadRegSzKey(ControlKey, L"SystemStartOptions", &SystemStartOptions);
106 if (rc != ERROR_SUCCESS)
107 {
108 WARN("ReadRegSzKey() failed with error %lu\n", rc);
109 goto cleanup;
110 }
111
112 /* Check for CONSOLE switch in SystemStartOptions */
113 CurrentOption = SystemStartOptions;
114 while (CurrentOption)
115 {
116 NextOption = wcschr(CurrentOption, L' ');
117 if (NextOption)
118 *NextOption = L'\0';
119 if (_wcsicmp(CurrentOption, L"CONSOLE") == 0)
120 {
121 TRACE("Found 'CONSOLE' boot option\n");
122 ret = TRUE;
123 goto cleanup;
124 }
125 CurrentOption = NextOption ? NextOption + 1 : NULL;
126 }
127
128 cleanup:
129 if (ControlKey != NULL)
130 RegCloseKey(ControlKey);
131 HeapFree(GetProcessHeap(), 0, SystemStartOptions);
132 TRACE("IsConsoleShell() returning %d\n", ret);
133 return ret;
134 }
135
136 static BOOL
137 GetShell(
138 OUT WCHAR *CommandLine, /* must be at least MAX_PATH long */
139 IN HKEY hRootKey)
140 {
141 HKEY hKey;
142 DWORD Type, Size;
143 WCHAR Shell[MAX_PATH];
144 BOOL ConsoleShell = IsConsoleShell();
145 LONG rc;
146
147 TRACE("(%p, %p)\n", CommandLine, hRootKey);
148
149 rc = RegOpenKeyExW(hRootKey, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
150 0, KEY_QUERY_VALUE, &hKey);
151 if (rc != ERROR_SUCCESS)
152 {
153 WARN("RegOpenKeyEx() failed with error %lu\n", rc);
154 return FALSE;
155 }
156
157 Size = sizeof(Shell);
158 rc = RegQueryValueExW(hKey,
159 ConsoleShell ? L"ConsoleShell" : L"Shell",
160 NULL,
161 &Type,
162 (LPBYTE)Shell,
163 &Size);
164 RegCloseKey(hKey);
165
166 if (rc != ERROR_SUCCESS)
167 {
168 WARN("RegQueryValueEx() failed with error %lu\n", rc);
169 return FALSE;
170 }
171
172 if ((Type == REG_SZ) || (Type == REG_EXPAND_SZ))
173 {
174 TRACE("Found command line %s\n", debugstr_w(Shell));
175 wcscpy(CommandLine, Shell);
176 return TRUE;
177 }
178 else
179 {
180 WARN("Wrong type %lu (expected %u or %u)\n", Type, REG_SZ, REG_EXPAND_SZ);
181 return FALSE;
182 }
183 }
184
185 static VOID
186 StartAutoApplications(
187 IN INT clsid)
188 {
189 WCHAR szPath[MAX_PATH] = {0};
190 HRESULT hResult;
191 HANDLE hFind;
192 WIN32_FIND_DATAW findData;
193 SHELLEXECUTEINFOW ExecInfo;
194 size_t len;
195
196 TRACE("(%d)\n", clsid);
197
198 hResult = SHGetFolderPathW(NULL, clsid, NULL, SHGFP_TYPE_CURRENT, szPath);
199 len = wcslen(szPath);
200 if (!SUCCEEDED(hResult) || len == 0)
201 {
202 WARN("SHGetFolderPath() failed with error %lu\n", GetLastError());
203 return;
204 }
205
206 wcscat(szPath, L"\\*");
207 hFind = FindFirstFileW(szPath, &findData);
208 if (hFind == INVALID_HANDLE_VALUE)
209 {
210 WARN("FindFirstFile(%s) failed with error %lu\n", debugstr_w(szPath), GetLastError());
211 return;
212 }
213
214 do
215 {
216 if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && (findData.nFileSizeHigh || findData.nFileSizeLow))
217 {
218 ZeroMemory(&ExecInfo, sizeof(ExecInfo));
219 ExecInfo.cbSize = sizeof(ExecInfo);
220 wcscpy(&szPath[len+1], findData.cFileName);
221 ExecInfo.lpVerb = L"open";
222 ExecInfo.lpFile = szPath;
223 ExecInfo.lpDirectory = NULL;
224 TRACE("Executing %s in directory %s\n",
225 debugstr_w(findData.cFileName), debugstr_w(szPath));
226 ShellExecuteExW(&ExecInfo);
227 }
228 } while (FindNextFileW(hFind, &findData));
229 FindClose(hFind);
230 }
231
232 static BOOL
233 TryToStartShell(
234 IN LPCWSTR Shell)
235 {
236 STARTUPINFO si;
237 PROCESS_INFORMATION pi;
238 WCHAR ExpandedShell[MAX_PATH];
239
240 TRACE("(%s)\n", debugstr_w(Shell));
241
242 ZeroMemory(&si, sizeof(si));
243 si.cb = sizeof(si);
244 si.dwFlags = STARTF_USESHOWWINDOW;
245 si.wShowWindow = SW_SHOWNORMAL;
246 ZeroMemory(&pi, sizeof(pi));
247
248 ExpandEnvironmentStringsW(Shell, ExpandedShell, ARRAYSIZE(ExpandedShell));
249
250 if (!CreateProcessW(NULL,
251 ExpandedShell,
252 NULL,
253 NULL,
254 FALSE,
255 NORMAL_PRIORITY_CLASS,
256 NULL,
257 NULL,
258 &si,
259 &pi))
260 {
261 WARN("CreateProcess() failed with error %lu\n", GetLastError());
262 return FALSE;
263 }
264
265 StartAutoApplications(CSIDL_STARTUP);
266 StartAutoApplications(CSIDL_COMMON_STARTUP);
267 CloseHandle(pi.hProcess);
268 CloseHandle(pi.hThread);
269 return TRUE;
270 }
271
272 static BOOL
273 StartShell(VOID)
274 {
275 WCHAR Shell[MAX_PATH];
276 WCHAR szMsg[RC_STRING_MAX_SIZE];
277 DWORD Type, Size;
278 DWORD Value = 0;
279 LONG rc;
280 HKEY hKey;
281
282 TRACE("()\n");
283
284 /* Safe Mode shell run */
285 rc = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
286 L"SYSTEM\\CurrentControlSet\\Control\\SafeBoot\\Option",
287 0, KEY_QUERY_VALUE, &hKey);
288 if (rc == ERROR_SUCCESS)
289 {
290 Size = sizeof(Value);
291 rc = RegQueryValueExW(hKey, L"UseAlternateShell", NULL,
292 &Type, (LPBYTE)&Value, &Size);
293 RegCloseKey(hKey);
294
295 if (rc == ERROR_SUCCESS)
296 {
297 if (Type == REG_DWORD)
298 {
299 if (Value)
300 {
301 /* Safe Mode Alternate Shell required */
302 rc = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
303 L"SYSTEM\\CurrentControlSet\\Control\\SafeBoot",
304 0, KEY_READ, &hKey);
305 if (rc == ERROR_SUCCESS)
306 {
307 Size = sizeof(Shell);
308 rc = RegQueryValueExW(hKey, L"AlternateShell", NULL,
309 &Type, (LPBYTE)Shell, &Size);
310 RegCloseKey(hKey);
311
312 if (rc == ERROR_SUCCESS)
313 {
314 if ((Type == REG_SZ) || (Type == REG_EXPAND_SZ))
315 {
316 TRACE("Key located - %s\n", debugstr_w(Shell));
317
318 /* Try to run alternate shell */
319 if (TryToStartShell(Shell))
320 {
321 TRACE("Alternate shell started (Safe Mode)\n");
322 return TRUE;
323 }
324 }
325 else
326 {
327 WARN("Wrong type %lu (expected %u or %u)\n",
328 Type, REG_SZ, REG_EXPAND_SZ);
329 }
330 }
331 else
332 {
333 WARN("Alternate shell in Safe Mode required but not specified.");
334 }
335 }
336 }
337 }
338 else
339 {
340 WARN("Wrong type %lu (expected %u)\n", Type, REG_DWORD);
341 }
342 }
343 }
344
345 /* Try to run shell in user key */
346 if (GetShell(Shell, HKEY_CURRENT_USER) && TryToStartShell(Shell))
347 {
348 TRACE("Started shell from HKEY_CURRENT_USER\n");
349 return TRUE;
350 }
351
352 /* Try to run shell in local machine key */
353 if (GetShell(Shell, HKEY_LOCAL_MACHINE) && TryToStartShell(Shell))
354 {
355 TRACE("Started shell from HKEY_LOCAL_MACHINE\n");
356 return TRUE;
357 }
358
359 /* Try default shell */
360 if (IsConsoleShell())
361 {
362 if (GetSystemDirectoryW(Shell, ARRAYSIZE(Shell) - 8))
363 wcscat(Shell, L"\\cmd.exe");
364 else
365 wcscpy(Shell, L"cmd.exe");
366 }
367 else
368 {
369 if (GetWindowsDirectoryW(Shell, ARRAYSIZE(Shell) - 13))
370 wcscat(Shell, L"\\explorer.exe");
371 else
372 wcscpy(Shell, L"explorer.exe");
373 }
374
375 if (!TryToStartShell(Shell))
376 {
377 WARN("Failed to start default shell %s\n", debugstr_w(Shell));
378 LoadStringW(GetModuleHandle(NULL), IDS_SHELL_FAIL, szMsg, ARRAYSIZE(szMsg));
379 MessageBoxW(NULL, szMsg, NULL, MB_OK);
380 return FALSE;
381 }
382 return TRUE;
383 }
384
385 const WCHAR g_RegColorNames[][32] = {
386 L"Scrollbar", /* 00 = COLOR_SCROLLBAR */
387 L"Background", /* 01 = COLOR_DESKTOP */
388 L"ActiveTitle", /* 02 = COLOR_ACTIVECAPTION */
389 L"InactiveTitle", /* 03 = COLOR_INACTIVECAPTION */
390 L"Menu", /* 04 = COLOR_MENU */
391 L"Window", /* 05 = COLOR_WINDOW */
392 L"WindowFrame", /* 06 = COLOR_WINDOWFRAME */
393 L"MenuText", /* 07 = COLOR_MENUTEXT */
394 L"WindowText", /* 08 = COLOR_WINDOWTEXT */
395 L"TitleText", /* 09 = COLOR_CAPTIONTEXT */
396 L"ActiveBorder", /* 10 = COLOR_ACTIVEBORDER */
397 L"InactiveBorder", /* 11 = COLOR_INACTIVEBORDER */
398 L"AppWorkSpace", /* 12 = COLOR_APPWORKSPACE */
399 L"Hilight", /* 13 = COLOR_HIGHLIGHT */
400 L"HilightText", /* 14 = COLOR_HIGHLIGHTTEXT */
401 L"ButtonFace", /* 15 = COLOR_BTNFACE */
402 L"ButtonShadow", /* 16 = COLOR_BTNSHADOW */
403 L"GrayText", /* 17 = COLOR_GRAYTEXT */
404 L"ButtonText", /* 18 = COLOR_BTNTEXT */
405 L"InactiveTitleText", /* 19 = COLOR_INACTIVECAPTIONTEXT */
406 L"ButtonHilight", /* 20 = COLOR_BTNHIGHLIGHT */
407 L"ButtonDkShadow", /* 21 = COLOR_3DDKSHADOW */
408 L"ButtonLight", /* 22 = COLOR_3DLIGHT */
409 L"InfoText", /* 23 = COLOR_INFOTEXT */
410 L"InfoWindow", /* 24 = COLOR_INFOBK */
411 L"ButtonAlternateFace", /* 25 = COLOR_ALTERNATEBTNFACE */
412 L"HotTrackingColor", /* 26 = COLOR_HOTLIGHT */
413 L"GradientActiveTitle", /* 27 = COLOR_GRADIENTACTIVECAPTION */
414 L"GradientInactiveTitle", /* 28 = COLOR_GRADIENTINACTIVECAPTION */
415 L"MenuHilight", /* 29 = COLOR_MENUHILIGHT */
416 L"MenuBar" /* 30 = COLOR_MENUBAR */
417 };
418
419 static COLORREF
420 StrToColorref(
421 IN LPWSTR lpszCol)
422 {
423 BYTE rgb[3];
424
425 TRACE("(%s)\n", debugstr_w(lpszCol));
426
427 rgb[0] = (BYTE)wcstoul(lpszCol, &lpszCol, 10);
428 rgb[1] = (BYTE)wcstoul(lpszCol, &lpszCol, 10);
429 rgb[2] = (BYTE)wcstoul(lpszCol, &lpszCol, 10);
430 return RGB(rgb[0], rgb[1], rgb[2]);
431 }
432
433 static VOID
434 SetUserSysColors(VOID)
435 {
436 HKEY hKey;
437 INT i;
438 WCHAR szColor[25];
439 DWORD Type, Size;
440 COLORREF crColor;
441 LONG rc;
442
443 TRACE("()\n");
444
445 rc = RegOpenKeyExW(HKEY_CURRENT_USER, REGSTR_PATH_COLORS,
446 0, KEY_QUERY_VALUE, &hKey);
447 if (rc != ERROR_SUCCESS)
448 {
449 WARN("RegOpenKeyEx() failed with error %lu\n", rc);
450 return;
451 }
452
453 for (i = 0; i < ARRAYSIZE(g_RegColorNames); i++)
454 {
455 Size = sizeof(szColor);
456 rc = RegQueryValueExW(hKey, g_RegColorNames[i], NULL, &Type,
457 (LPBYTE)szColor, &Size);
458 if (rc == ERROR_SUCCESS && Type == REG_SZ)
459 {
460 crColor = StrToColorref(szColor);
461 SetSysColors(1, &i, &crColor);
462 }
463 else
464 {
465 WARN("RegQueryValueEx(%s) failed with error %lu\n",
466 debugstr_w(g_RegColorNames[i]), rc);
467 }
468 }
469
470 RegCloseKey(hKey);
471 }
472
473 static VOID
474 SetUserWallpaper(VOID)
475 {
476 HKEY hKey;
477 DWORD Type, Size;
478 WCHAR szWallpaper[MAX_PATH + 1];
479 LONG rc;
480
481 TRACE("()\n");
482
483 rc = RegOpenKeyExW(HKEY_CURRENT_USER, REGSTR_PATH_DESKTOP,
484 0, KEY_QUERY_VALUE, &hKey);
485 if (rc != ERROR_SUCCESS)
486 {
487 WARN("RegOpenKeyEx() failed with error %lu\n", rc);
488 return;
489 }
490
491 Size = sizeof(szWallpaper);
492 rc = RegQueryValueExW(hKey,
493 L"Wallpaper",
494 NULL,
495 &Type,
496 (LPBYTE)szWallpaper,
497 &Size);
498 RegCloseKey(hKey);
499
500 if (rc == ERROR_SUCCESS && Type == REG_SZ)
501 {
502 ExpandEnvironmentStringsW(szWallpaper, szWallpaper, ARRAYSIZE(szWallpaper));
503 TRACE("Using wallpaper %s\n", debugstr_w(szWallpaper));
504
505 /* Load and change the wallpaper */
506 SystemParametersInfoW(SPI_SETDESKWALLPAPER, 0, szWallpaper, SPIF_SENDCHANGE);
507 }
508 else
509 {
510 /* Remove the wallpaper */
511 TRACE("No wallpaper set in registry (error %lu)\n", rc);
512 SystemParametersInfoW(SPI_SETDESKWALLPAPER, 0, NULL, SPIF_SENDCHANGE);
513 }
514 }
515
516 static VOID
517 SetUserSettings(VOID)
518 {
519 TRACE("()\n");
520
521 UpdatePerUserSystemParameters(1, TRUE);
522 SetUserSysColors();
523 SetUserWallpaper();
524 }
525
526 typedef DWORD (WINAPI *PCMP_REPORT_LOGON)(DWORD, DWORD);
527
528 static VOID
529 NotifyLogon(VOID)
530 {
531 HINSTANCE hModule;
532 PCMP_REPORT_LOGON CMP_Report_LogOn;
533
534 TRACE("()\n");
535
536 hModule = LoadLibraryW(L"setupapi.dll");
537 if (!hModule)
538 {
539 WARN("LoadLibrary() failed with error %lu\n", GetLastError());
540 return;
541 }
542
543 CMP_Report_LogOn = (PCMP_REPORT_LOGON)GetProcAddress(hModule, "CMP_Report_LogOn");
544 if (CMP_Report_LogOn)
545 CMP_Report_LogOn(CMP_MAGIC, GetCurrentProcessId());
546 else
547 WARN("GetProcAddress() failed\n");
548
549 FreeLibrary(hModule);
550 }
551
552 static BOOL
553 StartInstaller(VOID)
554 {
555 WCHAR Shell[MAX_PATH];
556 WCHAR szMsg[RC_STRING_MAX_SIZE];
557
558 if (GetWindowsDirectoryW(Shell, ARRAYSIZE(Shell) - 12))
559 wcscat(Shell, L"\\reactos.exe");
560 else
561 wcscpy(Shell, L"reactos.exe");
562
563 if (!TryToStartShell(Shell))
564 {
565 WARN("Failed to start the installer: %s\n", debugstr_w(Shell));
566 LoadStringW(GetModuleHandle(NULL), IDS_INSTALLER_FAIL, szMsg, ARRAYSIZE(szMsg));
567 MessageBoxW(NULL, szMsg, NULL, MB_OK);
568 return FALSE;
569 }
570 return TRUE;
571 }
572
573
574 int WINAPI
575 wWinMain(IN HINSTANCE hInst,
576 IN HINSTANCE hPrevInstance,
577 IN LPWSTR lpszCmdLine,
578 IN int nCmdShow)
579 {
580 STATE State;
581
582 hInstance = hInst;
583
584 SetUserSettings();
585
586 if (IsLiveCD())
587 {
588 State.NextPage = LOCALEPAGE;
589 State.Run = SHELL;
590 }
591 else
592 {
593 State.NextPage = DONE;
594 State.Run = SHELL;
595 }
596
597 if (State.NextPage != DONE)
598 {
599 RunLiveCD(&State);
600 }
601
602 if (State.Run == SHELL)
603 {
604 StartShell();
605 NotifyLogon();
606 }
607 else if (State.Run == INSTALLER)
608 {
609 StartInstaller();
610 }
611
612 return 0;
613 }
614
615 /* EOF */