932 lines
28 KiB
C
932 lines
28 KiB
C
|
#include "ctlspriv.h"
|
||
|
#include "prshti.h"
|
||
|
|
||
|
#ifdef WX86
|
||
|
#include <wx86ofl.h>
|
||
|
#endif
|
||
|
|
||
|
#define _Rstrcpyn lstrcpyn
|
||
|
|
||
|
//
|
||
|
// Miracle of miracles - Win95 implements lstrlenW.
|
||
|
//
|
||
|
#define _Rstrlen lstrlenW
|
||
|
|
||
|
#define RESCHAR WCHAR
|
||
|
|
||
|
#include <pshpack2.h>
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
WORD wDlgVer;
|
||
|
WORD wSignature;
|
||
|
DWORD dwHelpID;
|
||
|
DWORD dwExStyle;
|
||
|
DWORD dwStyle;
|
||
|
WORD cDlgItems;
|
||
|
WORD x;
|
||
|
WORD y;
|
||
|
WORD cx;
|
||
|
WORD cy;
|
||
|
} DLGEXTEMPLATE, *LPDLGEXTEMPLATE;
|
||
|
|
||
|
#include <poppack.h> /* Resume normal packing */
|
||
|
|
||
|
//
|
||
|
// CallPropertyPageCallback
|
||
|
//
|
||
|
// Call the callback for the property page, passing it the correct lParam
|
||
|
// based on the character set it wants.
|
||
|
//
|
||
|
UINT CallPropertyPageCallback(PROPDATA* ppd, PISP pisp, UINT uMsg)
|
||
|
{
|
||
|
UINT uiResult = TRUE; // assume success
|
||
|
|
||
|
if (HASCALLBACK(pisp) &&
|
||
|
(pisp->_psp.dwSize > PROPSHEETPAGE_V1_SIZE ||
|
||
|
uMsg == PSPCB_CREATE || uMsg == PSPCB_RELEASE))
|
||
|
{
|
||
|
ULONG_PTR dwCookie = PropPageActivateContext(ppd, pisp);
|
||
|
|
||
|
if (HASANSISHADOW(pisp))
|
||
|
{
|
||
|
#ifdef WX86
|
||
|
if ( pisp->_pfx.dwInternalFlags & PSPI_WX86 )
|
||
|
uiResult = Wx86Callback(pisp->_psp.pfnCallback, NULL, uMsg, (LPARAM) &pisp->_cpfx.pispShadow->_psp);
|
||
|
else
|
||
|
#endif
|
||
|
uiResult = pisp->_psp.pfnCallback(NULL, uMsg, &pisp->_cpfx.pispShadow->_psp);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
#ifdef WX86
|
||
|
if ( pisp->_pfx.dwInternalFlags & PSPI_WX86 )
|
||
|
uiResult = Wx86Callback(pisp->_psp.pfnCallback, NULL, uMsg, (LPARAM) &pisp->_psp);
|
||
|
else
|
||
|
#endif
|
||
|
uiResult = pisp->_psp.pfnCallback(NULL, uMsg, &pisp->_psp);
|
||
|
}
|
||
|
|
||
|
PropPageDeactivateContext(dwCookie);
|
||
|
|
||
|
}
|
||
|
return uiResult;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// FreePropertyPageStruct
|
||
|
//
|
||
|
// Free the memory block that contains a property sheet page.
|
||
|
// It is the caller's responsibility to have freed all the things
|
||
|
// that were attached to it.
|
||
|
//
|
||
|
//
|
||
|
__inline void FreePropertyPageStruct(PISP pisp)
|
||
|
{
|
||
|
LocalFree(PropSheetBase(pisp));
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// DestroyPropertySheetPage
|
||
|
//
|
||
|
// Do the appropriate thing to destroy a property sheet page, whether
|
||
|
// this entails talking to 16-bit thunks, sending the PSPCB_RELEASE,
|
||
|
// or freeing the shadow page.
|
||
|
//
|
||
|
BOOL WINAPI DestroyPropertySheetPage(HPROPSHEETPAGE hpage)
|
||
|
{
|
||
|
PISP pisp = InternalizeHPROPSHEETPAGE(hpage);
|
||
|
|
||
|
CallPropertyPageCallback(NULL, pisp, PSPCB_RELEASE);
|
||
|
|
||
|
// Do the decrement *after* calling the callback for the last time
|
||
|
|
||
|
if (HASREFPARENT(pisp))
|
||
|
InterlockedDecrement((LPLONG)pisp->_psp.pcRefParent);
|
||
|
|
||
|
if (HASANSISHADOW(pisp))
|
||
|
{
|
||
|
FreePropertyPageStrings(&pisp->_cpfx.pispShadow->_psp);
|
||
|
FreePropertyPageStruct(pisp->_cpfx.pispShadow);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Note that FreePropertyPageStrings will try to destroy strings for
|
||
|
// proxy pages, but that's okay, because the corresponding P_pszBlah
|
||
|
// fields are all NULL since we never initialized them.
|
||
|
//
|
||
|
FreePropertyPageStrings(&pisp->_psp);
|
||
|
FreePropertyPageStruct(pisp);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// GetPageInfoEx
|
||
|
//
|
||
|
// Extract information about a page into a PAGEINFOEX structure.
|
||
|
//
|
||
|
// WARNING! EVIL HORRIBLE RESTRICTION!
|
||
|
//
|
||
|
// You are allowed to pass GPI_ICON only once per page.
|
||
|
//
|
||
|
BOOL WINAPI GetPageInfoEx(LPPROPDATA ppd, PISP pisp, PAGEINFOEX *ppi, LANGID langidMUI, DWORD flags)
|
||
|
{
|
||
|
HRSRC hRes;
|
||
|
LPDLGTEMPLATE pDlgTemplate;
|
||
|
LPDLGEXTEMPLATE pDlgExTemplate;
|
||
|
BOOL bResult = FALSE;
|
||
|
HGLOBAL hDlgTemplate = 0;
|
||
|
BOOL bSetFont;
|
||
|
LPBYTE pszT;
|
||
|
|
||
|
//
|
||
|
// Init the output structure.
|
||
|
//
|
||
|
ZeroMemory(ppi, sizeof(*ppi));
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
// Enforce the GPI_ICON rule.
|
||
|
if (flags & GPI_ICON)
|
||
|
{
|
||
|
ASSERT(!(pisp->_pfx.dwInternalFlags & PSPI_FETCHEDICON));
|
||
|
pisp->_pfx.dwInternalFlags |= PSPI_FETCHEDICON;
|
||
|
}
|
||
|
|
||
|
// For compatibility with 16-bit stuff, you are only allowed to
|
||
|
// pass these combinations of flags.
|
||
|
switch (LOWORD(flags)) {
|
||
|
case GPI_PT | GPI_ICON | GPI_FONT | GPI_BRTL | GPI_CAPTION:
|
||
|
break;
|
||
|
case GPI_PT | GPI_ICON | GPI_BRTL | GPI_CAPTION:
|
||
|
break;
|
||
|
case GPI_DIALOGEX:
|
||
|
break;
|
||
|
default:
|
||
|
ASSERT(!"Invalid flags passed to GetPageInfoEx");
|
||
|
break;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
if (flags & GPI_ICON) {
|
||
|
if (pisp->_psp.dwFlags & PSP_USEHICON)
|
||
|
ppi->hIcon = pisp->_psp.P_hIcon;
|
||
|
else if (pisp->_psp.dwFlags & PSP_USEICONID)
|
||
|
ppi->hIcon = LoadImage(pisp->_psp.hInstance, pisp->_psp.P_pszIcon, IMAGE_ICON, g_cxSmIcon, g_cySmIcon, LR_DEFAULTCOLOR);
|
||
|
}
|
||
|
|
||
|
if (pisp->_psp.dwFlags & PSP_DLGINDIRECT)
|
||
|
{
|
||
|
pDlgTemplate = (LPDLGTEMPLATE)pisp->_psp.P_pResource;
|
||
|
goto UseTemplate;
|
||
|
}
|
||
|
|
||
|
// We also need to stash away the langid that we actually found
|
||
|
// so we can later determine if we have to do any ML stuff...
|
||
|
hRes = FindResourceExRetry(pisp->_psp.hInstance, RT_DIALOG,
|
||
|
pisp->_psp.P_pszTemplate, langidMUI);
|
||
|
if (hRes)
|
||
|
{
|
||
|
hDlgTemplate = LoadResource(pisp->_psp.hInstance, hRes);
|
||
|
if (hDlgTemplate)
|
||
|
{
|
||
|
pDlgTemplate = (LPDLGTEMPLATE)LockResource(hDlgTemplate);
|
||
|
UseTemplate:
|
||
|
if (pDlgTemplate)
|
||
|
{
|
||
|
pDlgExTemplate = (LPDLGEXTEMPLATE) pDlgTemplate;
|
||
|
//
|
||
|
// Get the width and the height in dialog units.
|
||
|
//
|
||
|
if (pDlgExTemplate->wSignature == 0xFFFF)
|
||
|
{
|
||
|
// DIALOGEX structure
|
||
|
ppi->bDialogEx = TRUE;
|
||
|
ppi->dwStyle = pDlgExTemplate->dwStyle;
|
||
|
ppi->pt.x = pDlgExTemplate->cx;
|
||
|
ppi->pt.y = pDlgExTemplate->cy;
|
||
|
// Get the RTL reading order for the caption
|
||
|
ppi->bRTL = (((pDlgExTemplate->dwExStyle) & WS_EX_RTLREADING) || (pisp->_psp.dwFlags & PSP_RTLREADING)) ? TRUE : FALSE;
|
||
|
ppi->bMirrored = ((pDlgExTemplate->dwExStyle) & (RTL_MIRRORED_WINDOW)) ? TRUE : FALSE;
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ppi->dwStyle = pDlgTemplate->style;
|
||
|
ppi->pt.x = pDlgTemplate->cx;
|
||
|
ppi->pt.y = pDlgTemplate->cy;
|
||
|
ppi->bRTL = (pisp->_psp.dwFlags & PSP_RTLREADING) ? TRUE : FALSE;
|
||
|
}
|
||
|
|
||
|
bResult = TRUE;
|
||
|
|
||
|
if (flags & (GPI_CAPTION | GPI_FONT))
|
||
|
{
|
||
|
if (pisp->_psp.dwFlags & PSP_USETITLE)
|
||
|
{
|
||
|
if (IS_INTRESOURCE(pisp->_psp.pszTitle))
|
||
|
{
|
||
|
CCLoadStringExInternal(pisp->_psp.hInstance,
|
||
|
(UINT)LOWORD(pisp->_psp.pszTitle),
|
||
|
ppi->szCaption,
|
||
|
ARRAYSIZE(ppi->szCaption),
|
||
|
langidMUI);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Copy pszTitle
|
||
|
lstrcpyn(ppi->szCaption, pisp->_psp.pszTitle, ARRAYSIZE(ppi->szCaption));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// ML UI support for NT5
|
||
|
// Grab the font face and size in point from page so that
|
||
|
// we can calculate size of page in real screen pixel
|
||
|
// This is for NT5 MLUI but should not be any harm for Win95
|
||
|
// or even works better for the platform.
|
||
|
|
||
|
// 1. check if the page has font specified
|
||
|
if ( ppi->bDialogEx )
|
||
|
bSetFont = ((pDlgExTemplate->dwStyle & DS_SETFONT) != 0);
|
||
|
else
|
||
|
bSetFont = ((pDlgTemplate->style & DS_SETFONT) != 0);
|
||
|
|
||
|
// 2. Skip until after class name
|
||
|
// only if either font is set or we want title
|
||
|
//
|
||
|
if (bSetFont || !(pisp->_psp.dwFlags & PSP_USETITLE))
|
||
|
{
|
||
|
// Get the caption string from the dialog template, only
|
||
|
//
|
||
|
if (ppi->bDialogEx)
|
||
|
pszT = (BYTE *) (pDlgExTemplate + 1);
|
||
|
else
|
||
|
pszT = (BYTE *) (pDlgTemplate + 1);
|
||
|
|
||
|
// The menu name is either 0xffff followed by a word,
|
||
|
// or a string.
|
||
|
switch (*(LPWORD)pszT) {
|
||
|
case 0xffff:
|
||
|
pszT += 2 * sizeof(WORD);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
pszT += (_Rstrlen((LPTSTR)pszT) + 1) * sizeof(RESCHAR);
|
||
|
break;
|
||
|
}
|
||
|
//
|
||
|
// Now we are pointing at the class name.
|
||
|
//
|
||
|
pszT += (_Rstrlen((LPTSTR)pszT) + 1) * sizeof(RESCHAR);
|
||
|
}
|
||
|
// 3. grab the title from template if PSP_USETITLE isn't set
|
||
|
//
|
||
|
if (!(pisp->_psp.dwFlags & PSP_USETITLE))
|
||
|
_Rstrcpyn(ppi->szCaption, (LPTSTR)pszT, ARRAYSIZE(ppi->szCaption));
|
||
|
|
||
|
// 4. grab the point size and face name if DS_SETFONT
|
||
|
//
|
||
|
if (bSetFont && (flags & GPI_FONT))
|
||
|
{
|
||
|
// skip the title string
|
||
|
pszT += (_Rstrlen((LPTSTR)pszT)+1) * sizeof(RESCHAR);
|
||
|
ppi->pfd.PointSize = *((short *)pszT)++;
|
||
|
if (ppi->bDialogEx)
|
||
|
{
|
||
|
((short *)pszT)++; // skip weight as we always use FW_NORMAL w/ DS_3DLOOK
|
||
|
ppi->pfd.bItalic = *(BYTE *)pszT++;
|
||
|
ppi->pfd.iCharset = *(BYTE *)pszT++;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ppi->pfd.bItalic = FALSE;
|
||
|
ppi->pfd.iCharset = DEFAULT_CHARSET;
|
||
|
}
|
||
|
|
||
|
_Rstrcpyn(ppi->pfd.szFace, (LPTSTR)pszT, ARRAYSIZE(ppi->pfd.szFace));
|
||
|
|
||
|
// But if this is a SHELLFONT page and the font name is "MS Shell Dlg",
|
||
|
// then its font secretly gets morphed into MS Shell Dlg 2 (if
|
||
|
// all the other pages agree)... The wackiness continues...
|
||
|
if (staticIsOS(OS_WIN2000ORGREATER) &&
|
||
|
(ppd->fFlags & PD_SHELLFONT) &&
|
||
|
IsPageInfoSHELLFONT(ppi) &&
|
||
|
lstrcmpi(ppi->pfd.szFace, TEXT("MS Shell Dlg")) == 0)
|
||
|
{
|
||
|
_Rstrcpyn(ppi->pfd.szFace, TEXT("MS Shell Dlg 2"), ARRAYSIZE(ppi->pfd.szFace));
|
||
|
}
|
||
|
//
|
||
|
// USER quirk #2: If the font height is 0x7FFF, then
|
||
|
// USER really uses the MessageBox font and no font
|
||
|
// information is stored in the dialog template.
|
||
|
// Win95's dialog template converter doesn't support
|
||
|
// this, so we won't either.
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (pisp->_psp.dwFlags & PSP_DLGINDIRECT)
|
||
|
return bResult;
|
||
|
|
||
|
UnlockResource(hDlgTemplate);
|
||
|
}
|
||
|
FreeResource(hDlgTemplate);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DebugMsg(DM_ERROR, TEXT("GetPageInfo - ERROR: FindResource() failed"));
|
||
|
}
|
||
|
return bResult;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Helper function that edits a dialog template in preparation for it
|
||
|
// becoming a property sheet page. This has been split out because
|
||
|
// the legacy CreatePage function needs to do this, too.
|
||
|
//
|
||
|
// Returns the place where the style was edited on success, or
|
||
|
// NULL if we took an exception while editing the template.
|
||
|
//
|
||
|
// The old style is returned in pdwSaveStyle so it can be replaced later.
|
||
|
//
|
||
|
|
||
|
LPDWORD
|
||
|
EditPropSheetTemplate(
|
||
|
LPDLGTEMPLATE pDlgTemplate,
|
||
|
LPDWORD pdwSaveStyle,
|
||
|
BOOL fFlags) // PD_*
|
||
|
{
|
||
|
DWORD lSaveStyle;
|
||
|
DWORD dwNewStyle;
|
||
|
LPDWORD pdwStyle;
|
||
|
LPDLGEXTEMPLATE pDlgExTemplate = (LPDLGEXTEMPLATE) pDlgTemplate;
|
||
|
|
||
|
try
|
||
|
{
|
||
|
//
|
||
|
// We need to save the SETFONT, LOCALEDIT, and CLIPCHILDREN
|
||
|
// flags.
|
||
|
//
|
||
|
if (pDlgExTemplate->wSignature == 0xFFFF)
|
||
|
{
|
||
|
pdwStyle = &pDlgExTemplate->dwStyle;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pdwStyle = &pDlgTemplate->style;
|
||
|
}
|
||
|
|
||
|
lSaveStyle = *pdwStyle;
|
||
|
*pdwSaveStyle = lSaveStyle;
|
||
|
|
||
|
dwNewStyle = (lSaveStyle & (DS_SHELLFONT | DS_LOCALEDIT | WS_CLIPCHILDREN))
|
||
|
| WS_CHILD | WS_TABSTOP | DS_3DLOOK | DS_CONTROL;
|
||
|
|
||
|
// If SHELLFONT has been turned off and this page uses it, then turn
|
||
|
// it off.
|
||
|
if (!(fFlags & PD_SHELLFONT) &&
|
||
|
(dwNewStyle & DS_SHELLFONT) == DS_SHELLFONT)
|
||
|
dwNewStyle &= ~DS_FIXEDSYS; // Leave DS_USEFONT but lose FIXEDSYS
|
||
|
|
||
|
*pdwStyle = dwNewStyle;
|
||
|
|
||
|
} except (UnhandledExceptionFilter( GetExceptionInformation() )) {
|
||
|
return NULL;
|
||
|
}
|
||
|
__endexcept
|
||
|
|
||
|
return pdwStyle;
|
||
|
}
|
||
|
|
||
|
void RethunkShadowStrings(PISP pisp)
|
||
|
{
|
||
|
//
|
||
|
// Note: Old code recomputed the entire UNICODE PROPSHEETHEADER
|
||
|
// from the ANSI shadow at certain points, in case
|
||
|
// the app edited the ANSI shadow.
|
||
|
//
|
||
|
// So we do it too. I need to ask Eric Flo why we did it in the
|
||
|
// first place. Note that the algorithm is buggy - if the app
|
||
|
// edited any of the string fields (or any of the flags that
|
||
|
// gate the string fields), we both leak the original memory
|
||
|
// *and* fault when we try to free something that wasn't
|
||
|
// allocated via LocalAlloc. We preserve the bug to be compatible
|
||
|
// with NT4. (Snicker.)
|
||
|
//
|
||
|
DWORD dwSize = min(sizeof(PROPSHEETPAGE), pisp->_cpfx.pispShadow->_psp.dwSize);
|
||
|
dwSize = min(dwSize, GETORIGINALSIZE(pisp));
|
||
|
|
||
|
FreePropertyPageStrings(&pisp->_psp);
|
||
|
hmemcpy(&pisp->_psp, &pisp->_cpfx.pispShadow->_psp, dwSize);
|
||
|
//
|
||
|
// If this copy fails, we will carry on with happy NULL strings.
|
||
|
// So some strings are empty, boo-hoo.
|
||
|
//
|
||
|
EVAL(CopyPropertyPageStrings(&pisp->_psp, StrDup_AtoW));
|
||
|
}
|
||
|
|
||
|
|
||
|
ULONG_PTR PropPageActivateContext(LPPROPDATA ppd, PISP pisp)
|
||
|
{
|
||
|
ULONG_PTR dwCookie = 0;
|
||
|
// Activate the fusion context if available for this page.
|
||
|
if (pisp &&
|
||
|
pisp->_psp.dwFlags & PSP_USEFUSIONCONTEXT &&
|
||
|
pisp->_psp.dwSize > PROPSHEETPAGE_V2_SIZE &&
|
||
|
pisp->_psp.hActCtx)
|
||
|
{
|
||
|
ActivateActCtx(pisp->_psp.hActCtx, &dwCookie);
|
||
|
}
|
||
|
else if (ppd)
|
||
|
{
|
||
|
ActivateActCtx(ppd->hActCtxInit, &dwCookie);
|
||
|
}
|
||
|
|
||
|
return dwCookie;
|
||
|
}
|
||
|
|
||
|
void PropPageDeactivateContext(ULONG_PTR dw)
|
||
|
{
|
||
|
if (dw)
|
||
|
DeactivateActCtx(0, dw);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// This function creates a dialog box from the specified dialog template
|
||
|
// with appropriate style flags.
|
||
|
//
|
||
|
HWND _CreatePageDialog(LPPROPDATA ppd, PISP pisp, HWND hwndParent, LPDLGTEMPLATE pDlgTemplate)
|
||
|
{
|
||
|
HWND hwndPage;
|
||
|
LPARAM lParam;
|
||
|
LPDWORD pdwStyle;
|
||
|
DWORD lSaveStyle;
|
||
|
ULONG_PTR dwCookie = 0;
|
||
|
|
||
|
DLGPROC pfnDlgProc;
|
||
|
|
||
|
pdwStyle = EditPropSheetTemplate(pDlgTemplate, &lSaveStyle, ppd->fFlags);
|
||
|
|
||
|
if (!pdwStyle) // error editing template
|
||
|
return NULL;
|
||
|
|
||
|
//
|
||
|
// Thunk the Dialog proc if we were created by x86 code on RISC.
|
||
|
//
|
||
|
|
||
|
#ifdef WX86
|
||
|
if (pisp->_pfx.dwInternalFlags & PSPI_WX86) {
|
||
|
pfnDlgProc = (DLGPROC) Wx86ThunkProc( pisp->_psp.pfnDlgProc, (PVOID) 4, TRUE );
|
||
|
|
||
|
if (pfnDlgProc == NULL)
|
||
|
return NULL;
|
||
|
}
|
||
|
else
|
||
|
#endif
|
||
|
pfnDlgProc = pisp->_psp.pfnDlgProc;
|
||
|
|
||
|
//
|
||
|
// Decide what to pass as the lParam to the CreateDialogIndirectParam.
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// If the caller was ANSI, then use the ANSI PROPSHEETPAGE.
|
||
|
//
|
||
|
if (HASANSISHADOW(pisp))
|
||
|
{
|
||
|
lParam = (LPARAM) &pisp->_cpfx.pispShadow->_psp;
|
||
|
}
|
||
|
|
||
|
else if (pisp->_psp.dwFlags & PSP_SHPAGE)
|
||
|
{
|
||
|
//
|
||
|
// PSP_SHPAGE is a special flag used by pre-IE5 shell32 only.
|
||
|
// See prshti.h for gory details. If we get this far, it means
|
||
|
// that we need to pass the CLASSICPREFIX instead of the
|
||
|
// PROPSHEETPAGE.
|
||
|
//
|
||
|
lParam = (LPARAM)&pisp->_cpfx;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// Normal UNICODE caller gets the UNICODE PROPSHEETPAGE.
|
||
|
//
|
||
|
lParam = (LPARAM)&pisp->_psp;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// All set - go create it.
|
||
|
//
|
||
|
|
||
|
dwCookie = PropPageActivateContext(ppd, pisp);
|
||
|
|
||
|
if (HASANSISHADOW(pisp))
|
||
|
{
|
||
|
hwndPage = CreateDialogIndirectParamA(
|
||
|
pisp->_psp.hInstance,
|
||
|
(LPCDLGTEMPLATE)pDlgTemplate,
|
||
|
hwndParent,
|
||
|
pfnDlgProc, lParam);
|
||
|
RethunkShadowStrings(pisp);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hwndPage = SHNoFusionCreateDialogIndirectParam(
|
||
|
pisp->_psp.hInstance,
|
||
|
(LPCDLGTEMPLATE)pDlgTemplate,
|
||
|
hwndParent,
|
||
|
pfnDlgProc, lParam);
|
||
|
}
|
||
|
|
||
|
// Don't set the theme me style if it's a wizard page. The wizards have their own overrides that conflict
|
||
|
// with the theme manager
|
||
|
if (!((ppd->psh).dwFlags & (PSH_WIZARD | PSH_WIZARD97 | PSH_WIZARD_LITE)))
|
||
|
{
|
||
|
EnableThemeDialogTexture(hwndPage, ETDT_USETABTEXTURE);
|
||
|
}
|
||
|
|
||
|
PropPageDeactivateContext(dwCookie);
|
||
|
|
||
|
|
||
|
//
|
||
|
// Restore the original dialog template style.
|
||
|
//
|
||
|
try
|
||
|
{
|
||
|
MwWriteDWORD((LPBYTE)pdwStyle, lSaveStyle);
|
||
|
} except (UnhandledExceptionFilter( GetExceptionInformation() ))
|
||
|
{
|
||
|
|
||
|
if (hwndPage)
|
||
|
{
|
||
|
DestroyWindow(hwndPage);
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
__endexcept
|
||
|
|
||
|
|
||
|
return hwndPage;
|
||
|
}
|
||
|
|
||
|
|
||
|
HWND _CreatePage(LPPROPDATA ppd, PISP pisp, HWND hwndParent, LANGID langidMUI)
|
||
|
{
|
||
|
HWND hwndPage = NULL; // NULL indicates an error
|
||
|
|
||
|
if (!CallPropertyPageCallback(ppd, pisp, PSPCB_CREATE))
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
if (HASANSISHADOW(pisp))
|
||
|
{
|
||
|
RethunkShadowStrings(pisp);
|
||
|
}
|
||
|
|
||
|
if (pisp->_psp.dwFlags & PSP_DLGINDIRECT)
|
||
|
{
|
||
|
hwndPage=_CreatePageDialog(ppd, pisp, hwndParent, (LPDLGTEMPLATE)pisp->_psp.P_pResource);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
HRSRC hRes;
|
||
|
hRes = FindResourceExRetry(pisp->_psp.hInstance, RT_DIALOG,
|
||
|
pisp->_psp.P_pszTemplate, langidMUI);
|
||
|
if (hRes)
|
||
|
{
|
||
|
HGLOBAL hDlgTemplate;
|
||
|
hDlgTemplate = LoadResource(pisp->_psp.hInstance, hRes);
|
||
|
if (hDlgTemplate)
|
||
|
{
|
||
|
const DLGTEMPLATE * pDlgTemplate;
|
||
|
pDlgTemplate = (LPDLGTEMPLATE)LockResource(hDlgTemplate);
|
||
|
if (pDlgTemplate)
|
||
|
{
|
||
|
ULONG cbTemplate=SizeofResource(pisp->_psp.hInstance, hRes);
|
||
|
LPDLGTEMPLATE pdtCopy = (LPDLGTEMPLATE)Alloc(cbTemplate);
|
||
|
|
||
|
ASSERT(cbTemplate>=sizeof(DLGTEMPLATE));
|
||
|
|
||
|
if (pdtCopy)
|
||
|
{
|
||
|
hmemcpy(pdtCopy, pDlgTemplate, cbTemplate);
|
||
|
hwndPage=_CreatePageDialog(ppd, pisp, hwndParent, pdtCopy);
|
||
|
Free(pdtCopy);
|
||
|
}
|
||
|
|
||
|
UnlockResource(hDlgTemplate);
|
||
|
}
|
||
|
FreeResource(hDlgTemplate);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return hwndPage;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
//
|
||
|
// Legacy
|
||
|
//
|
||
|
// CreatePage is an internal entry point used by shell32 prior to NT5/IE5.
|
||
|
//
|
||
|
// Win95's shell32 passes a PROPSHEETPAGEA.
|
||
|
//
|
||
|
// WinNT's shell32 passes a CLASSICPREFIX + PROPSHEETPAGEW.
|
||
|
//
|
||
|
// The kicker is that shell32 really doesn't need any property sheet page
|
||
|
// features. It's just too lazy to do some dialog style editing.
|
||
|
//
|
||
|
//
|
||
|
|
||
|
HWND WINAPI CreatePage(LPVOID hpage, HWND hwndParent)
|
||
|
{
|
||
|
HWND hwndPage = NULL; // NULL indicates an error
|
||
|
HRSRC hrsrc;
|
||
|
LPPROPSHEETPAGE ppsp;
|
||
|
|
||
|
//
|
||
|
// Move from the CLASSICPREFIX to the PROPSHEETHEADER.
|
||
|
//
|
||
|
ppsp = &CONTAINING_RECORD(hpage, ISP, _cpfx)->_psp;
|
||
|
|
||
|
// Docfind2.c never passed these flags, so we don't need to implement them.
|
||
|
ASSERT(!(ppsp->dwFlags & (PSP_USECALLBACK | PSP_IS16 | PSP_DLGINDIRECT)));
|
||
|
|
||
|
hrsrc = FindResourceW(ppsp->hInstance, ppsp->P_pszTemplate, RT_DIALOG);
|
||
|
|
||
|
if (hrsrc)
|
||
|
{
|
||
|
LPCDLGTEMPLATE pDlgTemplate = LoadResource(ppsp->hInstance, hrsrc);
|
||
|
if (pDlgTemplate)
|
||
|
{
|
||
|
//
|
||
|
// Make a copy of the template so we can edit it.
|
||
|
//
|
||
|
|
||
|
DWORD cbTemplate = SizeofResource(ppsp->hInstance, hrsrc);
|
||
|
LPDLGTEMPLATE pdtCopy = (LPDLGTEMPLATE)Alloc(cbTemplate);
|
||
|
|
||
|
ASSERT(cbTemplate>=sizeof(DLGTEMPLATE));
|
||
|
|
||
|
if (pdtCopy)
|
||
|
{
|
||
|
DWORD dwScratch;
|
||
|
|
||
|
hmemcpy(pdtCopy, pDlgTemplate, cbTemplate);
|
||
|
if (EditPropSheetTemplate(pdtCopy, &dwScratch, PD_SHELLFONT))
|
||
|
{
|
||
|
|
||
|
hwndPage = CreateDialogIndirectParamW(
|
||
|
ppsp->hInstance,
|
||
|
pdtCopy,
|
||
|
hwndParent,
|
||
|
ppsp->pfnDlgProc, (LPARAM)hpage);
|
||
|
}
|
||
|
Free(pdtCopy);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return hwndPage;
|
||
|
}
|
||
|
|
||
|
// End of legacy
|
||
|
//
|
||
|
//===========================================================================
|
||
|
|
||
|
//
|
||
|
// AllocPropertySheetPage
|
||
|
//
|
||
|
// Allocate the memory into which we will dump a property sheet page.
|
||
|
//
|
||
|
// Nothing is actually copied into the buffer. The only thing interesting
|
||
|
// is that the external HPROPSHEETPAGE is set up on the assumption that
|
||
|
// we will not require a shadow.
|
||
|
//
|
||
|
// We assume that we are allocating the memory for a non-shadow page.
|
||
|
//
|
||
|
PISP AllocPropertySheetPage(DWORD dwClientSize)
|
||
|
{
|
||
|
PISP pisp;
|
||
|
LPBYTE pbAlloc;
|
||
|
|
||
|
//
|
||
|
// An ISP consists of the "above" part, the "below" part, and
|
||
|
// the baggage passed by the app. Negative baggage is okay;
|
||
|
// it means we have a down-level app that doesn't know about
|
||
|
// pszHeaderTitle.
|
||
|
//
|
||
|
|
||
|
pbAlloc = LocalAlloc(LPTR, sizeof(pisp->above) + sizeof(pisp->below) +
|
||
|
(dwClientSize - sizeof(PROPSHEETPAGE)));
|
||
|
|
||
|
if (!pbAlloc)
|
||
|
return NULL;
|
||
|
|
||
|
pisp = (PISP)(pbAlloc + sizeof(pisp->above));
|
||
|
|
||
|
//
|
||
|
// Set up the CLASSICPREFIX fields.
|
||
|
//
|
||
|
pisp->_cpfx.pispMain = pisp;
|
||
|
ASSERT(pisp->_cpfx.pispShadow == NULL);
|
||
|
|
||
|
//
|
||
|
// Assume no shadow - The app gets the PISP itself.
|
||
|
//
|
||
|
|
||
|
pisp->_pfx.hpage = (HPROPSHEETPAGE)pisp;
|
||
|
|
||
|
return pisp;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Helper function during page creation. The incoming string is really
|
||
|
// an ANSI string. Thunk it to UNICODE. Fortunately, we already have
|
||
|
// another helper function that does the work.
|
||
|
//
|
||
|
STDAPI_(LPTSTR) StrDup_AtoW(LPCTSTR ptsz)
|
||
|
{
|
||
|
return ProduceWFromA(CP_ACP, (LPCSTR)ptsz);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// CreatePropertySheetPage
|
||
|
//
|
||
|
// Where HPROPSHEETPAGEs come from.
|
||
|
//
|
||
|
// The fNeedShadow parameter means "The incoming LPCPROPSHEETPAGE is in the
|
||
|
// opposite character set from what you implement natively".
|
||
|
//
|
||
|
// If we are compiling UNICODE, then fNeedShadow is TRUE if the incoming
|
||
|
// LPCPROPSHEETPAGE is really an ANSI property sheet page.
|
||
|
//
|
||
|
// If we are compiling ANSI-only, then fNeedShadow is always FALSE because
|
||
|
// we don't support UNICODE in the ANSI-only version.
|
||
|
//
|
||
|
HPROPSHEETPAGE WINAPI _CreatePropertySheetPage(LPCPROPSHEETPAGE psp, BOOL fNeedShadow, BOOL fWx86)
|
||
|
{
|
||
|
PISP pisp;
|
||
|
DWORD dwSize;
|
||
|
|
||
|
COMPILETIME_ASSERT(PROPSHEETPAGEA_V1_SIZE == PROPSHEETPAGEW_V1_SIZE);
|
||
|
COMPILETIME_ASSERT(sizeof(PROPSHEETPAGEA) == sizeof(PROPSHEETPAGEW));
|
||
|
|
||
|
if ((psp->dwSize < MINPROPSHEETPAGESIZE) ||
|
||
|
(psp->dwSize > 4096) || // or the second version
|
||
|
(psp->dwFlags & ~PSP_ALL)) // bogus flag used
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// The PROPSHEETPAGE structure can be larger than the
|
||
|
// defined size. This allows ISV's to place private
|
||
|
// data at the end of the structure. The ISP structure
|
||
|
// consists of some private fields and a PROPSHEETPAGE
|
||
|
// structure. Calculate the size of the private fields,
|
||
|
// and then add in the dwSize field to determine the
|
||
|
// amount of memory necessary.
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// An ISP consists of the "above" part, the "below" part, and
|
||
|
// the baggage passed by the app. Negative baggage is okay;
|
||
|
// it means we have a down-level app that doesn't know about
|
||
|
// pszHeaderTitle.
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// If we have an "other" client, then the native side of the
|
||
|
// property sheet doesn't carry any baggage. It's just a
|
||
|
// plain old PROPSHEETPAGE.
|
||
|
//
|
||
|
|
||
|
dwSize = fNeedShadow ? sizeof(PROPSHEETPAGE) : psp->dwSize;
|
||
|
pisp = AllocPropertySheetPage(dwSize);
|
||
|
|
||
|
if (pisp)
|
||
|
{
|
||
|
STRDUPPROC pfnStrDup;
|
||
|
|
||
|
#ifdef WX86
|
||
|
//
|
||
|
// We we're being called by Wx86, set the flag so we remember.
|
||
|
//
|
||
|
|
||
|
if ( fWx86 ) {
|
||
|
pisp->_pfx.dwInternalFlags |= PSPI_WX86;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
SETORIGINALSIZE(pisp, dwSize);
|
||
|
|
||
|
//
|
||
|
// Bulk copy the contents of the PROPSHEETPAGE, or
|
||
|
// as much of it as the app gave us.
|
||
|
//
|
||
|
hmemcpy(&pisp->_psp, psp, min(dwSize, psp->dwSize));
|
||
|
|
||
|
//
|
||
|
// Decide how to copy the strings
|
||
|
//
|
||
|
if (fNeedShadow)
|
||
|
pfnStrDup = StrDup_AtoW;
|
||
|
else
|
||
|
pfnStrDup = StrDup;
|
||
|
|
||
|
// Now copy them
|
||
|
if (!CopyPropertyPageStrings(&pisp->_psp, pfnStrDup))
|
||
|
goto ExitStrings;
|
||
|
|
||
|
if (fNeedShadow)
|
||
|
{
|
||
|
PISP pispAnsi = AllocPropertySheetPage(psp->dwSize);
|
||
|
if (!pispAnsi)
|
||
|
goto ExitShadow;
|
||
|
|
||
|
//
|
||
|
// Copy the entire client PROPSHEETPAGE, including the
|
||
|
// baggage.
|
||
|
//
|
||
|
hmemcpy(&pispAnsi->_psp, psp, psp->dwSize);
|
||
|
|
||
|
//
|
||
|
// Hook the two copies to point to each other.
|
||
|
//
|
||
|
pisp->_cpfx.pispShadow = pispAnsi;
|
||
|
pispAnsi->_cpfx.pispShadow = pispAnsi;
|
||
|
pispAnsi->_cpfx.pispMain = pisp;
|
||
|
|
||
|
//
|
||
|
// If there is a shadow, then the
|
||
|
// external handle is the ANSI shadow.
|
||
|
//
|
||
|
ASSERT(pispAnsi->_pfx.hpage == (HPROPSHEETPAGE)pispAnsi);
|
||
|
pisp->_pfx.hpage = (HPROPSHEETPAGE)pispAnsi;
|
||
|
|
||
|
//
|
||
|
// Okay, now StrDupA them strings.
|
||
|
//
|
||
|
if (!CopyPropertyPageStrings(&pispAnsi->_psp, (STRDUPPROC)StrDupA))
|
||
|
goto ExitShadowStrings;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Increment the reference count to the parent object.
|
||
|
//
|
||
|
|
||
|
if (HASREFPARENT(pisp))
|
||
|
InterlockedIncrement((LPLONG)pisp->_psp.pcRefParent);
|
||
|
|
||
|
//
|
||
|
// Welcome to the world.
|
||
|
//
|
||
|
CallPropertyPageCallback(NULL, pisp, PSPCB_ADDREF); // don't need because there is no hwnd
|
||
|
|
||
|
return ExternalizeHPROPSHEETPAGE(pisp);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
ExitShadowStrings:
|
||
|
FreePropertyPageStrings(&pisp->_cpfx.pispShadow->_psp);
|
||
|
FreePropertyPageStruct(pisp->_cpfx.pispShadow);
|
||
|
ExitShadow:;
|
||
|
ExitStrings:
|
||
|
FreePropertyPageStrings(&pisp->_psp);
|
||
|
FreePropertyPageStruct(pisp);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
HPROPSHEETPAGE WINAPI CreatePropertySheetPageW(LPCPROPSHEETPAGEW psp)
|
||
|
{
|
||
|
BOOL fWx86 = FALSE;
|
||
|
|
||
|
#ifdef WX86
|
||
|
fWx86 = Wx86IsCallThunked();
|
||
|
#endif
|
||
|
|
||
|
return _CreatePropertySheetPage(psp, FALSE, fWx86);
|
||
|
}
|
||
|
|
||
|
HPROPSHEETPAGE WINAPI CreatePropertySheetPageA(LPCPROPSHEETPAGEA psp)
|
||
|
{
|
||
|
BOOL fWx86 = FALSE;
|
||
|
|
||
|
#ifdef WX86
|
||
|
fWx86 = Wx86IsCallThunked();
|
||
|
#endif
|
||
|
|
||
|
return _CreatePropertySheetPage((LPCPROPSHEETPAGE)psp, TRUE, fWx86);
|
||
|
}
|