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