Windows2000/private/windows/shell/progman/pminit.c
2020-09-30 17:12:32 +02:00

2063 lines
54 KiB
C

/*
* pminit.c - program manager
* Copyright (c) 1991, Microsoft Corporation
* DESCRIPTION
* This file is for support of program manager under NT Windows.
* This file is/was ported from pminit.c (program manager).
* MODIFICATION HISTORY
* Initial Version: x/x/90 Author Unknown, since he didn't feel
* like commenting the code...
* NT 32b Version: 1/25/91 Jeff Pack
* Intitial port to begin.
*/
#include "progman.h"
#include "util.h"
#include "commdlg.h"
#include <winuserp.h>
//#ifdef FE_IME
#include "winnls32.h"
//#endif
#include "uniconv.h"
#include "security.h"
#define MAX_USERNAME_LENGTH 256
#define PROGMAN_KEY L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Program Manager"
#define WINDOWS_KEY L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows"
//#define MYDEBUG 1
SECURITY_ATTRIBUTES SecurityAttributes;
SECURITY_ATTRIBUTES AdminSecAttr; // security attributes for common groups
BOOL bInitialArrange;
BOOL bInNtSetup;
TCHAR szProgramGroups [] = TEXT("UNICODE Program Groups"); // registry key for groups
TCHAR szRestrict [] = TEXT("Restrictions");
TCHAR szNoRun [] = TEXT("NoRun");
TCHAR szNoClose [] = TEXT("NoClose");
TCHAR szEditLevel [] = TEXT("EditLevel");
TCHAR szNoFileMenu [] = TEXT("NoFileMenu");
TCHAR szNoSave [] = TEXT("NoSaveSettings");
TCHAR szShowCommonGroups [] = TEXT("ShowCommonGroups");
TCHAR szSettings [] = TEXT("Settings");
TCHAR szGroups [] = TEXT("UNICODE Groups");
TCHAR szAnsiGroups [] = TEXT("Groups");
TCHAR szCommonGroups [] = TEXT("Common Groups");
TCHAR szSystemBoot [] = TEXT("Boot");
TCHAR szSystemDisplay [] = TEXT("display.drv");
TCHAR szDefPrograms [] = TEXT("EXE COM BAT PIF");
TCHAR szSystemIni [] = TEXT("system.ini");
TCHAR szWindows [] = TEXT("Windows");
TCHAR szCheckBinaryType [] = TEXT("CheckBinaryType");
TCHAR szCheckBinaryTimeout [] = TEXT("CheckBinaryTimeout");
TCHAR szMigrateAnsi [] = TEXT("Migrate ANSI");
BOOL bDisableDDE = FALSE;
/* in hotkey.c */
BOOL APIENTRY RegisterHotKeyClass(HANDLE hInstance);
/* in pmgseg.c */
HWND NEAR PASCAL IsGroupAlreadyLoaded(LPTSTR lpGroupKey, BOOL bCommonGroup);
/*
* A fixed buffer case and space insensative compare...
* Returns true if they compare the same.
*/
BOOL NEAR PASCAL StartupCmp(LPTSTR szSrc1, LPTSTR szSrc2)
{
TCHAR sz1[MAXGROUPNAMELEN + 1];
TCHAR sz2[MAXMESSAGELEN + 1];
LPTSTR lp1, lp2;
lstrcpy(sz1, szSrc1);
CharUpper(sz1);
lstrcpy(sz2, szSrc2);
CharUpper(sz2);
lp1 = sz1;
lp2 = sz2;
for (;;)
{
while (*lp1 == TEXT(' '))
lp1++;
while (*lp2 == TEXT(' '))
lp2++;
if (*lp1 != *lp2)
return FALSE;
if (!*lp1)
break;
while (*lp1 == *lp2 && *lp1)
lp1++, lp2++;
}
return TRUE;
}
/*
* Handles finding and execing the items in the startup group.
*/
VOID NEAR PASCAL HandleStartupGroup(int nCmdShow)
{
TCHAR szGroupTitle[MAXGROUPNAMELEN + 1];
HWND hwndT;
DWORD cbData = sizeof(TCHAR)*(MAXGROUPNAMELEN + 1);
PGROUP pGroup;
LPGROUPDEF lpgd;
TCHAR szCommonStartupGroup[MAXGROUPNAMELEN + 1];
TCHAR szDefaultStartup[MAXGROUPNAMELEN + 1] = TEXT("startup");
TCHAR szStartupKana [] = TEXT("^?X^?^^?[^?g^?A^?b^?v");
if (nCmdShow != SW_SHOWMINNOACTIVE)
{
// Daytona security weenies decreed that GetAsyncKeyState only work
// if threads window is foreground, so make it so.
hwndT = GetForegroundWindow();
if (hwndProgman != hwndT)
SetForegroundWindow(hwndProgman);
if (GetAsyncKeyState(VK_SHIFT) < 0) // SHIFT will cancel the startup group
return;
}
// The Default startup group name is "Startup", for personal and common
// groups.
LoadString(hAppInstance, IDS_DEFAULTSTARTUP, szDefaultStartup, CharSizeOf(szDefaultStartup));
lstrcpy(szGroupTitle, szDefaultStartup);
lstrcpy(szCommonStartupGroup, szDefaultStartup);
// Get the Personal startup group name.
if (hkeyPMSettings)
{
if (RegQueryValueEx(hkeyPMSettings, szStartup, 0, 0, (LPBYTE) szGroupTitle, &cbData) != ERROR_SUCCESS)
{
lstrcpy(szGroupTitle, szDefaultStartup);
}
}
// Search for the startup group.
hwndT = GetWindow(hwndMDIClient, GW_CHILD);
while (hwndT)
{
// Skip icon titles.
if (!GetWindow(hwndT, GW_OWNER))
{
/* Compare the group name with the startup. */
pGroup = (PGROUP) GetWindowLongPtr(hwndT, GWLP_PGROUP);
if (lpgd = (LPGROUPDEF) GlobalLock(pGroup->hGroup))
{
// ToddB: We want to check for three things here:
// 1.) A common group with the name szCommonStartupGroup
// 2.) Any group with the name szGroupTitle (which is a copy of szDefaultStartup)
// 3.) If we are in Japan then we also search for two hardcoded strings,
// szStartupKana AND szStartup. I think this special Japanese
// check is a bug and should be removed.
if (pGroup->fCommon)
{
if (StartupCmp(szCommonStartupGroup, (LPTSTR) PTR(lpgd, lpgd->pName)))
StartupGroup(hwndT);
}
else if (StartupCmp(szGroupTitle, (LPTSTR) PTR(lpgd, lpgd->pName)))
{
StartupGroup(hwndT);
}
#ifdef JAPAN_HACK_WHICH_TODDB_THINKS_IS_A_BUG
else if (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) == LANG_JAPANESE)
{
if (StartupCmp(szStartupKana, (LPTSTR) PTR(lpgd, lpgd->pName)) || // search for hardcoded localized startup
StartupCmp(szStartup, (LPTSTR) PTR(lpgd, lpgd->pName))) // search for hardcoded non-localized "startup"
{
StartupGroup(hwndT);
}
}
#endif
GlobalUnlock(pGroup->hGroup);
}
}
hwndT = GetWindow(hwndT, GW_HWNDNEXT);
}
}
/** BoilThatDustSpec -- strips string to program name
* VOID APIENTRY BoilThatDustSpec(PSTR pStart, BOOL bLoadIt)
* ENTRY - PSTR pStart - Program to exec, and possible parameters
* BOOL LoadIt -
* EXIT - VOID
* SYNOPSIS - strips everything after program name, then exec's program.
* WARNINGS -
* EFFECTS -
*/
VOID APIENTRY BoilThatDustSpec(LPTSTR pStart, BOOL bLoadIt)
{
register LPTSTR pEnd;
WORD ret;
BOOL bFinished;
TCHAR szText[MAXMESSAGELEN + 1];
TCHAR szExtra[MAXMESSAGELEN + 1];
TCHAR szFilename[MAXITEMPATHLEN + 1];
TCHAR szWindowsDirectory2[MAXITEMPATHLEN + 1];
if (*pStart == TEXT('\0'))
{ /*test for null string*/
return;
}
// Used to massage any errors.
LoadString(hAppInstance, IDS_WININIERR, szExtra, CharSizeOf(szExtra));
// skip first spaces
while (*pStart == ' ')
{
pStart = CharNext(pStart);
}
bFinished = !*pStart;
GetWindowsDirectory(szWindowsDirectory2, CharSizeOf(szWindowsDirectory2));
while (!bFinished)
{
pEnd = pStart;
/* strip anything after execprogram name*/
while ((*pEnd) && (*pEnd != TEXT(' ')) && (*pEnd != TEXT(',')))
{
pEnd = CharNext(pEnd);
}
if (*pEnd == TEXT('\0'))
bFinished = TRUE;
else
*pEnd = TEXT('\0');
if (!*pStart)
{
pStart = pEnd + 1;
continue;
}
if (GetFreeSpace(GMEM_NOT_BANKED) < 65535L)
break;
GetDirectoryFromPath(pStart, szDirField);
// Load and Run lines are done relative to windows directory.
SetCurrentDirectory(szWindowsDirectory2);
GetFilenameFromPath(pStart, szFilename);
ret = ExecProgram(szFilename, szDirField, NULL, bLoadIt, 0, 0, 0);
if (ret)
{
// Insert a phrase mentioning win.ini after the file name.
szText[0] = TEXT('\'');
lstrcpy(&szText[1], pStart);
lstrcat(szText, szExtra);
MyMessageBox(NULL, IDS_APPTITLE, ret, szText, MB_OK | MB_ICONEXCLAMATION | MB_SYSTEMMODAL);
}
pStart = pEnd + 1;
}
SetCurrentDirectory(szWindowsDirectory); // in fact system32 directory
}
/** DoRunEquals --
* VOID APIENTRY DoRunEquals(PINT pnCmdShow)
* ENTRY - PINT pnCmdShow - point to cmdshow
* EXIT - VOID
* SYNOPSIS - ???
* WARNINGS -
* EFFECTS -
*/
VOID APIENTRY DoRunEquals(PINT pnCmdShow)
{
TCHAR szBuffer[MAX_PATH];
DWORD dwType;
DWORD cbData;
HKEY hkeyWindows;
/* "Load" apps before "Run"ning any. */
if (RegOpenKeyEx(HKEY_CURRENT_USER, WINDOWS_KEY, 0, KEY_READ, &hkeyWindows) != ERROR_SUCCESS)
{
return;
}
*szBuffer = 0;
cbData = sizeof(szBuffer);
RegQueryValueEx(hkeyWindows, L"Load", 0, &dwType, (LPBYTE) szBuffer, &cbData);
if (*szBuffer)
BoilThatDustSpec(szBuffer, TRUE);
*szBuffer = 0;
cbData = sizeof(szBuffer);
RegQueryValueEx(hkeyWindows, L"Run", 0, &dwType, (LPBYTE) szBuffer, &cbData);
if (*szBuffer)
{
BoilThatDustSpec(szBuffer, FALSE);
*pnCmdShow = SW_SHOWMINNOACTIVE;
}
RegCloseKey(hkeyWindows);
}
/** GetSettings --
* PSTR APIENTRY GetSettings(VOID)
* ENTRY - VOID
* EXIT - PSTR - if NULL then error.
* SYNOPSIS - ??
* WARNINGS -
* EFFECTS -
*/
LPTSTR APIENTRY GetSettings()
{
LPTSTR pszT;
TCHAR szGroups[32];
TCHAR szAppTitle[MAXKEYLEN + 1];
DWORD cbData;
DWORD dwType;
DWORD rc;
DWORD dwBinaryInfo;
#define SETTING_SIZE 160
/* Get the flags out of the INI file. */
LoadString(hAppInstance, IDS_GROUPS, szGroups, CharSizeOf(szGroups));
LoadString(hAppInstance, IDS_APPTITLE, szAppTitle, CharSizeOf(szAppTitle));
/*
* Use direct registry call.
*/
if (hkeyPMSettings)
{
cbData = sizeof(bMinOnRun);
RegQueryValueEx(hkeyPMSettings, szMinOnRun, 0, &dwType, (LPBYTE) &bMinOnRun, &cbData);
cbData = sizeof(bAutoArrange);
RegQueryValueEx(hkeyPMSettings, szAutoArrange, 0, &dwType, (LPBYTE) &bAutoArrange, &cbData);
cbData = sizeof(bSaveSettings);
RegQueryValueEx(hkeyPMSettings, szSaveSettings, 0, &dwType, (LPBYTE) &bSaveSettings, &cbData);
cbData = sizeof(bInitialArrange);
bInitialArrange = FALSE;
rc = RegQueryValueEx(hkeyPMSettings, TEXT("InitialArrange"), 0, &dwType, (LPBYTE) &bInitialArrange, &cbData);
if (bInitialArrange)
{
RegDeleteValue(hkeyPMSettings, TEXT("InitialArrange"));
}
// Check if the binary type checking information exists. If not, add it.
// First check for the enabled / disabled entry.
cbData = sizeof(dwBinaryInfo);
if (RegQueryValueEx(hkeyPMSettings, szCheckBinaryType, 0, &dwType, (LPBYTE) &dwBinaryInfo, &cbData) == ERROR_FILE_NOT_FOUND)
{
// Key doesn't exist, so create the default case.
dwBinaryInfo = BINARY_TYPE_DEFAULT;
RegSetValueEx(hkeyPMSettings, szCheckBinaryType, 0, REG_DWORD, (LPBYTE) &dwBinaryInfo, cbData);
}
// Now check for the timeout value. This is the number of milliseconds
// of delay after the lastkeystroke and before the background thread
// is signaled to check the type.
cbData = sizeof(dwBinaryInfo);
if (RegQueryValueEx(hkeyPMSettings, szCheckBinaryTimeout, 0, &dwType, (LPBYTE) &dwBinaryInfo, &cbData) == ERROR_FILE_NOT_FOUND)
{
// Key doesn't exist, so create the default case.
dwBinaryInfo = BINARY_TIMEOUT_DEFAULT;
RegSetValueEx(hkeyPMSettings, szCheckBinaryTimeout, 0, REG_DWORD, (LPBYTE) &dwBinaryInfo, cbData);
}
}
if (hkeyPMRestrict && !UserIsAdmin)
{
cbData = sizeof(fNoRun);
RegQueryValueEx(hkeyPMRestrict, szNoRun, 0, &dwType, (LPBYTE) &fNoRun, &cbData);
cbData = sizeof(fNoClose);
RegQueryValueEx(hkeyPMRestrict, szNoClose, 0, &dwType, (LPBYTE) &fNoClose, &cbData);
cbData = sizeof(fNoSave);
RegQueryValueEx(hkeyPMRestrict, szNoSave, 0, &dwType, (LPBYTE) &fNoSave, &cbData);
cbData = sizeof(dwEditLevel);
RegQueryValueEx(hkeyPMRestrict, szEditLevel, 0, &dwType, (LPBYTE) &dwEditLevel, &cbData);
}
pszT = (LPTSTR) LocalAlloc(LPTR, SETTING_SIZE);
if (!pszT)
return(NULL);
/*
* Use direct registry call.
*/
if (hkeyPMSettings)
{
cbData = SETTING_SIZE;
if (RegQueryValueEx(hkeyPMSettings, szWindow, 0, &dwType, (LPBYTE) pszT, &cbData))
{
LocalFree((HANDLE) pszT);
return NULL;
}
}
else
{
return(NULL);
}
return pszT;
}
//#if 0
BOOL GetUserAndDomainName(LPTSTR lpBuffer, DWORD cb)
{
HANDLE hToken;
DWORD cbTokenBuffer = 0;
PTOKEN_USER pUserToken;
LPTSTR lpUserName = NULL;
LPTSTR lpUserDomain = NULL;
DWORD cbAccountName = 0;
DWORD cbUserDomain = 0;
SID_NAME_USE SidNameUse;
if (!OpenProcessToken(GetCurrentProcess(),
TOKEN_QUERY,
&hToken))
{
return(FALSE);
}
// Get space needed for token information
if (!GetTokenInformation(hToken,
TokenUser,
NULL,
0,
&cbTokenBuffer))
{
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
{
return(FALSE);
}
}
// Get the actual token information
pUserToken = (PTOKEN_USER) Alloc(cbTokenBuffer);
if (pUserToken == NULL)
{
return(FALSE);
}
if (!GetTokenInformation(hToken,
TokenUser,
pUserToken,
cbTokenBuffer,
&cbTokenBuffer))
{
Free(pUserToken);
return(FALSE);
}
// Get the space needed for the User name and the Domain name
if (!LookupAccountSid(NULL, pUserToken->User.Sid, NULL, &cbAccountName, NULL, &cbUserDomain, &SidNameUse))
{
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
{
Free(pUserToken);
return(FALSE);
}
}
lpUserName = (LPTSTR) LocalAlloc(LPTR, sizeof(TCHAR)*(cbAccountName + 1));
if (!lpUserName)
{
Free(pUserToken);
return(FALSE);
}
lpUserDomain = (LPTSTR) LocalAlloc(LPTR, sizeof(TCHAR)*(1 + cbUserDomain));
if (!lpUserDomain)
{
LocalFree(lpUserName);
Free(pUserToken);
return(FALSE);
}
// Now get the user name and domain name
if (!LookupAccountSid(NULL, pUserToken->User.Sid, lpUserName, &cbAccountName, lpUserDomain, &cbUserDomain, &SidNameUse))
{
LocalFree(lpUserName);
LocalFree(lpUserDomain);
Free(pUserToken);
return(FALSE);
}
if (*lpUserName &&
((int)sizeof(TCHAR)*(lstrlen(lpBuffer) + lstrlen(lpUserName) + lstrlen(lpUserDomain)) < (int) (cb + 4)))
{
lstrcat(lpBuffer, TEXT(" - "));
lstrcat(lpBuffer, lpUserDomain);
lstrcat(lpBuffer, TEXT("\\"));
lstrcat(lpBuffer, lpUserName);
}
Free(pUserToken);
LocalFree(lpUserName);
LocalFree(lpUserDomain);
return(TRUE);
}
//#endif
/** CreateFrameWindow --
* HWND APIENTRY CreateFrameWindow(register PRECT prc, WORD nCmdShow)
* ENTRY - PRECT prc -
* WORD nCmdShow -
* EXIT - HWND - (NULL = Error)
* SYNOPSIS - ??
* WARNINGS -
* EFFECTS -
*/
HWND APIENTRY CreateFrameWindow(register PRECT prc, WORD nCmdShow)
{
HDC hdc;
HBRUSH hbr;
HMENU hMenu;
HMENU hSystemMenu;
TCHAR szBuffer[40 + MAX_USERNAME_LENGTH];
TCHAR szProgmanClass[16];
TCHAR szUserName[MAX_USERNAME_LENGTH + 1] = TEXT("");
TCHAR szUserDomain[MAX_USERNAME_LENGTH + 1] = TEXT("");
DWORD dwType, cbData;
/* Create the Desktop Manager window. */
LoadString(hAppInstance, IDS_APPTITLE, szBuffer, CharSizeOf(szBuffer));
LoadString(hAppInstance, IDS_PMCLASS, szProgmanClass, CharSizeOf(szProgmanClass));
#if 1
GetUserAndDomainName(szBuffer, sizeof(szBuffer));
#else
cbData = CharSizeOf(szUserName);
GetUserName(szUserName, &cbData);
cbData = CharSizeOf(szUserDomain);
GetEnvironmentVariable(TEXT("USERDOMAIN"), szUserDomain, cbData);
if (*szUserName)
{
lstrcat(szBuffer, TEXT(" - "));
lstrcat(szBuffer, szUserDomain);
lstrcat(szBuffer, TEXT("\\"));
lstrcat(szBuffer, szUserName);
}
#endif
hwndProgman = CreateWindow(szProgmanClass,
szBuffer,
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
prc->left, prc->top,
prc->right - prc->left,
prc->bottom - prc->top,
NULL, /* No Parent */
NULL, /* Use Class Menu */
hAppInstance,
NULL);
if (!hwndProgman)
return NULL;
SetWindowLong(hwndProgman, GWL_EXITING, 0);
hMenu = GetMenu(hwndProgman);
hSystemMenu = GetSystemMenu(hwndProgman, FALSE);
if (!bExitWindows)
{
LoadString(hAppInstance, IDS_EXIT, szBuffer, CharSizeOf(szBuffer));
ModifyMenu(hMenu, IDM_EXIT, MF_BYCOMMAND | MF_STRING, IDM_EXIT, szBuffer);
DeleteMenu(hMenu, IDM_SHUTDOWN, MF_BYCOMMAND);
}
else
{
// replace Close menu item with Logoff and Shutdown
LoadString(hAppInstance, IDS_LOGOFF, szBuffer, CharSizeOf(szBuffer));
InsertMenu(hSystemMenu, SC_CLOSE, MF_BYCOMMAND | MF_STRING, SC_CLOSE, szBuffer);
LoadString(hAppInstance, IDS_SHUTDOWN, szBuffer, CharSizeOf(szBuffer));
ModifyMenu(hSystemMenu, SC_CLOSE, MF_BYCOMMAND | MF_STRING, IDM_SHUTDOWN, szBuffer);
}
if (hkeyPMRestrict && !UserIsAdmin)
{
cbData = sizeof(fNoFileMenu);
RegQueryValueEx(hkeyPMRestrict, szNoFileMenu, 0, &dwType, (LPBYTE) &fNoFileMenu, &cbData);
}
if (fNoFileMenu)
{
DeleteMenu(hMenu, IDM_FILE, MF_BYPOSITION);
}
if (fNoSave)
{
bSaveSettings = FALSE;
EnableMenuItem(hMenu, IDM_SAVESETTINGS, MF_BYCOMMAND | MF_GRAYED | MF_DISABLED);
EnableMenuItem(hMenu, IDM_SAVENOW, MF_BYCOMMAND | MF_GRAYED | MF_DISABLED);
}
/* Update the menu items here (no maximized kids to deal with). */
if (bMinOnRun)
CheckMenuItem(hMenu, IDM_MINONRUN, MF_CHECKED);
if (bAutoArrange)
CheckMenuItem(hMenu, IDM_AUTOARRANGE, MF_CHECKED);
if (bSaveSettings)
CheckMenuItem(hMenu, IDM_SAVESETTINGS, MF_CHECKED);
if (bInNtSetup)
{
EnableWindow(hwndProgman, FALSE);
}
ShowWindow(hwndProgman, nCmdShow);
UpdateWindow(hwndProgman);
/* fake-paint the client area with the color of the MDI client so users
* have something pleasent to stare at while we hit the disk for the
* group files
*/
hdc = GetDC(hwndProgman);
GetClientRect(hwndProgman, prc);
hbr = CreateSolidBrush(GetSysColor(COLOR_APPWORKSPACE));
if (hbr)
{
FillRect(hdc, prc, hbr);
DeleteObject(hbr);
}
ReleaseDC(hwndProgman, hdc);
return hwndProgman;
}
/** IsGroup --
* BOOL APIENTRY IsGroup(PSTR p)
* ENTRY - PSTR p -
* EXIT - BOOL - (FALSE == ERROR)
* SYNOPSIS - ??
* WARNINGS -
* EFFECTS -
*/
BOOL PASCAL IsGroup(LPTSTR p)
{
if (_wcsnicmp(p, TEXT("GROUP"), CCHGROUP) != 0)
{
return FALSE;
}
/*
* Can't have 0 for first digit
*/
if (p[5] == TEXT('0'))
{
return FALSE;
}
/*
* Everything else must be a number
*/
for (p += CCHGROUP; *p; p++)
{
if (*p != TEXT('C') && (*p < TEXT('0') || *p > TEXT('9')))
{
return FALSE;
}
}
return TRUE;
}
/** RemoveString --
* VOID APIENTRY RemoveString(PSTR pString)
* ENTRY - PSTR pString -
* EXIT - VOID
* SYNOPSIS - ??
* WARNINGS -
* EFFECTS -
*/
VOID APIENTRY RemoveString(LPTSTR pString)
{
LPTSTR pT = pString + lstrlen(pString) + 1;
while (*pT)
{
while (*pString++ = *pT++)
;
}
*pString = 0;
}
/** StringToEnd --
* VOID APIENTRY StringToEnd(PSTR pString)
* ENTRY - PSTR pString -
* EXIT - VOID
* SYNOPSIS - ??
* WARNINGS -
* EFFECTS -
*/
VOID PASCAL StringToEnd(LPTSTR pString)
{
TCHAR *pT, *pTT;
for (pT = pString; *pT;) //go to end of strings
while (*pT++)
;
for (pTT = pString; *pT++ = *pTT++;) // copy first string to the end
;
*pT = 0;
RemoveString(pString); // remove first string
}
/** GetGroupList --
* VOID APIENTRY GetGroupList(PSTR szList)
* ENTRY - PSTR szList -
* EXIT - VOID
* SYNOPSIS - ??
* WARNINGS -
* EFFECTS -
*/
VOID PASCAL GetGroupList(LPTSTR szList, HKEY hkeyPMGroups)
{
TCHAR szOrd[CGROUPSMAX * 8 + 7];
TCHAR szT[20];
LPTSTR pT, pTT, pS;
INT cGroups; // The number of Groups= lines.
LPTSTR lpList;
DWORD dwType;
DWORD dwIndex = 0;
DWORD cbValueName = 8;
DWORD cbData;
INT cbList = (CGROUPSMAX + 1) * 18;
LPTSTR lpOrder;
lpList = szList;
// Get the user's list of personal groups.
if (hkeyPMGroups)
{
cbValueName = cbList;
while (!RegEnumValue(hkeyPMGroups, dwIndex, lpList, &cbValueName, 0, 0,
0, 0))
{
dwIndex++; cbValueName++;
lpList += cbValueName;
cbList -= cbValueName;
cbValueName = cbList;
}
}
// Now get the user's list of common groups.
if (hkeyPMCommonGroups)
{
cbValueName = cbList;
dwIndex = 0;
while (!RegEnumValue(hkeyPMCommonGroups, dwIndex, lpList, &cbValueName, 0, 0,
0, 0))
{
dwIndex++; cbValueName++;
lpList += cbValueName;
cbList -= cbValueName;
cbValueName = cbList;
}
}
*lpList = TEXT('\0');
cbData = sizeof(szOrd);
if (bUseANSIGroups)
lpOrder = szAnsiOrder;
else
lpOrder = szOrder;
if (!hkeyPMSettings || RegQueryValueEx(hkeyPMSettings, lpOrder, 0, &dwType, (LPBYTE) szOrd, &cbData))
*szOrd = TEXT('\0');
cGroups = 0;
/*
* Filter out anything that isn't group#.
*/
for (pT = szList; *pT;)
{
CharUpper(pT);
if (IsGroup(pT))
{
pT += lstrlen(pT) + 1;
cGroups++;
}
else
{
RemoveString(pT);
}
}
/*
* Sort the groups
*/
lstrcpy(szT, TEXT("Group"));
for (pT = szOrd; *pT;)
{
while (*pT == TEXT(' '))
{
pT++;
}
if ((*pT == TEXT('C') && (*(pT + 1) < TEXT('0') || *(pT + 1) > TEXT('9'))) ||
(*pT != TEXT('C') && (*pT < TEXT('0') || *pT > TEXT('9'))))
{
break;
}
pTT = szT + CCHGROUP;
while (*pT == TEXT('C') || (*pT >= TEXT('0') && *pT <= TEXT('9')))
{
*pTT++ = *pT++;
}
*pTT = 0;
for (pS = szList; *pS; pS += lstrlen(pS) + 1)
{
if (!lstrcmpi(pS, szT))
{
StringToEnd(pS);
cGroups--;
break;
}
}
}
/*
* Move any remaining groups to the end of the list so that they load
* last and appear on top of everything else - keeps DOS based install
* programs happy.
* If bInitialArrange is set then the remaining groups come from the
* Windows 3.1 migration and we want these groups to be loaded before
* the remaining groups so they appear below the regular groups.
* 10-15-93 johannec
*/
if (!bInitialArrange)
{
while (cGroups > 0)
{
StringToEnd(szList);
cGroups--;
}
}
}
/** LoadCommonGroups --
* VOID APIENTRY LoadCommonGroups(LPTSTR)
* ENTRY - LPTSTR the key name of the common group that should have the focus.
* EXIT - HWND hwnd of the common group which should have the focus.
* SYNOPSIS -
* WARNINGS -
* EFFECTS -
*/
HWND LoadCommonGroups(LPTSTR lpFocusGroup)
{
int i = 0;
DWORD cbGroupKey = MAXKEYLEN;
TCHAR szGroupKey[MAXKEYLEN];
BOOL bRealArrange;
FILETIME ft;
HWND hwnd;
if (!hkeyCommonGroups)
{ // cannot access registry.
return(NULL);
}
/*
* Set global to note that we haven't run out of memory yet.
*/
fLowMemErrYet = FALSE;
/*
* Flag for extraction problems.
*/
fErrorOnExtract = FALSE;
// REVIEW - Why stop AutoArrange on load ? Switch it off for now.
bRealArrange = bAutoArrange;
// For mow, just load the groups in whatever order they are enumerated
// in the registry.
while (!RegEnumKeyEx(hkeyCommonGroups, i, szGroupKey, &cbGroupKey, 0, 0, 0, &ft))
{
if (cbGroupKey)
{
hwnd = LoadGroupWindow(szGroupKey, 0, TRUE);
}
cbGroupKey = sizeof(szGroupKey);
i++;
}
bAutoArrange = bRealArrange;
/*
* Check to see if there was any trouble.
*/
if (fErrorOnExtract)
{
/*
* On observed problem with icon extraction has been to do
* with a low memory.
*/
MyMessageBox(hwndProgman, IDS_OOMEXITTITLE, IDS_LOWMEMONEXTRACT,
NULL, MB_OK | MB_ICONHAND | MB_SYSTEMMODAL);
}
return(hwnd);
}
/** LoadAllGroups --
* VOID APIENTRY LoadAllGroups(VOID)
* ENTRY - VOID
* EXIT - VOID
* SYNOPSIS - ??
* WARNINGS -
* EFFECTS -
*/
VOID PASCAL LoadAllGroups()
{
LPTSTR pT, pszT;
TCHAR szGroupList[(CGROUPSMAX + 1) * 18];
WORD wIndex;
TCHAR szPath[120];
TCHAR szGroupKey[MAXKEYLEN];
BOOL bRealArrange;
DWORD cbData;
DWORD dwType;
BOOL fShowCommonGrps = TRUE;
HKEY hkeyPMAnsiGroups = NULL;
HKEY hkeyGroups;
TCHAR szCommonGrpInfo[MAXKEYLEN];
INT i;
BOOL bDefaultPosition = FALSE;
INT rgiPos[7];
HWND hwndGroup;
if (bUseANSIGroups)
{
RegCreateKeyEx(hkeyProgramManager, szAnsiGroups, 0, szProgman, 0, KEY_READ | KEY_WRITE, pSecurityAttributes, &hkeyPMAnsiGroups, NULL);
hkeyGroups = hkeyPMAnsiGroups;
}
else
{
hkeyGroups = hkeyPMGroups;
}
if (!hkeyGroups)
{ // cannot access registry.
return;
}
/*
* Set global to note that we haven't run out of memory yet.
*/
fLowMemErrYet = FALSE;
/*
* Flag for extraction problems.
*/
fErrorOnExtract = FALSE;
// REVIEW - Why stop AutoArrange on load ? Switch it off for now.
bRealArrange = bAutoArrange;
// If the user is allowed to see the common program groups, load them.
if (hkeyPMRestrict)
{
cbData = sizeof(fShowCommonGrps);
RegQueryValueEx(hkeyPMRestrict, szShowCommonGroups, 0, &dwType, (LPBYTE) &fShowCommonGrps, &cbData);
}
if (fShowCommonGrps || AccessToCommonGroups)
{
RegCreateKeyEx(hkeyProgramManager, szCommonGroups, 0, szProgman, 0, KEY_READ | KEY_WRITE, pSecurityAttributes, &hkeyPMCommonGroups, NULL);
// Load all common program groups
LoadCommonGroups(szNULL);
}
// Now load the user's personal program groups.
pT = szGroupList;
for (GetGroupList(pT, hkeyGroups); *pT; pT += (lstrlen(pT) + 1))
{
*szGroupKey = TEXT('\0');
cbData = sizeof(szCommonGrpInfo);
// If we're loading a common group...
if (*(pT + CCHGROUP) == TEXT('C') && hkeyPMCommonGroups)
{
if (RegQueryValueEx(hkeyPMCommonGroups, pT, 0, 0,
(LPBYTE) szCommonGrpInfo, &cbData))
continue;
wIndex = 0;
for (pszT = pT + CCHCOMMONGROUP; *pszT; pszT++)
{
wIndex *= 10;
wIndex += *pszT - TEXT('0');
}
// Get the window coordinates of this common group.
pszT = szCommonGrpInfo;
for (i = 0; i < 7; i++)
{
rgiPos[i] = 0;
while (*pszT && !((*pszT >= TEXT('0') && *pszT <= TEXT('9')) || *pszT == TEXT('-')))
pszT++;
if (!*pszT)
{
bDefaultPosition = TRUE;
break;
}
rgiPos[i] = MyAtoi(pszT);
while (*pszT && ((*pszT >= TEXT('0') && *pszT <= TEXT('9')) || *pszT == TEXT('-')))
pszT++;
}
// Now get the common group's name.
if (*pszT)
{
while (*pszT && *pszT == TEXT(' ')) pszT++;
lstrcpy(szGroupKey, pszT);
}
hwndGroup = IsGroupAlreadyLoaded(szGroupKey, TRUE);
if (!hwndGroup)
{
// The common group no longer exists, remove this entry from
// the user's list.
RegDeleteValue(hkeyPMCommonGroups, pT);
}
if (hwndGroup && !bDefaultPosition)
{
// Position the common group according to the user's choice.
SetInternalWindowPos(hwndGroup, (UINT) rgiPos[6],
(LPRECT) &rgiPos[0], (LPPOINT) &rgiPos[4]);
}
}
else
{
if (RegQueryValueEx(hkeyGroups, pT, 0, 0, (LPBYTE) szGroupKey, &cbData))
continue;
wIndex = 0;
for (pszT = pT + CCHGROUP; *pszT; pszT++)
{
wIndex *= 10;
wIndex += *pszT - TEXT('0');
}
LoadGroupWindow(szGroupKey, wIndex, FALSE);
}
}
bAutoArrange = bRealArrange;
// If we started with ANSI groups, save the newly converted unicode
// groups now.
if (bUseANSIGroups)
{
WriteINIFile();
}
if (hkeyPMAnsiGroups)
{
RegCloseKey(hkeyPMAnsiGroups);
}
/*
* Record the current display driver.
*/
GetPrivateProfileString(szSystemBoot, szSystemDisplay, szPath, szPath, CharSizeOf(szPath), szSystemIni);
RegSetValueEx(hkeyPMSettings, szSystemDisplay, 0, REG_SZ, (LPBYTE) szPath, sizeof(TCHAR)*(lstrlen(szPath) + 1));
/*
* Check to see if there was any trouble.
*/
if (fErrorOnExtract)
{
/*
* On observed problem with icon extraction has been to do
* with a low memory.
*/
MyMessageBox(hwndProgman, IDS_OOMEXITTITLE, IDS_LOWMEMONEXTRACT,
NULL, MB_OK | MB_ICONHAND | MB_SYSTEMMODAL);
}
}
// UseAnsiGroups()
// Purpose: Determine if we should convert the ANSI groups
// to Unicode groups.
// Parameters: DWORD dwDisp - disposition from RegCreateKeyEx
// on UNICODE Program Groups
// Return: BOOL TRUE if the groups should be converted
// FALSE if not
BOOL UseAnsiGroups(DWORD dwDisp)
{
DWORD dwType, dwMigrateValue, dwSize, dwAnsiValue = 0;
LONG lResult;
BOOL bRet = FALSE;
HKEY hKeyAnsiPG;
// If the dwDisp is a new key, then we return immediately and use
// the ANSI groups if they exist.
if (dwDisp == REG_CREATED_NEW_KEY)
{
return TRUE;
}
// dwDisp is an existing key.
// If the "Migrate Ansi" value exist and the ANSI groups exist,
// then use them otherwise use the current UNICODE information.
dwSize = sizeof(DWORD);
lResult = RegQueryValueEx(hkeyProgramGroups, szMigrateAnsi,
NULL, &dwType, (LPBYTE) &dwMigrateValue,
&dwSize);
// Check the return value of registry call. If it fails
// then we are working with a machine that has UNICODE Program
// Groups, and does not need to be updated from the ANSI groups.
// Most of the time, we will exit here.
if (lResult != ERROR_SUCCESS)
{
return FALSE;
}
// Now we need to know if any ANSI groups exist.
lResult = RegOpenKeyEx(HKEY_CURRENT_USER, szAnsiProgramGroups,
0, KEY_READ, &hKeyAnsiPG);
if (lResult == ERROR_SUCCESS)
{
TCHAR szName[MAX_PATH];
DWORD dwNameSize = MAX_PATH;
FILETIME ft;
// The "Program Groups" key exists, check to see if there is
// really something in it.
lResult = RegEnumKeyEx(hKeyAnsiPG, 0, szName, &dwNameSize, NULL,
NULL, NULL, &ft);
// If the return value is success, then there is one or more
// items in the ANSI key.
if (lResult == ERROR_SUCCESS)
{
dwAnsiValue = 1;
}
else
{
dwAnsiValue = 0;
}
// Close the key
RegCloseKey(hKeyAnsiPG);
}
// If the MigrateValue is set, then we want to delete this entry
// so the next time the user logs we don't try to convert the ANSI
// groups again (and this function will execute faster).
if (dwMigrateValue)
{
RegDeleteValue(hkeyProgramGroups, szMigrateAnsi);
}
// Determine the return value.
if (dwMigrateValue && dwAnsiValue)
{
bRet = TRUE;
}
else
{
bRet = FALSE;
}
return (bRet);
}
/** ReadConfigFile --
* BOOL APIENTRY ReadConfigFile(int nCmdShow)
* ENTRY - int CmdShow -
* EXIT - void
* SYNOPSIS - ??
* WARNINGS -
* EFFECTS -
*/
VOID NEAR PASCAL ReadConfigFile(int nCmdShow)
{
int j;
int rgiPos[5];
LPTSTR pszT, pT;
HCURSOR hCursor;
BOOL bErrorMsgDisplayed = FALSE;
TCHAR szCommonGroupsKey[MAXKEYLEN];
DWORD dwDisposition;
HKEY hkey = NULL;
hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
ShowCursor(TRUE);
/*
* Create/Open the registry keys corresponding to progman.ini sections.
*/
if (!RegCreateKeyEx(HKEY_CURRENT_USER, PROGMAN_KEY, 0, szProgman, 0, KEY_READ | KEY_WRITE, pSecurityAttributes, &hkeyProgramManager, NULL))
{
RegCreateKeyEx(hkeyProgramManager, szSettings, 0, szProgman, 0, KEY_READ | KEY_WRITE, pSecurityAttributes, &hkeyPMSettings, NULL);
RegCreateKeyEx(hkeyProgramManager, szRestrict, 0, szProgman, 0, KEY_READ, pSecurityAttributes, &hkeyPMRestrict, NULL);
RegCreateKeyEx(hkeyProgramManager, szGroups, 0, szProgman, 0, KEY_READ | KEY_WRITE, pSecurityAttributes, &hkeyPMGroups, NULL);
}
else
{
MyMessageBox(NULL, IDS_APPTITLE, IDS_REGISTRYERROR, NULL, MB_OK | MB_ICONEXCLAMATION);
bErrorMsgDisplayed = TRUE;
}
/* Get the global variable settings out of the INI file. */
if (pszT = GetSettings())
{
/* Get the window coordinates for PROGMAN's main window. */
pT = pszT;
for (j = 0; j < 5; j++)
{
rgiPos[j] = 0;
while (*pT && !((*pT >= TEXT('0') && *pT <= TEXT('9')) || *pT == TEXT('-')))
pT++;
if (!*pT)
{
LocalFree((HANDLE) pszT);
goto DefaultPosition;
}
rgiPos[j] = MyAtoi(pT);
while (*pT && ((*pT >= TEXT('0') && *pT <= TEXT('9')) || *pT == TEXT('-')))
pT++;
}
LocalFree((HANDLE) pszT);
}
else
{
DefaultPosition:
/* NOTE: cx = 0 - CW_USEDEFAULT == CW_USEDEFAULT (0x8000) */
rgiPos[0] = rgiPos[1] = CW_USEDEFAULT;
rgiPos[2] = rgiPos[3] = 0;
rgiPos[4] = SW_SHOWNORMAL;
}
if (nCmdShow != SW_SHOWNORMAL)
rgiPos[4] = nCmdShow;
/*
* We don't want an invisible Program Manager!
*/
if (!(rgiPos[4]))
rgiPos[4] = SW_SHOWNORMAL;
/* Create and paint the top-level frame window. */
if (!CreateFrameWindow((PRECT) rgiPos, (WORD) rgiPos[4]))
goto RCFErrExit;
/*
* Will create/open the key Program Groups, parent of all groups.
*/
if (RegCreateKeyEx(HKEY_CURRENT_USER, szProgramGroups, 0, szGroups, 0, KEY_READ | KEY_WRITE, pSecurityAttributes, &hkeyProgramGroups, &dwDisposition))
{
if (!bErrorMsgDisplayed)
{
MyMessageBox(NULL, IDS_APPTITLE, IDS_REGISTRYERROR, NULL, MB_OK | MB_ICONEXCLAMATION);
}
goto RCFErrExit;
}
if (UseAnsiGroups(dwDisposition))
{
// There are no UNICODE groups, so convert the ANSI groups and save
// them as UNICODE groups.
bUseANSIGroups = TRUE;
if (RegCreateKeyEx(HKEY_CURRENT_USER, szAnsiProgramGroups, 0, szGroups, 0, KEY_READ, pSecurityAttributes, &hkeyAnsiProgramGroups, &dwDisposition))
{
if (!bErrorMsgDisplayed)
{
MyMessageBox(NULL, IDS_APPTITLE, IDS_REGISTRYERROR, NULL, MB_OK | MB_ICONEXCLAMATION);
}
goto RCFErrExit;
}
}
/*
* Will create/open the key Program Groups for common groups on the local
* machine.
*/
lstrcpy(szCommonGroupsKey, TEXT("SOFTWARE\\"));
lstrcat(szCommonGroupsKey, szAnsiProgramGroups);
// Try opening/creating the common groups key with Write access
OpenCommonGroupsKey:
if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, szCommonGroupsKey, 0, szGroups, 0, KEY_READ | KEY_WRITE | DELETE, pAdminSecAttr, &hkeyCommonGroups, &dwDisposition) == ERROR_SUCCESS)
{
if (dwDisposition == REG_CREATED_NEW_KEY)
{
// need to close and reopen the key to make sure we have the
// right access
RegCloseKey(hkeyCommonGroups);
goto OpenCommonGroupsKey;
}
AccessToCommonGroups = TRUE;
}
else
{
RegOpenKeyEx(HKEY_LOCAL_MACHINE, szCommonGroupsKey, 0, KEY_READ,
&hkeyCommonGroups);
}
// If we have Ansi groups in the profile, add a menu item under the Options menu
// to remove the old NT1.0 ANSI groups. This menu item will be deleted we the
// user selects to remove the old groups
if (!fNoSave && (bUseANSIGroups || !RegOpenKeyEx(HKEY_CURRENT_USER,
szAnsiProgramGroups,
0,
DELETE | KEY_READ | KEY_WRITE, &hkey)))
{
HMENU hMenu = GetSubMenu(GetMenu(hwndProgman), 1);
AppendMenu(hMenu, MF_SEPARATOR, 0, NULL);
LoadString(hAppInstance, IDS_ANSIGROUPSMENU, szMessage, CharSizeOf(szMessage));
AppendMenu(hMenu, MF_STRING | MF_ENABLED, IDM_ANSIGROUPS, szMessage);
if (hkey)
{
RegCloseKey(hkey);
}
}
/* The main frame window's been created, shown, and filled.
* It's time to read the various group files, by enumerating group#
* lines in PROGMAN.INI
*/
LoadAllGroups();
/*
* Restriction key is no longer needed.
*/
if (hkeyPMRestrict)
{
RegCloseKey(hkeyPMRestrict);
hkeyPMRestrict = NULL;
}
RCFErrExit:
// We've got the Ansi groups, reset this value.
bUseANSIGroups = FALSE;
RegCloseKey(hkeyAnsiProgramGroups);
hkeyAnsiProgramGroups = NULL;
ShowCursor(FALSE);
SetCursor(hCursor);
ShowWindow(hwndMDIClient, SW_SHOWNORMAL);
}
/*
* FUNCTION: ParseReserved(LPTSTR lpReserved, LPDWORD lpDdeId, LPDWORD lpHotKey)
* PURPOSE: Parses the lpReserved field of the StartupInfo structure to
* get the Progman's new instance DDE id and its Hot key.
* The lpReserved field is a string of thee following format:
* "dde.%d,hotkey.%d"
* Returns the dde id and hotkey.
* COMMENTS: This is to be compatible with Win3.1 by allowing users to
* set a hotkey for Progman, and to allow them to change
* Progman's icon and window title (see SetProgmanProperties in
* pmwprocs.c)
* HISTORY: 08-28-92 JohanneC Created.
*/
void ParseReserved(LPTSTR lpReserved, LPDWORD lpDdeId, LPDWORD lpHotKey)
{
TCHAR *pch, *pchT, ch;
// The string will be of the format "dde.%d,hotkey.%d"
// Get the DDE id.
if ((pch = wcsstr(lpReserved, TEXT("dde."))) != NULL)
{
pch += 4;
pchT = pch;
while (*pchT >= TEXT('0') && *pchT <= TEXT('9'))
pchT++;
ch = *pchT;
*pchT = 0;
*lpDdeId = MyAtoi(pch);
*pchT = ch;
}
// Get the hot key.
if ((pch = wcsstr(lpReserved, TEXT("hotkey."))) != NULL)
{
pch += 7;
pchT = pch;
while (*pchT >= TEXT('0') && *pchT <= TEXT('9'))
pchT++;
ch = *pchT;
*pchT = 0;
*lpHotKey = MyAtoi(pch);
*pchT = ch;
}
}
/** IsHandleReallyProgman --
* BOOL IsHandleReallyProgman (HWND hProgman, LPTSTR lpClassName)
* ENTRY - HWND hProgman
* EXIT - BOOL TRUE if it is progman
* FALSE if not
* SYNOPSIS - ??
* WARNINGS -
* EFFECTS -
*/
BOOL IsHandleReallyProgman(HWND hwndProgman)
{
// Test to see if we found Progman or Explorer.
if ((GetClassLong(hwndProgman, GCL_STYLE) == 0) &&
(GetClassLongPtr(hwndProgman, GCLP_HICON) != 0) &&
(GetClassLongPtr(hwndProgman, GCLP_MENUNAME) != 0))
{
return TRUE;
}
return FALSE;
}
/** AppInit --
* BOOL APIENTRY AppInit(HANDLE hInstance, HANDLE hPrevInstance,
* LPTSTR lpszCmdLine, int nCmdShow)
* ENTRY - HANDLE hInstance
* HANDLE hPrevInstance
* LPTSTR lpszCmdLine
* int nCmdSHow
* EXIT - BOOL xxx - (FALSE == ERROR)
* SYNOPSIS - ??
* WARNINGS -
* EFFECTS -
*/
BOOL APIENTRY AppInit(HANDLE hInstance, LPTSTR lpszCmdLine, int nCmdShow)
{
WORD ret;
WNDCLASS wndClass;
TCHAR szClass[16];
TCHAR szBuffer[MAX_PATH];
LOGFONT lf;
TCHAR szText[MAXMESSAGELEN + 1];
STARTUPINFO si;
HWND hwndPrev;
INT nTempCmdShow = nCmdShow;
#ifdef DEBUG_PROGMAN_DDE
{
TCHAR szDebug[300];
wsprintf(szDebug, TEXT("%d PROGMAN: Enter AppInit\r\n"), GetTickCount());
OutputDebugString(szDebug);
}
#endif
// Preserve this instance's module handle.
hAppInstance = hInstance;
// Specify the shutdown order of the progman process.
// 2 means Porgman will shutdown before taskman (level = 1) and
// ntsd or windbg (level = 0)
SetProcessShutdownParameters(2, 0);
#ifndef MYDEBUG
LoadString(hAppInstance, IDS_PMCLASS, szClass, CharSizeOf(szClass));
if (hwndPrev = FindWindow(szClass, NULL))
{
bDisableDDE = TRUE; // Only 1 "PROGMAN" should respond to dde
if (IsHandleReallyProgman(hwndPrev))
{
DWORD dwDdeId = 0;
DWORD dwHotKey = 0;
LONG lExiting;
GetStartupInfo(&si);
if (si.lpReserved)
{
ParseReserved(si.lpReserved, &dwDdeId, &dwHotKey);
}
PostMessage(hwndPrev, WM_EXECINSTANCE, (WPARAM) dwDdeId, dwHotKey);
// Need to check the other progman to see if it is exiting currently.
// If so, then we will continue. GetWindowLong returns 0 as a
// failure case and as the "Not exiting" case (1 if we are exiting),
// so we need to confirm that the last error is also
// zero.
lExiting = GetWindowLong(hwndPrev, GWL_EXITING);
if (lExiting != 1)
{
return FALSE;
}
}
}
#endif
/*
* Compute general constants.
*/
dyBorder = GetSystemMetrics(SM_CYBORDER);
hItemIcon = LoadIcon(hAppInstance, (LPTSTR) MAKEINTRESOURCE(ITEMICON));
if (!hItemIcon)
{
return FALSE;
}
/*
* Load the accelerator table.
*/
hAccel = LoadAccelerators(hAppInstance, (LPTSTR) MAKEINTRESOURCE(PMACCELS));
if (!hAccel)
return FALSE;
cxIcon = GetSystemMetrics(SM_CXICON);
cyIcon = GetSystemMetrics(SM_CYICON);
cxOffset = 2 * GetSystemMetrics(SM_CXBORDER);
cyOffset = 2 * GetSystemMetrics(SM_CYBORDER);
cxIconSpace = cxIcon + 2 * cxOffset;
cyIconSpace = cyIcon + 2 * cyOffset;
SystemParametersInfo(SPI_ICONHORIZONTALSPACING, 0, (PVOID) (LPINT) &cxArrange, FALSE);
SystemParametersInfo(SPI_ICONVERTICALSPACING, 0, (PVOID) (LPINT) &cyArrange, FALSE);
SystemParametersInfo(SPI_GETICONTITLEWRAP, 0, (PVOID) (LPWORD) &bIconTitleWrap, FALSE);
SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(lf), (PVOID) (LPLOGFONT) &lf, FALSE);
// lhb tracks check this out !!!! save this one for later! 1/21/93
//lf.lfCharSet = ANSI_CHARSET ;
//lstrcpy (lf.lfFaceName, TEXT("Lucida Sans Unicode"));
hFontTitle = CreateFontIndirect(&lf);
if (!hFontTitle)
return FALSE;
hIconGlobal = LoadIcon(hAppInstance, (LPTSTR) MAKEINTRESOURCE(WORDICON));
if (!hIconGlobal)
{
return FALSE;
}
/*
* Remember the original directory.
*/
GetCurrentDirectory(MAXITEMPATHLEN + 1, szOriginalDirectory);
// Set Progman's working directory to system32 directory instead of the
// windows directory. johannec 5-4-93 bug 8364
//GetWindowsDirectory(szWindowsDirectory, MAXITEMPATHLEN+1);
GetSystemDirectory(szWindowsDirectory, MAXITEMPATHLEN + 1);
/*
* Make sure drive letter is upper case.
*/
CharUpperBuff(szWindowsDirectory, 1);
bInNtSetup = FALSE;
if (lpszCmdLine && *lpszCmdLine &&
!lstrcmpi(lpszCmdLine, TEXT("/NTSETUP")))
{
// Progman was started from ntsetup.exe, so it can be exited
// without causing NT Windows to exit.
bExitWindows = FALSE;
bInNtSetup = TRUE;
*lpszCmdLine = 0;
}
else
{
HKEY hkeyWinlogon;
DWORD dwType;
DWORD cbBuffer;
LPTSTR lpt;
/* Check if we should be the shell by looking at shell= line for WInlogon
*/
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"), 0, KEY_READ, &hkeyWinlogon) == ERROR_SUCCESS)
{
cbBuffer = sizeof(szBuffer);
if (RegQueryValueEx(hkeyWinlogon, TEXT("Shell"), 0, &dwType, (LPBYTE) szBuffer, &cbBuffer) == ERROR_SUCCESS)
{
CharLower(szBuffer);
lpt = szBuffer;
while (lpt = wcsstr(lpt, szProgman))
{
// we probably found progman
lpt += lstrlen(szProgman);
if (*lpt == TEXT(' ') || *lpt == TEXT('.') || *lpt == TEXT(',') || !*lpt)
bExitWindows = TRUE;
}
}
else
{
// assume that progman is the shell.
bExitWindows = TRUE;
}
RegCloseKey(hkeyWinlogon);
}
else
{
// assume that progman is the shell.
bExitWindows = TRUE;
}
}
if (lpszCmdLine && *lpszCmdLine)
{
nCmdShow = SW_SHOWMINNOACTIVE;
}
/*
* call private api to mark task man as a system app. This causes
* it to be killed after all other non-system apps during shutdown.
*/
// MarkProcess(MP_SYSTEMAPP);
/*
* Load these strings now. If we need them later,
* we won't be able to load them at that time.
*/
LoadString(hAppInstance, IDS_OOMEXITTITLE, szOOMExitTitle, CharSizeOf(szOOMExitTitle));
LoadString(hAppInstance, IDS_OOMEXITMSG, szOOMExitMsg, CharSizeOf(szOOMExitMsg));
LoadString(hAppInstance, IDS_PMCLASS, szClass, CharSizeOf(szClass));
SetCurrentDirectory(szWindowsDirectory);
SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS); // Bounce errors to us, not fs.
// Set global exit flag.
fExiting = FALSE;
uiHelpMessage = RegisterWindowMessage(TEXT("ShellHelp"));
uiBrowseMessage = RegisterWindowMessage(HELPMSGSTRING);
uiActivateShellWindowMessage = RegisterWindowMessage(TEXT("ACTIVATESHELLWINDOW"));
uiConsoleWindowMessage = RegisterWindowMessage(TEXT("ConsoleProgmanHandle"));
uiSaveSettingsMessage = RegisterWindowMessage(TEXT("SaveSettings")); // for UPEDIT.exe : User Profile Editor
hhkMsgFilter = SetWindowsHook(WH_MSGFILTER, MessageFilter);
if (hhkMsgFilter == 0)
{
GetLastError();
}
/*
* Register the Frame window class.
*/
wndClass.lpszClassName = szClass;
wndClass.style = 0;
wndClass.lpfnWndProc = ProgmanWndProc;
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = sizeof(LONG);
wndClass.hInstance = hAppInstance;
wndClass.hIcon = hProgmanIcon = LoadIcon(hAppInstance, (LPTSTR) MAKEINTRESOURCE(PROGMANICON));
wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndClass.hbrBackground = NULL;
wndClass.lpszMenuName = (LPTSTR) MAKEINTRESOURCE(PROGMANMENU);
if (!RegisterClass(&wndClass))
return(FALSE);
/*
* Register the Program Group window class.
*/
LoadString(hAppInstance, IDS_GROUPCLASS, szClass, 16);
wndClass.lpszClassName = szClass;
wndClass.style = CS_DBLCLKS;
wndClass.lpfnWndProc = GroupWndProc;
/*wndClass.cbClsExtra = 0;*/
wndClass.cbWndExtra = sizeof(PGROUP); /* <== PGROUP */
/*wndClass.hInstance = hAppInstance;*/
wndClass.hIcon = NULL;
/*wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);*/
wndClass.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
wndClass.lpszMenuName = NULL;
if (!RegisterClass(&wndClass))
return(FALSE);
{
// Set the working set size to 300k.
QUOTA_LIMITS QuotaLimits;
NTSTATUS status;
status = NtQueryInformationProcess(NtCurrentProcess(), ProcessQuotaLimits, &QuotaLimits, sizeof(QUOTA_LIMITS), NULL);
if (NT_SUCCESS(status))
{
QuotaLimits.MinimumWorkingSetSize = 400 * 1024;
QuotaLimits.MaximumWorkingSetSize = 508 * 1024;
NtSetInformationProcess(NtCurrentProcess(), ProcessQuotaLimits, &QuotaLimits, sizeof(QUOTA_LIMITS));
}
}
hGroupIcon = LoadIcon(hAppInstance, (LPTSTR) MAKEINTRESOURCE(PERSGROUPICON));
hCommonGrpIcon = LoadIcon(hAppInstance, (LPTSTR) MAKEINTRESOURCE(COMMGROUPICON));
if (!RegisterHotKeyClass((HANDLE) hAppInstance))
return FALSE;
RegisterDDEClasses((HANDLE) hAppInstance);
/*
* Initialize the security descriptor for the registry keys that
* will be added to the user's personal profile.
*/
pSecurityAttributes = &SecurityAttributes;
if (!InitializeSecurityAttributes(pSecurityAttributes, TRUE))
pSecurityAttributes = NULL;
/*
* Initialize the security descriptor for the registry keys that
* will be added to the local machine program groups. Only
* Administrators, Power Users and Server Operators
* have all access to these keys, other users have only read access.
*/
pAdminSecAttr = &AdminSecAttr;
if (!InitializeSecurityAttributes(pAdminSecAttr, FALSE))
pAdminSecAttr = NULL;
/*
* Test if the current user is an admin. If so, ignore restrictions
* from the profile.
*/
UserIsAdmin = TestUserForAdmin();
/*
* Read in the Group/Item data structures and create the windows.
*/
#ifdef DEBUG_PROGMAN_DDE
{
TCHAR szDebug[300];
wsprintf(szDebug, TEXT("%d PROGMAN: Before ReadConfigFile\r\n"), GetTickCount());
OutputDebugString(szDebug);
}
#endif
ReadConfigFile(nCmdShow);
#ifdef DEBUG_PROGMAN_DDE
{
TCHAR szDebug[300];
wsprintf(szDebug, TEXT("%d PROGMAN: After ReadConfigFile\r\n"), GetTickCount());
OutputDebugString(szDebug);
}
#endif
if (hwndProgman == NULL)
return FALSE;
/*
* NOTE: the nCmdShow stuff from here down is bogus
* Do load/run lines, then the command line, then the startup group...
*/
if (bExitWindows)
DoRunEquals(&nCmdShow);
/* Process the Command Line */
if (lpszCmdLine && *lpszCmdLine)
{
WORD cbText;
TCHAR szFilename[MAXITEMPATHLEN + 1];
lstrcpy(szPathField, lpszCmdLine);
// win foo.bar is done relative to the original directory.
SetCurrentDirectory(szOriginalDirectory);
GetDirectoryFromPath(szPathField, szDirField);
// now kernel converts the DOS cmd line to Ansi for us!
GetFilenameFromPath(szPathField, szFilename);
ret = ExecProgram(szFilename, szDirField, NULL, FALSE, 0, 0, 0);
if (ret)
{
szText[0] = TEXT('\'');
lstrcpy(&szText[1], szPathField);
cbText = (WORD) lstrlen(szText);
LoadString(hAppInstance, IDS_CMDLINEERR, &szText[cbText], CharSizeOf(szText) - cbText);
MyMessageBox(NULL, IDS_APPTITLE, ret, szText, MB_OK | MB_ICONEXCLAMATION | MB_SYSTEMMODAL);
}
else
nCmdShow = SW_SHOWMINNOACTIVE;
SetCurrentDirectory(szWindowsDirectory);
}
/*
* See if we have a startup group last.
*/
#ifndef MYDEBUG
if (bExitWindows || GetAsyncKeyState(VK_CONTROL) < 0)
#endif
HandleStartupGroup(nTempCmdShow);
/*
* create an event for monitoring the ProgramGroups key.
*/
InitializeGroupKeyNotification();
if (bInitialArrange)
{
PostMessage(hwndMDIClient, WM_MDIICONARRANGE, 0, 0L);
PostMessage(hwndProgman, WM_COMMAND, IDM_SAVENOW, 0L);
}
#ifdef DEBUG_PROGMAN_DDE
{
TCHAR szDebug[300];
wsprintf(szDebug, TEXT("%d PROGMAN: Leave AppInit\r\n"), GetTickCount());
OutputDebugString(szDebug);
}
#endif
return TRUE;
}