#include "ctlspriv.h" #include "prshti.h" #ifdef WX86 #include #endif #include 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 /* 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)) { ASSERT( 0 != *pisp->_psp.pcRefParent ); 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(PAGEINFOEX)); #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 StringCchCopy(ppi->szCaption, ARRAYSIZE(ppi->szCaption), pisp->_psp.pszTitle); } } // 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 += (lstrlenW((LPTSTR)pszT) + 1) * sizeof(WCHAR); break; } // // Now we are pointing at the class name. // pszT += (lstrlenW((LPTSTR)pszT) + 1) * sizeof(WCHAR); } // 3. grab the title from template if PSP_USETITLE isn't set // if (!(pisp->_psp.dwFlags & PSP_USETITLE)) { StringCchCopy(ppi->szCaption, ARRAYSIZE(ppi->szCaption), (LPTSTR)pszT); } // 4. grab the point size and face name if DS_SETFONT // if (bSetFont && (flags & GPI_FONT)) { // skip the title string pszT += (lstrlenW((LPTSTR)pszT)+1) * sizeof(WCHAR); 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; } StringCchCopy(ppi->pfd.szFace, ARRAYSIZE(ppi->pfd.szFace), (LPTSTR)pszT); // 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) { StringCchCopy(ppi->pfd.szFace, ARRAYSIZE(ppi->pfd.szFace), TEXT("MS Shell Dlg 2")); } // // 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 = 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); }