6b81fe38bfa102ac0de57873ee4d7389b33aa036
[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
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 CloseHandle(pi.hProcess);
267 CloseHandle(pi.hThread);
268 return TRUE;
269 }
270
271 static
272 VOID StartShell(VOID)
273 {
274 WCHAR Shell[MAX_PATH];
275 TCHAR szMsg[RC_STRING_MAX_SIZE];
276
277 TRACE("()\n");
278
279 /* Try to run shell in user key */
280 if (GetShell(Shell, HKEY_CURRENT_USER) && TryToStartShell(Shell))
281 {
282 TRACE("Started shell from HKEY_CURRENT_USER\n");
283 return;
284 }
285
286 /* Try to run shell in local machine key */
287 if (GetShell(Shell, HKEY_LOCAL_MACHINE) && TryToStartShell(Shell))
288 {
289 TRACE("Started shell from HKEY_LOCAL_MACHINE\n");
290 return;
291 }
292
293 /* Try default shell */
294 if (IsConsoleShell())
295 {
296 if (GetSystemDirectory(Shell, MAX_PATH - 8))
297 wcscat(Shell, L"\\cmd.exe");
298 else
299 wcscpy(Shell, L"cmd.exe");
300 }
301 else
302 {
303 if (GetWindowsDirectory(Shell, MAX_PATH - 13))
304 wcscat(Shell, L"\\explorer.exe");
305 else
306 wcscpy(Shell, L"explorer.exe");
307 }
308 if (!TryToStartShell(Shell))
309 {
310 WARN("Failed to start default shell %s\n", debugstr_w(Shell));
311 LoadString( GetModuleHandle(NULL), STRING_USERINIT_FAIL, szMsg, sizeof(szMsg) / sizeof(szMsg[0]));
312 MessageBox(0, szMsg, NULL, 0);
313 }
314 }
315
316 const WCHAR g_RegColorNames[][32] = {
317 L"Scrollbar", /* 00 = COLOR_SCROLLBAR */
318 L"Background", /* 01 = COLOR_DESKTOP */
319 L"ActiveTitle", /* 02 = COLOR_ACTIVECAPTION */
320 L"InactiveTitle", /* 03 = COLOR_INACTIVECAPTION */
321 L"Menu", /* 04 = COLOR_MENU */
322 L"Window", /* 05 = COLOR_WINDOW */
323 L"WindowFrame", /* 06 = COLOR_WINDOWFRAME */
324 L"MenuText", /* 07 = COLOR_MENUTEXT */
325 L"WindowText", /* 08 = COLOR_WINDOWTEXT */
326 L"TitleText", /* 09 = COLOR_CAPTIONTEXT */
327 L"ActiveBorder", /* 10 = COLOR_ACTIVEBORDER */
328 L"InactiveBorder", /* 11 = COLOR_INACTIVEBORDER */
329 L"AppWorkSpace", /* 12 = COLOR_APPWORKSPACE */
330 L"Hilight", /* 13 = COLOR_HIGHLIGHT */
331 L"HilightText", /* 14 = COLOR_HIGHLIGHTTEXT */
332 L"ButtonFace", /* 15 = COLOR_BTNFACE */
333 L"ButtonShadow", /* 16 = COLOR_BTNSHADOW */
334 L"GrayText", /* 17 = COLOR_GRAYTEXT */
335 L"ButtonText", /* 18 = COLOR_BTNTEXT */
336 L"InactiveTitleText", /* 19 = COLOR_INACTIVECAPTIONTEXT */
337 L"ButtonHilight", /* 20 = COLOR_BTNHIGHLIGHT */
338 L"ButtonDkShadow", /* 21 = COLOR_3DDKSHADOW */
339 L"ButtonLight", /* 22 = COLOR_3DLIGHT */
340 L"InfoText", /* 23 = COLOR_INFOTEXT */
341 L"InfoWindow", /* 24 = COLOR_INFOBK */
342 L"ButtonAlternateFace", /* 25 = COLOR_ALTERNATEBTNFACE */
343 L"HotTrackingColor", /* 26 = COLOR_HOTLIGHT */
344 L"GradientActiveTitle", /* 27 = COLOR_GRADIENTACTIVECAPTION */
345 L"GradientInactiveTitle", /* 28 = COLOR_GRADIENTINACTIVECAPTION */
346 L"MenuHilight", /* 29 = COLOR_MENUHILIGHT */
347 L"MenuBar" /* 30 = COLOR_MENUBAR */
348 };
349 #define NUM_SYSCOLORS (sizeof(g_RegColorNames) / sizeof(g_RegColorNames[0]))
350
351 static
352 COLORREF StrToColorref(
353 IN LPWSTR lpszCol)
354 {
355 BYTE rgb[3];
356
357 TRACE("(%s)\n", debugstr_w(lpszCol));
358
359 rgb[0] = StrToIntW(lpszCol);
360 lpszCol = StrChrW(lpszCol, L' ') + 1;
361 rgb[1] = StrToIntW(lpszCol);
362 lpszCol = StrChrW(lpszCol, L' ') + 1;
363 rgb[2] = StrToIntW(lpszCol);
364 return RGB(rgb[0], rgb[1], rgb[2]);
365 }
366
367 static
368 VOID SetUserSysColors(VOID)
369 {
370 HKEY hKey;
371 INT i;
372 WCHAR szColor[20];
373 DWORD Type, Size;
374 COLORREF crColor;
375 LONG rc;
376
377 TRACE("()\n");
378
379 rc = RegOpenKeyEx(HKEY_CURRENT_USER, REGSTR_PATH_COLORS,
380 0, KEY_QUERY_VALUE, &hKey);
381 if (rc != ERROR_SUCCESS)
382 {
383 WARN("RegOpenKeyEx() failed with error %lu\n", rc);
384 return;
385 }
386 for(i = 0; i < NUM_SYSCOLORS; i++)
387 {
388 Size = sizeof(szColor);
389 rc = RegQueryValueEx(hKey, g_RegColorNames[i], NULL, &Type,
390 (LPBYTE)szColor, &Size);
391 if (rc == ERROR_SUCCESS && Type == REG_SZ)
392 {
393 crColor = StrToColorref(szColor);
394 SetSysColors(1, &i, &crColor);
395 }
396 else
397 WARN("RegQueryValueEx(%s) failed with error %lu\n",
398 debugstr_w(g_RegColorNames[i]), rc);
399 }
400 RegCloseKey(hKey);
401 }
402
403 static
404 VOID LoadUserFontSetting(
405 IN LPWSTR lpValueName,
406 OUT PLOGFONTW pFont)
407 {
408 HKEY hKey;
409 LOGFONTW lfTemp;
410 DWORD Type, Size;
411 LONG rc;
412
413 TRACE("(%s, %p)\n", debugstr_w(lpValueName), pFont);
414
415 Size = sizeof(LOGFONTW);
416 rc = RegOpenKeyEx(HKEY_CURRENT_USER, REGSTR_PATH_METRICS,
417 0, KEY_QUERY_VALUE, &hKey);
418 if (rc != ERROR_SUCCESS)
419 {
420 WARN("RegOpenKeyEx() failed with error %lu\n", rc);
421 return;
422 }
423 rc = RegQueryValueEx(hKey, lpValueName, NULL, &Type, (LPBYTE)&lfTemp, &Size);
424 if (rc != ERROR_SUCCESS || Type != REG_BINARY)
425 {
426 WARN("RegQueryValueEx() failed with error %lu\n", rc);
427 return;
428 }
429 RegCloseKey(hKey);
430 /* FIXME: Check if lfTemp is a valid font */
431 *pFont = lfTemp;
432 }
433
434 static
435 VOID LoadUserMetricSetting(
436 IN LPWSTR lpValueName,
437 OUT INT *pValue)
438 {
439 HKEY hKey;
440 DWORD Type, Size;
441 WCHAR strValue[8];
442 LONG rc;
443
444 TRACE("(%s, %p)\n", debugstr_w(lpValueName), pValue);
445
446 Size = sizeof(strValue);
447 rc = RegOpenKeyEx(HKEY_CURRENT_USER, REGSTR_PATH_METRICS,
448 0, KEY_QUERY_VALUE, &hKey);
449 if (rc != ERROR_SUCCESS)
450 {
451 WARN("RegOpenKeyEx() failed with error %lu\n", rc);
452 return;
453 }
454 rc = RegQueryValueEx(hKey, lpValueName, NULL, &Type, (LPBYTE)&strValue, &Size);
455 if (rc != ERROR_SUCCESS || Type != REG_SZ)
456 {
457 WARN("RegQueryValueEx() failed with error %lu\n", rc);
458 return;
459 }
460 RegCloseKey(hKey);
461 *pValue = StrToInt(strValue);
462 }
463
464 static
465 VOID SetUserMetrics(VOID)
466 {
467 NONCLIENTMETRICSW ncmetrics;
468 MINIMIZEDMETRICS mmmetrics;
469
470 TRACE("()\n");
471
472 ncmetrics.cbSize = sizeof(NONCLIENTMETRICSW);
473 mmmetrics.cbSize = sizeof(MINIMIZEDMETRICS);
474 SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICSW), &ncmetrics, 0);
475 SystemParametersInfoW(SPI_GETMINIMIZEDMETRICS, sizeof(MINIMIZEDMETRICS), &mmmetrics, 0);
476
477 LoadUserFontSetting(L"CaptionFont", &ncmetrics.lfCaptionFont);
478 LoadUserFontSetting(L"SmCaptionFont", &ncmetrics.lfSmCaptionFont);
479 LoadUserFontSetting(L"MenuFont", &ncmetrics.lfMenuFont);
480 LoadUserFontSetting(L"StatusFont", &ncmetrics.lfStatusFont);
481 LoadUserFontSetting(L"MessageFont", &ncmetrics.lfMessageFont);
482 /* FIXME: load icon font ? */
483
484 LoadUserMetricSetting(L"BorderWidth", &ncmetrics.iBorderWidth);
485 LoadUserMetricSetting(L"ScrollWidth", &ncmetrics.iScrollWidth);
486 LoadUserMetricSetting(L"ScrollHeight", &ncmetrics.iScrollHeight);
487 LoadUserMetricSetting(L"CaptionWidth", &ncmetrics.iCaptionWidth);
488 LoadUserMetricSetting(L"CaptionHeight", &ncmetrics.iCaptionHeight);
489 LoadUserMetricSetting(L"SmCaptionWidth", &ncmetrics.iSmCaptionWidth);
490 LoadUserMetricSetting(L"SmCaptionHeight", &ncmetrics.iSmCaptionHeight);
491 LoadUserMetricSetting(L"Menuwidth", &ncmetrics.iMenuWidth);
492 LoadUserMetricSetting(L"MenuHeight", &ncmetrics.iMenuHeight);
493
494 SystemParametersInfoW(SPI_SETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICSW), &ncmetrics, 0);
495 }
496
497 static
498 VOID SetUserWallpaper(VOID)
499 {
500 HKEY hKey;
501 DWORD Type, Size;
502 WCHAR szWallpaper[MAX_PATH + 1];
503 LONG rc;
504
505 TRACE("()\n");
506
507 rc = RegOpenKeyEx(HKEY_CURRENT_USER, REGSTR_PATH_DESKTOP,
508 0, KEY_QUERY_VALUE, &hKey);
509 if (rc == ERROR_SUCCESS)
510 {
511 Size = sizeof(szWallpaper);
512 rc = RegQueryValueEx(hKey,
513 L"Wallpaper",
514 NULL,
515 &Type,
516 (LPBYTE)szWallpaper,
517 &Size);
518 if (rc == ERROR_SUCCESS && Type == REG_SZ)
519 {
520 ExpandEnvironmentStrings(szWallpaper, szWallpaper, MAX_PATH);
521 TRACE("Using wallpaper %s\n", debugstr_w(szWallpaper));
522
523 /* Load and change the wallpaper */
524 SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, szWallpaper, SPIF_SENDCHANGE);
525 }
526 else
527 {
528 /* remove the wallpaper */
529 TRACE("No wallpaper set in registry (error %lu)\n", rc);
530 SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, NULL, SPIF_SENDCHANGE);
531 }
532 RegCloseKey(hKey);
533 }
534 else
535 WARN("RegOpenKeyEx() failed with error %lu\n", rc);
536 }
537
538 static
539 VOID SetUserSettings(VOID)
540 {
541 TRACE("()\n");
542
543 SetUserSysColors();
544 SetUserMetrics();
545 SetUserWallpaper();
546 }
547
548 typedef DWORD (WINAPI *PCMP_REPORT_LOGON)(DWORD, DWORD);
549
550 static VOID
551 NotifyLogon(VOID)
552 {
553 HINSTANCE hModule;
554 PCMP_REPORT_LOGON CMP_Report_LogOn;
555
556 TRACE("()\n");
557
558 hModule = LoadLibrary(L"setupapi.dll");
559 if (hModule)
560 {
561 CMP_Report_LogOn = (PCMP_REPORT_LOGON)GetProcAddress(hModule, "CMP_Report_LogOn");
562 if (CMP_Report_LogOn)
563 CMP_Report_LogOn(CMP_MAGIC, GetCurrentProcessId());
564 else
565 WARN("GetProcAddress() failed\n");
566
567 FreeLibrary(hModule);
568 }
569 else
570 WARN("LoadLibrary() failed with error %lu\n", GetLastError());
571 }
572
573 #ifdef _MSC_VER
574 #pragma warning(disable : 4100)
575 #endif /* _MSC_VER */
576
577 int WINAPI
578 wWinMain(IN HINSTANCE hInst,
579 IN HINSTANCE hPrevInstance,
580 IN LPWSTR lpszCmdLine,
581 IN int nCmdShow)
582 {
583 NotifyLogon();
584 SetUserSettings();
585 StartShell();
586 return 0;
587 }
588
589 /* EOF */