872 lines
30 KiB
C
872 lines
30 KiB
C
// Created 07-Jan-1993 11:20am by Jeff Parsons
|
|
|
|
#include "shellprv.h"
|
|
#pragma hdrstop
|
|
#include <setupapi.h>
|
|
|
|
const CHAR szIpOpen []= "SetupOpenInfFileW";
|
|
const CHAR szIpFindFirstLine []= "SetupFindFirstLineW";
|
|
const CHAR szIpFindNextLine []= "SetupFindNextLine";
|
|
const CHAR szIpGetStringField[]= "SetupGetStringFieldW";
|
|
const CHAR szIpGetIntField []= "SetupGetIntField";
|
|
const CHAR szIpClose []= "SetupCloseInfFile";
|
|
const TCHAR szOne []= TEXT("1");
|
|
|
|
//
|
|
// WARNING: Do not change the format of this structure (BPSTR followed by
|
|
// FARPROC) unless you also plan on the changing the code below that fills
|
|
// the structure in. The sole purpose of this structure is and should
|
|
// remain to obtain various exported procedure addresses from SETUPX.DLL!
|
|
//
|
|
|
|
typedef const CHAR *BPSTR;
|
|
struct {
|
|
BPSTR pszIpOpen;
|
|
HINF (WINAPI *lpIpOpen)(LPCTSTR pszFileSpec, LPCTSTR InfClass, DWORD InfStyle, UINT *ErrorLine);
|
|
BPSTR pszIpFindFirstLine;
|
|
BOOL (WINAPI *lpIpFindFirstLine)(HINF hInf, LPCTSTR lpszSect, LPCTSTR lpszKey, PINFCONTEXT Context);
|
|
BPSTR pszIpFindNextLine;
|
|
BOOL (WINAPI *lpIpFindNextLine)(PINFCONTEXT ContextIn, PINFCONTEXT ContextOut);
|
|
BPSTR pszIpGetStringField;
|
|
BOOL (WINAPI *lpIpGetStringField)(PINFCONTEXT Context, DWORD FieldIndex, LPTSTR ReturnBuffer, DWORD ReturnBufferSize, DWORD * RequiredSize);
|
|
BPSTR pszIpGetIntField;
|
|
BOOL (WINAPI *lpIpGetIntField)(PINFCONTEXT Context, DWORD FieldIndex, INT * IntegerValue);
|
|
BPSTR pszIpClose;
|
|
VOID (WINAPI *lpIpClose)(HINF hInf);
|
|
} sfnIp = {
|
|
szIpOpen ,NULL,
|
|
szIpFindFirstLine ,NULL,
|
|
szIpFindNextLine ,NULL,
|
|
szIpGetStringField,NULL,
|
|
szIpGetIntField ,NULL,
|
|
szIpClose ,NULL,
|
|
};
|
|
#define NUM_FUNCTIONS 6
|
|
|
|
static UINT g_SXUseCount = 0;
|
|
static HINSTANCE g_hSetupDLL = NULL;
|
|
|
|
const TCHAR szRegKeyMSDOSApps[] = REGSTR_PATH_NEWDOSBOX;
|
|
|
|
const TCHAR szParams[] = KEY_PARAMS;
|
|
const TCHAR szBatchFile[] = KEY_BATCHFILE;
|
|
const TCHAR szLowMem[] = KEY_LOWMEM;
|
|
const TCHAR szEmsMem[] = KEY_EMSMEM;
|
|
const TCHAR szXmsMem[] = KEY_XMSMEM;
|
|
const TCHAR szDpmiMem[] = KEY_DPMIMEM;
|
|
const TCHAR szEnable[] = KEY_ENABLE;
|
|
const TCHAR szDisable[] = KEY_DISABLE;
|
|
|
|
const TCHAR szWindowed[] = KEYVAL_WINDOWED;
|
|
const TCHAR szBackground[] = KEYVAL_BACKGROUND;
|
|
const TCHAR szExclusive[] = KEYVAL_EXCLUSIVE;
|
|
const TCHAR szDetectIdle[] = KEYVAL_DETECTIDLE;
|
|
const TCHAR szLowLocked[] = KEYVAL_LOWLOCKED;
|
|
const TCHAR szEMSLocked[] = KEYVAL_EMSLOCKED;
|
|
const TCHAR szXMSLocked[] = KEYVAL_XMSLOCKED;
|
|
const TCHAR szUseHMA[] = KEYVAL_USEHMA;
|
|
const TCHAR szEmulateROM[] = KEYVAL_EMULATEROM;
|
|
const TCHAR szRetainVRAM[] = KEYVAL_RETAINVRAM;
|
|
const TCHAR szFastPaste[] = KEYVAL_FASTPASTE;
|
|
const TCHAR szALTTAB[] = KEYVAL_ALTTAB;
|
|
const TCHAR szALTESC[] = KEYVAL_ALTESC;
|
|
const TCHAR szCTRLESC[] = KEYVAL_CTRLESC;
|
|
const TCHAR szPRTSCRN[] = KEYVAL_PRTSCRN;
|
|
const TCHAR szALTPRTSCRN[] = KEYVAL_ALTPRTSCRN;
|
|
const TCHAR szALTSPACE[] = KEYVAL_ALTSPACE;
|
|
const TCHAR szALTENTER[] = KEYVAL_ALTENTER;
|
|
const TCHAR szWinLie[] = KEYVAL_WINLIE;
|
|
const TCHAR szGlobalMem[] = KEYVAL_GLOBALMEM;
|
|
const TCHAR szRealMode[] = KEYVAL_REALMODE;
|
|
const TCHAR szMouse[] = KEYVAL_MOUSE;
|
|
const TCHAR szEMS[] = KEYVAL_EMS;
|
|
const TCHAR szCDROM[] = KEYVAL_CDROM;
|
|
const TCHAR szNetwork[] = KEYVAL_NETWORK;
|
|
const TCHAR szDiskLock[] = KEYVAL_DISKLOCK;
|
|
const TCHAR szPrivateCFG[] = KEYVAL_PRIVATECFG;
|
|
const TCHAR szCloseOnExit[] = KEYVAL_CLOSEONEXIT;
|
|
const TCHAR szAllowSSaver[] = KEYVAL_ALLOWSSAVER;
|
|
const TCHAR szUniqueSettings[] = KEYVAL_UNIQUESETTINGS;
|
|
|
|
const LPCTSTR apszKey[] = {
|
|
szParams,
|
|
szBatchFile,
|
|
szLowMem,
|
|
szEmsMem,
|
|
szXmsMem,
|
|
szDpmiMem,
|
|
szEnable,
|
|
szDisable,
|
|
};
|
|
|
|
const LPCTSTR apszKeyVal[] = {
|
|
szWindowed, // abKeyValIDBits[0]
|
|
szBackground, // abKeyValIDBits[1]
|
|
szExclusive, // abKeyValIDBits[2]
|
|
szDetectIdle, // abKeyValIDBits[3]
|
|
szLowLocked, // abKeyValIDBits[4]
|
|
szEMSLocked, // abKeyValIDBits[5]
|
|
szXMSLocked, // abKeyValIDBits[6]
|
|
szUseHMA, // abKeyValIDBits[7]
|
|
szEmulateROM, // abKeyValIDBits[8]
|
|
szRetainVRAM, // abKeyValIDBits[9]
|
|
szFastPaste, // abKeyValIDBits[10]
|
|
szALTTAB, // abKeyValIDBits[11]
|
|
szALTESC, // abKeyValIDBits[12]
|
|
szCTRLESC, // abKeyValIDBits[13]
|
|
szPRTSCRN, // abKeyValIDBits[14]
|
|
szALTPRTSCRN, // abKeyValIDBits[15]
|
|
szALTSPACE, // abKeyValIDBits[16]
|
|
szALTENTER, // abKeyValIDBits[17]
|
|
szWinLie, // abKeyValIDBits[18]
|
|
szGlobalMem, // abKeyValIDBits[19]
|
|
szRealMode, // abKeyValIDBits[20]
|
|
szMouse, // abRMKeyValIDBits[0]
|
|
szEMS, // abRMKeyValIDBits[1]
|
|
szCDROM, // abRMKeyValIDBits[2]
|
|
szNetwork, // abRMKeyValIDBits[3]
|
|
szDiskLock, // abRMKeyValIDBits[4]
|
|
szPrivateCFG, // abRMKeyValIDBits[5]
|
|
szCloseOnExit, // special case 0 (see "special case 0" below)
|
|
szAllowSSaver, // special case 1 (see "special case 1" below)
|
|
szUniqueSettings, // Never transferred to PIF - Used to populate registry
|
|
};
|
|
|
|
// Array of bit numbers that must be kept in sync with KEYVALIDs
|
|
//
|
|
// 0x80 means bit must be inverted
|
|
// 0x40 means bit must be set in PfW386Flags2 instead of PfW386Flags
|
|
|
|
const BYTE abKeyValIDBits[] = {
|
|
BITNUM(fFullScreen) | 0x80,
|
|
BITNUM(fBackground),
|
|
BITNUM(fExclusive),
|
|
BITNUM(fPollingDetect),
|
|
BITNUM(fVMLocked),
|
|
BITNUM(fEMSLocked),
|
|
BITNUM(fXMSLocked),
|
|
BITNUM(fNoHMA) | 0x80,
|
|
BITNUM(fVidTxtEmulate) | 0x40,
|
|
BITNUM(fVidRetainAllo) | 0x40,
|
|
BITNUM(fINT16Paste),
|
|
BITNUM(fALTTABdis) | 0x80,
|
|
BITNUM(fALTESCdis) | 0x80,
|
|
BITNUM(fCTRLESCdis) | 0x80,
|
|
BITNUM(fPRTSCdis) | 0x80,
|
|
BITNUM(fALTPRTSCdis) | 0x80,
|
|
BITNUM(fALTSPACEdis) | 0x80,
|
|
BITNUM(fALTENTERdis) | 0x80,
|
|
BITNUM(fWinLie),
|
|
BITNUM(fGlobalProtect),
|
|
BITNUM(fRealMode),
|
|
};
|
|
|
|
const BYTE abRMKeyValIDBits[] = {
|
|
BITNUM(RMOPT_MOUSE),
|
|
BITNUM(RMOPT_EMS),
|
|
BITNUM(RMOPT_CDROM),
|
|
BITNUM(RMOPT_NETWORK),
|
|
BITNUM(RMOPT_DISKLOCK),
|
|
BITNUM(RMOPT_PRIVATECFG),
|
|
BITNUM(RMOPT_VESA),
|
|
};
|
|
// FEATURE: other bits to be supported (maybe):
|
|
// WIN_TOOLBAR,
|
|
// WIN_SAVESETTINGS,
|
|
// MSE_WINDOWENABLE | 0x80,
|
|
// MSE_EXCLUSIVE,
|
|
// TSK_NOWARNTERMINATE | 0x80,
|
|
|
|
|
|
//
|
|
// Load setupx.dll and get proc address for all entry points in table
|
|
//
|
|
BOOL InitSetupxDll(void)
|
|
{
|
|
BOOL fSuccess = TRUE; // Assume it works
|
|
if (g_SXUseCount == 0) {
|
|
//
|
|
// Dynamically load SETUPX.DLL
|
|
//
|
|
UINT uOldMode = SetErrorMode(SEM_NOOPENFILEERRORBOX);
|
|
g_hSetupDLL = LoadLibrary(TEXT("SETUPAPI.DLL"));
|
|
SetErrorMode(uOldMode);
|
|
fSuccess = (g_hSetupDLL != NULL);
|
|
|
|
if (fSuccess)
|
|
{
|
|
int i;
|
|
BPSTR *ppsz;
|
|
FARPROC *plpfn;
|
|
|
|
ppsz = (BPSTR *)&sfnIp;
|
|
|
|
for (i=0; i<NUM_FUNCTIONS; i++)
|
|
{
|
|
plpfn = (FARPROC *)(ppsz+1);
|
|
*plpfn = GetProcAddress(g_hSetupDLL, *ppsz);
|
|
if (*plpfn == NULL)
|
|
{
|
|
FreeLibrary(g_hSetupDLL);
|
|
g_hSetupDLL = NULL;
|
|
fSuccess = FALSE;
|
|
break;
|
|
}
|
|
ppsz = (BPSTR *)(plpfn+1);
|
|
}
|
|
}
|
|
}
|
|
if (fSuccess) {
|
|
g_SXUseCount++;
|
|
}
|
|
return(fSuccess);
|
|
}
|
|
|
|
//
|
|
// When the last user of setupx.dll calls this function, the library is freed.
|
|
//
|
|
void FreeSetupxDll(void)
|
|
{
|
|
g_SXUseCount--;
|
|
if (g_SXUseCount == 0) {
|
|
FreeLibrary(g_hSetupDLL);
|
|
g_hSetupDLL = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
void InitWorkDir(PPROPLINK ppl, LPPROPPRG lpPrg, LPPROPNT40 lpnt40)
|
|
{
|
|
int i;
|
|
|
|
if (lpnt40)
|
|
{
|
|
lstrcpyn((LPTSTR)lpnt40->awchWorkDir,
|
|
ppl->szPathName,
|
|
min(ARRAYSIZE(lpnt40->awchWorkDir),ppl->iFileName+1));
|
|
|
|
// Working directories like C:\ are ok, but C:\FOO\ are not,
|
|
// so remove trailing '\' in that case
|
|
|
|
i = lstrlen((LPTSTR)lpnt40->awchWorkDir)-1;
|
|
if (i > 2 && lpnt40->awchWorkDir[i] == TEXT('\\'))
|
|
lpnt40->awchWorkDir[i] = TEXT('\0');
|
|
|
|
WideCharToMultiByte( CP_ACP, 0, (LPWSTR)lpnt40->awchWorkDir, -1, lpPrg->achWorkDir, ARRAYSIZE(lpPrg->achWorkDir), NULL, NULL );
|
|
}
|
|
else
|
|
{
|
|
WideCharToMultiByte( CP_ACP, 0,
|
|
ppl->szPathName,
|
|
min(ARRAYSIZE(lpPrg->achWorkDir),ppl->iFileName+1),
|
|
(LPSTR)lpPrg->achWorkDir,
|
|
ARRAYSIZE(lpPrg->achWorkDir),
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
// Working directories like C:\ are ok, but C:\FOO\ are not,
|
|
// so remove trailing '\' in that case
|
|
|
|
i = lstrlenA(lpPrg->achWorkDir)-1;
|
|
if (i > 2 && lpPrg->achWorkDir[i] == '\\')
|
|
lpPrg->achWorkDir[i] = '\0';
|
|
}
|
|
}
|
|
|
|
|
|
BOOL FAR GetAppsInfData(PPROPLINK ppl, LPPROPPRG lpPrg, LPPROPNT40 lpnt40, HINF hInf, LPCTSTR lpszApp, BOOL fNotAmbiguous, int flOpt)
|
|
{
|
|
HINF hinfApps;
|
|
int id, i;
|
|
TCHAR szTmp[MAX_PATH];
|
|
TCHAR szPIFSection[MAX_KEY_SIZE];
|
|
BOOL fSuccess = FALSE;
|
|
INFCONTEXT InfContext;
|
|
DWORD dwSize;
|
|
FunctionName(GetAppsInfData);
|
|
|
|
//
|
|
// Although not strictly part of INF processing, it's most
|
|
// convenient here to search for any ICO file that might exist
|
|
// in the same directory as the app, and select it for our default icon.
|
|
//
|
|
lstrcpyn(szTmp, ppl->szPathName, ppl->iFileExt+1);
|
|
lstrcpy(szTmp + ppl->iFileExt, TEXT(".ICO"));
|
|
if ((int)GetFileAttributes(szTmp) != -1) {
|
|
lstrcpyn((LPTSTR)lpnt40->awchIconFile, szTmp, ARRAYSIZE(lpnt40->awchIconFile));
|
|
WideCharToMultiByte( CP_ACP, 0, (LPWSTR)lpnt40->awchIconFile, -1, lpPrg->achIconFile, ARRAYSIZE(lpPrg->achIconFile), NULL, NULL );
|
|
lpPrg->wIconIndex = 0;
|
|
PifMgr_SetProperties(ppl, MAKELP(0,GROUP_PRG),
|
|
lpPrg, SIZEOF(*lpPrg), SETPROPS_CACHE);
|
|
PifMgr_SetProperties(ppl, MAKELP(0,GROUP_NT40),
|
|
lpnt40, SIZEOF(*lpnt40), SETPROPS_CACHE);
|
|
}
|
|
|
|
//
|
|
// Dynamically load SETUPX.DLL
|
|
//
|
|
if (!InitSetupxDll())
|
|
goto DllLoadFalied;
|
|
|
|
if (hInf)
|
|
hinfApps = hInf;
|
|
else
|
|
hinfApps = (*sfnIp.lpIpOpen)(LoadStringSafe(NULL,
|
|
IDS_APPSINF,
|
|
szTmp,
|
|
ARRAYSIZE(szTmp)),
|
|
0, INF_STYLE_WIN4, NULL );
|
|
|
|
if (hinfApps==INVALID_HANDLE_VALUE) {
|
|
id = IDS_CANTOPENAPPSINF;
|
|
if (GetLastError()==ERROR_FILE_NOT_FOUND)
|
|
id = IDS_NOAPPSINF;
|
|
Warning((HWND)ppl, (WORD)id, MB_ICONEXCLAMATION | MB_OK | MB_NOFOCUS);
|
|
goto CloseDLL;
|
|
}
|
|
|
|
// OK, now we have APPS.INF open, so let's bounce around the [pif95]
|
|
// section and try to find the app of interest.
|
|
|
|
if (!(*sfnIp.lpIpFindFirstLine)(hinfApps, TEXT("pif95"), NULL, &InfContext)) {
|
|
Warning((HWND)ppl, IDS_APPSINFERROR, MB_ICONEXCLAMATION | MB_OK | MB_NOFOCUS);
|
|
goto CloseInf;
|
|
}
|
|
|
|
// OK, we've found the [pif95] section, so let's go to it
|
|
|
|
do {
|
|
|
|
|
|
if (!(*sfnIp.lpIpGetStringField)(&InfContext, APPSINF_FILENAME, szTmp, ARRAYSIZE(szTmp), &dwSize))
|
|
continue;
|
|
|
|
// We need to read the rest of the fields now, before we do any
|
|
// more processing, because otherwise we lose our place in the file
|
|
|
|
if (lstrcmpi(szTmp, ppl->szPathName+ppl->iFileName) == 0) {
|
|
|
|
// See if Other File was specified, and then make sure it
|
|
// exists. If it doesn't, then we need to continue the search.
|
|
|
|
// Initialize szTmp with only the path portion of the app's
|
|
// fully-qualified name. Giving lstrcpyn a length of iFileName+1
|
|
// insures that szTmp[ppl->iFileName] will be NULL.
|
|
|
|
lstrcpyn(szTmp, ppl->szPathName, ppl->iFileName+1);
|
|
|
|
(*sfnIp.lpIpGetStringField)(&InfContext, APPSINF_OTHERFILE,
|
|
&szTmp[ppl->iFileName], ARRAYSIZE(lpPrg->achOtherFile), &dwSize);
|
|
|
|
// If szTmp[ppl->iFileName] is no longer NULL, then
|
|
// GetStringField filled it in. See if the file exists.
|
|
|
|
if (szTmp[ppl->iFileName]) {
|
|
if ((int)GetFileAttributes(szTmp) == -1)
|
|
continue; // Other File didn't exist, continue search
|
|
}
|
|
|
|
// If the PIF data we have is ambiguous, and it has already
|
|
// been initialized with data from this APPS.INF entry, then just
|
|
// leave the PIF data alone and LEAVE.
|
|
|
|
if (lpPrg->flPrgInit & PRGINIT_AMBIGUOUSPIF) {
|
|
|
|
if (lstrcmpi((LPWSTR)lpnt40->awchOtherFile, szTmp+ppl->iFileName) == 0) {
|
|
|
|
if (!szTmp[ppl->iFileName]) {
|
|
|
|
// The comparison was inconclusive; both filenames
|
|
// are blank. See if the filename contained in
|
|
// lpPrg->achCmdLine matches lpszApp; if not, again
|
|
// we should fail the search.
|
|
//
|
|
// It's ok to whack lpPrg->achCmdLine with a null;
|
|
// OpenProperties (our only caller) doesn't depend on
|
|
// that data in lpPrg.
|
|
|
|
lpnt40->awchCmdLine[lstrskipfnameA(lpPrg->achCmdLine)] = L'\0';
|
|
|
|
if (lstrcmpi((LPWSTR)lpnt40->awchCmdLine, lpszApp) != 0)
|
|
|
|
|
|
goto CloseInf; // unsuccessful search
|
|
}
|
|
fSuccess++; // successful search
|
|
}
|
|
|
|
// Otherwise, this APPS.INF entry isn't a match, implying
|
|
// some of the PIF's settings don't really apply. We need
|
|
// to fail this search, get back to OpenProperties, look ONLY
|
|
// for _DEFAULT.PIF, and let it try to call GetAppsInfData
|
|
// one more time.
|
|
|
|
goto CloseInf;
|
|
}
|
|
|
|
// Otherwise, update Other File. THIS is the APPS.INF entry
|
|
// we're going to use!
|
|
|
|
lstrcpyn((LPWSTR)lpnt40->awchOtherFile, szTmp + ppl->iFileName, ARRAYSIZE(lpnt40->awchOtherFile));
|
|
WideCharToMultiByte( CP_ACP, 0, (LPWSTR)lpnt40->awchOtherFile, -1, lpPrg->achOtherFile, ARRAYSIZE( lpPrg->achOtherFile ), NULL, NULL );
|
|
|
|
(*sfnIp.lpIpGetStringField)(&InfContext, APPSINF_TITLE, (LPWSTR)lpnt40->awchTitle, ARRAYSIZE(lpnt40->awchTitle), &dwSize);
|
|
WideCharToMultiByte( CP_ACP, 0, (LPWSTR)lpnt40->awchTitle, -1, lpPrg->achTitle, ARRAYSIZE( lpPrg->achTitle ), NULL, NULL );
|
|
|
|
lstrcpyn((LPWSTR)lpnt40->awchCmdLine, lpszApp, ARRAYSIZE(lpnt40->awchCmdLine));
|
|
WideCharToMultiByte( CP_ACP, 0, (LPWSTR)lpnt40->awchCmdLine, -1, lpPrg->achCmdLine, ARRAYSIZE( lpPrg->achCmdLine ), NULL, NULL );
|
|
|
|
i = 0;
|
|
(*sfnIp.lpIpGetIntField)(&InfContext, APPSINF_NOWORKDIR, &i);
|
|
|
|
// Only set the working directory if "NoWorkDir" in the INF
|
|
// is FALSE and no working directory was supplied by the caller.
|
|
|
|
if (i == 0 && !lpnt40->awchWorkDir[0]) {
|
|
// No hard-coded working directory, so let's provide one
|
|
|
|
InitWorkDir(ppl, lpPrg, lpnt40);
|
|
}
|
|
|
|
szTmp[0] = 0;
|
|
sfnIp.lpIpGetStringField(&InfContext, APPSINF_ICONFILE, szTmp, ARRAYSIZE(szTmp), &dwSize);
|
|
|
|
if (!szTmp[0])
|
|
lstrcpy(szTmp, TEXT("SHELL32.DLL"));
|
|
|
|
i = 0;
|
|
sfnIp.lpIpGetIntField(&InfContext, APPSINF_ICONINDEX, &i);
|
|
|
|
// Update the icon info now, if it's valid
|
|
|
|
if (i != 0) {
|
|
lstrcpy((LPWSTR)lpnt40->awchIconFile, szTmp);
|
|
WideCharToMultiByte( CP_ACP, 0, (LPWSTR)lpnt40->awchIconFile, -1, lpPrg->achIconFile, ARRAYSIZE( lpPrg->achIconFile ), NULL, NULL );
|
|
lpPrg->wIconIndex = (WORD) i;
|
|
}
|
|
|
|
(*sfnIp.lpIpGetStringField)(&InfContext, APPSINF_SECTIONID,
|
|
szPIFSection, ARRAYSIZE(szPIFSection), &dwSize);
|
|
|
|
szTmp[0] = TEXT('\0');
|
|
(*sfnIp.lpIpGetStringField)(&InfContext, APPSINF_NOPIF,
|
|
szTmp, ARRAYSIZE(szTmp), &dwSize);
|
|
|
|
// This code used to set INHBITPIF if the app was NOT on a
|
|
// fixed disk, knowing that we would otherwise try to create
|
|
// a PIF in the PIF directory instead of the app's directory;
|
|
// in other words, NOPIF really meant "no PIF in the PIF
|
|
// directory please, because this app is ambiguously named".
|
|
|
|
// Now, we want to always allow PIF creation, so the user
|
|
// always has a place to save properties for an app. But we
|
|
// also need to propagate the old NOPIF flag to AMBIGUOUSPIF,
|
|
// so that we'll always check to see if the PIF should be
|
|
// regenerated (based on the presence of a NEW Other File).
|
|
|
|
lpPrg->flPrgInit &= ~PRGINIT_AMBIGUOUSPIF;
|
|
if (!fNotAmbiguous && szTmp[0] == TEXT('1'))
|
|
lpPrg->flPrgInit |= PRGINIT_AMBIGUOUSPIF;
|
|
|
|
if (flOpt & OPENPROPS_FORCEREALMODE)
|
|
lpPrg->flPrgInit |= PRGINIT_REALMODE;
|
|
|
|
// Time to dirty those properties!
|
|
|
|
PifMgr_SetProperties(ppl, MAKELP(0,GROUP_PRG),
|
|
lpPrg, SIZEOF(*lpPrg), SETPROPS_CACHE);
|
|
PifMgr_SetProperties(ppl, MAKELP(0,GROUP_NT40),
|
|
lpnt40, SIZEOF(*lpnt40), SETPROPS_CACHE);
|
|
|
|
GetAppsInfSectionData(&InfContext, APPSINF_DEFAULT_SECTION, ppl);
|
|
|
|
if (*szPIFSection)
|
|
GetAppsInfSectionData(&InfContext, szPIFSection, ppl);
|
|
|
|
// Make a note that we found INF settings (appwiz cares)
|
|
|
|
ppl->flProp |= PROP_INFSETTINGS;
|
|
|
|
// GetAppsInfSectionData affects program props, so get fresh copy
|
|
|
|
PifMgr_GetProperties(ppl, MAKELP(0,GROUP_PRG),
|
|
lpPrg, SIZEOF(*lpPrg), GETPROPS_NONE);
|
|
|
|
// Now call appwiz in "silent configuration mode", to create the
|
|
// per-app config and autoexec images, if app runs in real mode;
|
|
// BUT don't do this if the caller (NOT the INF) specified no PIF,
|
|
// to avoid unwanted dialog boxes popping up from appwiz. Yes, I'm
|
|
// telling appwiz to be quiet, but sometimes he just can't contain
|
|
// himself (ie, silent configuration may not be possible given the
|
|
// the real-mode configuration required).
|
|
|
|
if (!(ppl->flProp & PROP_INHIBITPIF)) {
|
|
if (lpPrg->flPrgInit & PRGINIT_REALMODE)
|
|
AppWizard(NULL, ppl, WIZACTION_SILENTCONFIGPROP);
|
|
}
|
|
FlushPIFData(ppl, FALSE);
|
|
|
|
fSuccess++; // successful search
|
|
goto CloseInf;
|
|
}
|
|
|
|
} while ((*sfnIp.lpIpFindNextLine)(&InfContext, &InfContext));
|
|
|
|
CloseInf:
|
|
if (!hInf)
|
|
(*sfnIp.lpIpClose)(hinfApps);
|
|
|
|
CloseDLL:
|
|
FreeSetupxDll();
|
|
|
|
DllLoadFalied:
|
|
return fSuccess;
|
|
}
|
|
|
|
|
|
void GetAppsInfSectionData(PINFCONTEXT pInfContext, LPCTSTR lpszSection, PPROPLINK ppl)
|
|
{
|
|
int i, j, idKey;
|
|
LPSTDPIF lpstd;
|
|
LPW386PIF30 lp386;
|
|
LPWENHPIF40 lpenh;
|
|
TCHAR szVal[MAX_KEYVAL_SIZE];
|
|
TCHAR szVal2[MAX_KEYVAL_SIZE];
|
|
FunctionName(GetAppsInfSectionData);
|
|
|
|
if (!(*sfnIp.lpIpFindFirstLine)(pInfContext, lpszSection, NULL, NULL))
|
|
return;
|
|
|
|
ppl->cLocks++;
|
|
|
|
lpstd = (LPSTDPIF)ppl->lpPIFData;
|
|
|
|
// lp386 may or may not exist, but we'll create if not
|
|
|
|
lp386 = GetGroupData(ppl, szW386HDRSIG30, NULL, NULL);
|
|
if (!lp386) {
|
|
if (AddGroupData(ppl, szW386HDRSIG30, NULL, SIZEOF(W386PIF30))) {
|
|
lp386 = GetGroupData(ppl, szW386HDRSIG30, NULL, NULL);
|
|
if (!lp386)
|
|
goto UnlockPIF;
|
|
}
|
|
}
|
|
|
|
// lpenh may or may not exist, but we'll create if not
|
|
|
|
lpenh = GetGroupData(ppl, szWENHHDRSIG40, NULL, NULL);
|
|
if (!lpenh) {
|
|
if (AddGroupData(ppl, szWENHHDRSIG40, NULL, SIZEOF(WENHPIF40))) {
|
|
lpenh = GetGroupData(ppl, szWENHHDRSIG40, NULL, NULL);
|
|
if (!lpenh)
|
|
goto UnlockPIF;
|
|
}
|
|
}
|
|
|
|
do {
|
|
BYTE bInvert;
|
|
DWORD dwSize;
|
|
|
|
idKey = GetKeyID(pInfContext);
|
|
|
|
if (!(*sfnIp.lpIpGetStringField)(pInfContext, APPSINF_KEYVAL, szVal, ARRAYSIZE(szVal), &dwSize))
|
|
continue;
|
|
|
|
szVal2[0] = TEXT('\0');
|
|
if (idKey >= KEYID_LOWMEM && idKey <= KEYID_DPMIMEM)
|
|
(*sfnIp.lpIpGetStringField)(pInfContext, APPSINF_KEYVAL2, szVal2, ARRAYSIZE(szVal2), &dwSize);
|
|
|
|
bInvert = 0;
|
|
|
|
switch (idKey)
|
|
{
|
|
case KEYID_UNKNOWN:
|
|
ASSERTFAIL();
|
|
break;
|
|
|
|
case KEYID_NONE:
|
|
break;
|
|
|
|
case KEYID_PARAMS:
|
|
{
|
|
WCHAR szTmp[ ARRAYSIZE(lp386->PfW386params) ];
|
|
|
|
MultiByteToWideChar( CP_ACP, 0, (LPSTR)lp386->PfW386params, -1, szTmp, ARRAYSIZE(szTmp) );
|
|
(*sfnIp.lpIpGetStringField)(pInfContext, APPSINF_KEYVAL, szTmp, SIZEOF(lp386->PfW386params), &dwSize);
|
|
}
|
|
|
|
break;
|
|
|
|
case KEYID_BATCHFILE:
|
|
break;
|
|
|
|
case KEYID_LOWMEM:
|
|
if (!lstrcmpi(szVal, g_szAuto))
|
|
lp386->PfW386minmem = 0xFFFF;
|
|
else
|
|
lp386->PfW386minmem = (WORD) StrToInt(szVal);
|
|
|
|
if (!szVal2[0])
|
|
lp386->PfW386maxmem = 0xFFFF;
|
|
else
|
|
lp386->PfW386maxmem = (WORD) StrToInt(szVal2);
|
|
break;
|
|
|
|
case KEYID_EMSMEM:
|
|
if (!lstrcmpi(szVal, g_szNone)) {
|
|
lp386->PfMaxEMMK = lp386->PfMinEMMK = 0;
|
|
}
|
|
if (!lstrcmpi(szVal, g_szAuto)) {
|
|
lp386->PfMinEMMK = 0;
|
|
lp386->PfMaxEMMK = 0xFFFF;
|
|
}
|
|
else
|
|
lp386->PfMaxEMMK = lp386->PfMinEMMK = (WORD) StrToInt(szVal);
|
|
|
|
if (szVal2[0])
|
|
lp386->PfMaxEMMK = (WORD) StrToInt(szVal2);
|
|
break;
|
|
|
|
case KEYID_XMSMEM:
|
|
if (!lstrcmpi(szVal, g_szNone)) {
|
|
lp386->PfMaxXmsK = lp386->PfMinXmsK = 0;
|
|
}
|
|
if (!lstrcmpi(szVal, g_szAuto)) {
|
|
lp386->PfMinXmsK = 0;
|
|
lp386->PfMaxXmsK = 0xFFFF;
|
|
}
|
|
else
|
|
lp386->PfMaxXmsK = lp386->PfMinXmsK = (WORD) StrToInt(szVal);
|
|
|
|
if (szVal2[0])
|
|
lp386->PfMaxXmsK = (WORD) StrToInt(szVal2);
|
|
break;
|
|
|
|
case KEYID_DPMIMEM:
|
|
if (!lstrcmpi(szVal, g_szAuto))
|
|
lpenh->envProp.wMaxDPMI = 0;
|
|
else
|
|
lpenh->envProp.wMaxDPMI = (WORD) StrToInt(szVal);
|
|
break;
|
|
|
|
case KEYID_DISABLE:
|
|
bInvert = 0x80;
|
|
// fall into KEYID_ENABLE...
|
|
|
|
case KEYID_ENABLE:
|
|
for (i=1; 0 != (j = GetKeyValID(pInfContext, i)); i++)
|
|
{
|
|
int s;
|
|
BYTE b;
|
|
|
|
if (j == KEYVAL_ID_UNKNOWN) {
|
|
ASSERTFAIL();
|
|
continue;
|
|
}
|
|
|
|
if (j == KEYVAL_ID_UNIQUESETTINGS) {
|
|
continue;
|
|
}
|
|
|
|
j--;
|
|
|
|
if (j < ARRAYSIZE(abKeyValIDBits)) {
|
|
|
|
b = abKeyValIDBits[j];
|
|
|
|
s = b & 0x3F;
|
|
b ^= bInvert;
|
|
if (!(b & 0x80)) {
|
|
if (!(b & 0x40)) {
|
|
lp386->PfW386Flags |= 1L << s;
|
|
}
|
|
else
|
|
lp386->PfW386Flags2 |= 1L << s;
|
|
}
|
|
else {
|
|
if (!(b & 0x40))
|
|
lp386->PfW386Flags &= ~(1L << s);
|
|
else
|
|
lp386->PfW386Flags2 &= ~(1L << s);
|
|
}
|
|
}
|
|
else {
|
|
j -= ARRAYSIZE(abKeyValIDBits);
|
|
|
|
if (j < ARRAYSIZE(abRMKeyValIDBits)) {
|
|
|
|
b = abRMKeyValIDBits[j];
|
|
|
|
s = b & 0x3F;
|
|
b ^= bInvert;
|
|
|
|
if (!(b & 0x80))
|
|
lpenh->dwRealModeFlagsProp |= 1L << s;
|
|
else
|
|
lpenh->dwRealModeFlagsProp &= ~(1L << s);
|
|
}
|
|
else {
|
|
j -= ARRAYSIZE(abRMKeyValIDBits);
|
|
|
|
switch(j) {
|
|
case 0: // special case 0
|
|
if (!bInvert)
|
|
lpstd->MSflags |= EXITMASK;
|
|
else
|
|
lpstd->MSflags &= ~EXITMASK;
|
|
break;
|
|
|
|
case 1: // special case 1
|
|
if (bInvert)
|
|
lpenh->tskProp.flTsk |= TSK_NOSCREENSAVER;
|
|
else
|
|
lpenh->tskProp.flTsk &= ~TSK_NOSCREENSAVER;
|
|
break;
|
|
|
|
default:
|
|
ASSERTFAIL();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
} while ((*sfnIp.lpIpFindNextLine)(pInfContext, pInfContext));
|
|
|
|
UnlockPIF:
|
|
ppl->cLocks--;
|
|
|
|
}
|
|
|
|
|
|
int GetKeyID(PINFCONTEXT pInfContext)
|
|
{
|
|
int i;
|
|
TCHAR szCurKey[MAX_KEY_SIZE];
|
|
DWORD dwSize;
|
|
FunctionName(GetKeyID);
|
|
|
|
if ((*sfnIp.lpIpGetStringField)(pInfContext, APPSINF_KEY, szCurKey, ARRAYSIZE(szCurKey), &dwSize)) {
|
|
for (i=0; i<ARRAYSIZE(apszKey); i++) {
|
|
if (!lstrcmpi(szCurKey, apszKey[i]))
|
|
return i+1;
|
|
}
|
|
return KEYID_UNKNOWN;
|
|
}
|
|
return KEYID_NONE;
|
|
}
|
|
|
|
|
|
int GetKeyValID(PINFCONTEXT pInfContext, int i)
|
|
{
|
|
TCHAR szCurKeyVal[MAX_KEYVAL_SIZE];
|
|
DWORD dwSize;
|
|
FunctionName(GetKeyValID);
|
|
|
|
if ((*sfnIp.lpIpGetStringField)(pInfContext, i, szCurKeyVal, ARRAYSIZE(szCurKeyVal), &dwSize)) {
|
|
for (i=0; i<ARRAYSIZE(apszKeyVal); i++) {
|
|
if (!lstrcmpi(szCurKeyVal, apszKeyVal[i]))
|
|
return i+1;
|
|
}
|
|
return KEYVAL_ID_UNKNOWN;
|
|
}
|
|
return KEYVAL_ID_NONE;
|
|
}
|
|
|
|
DWORD GetSettingsFlags(PINFCONTEXT pInfContext, LPCTSTR lpszSection)
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
BOOL Initialize1AppReg(HWND hwndParent)
|
|
{
|
|
BOOL fSuccess = FALSE; // Assume failure
|
|
TCHAR szTmp[MAX_PATH];
|
|
HINF hinfApps;
|
|
HKEY hk1App;
|
|
INFCONTEXT InfContext;
|
|
|
|
if (!InitSetupxDll()) {
|
|
goto DllLoadFailed;
|
|
}
|
|
|
|
|
|
hinfApps = (*sfnIp.lpIpOpen)(LoadStringSafe(NULL,
|
|
IDS_APPSINF,
|
|
szTmp,
|
|
ARRAYSIZE(szTmp)),
|
|
0, INF_STYLE_WIN4, NULL );
|
|
|
|
if (hinfApps==INVALID_HANDLE_VALUE) {
|
|
int id = IDS_CANTOPENAPPSINF;
|
|
if (GetLastError()==ERROR_FILE_NOT_FOUND)
|
|
id = IDS_NOAPPSINF;
|
|
Warning(hwndParent, (WORD)id, MB_ICONEXCLAMATION | MB_OK | MB_NOFOCUS);
|
|
goto CloseDLL;
|
|
}
|
|
|
|
// OK, now we have APPS.INF open, so let's find [PIF95]
|
|
|
|
if (!(*sfnIp.lpIpFindFirstLine)(hinfApps, TEXT("pif95"), NULL, &InfContext)) {
|
|
Warning(hwndParent, IDS_APPSINFERROR, MB_ICONEXCLAMATION | MB_OK | MB_NOFOCUS);
|
|
goto CloseInf;
|
|
}
|
|
|
|
// OK, we've found the [pif95] section, so now we'll create the reg branch
|
|
|
|
//
|
|
// Always start with a clean slate!
|
|
//
|
|
RegDeleteKey(HKEY_LOCAL_MACHINE, szRegKeyMSDOSApps);
|
|
|
|
if (RegCreateKey(HKEY_LOCAL_MACHINE, szRegKeyMSDOSApps, &hk1App) !=
|
|
ERROR_SUCCESS) {
|
|
goto CloseInf;
|
|
}
|
|
|
|
do {
|
|
DWORD dwSettings;
|
|
DWORD dwSize;
|
|
TCHAR szSectionName[MAX_KEY_SIZE];
|
|
if (!(*sfnIp.lpIpGetStringField)(&InfContext, APPSINF_FILENAME,
|
|
szTmp, ARRAYSIZE(szTmp), &dwSize)) {
|
|
continue;
|
|
}
|
|
(*sfnIp.lpIpGetStringField)(&InfContext, APPSINF_SECTIONID,
|
|
szSectionName, ARRAYSIZE(szSectionName), &dwSize);
|
|
dwSettings = GetSettingsFlags(&InfContext, szSectionName);
|
|
if (dwSettings) {
|
|
HKEY hkThisApp;
|
|
if (RegCreateKey(hk1App, szTmp, &hkThisApp) == ERROR_SUCCESS) {
|
|
(*sfnIp.lpIpGetStringField)(&InfContext, APPSINF_OTHERFILE,
|
|
szTmp, ARRAYSIZE(szTmp), &dwSize);
|
|
if (szTmp[0] == 0) {
|
|
(*sfnIp.lpIpGetStringField)(&InfContext, APPSINF_FILENAME,
|
|
szTmp, ARRAYSIZE(szTmp), &dwSize);
|
|
}
|
|
RegSetValueEx(hkThisApp, szTmp, 0, REG_BINARY, (LPSTR)&dwSettings, sizeof(dwSettings));
|
|
RegCloseKey(hkThisApp);
|
|
}
|
|
}
|
|
} while ((*sfnIp.lpIpFindNextLine)(&InfContext, &InfContext));
|
|
fSuccess = TRUE;
|
|
|
|
RegCloseKey(hk1App);
|
|
CloseInf:
|
|
(*sfnIp.lpIpClose)(hinfApps);
|
|
CloseDLL:
|
|
FreeSetupxDll();
|
|
DllLoadFailed:
|
|
return(fSuccess);
|
|
}
|
|
|
|
//
|
|
// A RUNDLL entry point that is called at boot time to initialize the registry.
|
|
//
|
|
void WINAPI InitPIFRegEntries(HWND hwnd, HINSTANCE hAppInstance, LPSTR lpszCmdLine, int nCmdShow)
|
|
{
|
|
Initialize1AppReg(hwnd);
|
|
}
|