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