|
|
/*
* 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
|