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