xref: /reactos/base/system/userinit/userinit.c (revision 2b82fe44)
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 */
559