Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

931 lines
28 KiB

  1. #include "ctlspriv.h"
  2. #include "prshti.h"
  3. #ifdef WX86
  4. #include <wx86ofl.h>
  5. #endif
  6. #define _Rstrcpyn lstrcpyn
  7. //
  8. // Miracle of miracles - Win95 implements lstrlenW.
  9. //
  10. #define _Rstrlen lstrlenW
  11. #define RESCHAR WCHAR
  12. #include <pshpack2.h>
  13. typedef struct
  14. {
  15. WORD wDlgVer;
  16. WORD wSignature;
  17. DWORD dwHelpID;
  18. DWORD dwExStyle;
  19. DWORD dwStyle;
  20. WORD cDlgItems;
  21. WORD x;
  22. WORD y;
  23. WORD cx;
  24. WORD cy;
  25. } DLGEXTEMPLATE, *LPDLGEXTEMPLATE;
  26. #include <poppack.h> /* Resume normal packing */
  27. //
  28. // CallPropertyPageCallback
  29. //
  30. // Call the callback for the property page, passing it the correct lParam
  31. // based on the character set it wants.
  32. //
  33. UINT CallPropertyPageCallback(PROPDATA* ppd, PISP pisp, UINT uMsg)
  34. {
  35. UINT uiResult = TRUE; // assume success
  36. if (HASCALLBACK(pisp) &&
  37. (pisp->_psp.dwSize > PROPSHEETPAGE_V1_SIZE ||
  38. uMsg == PSPCB_CREATE || uMsg == PSPCB_RELEASE))
  39. {
  40. ULONG_PTR dwCookie = PropPageActivateContext(ppd, pisp);
  41. if (HASANSISHADOW(pisp))
  42. {
  43. #ifdef WX86
  44. if ( pisp->_pfx.dwInternalFlags & PSPI_WX86 )
  45. uiResult = Wx86Callback(pisp->_psp.pfnCallback, NULL, uMsg, (LPARAM) &pisp->_cpfx.pispShadow->_psp);
  46. else
  47. #endif
  48. uiResult = pisp->_psp.pfnCallback(NULL, uMsg, &pisp->_cpfx.pispShadow->_psp);
  49. }
  50. else
  51. {
  52. #ifdef WX86
  53. if ( pisp->_pfx.dwInternalFlags & PSPI_WX86 )
  54. uiResult = Wx86Callback(pisp->_psp.pfnCallback, NULL, uMsg, (LPARAM) &pisp->_psp);
  55. else
  56. #endif
  57. uiResult = pisp->_psp.pfnCallback(NULL, uMsg, &pisp->_psp);
  58. }
  59. PropPageDeactivateContext(dwCookie);
  60. }
  61. return uiResult;
  62. }
  63. //
  64. // FreePropertyPageStruct
  65. //
  66. // Free the memory block that contains a property sheet page.
  67. // It is the caller's responsibility to have freed all the things
  68. // that were attached to it.
  69. //
  70. //
  71. __inline void FreePropertyPageStruct(PISP pisp)
  72. {
  73. LocalFree(PropSheetBase(pisp));
  74. }
  75. //
  76. // DestroyPropertySheetPage
  77. //
  78. // Do the appropriate thing to destroy a property sheet page, whether
  79. // this entails talking to 16-bit thunks, sending the PSPCB_RELEASE,
  80. // or freeing the shadow page.
  81. //
  82. BOOL WINAPI DestroyPropertySheetPage(HPROPSHEETPAGE hpage)
  83. {
  84. PISP pisp = InternalizeHPROPSHEETPAGE(hpage);
  85. CallPropertyPageCallback(NULL, pisp, PSPCB_RELEASE);
  86. // Do the decrement *after* calling the callback for the last time
  87. if (HASREFPARENT(pisp))
  88. InterlockedDecrement((LPLONG)pisp->_psp.pcRefParent);
  89. if (HASANSISHADOW(pisp))
  90. {
  91. FreePropertyPageStrings(&pisp->_cpfx.pispShadow->_psp);
  92. FreePropertyPageStruct(pisp->_cpfx.pispShadow);
  93. }
  94. //
  95. // Note that FreePropertyPageStrings will try to destroy strings for
  96. // proxy pages, but that's okay, because the corresponding P_pszBlah
  97. // fields are all NULL since we never initialized them.
  98. //
  99. FreePropertyPageStrings(&pisp->_psp);
  100. FreePropertyPageStruct(pisp);
  101. return TRUE;
  102. }
  103. //
  104. // GetPageInfoEx
  105. //
  106. // Extract information about a page into a PAGEINFOEX structure.
  107. //
  108. // WARNING! EVIL HORRIBLE RESTRICTION!
  109. //
  110. // You are allowed to pass GPI_ICON only once per page.
  111. //
  112. BOOL WINAPI GetPageInfoEx(LPPROPDATA ppd, PISP pisp, PAGEINFOEX *ppi, LANGID langidMUI, DWORD flags)
  113. {
  114. HRSRC hRes;
  115. LPDLGTEMPLATE pDlgTemplate;
  116. LPDLGEXTEMPLATE pDlgExTemplate;
  117. BOOL bResult = FALSE;
  118. HGLOBAL hDlgTemplate = 0;
  119. BOOL bSetFont;
  120. LPBYTE pszT;
  121. //
  122. // Init the output structure.
  123. //
  124. ZeroMemory(ppi, sizeof(*ppi));
  125. #ifdef DEBUG
  126. // Enforce the GPI_ICON rule.
  127. if (flags & GPI_ICON)
  128. {
  129. ASSERT(!(pisp->_pfx.dwInternalFlags & PSPI_FETCHEDICON));
  130. pisp->_pfx.dwInternalFlags |= PSPI_FETCHEDICON;
  131. }
  132. // For compatibility with 16-bit stuff, you are only allowed to
  133. // pass these combinations of flags.
  134. switch (LOWORD(flags)) {
  135. case GPI_PT | GPI_ICON | GPI_FONT | GPI_BRTL | GPI_CAPTION:
  136. break;
  137. case GPI_PT | GPI_ICON | GPI_BRTL | GPI_CAPTION:
  138. break;
  139. case GPI_DIALOGEX:
  140. break;
  141. default:
  142. ASSERT(!"Invalid flags passed to GetPageInfoEx");
  143. break;
  144. }
  145. #endif
  146. if (flags & GPI_ICON) {
  147. if (pisp->_psp.dwFlags & PSP_USEHICON)
  148. ppi->hIcon = pisp->_psp.P_hIcon;
  149. else if (pisp->_psp.dwFlags & PSP_USEICONID)
  150. ppi->hIcon = LoadImage(pisp->_psp.hInstance, pisp->_psp.P_pszIcon, IMAGE_ICON, g_cxSmIcon, g_cySmIcon, LR_DEFAULTCOLOR);
  151. }
  152. if (pisp->_psp.dwFlags & PSP_DLGINDIRECT)
  153. {
  154. pDlgTemplate = (LPDLGTEMPLATE)pisp->_psp.P_pResource;
  155. goto UseTemplate;
  156. }
  157. // We also need to stash away the langid that we actually found
  158. // so we can later determine if we have to do any ML stuff...
  159. hRes = FindResourceExRetry(pisp->_psp.hInstance, RT_DIALOG,
  160. pisp->_psp.P_pszTemplate, langidMUI);
  161. if (hRes)
  162. {
  163. hDlgTemplate = LoadResource(pisp->_psp.hInstance, hRes);
  164. if (hDlgTemplate)
  165. {
  166. pDlgTemplate = (LPDLGTEMPLATE)LockResource(hDlgTemplate);
  167. UseTemplate:
  168. if (pDlgTemplate)
  169. {
  170. pDlgExTemplate = (LPDLGEXTEMPLATE) pDlgTemplate;
  171. //
  172. // Get the width and the height in dialog units.
  173. //
  174. if (pDlgExTemplate->wSignature == 0xFFFF)
  175. {
  176. // DIALOGEX structure
  177. ppi->bDialogEx = TRUE;
  178. ppi->dwStyle = pDlgExTemplate->dwStyle;
  179. ppi->pt.x = pDlgExTemplate->cx;
  180. ppi->pt.y = pDlgExTemplate->cy;
  181. // Get the RTL reading order for the caption
  182. ppi->bRTL = (((pDlgExTemplate->dwExStyle) & WS_EX_RTLREADING) || (pisp->_psp.dwFlags & PSP_RTLREADING)) ? TRUE : FALSE;
  183. ppi->bMirrored = ((pDlgExTemplate->dwExStyle) & (RTL_MIRRORED_WINDOW)) ? TRUE : FALSE;
  184. }
  185. else
  186. {
  187. ppi->dwStyle = pDlgTemplate->style;
  188. ppi->pt.x = pDlgTemplate->cx;
  189. ppi->pt.y = pDlgTemplate->cy;
  190. ppi->bRTL = (pisp->_psp.dwFlags & PSP_RTLREADING) ? TRUE : FALSE;
  191. }
  192. bResult = TRUE;
  193. if (flags & (GPI_CAPTION | GPI_FONT))
  194. {
  195. if (pisp->_psp.dwFlags & PSP_USETITLE)
  196. {
  197. if (IS_INTRESOURCE(pisp->_psp.pszTitle))
  198. {
  199. CCLoadStringExInternal(pisp->_psp.hInstance,
  200. (UINT)LOWORD(pisp->_psp.pszTitle),
  201. ppi->szCaption,
  202. ARRAYSIZE(ppi->szCaption),
  203. langidMUI);
  204. }
  205. else
  206. {
  207. // Copy pszTitle
  208. lstrcpyn(ppi->szCaption, pisp->_psp.pszTitle, ARRAYSIZE(ppi->szCaption));
  209. }
  210. }
  211. // ML UI support for NT5
  212. // Grab the font face and size in point from page so that
  213. // we can calculate size of page in real screen pixel
  214. // This is for NT5 MLUI but should not be any harm for Win95
  215. // or even works better for the platform.
  216. // 1. check if the page has font specified
  217. if ( ppi->bDialogEx )
  218. bSetFont = ((pDlgExTemplate->dwStyle & DS_SETFONT) != 0);
  219. else
  220. bSetFont = ((pDlgTemplate->style & DS_SETFONT) != 0);
  221. // 2. Skip until after class name
  222. // only if either font is set or we want title
  223. //
  224. if (bSetFont || !(pisp->_psp.dwFlags & PSP_USETITLE))
  225. {
  226. // Get the caption string from the dialog template, only
  227. //
  228. if (ppi->bDialogEx)
  229. pszT = (BYTE *) (pDlgExTemplate + 1);
  230. else
  231. pszT = (BYTE *) (pDlgTemplate + 1);
  232. // The menu name is either 0xffff followed by a word,
  233. // or a string.
  234. switch (*(LPWORD)pszT) {
  235. case 0xffff:
  236. pszT += 2 * sizeof(WORD);
  237. break;
  238. default:
  239. pszT += (_Rstrlen((LPTSTR)pszT) + 1) * sizeof(RESCHAR);
  240. break;
  241. }
  242. //
  243. // Now we are pointing at the class name.
  244. //
  245. pszT += (_Rstrlen((LPTSTR)pszT) + 1) * sizeof(RESCHAR);
  246. }
  247. // 3. grab the title from template if PSP_USETITLE isn't set
  248. //
  249. if (!(pisp->_psp.dwFlags & PSP_USETITLE))
  250. _Rstrcpyn(ppi->szCaption, (LPTSTR)pszT, ARRAYSIZE(ppi->szCaption));
  251. // 4. grab the point size and face name if DS_SETFONT
  252. //
  253. if (bSetFont && (flags & GPI_FONT))
  254. {
  255. // skip the title string
  256. pszT += (_Rstrlen((LPTSTR)pszT)+1) * sizeof(RESCHAR);
  257. ppi->pfd.PointSize = *((short *)pszT)++;
  258. if (ppi->bDialogEx)
  259. {
  260. ((short *)pszT)++; // skip weight as we always use FW_NORMAL w/ DS_3DLOOK
  261. ppi->pfd.bItalic = *(BYTE *)pszT++;
  262. ppi->pfd.iCharset = *(BYTE *)pszT++;
  263. }
  264. else
  265. {
  266. ppi->pfd.bItalic = FALSE;
  267. ppi->pfd.iCharset = DEFAULT_CHARSET;
  268. }
  269. _Rstrcpyn(ppi->pfd.szFace, (LPTSTR)pszT, ARRAYSIZE(ppi->pfd.szFace));
  270. // But if this is a SHELLFONT page and the font name is "MS Shell Dlg",
  271. // then its font secretly gets morphed into MS Shell Dlg 2 (if
  272. // all the other pages agree)... The wackiness continues...
  273. if (staticIsOS(OS_WIN2000ORGREATER) &&
  274. (ppd->fFlags & PD_SHELLFONT) &&
  275. IsPageInfoSHELLFONT(ppi) &&
  276. lstrcmpi(ppi->pfd.szFace, TEXT("MS Shell Dlg")) == 0)
  277. {
  278. _Rstrcpyn(ppi->pfd.szFace, TEXT("MS Shell Dlg 2"), ARRAYSIZE(ppi->pfd.szFace));
  279. }
  280. //
  281. // USER quirk #2: If the font height is 0x7FFF, then
  282. // USER really uses the MessageBox font and no font
  283. // information is stored in the dialog template.
  284. // Win95's dialog template converter doesn't support
  285. // this, so we won't either.
  286. }
  287. }
  288. if (pisp->_psp.dwFlags & PSP_DLGINDIRECT)
  289. return bResult;
  290. UnlockResource(hDlgTemplate);
  291. }
  292. FreeResource(hDlgTemplate);
  293. }
  294. }
  295. else
  296. {
  297. DebugMsg(DM_ERROR, TEXT("GetPageInfo - ERROR: FindResource() failed"));
  298. }
  299. return bResult;
  300. }
  301. //
  302. // Helper function that edits a dialog template in preparation for it
  303. // becoming a property sheet page. This has been split out because
  304. // the legacy CreatePage function needs to do this, too.
  305. //
  306. // Returns the place where the style was edited on success, or
  307. // NULL if we took an exception while editing the template.
  308. //
  309. // The old style is returned in pdwSaveStyle so it can be replaced later.
  310. //
  311. LPDWORD
  312. EditPropSheetTemplate(
  313. LPDLGTEMPLATE pDlgTemplate,
  314. LPDWORD pdwSaveStyle,
  315. BOOL fFlags) // PD_*
  316. {
  317. DWORD lSaveStyle;
  318. DWORD dwNewStyle;
  319. LPDWORD pdwStyle;
  320. LPDLGEXTEMPLATE pDlgExTemplate = (LPDLGEXTEMPLATE) pDlgTemplate;
  321. try
  322. {
  323. //
  324. // We need to save the SETFONT, LOCALEDIT, and CLIPCHILDREN
  325. // flags.
  326. //
  327. if (pDlgExTemplate->wSignature == 0xFFFF)
  328. {
  329. pdwStyle = &pDlgExTemplate->dwStyle;
  330. }
  331. else
  332. {
  333. pdwStyle = &pDlgTemplate->style;
  334. }
  335. lSaveStyle = *pdwStyle;
  336. *pdwSaveStyle = lSaveStyle;
  337. dwNewStyle = (lSaveStyle & (DS_SHELLFONT | DS_LOCALEDIT | WS_CLIPCHILDREN))
  338. | WS_CHILD | WS_TABSTOP | DS_3DLOOK | DS_CONTROL;
  339. // If SHELLFONT has been turned off and this page uses it, then turn
  340. // it off.
  341. if (!(fFlags & PD_SHELLFONT) &&
  342. (dwNewStyle & DS_SHELLFONT) == DS_SHELLFONT)
  343. dwNewStyle &= ~DS_FIXEDSYS; // Leave DS_USEFONT but lose FIXEDSYS
  344. *pdwStyle = dwNewStyle;
  345. } except (UnhandledExceptionFilter( GetExceptionInformation() )) {
  346. return NULL;
  347. }
  348. __endexcept
  349. return pdwStyle;
  350. }
  351. void RethunkShadowStrings(PISP pisp)
  352. {
  353. //
  354. // Note: Old code recomputed the entire UNICODE PROPSHEETHEADER
  355. // from the ANSI shadow at certain points, in case
  356. // the app edited the ANSI shadow.
  357. //
  358. // So we do it too. I need to ask Eric Flo why we did it in the
  359. // first place. Note that the algorithm is buggy - if the app
  360. // edited any of the string fields (or any of the flags that
  361. // gate the string fields), we both leak the original memory
  362. // *and* fault when we try to free something that wasn't
  363. // allocated via LocalAlloc. We preserve the bug to be compatible
  364. // with NT4. (Snicker.)
  365. //
  366. DWORD dwSize = min(sizeof(PROPSHEETPAGE), pisp->_cpfx.pispShadow->_psp.dwSize);
  367. dwSize = min(dwSize, GETORIGINALSIZE(pisp));
  368. FreePropertyPageStrings(&pisp->_psp);
  369. hmemcpy(&pisp->_psp, &pisp->_cpfx.pispShadow->_psp, dwSize);
  370. //
  371. // If this copy fails, we will carry on with happy NULL strings.
  372. // So some strings are empty, boo-hoo.
  373. //
  374. EVAL(CopyPropertyPageStrings(&pisp->_psp, StrDup_AtoW));
  375. }
  376. ULONG_PTR PropPageActivateContext(LPPROPDATA ppd, PISP pisp)
  377. {
  378. ULONG_PTR dwCookie = 0;
  379. // Activate the fusion context if available for this page.
  380. if (pisp &&
  381. pisp->_psp.dwFlags & PSP_USEFUSIONCONTEXT &&
  382. pisp->_psp.dwSize > PROPSHEETPAGE_V2_SIZE &&
  383. pisp->_psp.hActCtx)
  384. {
  385. ActivateActCtx(pisp->_psp.hActCtx, &dwCookie);
  386. }
  387. else if (ppd)
  388. {
  389. ActivateActCtx(ppd->hActCtxInit, &dwCookie);
  390. }
  391. return dwCookie;
  392. }
  393. void PropPageDeactivateContext(ULONG_PTR dw)
  394. {
  395. if (dw)
  396. DeactivateActCtx(0, dw);
  397. }
  398. //
  399. // This function creates a dialog box from the specified dialog template
  400. // with appropriate style flags.
  401. //
  402. HWND _CreatePageDialog(LPPROPDATA ppd, PISP pisp, HWND hwndParent, LPDLGTEMPLATE pDlgTemplate)
  403. {
  404. HWND hwndPage;
  405. LPARAM lParam;
  406. LPDWORD pdwStyle;
  407. DWORD lSaveStyle;
  408. ULONG_PTR dwCookie = 0;
  409. DLGPROC pfnDlgProc;
  410. pdwStyle = EditPropSheetTemplate(pDlgTemplate, &lSaveStyle, ppd->fFlags);
  411. if (!pdwStyle) // error editing template
  412. return NULL;
  413. //
  414. // Thunk the Dialog proc if we were created by x86 code on RISC.
  415. //
  416. #ifdef WX86
  417. if (pisp->_pfx.dwInternalFlags & PSPI_WX86) {
  418. pfnDlgProc = (DLGPROC) Wx86ThunkProc( pisp->_psp.pfnDlgProc, (PVOID) 4, TRUE );
  419. if (pfnDlgProc == NULL)
  420. return NULL;
  421. }
  422. else
  423. #endif
  424. pfnDlgProc = pisp->_psp.pfnDlgProc;
  425. //
  426. // Decide what to pass as the lParam to the CreateDialogIndirectParam.
  427. //
  428. //
  429. // If the caller was ANSI, then use the ANSI PROPSHEETPAGE.
  430. //
  431. if (HASANSISHADOW(pisp))
  432. {
  433. lParam = (LPARAM) &pisp->_cpfx.pispShadow->_psp;
  434. }
  435. else if (pisp->_psp.dwFlags & PSP_SHPAGE)
  436. {
  437. //
  438. // PSP_SHPAGE is a special flag used by pre-IE5 shell32 only.
  439. // See prshti.h for gory details. If we get this far, it means
  440. // that we need to pass the CLASSICPREFIX instead of the
  441. // PROPSHEETPAGE.
  442. //
  443. lParam = (LPARAM)&pisp->_cpfx;
  444. }
  445. else
  446. {
  447. //
  448. // Normal UNICODE caller gets the UNICODE PROPSHEETPAGE.
  449. //
  450. lParam = (LPARAM)&pisp->_psp;
  451. }
  452. //
  453. // All set - go create it.
  454. //
  455. dwCookie = PropPageActivateContext(ppd, pisp);
  456. if (HASANSISHADOW(pisp))
  457. {
  458. hwndPage = CreateDialogIndirectParamA(
  459. pisp->_psp.hInstance,
  460. (LPCDLGTEMPLATE)pDlgTemplate,
  461. hwndParent,
  462. pfnDlgProc, lParam);
  463. RethunkShadowStrings(pisp);
  464. }
  465. else
  466. {
  467. hwndPage = SHNoFusionCreateDialogIndirectParam(
  468. pisp->_psp.hInstance,
  469. (LPCDLGTEMPLATE)pDlgTemplate,
  470. hwndParent,
  471. pfnDlgProc, lParam);
  472. }
  473. // Don't set the theme me style if it's a wizard page. The wizards have their own overrides that conflict
  474. // with the theme manager
  475. if (!((ppd->psh).dwFlags & (PSH_WIZARD | PSH_WIZARD97 | PSH_WIZARD_LITE)))
  476. {
  477. EnableThemeDialogTexture(hwndPage, ETDT_USETABTEXTURE);
  478. }
  479. PropPageDeactivateContext(dwCookie);
  480. //
  481. // Restore the original dialog template style.
  482. //
  483. try
  484. {
  485. MwWriteDWORD((LPBYTE)pdwStyle, lSaveStyle);
  486. } except (UnhandledExceptionFilter( GetExceptionInformation() ))
  487. {
  488. if (hwndPage)
  489. {
  490. DestroyWindow(hwndPage);
  491. }
  492. return NULL;
  493. }
  494. __endexcept
  495. return hwndPage;
  496. }
  497. HWND _CreatePage(LPPROPDATA ppd, PISP pisp, HWND hwndParent, LANGID langidMUI)
  498. {
  499. HWND hwndPage = NULL; // NULL indicates an error
  500. if (!CallPropertyPageCallback(ppd, pisp, PSPCB_CREATE))
  501. {
  502. return NULL;
  503. }
  504. if (HASANSISHADOW(pisp))
  505. {
  506. RethunkShadowStrings(pisp);
  507. }
  508. if (pisp->_psp.dwFlags & PSP_DLGINDIRECT)
  509. {
  510. hwndPage=_CreatePageDialog(ppd, pisp, hwndParent, (LPDLGTEMPLATE)pisp->_psp.P_pResource);
  511. }
  512. else
  513. {
  514. HRSRC hRes;
  515. hRes = FindResourceExRetry(pisp->_psp.hInstance, RT_DIALOG,
  516. pisp->_psp.P_pszTemplate, langidMUI);
  517. if (hRes)
  518. {
  519. HGLOBAL hDlgTemplate;
  520. hDlgTemplate = LoadResource(pisp->_psp.hInstance, hRes);
  521. if (hDlgTemplate)
  522. {
  523. const DLGTEMPLATE * pDlgTemplate;
  524. pDlgTemplate = (LPDLGTEMPLATE)LockResource(hDlgTemplate);
  525. if (pDlgTemplate)
  526. {
  527. ULONG cbTemplate=SizeofResource(pisp->_psp.hInstance, hRes);
  528. LPDLGTEMPLATE pdtCopy = (LPDLGTEMPLATE)Alloc(cbTemplate);
  529. ASSERT(cbTemplate>=sizeof(DLGTEMPLATE));
  530. if (pdtCopy)
  531. {
  532. hmemcpy(pdtCopy, pDlgTemplate, cbTemplate);
  533. hwndPage=_CreatePageDialog(ppd, pisp, hwndParent, pdtCopy);
  534. Free(pdtCopy);
  535. }
  536. UnlockResource(hDlgTemplate);
  537. }
  538. FreeResource(hDlgTemplate);
  539. }
  540. }
  541. }
  542. return hwndPage;
  543. }
  544. //===========================================================================
  545. //
  546. // Legacy
  547. //
  548. // CreatePage is an internal entry point used by shell32 prior to NT5/IE5.
  549. //
  550. // Win95's shell32 passes a PROPSHEETPAGEA.
  551. //
  552. // WinNT's shell32 passes a CLASSICPREFIX + PROPSHEETPAGEW.
  553. //
  554. // The kicker is that shell32 really doesn't need any property sheet page
  555. // features. It's just too lazy to do some dialog style editing.
  556. //
  557. //
  558. HWND WINAPI CreatePage(LPVOID hpage, HWND hwndParent)
  559. {
  560. HWND hwndPage = NULL; // NULL indicates an error
  561. HRSRC hrsrc;
  562. LPPROPSHEETPAGE ppsp;
  563. //
  564. // Move from the CLASSICPREFIX to the PROPSHEETHEADER.
  565. //
  566. ppsp = &CONTAINING_RECORD(hpage, ISP, _cpfx)->_psp;
  567. // Docfind2.c never passed these flags, so we don't need to implement them.
  568. ASSERT(!(ppsp->dwFlags & (PSP_USECALLBACK | PSP_IS16 | PSP_DLGINDIRECT)));
  569. hrsrc = FindResourceW(ppsp->hInstance, ppsp->P_pszTemplate, RT_DIALOG);
  570. if (hrsrc)
  571. {
  572. LPCDLGTEMPLATE pDlgTemplate = LoadResource(ppsp->hInstance, hrsrc);
  573. if (pDlgTemplate)
  574. {
  575. //
  576. // Make a copy of the template so we can edit it.
  577. //
  578. DWORD cbTemplate = SizeofResource(ppsp->hInstance, hrsrc);
  579. LPDLGTEMPLATE pdtCopy = (LPDLGTEMPLATE)Alloc(cbTemplate);
  580. ASSERT(cbTemplate>=sizeof(DLGTEMPLATE));
  581. if (pdtCopy)
  582. {
  583. DWORD dwScratch;
  584. hmemcpy(pdtCopy, pDlgTemplate, cbTemplate);
  585. if (EditPropSheetTemplate(pdtCopy, &dwScratch, PD_SHELLFONT))
  586. {
  587. hwndPage = CreateDialogIndirectParamW(
  588. ppsp->hInstance,
  589. pdtCopy,
  590. hwndParent,
  591. ppsp->pfnDlgProc, (LPARAM)hpage);
  592. }
  593. Free(pdtCopy);
  594. }
  595. }
  596. }
  597. return hwndPage;
  598. }
  599. // End of legacy
  600. //
  601. //===========================================================================
  602. //
  603. // AllocPropertySheetPage
  604. //
  605. // Allocate the memory into which we will dump a property sheet page.
  606. //
  607. // Nothing is actually copied into the buffer. The only thing interesting
  608. // is that the external HPROPSHEETPAGE is set up on the assumption that
  609. // we will not require a shadow.
  610. //
  611. // We assume that we are allocating the memory for a non-shadow page.
  612. //
  613. PISP AllocPropertySheetPage(DWORD dwClientSize)
  614. {
  615. PISP pisp;
  616. LPBYTE pbAlloc;
  617. //
  618. // An ISP consists of the "above" part, the "below" part, and
  619. // the baggage passed by the app. Negative baggage is okay;
  620. // it means we have a down-level app that doesn't know about
  621. // pszHeaderTitle.
  622. //
  623. pbAlloc = LocalAlloc(LPTR, sizeof(pisp->above) + sizeof(pisp->below) +
  624. (dwClientSize - sizeof(PROPSHEETPAGE)));
  625. if (!pbAlloc)
  626. return NULL;
  627. pisp = (PISP)(pbAlloc + sizeof(pisp->above));
  628. //
  629. // Set up the CLASSICPREFIX fields.
  630. //
  631. pisp->_cpfx.pispMain = pisp;
  632. ASSERT(pisp->_cpfx.pispShadow == NULL);
  633. //
  634. // Assume no shadow - The app gets the PISP itself.
  635. //
  636. pisp->_pfx.hpage = (HPROPSHEETPAGE)pisp;
  637. return pisp;
  638. }
  639. //
  640. // Helper function during page creation. The incoming string is really
  641. // an ANSI string. Thunk it to UNICODE. Fortunately, we already have
  642. // another helper function that does the work.
  643. //
  644. STDAPI_(LPTSTR) StrDup_AtoW(LPCTSTR ptsz)
  645. {
  646. return ProduceWFromA(CP_ACP, (LPCSTR)ptsz);
  647. }
  648. //
  649. // CreatePropertySheetPage
  650. //
  651. // Where HPROPSHEETPAGEs come from.
  652. //
  653. // The fNeedShadow parameter means "The incoming LPCPROPSHEETPAGE is in the
  654. // opposite character set from what you implement natively".
  655. //
  656. // If we are compiling UNICODE, then fNeedShadow is TRUE if the incoming
  657. // LPCPROPSHEETPAGE is really an ANSI property sheet page.
  658. //
  659. // If we are compiling ANSI-only, then fNeedShadow is always FALSE because
  660. // we don't support UNICODE in the ANSI-only version.
  661. //
  662. HPROPSHEETPAGE WINAPI _CreatePropertySheetPage(LPCPROPSHEETPAGE psp, BOOL fNeedShadow, BOOL fWx86)
  663. {
  664. PISP pisp;
  665. DWORD dwSize;
  666. COMPILETIME_ASSERT(PROPSHEETPAGEA_V1_SIZE == PROPSHEETPAGEW_V1_SIZE);
  667. COMPILETIME_ASSERT(sizeof(PROPSHEETPAGEA) == sizeof(PROPSHEETPAGEW));
  668. if ((psp->dwSize < MINPROPSHEETPAGESIZE) ||
  669. (psp->dwSize > 4096) || // or the second version
  670. (psp->dwFlags & ~PSP_ALL)) // bogus flag used
  671. {
  672. return NULL;
  673. }
  674. //
  675. // The PROPSHEETPAGE structure can be larger than the
  676. // defined size. This allows ISV's to place private
  677. // data at the end of the structure. The ISP structure
  678. // consists of some private fields and a PROPSHEETPAGE
  679. // structure. Calculate the size of the private fields,
  680. // and then add in the dwSize field to determine the
  681. // amount of memory necessary.
  682. //
  683. //
  684. // An ISP consists of the "above" part, the "below" part, and
  685. // the baggage passed by the app. Negative baggage is okay;
  686. // it means we have a down-level app that doesn't know about
  687. // pszHeaderTitle.
  688. //
  689. //
  690. // If we have an "other" client, then the native side of the
  691. // property sheet doesn't carry any baggage. It's just a
  692. // plain old PROPSHEETPAGE.
  693. //
  694. dwSize = fNeedShadow ? sizeof(PROPSHEETPAGE) : psp->dwSize;
  695. pisp = AllocPropertySheetPage(dwSize);
  696. if (pisp)
  697. {
  698. STRDUPPROC pfnStrDup;
  699. #ifdef WX86
  700. //
  701. // We we're being called by Wx86, set the flag so we remember.
  702. //
  703. if ( fWx86 ) {
  704. pisp->_pfx.dwInternalFlags |= PSPI_WX86;
  705. }
  706. #endif
  707. SETORIGINALSIZE(pisp, dwSize);
  708. //
  709. // Bulk copy the contents of the PROPSHEETPAGE, or
  710. // as much of it as the app gave us.
  711. //
  712. hmemcpy(&pisp->_psp, psp, min(dwSize, psp->dwSize));
  713. //
  714. // Decide how to copy the strings
  715. //
  716. if (fNeedShadow)
  717. pfnStrDup = StrDup_AtoW;
  718. else
  719. pfnStrDup = StrDup;
  720. // Now copy them
  721. if (!CopyPropertyPageStrings(&pisp->_psp, pfnStrDup))
  722. goto ExitStrings;
  723. if (fNeedShadow)
  724. {
  725. PISP pispAnsi = AllocPropertySheetPage(psp->dwSize);
  726. if (!pispAnsi)
  727. goto ExitShadow;
  728. //
  729. // Copy the entire client PROPSHEETPAGE, including the
  730. // baggage.
  731. //
  732. hmemcpy(&pispAnsi->_psp, psp, psp->dwSize);
  733. //
  734. // Hook the two copies to point to each other.
  735. //
  736. pisp->_cpfx.pispShadow = pispAnsi;
  737. pispAnsi->_cpfx.pispShadow = pispAnsi;
  738. pispAnsi->_cpfx.pispMain = pisp;
  739. //
  740. // If there is a shadow, then the
  741. // external handle is the ANSI shadow.
  742. //
  743. ASSERT(pispAnsi->_pfx.hpage == (HPROPSHEETPAGE)pispAnsi);
  744. pisp->_pfx.hpage = (HPROPSHEETPAGE)pispAnsi;
  745. //
  746. // Okay, now StrDupA them strings.
  747. //
  748. if (!CopyPropertyPageStrings(&pispAnsi->_psp, (STRDUPPROC)StrDupA))
  749. goto ExitShadowStrings;
  750. }
  751. //
  752. // Increment the reference count to the parent object.
  753. //
  754. if (HASREFPARENT(pisp))
  755. InterlockedIncrement((LPLONG)pisp->_psp.pcRefParent);
  756. //
  757. // Welcome to the world.
  758. //
  759. CallPropertyPageCallback(NULL, pisp, PSPCB_ADDREF); // don't need because there is no hwnd
  760. return ExternalizeHPROPSHEETPAGE(pisp);
  761. }
  762. else
  763. {
  764. return NULL;
  765. }
  766. ExitShadowStrings:
  767. FreePropertyPageStrings(&pisp->_cpfx.pispShadow->_psp);
  768. FreePropertyPageStruct(pisp->_cpfx.pispShadow);
  769. ExitShadow:;
  770. ExitStrings:
  771. FreePropertyPageStrings(&pisp->_psp);
  772. FreePropertyPageStruct(pisp);
  773. return NULL;
  774. }
  775. HPROPSHEETPAGE WINAPI CreatePropertySheetPageW(LPCPROPSHEETPAGEW psp)
  776. {
  777. BOOL fWx86 = FALSE;
  778. #ifdef WX86
  779. fWx86 = Wx86IsCallThunked();
  780. #endif
  781. return _CreatePropertySheetPage(psp, FALSE, fWx86);
  782. }
  783. HPROPSHEETPAGE WINAPI CreatePropertySheetPageA(LPCPROPSHEETPAGEA psp)
  784. {
  785. BOOL fWx86 = FALSE;
  786. #ifdef WX86
  787. fWx86 = Wx86IsCallThunked();
  788. #endif
  789. return _CreatePropertySheetPage((LPCPROPSHEETPAGE)psp, TRUE, fWx86);
  790. }