reactos/base/shell/progman/main.c

1207 lines
35 KiB
C

/*
* Program Manager
*
* Copyright 1996 Ulrich Schmid
* Copyright 2002 Sylvain Petreolle
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* 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_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);
#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)
{
StringCbPrintfW(caption, size, 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);
StringCbPrintfW(buffer, sizeof(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;
}
/***********************************************************************
*
* WinMain
*/
INT WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, INT nCmdShow)
{
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;
}
/* 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();
/* Load all the groups */
// MAIN_CreateGroups();
MAIN_LoadGroups();
/* Load the Startup group: start the initial applications */
MAIN_AutoStart();
/* Message loop */
while (GetMessageW(&msg, NULL, 0, 0))
{
if (!TranslateMDISysAccel(Globals.hMDIWnd, &msg) &&
!TranslateAcceleratorW(Globals.hMainWnd, Globals.hAccel, &msg))
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
}
Quit:
/* Save the settings, close the registry keys and quit */
// 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);
return 0;
}
/***********************************************************************
*
* MAIN_CreateGroups
*/
#if 0
static VOID MAIN_CreateGroups(VOID)
{
CHAR buffer[BUFFER_SIZE];
CHAR szPath[MAX_PATHNAME_LEN];
CHAR key[20], *ptr;
/* Initialize groups according the `Order' entry of `progman.ini' */
GetPrivateProfileStringA("Settings", "Order", "", buffer, sizeof(buffer), Globals.lpszIniFile);
ptr = buffer;
while (ptr < buffer + sizeof(buffer))
{
int num, skip, ret;
ret = sscanf(ptr, "%d%n", &num, &skip);
if (ret == 0)
MAIN_MessageBoxIDS_s(IDS_FILE_READ_ERROR_s, Globals.lpszIniFile, IDS_ERROR, MB_OK);
if (ret != 1) break;
sprintf(key, "Group%d", num);
GetPrivateProfileStringA("Groups", key, "", szPath,
sizeof(szPath), Globals.lpszIniFile);
if (!szPath[0]) continue;
GRPFILE_ReadGroupFile(szPath);
ptr += skip;
}
/* FIXME initialize other groups, not enumerated by `Order' */
}
#endif
static VOID MAIN_LoadGroups(VOID)
{
}
/***********************************************************************
*
* MAIN_AutoStart
*/
static VOID MAIN_AutoStart(VOID)
{
LONG lRet;
DWORD dwSize;
DWORD dwType;
PROGGROUP* hGroup;
PROGRAM* hProgram;
WCHAR buffer[BUFFER_SIZE];
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);
}
}
}
/***********************************************************************
*
* MAIN_MainWndProc
*/
static LRESULT CALLBACK MAIN_MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
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, uMsg, wParam, lParam);
}
/***********************************************************************
*
* MAIN_MenuCommand
*/
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);
switch(wParam)
{
/* Menu File */
case PM_NEW:
switch (DIALOG_New((hActiveGroupWnd && !IsIconic(hActiveGroupWnd)) ?
PM_NEW_PROGRAM : PM_NEW_GROUP))
{
case PM_NEW_PROGRAM:
if (hActiveGroup) PROGRAM_NewProgram(hActiveGroup);
break;
case PM_NEW_GROUP:
GROUP_NewGroup();
break;
}
break;
case PM_DELETE:
if (hActiveProgram)
{
if (DIALOG_Delete(IDS_DELETE_PROGRAM_s, PROGRAM_ProgramName(hActiveProgram)))
PROGRAM_DeleteProgram(hActiveProgram, TRUE);
}
else if (hActiveGroup)
{
if (DIALOG_Delete(IDS_DELETE_GROUP_s, GROUP_GroupName(hActiveGroup)))
GROUP_DeleteGroup(hActiveGroup);
}
break;
case PM_SAVE_SETTINGS:
Globals.bSaveSettings = !Globals.bSaveSettings;
CheckMenuItem(Globals.hOptionMenu, PM_SAVE_SETTINGS,
MF_BYCOMMAND | (Globals.bSaveSettings ?
MF_CHECKED : MF_UNCHECKED));
WritePrivateProfileStringA("Settings", "SaveSettings",
Globals.bSaveSettings ? "1" : "0",
Globals.lpszIniFile);
WritePrivateProfileStringA(NULL,NULL,NULL,Globals.lpszIniFile); /* flush it */
break;
case PM_ARRANGE:
if (hActiveGroupWnd && !IsIconic(hActiveGroupWnd))
ArrangeIconicWindows(hActiveGroupWnd);
else
SendMessageW(Globals.hMDIWnd, WM_MDIICONARRANGE, 0, 0);
break;
}
#endif
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;
}
}
/***********************************************************************
*
* MAIN_RegisterMainWinClass
*/
static ATOM MAIN_RegisterMainWinClass(VOID)
{
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);
}
/***********************************************************************
*
* MAIN_CreateMainWindow
*/
static VOID MAIN_CreateMainWindow(VOID)
{
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);
}
/***********************************************************************
*
* MAIN_CreateMDIWindow
*/
static VOID MAIN_CreateMDIWindow(VOID)
{
CLIENTCREATESTRUCT ccs;
RECT rect;
/* Get the geometry of the MDI window */
GetClientRect(Globals.hMainWnd, &rect);
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);
/* 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);
}
/**********************************************************************/
/***********************************************************************
*
* MAIN_MessageBoxIDS
*/
INT MAIN_MessageBoxIDS(UINT ids_text, UINT ids_title, WORD type)
{
WCHAR text[MAX_STRING_LEN];
WCHAR title[MAX_STRING_LEN];
LoadStringW(Globals.hInstance, ids_text , text , ARRAYSIZE(text));
LoadStringW(Globals.hInstance, ids_title, title, ARRAYSIZE(title));
return MessageBoxW(Globals.hMainWnd, text, title, type);
}
/***********************************************************************
*
* MAIN_MessageBoxIDS_s
*/
INT MAIN_MessageBoxIDS_s(UINT ids_text, LPCWSTR str, UINT ids_title, WORD type)
{
WCHAR text[MAX_STRING_LEN];
WCHAR title[MAX_STRING_LEN];
WCHAR newtext[MAX_STRING_LEN + MAX_PATHNAME_LEN];
LoadStringW(Globals.hInstance, ids_text , text , ARRAYSIZE(text));
LoadStringW(Globals.hInstance, ids_title, title, ARRAYSIZE(title));
wsprintfW(newtext, text, str);
return MessageBoxW(Globals.hMainWnd, newtext, title, type);
}
/***********************************************************************
*
* MAIN_ReplaceString
*/
VOID MAIN_ReplaceString(LPWSTR* string, LPWSTR replace)
{
LPWSTR newstring;
newstring = Alloc(HEAP_ZERO_MEMORY, (wcslen(replace) + 1) * sizeof(WCHAR));
if (newstring)
{
wcscpy(newstring, replace);
*string = newstring;
}
else
{
MAIN_MessageBoxIDS(IDS_OUT_OF_MEMORY, IDS_ERROR, MB_OK);
}
}