[USERINIT]
[reactos.git] / reactos / base / system / userinit / userinit.c
index b82a698..81027d4 100644 (file)
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 /*
  * COPYRIGHT:   See COPYING in the top level directory
  * PROJECT:     ReactOS Userinit Logon Application
  * FILE:        subsys/system/userinit/userinit.c
  * PROGRAMMERS: Thomas Weidenmueller (w3seek@users.sourceforge.net)
+ *              HervĂ© Poussineau (hpoussin@reactos.org)
  */
 #include <windows.h>
 #include <cfgmgr32.h>
+#include <regstr.h>
+#include <shlobj.h>
+#include <shlwapi.h>
 #include "resource.h"
+#include <wine/debug.h>
+#include <win32k/ntusrtyp.h>
+
+WINE_DEFAULT_DEBUG_CHANNEL(userinit);
 
 #define CMP_MAGIC  0x01234567
 
 
 /* FUNCTIONS ****************************************************************/
 
+static LONG
+ReadRegSzKey(
+    IN HKEY hKey,
+    IN LPCWSTR pszKey,
+    OUT LPWSTR* pValue)
+{
+    LONG rc;
+    DWORD dwType;
+    DWORD cbData = 0;
+    LPWSTR Value;
+
+    TRACE("(%p, %s, %p)\n", hKey, debugstr_w(pszKey), pValue);
+
+    rc = RegQueryValueExW(hKey, pszKey, NULL, &dwType, NULL, &cbData);
+    if (rc != ERROR_SUCCESS)
+    {
+        WARN("RegQueryValueEx(%s) failed with error %lu\n", debugstr_w(pszKey), rc);
+        return rc;
+    }
+    if (dwType != REG_SZ)
+    {
+        WARN("Wrong registry data type (%u vs %u)\n", dwType, REG_SZ);
+        return ERROR_FILE_NOT_FOUND;
+    }
+    Value = (WCHAR*) HeapAlloc(GetProcessHeap(), 0, cbData + sizeof(WCHAR));
+    if (!Value)
+    {
+        WARN("No memory\n");
+        return ERROR_NOT_ENOUGH_MEMORY;
+    }
+    rc = RegQueryValueExW(hKey, pszKey, NULL, NULL, (LPBYTE)Value, &cbData);
+    if (rc != ERROR_SUCCESS)
+    {
+        WARN("RegQueryValueEx(%s) failed with error %lu\n", debugstr_w(pszKey), rc);
+        HeapFree(GetProcessHeap(), 0, Value);
+        return rc;
+    }
+    /* NULL-terminate the string */
+    Value[cbData / sizeof(WCHAR)] = '\0';
+
+    *pValue = Value;
+    return ERROR_SUCCESS;
+}
+
 static
-BOOL GetShell(WCHAR *CommandLine)
+BOOL IsConsoleShell(VOID)
 {
-  HKEY hKey;
-  DWORD Type, Size;
-  WCHAR Shell[MAX_PATH];
-  BOOL Ret = FALSE;
-
-  if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
-                  L"SOFTWARE\\ReactOS\\Windows NT\\CurrentVersion\\Winlogon",
-                  0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
-  {
-    Size = MAX_PATH * sizeof(WCHAR);
-    if(RegQueryValueEx(hKey,
-                       L"Shell",
-                       NULL,
-                       &Type,
-                       (LPBYTE)Shell,
-                       &Size) == ERROR_SUCCESS)
-    {
-      if((Type == REG_SZ) || (Type == REG_EXPAND_SZ))
-      {
-        wcscpy(CommandLine, Shell);
-        Ret = TRUE;
-      }
+    HKEY ControlKey = NULL;
+    LPWSTR SystemStartOptions = NULL;
+    LPWSTR CurrentOption, NextOption; /* Pointers into SystemStartOptions */
+    LONG rc;
+    BOOL ret = FALSE;
+
+    TRACE("()\n");
+
+    rc = RegOpenKeyEx(
+        HKEY_LOCAL_MACHINE,
+        REGSTR_PATH_CURRENT_CONTROL_SET,
+        0,
+        KEY_QUERY_VALUE,
+        &ControlKey);
+    if (rc != ERROR_SUCCESS)
+    {
+        WARN("RegOpenKeyEx() failed with error %lu\n", rc);
+        goto cleanup;
     }
-    RegCloseKey(hKey);
-  }
 
-  if(!Ret)
-  {
-    if(GetWindowsDirectory(CommandLine, MAX_PATH - 13))
-      wcscat(CommandLine, L"\\explorer.exe");
-    else
-      wcscpy(CommandLine, L"explorer.exe");
-  }
+    rc = ReadRegSzKey(ControlKey, L"SystemStartOptions", &SystemStartOptions);
+    if (rc != ERROR_SUCCESS)
+    {
+        WARN("ReadRegSzKey() failed with error %lu\n", rc);
+        goto cleanup;
+    }
+
+    /* Check for CONSOLE in SystemStartOptions */
+    CurrentOption = SystemStartOptions;
+    while (CurrentOption)
+    {
+        NextOption = wcschr(CurrentOption, L' ');
+        if (NextOption)
+            *NextOption = L'\0';
+        if (_wcsicmp(CurrentOption, L"CONSOLE") == 0)
+        {
+            TRACE("Found 'CONSOLE' boot option\n");
+            ret = TRUE;
+            goto cleanup;
+        }
+        CurrentOption = NextOption ? NextOption + 1 : NULL;
+    }
 
-  return Ret;
+cleanup:
+    if (ControlKey != NULL)
+        RegCloseKey(ControlKey);
+    HeapFree(GetProcessHeap(), 0, SystemStartOptions);
+    TRACE("IsConsoleShell() returning %d\n", ret);
+    return ret;
 }
 
 static
-void StartShell(void)
+BOOL GetShell(
+    OUT WCHAR *CommandLine, /* must be at least MAX_PATH long */
+    IN HKEY hRootKey)
 {
-  STARTUPINFO si;
-  PROCESS_INFORMATION pi;
-  WCHAR Shell[MAX_PATH];
-  WCHAR ExpandedShell[MAX_PATH];
-  TCHAR szMsg[RC_STRING_MAX_SIZE];
-
-  GetShell(Shell);
-
-  ZeroMemory(&si, sizeof(STARTUPINFO));
-  si.cb = sizeof(STARTUPINFO);
-  ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
-
-  ExpandEnvironmentStrings(Shell, ExpandedShell, MAX_PATH);
-
-  if(CreateProcess(NULL,
-                   ExpandedShell,
-                   NULL,
-                   NULL,
-                   FALSE,
-                   NORMAL_PRIORITY_CLASS,
-                   NULL,
-                   NULL,
-                   &si,
-                   &pi))
-  {
-    WaitForSingleObject(pi.hProcess, INFINITE);
+    HKEY hKey;
+    DWORD Type, Size;
+    WCHAR Shell[MAX_PATH];
+    BOOL Ret = FALSE;
+    BOOL ConsoleShell = IsConsoleShell();
+    LONG rc;
+
+    TRACE("(%p, %p)\n", CommandLine, hRootKey);
+
+    rc = RegOpenKeyExW(hRootKey, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
+                       0, KEY_QUERY_VALUE, &hKey);
+    if (rc == ERROR_SUCCESS)
+    {
+        Size = MAX_PATH * sizeof(WCHAR);
+        rc = RegQueryValueExW(hKey,
+                              ConsoleShell ? L"ConsoleShell" : L"Shell",
+                              NULL,
+                              &Type,
+                              (LPBYTE)Shell,
+                              &Size);
+        if (rc == ERROR_SUCCESS)
+        {
+            if ((Type == REG_SZ) || (Type == REG_EXPAND_SZ))
+            {
+                TRACE("Found command line %s\n", debugstr_w(Shell));
+                wcscpy(CommandLine, Shell);
+                Ret = TRUE;
+            }
+            else
+                WARN("Wrong type %lu (expected %u or %u)\n", Type, REG_SZ, REG_EXPAND_SZ);
+        }
+        else
+            WARN("RegQueryValueEx() failed with error %lu\n", rc);
+        RegCloseKey(hKey);
+    }
+    else
+        WARN("RegOpenKeyEx() failed with error %lu\n", rc);
+
+    return Ret;
+}
+
+static VOID
+StartAutoApplications(
+    IN INT clsid)
+{
+    WCHAR szPath[MAX_PATH] = {0};
+    HRESULT hResult;
+    HANDLE hFind;
+    WIN32_FIND_DATAW findData;
+    SHELLEXECUTEINFOW ExecInfo;
+    size_t len;
+
+    TRACE("(%d)\n", clsid);
+
+    hResult = SHGetFolderPathW(NULL, clsid, NULL, SHGFP_TYPE_CURRENT, szPath);
+    len = wcslen(szPath);
+    if (!SUCCEEDED(hResult) || len == 0)
+    {
+        WARN("SHGetFolderPath() failed with error %lu\n", GetLastError());
+        return;
+    }
+
+    wcscat(szPath, L"\\*");
+    hFind = FindFirstFileW(szPath, &findData);
+    if (hFind == INVALID_HANDLE_VALUE)
+    {
+        WARN("FindFirstFile(%s) failed with error %lu\n", debugstr_w(szPath), GetLastError());
+        return;
+    }
+
+    do
+    {
+        if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && (findData.nFileSizeHigh || findData.nFileSizeLow))
+        {
+            memset(&ExecInfo, 0x0, sizeof(SHELLEXECUTEINFOW));
+            ExecInfo.cbSize = sizeof(ExecInfo);
+            wcscpy(&szPath[len+1], findData.cFileName);
+            ExecInfo.lpVerb = L"open";
+            ExecInfo.lpFile = szPath;
+            ExecInfo.lpDirectory = NULL;
+            TRACE("Executing %s in directory %s\n",
+                debugstr_w(findData.cFileName), debugstr_w(szPath));
+            ShellExecuteExW(&ExecInfo);
+        }
+    } while (FindNextFileW(hFind, &findData));
+    FindClose(hFind);
+}
+
+static BOOL
+TryToStartShell(
+    IN LPCWSTR Shell)
+{
+    STARTUPINFO si;
+    PROCESS_INFORMATION pi;
+    WCHAR ExpandedShell[MAX_PATH];
+
+    TRACE("(%s)\n", debugstr_w(Shell));
+
+    ZeroMemory(&si, sizeof(STARTUPINFO));
+    si.cb = sizeof(STARTUPINFO);
+    ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
+
+    ExpandEnvironmentStrings(Shell, ExpandedShell, MAX_PATH);
+
+    if (!CreateProcess(NULL,
+                      ExpandedShell,
+                      NULL,
+                      NULL,
+                      FALSE,
+                      NORMAL_PRIORITY_CLASS,
+                      NULL,
+                      NULL,
+                      &si,
+                      &pi))
+    {
+        WARN("CreateProcess() failed with error %lu\n", GetLastError());
+        return FALSE;
+    }
+
+    StartAutoApplications(CSIDL_STARTUP);
+    StartAutoApplications(CSIDL_COMMON_STARTUP);
     CloseHandle(pi.hProcess);
     CloseHandle(pi.hThread);
-  }
-  else
-  {
-    LoadString( GetModuleHandle(NULL), STRING_USERINIT_FAIL, szMsg, sizeof(szMsg) / sizeof(szMsg[0]));
-    MessageBox(0, szMsg, NULL, 0);
-  }
+    return TRUE;
 }
 
 static
-void SetUserSettings(void)
+VOID StartShell(VOID)
 {
-  HKEY hKey;
-  DWORD Type, Size;
-  WCHAR szWallpaper[MAX_PATH + 1];
-
-  if(RegOpenKeyEx(HKEY_CURRENT_USER,
-                  L"Control Panel\\Desktop",
-                  0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
-  {
-    Size = sizeof(szWallpaper);
-    if(RegQueryValueEx(hKey,
-                       L"Wallpaper",
-                       NULL,
-                       &Type,
-                       (LPBYTE)szWallpaper,
-                       &Size) == ERROR_SUCCESS
-       && Type == REG_SZ)
-    {
-      /* Load and change the wallpaper */
-      SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, szWallpaper, SPIF_SENDCHANGE);
+    WCHAR Shell[MAX_PATH];
+    TCHAR szMsg[RC_STRING_MAX_SIZE];
+
+    TRACE("()\n");
+
+    /* Try to run shell in user key */
+    if (GetShell(Shell, HKEY_CURRENT_USER) && TryToStartShell(Shell))
+    {
+        TRACE("Started shell from HKEY_CURRENT_USER\n");
+        return;
+    }
+
+    /* Try to run shell in local machine key */
+    if (GetShell(Shell, HKEY_LOCAL_MACHINE) && TryToStartShell(Shell))
+    {
+        TRACE("Started shell from HKEY_LOCAL_MACHINE\n");
+        return;
+    }
+
+    /* Try default shell */
+    if (IsConsoleShell())
+    {
+        if (GetSystemDirectory(Shell, MAX_PATH - 8))
+            wcscat(Shell, L"\\cmd.exe");
+        else
+            wcscpy(Shell, L"cmd.exe");
     }
     else
     {
-      /* remove the wallpaper */
-      SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, NULL, SPIF_SENDCHANGE);
+        if (GetWindowsDirectory(Shell, MAX_PATH - 13))
+            wcscat(Shell, L"\\explorer.exe");
+        else
+            wcscpy(Shell, L"explorer.exe");
+    }
+    if (!TryToStartShell(Shell))
+    {
+        WARN("Failed to start default shell %s\n", debugstr_w(Shell));
+        LoadString( GetModuleHandle(NULL), STRING_USERINIT_FAIL, szMsg, sizeof(szMsg) / sizeof(szMsg[0]));
+        MessageBox(0, szMsg, NULL, 0);
+    }
+}
+
+const WCHAR g_RegColorNames[][32] = {
+    L"Scrollbar",             /* 00 = COLOR_SCROLLBAR */
+    L"Background",            /* 01 = COLOR_DESKTOP */
+    L"ActiveTitle",           /* 02 = COLOR_ACTIVECAPTION  */
+    L"InactiveTitle",         /* 03 = COLOR_INACTIVECAPTION */
+    L"Menu",                  /* 04 = COLOR_MENU */
+    L"Window",                /* 05 = COLOR_WINDOW */
+    L"WindowFrame",           /* 06 = COLOR_WINDOWFRAME */
+    L"MenuText",              /* 07 = COLOR_MENUTEXT */
+    L"WindowText",            /* 08 = COLOR_WINDOWTEXT */
+    L"TitleText",             /* 09 = COLOR_CAPTIONTEXT */
+    L"ActiveBorder",          /* 10 = COLOR_ACTIVEBORDER */
+    L"InactiveBorder",        /* 11 = COLOR_INACTIVEBORDER */
+    L"AppWorkSpace",          /* 12 = COLOR_APPWORKSPACE */
+    L"Hilight",               /* 13 = COLOR_HIGHLIGHT */
+    L"HilightText",           /* 14 = COLOR_HIGHLIGHTTEXT */
+    L"ButtonFace",            /* 15 = COLOR_BTNFACE */
+    L"ButtonShadow",          /* 16 = COLOR_BTNSHADOW */
+    L"GrayText",              /* 17 = COLOR_GRAYTEXT */
+    L"ButtonText",            /* 18 = COLOR_BTNTEXT */
+    L"InactiveTitleText",     /* 19 = COLOR_INACTIVECAPTIONTEXT */
+    L"ButtonHilight",         /* 20 = COLOR_BTNHIGHLIGHT */
+    L"ButtonDkShadow",        /* 21 = COLOR_3DDKSHADOW */
+    L"ButtonLight",           /* 22 = COLOR_3DLIGHT */
+    L"InfoText",              /* 23 = COLOR_INFOTEXT */
+    L"InfoWindow",            /* 24 = COLOR_INFOBK */
+    L"ButtonAlternateFace",   /* 25 = COLOR_ALTERNATEBTNFACE */
+    L"HotTrackingColor",      /* 26 = COLOR_HOTLIGHT */
+    L"GradientActiveTitle",   /* 27 = COLOR_GRADIENTACTIVECAPTION */
+    L"GradientInactiveTitle", /* 28 = COLOR_GRADIENTINACTIVECAPTION */
+    L"MenuHilight",           /* 29 = COLOR_MENUHILIGHT */
+    L"MenuBar"                /* 30 = COLOR_MENUBAR */
+};
+#define NUM_SYSCOLORS (sizeof(g_RegColorNames) / sizeof(g_RegColorNames[0]))
+
+static
+COLORREF StrToColorref(
+    IN LPWSTR lpszCol)
+{
+    BYTE rgb[3];
+
+    TRACE("(%s)\n", debugstr_w(lpszCol));
+
+    rgb[0] = StrToIntW(lpszCol);
+    lpszCol = StrChrW(lpszCol, L' ') + 1;
+    rgb[1] = StrToIntW(lpszCol);
+    lpszCol = StrChrW(lpszCol, L' ') + 1;
+    rgb[2] = StrToIntW(lpszCol);
+    return RGB(rgb[0], rgb[1], rgb[2]);
+}
+
+static
+VOID SetUserSysColors(VOID)
+{
+    HKEY hKey;
+    INT i;
+    WCHAR szColor[20];
+    DWORD Type, Size;
+    COLORREF crColor;
+    LONG rc;
+
+    TRACE("()\n");
+
+    rc = RegOpenKeyEx(HKEY_CURRENT_USER, REGSTR_PATH_COLORS,
+                      0, KEY_QUERY_VALUE, &hKey);
+    if (rc != ERROR_SUCCESS)
+    {
+        WARN("RegOpenKeyEx() failed with error %lu\n", rc);
+        return;
+    }
+    for(i = 0; i < NUM_SYSCOLORS; i++)
+    {
+        Size = sizeof(szColor);
+        rc = RegQueryValueEx(hKey, g_RegColorNames[i], NULL, &Type,
+                             (LPBYTE)szColor, &Size);
+        if (rc == ERROR_SUCCESS && Type == REG_SZ)
+        {
+            crColor = StrToColorref(szColor);
+            SetSysColors(1, &i, &crColor);
+        }
+        else
+            WARN("RegQueryValueEx(%s) failed with error %lu\n",
+                debugstr_w(g_RegColorNames[i]), rc);
     }
     RegCloseKey(hKey);
-  }
 }
 
+DWORD
+WINAPI
+UpdatePerUserSystemParameters(DWORD dw1, BOOL bEnable);
+
+
+static
+VOID SetUserWallpaper(VOID)
+{
+    HKEY hKey;
+    DWORD Type, Size;
+    WCHAR szWallpaper[MAX_PATH + 1];
+    LONG rc;
+
+    TRACE("()\n");
+
+    rc = RegOpenKeyEx(HKEY_CURRENT_USER, REGSTR_PATH_DESKTOP,
+                      0, KEY_QUERY_VALUE, &hKey);
+    if (rc == ERROR_SUCCESS)
+    {
+        Size = sizeof(szWallpaper);
+        rc = RegQueryValueEx(hKey,
+                             L"Wallpaper",
+                             NULL,
+                             &Type,
+                             (LPBYTE)szWallpaper,
+                             &Size);
+        if (rc == ERROR_SUCCESS && Type == REG_SZ)
+        {
+            ExpandEnvironmentStrings(szWallpaper, szWallpaper, MAX_PATH);
+            TRACE("Using wallpaper %s\n", debugstr_w(szWallpaper));
+
+            /* Load and change the wallpaper */
+            SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, szWallpaper, SPIF_SENDCHANGE);
+        }
+        else
+        {
+            /* remove the wallpaper */
+            TRACE("No wallpaper set in registry (error %lu)\n", rc);
+            SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, NULL, SPIF_SENDCHANGE);
+        }
+        RegCloseKey(hKey);
+    }
+    else
+        WARN("RegOpenKeyEx() failed with error %lu\n", rc);
+}
+
+static
+VOID SetUserSettings(VOID)
+{
+    TRACE("()\n");
+
+    UpdatePerUserSystemParameters(1, TRUE);
+    SetUserSysColors();
+    SetUserWallpaper();
+}
 
 typedef DWORD (WINAPI *PCMP_REPORT_LOGON)(DWORD, DWORD);
 
@@ -152,32 +465,37 @@ NotifyLogon(VOID)
     HINSTANCE hModule;
     PCMP_REPORT_LOGON CMP_Report_LogOn;
 
+    TRACE("()\n");
+
     hModule = LoadLibrary(L"setupapi.dll");
     if (hModule)
     {
         CMP_Report_LogOn = (PCMP_REPORT_LOGON)GetProcAddress(hModule, "CMP_Report_LogOn");
         if (CMP_Report_LogOn)
             CMP_Report_LogOn(CMP_MAGIC, GetCurrentProcessId());
+        else
+            WARN("GetProcAddress() failed\n");
 
         FreeLibrary(hModule);
     }
+    else
+        WARN("LoadLibrary() failed with error %lu\n", GetLastError());
 }
 
-
 #ifdef _MSC_VER
 #pragma warning(disable : 4100)
 #endif /* _MSC_VER */
 
 int WINAPI
-WinMain(HINSTANCE hInst,
-        HINSTANCE hPrevInstance,
-        LPSTR lpszCmdLine,
-        int nCmdShow)
+wWinMain(IN HINSTANCE hInst,
+         IN HINSTANCE hPrevInstance,
+         IN LPWSTR lpszCmdLine,
+         IN int nCmdShow)
 {
-  NotifyLogon();
-  SetUserSettings();
-  StartShell();
-  return 0;
+    SetUserSettings();
+    StartShell();
+    NotifyLogon();
+    return 0;
 }
 
 /* EOF */