Expand environment strings in the szWallpaper variable. (patch by Marc Piulachs,...
[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
33 #define CMP_MAGIC 0x01234567
34
35 /* GLOBALS ******************************************************************/
36
37 /* FUNCTIONS ****************************************************************/
38
39 static LONG
40 ReadRegSzKey(
41 IN HKEY hKey,
42 IN LPCWSTR pszKey,
43 OUT LPWSTR* pValue)
44 {
45 LONG rc;
46 DWORD dwType;
47 DWORD cbData = 0;
48 LPWSTR Value;
49
50 rc = RegQueryValueExW(hKey, pszKey, NULL, &dwType, NULL, &cbData);
51 if (rc != ERROR_SUCCESS)
52 return rc;
53 if (dwType != REG_SZ)
54 return ERROR_FILE_NOT_FOUND;
55 Value = (WCHAR*) HeapAlloc(GetProcessHeap(), 0, cbData + sizeof(WCHAR));
56 if (!Value)
57 return ERROR_NOT_ENOUGH_MEMORY;
58 rc = RegQueryValueExW(hKey, pszKey, NULL, NULL, (LPBYTE)Value, &cbData);
59 if (rc != ERROR_SUCCESS)
60 {
61 HeapFree(GetProcessHeap(), 0, Value);
62 return rc;
63 }
64 /* NULL-terminate the string */
65 Value[cbData / sizeof(WCHAR)] = '\0';
66
67 *pValue = Value;
68 return ERROR_SUCCESS;
69 }
70
71 static
72 BOOL IsConsoleShell(void)
73 {
74 HKEY ControlKey = NULL;
75 LPWSTR SystemStartOptions = NULL;
76 LPWSTR CurrentOption, NextOption; /* Pointers into SystemStartOptions */
77 LONG rc;
78 BOOL ret = FALSE;
79
80 rc = RegOpenKeyEx(
81 HKEY_LOCAL_MACHINE,
82 REGSTR_PATH_CURRENT_CONTROL_SET,
83 0,
84 KEY_QUERY_VALUE,
85 &ControlKey);
86
87 rc = ReadRegSzKey(ControlKey, L"SystemStartOptions", &SystemStartOptions);
88 if (rc != ERROR_SUCCESS)
89 goto cleanup;
90
91 /* Check for CMDCONS in SystemStartOptions */
92 CurrentOption = SystemStartOptions;
93 while (CurrentOption)
94 {
95 NextOption = wcschr(CurrentOption, L' ');
96 if (NextOption)
97 *NextOption = L'\0';
98 if (wcsicmp(CurrentOption, L"CMDCONS") == 0)
99 {
100 ret = TRUE;
101 goto cleanup;
102 }
103 CurrentOption = NextOption ? NextOption + 1 : NULL;
104 }
105
106 cleanup:
107 if (ControlKey != NULL)
108 RegCloseKey(ControlKey);
109 HeapFree(GetProcessHeap(), 0, SystemStartOptions);
110 return ret;
111 }
112
113 static
114 BOOL GetShell(WCHAR *CommandLine, HKEY hRootKey)
115 {
116 HKEY hKey;
117 DWORD Type, Size;
118 WCHAR Shell[MAX_PATH];
119 BOOL Ret = FALSE;
120 BOOL ConsoleShell = IsConsoleShell();
121
122 if(RegOpenKeyEx(hRootKey,
123 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon", /* FIXME: should be REGSTR_PATH_WINLOGON */
124 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
125 {
126 Size = MAX_PATH * sizeof(WCHAR);
127 if(RegQueryValueEx(hKey,
128 ConsoleShell ? L"ConsoleShell" : L"Shell",
129 NULL,
130 &Type,
131 (LPBYTE)Shell,
132 &Size) == ERROR_SUCCESS)
133 {
134 if((Type == REG_SZ) || (Type == REG_EXPAND_SZ))
135 {
136 wcscpy(CommandLine, Shell);
137 Ret = TRUE;
138 }
139 }
140 RegCloseKey(hKey);
141 }
142
143 return Ret;
144 }
145
146 static VOID
147 StartAutoApplications(int clsid)
148 {
149 WCHAR szPath[MAX_PATH] = {0};
150 HRESULT hResult;
151 HANDLE hFind;
152 WIN32_FIND_DATAW findData;
153 SHELLEXECUTEINFOW ExecInfo;
154 size_t len;
155
156 hResult = SHGetFolderPathW(NULL, clsid, NULL, SHGFP_TYPE_CURRENT, szPath);
157 len = wcslen(szPath);
158 if (!SUCCEEDED(hResult) || len == 0)
159 {
160 return;
161 }
162
163 wcscat(szPath, L"\\*");
164 hFind = FindFirstFileW(szPath, &findData);
165 if (hFind == INVALID_HANDLE_VALUE)
166 {
167 return;
168 }
169 szPath[len] = L'\0';
170
171 do
172 {
173 if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && (findData.nFileSizeHigh || findData.nFileSizeLow))
174 {
175 memset(&ExecInfo, 0x0, sizeof(SHELLEXECUTEINFOW));
176 ExecInfo.cbSize = sizeof(ExecInfo);
177 ExecInfo.lpVerb = L"open";
178 ExecInfo.lpFile = findData.cFileName;
179 ExecInfo.lpDirectory = szPath;
180 ShellExecuteExW(&ExecInfo);
181 }
182 }while(FindNextFileW(hFind, &findData));
183 FindClose(hFind);
184 }
185
186
187 static BOOL
188 TryToStartShell(LPCWSTR Shell)
189 {
190 STARTUPINFO si;
191 PROCESS_INFORMATION pi;
192 WCHAR ExpandedShell[MAX_PATH];
193
194 ZeroMemory(&si, sizeof(STARTUPINFO));
195 si.cb = sizeof(STARTUPINFO);
196 ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
197
198 ExpandEnvironmentStrings(Shell, ExpandedShell, MAX_PATH);
199
200 if(!CreateProcess(NULL,
201 ExpandedShell,
202 NULL,
203 NULL,
204 FALSE,
205 NORMAL_PRIORITY_CLASS,
206 NULL,
207 NULL,
208 &si,
209 &pi))
210 return FALSE;
211
212 StartAutoApplications(CSIDL_STARTUP);
213 StartAutoApplications(CSIDL_COMMON_STARTUP);
214 WaitForSingleObject(pi.hProcess, INFINITE);
215 CloseHandle(pi.hProcess);
216 CloseHandle(pi.hThread);
217 return TRUE;
218 }
219
220 static
221 void StartShell(void)
222 {
223 WCHAR Shell[MAX_PATH];
224 TCHAR szMsg[RC_STRING_MAX_SIZE];
225
226 /* Try to run shell in user key */
227 if (GetShell(Shell, HKEY_CURRENT_USER) && TryToStartShell(Shell))
228 return;
229
230 /* Try to run shell in local machine key */
231 if (GetShell(Shell, HKEY_LOCAL_MACHINE) && TryToStartShell(Shell))
232 return;
233
234 /* Try default shell */
235 if (IsConsoleShell())
236 {
237 if(GetSystemDirectory(Shell, MAX_PATH - 8))
238 wcscat(Shell, L"\\cmd.exe");
239 else
240 wcscpy(Shell, L"cmd.exe");
241 }
242 else
243 {
244 if(GetWindowsDirectory(Shell, MAX_PATH - 13))
245 wcscat(Shell, L"\\explorer.exe");
246 else
247 wcscpy(Shell, L"explorer.exe");
248 }
249 if (!TryToStartShell(Shell))
250 {
251 LoadString( GetModuleHandle(NULL), STRING_USERINIT_FAIL, szMsg, sizeof(szMsg) / sizeof(szMsg[0]));
252 MessageBox(0, szMsg, NULL, 0);
253 }
254 }
255
256 WCHAR g_RegColorNames[][32] =
257 {L"Scrollbar", /* 00 = COLOR_SCROLLBAR */
258 L"Background", /* 01 = COLOR_DESKTOP */
259 L"ActiveTitle", /* 02 = COLOR_ACTIVECAPTION */
260 L"InactiveTitle", /* 03 = COLOR_INACTIVECAPTION */
261 L"Menu", /* 04 = COLOR_MENU */
262 L"Window", /* 05 = COLOR_WINDOW */
263 L"WindowFrame", /* 06 = COLOR_WINDOWFRAME */
264 L"MenuText", /* 07 = COLOR_MENUTEXT */
265 L"WindowText", /* 08 = COLOR_WINDOWTEXT */
266 L"TitleText", /* 09 = COLOR_CAPTIONTEXT */
267 L"ActiveBorder", /* 10 = COLOR_ACTIVEBORDER */
268 L"InactiveBorder", /* 11 = COLOR_INACTIVEBORDER */
269 L"AppWorkSpace", /* 12 = COLOR_APPWORKSPACE */
270 L"Hilight", /* 13 = COLOR_HIGHLIGHT */
271 L"HilightText", /* 14 = COLOR_HIGHLIGHTTEXT */
272 L"ButtonFace", /* 15 = COLOR_BTNFACE */
273 L"ButtonShadow", /* 16 = COLOR_BTNSHADOW */
274 L"GrayText", /* 17 = COLOR_GRAYTEXT */
275 L"ButtonText", /* 18 = COLOR_BTNTEXT */
276 L"InactiveTitleText", /* 19 = COLOR_INACTIVECAPTIONTEXT */
277 L"ButtonHilight", /* 20 = COLOR_BTNHIGHLIGHT */
278 L"ButtonDkShadow", /* 21 = COLOR_3DDKSHADOW */
279 L"ButtonLight", /* 22 = COLOR_3DLIGHT */
280 L"InfoText", /* 23 = COLOR_INFOTEXT */
281 L"InfoWindow", /* 24 = COLOR_INFOBK */
282 L"ButtonAlternateFace", /* 25 = COLOR_ALTERNATEBTNFACE */
283 L"HotTrackingColor", /* 26 = COLOR_HOTLIGHT */
284 L"GradientActiveTitle", /* 27 = COLOR_GRADIENTACTIVECAPTION */
285 L"GradientInactiveTitle", /* 28 = COLOR_GRADIENTINACTIVECAPTION */
286 L"MenuHilight", /* 29 = COLOR_MENUHILIGHT */
287 L"MenuBar" /* 30 = COLOR_MENUBAR */
288 };
289 #define NUM_SYSCOLORS (sizeof(g_RegColorNames) / sizeof(g_RegColorNames[0]))
290
291 static
292 COLORREF StrToColorref(LPWSTR lpszCol)
293 {
294 BYTE rgb[3];
295
296 rgb[0] = StrToIntW(lpszCol);
297 lpszCol = StrChrW(lpszCol, L' ') + 1;
298 rgb[1] = StrToIntW(lpszCol);
299 lpszCol = StrChrW(lpszCol, L' ') + 1;
300 rgb[2] = StrToIntW(lpszCol);
301 return RGB(rgb[0], rgb[1], rgb[2]);
302 }
303
304 static
305 void SetUserSysColors(void)
306 {
307 HKEY hKey;
308 INT i;
309 WCHAR szColor[20];
310 DWORD Type, Size;
311 COLORREF crColor;
312
313 if(!RegOpenKeyEx(HKEY_CURRENT_USER,
314 L"Control Panel\\Colors",
315 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
316 {
317 return;
318 }
319 for(i = 0; i < NUM_SYSCOLORS; i++)
320 {
321 Size = sizeof(szColor);
322 if(RegQueryValueEx(hKey, g_RegColorNames[i], NULL, &Type,
323 (LPBYTE)szColor, &Size) == ERROR_SUCCESS && Type == REG_SZ)
324 {
325 crColor = StrToColorref(szColor);
326 SetSysColors(1, &i, &crColor);
327 }
328 }
329 RegCloseKey(hKey);
330 return;
331 }
332
333 static
334 void LoadUserFontSetting(LPWSTR lpValueName, PLOGFONTW pFont)
335 {
336 HKEY hKey;
337 LOGFONTW lfTemp;
338 DWORD Type, Size;
339 INT error;
340
341 Size = sizeof(LOGFONTW);
342 if(!RegOpenKeyEx(HKEY_CURRENT_USER,
343 L"Control Panel\\Desktop\\WindowMetrics",
344 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
345 {
346 return;
347 }
348 error = RegQueryValueEx(hKey, lpValueName, NULL, &Type, (LPBYTE)&lfTemp, &Size);
349 if ((error != ERROR_SUCCESS) || (Type != REG_BINARY))
350 {
351 return;
352 }
353 RegCloseKey(hKey);
354 /* FIXME: Check if lfTemp is a valid font */
355 *pFont = lfTemp;
356 return;
357 }
358
359 static
360 void LoadUserMetricSetting(LPWSTR lpValueName, INT *pValue)
361 {
362 HKEY hKey;
363 DWORD Type, Size;
364 INT ret;
365 WCHAR strValue[8];
366
367 Size = sizeof(strValue);
368 if(!RegOpenKeyEx(HKEY_CURRENT_USER,
369 L"Control Panel\\Desktop\\WindowMetrics",
370 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
371 {
372 return;
373 }
374 ret = RegQueryValueEx(hKey, lpValueName, NULL, &Type, (LPBYTE)&strValue, &Size);
375 if ((ret != ERROR_SUCCESS) || (Type != REG_SZ))
376 {
377 return;
378 }
379 RegCloseKey(hKey);
380 *pValue = StrToInt(strValue);
381 return;
382 }
383
384 static
385 void SetUserMetrics(void)
386 {
387 NONCLIENTMETRICSW ncmetrics;
388 MINIMIZEDMETRICS mmmetrics;
389
390 ncmetrics.cbSize = sizeof(NONCLIENTMETRICSW);
391 mmmetrics.cbSize = sizeof(MINIMIZEDMETRICS);
392 SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICSW), &ncmetrics, 0);
393 SystemParametersInfoW(SPI_GETMINIMIZEDMETRICS, sizeof(MINIMIZEDMETRICS), &mmmetrics, 0);
394
395 LoadUserFontSetting(L"CaptionFont", &ncmetrics.lfCaptionFont);
396 LoadUserFontSetting(L"SmCaptionFont", &ncmetrics.lfSmCaptionFont);
397 LoadUserFontSetting(L"MenuFont", &ncmetrics.lfMenuFont);
398 LoadUserFontSetting(L"StatusFont", &ncmetrics.lfStatusFont);
399 LoadUserFontSetting(L"MessageFont", &ncmetrics.lfMessageFont);
400 /* FIXME: load icon font ? */
401
402 LoadUserMetricSetting(L"BorderWidth", &ncmetrics.iBorderWidth);
403 LoadUserMetricSetting(L"ScrollWidth", &ncmetrics.iScrollWidth);
404 LoadUserMetricSetting(L"ScrollHeight", &ncmetrics.iScrollHeight);
405 LoadUserMetricSetting(L"CaptionWidth", &ncmetrics.iCaptionWidth);
406 LoadUserMetricSetting(L"CaptionHeight", &ncmetrics.iCaptionHeight);
407 LoadUserMetricSetting(L"SmCaptionWidth", &ncmetrics.iSmCaptionWidth);
408 LoadUserMetricSetting(L"SmCaptionHeight", &ncmetrics.iSmCaptionHeight);
409 LoadUserMetricSetting(L"Menuwidth", &ncmetrics.iMenuWidth);
410 LoadUserMetricSetting(L"MenuHeight", &ncmetrics.iMenuHeight);
411
412 SystemParametersInfoW(SPI_SETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICSW), &ncmetrics, 0);
413
414 return;
415 }
416
417 static
418 void SetUserWallpaper(void)
419 {
420 HKEY hKey;
421 DWORD Type, Size;
422 WCHAR szWallpaper[MAX_PATH + 1];
423
424 if(RegOpenKeyEx(HKEY_CURRENT_USER,
425 REGSTR_PATH_DESKTOP,
426 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
427 {
428 Size = sizeof(szWallpaper);
429 if(RegQueryValueEx(hKey,
430 L"Wallpaper",
431 NULL,
432 &Type,
433 (LPBYTE)szWallpaper,
434 &Size) == ERROR_SUCCESS
435 && Type == REG_SZ)
436 {
437 ExpandEnvironmentStrings(szWallpaper, szWallpaper, MAX_PATH);
438
439 /* Load and change the wallpaper */
440 SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, szWallpaper, SPIF_SENDCHANGE);
441 }
442 else
443 {
444 /* remove the wallpaper */
445 SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, NULL, SPIF_SENDCHANGE);
446 }
447 RegCloseKey(hKey);
448 }
449 }
450
451 static
452 void SetUserSettings(void)
453 {
454 SetUserSysColors();
455 SetUserMetrics();
456 SetUserWallpaper();
457 }
458
459 typedef DWORD (WINAPI *PCMP_REPORT_LOGON)(DWORD, DWORD);
460
461 static VOID
462 NotifyLogon(VOID)
463 {
464 HINSTANCE hModule;
465 PCMP_REPORT_LOGON CMP_Report_LogOn;
466
467 hModule = LoadLibrary(L"setupapi.dll");
468 if (hModule)
469 {
470 CMP_Report_LogOn = (PCMP_REPORT_LOGON)GetProcAddress(hModule, "CMP_Report_LogOn");
471 if (CMP_Report_LogOn)
472 CMP_Report_LogOn(CMP_MAGIC, GetCurrentProcessId());
473
474 FreeLibrary(hModule);
475 }
476 }
477
478
479
480 #ifdef _MSC_VER
481 #pragma warning(disable : 4100)
482 #endif /* _MSC_VER */
483
484 int WINAPI
485 WinMain(HINSTANCE hInst,
486 HINSTANCE hPrevInstance,
487 LPSTR lpszCmdLine,
488 int nCmdShow)
489 {
490 NotifyLogon();
491 SetUserSettings();
492 StartShell();
493 return 0;
494 }
495
496 /* EOF */