659 lines
15 KiB
C
659 lines
15 KiB
C
/*
|
|
* Microsoft Confidential
|
|
* Copyright (C) Microsoft Corporation 1991
|
|
* All Rights Reserved.
|
|
*
|
|
*
|
|
* PIFLIB.C
|
|
* User interface routines for PIFMGR.DLL
|
|
*
|
|
* History:
|
|
* Created 31-Jul-1992 3:30pm by Jeff Parsons
|
|
*/
|
|
|
|
#include "shellprv.h"
|
|
#pragma hdrstop
|
|
|
|
|
|
#define LIB_SIG 0x504A
|
|
|
|
#define LIB_DEFER LOADPROPLIB_DEFER
|
|
|
|
typedef struct LIBLINK { /* ll */
|
|
struct LIBLINK *pllNext; //
|
|
struct LIBLINK *pllPrev; //
|
|
int iSig; // liblink signature
|
|
int flLib; // proplink flags (LIB_*)
|
|
HINSTANCE hDLL; // if NULL, then load has been deferred
|
|
TCHAR achDLL[80]; // name of DLL
|
|
} LIBLINK;
|
|
typedef LIBLINK *PLIBLINK;
|
|
|
|
|
|
#define SHEET_SIG 0x504A
|
|
|
|
typedef struct SHEETLINK { /* sl */
|
|
struct SHEETLINK *pslNext;
|
|
struct SHEETLINK *pslPrev;
|
|
int iSig;
|
|
int iType;
|
|
PROPSHEETPAGE psi;
|
|
} SHEETLINK;
|
|
typedef SHEETLINK *PSHEETLINK;
|
|
|
|
|
|
UINT cEdits; // number of edit sessions in progress
|
|
|
|
PLIBLINK pllHead; // pointer to first lib link
|
|
HANDLE offHighestLibLink; // highest offset of a lib link thus far recorded
|
|
|
|
PSHEETLINK pslHead; // pointer to first sheet link
|
|
UINT cSheetLinks; // number of sheet links
|
|
HANDLE offHighestSheetLink; // highest offset of a sheet link thus far recorded
|
|
|
|
|
|
struct { // built-in property sheet info
|
|
LPCTSTR lpTemplateName;
|
|
DLGPROC lpfnDlgProc;
|
|
int iType;
|
|
} const aPSInfo[] = {
|
|
{ MAKEINTRESOURCE(IDD_PROGRAM), DlgPrgProc, SHEETTYPE_SIMPLE},
|
|
{ MAKEINTRESOURCE(IDD_FONT), DlgFntProc, SHEETTYPE_SIMPLE},
|
|
{ MAKEINTRESOURCE(IDD_MEMORY), DlgMemProc, SHEETTYPE_SIMPLE},
|
|
{ MAKEINTRESOURCE(IDD_SCREEN), DlgVidProc, SHEETTYPE_SIMPLE},
|
|
{ MAKEINTRESOURCE(IDD_MISC), DlgMscProc, SHEETTYPE_SIMPLE},
|
|
};
|
|
|
|
|
|
/** LoadPropertyLib - load new property library
|
|
*
|
|
* INPUT
|
|
* lpszDLL -> name of DLL
|
|
* fLoad == flags (see LOADPROPLIB_*)
|
|
*
|
|
* OUTPUT
|
|
* handle to property library if loaded, FALSE if not
|
|
*/
|
|
|
|
HANDLE WINAPI LoadPropertyLib(LPCTSTR lpszDLL, int fLoad)
|
|
{
|
|
HINSTANCE hDLL;
|
|
register PLIBLINK pll;
|
|
FunctionName(LoadPropertyLib);
|
|
|
|
hDLL = NULL;
|
|
if (!(fLoad & LOADPROPLIB_DEFER)) {
|
|
|
|
hDLL = LoadLibrary(lpszDLL);
|
|
|
|
if (hDLL < (HINSTANCE)HINSTANCE_ERROR)
|
|
return FALSE;
|
|
}
|
|
|
|
// Allocate new lib link
|
|
|
|
if (!(pll = (PLIBLINK)LocalAlloc(LPTR, SIZEOF(LIBLINK))))
|
|
return FALSE;
|
|
|
|
if ((HANDLE) pll > offHighestLibLink)
|
|
offHighestLibLink = pll;
|
|
|
|
// Initialize the lib link
|
|
|
|
pll->pllPrev = NULL;
|
|
pll->iSig = LIB_SIG;
|
|
pll->hDLL = hDLL;
|
|
pll->flLib = 0;
|
|
if (!hDLL)
|
|
pll->flLib |= LIB_DEFER;
|
|
lstrcpyn(pll->achDLL, lpszDLL, ARRAYSIZE(pll->achDLL));
|
|
|
|
// Link into the global lib list
|
|
|
|
if (NULL != (pll->pllNext = pllHead))
|
|
pllHead->pllPrev = pll;
|
|
pllHead = pll;
|
|
|
|
return pll;
|
|
}
|
|
|
|
|
|
/** EnumPropertyLibs - enumerate property libraries
|
|
*
|
|
* INPUT
|
|
* iLib == 0 to begin enumeration, or result of previous call
|
|
* lphDLL -> where to store handle (NULL if don't care)
|
|
* lpszDLL -> where to store name of library (NULL if don't care)
|
|
* cchszDLL == size of space (in chars) to store name
|
|
*
|
|
* OUTPUT
|
|
* lphDLL and lpszDLL filled in as appropriate, 0 if no more libs (or error)
|
|
*/
|
|
|
|
HANDLE WINAPI EnumPropertyLibs(HANDLE iLib, LPHANDLE lphDLL, LPTSTR lpszDLL, int cchszDLL)
|
|
{
|
|
register PLIBLINK pll;
|
|
FunctionName(EnumPropertyLibs);
|
|
|
|
if (!iLib)
|
|
pll = pllHead;
|
|
else
|
|
pll = ((PLIBLINK)iLib)->pllNext;
|
|
|
|
// Validate the handle
|
|
|
|
if (!pll)
|
|
return 0;
|
|
|
|
if ((HANDLE) pll > offHighestLibLink)
|
|
return 0;
|
|
|
|
if (pll->iSig != LIB_SIG)
|
|
return 0;
|
|
|
|
if (lphDLL)
|
|
*lphDLL = pll->hDLL;
|
|
|
|
if (lpszDLL)
|
|
lstrcpyn(lpszDLL, pll->achDLL, min(cchszDLL, ARRAYSIZE(pll->achDLL)));
|
|
|
|
return pll;
|
|
}
|
|
|
|
|
|
/** FreePropertyLib - free installable property library
|
|
*
|
|
* INPUT
|
|
* hLib == handle to property library
|
|
*
|
|
* OUTPUT
|
|
* TRUE if successful, FALSE otherwise
|
|
*/
|
|
|
|
BOOL WINAPI FreePropertyLib(HANDLE hLib)
|
|
{
|
|
register PLIBLINK pll;
|
|
FunctionName(FreePropertyLib);
|
|
|
|
// Validate the handle
|
|
|
|
if (!hLib)
|
|
return FALSE;
|
|
|
|
if ((HANDLE)hLib > offHighestLibLink)
|
|
return FALSE;
|
|
|
|
pll = (PLIBLINK)hLib;
|
|
|
|
if (pll->iSig != LIB_SIG)
|
|
return FALSE;
|
|
|
|
// Free the associated library
|
|
|
|
if (pll->hDLL)
|
|
FreeLibrary(pll->hDLL);
|
|
|
|
// Unlink from the global list
|
|
|
|
if (pll->pllPrev)
|
|
pll->pllPrev->pllNext = pll->pllNext;
|
|
else
|
|
pllHead = pll->pllNext;
|
|
|
|
if (pll->pllNext)
|
|
pll->pllNext->pllPrev = pll->pllPrev;
|
|
|
|
EVAL(LocalFree(pll) == NULL);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/** AddPropertySheet - install new property sheet
|
|
*
|
|
* INPUT
|
|
* lppsi -> property sheet info structure
|
|
* iType == sheet type (see SHEETTYPE_* constants)
|
|
*
|
|
* OUTPUT
|
|
* handle to property sheet link, or NULL if failure
|
|
*/
|
|
|
|
HANDLE WINAPI AddPropertySheet(const PROPSHEETPAGE *lppsi, int iType)
|
|
{
|
|
register PSHEETLINK psl;
|
|
FunctionName(AddPropertySheet);
|
|
|
|
// Allocate new sheet link
|
|
|
|
if (!(psl = (PSHEETLINK)LocalAlloc(LPTR, SIZEOF(SHEETLINK))))
|
|
return FALSE;
|
|
|
|
if ((HANDLE) psl > offHighestSheetLink)
|
|
offHighestSheetLink = psl;
|
|
|
|
// Initialize the sheet link
|
|
|
|
psl->pslPrev = NULL;
|
|
psl->iSig = SHEET_SIG;
|
|
psl->psi = *lppsi;
|
|
psl->iType = iType;
|
|
|
|
// Link into the global sheet list
|
|
|
|
if (NULL != (psl->pslNext = pslHead))
|
|
pslHead->pslPrev = psl;
|
|
pslHead = psl;
|
|
|
|
cSheetLinks++;
|
|
|
|
return psl;
|
|
}
|
|
|
|
|
|
/** RemovePropertySheet - remove installable property sheet
|
|
*
|
|
* INPUT
|
|
* hSheet == handle to sheet link
|
|
*
|
|
* OUTPUT
|
|
* TRUE if successful, FALSE otherwise
|
|
*/
|
|
|
|
BOOL WINAPI RemovePropertySheet(HANDLE hSheet)
|
|
{
|
|
register PSHEETLINK psl;
|
|
FunctionName(RemovePropertySheet);
|
|
|
|
// Validate the handle
|
|
|
|
if (!hSheet)
|
|
return FALSE;
|
|
|
|
if ((HANDLE)hSheet > offHighestSheetLink)
|
|
return FALSE;
|
|
|
|
psl = (PSHEETLINK)hSheet;
|
|
|
|
if (psl->iSig != SHEET_SIG)
|
|
return FALSE;
|
|
|
|
// Unlink from the global list
|
|
|
|
cSheetLinks--;
|
|
|
|
if (psl->pslPrev)
|
|
psl->pslPrev->pslNext = psl->pslNext;
|
|
else
|
|
pslHead = psl->pslNext;
|
|
|
|
if (psl->pslNext)
|
|
psl->pslNext->pslPrev = psl->pslPrev;
|
|
|
|
EVAL(LocalFree(psl) == NULL);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/** LoadPropertySheets - load property sheets
|
|
*
|
|
* INPUT
|
|
* hProps = property handle
|
|
* flags = 0 (reserved)
|
|
*
|
|
* OUTPUT
|
|
* # of sheets loaded, 0 if error
|
|
*/
|
|
|
|
int WINAPI LoadPropertySheets(HANDLE hProps, int flags)
|
|
{
|
|
register PLIBLINK pll;
|
|
FunctionName(LoadPropertySheets);
|
|
|
|
// If this is the first edit session, do global init now
|
|
|
|
if (cEdits++ == 0)
|
|
if (!LoadGlobalEditData())
|
|
return 0;
|
|
|
|
pll = NULL;
|
|
while (NULL != (pll = (PLIBLINK)EnumPropertyLibs(pll, NULL, NULL, 0))) {
|
|
if (!pll->hDLL && (pll->flLib & LIB_DEFER)) {
|
|
|
|
pll->hDLL = LoadLibrary(pll->achDLL);
|
|
|
|
// If the load failed, to us that simply means those sheets
|
|
// will not be available; the particular error is not interesting,
|
|
// so nullify the handle
|
|
|
|
if (pll->hDLL < (HINSTANCE)HINSTANCE_ERROR)
|
|
pll->hDLL = NULL;
|
|
}
|
|
}
|
|
return cSheetLinks + ARRAYSIZE(aPSInfo);
|
|
}
|
|
|
|
|
|
/** EnumPropertySheets - enumerate property sheets
|
|
*
|
|
* INPUT
|
|
* hProps == property handle
|
|
* iType == sheet type (see SHEETTYPE_* constants)
|
|
* iSheet == 0 to begin enumeration, or result of previous call
|
|
* lppsi -> property sheet info structure to be filled in
|
|
*
|
|
* OUTPUT
|
|
* lppsi filled in as appropriate, 0 if no more sheets (or error)
|
|
*/
|
|
|
|
INT_PTR WINAPI EnumPropertySheets(HANDLE hProps, int iType, INT_PTR iSheet, LPPROPSHEETPAGE lppsp)
|
|
{
|
|
register PSHEETLINK psl;
|
|
FunctionName(EnumPropertySheets);
|
|
|
|
while (iSheet < ARRAYSIZE(aPSInfo)) {
|
|
if (aPSInfo[iSheet].iType <= iType) {
|
|
if (lppsp) {
|
|
lppsp->dwSize = SIZEOF(PROPSHEETPAGE);
|
|
lppsp->dwFlags = PSP_DEFAULT;
|
|
lppsp->hInstance = HINST_THISDLL;
|
|
lppsp->pszTemplate = aPSInfo[iSheet].lpTemplateName;
|
|
lppsp->pfnDlgProc = aPSInfo[iSheet].lpfnDlgProc;
|
|
// lppsp->pszTitle = NULL;
|
|
lppsp->lParam = (LONG_PTR)hProps;
|
|
}
|
|
return ++iSheet;
|
|
}
|
|
++iSheet;
|
|
}
|
|
if (iSheet == ARRAYSIZE(aPSInfo))
|
|
psl = pslHead;
|
|
else
|
|
psl = ((PSHEETLINK)iSheet)->pslNext;
|
|
|
|
// Validate the handle
|
|
|
|
while (psl && (HANDLE) psl <= offHighestSheetLink && psl->iSig == SHEET_SIG) {
|
|
|
|
if (psl->iType <= iType) {
|
|
|
|
*lppsp = psl->psi;
|
|
lppsp->lParam = (LONG_PTR)hProps;
|
|
|
|
return (INT_PTR) psl;
|
|
}
|
|
psl = psl->pslNext;
|
|
}
|
|
return 0; // no more matching sheets
|
|
}
|
|
|
|
|
|
/** FreePropertySheets - free property sheets
|
|
*
|
|
* INPUT
|
|
* hProps = property handle
|
|
* flags = 0 (reserved)
|
|
*
|
|
* OUTPUT
|
|
* Nothing
|
|
*/
|
|
|
|
HANDLE WINAPI FreePropertySheets(HANDLE hProps, int flags)
|
|
{
|
|
register PLIBLINK pll;
|
|
FunctionName(FreePropertySheets);
|
|
|
|
pll = NULL;
|
|
while (NULL != (pll = (PLIBLINK)EnumPropertyLibs(pll, NULL, NULL, 0))) {
|
|
if (pll->hDLL && (pll->flLib & LIB_DEFER)) {
|
|
FreeLibrary(pll->hDLL);
|
|
pll->hDLL = NULL;
|
|
}
|
|
}
|
|
// If this is the last edit session, do global un-init now
|
|
|
|
if (--cEdits == 0)
|
|
FreeGlobalEditData();
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/** InitRealModeFlag - Initialize PROP_REALMODE
|
|
*
|
|
* INPUT
|
|
* ppl = properties
|
|
*
|
|
* OUTPUT
|
|
* ppl->flProp PROP_REALMODE bit set if sheet is for real-mode app,
|
|
* else clear.
|
|
*/
|
|
|
|
void InitRealModeFlag(PPROPLINK ppl)
|
|
{
|
|
PROPPRG prg;
|
|
|
|
if (!PifMgr_GetProperties(ppl, MAKELP(0,GROUP_PRG),
|
|
&prg, SIZEOF(prg), GETPROPS_NONE)) {
|
|
return; /* Weird */
|
|
}
|
|
if (prg.flPrgInit & PRGINIT_REALMODE) {
|
|
ppl->flProp |= PROP_REALMODE;
|
|
} else {
|
|
ppl->flProp &= ~PROP_REALMODE;
|
|
}
|
|
}
|
|
|
|
|
|
/** EditProperties - edit property info
|
|
*
|
|
* INPUT
|
|
* hProps = handle to properties
|
|
* lpszTitle = pointer to title to use (NULL if none)
|
|
* uStartPage = starting property sheet #
|
|
* hwnd = handle to window of parent (NULL if none)
|
|
* uMsgPost = msg # to post to hwnd with change notification (0 if none)
|
|
*
|
|
* OUTPUT
|
|
* TRUE if successful, FALSE otherwise
|
|
*/
|
|
|
|
int WINAPI EditProperties(HANDLE hProps, LPCTSTR lpszTitle, UINT uStartPage, HWND hwnd, UINT uMsgPost)
|
|
{
|
|
int cSheets;
|
|
INT_PTR iSheet;
|
|
PPROPLINK ppl;
|
|
PROPSHEETHEADER psh;
|
|
PROPSHEETPAGE *ppsp;
|
|
register PSHEETLINK psl;
|
|
FunctionName(EditProperties);
|
|
|
|
if (!(ppl = ValidPropHandle(hProps)))
|
|
return FALSE;
|
|
|
|
if (hwnd && uMsgPost) {
|
|
ppl->hwndNotify = hwnd;
|
|
ppl->uMsgNotify = uMsgPost;
|
|
}
|
|
cSheets = LoadPropertySheets(hProps, 0);
|
|
|
|
psl = pslHead;
|
|
if (!(ppsp = (PROPSHEETPAGE *)LocalAlloc(LPTR, cSheets*SIZEOF(PROPSHEETPAGE))))
|
|
return FALSE;
|
|
|
|
psh.dwSize = SIZEOF(psh);
|
|
psh.dwFlags = PSH_PROPTITLE | PSH_PROPSHEETPAGE;
|
|
psh.hwndParent = hwnd;
|
|
if (!lpszTitle)
|
|
psh.pszCaption = ppl->szPathName+ppl->iFileName;
|
|
else
|
|
psh.pszCaption = ppl->lpszTitle = lpszTitle;
|
|
psh.nPages = 0;
|
|
psh.nStartPage = uStartPage;
|
|
psh.ppsp = ppsp;
|
|
|
|
iSheet = cSheets = 0;
|
|
|
|
while (0 != (iSheet = EnumPropertySheets(hProps, SHEETTYPE_SIMPLE, iSheet, ppsp))) {
|
|
cSheets++;
|
|
ppsp++;
|
|
}
|
|
psh.nPages = cSheets;
|
|
|
|
// Since the user wishes to *explicitly* change settings for this app
|
|
// we make sure that the DONTWRITE flag isn't going to get in his way...
|
|
|
|
ppl->flProp &= ~PROP_DONTWRITE;
|
|
|
|
InitRealModeFlag(ppl);
|
|
|
|
PropertySheet(&psh);
|
|
|
|
VERIFYFALSE(LocalFree((HLOCAL)psh.ppsp));
|
|
|
|
FreePropertySheets(hProps, 0);
|
|
|
|
if (ppl->flProp & PROP_NOTIFY) {
|
|
ppl->flProp &= ~PROP_NOTIFY;
|
|
PostMessage(ppl->hwndNotify, ppl->uMsgNotify, 0, 0);
|
|
}
|
|
ppl->hwndNotify = NULL;
|
|
ppl->uMsgNotify = 0;
|
|
ppl->lpszTitle = NULL;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL LoadGlobalEditData()
|
|
{
|
|
FunctionName(LoadGlobalEditData);
|
|
|
|
if (!LoadGlobalFontEditData())
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
void FreeGlobalEditData()
|
|
{
|
|
FunctionName(FreeGlobalEditData);
|
|
FreeGlobalFontEditData();
|
|
}
|
|
|
|
|
|
UINT CALLBACK PifPropPageRelease(HWND hwnd, UINT uMsg, LPPROPSHEETPAGE lppsp)
|
|
{
|
|
FunctionName(PifPropPageRelease);
|
|
|
|
if (uMsg == PSPCB_RELEASE) {
|
|
PPROPLINK ppl = (PPROPLINK)(INT_PTR)lppsp->lParam;
|
|
|
|
if ((--ppl->iSheetUsage) == 0) {
|
|
|
|
FreePropertySheets(ppl, 0);
|
|
|
|
PifMgr_CloseProperties(ppl, CLOSEPROPS_NONE);
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
#define MZMAGIC ((WORD)'M'+((WORD)'Z'<<8))
|
|
|
|
//
|
|
// call SHELL.DLL to get the EXE type.
|
|
//
|
|
BOOL IsWinExe(LPCTSTR lpszFile)
|
|
{
|
|
DWORD dw = (DWORD) SHGetFileInfo(lpszFile, 0, NULL, 0, SHGFI_EXETYPE);
|
|
|
|
return dw && LOWORD(dw) != MZMAGIC;
|
|
}
|
|
|
|
BOOL WINAPI PifPropGetPages(LPVOID lpv,
|
|
LPFNADDPROPSHEETPAGE lpfnAddPage,
|
|
LPARAM lParam)
|
|
{
|
|
#define hDrop (HDROP)lpv
|
|
PPROPLINK ppl;
|
|
PROPSHEETPAGE psp;
|
|
int iType, cSheets;
|
|
INT_PTR iSheet;
|
|
HPROPSHEETPAGE hpage;
|
|
TCHAR szFileName[MAXPATHNAME];
|
|
FunctionName(PifPropGetPages);
|
|
|
|
// only process things if hDrop contains only one file
|
|
if (DragQueryFile(hDrop, (UINT)-1, NULL, 0) != 1)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
// get the name of the file
|
|
DragQueryFile(hDrop, 0, szFileName, ARRAYSIZE(szFileName));
|
|
|
|
if (GetFileAttributes( szFileName) & FILE_ATTRIBUTE_OFFLINE)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// if this is a windows app, don't do no properties
|
|
if (IsWinExe(szFileName))
|
|
return TRUE;
|
|
|
|
// if we can't get a property handle, don't do no properties either
|
|
if (!(ppl = (PPROPLINK)PifMgr_OpenProperties(szFileName, NULL, 0, OPENPROPS_NONE)))
|
|
return TRUE;
|
|
|
|
InitRealModeFlag(ppl);
|
|
|
|
if (!(cSheets = LoadPropertySheets(ppl, 0)))
|
|
goto CloseProps;
|
|
|
|
// Since the user wishes to *explicitly* change settings for this app
|
|
// we make sure that the DONTWRITE flag isn't going to get in his way...
|
|
|
|
ppl->flProp &= ~PROP_DONTWRITE;
|
|
|
|
iSheet = cSheets = 0;
|
|
iType = (GetKeyState(VK_CONTROL) >= 0? SHEETTYPE_SIMPLE : SHEETTYPE_ADVANCED);
|
|
|
|
while (TRUE) {
|
|
|
|
if (!(iSheet = EnumPropertySheets(ppl, iType, iSheet, &psp))) {
|
|
// done with enumeration
|
|
break;
|
|
}
|
|
psp.dwFlags |= PSP_USECALLBACK;
|
|
psp.pfnCallback = PifPropPageRelease;
|
|
psp.pcRefParent = 0;
|
|
|
|
hpage = CreatePropertySheetPage(&psp);
|
|
if (hpage)
|
|
{
|
|
// the PROPLINK is now being used by this property sheet as well
|
|
|
|
if (lpfnAddPage(hpage, lParam))
|
|
{
|
|
ppl->iSheetUsage++;
|
|
cSheets++;
|
|
}
|
|
else
|
|
{
|
|
PifPropPageRelease(NULL, PSPCB_RELEASE, &psp);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!cSheets) {
|
|
FreePropertySheets(ppl, 0);
|
|
|
|
CloseProps:
|
|
PifMgr_CloseProperties(ppl, CLOSEPROPS_NONE);
|
|
}
|
|
return TRUE;
|
|
}
|
|
#undef hDrop
|