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 /* Used to get the shutdown privilege */ 574 static BOOL 575 EnablePrivilege(LPCWSTR lpszPrivilegeName, BOOL bEnablePrivilege) 576 { 577 BOOL Success; 578 HANDLE hToken; 579 TOKEN_PRIVILEGES tp; 580 581 Success = OpenProcessToken(GetCurrentProcess(), 582 TOKEN_ADJUST_PRIVILEGES, 583 &hToken); 584 if (!Success) return Success; 585 586 Success = LookupPrivilegeValueW(NULL, 587 lpszPrivilegeName, 588 &tp.Privileges[0].Luid); 589 if (!Success) goto Quit; 590 591 tp.PrivilegeCount = 1; 592 tp.Privileges[0].Attributes = (bEnablePrivilege ? SE_PRIVILEGE_ENABLED : 0); 593 594 Success = AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL); 595 596 Quit: 597 CloseHandle(hToken); 598 return Success; 599 } 600 601 602 int WINAPI 603 wWinMain(IN HINSTANCE hInst, 604 IN HINSTANCE hPrevInstance, 605 IN LPWSTR lpszCmdLine, 606 IN int nCmdShow) 607 { 608 BOOL bIsLiveCD, Success = TRUE; 609 STATE State; 610 611 hInstance = hInst; 612 613 bIsLiveCD = IsLiveCD(); 614 615 Restart: 616 SetUserSettings(); 617 618 if (bIsLiveCD) 619 { 620 State.NextPage = LOCALEPAGE; 621 State.Run = SHELL; 622 } 623 else 624 { 625 State.NextPage = DONE; 626 State.Run = SHELL; 627 } 628 629 if (State.NextPage != DONE) // && bIsLiveCD 630 { 631 RunLiveCD(&State); 632 } 633 634 switch (State.Run) 635 { 636 case SHELL: 637 Success = StartShell(); 638 if (Success) 639 NotifyLogon(); 640 break; 641 642 case INSTALLER: 643 Success = StartInstaller(); 644 break; 645 646 case REBOOT: 647 { 648 EnablePrivilege(SE_SHUTDOWN_NAME, TRUE); 649 ExitWindowsEx(EWX_REBOOT, 0); 650 EnablePrivilege(SE_SHUTDOWN_NAME, FALSE); 651 Success = TRUE; 652 break; 653 } 654 655 default: 656 Success = FALSE; 657 break; 658 } 659 660 /* 661 * In LiveCD mode, go back to the main menu if we failed 662 * to either start the shell or the installer. 663 */ 664 if (bIsLiveCD && !Success) 665 goto Restart; 666 667 return 0; 668 } 669 670 /* EOF */ 671