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 BOOL 186 TryToStartShell( 187 IN LPCWSTR Shell) 188 { 189 STARTUPINFO si; 190 PROCESS_INFORMATION pi; 191 WCHAR ExpandedShell[MAX_PATH]; 192 193 TRACE("(%s)\n", debugstr_w(Shell)); 194 195 ZeroMemory(&si, sizeof(si)); 196 si.cb = sizeof(si); 197 si.dwFlags = STARTF_USESHOWWINDOW; 198 si.wShowWindow = SW_SHOWNORMAL; 199 ZeroMemory(&pi, sizeof(pi)); 200 201 ExpandEnvironmentStringsW(Shell, ExpandedShell, ARRAYSIZE(ExpandedShell)); 202 203 if (!CreateProcessW(NULL, 204 ExpandedShell, 205 NULL, 206 NULL, 207 FALSE, 208 NORMAL_PRIORITY_CLASS, 209 NULL, 210 NULL, 211 &si, 212 &pi)) 213 { 214 WARN("CreateProcess() failed with error %lu\n", GetLastError()); 215 return FALSE; 216 } 217 218 CloseHandle(pi.hProcess); 219 CloseHandle(pi.hThread); 220 return TRUE; 221 } 222 223 static BOOL 224 StartShell(VOID) 225 { 226 WCHAR Shell[MAX_PATH]; 227 WCHAR szMsg[RC_STRING_MAX_SIZE]; 228 DWORD Type, Size; 229 DWORD Value = 0; 230 LONG rc; 231 HKEY hKey; 232 233 TRACE("()\n"); 234 235 /* Safe Mode shell run */ 236 rc = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 237 L"SYSTEM\\CurrentControlSet\\Control\\SafeBoot\\Option", 238 0, KEY_QUERY_VALUE, &hKey); 239 if (rc == ERROR_SUCCESS) 240 { 241 Size = sizeof(Value); 242 rc = RegQueryValueExW(hKey, L"UseAlternateShell", NULL, 243 &Type, (LPBYTE)&Value, &Size); 244 RegCloseKey(hKey); 245 246 if (rc == ERROR_SUCCESS) 247 { 248 if (Type == REG_DWORD) 249 { 250 if (Value) 251 { 252 /* Safe Mode Alternate Shell required */ 253 rc = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 254 L"SYSTEM\\CurrentControlSet\\Control\\SafeBoot", 255 0, KEY_READ, &hKey); 256 if (rc == ERROR_SUCCESS) 257 { 258 Size = sizeof(Shell); 259 rc = RegQueryValueExW(hKey, L"AlternateShell", NULL, 260 &Type, (LPBYTE)Shell, &Size); 261 RegCloseKey(hKey); 262 263 if (rc == ERROR_SUCCESS) 264 { 265 if ((Type == REG_SZ) || (Type == REG_EXPAND_SZ)) 266 { 267 TRACE("Key located - %s\n", debugstr_w(Shell)); 268 269 /* Try to run alternate shell */ 270 if (TryToStartShell(Shell)) 271 { 272 TRACE("Alternate shell started (Safe Mode)\n"); 273 return TRUE; 274 } 275 } 276 else 277 { 278 WARN("Wrong type %lu (expected %u or %u)\n", 279 Type, REG_SZ, REG_EXPAND_SZ); 280 } 281 } 282 else 283 { 284 WARN("Alternate shell in Safe Mode required but not specified."); 285 } 286 } 287 } 288 } 289 else 290 { 291 WARN("Wrong type %lu (expected %u)\n", Type, REG_DWORD); 292 } 293 } 294 } 295 296 /* Try to run shell in user key */ 297 if (GetShell(Shell, HKEY_CURRENT_USER) && TryToStartShell(Shell)) 298 { 299 TRACE("Started shell from HKEY_CURRENT_USER\n"); 300 return TRUE; 301 } 302 303 /* Try to run shell in local machine key */ 304 if (GetShell(Shell, HKEY_LOCAL_MACHINE) && TryToStartShell(Shell)) 305 { 306 TRACE("Started shell from HKEY_LOCAL_MACHINE\n"); 307 return TRUE; 308 } 309 310 /* Try default shell */ 311 if (IsConsoleShell()) 312 { 313 if (GetSystemDirectoryW(Shell, ARRAYSIZE(Shell) - 8)) 314 wcscat(Shell, L"\\cmd.exe"); 315 else 316 wcscpy(Shell, L"cmd.exe"); 317 } 318 else 319 { 320 if (GetWindowsDirectoryW(Shell, ARRAYSIZE(Shell) - 13)) 321 wcscat(Shell, L"\\explorer.exe"); 322 else 323 wcscpy(Shell, L"explorer.exe"); 324 } 325 326 if (!TryToStartShell(Shell)) 327 { 328 WARN("Failed to start default shell %s\n", debugstr_w(Shell)); 329 LoadStringW(GetModuleHandle(NULL), IDS_SHELL_FAIL, szMsg, ARRAYSIZE(szMsg)); 330 MessageBoxW(NULL, szMsg, NULL, MB_OK); 331 return FALSE; 332 } 333 return TRUE; 334 } 335 336 const WCHAR g_RegColorNames[][32] = { 337 L"Scrollbar", /* 00 = COLOR_SCROLLBAR */ 338 L"Background", /* 01 = COLOR_DESKTOP */ 339 L"ActiveTitle", /* 02 = COLOR_ACTIVECAPTION */ 340 L"InactiveTitle", /* 03 = COLOR_INACTIVECAPTION */ 341 L"Menu", /* 04 = COLOR_MENU */ 342 L"Window", /* 05 = COLOR_WINDOW */ 343 L"WindowFrame", /* 06 = COLOR_WINDOWFRAME */ 344 L"MenuText", /* 07 = COLOR_MENUTEXT */ 345 L"WindowText", /* 08 = COLOR_WINDOWTEXT */ 346 L"TitleText", /* 09 = COLOR_CAPTIONTEXT */ 347 L"ActiveBorder", /* 10 = COLOR_ACTIVEBORDER */ 348 L"InactiveBorder", /* 11 = COLOR_INACTIVEBORDER */ 349 L"AppWorkSpace", /* 12 = COLOR_APPWORKSPACE */ 350 L"Hilight", /* 13 = COLOR_HIGHLIGHT */ 351 L"HilightText", /* 14 = COLOR_HIGHLIGHTTEXT */ 352 L"ButtonFace", /* 15 = COLOR_BTNFACE */ 353 L"ButtonShadow", /* 16 = COLOR_BTNSHADOW */ 354 L"GrayText", /* 17 = COLOR_GRAYTEXT */ 355 L"ButtonText", /* 18 = COLOR_BTNTEXT */ 356 L"InactiveTitleText", /* 19 = COLOR_INACTIVECAPTIONTEXT */ 357 L"ButtonHilight", /* 20 = COLOR_BTNHIGHLIGHT */ 358 L"ButtonDkShadow", /* 21 = COLOR_3DDKSHADOW */ 359 L"ButtonLight", /* 22 = COLOR_3DLIGHT */ 360 L"InfoText", /* 23 = COLOR_INFOTEXT */ 361 L"InfoWindow", /* 24 = COLOR_INFOBK */ 362 L"ButtonAlternateFace", /* 25 = COLOR_ALTERNATEBTNFACE */ 363 L"HotTrackingColor", /* 26 = COLOR_HOTLIGHT */ 364 L"GradientActiveTitle", /* 27 = COLOR_GRADIENTACTIVECAPTION */ 365 L"GradientInactiveTitle", /* 28 = COLOR_GRADIENTINACTIVECAPTION */ 366 L"MenuHilight", /* 29 = COLOR_MENUHILIGHT */ 367 L"MenuBar" /* 30 = COLOR_MENUBAR */ 368 }; 369 370 static COLORREF 371 StrToColorref( 372 IN LPWSTR lpszCol) 373 { 374 BYTE rgb[3]; 375 376 TRACE("(%s)\n", debugstr_w(lpszCol)); 377 378 rgb[0] = (BYTE)wcstoul(lpszCol, &lpszCol, 10); 379 rgb[1] = (BYTE)wcstoul(lpszCol, &lpszCol, 10); 380 rgb[2] = (BYTE)wcstoul(lpszCol, &lpszCol, 10); 381 return RGB(rgb[0], rgb[1], rgb[2]); 382 } 383 384 static VOID 385 SetUserSysColors(VOID) 386 { 387 HKEY hKey; 388 INT i; 389 WCHAR szColor[25]; 390 DWORD Type, Size; 391 COLORREF crColor; 392 LONG rc; 393 394 TRACE("()\n"); 395 396 rc = RegOpenKeyExW(HKEY_CURRENT_USER, REGSTR_PATH_COLORS, 397 0, KEY_QUERY_VALUE, &hKey); 398 if (rc != ERROR_SUCCESS) 399 { 400 WARN("RegOpenKeyEx() failed with error %lu\n", rc); 401 return; 402 } 403 404 for (i = 0; i < ARRAYSIZE(g_RegColorNames); i++) 405 { 406 Size = sizeof(szColor); 407 rc = RegQueryValueExW(hKey, g_RegColorNames[i], NULL, &Type, 408 (LPBYTE)szColor, &Size); 409 if (rc == ERROR_SUCCESS && Type == REG_SZ) 410 { 411 crColor = StrToColorref(szColor); 412 SetSysColors(1, &i, &crColor); 413 } 414 else 415 { 416 WARN("RegQueryValueEx(%s) failed with error %lu\n", 417 debugstr_w(g_RegColorNames[i]), rc); 418 } 419 } 420 421 RegCloseKey(hKey); 422 } 423 424 static VOID 425 SetUserWallpaper(VOID) 426 { 427 HKEY hKey; 428 DWORD Type, Size; 429 WCHAR szWallpaper[MAX_PATH + 1]; 430 LONG rc; 431 432 TRACE("()\n"); 433 434 rc = RegOpenKeyExW(HKEY_CURRENT_USER, REGSTR_PATH_DESKTOP, 435 0, KEY_QUERY_VALUE, &hKey); 436 if (rc != ERROR_SUCCESS) 437 { 438 WARN("RegOpenKeyEx() failed with error %lu\n", rc); 439 return; 440 } 441 442 Size = sizeof(szWallpaper); 443 rc = RegQueryValueExW(hKey, 444 L"Wallpaper", 445 NULL, 446 &Type, 447 (LPBYTE)szWallpaper, 448 &Size); 449 RegCloseKey(hKey); 450 451 if (rc == ERROR_SUCCESS && Type == REG_SZ) 452 { 453 ExpandEnvironmentStringsW(szWallpaper, szWallpaper, ARRAYSIZE(szWallpaper)); 454 TRACE("Using wallpaper %s\n", debugstr_w(szWallpaper)); 455 456 /* Load and change the wallpaper */ 457 SystemParametersInfoW(SPI_SETDESKWALLPAPER, 0, szWallpaper, SPIF_SENDCHANGE); 458 } 459 else 460 { 461 /* Remove the wallpaper */ 462 TRACE("No wallpaper set in registry (error %lu)\n", rc); 463 SystemParametersInfoW(SPI_SETDESKWALLPAPER, 0, NULL, SPIF_SENDCHANGE); 464 } 465 } 466 467 static VOID 468 SetUserSettings(VOID) 469 { 470 TRACE("()\n"); 471 472 UpdatePerUserSystemParameters(1, TRUE); 473 SetUserSysColors(); 474 SetUserWallpaper(); 475 } 476 477 typedef DWORD (WINAPI *PCMP_REPORT_LOGON)(DWORD, DWORD); 478 479 static VOID 480 NotifyLogon(VOID) 481 { 482 HINSTANCE hModule; 483 PCMP_REPORT_LOGON CMP_Report_LogOn; 484 485 TRACE("()\n"); 486 487 hModule = LoadLibraryW(L"setupapi.dll"); 488 if (!hModule) 489 { 490 WARN("LoadLibrary() failed with error %lu\n", GetLastError()); 491 return; 492 } 493 494 CMP_Report_LogOn = (PCMP_REPORT_LOGON)GetProcAddress(hModule, "CMP_Report_LogOn"); 495 if (CMP_Report_LogOn) 496 CMP_Report_LogOn(CMP_MAGIC, GetCurrentProcessId()); 497 else 498 WARN("GetProcAddress() failed\n"); 499 500 FreeLibrary(hModule); 501 } 502 503 static BOOL 504 StartInstaller(VOID) 505 { 506 WCHAR Shell[MAX_PATH]; 507 WCHAR szMsg[RC_STRING_MAX_SIZE]; 508 509 if (GetWindowsDirectoryW(Shell, ARRAYSIZE(Shell) - 12)) 510 wcscat(Shell, L"\\reactos.exe"); 511 else 512 wcscpy(Shell, L"reactos.exe"); 513 514 if (!TryToStartShell(Shell)) 515 { 516 WARN("Failed to start the installer: %s\n", debugstr_w(Shell)); 517 LoadStringW(GetModuleHandle(NULL), IDS_INSTALLER_FAIL, szMsg, ARRAYSIZE(szMsg)); 518 MessageBoxW(NULL, szMsg, NULL, MB_OK); 519 return FALSE; 520 } 521 return TRUE; 522 } 523 524 /* Used to get the shutdown privilege */ 525 static BOOL 526 EnablePrivilege(LPCWSTR lpszPrivilegeName, BOOL bEnablePrivilege) 527 { 528 BOOL Success; 529 HANDLE hToken; 530 TOKEN_PRIVILEGES tp; 531 532 Success = OpenProcessToken(GetCurrentProcess(), 533 TOKEN_ADJUST_PRIVILEGES, 534 &hToken); 535 if (!Success) return Success; 536 537 Success = LookupPrivilegeValueW(NULL, 538 lpszPrivilegeName, 539 &tp.Privileges[0].Luid); 540 if (!Success) goto Quit; 541 542 tp.PrivilegeCount = 1; 543 tp.Privileges[0].Attributes = (bEnablePrivilege ? SE_PRIVILEGE_ENABLED : 0); 544 545 Success = AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL); 546 547 Quit: 548 CloseHandle(hToken); 549 return Success; 550 } 551 552 553 int WINAPI 554 wWinMain(IN HINSTANCE hInst, 555 IN HINSTANCE hPrevInstance, 556 IN LPWSTR lpszCmdLine, 557 IN int nCmdShow) 558 { 559 BOOL bIsLiveCD, Success = TRUE; 560 STATE State; 561 562 hInstance = hInst; 563 564 bIsLiveCD = IsLiveCD(); 565 566 Restart: 567 SetUserSettings(); 568 569 if (bIsLiveCD) 570 { 571 State.NextPage = LOCALEPAGE; 572 State.Run = SHELL; 573 } 574 else 575 { 576 State.NextPage = DONE; 577 State.Run = SHELL; 578 } 579 580 if (State.NextPage != DONE) // && bIsLiveCD 581 { 582 RunLiveCD(&State); 583 } 584 585 switch (State.Run) 586 { 587 case SHELL: 588 Success = StartShell(); 589 if (Success) 590 NotifyLogon(); 591 break; 592 593 case INSTALLER: 594 Success = StartInstaller(); 595 break; 596 597 case REBOOT: 598 { 599 EnablePrivilege(SE_SHUTDOWN_NAME, TRUE); 600 ExitWindowsEx(EWX_REBOOT, 0); 601 EnablePrivilege(SE_SHUTDOWN_NAME, FALSE); 602 Success = TRUE; 603 break; 604 } 605 606 default: 607 Success = FALSE; 608 break; 609 } 610 611 /* 612 * In LiveCD mode, go back to the main menu if we failed 613 * to either start the shell or the installer. 614 */ 615 if (bIsLiveCD && !Success) 616 goto Restart; 617 618 return 0; 619 } 620 621 /* EOF */ 622