Leaked source code of windows server 2003
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.

876 lines
26 KiB

  1. //
  2. // MyPrSht.cpp
  3. //
  4. // Implementation of the extensions made to the PropertySheet API
  5. // in IE5, but which we need on all platforms.
  6. //
  7. // History:
  8. //
  9. // 10/11/1999 KenSh Created
  10. //
  11. #include "stdafx.h"
  12. #include "TheApp.h"
  13. #include "MyPrSht.h"
  14. #include "CWnd.h"
  15. #include "unicwrap.h"
  16. // Thunk up to propsheetpage v6 for XP
  17. typedef struct _PROPSHEETPAGEV6W
  18. {
  19. DWORD dwSize;
  20. DWORD dwFlags;
  21. HINSTANCE hInstance;
  22. union
  23. {
  24. LPCWSTR pszTemplate;
  25. #ifdef _WIN32
  26. LPCDLGTEMPLATE pResource;
  27. #else
  28. const VOID *pResource;
  29. #endif
  30. } DUMMYUNIONNAME;
  31. union
  32. {
  33. HICON hIcon;
  34. LPCWSTR pszIcon;
  35. } DUMMYUNIONNAME2;
  36. LPCWSTR pszTitle;
  37. DLGPROC pfnDlgProc;
  38. LPARAM lParam;
  39. LPFNPSPCALLBACKW pfnCallback;
  40. UINT *pcRefParent;
  41. #if (_WIN32_IE >= 0x0400)
  42. LPCWSTR pszHeaderTitle; // this is displayed in the header
  43. LPCWSTR pszHeaderSubTitle; ///
  44. #endif
  45. HANDLE hActCtx;
  46. } PROPSHEETPAGEV6W, *LPPROPSHEETPAGEV6W;
  47. // Local data
  48. //
  49. static CMyPropSheet* g_pMyPropSheet;
  50. static const TCHAR c_szProp_ClassPointer[] = _T("CP");
  51. #define DEFAULTHEADERHEIGHT 58 // in pixels
  52. #define DEFAULTTEXTDIVIDERGAP 5
  53. #define DEFAULTCTRLWIDTH 501 // page list window in new wizard style
  54. #define DEFAULTCTRLHEIGHT 253 // page list window in new wizard style
  55. #define TITLEX 22
  56. #define TITLEY 10
  57. #define SUBTITLEX 44
  58. #define SUBTITLEY 25
  59. // fixed sizes for the bitmap painted in the header section
  60. #define HEADERBITMAP_Y 5
  61. #define HEADERBITMAP_WIDTH 49
  62. #define HEADERBITMAP_CXBACK (5 + HEADERBITMAP_WIDTH)
  63. #define HEADERBITMAP_HEIGHT 49
  64. #define HEADERSUBTITLE_WRAPOFFSET 10
  65. // Fixed sizes for the watermark bitmap (Wizard97IE5 style)
  66. #define BITMAP_WIDTH 164
  67. #define BITMAP_HEIGHT 312
  68. #define DRAWTEXT_WIZARD97FLAGS (DT_LEFT | DT_WORDBREAK | DT_NOPREFIX | DT_EDITCONTROL)
  69. #define IDD_PAGELIST 0x3020
  70. #define IDD_DIVIDER 0x3026
  71. #define IDD_TOPDIVIDER 0x3027
  72. #ifndef IS_INTRESOURCE
  73. #define IS_INTRESOURCE(psz) (HIWORD((DWORD_PTR)(psz)) == 0)
  74. #endif
  75. /////////////////////////////////////////////////////////////////////////////
  76. // MyPropertySheet
  77. INT_PTR MyPropertySheet(LPCPROPSHEETHEADER pHeader)
  78. {
  79. // If IE5 is present, use the built-in property sheet code
  80. // REVIEW: should we bother checking for IE5 on older OS's?
  81. if (theApp.IsWin98SEOrLater() && (! theApp.IsBiDiLocalized()) )
  82. {
  83. // ISSUE-2002/01/16-roelfc: THUNK THIS (but which way???)
  84. return PropertySheet(pHeader);
  85. }
  86. // ISSUE-2002/01/16-roelfc: nobody destroys g_pMyPropSheet, nobody does g_pMyPropSheet->Release()
  87. ASSERT(g_pMyPropSheet == NULL);
  88. g_pMyPropSheet = new CMyPropSheet();
  89. if (g_pMyPropSheet)
  90. return g_pMyPropSheet->DoPropSheet(pHeader);
  91. else
  92. return NULL;
  93. }
  94. /////////////////////////////////////////////////////////////////////////////
  95. // MyCreatePropertySheetPage
  96. HPROPSHEETPAGE MyCreatePropertySheetPage(LPPROPSHEETPAGE ppsp)
  97. {
  98. // If IE5 is present, use the built-in property sheet code
  99. // REVIEW: should we bother checking for IE5 on older OS's?
  100. if (theApp.IsWin98SEOrLater() && (! theApp.IsBiDiLocalized()) )
  101. {
  102. if (g_fRunningOnNT)
  103. {
  104. PROPSHEETPAGEV6W spv6;
  105. ASSERT(sizeof (spv6) >= sizeof (PROPSHEETPAGE));
  106. memcpy(&spv6, ppsp, sizeof (PROPSHEETPAGE));
  107. spv6.dwSize = sizeof (spv6);
  108. spv6.hActCtx = NULL;
  109. return CreatePropertySheetPage((PROPSHEETPAGE*) &spv6);
  110. }
  111. else
  112. {
  113. return CreatePropertySheetPage(ppsp);
  114. }
  115. }
  116. PROPSHEETPAGE psp;
  117. CopyMemory(&psp, ppsp, ppsp->dwSize);
  118. // REVIEW: this memory is never freed
  119. LPPROPSHEETPAGE ppspOriginal = (LPPROPSHEETPAGE)malloc(sizeof(PROPSHEETPAGE));
  120. if (ppspOriginal)
  121. {
  122. CopyMemory(ppspOriginal, ppsp, ppsp->dwSize);
  123. psp.dwSize = PROPSHEETPAGE_V1_SIZE;
  124. psp.dwFlags &= ~(PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE | PSP_HIDEHEADER);
  125. psp.lParam = (LPARAM)ppspOriginal;
  126. return ::CreatePropertySheetPage(&psp);
  127. }
  128. return NULL;
  129. }
  130. /////////////////////////////////////////////////////////////////////////////
  131. // IsIMEWindow
  132. BOOL IsIMEWindow(HWND hwnd, LPCREATESTRUCT lpcs)
  133. {
  134. // check for cheap CS_IME style first...
  135. if (GetClassLong(hwnd, GCL_STYLE) & CS_IME)
  136. return TRUE;
  137. // get class name of the window that is being created
  138. LPCTSTR pszClassName;
  139. TCHAR szClassName[_countof("ime")+1];
  140. if (HIWORD(lpcs->lpszClass))
  141. {
  142. pszClassName = lpcs->lpszClass;
  143. }
  144. else
  145. {
  146. szClassName[0] = _T('\0');
  147. GlobalGetAtomName((ATOM)lpcs->lpszClass, szClassName, _countof(szClassName));
  148. pszClassName = szClassName;
  149. }
  150. // a little more expensive to test this way, but necessary...
  151. if (StrCmpI(pszClassName, _T("ime")) == 0)
  152. return TRUE;
  153. return FALSE; // not an IME window
  154. }
  155. void CMyPropSheet::SetHeaderFonts()
  156. {
  157. if (m_hFontBold == NULL)
  158. {
  159. LOGFONT LogFont;
  160. GetObject(GetWindowFont(m_hWnd), sizeof(LogFont), &LogFont);
  161. LogFont.lfWeight = FW_BOLD;
  162. m_hFontBold = CreateFontIndirect(&LogFont);
  163. }
  164. }
  165. // Kensh: Copied and modified from _ComputeHeaderHeight in prsht.c (comctl32.dll)
  166. //
  167. // In Wizard97 only:
  168. // The subtitles user passed in could be larger than the two line spaces we give
  169. // them, especially in localization cases. So here we go through all subtitles and
  170. // compute the max space they need and set the header height so that no text is clipped
  171. int CMyPropSheet::ComputeHeaderHeight(int dxMax)
  172. {
  173. SetHeaderFonts();
  174. int dyHeaderHeight;
  175. int dyTextDividerGap;
  176. HDC hdc;
  177. dyHeaderHeight = DEFAULTHEADERHEIGHT;
  178. hdc = ::GetDC(m_hWnd);
  179. // First, let's get the correct text height and spacing, this can be used
  180. // as the title height and the between-lastline-and-divider spacing.
  181. {
  182. HFONT hFont, hFontOld;
  183. TEXTMETRIC tm;
  184. if (m_hFontBold)
  185. hFont = m_hFontBold;
  186. else
  187. hFont = GetWindowFont(m_hWnd);
  188. hFontOld = (HFONT)SelectObject(hdc, hFont);
  189. if (GetTextMetrics(hdc, &tm))
  190. {
  191. dyTextDividerGap = tm.tmExternalLeading;
  192. m_ySubTitle = max ((tm.tmHeight + tm.tmExternalLeading + TITLEY), SUBTITLEY);
  193. }
  194. else
  195. {
  196. dyTextDividerGap = DEFAULTTEXTDIVIDERGAP;
  197. m_ySubTitle = SUBTITLEY;
  198. }
  199. if (hFontOld)
  200. SelectObject(hdc, hFontOld);
  201. }
  202. // Second, get the subtitle text block height
  203. // should make into a function if shared
  204. {
  205. RECT rcWrap;
  206. // UINT uPages;
  207. //
  208. // WIZARD97IE5 subtracts out the space used by the header bitmap.
  209. // WIZARD97IE4 uses the full width since the header bitmap
  210. // in IE4 is a watermark and occupies no space.
  211. //
  212. // if (ppd->psh.dwFlags & PSH_WIZARD97IE4)
  213. // rcWrap.right = dxMax;
  214. // else
  215. rcWrap.right = dxMax - HEADERBITMAP_CXBACK - HEADERSUBTITLE_WRAPOFFSET;
  216. // Note (kensh): the "real" wizard code computes the max height across
  217. // all pages. Our cheap version only computes the current page's height
  218. LPPROPSHEETPAGE ppsp = GetCurrentPropSheetPage();
  219. if (ppsp != NULL)
  220. {
  221. if (!(ppsp->dwFlags & PSP_HIDEHEADER) &&
  222. (ppsp->dwFlags & PSP_USEHEADERSUBTITLE))
  223. {
  224. int iSubHeaderHeight = WriteHeaderTitle(hdc, &rcWrap, ppsp->pszHeaderSubTitle,
  225. FALSE, DT_CALCRECT | DRAWTEXT_WIZARD97FLAGS);
  226. if ((iSubHeaderHeight + m_ySubTitle) > dyHeaderHeight)
  227. dyHeaderHeight = iSubHeaderHeight + m_ySubTitle;
  228. }
  229. }
  230. }
  231. // If the header height has been recomputed, set the correct gap between
  232. // the text and the divider.
  233. if (dyHeaderHeight != DEFAULTHEADERHEIGHT)
  234. {
  235. ASSERT(dyHeaderHeight > DEFAULTHEADERHEIGHT);
  236. dyHeaderHeight += dyTextDividerGap;
  237. }
  238. ::ReleaseDC(m_hWnd, hdc);
  239. return dyHeaderHeight;
  240. }
  241. // Kensh: Copied and modified from _WriteHeaderTitle in prsht.c (comctl32.dll)
  242. //
  243. int CMyPropSheet::WriteHeaderTitle(HDC hdc, LPRECT prc, LPCTSTR pszTitle, BOOL bTitle, DWORD dwDrawFlags)
  244. {
  245. SetHeaderFonts();
  246. LPCTSTR pszOut;
  247. int cch;
  248. int cx, cy;
  249. UINT ETO_Flags=0;
  250. SIZE Size;
  251. TCHAR szTitle[MAX_PATH*4];
  252. HFONT hFontOld = NULL;
  253. HFONT hFont;
  254. int yDrawHeight = 0;
  255. if (IS_INTRESOURCE(pszTitle))
  256. {
  257. LPPROPSHEETPAGE ppsp = GetCurrentPropSheetPage();
  258. if (NULL != ppsp)
  259. {
  260. LoadString(ppsp->hInstance, (UINT)LOWORD(pszTitle), szTitle, _countof(szTitle));
  261. }
  262. else
  263. {
  264. *szTitle = 0;
  265. }
  266. pszOut = szTitle;
  267. }
  268. else
  269. pszOut = pszTitle;
  270. cch = lstrlen(pszOut);
  271. if (bTitle && m_hFontBold)
  272. hFont = m_hFontBold;
  273. else
  274. hFont = GetWindowFont(m_hWnd);
  275. hFontOld = (HFONT)SelectObject(hdc, hFont);
  276. if (bTitle)
  277. {
  278. cx = TITLEX;
  279. cy = TITLEY;
  280. if (theApp.IsBiDiLocalized())
  281. {
  282. ETO_Flags |= ETO_RTLREADING;
  283. if (GetTextExtentPoint32(hdc, pszOut, lstrlen (pszOut), &Size))
  284. cx = prc->right - Size.cx;
  285. }
  286. ExtTextOut(hdc, cx, cy, ETO_Flags, prc, pszOut, cch, NULL);
  287. }
  288. else
  289. {
  290. RECT rcWrap;
  291. CopyRect(&rcWrap, prc);
  292. rcWrap.left = SUBTITLEX;
  293. rcWrap.top = m_ySubTitle;
  294. if (theApp.IsBiDiLocalized())
  295. {
  296. dwDrawFlags |= DT_RTLREADING | DT_RIGHT;
  297. }
  298. yDrawHeight = DrawText(hdc, pszOut, cch, &rcWrap, dwDrawFlags);
  299. }
  300. if (hFontOld)
  301. SelectObject(hdc, hFontOld);
  302. return yDrawHeight;
  303. }
  304. /////////////////////////////////////////////////////////////////////////////
  305. // CMyPropSheet
  306. CMyPropSheet::CMyPropSheet()
  307. {
  308. m_pRealHeader = NULL;
  309. m_hHook = NULL;
  310. m_hbrWindow = NULL;
  311. m_hbrDialog = NULL;
  312. m_hwndActive = NULL;
  313. m_hbmWatermark = NULL;
  314. m_hbmHeader = NULL;
  315. m_hpalWatermark = NULL;
  316. m_hFontBold = NULL;
  317. }
  318. CMyPropSheet::~CMyPropSheet()
  319. {
  320. free(m_pRealHeader);
  321. ASSERT(m_hHook == NULL);
  322. if (m_hbrWindow != NULL)
  323. DeleteObject(m_hbrWindow);
  324. if (m_hbrDialog != NULL)
  325. DeleteObject(m_hbrDialog);
  326. }
  327. void CMyPropSheet::InitColorSettings()
  328. {
  329. if (m_hbrWindow != NULL)
  330. DeleteObject(m_hbrWindow);
  331. m_hbrWindow = CreateSolidBrush(GetSysColor(COLOR_WINDOW));
  332. if (m_hbrDialog != NULL)
  333. DeleteObject(m_hbrDialog);
  334. m_hbrDialog = CreateSolidBrush(GetSysColor(COLOR_3DFACE));
  335. }
  336. void CMyPropSheet::LoadBitmaps()
  337. {
  338. LPPROPSHEETHEADER ppsh = m_pRealHeader;
  339. if (ppsh)
  340. {
  341. if (ppsh->dwFlags & PSH_USEHBMHEADER)
  342. m_hbmHeader = ppsh->hbmHeader;
  343. else
  344. m_hbmHeader = LoadBitmap(ppsh->hInstance, ppsh->pszbmHeader);
  345. if (ppsh->dwFlags & PSH_USEHBMWATERMARK)
  346. m_hbmWatermark = ppsh->hbmWatermark;
  347. else
  348. m_hbmWatermark = LoadBitmap(ppsh->hInstance, ppsh->pszbmWatermark);
  349. // Note: might need a palette later, but so far it hasn't been necessary
  350. }
  351. }
  352. INT_PTR CMyPropSheet::DoPropSheet(LPCPROPSHEETHEADER ppsh)
  353. {
  354. INT_PTR nResult = 0;
  355. ASSERT(m_pRealHeader == NULL);
  356. m_pRealHeader = (LPPROPSHEETHEADER)malloc(ppsh->dwSize);
  357. if (m_pRealHeader)
  358. {
  359. CopyMemory(m_pRealHeader, ppsh, ppsh->dwSize);
  360. InitColorSettings();
  361. // Create header and watermark bitmaps
  362. LoadBitmaps();
  363. PROPSHEETHEADER psh;
  364. ASSERT(sizeof(psh) >= ppsh->dwSize);
  365. CopyMemory(&psh, ppsh, ppsh->dwSize);
  366. psh.dwSize = PROPSHEETHEADER_V1_SIZE;
  367. psh.dwFlags &= 0x00000fff; // W95 gold comctl32 prop sheet mask.
  368. psh.dwFlags |= PSH_WIZARD;
  369. ASSERT(m_hHook == NULL);
  370. m_hHook = SetWindowsHookEx(WH_CBT, HookProc, NULL, GetCurrentThreadId());
  371. nResult = ::PropertySheet(&psh);
  372. if (m_hHook != NULL)
  373. {
  374. UnhookWindowsHookEx(m_hHook);
  375. m_hHook = NULL;
  376. }
  377. }
  378. return nResult;
  379. }
  380. LRESULT CALLBACK CMyPropSheet::HookProc(int nCode, WPARAM wParam, LPARAM lParam)
  381. {
  382. ASSERT(g_pMyPropSheet != NULL);
  383. LRESULT lResult = CallNextHookEx(g_pMyPropSheet->m_hHook, nCode, wParam, lParam);
  384. if (nCode == HCBT_CREATEWND)
  385. {
  386. HWND hwnd = (HWND)wParam;
  387. LPCBT_CREATEWND pCbt = (LPCBT_CREATEWND)lParam;
  388. // Make sure this isn't an IME window
  389. if (IsIMEWindow(hwnd, pCbt->lpcs))
  390. goto done;
  391. if (g_pMyPropSheet->m_hWnd == NULL) // The main wizard window
  392. {
  393. // Add the WS_EX_DLGMODALFRAME extended style to the window
  394. // Remove WS_EX_CONTEXTHELP extended style from the window
  395. SHSetWindowBits(hwnd, GWL_EXSTYLE, WS_EX_DLGMODALFRAME|WS_EX_CONTEXTHELP, WS_EX_DLGMODALFRAME);
  396. // Add the WS_SYSMENU style to the window
  397. SHSetWindowBits(hwnd, GWL_STYLE, WS_SYSMENU, WS_SYSMENU);
  398. // Subclass the window
  399. g_pMyPropSheet->Attach(hwnd);
  400. }
  401. else if (pCbt->lpcs->hwndParent == g_pMyPropSheet->m_hWnd &&
  402. pCbt->lpcs->hMenu == NULL &&
  403. (pCbt->lpcs->style & WS_CHILD) == WS_CHILD)
  404. {
  405. // It's a wizard page sub-dialog -- subclass it so we can
  406. // draw its background
  407. CMyPropPage* pPropPage = new CMyPropPage;
  408. if (pPropPage)
  409. {
  410. pPropPage->Attach(hwnd);
  411. pPropPage->Release();
  412. }
  413. }
  414. }
  415. else if (nCode == HCBT_DESTROYWND)
  416. {
  417. HWND hwnd = (HWND)wParam;
  418. if (hwnd == g_pMyPropSheet->m_hWnd)
  419. {
  420. // Main window being destroyed -- stop hooking window creation
  421. UnhookWindowsHookEx(g_pMyPropSheet->m_hHook);
  422. g_pMyPropSheet->m_hHook = NULL;
  423. }
  424. }
  425. done:
  426. return lResult;
  427. }
  428. LPPROPSHEETPAGE CMyPropSheet::GetCurrentPropSheetPage()
  429. {
  430. CMyPropPage* pPage = CMyPropPage::FromHandle(GetActivePage());
  431. if (pPage)
  432. {
  433. return pPage->GetPropSheetPage();
  434. }
  435. return NULL;
  436. }
  437. LRESULT CMyPropSheet::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
  438. {
  439. switch (message)
  440. {
  441. case WM_SETTINGCHANGE:
  442. {
  443. InitColorSettings();
  444. return Default(message, wParam, lParam);
  445. }
  446. case PSM_SETCURSEL:
  447. {
  448. InvalidateRect(m_hWnd, NULL, TRUE);
  449. return Default(message, wParam, lParam);
  450. }
  451. break;
  452. /*
  453. case WM_ERASEBKGND:
  454. {
  455. TRACE("Main window - WM_ERASEBKGND - active page = %X\r\n", GetActivePage());
  456. LPPROPSHEETPAGE ppsp = GetCurrentPropSheetPage();
  457. HDC hdc = (HDC)wParam;
  458. RECT rcClient;
  459. GetClientRect(&rcClient);
  460. if (ppsp->dwFlags & PSP_HIDEHEADER)
  461. {
  462. RECT rcDivider;
  463. GetDlgItemRect(hwnd, IDD_DIVIDER, &rcDivider);
  464. rcClient.top = rcDivider.bottom;
  465. FillRect(hdc, &rcClient, m_hbrDialog);
  466. rcClient.bottom = rcClient.top;
  467. rcClient.top = 0;
  468. FillRect(hdc, &rcClient, m_hbrWindow);
  469. return TRUE;
  470. }
  471. else
  472. {
  473. RECT rcHeader;
  474. CopyRect(&rcHeader, &rcClient);
  475. rcHeader.bottom = DEFAULTHEADERHEIGHT;
  476. FillRect(hdc, &rcHeader, m_hbrWindow);
  477. rcClient.top = rcHeader.bottom;
  478. FillRect(hdc, &rcClient, m_hbrDialog);
  479. }
  480. }
  481. return FALSE;
  482. */
  483. case WM_PAINT:
  484. {
  485. PAINTSTRUCT ps;
  486. LPPROPSHEETPAGE ppsp = GetCurrentPropSheetPage();
  487. HDC hdc = ::BeginPaint(m_hWnd, &ps);
  488. if (ppsp != NULL)
  489. {
  490. if (ppsp->dwFlags & PSP_HIDEHEADER)
  491. {
  492. // Draw the watermark
  493. PaintWatermark(hdc, ppsp);
  494. }
  495. else
  496. {
  497. // Draw the header
  498. PaintHeader(hdc, ppsp);
  499. }
  500. }
  501. ::EndPaint(m_hWnd, &ps);
  502. }
  503. break;
  504. case WM_CTLCOLOREDIT:
  505. case WM_CTLCOLORDLG:
  506. case WM_CTLCOLOR:
  507. case WM_CTLCOLORMSGBOX:
  508. case WM_CTLCOLORLISTBOX:
  509. case WM_CTLCOLORBTN:
  510. case WM_CTLCOLORSCROLLBAR:
  511. case WM_CTLCOLORSTATIC:
  512. {
  513. return (LRESULT)OnCtlColor(message, (HDC)wParam, (HWND)lParam);
  514. }
  515. default:
  516. {
  517. return Default(message, wParam, lParam);
  518. }
  519. }
  520. return 0;
  521. }
  522. HBRUSH CMyPropSheet::OnCtlColor(UINT message, HDC hdc, HWND hwndControl)
  523. {
  524. HBRUSH hbr = (HBRUSH)Default(message, (WPARAM)hdc, (LPARAM)hwndControl);
  525. if (message == WM_CTLCOLOREDIT || message == WM_CTLCOLORDLG)
  526. return hbr;
  527. SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));
  528. SetBkColor(hdc, GetSysColor(COLOR_WINDOW));
  529. return m_hbrWindow;
  530. }
  531. //
  532. // lprc is the target rectangle.
  533. // Use as much of the bitmap as will fit into the target rectangle.
  534. // If the bitmap is smaller than the target rectangle, then fill the rest with
  535. // the pixel in the upper left corner of the hbmpPaint.
  536. //
  537. void PaintWithPaletteBitmap(HDC hdc, LPRECT lprc, HPALETTE hplPaint, HBITMAP hbmpPaint)
  538. {
  539. HDC hdcBmp = CreateCompatibleDC(hdc);
  540. if (hdcBmp)
  541. {
  542. BITMAP bm;
  543. int cxRect, cyRect, cxBmp, cyBmp;
  544. GetObject(hbmpPaint, sizeof(BITMAP), &bm);
  545. SelectObject(hdcBmp, hbmpPaint);
  546. if (hplPaint)
  547. {
  548. SelectPalette(hdc, hplPaint, FALSE);
  549. RealizePalette(hdc);
  550. }
  551. cxRect = RECTWIDTH(*lprc);
  552. cyRect = RECTHEIGHT(*lprc);
  553. // Never use more pixels from the bmp as we have room in the rect.
  554. cxBmp = min(bm.bmWidth, cxRect);
  555. cyBmp = min(bm.bmHeight, cyRect);
  556. BitBlt(hdc, lprc->left, lprc->top, cxBmp, cyBmp, hdcBmp, 0, 0, SRCCOPY);
  557. // If bitmap is too narrow, then StretchBlt to fill the width.
  558. if (cxBmp < cxRect)
  559. StretchBlt(hdc, lprc->left + cxBmp, lprc->top,
  560. cxRect - cxBmp, cyBmp,
  561. hdcBmp, 0, 0, 1, 1, SRCCOPY);
  562. // If bitmap is to short, then StretchBlt to fill the height.
  563. if (cyBmp < cyRect)
  564. StretchBlt(hdc, lprc->left, cyBmp,
  565. cxRect, cyRect - cyBmp,
  566. hdcBmp, 0, 0, 1, 1, SRCCOPY);
  567. DeleteDC(hdcBmp);
  568. }
  569. }
  570. void CMyPropSheet::PaintWatermark(HDC hdc, LPPROPSHEETPAGE ppsp)
  571. {
  572. RECT rcClient;
  573. RECT rcClient_Dlg;
  574. GetClientRect(m_hWnd, &rcClient);
  575. GetClientRect(m_hWnd, &rcClient_Dlg);
  576. RECT rcDivider;
  577. GetDlgItemRect(m_hWnd, IDD_DIVIDER, &rcDivider);
  578. if (m_hbmWatermark)
  579. {
  580. // Bottom gets gray
  581. rcClient.top = rcDivider.bottom;
  582. FillRect(hdc, &rcClient, m_hbrDialog);
  583. rcClient.bottom = rcClient.top;
  584. rcClient.top = 0;
  585. // Right-hand side gets m_hbrWindow.
  586. if (theApp.IsBiDiLocalized())
  587. rcClient.right = rcClient_Dlg.right - BITMAP_WIDTH;
  588. else
  589. rcClient.left = BITMAP_WIDTH;
  590. FillRect(hdc, &rcClient, m_hbrWindow);
  591. // Left-hand side gets watermark in top portion with autofill...
  592. if (theApp.IsBiDiLocalized())
  593. {
  594. rcClient.right = rcClient_Dlg.right;
  595. rcClient.left = rcClient_Dlg.right - BITMAP_WIDTH;
  596. }
  597. else
  598. {
  599. rcClient.right = rcClient.left;
  600. rcClient.left = 0;
  601. }
  602. PaintWithPaletteBitmap(hdc, &rcClient, m_hpalWatermark, m_hbmWatermark);
  603. }
  604. }
  605. void CMyPropSheet::PaintHeader(HDC hdc, LPPROPSHEETPAGE ppsp)
  606. {
  607. RECT rcClient, rcHeaderBitmap;
  608. GetClientRect(m_hWnd, &rcClient);
  609. int cyHeader = ComputeHeaderHeight(rcClient.right);
  610. // Bottom gets gray
  611. rcClient.top = cyHeader;
  612. FillRect(hdc, &rcClient, m_hbrDialog);
  613. // Top gets white
  614. rcClient.bottom = rcClient.top;
  615. rcClient.top = 0;
  616. FillRect(hdc, &rcClient, m_hbrWindow);
  617. // Draw the fixed-size header bitmap
  618. int bx= RECTWIDTH(rcClient) - HEADERBITMAP_CXBACK;
  619. ASSERT(bx > 0);
  620. SetRect(&rcHeaderBitmap, bx, HEADERBITMAP_Y, bx + HEADERBITMAP_WIDTH, HEADERBITMAP_Y + HEADERBITMAP_HEIGHT);
  621. PaintWithPaletteBitmap(hdc, &rcHeaderBitmap, m_hpalWatermark, m_hbmHeader);
  622. // Draw header title & subtitle
  623. rcClient.right = bx - HEADERSUBTITLE_WRAPOFFSET;
  624. WriteHeaderTitle(hdc, &rcClient, ppsp->pszHeaderTitle, TRUE, DRAWTEXT_WIZARD97FLAGS);
  625. WriteHeaderTitle(hdc, &rcClient, ppsp->pszHeaderSubTitle, FALSE, DRAWTEXT_WIZARD97FLAGS);
  626. }
  627. /////////////////////////////////////////////////////////////////////////////
  628. // CMyPropPage
  629. CMyPropPage* CMyPropPage::FromHandle(HWND hwnd)
  630. {
  631. return (CMyPropPage*)(CWnd::FromHandle(hwnd));
  632. }
  633. LPPROPSHEETPAGE CMyPropPage::GetPropSheetPage()
  634. {
  635. return m_ppspOriginal;
  636. }
  637. LRESULT CMyPropPage::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
  638. {
  639. switch (message)
  640. {
  641. case WM_INITDIALOG:
  642. {
  643. LPPROPSHEETPAGE ppspBogus = (LPPROPSHEETPAGE)lParam;
  644. LPPROPSHEETPAGE ppspOriginal = (LPPROPSHEETPAGE) ppspBogus->lParam;
  645. m_ppspOriginal = ppspOriginal;
  646. lParam = (LPARAM)ppspOriginal;
  647. }
  648. break;
  649. case WM_ERASEBKGND:
  650. {
  651. if ((m_ppspOriginal->dwFlags & PSP_HIDEHEADER) != 0)
  652. {
  653. // Let the parent window bleed through
  654. return FALSE;
  655. }
  656. }
  657. break;
  658. case WM_CTLCOLORSTATIC:
  659. {
  660. if ((m_ppspOriginal->dwFlags & PSP_HIDEHEADER) != 0)
  661. {
  662. return (LRESULT)g_pMyPropSheet->OnCtlColor(message, (HDC)wParam, (HWND)lParam);
  663. }
  664. }
  665. break;
  666. case WM_NOTIFY:
  667. {
  668. NMHDR* pHdr = (NMHDR*)lParam;
  669. switch (pHdr->code)
  670. {
  671. case PSN_KILLACTIVE:
  672. {
  673. // TRACE("PSN_KILLACTIVE - hwnd = %X\r\n", hwnd);
  674. }
  675. break;
  676. case PSN_SETACTIVE:
  677. {
  678. // TRACE("PSN_SETACTIVE - hwnd = %X\r\n", hwnd);
  679. HWND hwndParent = GetParent(m_hWnd);
  680. RECT rcParent;
  681. ::GetClientRect(hwndParent, &rcParent);
  682. RECT rcTopDivider;
  683. HWND hwndTopDivider = GetDlgItemRect(hwndParent, IDD_TOPDIVIDER, &rcTopDivider);
  684. // Hide the tab control (not sure why it's showing up, but it shouldn't)
  685. ShowWindow(::GetDlgItem(hwndParent, IDD_PAGELIST), SW_HIDE);
  686. RECT rcDivider;
  687. HWND hwndDivider = GetDlgItemRect(hwndParent, IDD_DIVIDER, &rcDivider);
  688. // Set the proper size and position for the dialog
  689. if ((m_ppspOriginal->dwFlags & PSP_HIDEHEADER) != 0)
  690. {
  691. // Reposition the divider
  692. SetWindowPos(hwndDivider, NULL, 0, rcDivider.top, rcParent.right, RECTHEIGHT(rcDivider),
  693. SWP_NOZORDER | SWP_NOACTIVATE);
  694. // Hide the top divider
  695. if (hwndTopDivider != NULL)
  696. ShowWindow(hwndTopDivider, SW_HIDE);
  697. // Reposition the dialog
  698. SetWindowPos(m_hWnd, NULL, rcParent.left, rcParent.top, RECTWIDTH(rcParent), rcDivider.top - rcParent.top,
  699. SWP_NOZORDER | SWP_NOACTIVATE);
  700. }
  701. else
  702. {
  703. int cyHeader = g_pMyPropSheet->ComputeHeaderHeight(rcParent.right);
  704. // Reposition and show the top divider
  705. if (hwndTopDivider != NULL)
  706. {
  707. SetWindowPos(hwndTopDivider, NULL, 0, cyHeader, rcParent.right, RECTHEIGHT(rcTopDivider),
  708. SWP_NOZORDER | SWP_NOACTIVATE);
  709. ShowWindow(hwndTopDivider, SW_SHOW);
  710. }
  711. // Reposition the dialog
  712. SetWindowPos(m_hWnd, NULL, rcParent.left + 7, cyHeader + 7, RECTWIDTH(rcParent) - 14, rcDivider.top - cyHeader - 14,
  713. SWP_NOZORDER | SWP_NOACTIVATE);
  714. }
  715. g_pMyPropSheet->OnSetActivePage(m_hWnd);
  716. }
  717. break;
  718. }
  719. }
  720. break;
  721. default:
  722. break;
  723. }
  724. return CWnd::Default(message, wParam, lParam);
  725. }