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