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