[PROGMAN]
[reactos.git] / reactos / base / shell / progman / main.c
index a918ea3..7d9f593 100644 (file)
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+/*
+ * PROJECT:         ReactOS Program Manager
+ * COPYRIGHT:       GPL - See COPYING in the top level directory
+ * FILE:            base/shell/progman/main.c
+ * PURPOSE:         ProgMan entry point & MDI window
+ * PROGRAMMERS:     Ulrich Schmid
+ *                  Sylvain Petreolle
+ *                  Hermes Belusca-Maito (hermes.belusca@sfr.fr)
+ */
+
 #include "progman.h"
 
 #include <shellapi.h>
 
+#define WC_MDICLIENTA        "MDICLIENT"
+#define WC_MDICLIENTW       L"MDICLIENT"
+
+#ifdef UNICODE
+#define WC_MDICLIENT        WC_MDICLIENTW
+#else
+#define WC_MDICLIENT        WC_MDICLIENTA
+#endif
+
 GLOBALS Globals;
 
-static VOID MAIN_CreateGroups(void);
+static VOID MAIN_LoadGroups(VOID);
 static VOID MAIN_MenuCommand(HWND hWnd, WPARAM wParam, LPARAM lParam);
-static ATOM MAIN_RegisterMainWinClass(void);
-static VOID MAIN_CreateMainWindow(void);
-static VOID MAIN_CreateMDIWindow(void);
-static VOID MAIN_AutoStart(void);
+static ATOM MAIN_RegisterMainWinClass(VOID);
+static VOID MAIN_CreateMainWindow(VOID);
+static VOID MAIN_CreateMDIWindow(VOID);
+static VOID MAIN_AutoStart(VOID);
+
+
+#define BUFFER_SIZE 1024
+
+
+
+/*
+ * Memory management functions
+ */
+PVOID
+Alloc(IN DWORD  dwFlags,
+      IN SIZE_T dwBytes)
+{
+    return HeapAlloc(GetProcessHeap(), dwFlags, dwBytes);
+}
+
+BOOL
+Free(IN PVOID lpMem)
+{
+    return HeapFree(GetProcessHeap(), 0, lpMem);
+}
+
+PVOID
+ReAlloc(IN DWORD  dwFlags,
+        IN PVOID  lpMem,
+        IN SIZE_T dwBytes)
+{
+    return HeapReAlloc(GetProcessHeap(), dwFlags, lpMem, dwBytes);
+}
+
+PVOID
+AppendToBuffer(IN PVOID   pBuffer,
+               IN PSIZE_T pdwBufferSize,
+               IN PVOID   pData,
+               IN SIZE_T  dwDataSize)
+{
+    PVOID  pTmp;
+    SIZE_T dwBufferSize;
+
+    dwBufferSize = dwDataSize + *pdwBufferSize;
+
+    if (pBuffer)
+        pTmp = ReAlloc(0, pBuffer, dwBufferSize);
+    else
+        pTmp = Alloc(0, dwBufferSize);
+
+    if (!pTmp)
+        return NULL;
+
+    memcpy((PVOID)((ULONG_PTR)pTmp + *pdwBufferSize), pData, dwDataSize);
+    *pdwBufferSize = dwBufferSize;
+
+    return pTmp;
+}
+
+
+
+/*
+ * Debugging helpers
+ */
+VOID
+PrintStringV(IN LPCWSTR szStr,
+             IN va_list args)
+{
+    WCHAR Buffer[4096];
+
+    _vsnwprintf(Buffer, ARRAYSIZE(Buffer), szStr, args);
+    MessageBoxW(Globals.hMainWnd, Buffer, L"Information", MB_OK);
+}
+
+VOID
+PrintString(IN LPCWSTR szStr, ...)
+{
+    va_list args;
+
+    va_start(args, szStr);
+    PrintStringV(szStr, args);
+    va_end(args);
+}
+
+VOID
+PrintResourceString(IN UINT uID, ...)
+{
+    WCHAR Buffer[4096];
+    va_list args;
+
+    va_start(args, uID);
+    LoadStringW(Globals.hInstance, uID, Buffer, ARRAYSIZE(Buffer));
+    PrintStringV(Buffer, args);
+    va_end(args);
+}
+
+VOID
+PrintWin32Error(IN LPWSTR Message, IN DWORD ErrorCode)
+{
+    LPWSTR lpMsgBuf;
+
+    FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+                   NULL, ErrorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+                   (LPWSTR)&lpMsgBuf, 0, NULL);
+
+    PrintString(L"%s: %s\n", Message, lpMsgBuf);
+    LocalFree(lpMsgBuf);
+}
+
+int ShowLastWin32Error(VOID)
+{
+    DWORD dwError;
+    LPWSTR lpMsgBuf = NULL;
+    WCHAR Buffer[4096];
+
+    dwError = GetLastError();
+
+    FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+                   NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+                   (LPWSTR)&lpMsgBuf, 0, NULL);
+    _snwprintf(Buffer, ARRAYSIZE(Buffer), L"Error %d: %s\n", dwError, lpMsgBuf);
+    LocalFree(lpMsgBuf);
+    return MessageBoxW(Globals.hMainWnd, Buffer, L"Error", MB_OK);
+}
+
+
+
+
+
+
+
+/* Copied and adapted from dll/win32/userenv/environment.c!GetUserAndDomainName */
+static
+BOOL
+GetUserAndDomainName(OUT LPWSTR* UserName,
+                     OUT LPWSTR* DomainName)
+{
+    BOOL bRet = TRUE;
+    HANDLE hToken;
+    DWORD cbTokenBuffer = 0;
+    PTOKEN_USER pUserToken;
+
+    LPWSTR lpUserName   = NULL;
+    LPWSTR lpDomainName = NULL;
+    DWORD  cbUserName   = 0;
+    DWORD  cbDomainName = 0;
+
+    SID_NAME_USE SidNameUse;
+
+    /* Get the process token */
+    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
+        return FALSE;
+
+    /* Retrieve token's information */
+    if (!GetTokenInformation(hToken, TokenUser, NULL, 0, &cbTokenBuffer))
+    {
+        if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+        {
+            CloseHandle(hToken);
+            return FALSE;
+        }
+    }
+
+    pUserToken = Alloc(HEAP_ZERO_MEMORY, cbTokenBuffer);
+    if (!pUserToken)
+    {
+        CloseHandle(hToken);
+        return FALSE;
+    }
+
+    if (!GetTokenInformation(hToken, TokenUser, pUserToken, cbTokenBuffer, &cbTokenBuffer))
+    {
+        Free(pUserToken);
+        CloseHandle(hToken);
+        return FALSE;
+    }
+
+    CloseHandle(hToken);
+
+    /* Retrieve the domain and user name */
+    if (!LookupAccountSidW(NULL,
+                           pUserToken->User.Sid,
+                           NULL,
+                           &cbUserName,
+                           NULL,
+                           &cbDomainName,
+                           &SidNameUse))
+    {
+        if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+        {
+            bRet = FALSE;
+            goto done;
+        }
+    }
+
+    lpUserName = Alloc(HEAP_ZERO_MEMORY, cbUserName * sizeof(WCHAR));
+    if (lpUserName == NULL)
+    {
+        bRet = FALSE;
+        goto done;
+    }
+
+    lpDomainName = Alloc(HEAP_ZERO_MEMORY, cbDomainName * sizeof(WCHAR));
+    if (lpDomainName == NULL)
+    {
+        bRet = FALSE;
+        goto done;
+    }
+
+    if (!LookupAccountSidW(NULL,
+                           pUserToken->User.Sid,
+                           lpUserName,
+                           &cbUserName,
+                           lpDomainName,
+                           &cbDomainName,
+                           &SidNameUse))
+    {
+        bRet = FALSE;
+        goto done;
+    }
+
+    *UserName   = lpUserName;
+    *DomainName = lpDomainName;
+
+done:
+    if (bRet == FALSE)
+    {
+        if (lpUserName != NULL)
+            Free(lpUserName);
+
+        if (lpDomainName != NULL)
+            Free(lpDomainName);
+    }
+
+    Free(pUserToken);
+
+    return bRet;
+}
+
+
+
+
+
+
+static
+VOID
+MAIN_SetMainWindowTitle(VOID)
+{
+    LPWSTR caption;
+    SIZE_T size;
+
+    LPWSTR lpDomainName = NULL;
+    LPWSTR lpUserName   = NULL;
+
+    if (GetUserAndDomainName(&lpUserName, &lpDomainName) && lpUserName && lpDomainName)
+    {
+        size = (256 + 3 + wcslen(lpDomainName) + wcslen(lpUserName) + 1) * sizeof(WCHAR);
+        caption = Alloc(HEAP_ZERO_MEMORY, size);
+        if (caption)
+        {
+            swprintf(caption, L"%s - %s\\%s", szTitle, lpDomainName, lpUserName);
+            SetWindowTextW(Globals.hMainWnd, caption);
+            Free(caption);
+        }
+        else
+        {
+            SetWindowTextW(Globals.hMainWnd, szTitle);
+        }
+    }
+    else
+    {
+        SetWindowTextW(Globals.hMainWnd, szTitle);
+    }
+
+    if (lpUserName)   Free(lpUserName);
+    if (lpDomainName) Free(lpDomainName);
+}
+
+
+
+
+static
+BOOL
+MAIN_LoadSettings(VOID)
+{
+    LPWSTR lpszTmp;
+    LPWSTR lpszSection;
+    LONG lRet;
+    WCHAR dummy[2];
+    LPWSTR lpszKeyValue;
+    const LPCWSTR lpszIniFile = L"progman.ini";
+    WCHAR szWinDir[MAX_PATH];
+    LPWSTR lpszKey;
+    DWORD Value;
+    HKEY hKey;
+    BOOL bIsIniMigrated;
+    DWORD dwSize;
+    LPWSTR lpszSections;
+    LPWSTR lpszData;
+    DWORD dwRet;
+    DWORD dwType;
+    LPWSTR lpszValue;
+
+    bIsIniMigrated = FALSE;
+    lpszSections = NULL;
+    lpszData = NULL;
+
+    /* Try to create/open the Program Manager user key */
+    if (RegCreateKeyExW(HKEY_CURRENT_USER,
+                        L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Program Manager",
+                        0,
+                        NULL,
+                        REG_OPTION_NON_VOLATILE,
+                        KEY_READ | KEY_WRITE,
+                        NULL,
+                        &Globals.hKeyProgMan,
+                        NULL) != ERROR_SUCCESS)
+    {
+        return FALSE;
+    }
+
+    /*
+     * TODO: Add the explanation for the migration...
+     */
+    dwSize = sizeof(Value);
+    lRet = RegQueryValueExW(Globals.hKeyProgMan, L"IniMigrated", NULL, &dwType, (LPBYTE)&Value, &dwSize);
+    if (lRet != ERROR_SUCCESS || dwType != REG_DWORD)
+        Value = 0;
+    bIsIniMigrated = !!Value;
+
+    if (bIsIniMigrated)
+    {
+        /* The migration was already done, just load the settings */
+        goto LoadSettings;
+    }
+
+    /* Perform the migration */
+
+    bIsIniMigrated = TRUE;
+    dwSize = ARRAYSIZE(dummy);
+    SetLastError(0);
+    GetPrivateProfileSectionW(L"Settings", dummy, dwSize, lpszIniFile);
+    if (GetLastError() == ERROR_FILE_NOT_FOUND)
+        goto MigrationDone;
+
+    SetLastError(0);
+    GetPrivateProfileSectionW(L"Groups", dummy, dwSize, lpszIniFile);
+    if (GetLastError() == ERROR_FILE_NOT_FOUND)
+        goto MigrationDone;
+
+    GetWindowsDirectoryW(szWinDir, ARRAYSIZE(szWinDir));
+    // NOTE: GCC complains we cannot use the "\u2022" (UNICODE Code Point) notation for specifying the bullet character,
+    // because it's only available in C++ or in C99. On the contrary MSVC is fine with it.
+    // Instead we use a hex specification for the character: "\x2022".
+    // Note also that the character "\x07" gives also a bullet, but a larger one.
+    PrintString(
+        L"The Program Manager has detected the presence of a legacy settings file PROGMAN.INI in the directory '%s' "
+        L"and is going to migrate its contents into the current-user Program Manager settings registry key:\n"
+        L"HKCU\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Program Manager"
+        L"\n\n"
+        L"\x2022 The migration operation will potentially overwrite all the existing current-user Program Manager settings in the registry by those stored in the PROGMAN.INI file.\n"
+        L"\n"
+        L"\x2022 The migration is done once, so that, at the next launch of the Program Manager, the new migrated settings are directly used.\n"
+        L"\n"
+        L"\x2022 It is possible to trigger later the migration by manually deleting the registry value \"IniMigrated\" under the current-user Program Manager settings registry key (specified above).\n"
+        L"\n"
+        L"Would you like to migrate its contents into the registry?",
+        szWinDir);
+
+    for (dwSize = BUFFER_SIZE; ; dwSize += BUFFER_SIZE)
+    {
+        lpszSections = Alloc(0, dwSize * sizeof(WCHAR));
+        dwRet = GetPrivateProfileSectionNamesW(lpszSections, dwSize, lpszIniFile);
+        if (dwRet < dwSize - 2)
+            break;
+        Free(lpszSections);
+    }
+    lpszSection = lpszSections;
+    while (*lpszSection)
+    {
+        lRet = RegCreateKeyExW(Globals.hKeyProgMan,
+                                lpszSection,
+                                0,
+                                NULL,
+                                REG_OPTION_NON_VOLATILE,
+                                KEY_WRITE,
+                                NULL,
+                                &hKey,
+                                NULL);
+        if (lRet == ERROR_SUCCESS)
+        {
+            for (dwSize = BUFFER_SIZE; ; dwSize += BUFFER_SIZE)
+            {
+                lpszData = Alloc(0, dwSize * sizeof(WCHAR));
+                dwRet = GetPrivateProfileSectionW(lpszSection, lpszData, dwSize, lpszIniFile);
+                if (dwRet < dwSize - 2)
+                    break;
+                Free(lpszData);
+            }
+            lpszKeyValue = lpszData;
+            while (*lpszKeyValue)
+            {
+                lpszKey = lpszKeyValue;
+                lpszValue = wcschr(lpszKeyValue, L'=');
+                lpszKeyValue += (wcslen(lpszKeyValue) + 1);
+                if (lpszValue)
+                {
+                    *lpszValue = '\0';
+                    ++lpszValue;
+                    Value = wcstoul(lpszValue, &lpszTmp, 0);
+                    if (lpszTmp - lpszValue >= wcslen(lpszValue))
+                    {
+                        lpszValue = (LPWSTR)&Value;
+                        dwSize = sizeof(Value);
+                        dwType = REG_DWORD;
+                    }
+                    else
+                    {
+                        dwSize = wcslen(lpszValue) * sizeof(WCHAR);
+                        dwType = REG_SZ;
+                    }
+                }
+                else
+                {
+                    dwSize = 0;
+                    dwType = REG_DWORD;
+                }
+                lRet = RegSetValueExW(hKey, lpszKey, 0, dwType, (LPBYTE)lpszValue, dwSize);
+            }
+            Free(lpszData);
+            RegCloseKey(hKey);
+            lpszSection += (wcslen(lpszSection) + 1);
+        }
+    }
+    Free(lpszSections);
+
+MigrationDone:
+    Value = TRUE;
+    RegSetValueExW(Globals.hKeyProgMan, L"IniMigrated", 0, REG_DWORD, (LPBYTE)&Value, sizeof(Value));
+
+
+LoadSettings:
+    /* Create the necessary registry keys for the Program Manager and load its settings from the registry */
+
+    lRet = RegCreateKeyExW(Globals.hKeyProgMan,
+                           L"Settings",
+                           0,
+                           NULL,
+                           REG_OPTION_NON_VOLATILE,
+                           KEY_READ | KEY_WRITE,
+                           NULL,
+                           &Globals.hKeyPMSettings,
+                           NULL);
+
+    lRet = RegCreateKeyExW(Globals.hKeyProgMan,
+                           L"Common Groups",
+                           0,
+                           NULL,
+                           REG_OPTION_NON_VOLATILE,
+                           KEY_READ | KEY_WRITE,
+                           NULL,
+                           &Globals.hKeyPMCommonGroups,
+                           NULL);
+
+    lRet = RegCreateKeyExW(Globals.hKeyProgMan,
+                           L"Groups",
+                           0,
+                           NULL,
+                           REG_OPTION_NON_VOLATILE,
+                           KEY_READ | KEY_WRITE,
+                           NULL,
+                           &Globals.hKeyPMAnsiGroups,
+                           NULL);
+
+    lRet = RegCreateKeyExW(Globals.hKeyProgMan,
+                           L"UNICODE Groups",
+                           0,
+                           NULL,
+                           REG_OPTION_NON_VOLATILE,
+                           KEY_READ | KEY_WRITE,
+                           NULL,
+                           &Globals.hKeyPMUnicodeGroups,
+                           NULL);
+
+    lRet = RegCreateKeyExW(HKEY_CURRENT_USER,
+                           L"Program Groups",
+                           0,
+                           NULL,
+                           REG_OPTION_NON_VOLATILE,
+                           KEY_READ | KEY_WRITE,
+                           NULL,
+                           &Globals.hKeyAnsiGroups,
+                           NULL);
+
+    lRet = RegCreateKeyExW(HKEY_CURRENT_USER,
+                           L"UNICODE Program Groups",
+                           0,
+                           NULL,
+                           REG_OPTION_NON_VOLATILE,
+                           KEY_READ | KEY_WRITE,
+                           NULL,
+                           &Globals.hKeyUnicodeGroups,
+                           NULL);
+
+    lRet = RegCreateKeyExW(HKEY_LOCAL_MACHINE,
+                           L"SOFTWARE\\Program Groups",
+                           0,
+                           NULL,
+                           REG_OPTION_NON_VOLATILE,
+                           KEY_READ | KEY_WRITE,
+                           NULL,
+                           &Globals.hKeyCommonGroups,
+                           NULL);
+
+    dwSize = sizeof(Globals.bAutoArrange);
+    RegQueryValueExW(Globals.hKeyPMSettings, L"AutoArrange", NULL, &dwType, (LPBYTE)&Globals.bAutoArrange, &dwSize);
+
+    dwSize = sizeof(Globals.bMinOnRun);
+    RegQueryValueExW(Globals.hKeyPMSettings, L"MinOnRun", NULL, &dwType, (LPBYTE)&Globals.bMinOnRun, &dwSize);
+
+    dwSize = sizeof(Globals.bSaveSettings);
+    RegQueryValueExW(Globals.hKeyPMSettings, L"SaveSettings", NULL, &dwType, (LPBYTE)&Globals.bSaveSettings, &dwSize);
+
+    return TRUE;
+}
+
+static
+BOOL
+MAIN_SaveSettings(VOID)
+{
+    WINDOWPLACEMENT WndPl;
+    DWORD dwSize;
+    WCHAR buffer[100];
+
+    WndPl.length = sizeof(WndPl);
+    GetWindowPlacement(Globals.hMainWnd, &WndPl);
+    swprintf(buffer, L"%d %d %d %d %d",
+             WndPl.rcNormalPosition.left,
+             WndPl.rcNormalPosition.top,
+             WndPl.rcNormalPosition.right,
+             WndPl.rcNormalPosition.bottom,
+             WndPl.showCmd);
+
+    dwSize = wcslen(buffer) * sizeof(WCHAR);
+    RegSetValueExW(Globals.hKeyPMSettings, L"Window", 0, REG_SZ, (LPBYTE)buffer, dwSize);
+
+    return TRUE;
+}
 
-#define BUFFER_SIZE 1000
 
 /***********************************************************************
  *
  *           WinMain
  */
 
-#ifdef __REACTOS__
-int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prev, LPSTR cmdline, int show)
-#else
-int PASCAL WinMain (HINSTANCE hInstance, HINSTANCE prev, LPSTR cmdline, int show)
-#endif
+INT WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, INT nCmdShow)
 {
-  MSG      msg;
+    MSG msg;
+    INITCOMMONCONTROLSEX icex;
+
+    /*
+     * Set our shutdown parameters: we want to shutdown the very last,
+     * but before any TaskMgr instance (which has a shutdown level of 1).
+     */
+    SetProcessShutdownParameters(2, 0);
+
+    Globals.hInstance    = hInstance;
+    Globals.hGroups      = NULL;
+    Globals.hActiveGroup = NULL;
+
+    /* Load Program Manager's settings */
+    MAIN_LoadSettings();
+
+    /* Load the default icons */
+    Globals.hDefaultIcon       = LoadIconW(NULL, MAKEINTRESOURCEW(IDI_WINLOGO));
+    Globals.hMainIcon          = LoadIconW(Globals.hInstance, MAKEINTRESOURCEW(IDI_APPICON));
+    Globals.hPersonalGroupIcon = LoadIconW(Globals.hInstance, MAKEINTRESOURCEW(IDI_GROUP_PERSONAL_ICON));
+    Globals.hCommonGroupIcon   = LoadIconW(Globals.hInstance, MAKEINTRESOURCEW(IDI_GROUP_COMMON_ICON));
+
+    /* Initialize the common controls */
+    icex.dwSize = sizeof(icex);
+    icex.dwICC  = ICC_HOTKEY_CLASS | ICC_LISTVIEW_CLASSES; // | ICC_STANDARD_CLASSES;
+    InitCommonControlsEx(&icex);
+
+    /* Register the window classes */
+    if (!hPrevInstance) // FIXME: Unused on Win32!
+    {
+        if (!MAIN_RegisterMainWinClass())   goto Quit;
+        if (!GROUP_RegisterGroupWinClass()) goto Quit;
+    }
 
-  Globals.lpszIniFile         = "progman.ini";
-#ifndef __REACTOS__
-  Globals.lpszIcoFile         = "progman.ico";
-#endif
+    /* Set up the strings, the main window, the accelerators, the menu, and the MDI child window */
+    STRING_LoadStrings();
+    MAIN_CreateMainWindow();
+    Globals.hAccel = LoadAcceleratorsW(Globals.hInstance, MAKEINTRESOURCEW(IDA_ACCEL));
+    STRING_LoadMenus();
+    MAIN_CreateMDIWindow();
 
-  Globals.hInstance           = hInstance;
-  Globals.hGroups             = 0;
-  Globals.hActiveGroup        = 0;
-
-  /* Read Options from `progman.ini' */
-  Globals.bAutoArrange =
-    GetPrivateProfileIntA("Settings", "AutoArrange", 0, Globals.lpszIniFile);
-  Globals.bMinOnRun =
-    GetPrivateProfileIntA("Settings", "MinOnRun", 0, Globals.lpszIniFile);
-  Globals.bSaveSettings =
-    GetPrivateProfileIntA("Settings", "SaveSettings", 0, Globals.lpszIniFile);
-
-  /* Load default icons */
-#ifdef __REACTOS__
-  Globals.hMainIcon = LoadIconW(Globals.hInstance, MAKEINTRESOURCEW(IDI_APPICON));
-  Globals.hGroupIcon = Globals.hMainIcon;
-  Globals.hDefaultIcon = Globals.hMainIcon;
-#else
-  Globals.hMainIcon    = ExtractIconA(Globals.hInstance, Globals.lpszIcoFile, 0);
-  Globals.hGroupIcon   = ExtractIconA(Globals.hInstance, Globals.lpszIcoFile, 0);
-  Globals.hDefaultIcon = ExtractIconA(Globals.hInstance, Globals.lpszIcoFile, 0);
-#endif
-  if (!Globals.hMainIcon)    Globals.hMainIcon = LoadIconW(0, (LPWSTR)DEFAULTICON);
-  if (!Globals.hGroupIcon)   Globals.hGroupIcon = LoadIconW(0, (LPWSTR)DEFAULTICON);
-  if (!Globals.hDefaultIcon) Globals.hDefaultIcon = LoadIconW(0, (LPWSTR)DEFAULTICON);
+    /* Load all the groups */
+    // MAIN_CreateGroups();
+    MAIN_LoadGroups();
 
-  /* Register classes */
-  if (!prev)
+    /* Load the Startup group: start the initial applications */
+    MAIN_AutoStart();
+
+    /* Message loop */
+    while (GetMessageW(&msg, NULL, 0, 0))
     {
-      if (!MAIN_RegisterMainWinClass()) return(FALSE);
-      if (!GROUP_RegisterGroupWinClass()) return(FALSE);
-      if (!PROGRAM_RegisterProgramWinClass()) return(FALSE);
+        if (!TranslateMDISysAccel(Globals.hMDIWnd, &msg) &&
+            !TranslateAcceleratorW(Globals.hMainWnd, Globals.hAccel, &msg))
+        {
+            TranslateMessage(&msg);
+            DispatchMessageW(&msg);
+        }
     }
 
-  /* Create main window */
-  MAIN_CreateMainWindow();
-  Globals.hAccel = LoadAcceleratorsW(Globals.hInstance, MAKEINTRESOURCEW(IDA_ACCEL));
-
-  /* Setup menu, stringtable and resourcenames */
-  STRING_LoadMenus();
-
-  MAIN_CreateMDIWindow();
+Quit:
 
-  /* Initialize groups */
-  MAIN_CreateGroups();
+    /* Save the settings, close the registry keys and quit */
 
-  /* Start initial applications */
-  MAIN_AutoStart();
+    // MAIN_SaveSettings();
+    RegCloseKey(Globals.hKeyCommonGroups);
+    RegCloseKey(Globals.hKeyUnicodeGroups);
+    RegCloseKey(Globals.hKeyAnsiGroups);
+    RegCloseKey(Globals.hKeyPMUnicodeGroups);
+    RegCloseKey(Globals.hKeyPMAnsiGroups);
+    RegCloseKey(Globals.hKeyPMCommonGroups);
+    RegCloseKey(Globals.hKeyPMSettings);
+    RegCloseKey(Globals.hKeyProgMan);
 
-  /* Message loop */
-  while (GetMessageW (&msg, 0, 0, 0))
-    if (!TranslateAcceleratorW(Globals.hMainWnd, Globals.hAccel, &msg))
-      {
-       TranslateMessage (&msg);
-       DispatchMessageW (&msg);
-      }
-  return 0;
+    return 0;
 }
 
 /***********************************************************************
@@ -116,7 +684,8 @@ int PASCAL WinMain (HINSTANCE hInstance, HINSTANCE prev, LPSTR cmdline, int show
  *           MAIN_CreateGroups
  */
 
-static VOID MAIN_CreateGroups(void)
+#if 0
+static VOID MAIN_CreateGroups(VOID)
 {
   CHAR buffer[BUFFER_SIZE];
   CHAR szPath[MAX_PATHNAME_LEN];
@@ -144,25 +713,41 @@ static VOID MAIN_CreateGroups(void)
     }
   /* FIXME initialize other groups, not enumerated by `Order' */
 }
+#endif
+
+static VOID MAIN_LoadGroups(VOID)
+{
+}
 
 /***********************************************************************
  *
  *           MAIN_AutoStart
  */
 
-VOID MAIN_AutoStart(void)
+static VOID MAIN_AutoStart(VOID)
 {
-  CHAR buffer[BUFFER_SIZE];
-  HLOCAL hGroup, hProgram;
+    LONG lRet;
+    DWORD dwSize;
+    DWORD dwType;
+
+    PROGGROUP* hGroup;
+    PROGRAM* hProgram;
 
-  GetPrivateProfileStringA("Settings", "AutoStart", "Autostart", buffer,
-                         sizeof(buffer), Globals.lpszIniFile);
+    WCHAR buffer[BUFFER_SIZE];
 
-  for (hGroup = GROUP_FirstGroup(); hGroup; hGroup = GROUP_NextGroup(hGroup))
-    if (!lstrcmpA(buffer, GROUP_GroupName(hGroup)))
-      for (hProgram = PROGRAM_FirstProgram(hGroup); hProgram;
-          hProgram = PROGRAM_NextProgram(hProgram))
-       PROGRAM_ExecuteProgram(hProgram);
+    dwSize = sizeof(buffer);
+    lRet = RegQueryValueExW(Globals.hKeyPMSettings, L"Startup", NULL, &dwType, (LPBYTE)buffer, &dwSize);
+    if (lRet != ERROR_SUCCESS || dwType != REG_SZ)
+        return;
+
+    for (hGroup = Globals.hGroups; hGroup; hGroup = hGroup->hNext)
+    {
+        if (_wcsicmp(buffer, hGroup->hName) == 0)
+        {
+            for (hProgram = hGroup->hPrograms; hProgram; hProgram = hProgram->hNext)
+                PROGRAM_ExecuteProgram(hProgram);
+        }
+    }
 }
 
 /***********************************************************************
@@ -170,33 +755,70 @@ VOID MAIN_AutoStart(void)
  *           MAIN_MainWndProc
  */
 
-static LRESULT CALLBACK MAIN_MainWndProc(HWND hWnd, UINT msg,
-                                WPARAM wParam, LPARAM lParam)
+static LRESULT CALLBACK MAIN_MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 {
-  switch (msg)
+    switch (uMsg)
     {
-    case WM_INITMENU:
-      CheckMenuItem(Globals.hOptionMenu, PM_AUTO_ARRANGE,
-                   MF_BYCOMMAND | (Globals.bAutoArrange ? MF_CHECKED : MF_UNCHECKED));
-      CheckMenuItem(Globals.hOptionMenu, PM_MIN_ON_RUN,
-                   MF_BYCOMMAND | (Globals.bMinOnRun ? MF_CHECKED : MF_UNCHECKED));
-      CheckMenuItem(Globals.hOptionMenu, PM_SAVE_SETTINGS,
-                   MF_BYCOMMAND | (Globals.bSaveSettings ? MF_CHECKED : MF_UNCHECKED));
-      break;
-
-    case WM_COMMAND:
-      if (LOWORD(wParam) < PM_FIRST_CHILD){
-       MAIN_MenuCommand(hWnd, LOWORD(wParam), lParam);
-      }
-      break;
-
-    case WM_DESTROY:
-      PostQuitMessage (0);
-      break;
+        case WM_INITMENU:
+        {
+            PROGGROUP* hActiveGroup = GROUP_ActiveGroup();
+            if (hActiveGroup)
+            {
+                if (PROGRAM_ActiveProgram(hActiveGroup))
+                {
+                    EnableMenuItem(Globals.hFileMenu, PM_OPEN, MF_ENABLED);
+                    EnableMenuItem(Globals.hFileMenu, PM_MOVE, MF_ENABLED);
+                    EnableMenuItem(Globals.hFileMenu, PM_COPY, MF_ENABLED);
+                    EnableMenuItem(Globals.hFileMenu, PM_DELETE    , MF_ENABLED);
+                    EnableMenuItem(Globals.hFileMenu, PM_ATTRIBUTES, MF_ENABLED);
+                }
+                else
+                {
+                    if (!hActiveGroup->hWnd || IsIconic(hActiveGroup->hWnd))
+                        EnableMenuItem(Globals.hFileMenu, PM_OPEN, MF_ENABLED);
+                    else
+                        EnableMenuItem(Globals.hFileMenu, PM_OPEN, MF_GRAYED);
+
+                    EnableMenuItem(Globals.hFileMenu, PM_MOVE, MF_GRAYED);
+                    EnableMenuItem(Globals.hFileMenu, PM_COPY, MF_GRAYED);
+                    EnableMenuItem(Globals.hFileMenu, PM_DELETE    , MF_ENABLED);
+                    EnableMenuItem(Globals.hFileMenu, PM_ATTRIBUTES, MF_ENABLED);
+                }
+            }
+            else
+            {
+                EnableMenuItem(Globals.hFileMenu, PM_OPEN, MF_GRAYED);
+                EnableMenuItem(Globals.hFileMenu, PM_MOVE, MF_GRAYED);
+                EnableMenuItem(Globals.hFileMenu, PM_COPY, MF_GRAYED);
+                EnableMenuItem(Globals.hFileMenu, PM_DELETE    , MF_GRAYED);
+                EnableMenuItem(Globals.hFileMenu, PM_ATTRIBUTES, MF_GRAYED);
+            }
+
+            CheckMenuItem(Globals.hOptionMenu, PM_AUTO_ARRANGE,
+                          MF_BYCOMMAND | (Globals.bAutoArrange  ? MF_CHECKED : MF_UNCHECKED));
+            CheckMenuItem(Globals.hOptionMenu, PM_MIN_ON_RUN,
+                          MF_BYCOMMAND | (Globals.bMinOnRun     ? MF_CHECKED : MF_UNCHECKED));
+            CheckMenuItem(Globals.hOptionMenu, PM_SAVE_SETTINGS,
+                          MF_BYCOMMAND | (Globals.bSaveSettings ? MF_CHECKED : MF_UNCHECKED));
+            break;
+        }
+
+        case WM_DESTROY:
+            if (Globals.bSaveSettings)
+                MAIN_SaveSettings();
+            PostQuitMessage(0);
+            break;
+
+        case WM_COMMAND:
+            if (LOWORD(wParam) < PM_FIRST_CHILD)
+                MAIN_MenuCommand(hWnd, LOWORD(wParam), lParam);
+            break;
     }
-  return DefFrameProcW(hWnd, Globals.hMDIWnd, msg, wParam, lParam);
+
+    return DefFrameProcW(hWnd, Globals.hMDIWnd, uMsg, wParam, lParam);
 }
 
+
 /***********************************************************************
  *
  *           MAIN_MenuCommand
@@ -204,6 +826,7 @@ static LRESULT CALLBACK MAIN_MainWndProc(HWND hWnd, UINT msg,
 
 static VOID MAIN_MenuCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
 {
+#if 0
   HLOCAL hActiveGroup    = GROUP_ActiveGroup();
   HLOCAL hActiveProgram  = PROGRAM_ActiveProgram(hActiveGroup);
   HWND   hActiveGroupWnd = GROUP_GroupWnd(hActiveGroup);
@@ -225,18 +848,6 @@ static VOID MAIN_MenuCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
       }
       break;
 
-    case PM_OPEN:
-      if (hActiveProgram)
-       PROGRAM_ExecuteProgram(hActiveProgram);
-      else if (hActiveGroupWnd)
-       OpenIcon(hActiveGroupWnd);
-      break;
-
-    case PM_MOVE:
-    case PM_COPY:
-      if (hActiveProgram)
-       PROGRAM_CopyMoveProgram(hActiveProgram, wParam == PM_MOVE);
-      break;
 
     case PM_DELETE:
       if (hActiveProgram)
@@ -251,43 +862,7 @@ static VOID MAIN_MenuCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
        }
       break;
 
-    case PM_ATTRIBUTES:
-      if (hActiveProgram)
-       PROGRAM_ModifyProgram(hActiveProgram);
-      else if (hActiveGroup)
-       GROUP_ModifyGroup(hActiveGroup);
-      break;
-
-    case PM_EXECUTE:
-      DIALOG_Execute();
-      break;
 
-    case PM_EXIT:
-      PostQuitMessage(0);
-      break;
-
-      /* Menu Options */
-    case PM_AUTO_ARRANGE:
-      Globals.bAutoArrange = !Globals.bAutoArrange;
-      CheckMenuItem(Globals.hOptionMenu, PM_AUTO_ARRANGE,
-                   MF_BYCOMMAND | (Globals.bAutoArrange ?
-                                   MF_CHECKED : MF_UNCHECKED));
-      WritePrivateProfileStringA("Settings", "AutoArrange",
-                               Globals.bAutoArrange ? "1" : "0",
-                               Globals.lpszIniFile);
-      WritePrivateProfileStringA(NULL,NULL,NULL,Globals.lpszIniFile); /* flush it */
-      break;
-
-    case PM_MIN_ON_RUN:
-      Globals.bMinOnRun = !Globals.bMinOnRun;
-      CheckMenuItem(Globals.hOptionMenu, PM_MIN_ON_RUN,
-                   MF_BYCOMMAND | (Globals.bMinOnRun ?
-                                   MF_CHECKED : MF_UNCHECKED));
-      WritePrivateProfileStringA("Settings", "MinOnRun",
-                               Globals.bMinOnRun ? "1" : "0",
-                               Globals.lpszIniFile);
-      WritePrivateProfileStringA(NULL,NULL,NULL,Globals.lpszIniFile); /* flush it */
-      break;
 
     case PM_SAVE_SETTINGS:
       Globals.bSaveSettings = !Globals.bSaveSettings;
@@ -300,14 +875,6 @@ static VOID MAIN_MenuCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
       WritePrivateProfileStringA(NULL,NULL,NULL,Globals.lpszIniFile); /* flush it */
       break;
 
-      /* Menu Windows */
-    case PM_OVERLAP:
-      SendMessageW(Globals.hMDIWnd, WM_MDICASCADE, 0, 0);
-      break;
-
-    case PM_SIDE_BY_SIDE:
-      SendMessageW(Globals.hMDIWnd, WM_MDITILE, MDITILE_VERTICAL, 0);
-      break;
 
     case PM_ARRANGE:
 
@@ -317,29 +884,165 @@ static VOID MAIN_MenuCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
        SendMessageW(Globals.hMDIWnd, WM_MDIICONARRANGE, 0, 0);
       break;
 
-      /* Menu Help */
-    case PM_CONTENTS:
-      if (!WinHelpA(Globals.hMainWnd, "progman.hlp", HELP_CONTENTS, 0))
-       MAIN_MessageBoxIDS(IDS_WINHELP_ERROR, IDS_ERROR, MB_OK);
-      break;
-
-    case PM_ABOUT_WINE:
-#ifdef __REACTOS__
-    {
-        WCHAR szTitle[MAX_STRING_LEN];
-        LoadStringW(Globals.hInstance, IDS_PROGRAM_MANAGER, szTitle, ARRAYSIZE(szTitle));
-        ShellAboutW(hWnd, szTitle, NULL, NULL);
-        break;
     }
-#else
-      ShellAboutA(hWnd, "WINE", "Program Manager", 0);
-      break;
+
+
+
+
 #endif
 
-    default:
-       MAIN_MessageBoxIDS(IDS_NOT_IMPLEMENTED, IDS_ERROR, MB_OK);
-      break;
+    DWORD Value;
+
+    PROGGROUP* hActiveGroup;
+    PROGRAM* hActiveProgram;
+    HWND hActiveGroupWnd;
+
+    hActiveGroup = GROUP_ActiveGroup();
+    hActiveProgram = PROGRAM_ActiveProgram(hActiveGroup);
+    hActiveGroupWnd = (hActiveGroup ? hActiveGroup->hWnd : NULL);
+
+    switch (wParam)
+    {
+        /* Menu File */
+
+        case PM_NEW:
+        {
+            BOOL Success;
+            INT nResult;
+
+            if (!hActiveGroupWnd || IsIconic(hActiveGroupWnd))
+                Success = DIALOG_New(PM_NEW_GROUP, &nResult);
+            else
+                Success = DIALOG_New(PM_NEW_PROGRAM, &nResult);
+            if (!Success)
+                break;
+
+            if (nResult & 1)
+            {
+                GROUPFORMAT format;
+                BOOL bIsCommonGroup;
+
+                format = (nResult & 0xC) >> 2;
+                bIsCommonGroup = (nResult & 2) != 0;
+                GROUP_NewGroup(format, bIsCommonGroup);
+            }
+            else if (hActiveGroup)
+            {
+                PROGRAM_NewProgram(hActiveGroup);
+            }
+
+            break;
+        }
+
+        case PM_OPEN:
+            if (hActiveProgram)
+                PROGRAM_ExecuteProgram(hActiveProgram);
+            else if (hActiveGroupWnd)
+                OpenIcon(hActiveGroupWnd);
+            break;
+
+        case PM_MOVE:
+        case PM_COPY:
+            if (hActiveProgram)
+                PROGRAM_CopyMoveProgram(hActiveProgram, wParam == PM_MOVE);
+            break;
+
+        case PM_DELETE:
+        {
+            if (hActiveProgram)
+            {
+                if (DIALOG_Delete(IDS_DELETE_PROGRAM_s, hActiveProgram->hName))
+                    PROGRAM_DeleteProgram(hActiveProgram, TRUE);
+            }
+            else if (hActiveGroup && DIALOG_Delete(IDS_DELETE_GROUP_s, hActiveGroup->hName))
+            {
+                GROUP_DeleteGroup(hActiveGroup);
+            }
+            break;
+        }
+
+        case PM_ATTRIBUTES:
+            if (hActiveProgram)
+                PROGRAM_ModifyProgram(hActiveProgram);
+            else if (hActiveGroup)
+                GROUP_ModifyGroup(hActiveGroup);
+            break;
+
+        case PM_EXECUTE:
+            DIALOG_Execute();
+            break;
+
+        case PM_EXIT:
+            // MAIN_SaveSettings();
+            PostQuitMessage(0);
+            break;
+
+
+        /* Menu Options */
+
+        case PM_AUTO_ARRANGE:
+            Globals.bAutoArrange = !Globals.bAutoArrange;
+            CheckMenuItem(Globals.hOptionMenu, PM_AUTO_ARRANGE,
+                          MF_BYCOMMAND | (Globals.bAutoArrange ? MF_CHECKED : MF_UNCHECKED));
+            Value = Globals.bAutoArrange;
+            RegSetValueExW(Globals.hKeyPMSettings, L"AutoArrange", 0, REG_DWORD, (LPBYTE)&Value, sizeof(Value));
+            break;
+
+        case PM_MIN_ON_RUN:
+            Globals.bMinOnRun = !Globals.bMinOnRun;
+            CheckMenuItem(Globals.hOptionMenu, PM_MIN_ON_RUN,
+                          MF_BYCOMMAND | (Globals.bMinOnRun ? MF_CHECKED : MF_UNCHECKED));
+            Value = Globals.bMinOnRun;
+            RegSetValueExW(Globals.hKeyPMSettings, L"MinOnRun", 0, REG_DWORD, (LPBYTE)&Value, sizeof(Value));
+            break;
+
+        case PM_SAVE_SETTINGS:
+            Globals.bSaveSettings = !Globals.bSaveSettings;
+            CheckMenuItem(Globals.hOptionMenu, PM_SAVE_SETTINGS,
+                          MF_BYCOMMAND | (Globals.bSaveSettings ? MF_CHECKED : MF_UNCHECKED));
+            Value = Globals.bSaveSettings;
+            RegSetValueExW(Globals.hKeyPMSettings, L"SaveSettings", 0, REG_DWORD, (LPBYTE)&Value, sizeof(Value));
+            break;
+
+        case PM_SAVE_SETTINGS_NOW:
+            MAIN_SaveSettings();
+            break;
+
+
+        /* Menu Windows */
+
+        case PM_OVERLAP:
+            SendMessageW(Globals.hMDIWnd, WM_MDICASCADE, 0, 0);
+            break;
+
+        case PM_SIDE_BY_SIDE:
+            SendMessageW(Globals.hMDIWnd, WM_MDITILE, MDITILE_VERTICAL, 0);
+            break;
+
+        case PM_ARRANGE:
+            if (!hActiveGroupWnd || IsIconic(hActiveGroupWnd))
+                SendMessageW(Globals.hMDIWnd, WM_MDIICONARRANGE, 0, 0);
+            else
+                SendMessageA(hActiveGroup->hListView, LVM_ARRANGE, 0, 0);
+            break;
+
+
+        /* Menu Help */
+
+        case PM_CONTENTS:
+            if (!WinHelpW(Globals.hMainWnd, L"progman.hlp", HELP_CONTENTS, 0))
+                MAIN_MessageBoxIDS(IDS_WINHELP_ERROR, IDS_ERROR, MB_OK);
+            break;
+
+        case PM_ABOUT:
+            ShellAboutW(hWnd, szTitle, NULL, Globals.hMainIcon);
+            break;
+
+        default:
+            MAIN_MessageBoxIDS(IDS_NOT_IMPLEMENTED, IDS_ERROR, MB_OK);
+            break;
     }
+
 }
 
 /***********************************************************************
@@ -347,22 +1050,22 @@ static VOID MAIN_MenuCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
  *           MAIN_RegisterMainWinClass
  */
 
-static ATOM MAIN_RegisterMainWinClass(void)
+static ATOM MAIN_RegisterMainWinClass(VOID)
 {
-  WNDCLASSW class;
-
-  class.style         = CS_HREDRAW | CS_VREDRAW;
-  class.lpfnWndProc   = MAIN_MainWndProc;
-  class.cbClsExtra    = 0;
-  class.cbWndExtra    = 0;
-  class.hInstance     = Globals.hInstance;
-  class.hIcon         = Globals.hMainIcon;
-  class.hCursor       = LoadCursorW (0, (LPWSTR)IDC_ARROW);
-  class.hbrBackground = GetStockObject (NULL_BRUSH);
-  class.lpszMenuName  = 0;
-  class.lpszClassName = STRING_MAIN_WIN_CLASS_NAME;
-
-  return RegisterClassW(&class);
+    WNDCLASSW wndClass;
+
+    wndClass.style         = CS_HREDRAW | CS_VREDRAW;
+    wndClass.lpfnWndProc   = MAIN_MainWndProc;
+    wndClass.cbClsExtra    = 0;
+    wndClass.cbWndExtra    = 0;
+    wndClass.hInstance     = Globals.hInstance;
+    wndClass.hIcon         = Globals.hMainIcon;
+    wndClass.hCursor       = LoadCursorW(NULL, MAKEINTRESOURCEW(IDC_ARROW));
+    wndClass.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);
+    wndClass.lpszMenuName  = NULL;
+    wndClass.lpszClassName = STRING_MAIN_WIN_CLASS_NAME;
+
+    return RegisterClassW(&wndClass);
 }
 
 /***********************************************************************
@@ -370,35 +1073,50 @@ static ATOM MAIN_RegisterMainWinClass(void)
  *           MAIN_CreateMainWindow
  */
 
-static VOID MAIN_CreateMainWindow(void)
+static VOID MAIN_CreateMainWindow(VOID)
 {
-  INT  left , top, right, bottom, width, height, show;
-  CHAR buffer[100];
-
-  Globals.hMDIWnd   = 0;
-  Globals.hMainMenu = 0;
-
-  /* Get the geometry of the main window */
-  GetPrivateProfileStringA("Settings", "Window", "", buffer, sizeof(buffer), Globals.lpszIniFile);
-  if (5 == sscanf(buffer, "%d %d %d %d %d", &left, &top, &right, &bottom, &show))
-  {
-    width  = right - left;
-    height = bottom - top;
-  }
-  else
-  {
-    left = top = width = height = CW_USEDEFAULT;
-    show = SW_SHOWNORMAL;
-  }
-
-  /* Create main Window */
-  Globals.hMainWnd =
-    CreateWindowW(STRING_MAIN_WIN_CLASS_NAME, NULL,
-                 WS_OVERLAPPEDWINDOW, left, top, width, height,
-                 0, 0, Globals.hInstance, 0);
-
-  ShowWindow (Globals.hMainWnd, show);
-  UpdateWindow (Globals.hMainWnd);
+    INT left, top, right, bottom;
+    INT width, height;
+    INT nCmdShow;
+    WCHAR buffer[100];
+
+    LONG lRet;
+    DWORD dwSize;
+    DWORD dwType;
+
+    Globals.hMDIWnd   = NULL;
+    Globals.hMainMenu = NULL;
+
+    /* Get the geometry of the main window */
+    dwSize = sizeof(buffer);
+    lRet = RegQueryValueExW(Globals.hKeyPMSettings, L"Window", NULL, &dwType, (LPBYTE)buffer, &dwSize);
+    if (lRet != ERROR_SUCCESS || dwType != REG_SZ)
+        buffer[0] = '\0';
+
+    if (swscanf(buffer, L"%d %d %d %d %d", &left, &top, &right, &bottom, &nCmdShow) == 5)
+    {
+        width  = right  - left;
+        height = bottom - top;
+    }
+    else
+    {
+        left = top = width = height = CW_USEDEFAULT;
+        nCmdShow = SW_SHOWNORMAL;
+    }
+
+    /* Create the main window */
+    Globals.hMainWnd =
+        CreateWindowW(STRING_MAIN_WIN_CLASS_NAME,
+                      szTitle,
+                      WS_OVERLAPPEDWINDOW, // /* | WS_CLIPSIBLINGS | WS_CLIPCHILDREN */
+                      left, top, width, height,
+                      NULL, NULL,
+                      Globals.hInstance,
+                      NULL);
+
+    MAIN_SetMainWindowTitle();
+    ShowWindow(Globals.hMainWnd, nCmdShow);
+    UpdateWindow(Globals.hMainWnd);
 }
 
 /***********************************************************************
@@ -406,27 +1124,30 @@ static VOID MAIN_CreateMainWindow(void)
  *           MAIN_CreateMDIWindow
  */
 
-static VOID MAIN_CreateMDIWindow(void)
+static VOID MAIN_CreateMDIWindow(VOID)
 {
-  CLIENTCREATESTRUCT ccs;
-  RECT rect;
+    CLIENTCREATESTRUCT ccs;
+    RECT rect;
+
+    /* Get the geometry of the MDI window */
+    GetClientRect(Globals.hMainWnd, &rect);
 
-  /* Get the geometry of the MDI window */
-  GetClientRect(Globals.hMainWnd, &rect);
+    ccs.hWindowMenu  = Globals.hWindowsMenu;
+    ccs.idFirstChild = PM_FIRST_CHILD;
 
-  ccs.hWindowMenu  = Globals.hWindowsMenu;
-  ccs.idFirstChild = PM_FIRST_CHILD;
+    /* Create MDI Window */
+    Globals.hMDIWnd =
+        CreateWindowW(WC_MDICLIENT, NULL, WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL, // WS_CHILDWINDOW | ...
+                      rect.left, rect.top,
+                      rect.right - rect.left, rect.bottom - rect.top,
+                      Globals.hMainWnd, 0,
+                      Globals.hInstance, &ccs);
 
-  /* Create MDI Window */
-  Globals.hMDIWnd =
-    CreateWindowW(STRING_MDI_WIN_CLASS_NAME, NULL,
-                 WS_CHILD, rect.left, rect.top,
-                 rect.right - rect.left, rect.bottom - rect.top,
-                 Globals.hMainWnd, 0,
-                 Globals.hInstance, &ccs);
+    /* Reset the background of the MDI client window (default: COLOR_APPWORKSPACE + 1) */
+    SetClassLongPtrW(Globals.hMDIWnd, GCLP_HBRBACKGROUND, (COLOR_WINDOW + 1));
 
-  ShowWindow (Globals.hMDIWnd, SW_SHOW);
-  UpdateWindow (Globals.hMDIWnd);
+    ShowWindow(Globals.hMDIWnd, SW_SHOW);
+    UpdateWindow(Globals.hMDIWnd);
 }
 
 /**********************************************************************/
@@ -436,30 +1157,30 @@ static VOID MAIN_CreateMDIWindow(void)
  */
 INT MAIN_MessageBoxIDS(UINT ids_text, UINT ids_title, WORD type)
 {
-  CHAR text[MAX_STRING_LEN];
-  CHAR title[MAX_STRING_LEN];
+    WCHAR text[MAX_STRING_LEN];
+    WCHAR title[MAX_STRING_LEN];
 
-  LoadStringA(Globals.hInstance, ids_text, text, sizeof(text));
-  LoadStringA(Globals.hInstance, ids_title, title, sizeof(title));
+    LoadStringW(Globals.hInstance, ids_text , text , ARRAYSIZE(text));
+    LoadStringW(Globals.hInstance, ids_title, title, ARRAYSIZE(title));
 
-  return(MessageBoxA(Globals.hMainWnd, text, title, type));
+    return MessageBoxW(Globals.hMainWnd, text, title, type);
 }
 
 /***********************************************************************
  *
  *           MAIN_MessageBoxIDS_s
  */
-INT MAIN_MessageBoxIDS_s(UINT ids_text, LPCSTR str, UINT ids_title, WORD type)
+INT MAIN_MessageBoxIDS_s(UINT ids_text, LPCWSTR str, UINT ids_title, WORD type)
 {
-  CHAR text[MAX_STRING_LEN];
-  CHAR title[MAX_STRING_LEN];
-  CHAR newtext[MAX_STRING_LEN + MAX_PATHNAME_LEN];
+    WCHAR text[MAX_STRING_LEN];
+    WCHAR title[MAX_STRING_LEN];
+    WCHAR newtext[MAX_STRING_LEN + MAX_PATHNAME_LEN];
 
-  LoadStringA(Globals.hInstance, ids_text, text, sizeof(text));
-  LoadStringA(Globals.hInstance, ids_title, title, sizeof(title));
-  wsprintfA(newtext, text, str);
+    LoadStringW(Globals.hInstance, ids_text , text , ARRAYSIZE(text));
+    LoadStringW(Globals.hInstance, ids_title, title, ARRAYSIZE(title));
+    wsprintfW(newtext, text, str);
 
-  return(MessageBoxA(Globals.hMainWnd, newtext, title, type));
+    return MessageBoxW(Globals.hMainWnd, newtext, title, type);
 }
 
 /***********************************************************************
@@ -467,15 +1188,18 @@ INT MAIN_MessageBoxIDS_s(UINT ids_text, LPCSTR str, UINT ids_title, WORD type)
  *           MAIN_ReplaceString
  */
 
-VOID MAIN_ReplaceString(HLOCAL *handle, LPSTR replace)
+VOID MAIN_ReplaceString(LPWSTR* string, LPWSTR replace)
 {
-  HLOCAL newhandle = LocalAlloc(LMEM_FIXED, strlen(replace) + 1);
-  if (newhandle)
+    LPWSTR newstring;
+
+    newstring = Alloc(HEAP_ZERO_MEMORY, (wcslen(replace) + 1) * sizeof(WCHAR));
+    if (newstring)
+    {
+        wcscpy(newstring, replace);
+        *string = newstring;
+    }
+    else
     {
-      LPSTR  newstring = LocalLock(newhandle);
-      strcpy(newstring, replace);
-      LocalFree(*handle);
-      *handle = newhandle;
+        MAIN_MessageBoxIDS(IDS_OUT_OF_MEMORY, IDS_ERROR, MB_OK);
     }
-  else MAIN_MessageBoxIDS(IDS_OUT_OF_MEMORY, IDS_ERROR, MB_OK);
 }