[FLTMC]
[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)] = '\0';
77
78 *pValue = Value;
79 return ERROR_SUCCESS;
80 }
81
82 static
83 BOOL 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
137 BOOL 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 Ret = FALSE;
145 BOOL ConsoleShell = IsConsoleShell();
146 LONG rc;
147
148 TRACE("(%p, %p)\n", CommandLine, hRootKey);
149
150 rc = RegOpenKeyExW(hRootKey, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
151 0, KEY_QUERY_VALUE, &hKey);
152 if (rc == ERROR_SUCCESS)
153 {
154 Size = MAX_PATH * sizeof(WCHAR);
155 rc = RegQueryValueExW(hKey,
156 ConsoleShell ? L"ConsoleShell" : L"Shell",
157 NULL,
158 &Type,
159 (LPBYTE)Shell,
160 &Size);
161 if (rc == ERROR_SUCCESS)
162 {
163 if ((Type == REG_SZ) || (Type == REG_EXPAND_SZ))
164 {
165 TRACE("Found command line %s\n", debugstr_w(Shell));
166 wcscpy(CommandLine, Shell);
167 Ret = TRUE;
168 }
169 else
170 WARN("Wrong type %lu (expected %u or %u)\n", Type, REG_SZ, REG_EXPAND_SZ);
171 }
172 else
173 WARN("RegQueryValueEx() failed with error %lu\n", rc);
174 RegCloseKey(hKey);
175 }
176 else
177 WARN("RegOpenKeyEx() failed with error %lu\n", rc);
178
179 return Ret;
180 }
181
182 static VOID
183 StartAutoApplications(
184 IN INT clsid)
185 {
186 WCHAR szPath[MAX_PATH] = {0};
187 HRESULT hResult;
188 HANDLE hFind;
189 WIN32_FIND_DATAW findData;
190 SHELLEXECUTEINFOW ExecInfo;
191 size_t len;
192
193 TRACE("(%d)\n", clsid);
194
195 hResult = SHGetFolderPathW(NULL, clsid, NULL, SHGFP_TYPE_CURRENT, szPath);
196 len = wcslen(szPath);
197 if (!SUCCEEDED(hResult) || len == 0)
198 {
199 WARN("SHGetFolderPath() failed with error %lu\n", GetLastError());
200 return;
201 }
202
203 wcscat(szPath, L"\\*");
204 hFind = FindFirstFileW(szPath, &findData);
205 if (hFind == INVALID_HANDLE_VALUE)
206 {
207 WARN("FindFirstFile(%s) failed with error %lu\n", debugstr_w(szPath), GetLastError());
208 return;
209 }
210
211 do
212 {
213 if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && (findData.nFileSizeHigh || findData.nFileSizeLow))
214 {
215 ZeroMemory(&ExecInfo, sizeof(SHELLEXECUTEINFOW));
216 ExecInfo.cbSize = sizeof(ExecInfo);
217 wcscpy(&szPath[len+1], findData.cFileName);
218 ExecInfo.lpVerb = L"open";
219 ExecInfo.lpFile = szPath;
220 ExecInfo.lpDirectory = NULL;
221 TRACE("Executing %s in directory %s\n",
222 debugstr_w(findData.cFileName), debugstr_w(szPath));
223 ShellExecuteExW(&ExecInfo);
224 }
225 } while (FindNextFileW(hFind, &findData));
226 FindClose(hFind);
227 }
228
229 static BOOL
230 TryToStartShell(
231 IN LPCWSTR Shell)
232 {
233 STARTUPINFO si;
234 PROCESS_INFORMATION pi;
235 WCHAR ExpandedShell[MAX_PATH];
236
237 TRACE("(%s)\n", debugstr_w(Shell));
238
239 ZeroMemory(&si, sizeof(si));
240 si.cb = sizeof(si);
241 si.dwFlags = STARTF_USESHOWWINDOW;
242 si.wShowWindow = SW_SHOWNORMAL;
243 ZeroMemory(&pi, sizeof(pi));
244
245 ExpandEnvironmentStrings(Shell, ExpandedShell, MAX_PATH);
246
247 if (!CreateProcess(NULL,
248 ExpandedShell,
249 NULL,
250 NULL,
251 FALSE,
252 NORMAL_PRIORITY_CLASS,
253 NULL,
254 NULL,
255 &si,
256 &pi))
257 {
258 WARN("CreateProcess() failed with error %lu\n", GetLastError());
259 return FALSE;
260 }
261
262 StartAutoApplications(CSIDL_STARTUP);
263 StartAutoApplications(CSIDL_COMMON_STARTUP);
264 CloseHandle(pi.hProcess);
265 CloseHandle(pi.hThread);
266 return TRUE;
267 }
268
269 static
270 VOID StartShell(VOID)
271 {
272 WCHAR Shell[MAX_PATH];
273 TCHAR szMsg[RC_STRING_MAX_SIZE];
274 DWORD Type, Size;
275 DWORD Value = 0;
276 LONG rc;
277 HKEY hKey;
278
279 TRACE("()\n");
280
281 /* Safe Mode shell run */
282 rc = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
283 L"SYSTEM\\CurrentControlSet\\Control\\SafeBoot\\Option",
284 0, KEY_QUERY_VALUE, &hKey);
285 if(rc == ERROR_SUCCESS)
286 {
287 Size = sizeof(Value);
288 rc = RegQueryValueExW(hKey, L"UseAlternateShell", NULL,
289 &Type, (LPBYTE)&Value, &Size);
290 if(rc == ERROR_SUCCESS)
291 {
292 RegCloseKey(hKey);
293 if(Type == REG_DWORD)
294 {
295 if(Value)
296 {
297 /* Safe Mode Alternate Shell required */
298 rc = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
299 L"SYSTEM\\CurrentControlSet\\Control\\SafeBoot",
300 0, KEY_READ, &hKey);
301 if(rc == ERROR_SUCCESS)
302 {
303 Size = MAX_PATH * sizeof(WCHAR);
304 rc = RegQueryValueExW(hKey, L"AlternateShell", NULL,
305 &Type, (LPBYTE)Shell, &Size);
306 if(rc == ERROR_SUCCESS)
307 {
308 RegCloseKey(hKey);
309 if ((Type == REG_SZ) || (Type == REG_EXPAND_SZ))
310 {
311 TRACE("Key located - %s\n", debugstr_w(Shell));
312 /* Try to run alternate shell */
313 if (TryToStartShell(Shell))
314 {
315 TRACE("Alternate shell started (Safe Mode)\n");
316 return;
317 }
318 }
319 else
320 {
321 WARN("Wrong type %lu (expected %u or %u)\n",
322 Type, REG_SZ, REG_EXPAND_SZ);
323 }
324 }
325 else
326 {
327 WARN("Alternate shell in Safe Mode required but not specified.");
328 }
329 }
330 }
331 }
332 else
333 {
334 WARN("Wrong type %lu (expected %u)\n", Type, REG_DWORD);
335 }
336 }
337 }
338 /* Try to run shell in user key */
339 if (GetShell(Shell, HKEY_CURRENT_USER) && TryToStartShell(Shell))
340 {
341 TRACE("Started shell from HKEY_CURRENT_USER\n");
342 return;
343 }
344
345 /* Try to run shell in local machine key */
346 if (GetShell(Shell, HKEY_LOCAL_MACHINE) && TryToStartShell(Shell))
347 {
348 TRACE("Started shell from HKEY_LOCAL_MACHINE\n");
349 return;
350 }
351
352 /* Try default shell */
353 if (IsConsoleShell())
354 {
355 if (GetSystemDirectory(Shell, MAX_PATH - 8))
356 wcscat(Shell, L"\\cmd.exe");
357 else
358 wcscpy(Shell, L"cmd.exe");
359 }
360 else
361 {
362 if (GetWindowsDirectory(Shell, MAX_PATH - 13))
363 wcscat(Shell, L"\\explorer.exe");
364 else
365 wcscpy(Shell, L"explorer.exe");
366 }
367 if (!TryToStartShell(Shell))
368 {
369 WARN("Failed to start default shell %s\n", debugstr_w(Shell));
370 LoadString( GetModuleHandle(NULL), IDS_SHELL_FAIL, szMsg, sizeof(szMsg) / sizeof(szMsg[0]));
371 MessageBox(0, szMsg, NULL, 0);
372 }
373 }
374
375 const WCHAR g_RegColorNames[][32] = {
376 L"Scrollbar", /* 00 = COLOR_SCROLLBAR */
377 L"Background", /* 01 = COLOR_DESKTOP */
378 L"ActiveTitle", /* 02 = COLOR_ACTIVECAPTION */
379 L"InactiveTitle", /* 03 = COLOR_INACTIVECAPTION */
380 L"Menu", /* 04 = COLOR_MENU */
381 L"Window", /* 05 = COLOR_WINDOW */
382 L"WindowFrame", /* 06 = COLOR_WINDOWFRAME */
383 L"MenuText", /* 07 = COLOR_MENUTEXT */
384 L"WindowText", /* 08 = COLOR_WINDOWTEXT */
385 L"TitleText", /* 09 = COLOR_CAPTIONTEXT */
386 L"ActiveBorder", /* 10 = COLOR_ACTIVEBORDER */
387 L"InactiveBorder", /* 11 = COLOR_INACTIVEBORDER */
388 L"AppWorkSpace", /* 12 = COLOR_APPWORKSPACE */
389 L"Hilight", /* 13 = COLOR_HIGHLIGHT */
390 L"HilightText", /* 14 = COLOR_HIGHLIGHTTEXT */
391 L"ButtonFace", /* 15 = COLOR_BTNFACE */
392 L"ButtonShadow", /* 16 = COLOR_BTNSHADOW */
393 L"GrayText", /* 17 = COLOR_GRAYTEXT */
394 L"ButtonText", /* 18 = COLOR_BTNTEXT */
395 L"InactiveTitleText", /* 19 = COLOR_INACTIVECAPTIONTEXT */
396 L"ButtonHilight", /* 20 = COLOR_BTNHIGHLIGHT */
397 L"ButtonDkShadow", /* 21 = COLOR_3DDKSHADOW */
398 L"ButtonLight", /* 22 = COLOR_3DLIGHT */
399 L"InfoText", /* 23 = COLOR_INFOTEXT */
400 L"InfoWindow", /* 24 = COLOR_INFOBK */
401 L"ButtonAlternateFace", /* 25 = COLOR_ALTERNATEBTNFACE */
402 L"HotTrackingColor", /* 26 = COLOR_HOTLIGHT */
403 L"GradientActiveTitle", /* 27 = COLOR_GRADIENTACTIVECAPTION */
404 L"GradientInactiveTitle", /* 28 = COLOR_GRADIENTINACTIVECAPTION */
405 L"MenuHilight", /* 29 = COLOR_MENUHILIGHT */
406 L"MenuBar" /* 30 = COLOR_MENUBAR */
407 };
408 #define NUM_SYSCOLORS (sizeof(g_RegColorNames) / sizeof(g_RegColorNames[0]))
409
410 static
411 COLORREF StrToColorref(
412 IN LPWSTR lpszCol)
413 {
414 BYTE rgb[3];
415
416 TRACE("(%s)\n", debugstr_w(lpszCol));
417
418 rgb[0] = (BYTE)wcstoul(lpszCol, &lpszCol, 10);
419 rgb[1] = (BYTE)wcstoul(lpszCol, &lpszCol, 10);
420 rgb[2] = (BYTE)wcstoul(lpszCol, &lpszCol, 10);
421 return RGB(rgb[0], rgb[1], rgb[2]);
422 }
423
424 static
425 VOID SetUserSysColors(VOID)
426 {
427 HKEY hKey;
428 INT i;
429 WCHAR szColor[25];
430 DWORD Type, Size;
431 COLORREF crColor;
432 LONG rc;
433
434 TRACE("()\n");
435
436 rc = RegOpenKeyEx(HKEY_CURRENT_USER, REGSTR_PATH_COLORS,
437 0, KEY_QUERY_VALUE, &hKey);
438 if (rc != ERROR_SUCCESS)
439 {
440 WARN("RegOpenKeyEx() failed with error %lu\n", rc);
441 return;
442 }
443 for(i = 0; i < NUM_SYSCOLORS; i++)
444 {
445 Size = sizeof(szColor);
446 rc = RegQueryValueEx(hKey, g_RegColorNames[i], NULL, &Type,
447 (LPBYTE)szColor, &Size);
448 if (rc == ERROR_SUCCESS && Type == REG_SZ)
449 {
450 crColor = StrToColorref(szColor);
451 SetSysColors(1, &i, &crColor);
452 }
453 else
454 WARN("RegQueryValueEx(%s) failed with error %lu\n",
455 debugstr_w(g_RegColorNames[i]), rc);
456 }
457 RegCloseKey(hKey);
458 }
459
460 static
461 VOID SetUserWallpaper(VOID)
462 {
463 HKEY hKey;
464 DWORD Type, Size;
465 WCHAR szWallpaper[MAX_PATH + 1];
466 LONG rc;
467
468 TRACE("()\n");
469
470 rc = RegOpenKeyEx(HKEY_CURRENT_USER, REGSTR_PATH_DESKTOP,
471 0, KEY_QUERY_VALUE, &hKey);
472 if (rc == ERROR_SUCCESS)
473 {
474 Size = sizeof(szWallpaper);
475 rc = RegQueryValueEx(hKey,
476 L"Wallpaper",
477 NULL,
478 &Type,
479 (LPBYTE)szWallpaper,
480 &Size);
481 if (rc == ERROR_SUCCESS && Type == REG_SZ)
482 {
483 ExpandEnvironmentStrings(szWallpaper, szWallpaper, MAX_PATH);
484 TRACE("Using wallpaper %s\n", debugstr_w(szWallpaper));
485
486 /* Load and change the wallpaper */
487 SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, szWallpaper, SPIF_SENDCHANGE);
488 }
489 else
490 {
491 /* remove the wallpaper */
492 TRACE("No wallpaper set in registry (error %lu)\n", rc);
493 SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, NULL, SPIF_SENDCHANGE);
494 }
495 RegCloseKey(hKey);
496 }
497 else
498 WARN("RegOpenKeyEx() failed with error %lu\n", rc);
499 }
500
501 static
502 VOID SetUserSettings(VOID)
503 {
504 TRACE("()\n");
505
506 UpdatePerUserSystemParameters(1, TRUE);
507 SetUserSysColors();
508 SetUserWallpaper();
509 }
510
511 typedef DWORD (WINAPI *PCMP_REPORT_LOGON)(DWORD, DWORD);
512
513 static VOID
514 NotifyLogon(VOID)
515 {
516 HINSTANCE hModule;
517 PCMP_REPORT_LOGON CMP_Report_LogOn;
518
519 TRACE("()\n");
520
521 hModule = LoadLibrary(L"setupapi.dll");
522 if (hModule)
523 {
524 CMP_Report_LogOn = (PCMP_REPORT_LOGON)GetProcAddress(hModule, "CMP_Report_LogOn");
525 if (CMP_Report_LogOn)
526 CMP_Report_LogOn(CMP_MAGIC, GetCurrentProcessId());
527 else
528 WARN("GetProcAddress() failed\n");
529
530 FreeLibrary(hModule);
531 }
532 else
533 WARN("LoadLibrary() failed with error %lu\n", GetLastError());
534 }
535
536 static
537 VOID
538 StartInstaller(VOID)
539 {
540 WCHAR Shell[MAX_PATH];
541 WCHAR szMsg[RC_STRING_MAX_SIZE];
542
543 if (GetWindowsDirectory(Shell, MAX_PATH - 12))
544 wcscat(Shell, L"\\reactos.exe");
545 else
546 wcscpy(Shell, L"reactos.exe");
547
548 if (!TryToStartShell(Shell))
549 {
550 ERR("Failed to start the installer: %s\n", debugstr_w(Shell));
551 LoadStringW(GetModuleHandle(NULL), IDS_INSTALLER_FAIL, szMsg, sizeof(szMsg) / sizeof(szMsg[0]));
552 MessageBoxW(0, szMsg, NULL, 0);
553 }
554 }
555
556
557 #ifdef _MSC_VER
558 #pragma warning(disable : 4100)
559 #endif /* _MSC_VER */
560
561 int WINAPI
562 wWinMain(IN HINSTANCE hInst,
563 IN HINSTANCE hPrevInstance,
564 IN LPWSTR lpszCmdLine,
565 IN int nCmdShow)
566 {
567 STATE State;
568
569 hInstance = hInst;
570
571 SetUserSettings();
572
573 if (IsLiveCD())
574 {
575 State.NextPage = LOCALEPAGE;
576 State.Run = SHELL;
577 }
578 else
579 {
580 State.NextPage = DONE;
581 State.Run = SHELL;
582 }
583
584 if (State.NextPage != DONE)
585 {
586 RunLiveCD(&State);
587 }
588
589 if (State.Run == SHELL)
590 {
591 StartShell();
592 NotifyLogon();
593 }
594 else if (State.Run == INSTALLER)
595 {
596 StartInstaller();
597 }
598
599 return 0;
600 }
601
602 /* EOF */