windows-nt/Source/XPSP1/NT/shell/comctl32/v6/prpage.c
2020-09-26 16:20:57 +08:00

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);
}