home *** CD-ROM | disk | FTP | other *** search
/ Supercompiler 1997 / SUPERCOMPILER97.iso / MS_VC.50 / VC / MFC / SRC / DLGPROP.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1996-12-03  |  31.2 KB  |  1,293 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1997 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10.  
  11. #include "stdafx.h"
  12. #include "occimpl.h"
  13.  
  14. #ifdef AFX_CORE4_SEG
  15. #pragma code_seg(AFX_CORE4_SEG)
  16. #endif
  17.  
  18. #ifdef _DEBUG
  19. #undef THIS_FILE
  20. static char THIS_FILE[] = __FILE__;
  21. #endif
  22.  
  23. #define new DEBUG_NEW
  24.  
  25. ////////////////////////////////////////////////////////////////////////////
  26. // CPropertyPage -- one page of a tabbed dialog
  27.  
  28. UINT CALLBACK
  29. AfxPropPageCallback(HWND, UINT message, LPPROPSHEETPAGE pPropPage)
  30. {
  31.     switch (message)
  32.     {
  33.     case PSPCB_CREATE:
  34.         {
  35.             ASSERT(AfxIsValidAddress(pPropPage, sizeof(PROPSHEETPAGE)));
  36.             CPropertyPage* pPage =
  37.                 STATIC_DOWNCAST(CPropertyPage, (CObject*)pPropPage->lParam);
  38.             ASSERT_VALID(pPage);
  39.             TRY
  40.             {
  41.                 AfxHookWindowCreate(pPage);
  42.             }
  43.             CATCH_ALL(e)
  44.             {
  45.                 // Note: DELETE_EXCEPTION(e) not necessary
  46.                 return FALSE;
  47.             }
  48.             END_CATCH_ALL
  49.         }
  50.         return TRUE;
  51.  
  52.     case PSPCB_RELEASE:
  53.         AfxUnhookWindowCreate();
  54.         break;
  55.     }
  56.  
  57.     return 0;
  58. }
  59.  
  60. BEGIN_MESSAGE_MAP(CPropertyPage, CDialog)
  61.     //{{AFX_MSG_MAP(CPropertyPage)
  62.     ON_WM_CTLCOLOR()
  63.     ON_MESSAGE(WM_QUERY3DCONTROLS, OnQuery3dControls)
  64.     //}}AFX_MSG_MAP
  65. END_MESSAGE_MAP()
  66.  
  67. CPropertyPage::CPropertyPage(UINT nIDTemplate, UINT nIDCaption)
  68. {
  69.     ASSERT(nIDTemplate != 0);
  70.     CommonConstruct(MAKEINTRESOURCE(nIDTemplate), nIDCaption);
  71. }
  72.  
  73. CPropertyPage::CPropertyPage(LPCTSTR lpszTemplateName, UINT nIDCaption)
  74. {
  75.     ASSERT(AfxIsValidString(lpszTemplateName));
  76.     CommonConstruct(lpszTemplateName, nIDCaption);
  77. }
  78.  
  79. void CPropertyPage::Construct(UINT nIDTemplate, UINT nIDCaption)
  80. {
  81.     ASSERT(nIDTemplate != 0);
  82.     CommonConstruct(MAKEINTRESOURCE(nIDTemplate), nIDCaption);
  83. }
  84.  
  85. void CPropertyPage::Construct(LPCTSTR lpszTemplateName, UINT nIDCaption)
  86. {
  87.     ASSERT(HIWORD(lpszTemplateName) == 0 ||
  88.         AfxIsValidString(lpszTemplateName));
  89.     CommonConstruct(lpszTemplateName, nIDCaption);
  90. }
  91.  
  92. CPropertyPage::CPropertyPage()
  93. {
  94.     CommonConstruct(NULL, 0);
  95. }
  96.  
  97. void CPropertyPage::CommonConstruct(LPCTSTR lpszTemplateName, UINT nIDCaption)
  98. {
  99.     memset(&m_psp, 0, sizeof(PROPSHEETPAGE));
  100.     m_psp.dwSize = sizeof(PROPSHEETPAGE);
  101.     m_psp.dwFlags = PSP_USECALLBACK;
  102.     if (lpszTemplateName != NULL)
  103.         m_psp.hInstance = AfxFindResourceHandle(lpszTemplateName, RT_DIALOG);
  104.     m_psp.pszTemplate = lpszTemplateName;
  105.     m_psp.pfnDlgProc = AfxDlgProc;
  106.     m_psp.lParam = (LPARAM)this;
  107.     m_psp.pfnCallback = AfxPropPageCallback;
  108.     if (nIDCaption != 0)
  109.     {
  110.         VERIFY(m_strCaption.LoadString(nIDCaption));
  111.         m_psp.pszTitle = m_strCaption;
  112.         m_psp.dwFlags |= PSP_USETITLE;
  113.     }
  114.     if (AfxHelpEnabled())
  115.         m_psp.dwFlags |= PSP_HASHELP;
  116.     if (HIWORD(lpszTemplateName) == 0)
  117.         m_nIDHelp = LOWORD((DWORD)lpszTemplateName);
  118.     m_lpszTemplateName = m_psp.pszTemplate;
  119.     m_bFirstSetActive = TRUE;
  120. }
  121.  
  122. CPropertyPage::~CPropertyPage()
  123. {
  124. #ifndef _AFX_NO_OCC_SUPPORT
  125.     Cleanup();
  126. #endif
  127.  
  128. #ifdef _MAC
  129.     // Still need to unlock and free resources on the Mac
  130.     // (using "borrowed" space in CDialog to store handle)
  131.     if (m_lpDialogTemplate != NULL)
  132.     {
  133.         UnlockResource((HGLOBAL)m_lpDialogTemplate);
  134.         FreeResource((HGLOBAL)m_lpDialogTemplate);
  135.     }
  136. #endif //_MAC
  137.  
  138. #ifndef _MAC
  139.     if (m_hDialogTemplate != NULL)
  140.         GlobalFree(m_hDialogTemplate);
  141. #endif //_MAC
  142. }
  143.  
  144. #ifndef _AFX_NO_OCC_SUPPORT
  145.  
  146. void CPropertyPage::Cleanup()
  147. {
  148.     COccManager* pOccManager = afxOccManager;
  149.     if ((pOccManager != NULL) && (m_pOccDialogInfo != NULL))
  150.     {
  151.         pOccManager->PostCreateDialog(m_pOccDialogInfo);
  152.         free(m_pOccDialogInfo);
  153.         m_pOccDialogInfo = NULL;
  154.     }
  155. }
  156.  
  157. #ifndef _MAC
  158.  
  159. static DLGTEMPLATE* _ChangePropPageFont(const DLGTEMPLATE* pTemplate, BOOL bWizard)
  160. {
  161.     CString strFaceDefault;
  162.     WORD wSizeDefault;
  163.  
  164.     if (!AfxGetPropSheetFont(strFaceDefault, wSizeDefault, bWizard))
  165.         return NULL;
  166.  
  167.     // set font of property page to same font used by property sheet
  168.     CString strFace;
  169.     WORD wSize;
  170.     if ((!CDialogTemplate::GetFont(pTemplate, strFace, wSize)) ||
  171.         (strFace != strFaceDefault) || (wSize != wSizeDefault))
  172.     {
  173.         CDialogTemplate dlgTemplate(pTemplate);
  174.         dlgTemplate.SetFont(strFaceDefault, wSizeDefault);
  175.         return (DLGTEMPLATE*)dlgTemplate.Detach();
  176.     }
  177.  
  178.     return NULL;
  179. }
  180.  
  181. #endif //!_MAC
  182.  
  183. const DLGTEMPLATE* CPropertyPage::InitDialogInfo(const DLGTEMPLATE* pTemplate)
  184. {
  185.     // cleanup from previous run, if any
  186.     Cleanup();
  187.  
  188.     m_pOccDialogInfo = (_AFX_OCC_DIALOG_INFO*)malloc(
  189.         sizeof(_AFX_OCC_DIALOG_INFO));
  190.  
  191.     return afxOccManager->PreCreateDialog(m_pOccDialogInfo, pTemplate);
  192. }
  193.  
  194. #endif
  195.  
  196. void CPropertyPage::PreProcessPageTemplate(PROPSHEETPAGE& psp, BOOL bWizard)
  197. {
  198.     const DLGTEMPLATE* pTemplate;
  199.  
  200.     if (psp.dwFlags & PSP_DLGINDIRECT)
  201.     {
  202.         pTemplate = psp.pResource;
  203.     }
  204.     else
  205.     {
  206.         HRSRC hResource = ::FindResource(psp.hInstance,
  207.             psp.pszTemplate, RT_DIALOG);
  208.         HGLOBAL hTemplate = LoadResource(psp.hInstance,
  209.             hResource);
  210.         pTemplate = (LPCDLGTEMPLATE)LockResource(hTemplate);
  211. #ifdef _MAC
  212.         // Still need to unlock and free resources on the Mac
  213.         // (using "borrowed" space in CDialog to store handle)
  214.         if (m_lpDialogTemplate != NULL)
  215.         {
  216.             UnlockResource((HGLOBAL)m_lpDialogTemplate);
  217.             FreeResource((HGLOBAL)m_lpDialogTemplate);
  218.         }
  219.  
  220.         if (hTemplate != NULL)
  221.             (HGLOBAL&)m_lpDialogTemplate = hTemplate;
  222. #endif //_MAC
  223.     }
  224.  
  225.     ASSERT(pTemplate != NULL);
  226.  
  227. #ifdef _DEBUG
  228.     // WINBUG: Windows currently does not support DIALOGEX resources!
  229.     // Assert that the template is *not* a DIALOGEX template.
  230.     // DIALOGEX templates are not supported by the PropertySheet API.
  231.  
  232.     // To change a DIALOGEX template back to a DIALOG template,
  233.     // remove the following:
  234.     //  1. Extended styles on the dialog
  235.     //  2. Help IDs on any control in the dialog
  236.     //  3. Control IDs that are DWORDs
  237.     //  4. Weight, italic, or charset attributes on the dialog's font
  238.  
  239. #ifdef _MAC
  240.     ASSERT(((DLGTEMPLATEEX*)pTemplate)->signature != 0xFFFF); // See above!
  241. #else
  242.     if (((DLGTEMPLATEEX*)pTemplate)->signature != 0xFFFF)
  243.     {
  244.         // it's a DIALOGEX -- we'd better check
  245.         DWORD dwVersion = ::GetVersion();
  246.         if (dwVersion & 0x80000000)
  247.         {
  248.             // it's Win95 -- versions of COMCTL32.DLL that export
  249.             // a function called DllGetVersion are okay
  250.  
  251.             HINSTANCE hInst = LoadLibrary(_T("COMCTL32.DLL"));
  252.             ASSERT(hInst != NULL);
  253.             if (hInst != NULL)
  254.             {
  255.                 FARPROC proc = GetProcAddress(hInst, "DllGetVersion");
  256.                 if (proc == NULL)
  257.                     ASSERT(FALSE);
  258.                 FreeLibrary(hInst);
  259.             }
  260.         }
  261.         else if (LOBYTE(LOWORD(dwVersion)) == 3)
  262.         {
  263.             // it's Windows NT 3.x; we have no hope of this working
  264.             ASSERT(FALSE);
  265.         }
  266.     }
  267. #endif // _MAC
  268. #endif // _DEBUG
  269.  
  270. #ifndef _AFX_NO_OCC_SUPPORT
  271.     // if the dialog could contain OLE controls, deal with them now
  272.     if (afxOccManager != NULL)
  273.         pTemplate = InitDialogInfo(pTemplate);
  274. #endif
  275.  
  276. #ifndef _MAC
  277.     // set font of property page to same font used by property sheet
  278.     HGLOBAL hTemplate = _ChangePropPageFont(pTemplate, bWizard);
  279.  
  280.     if (m_hDialogTemplate != NULL)
  281.     {
  282.         GlobalFree(m_hDialogTemplate);
  283.         m_hDialogTemplate = NULL;
  284.     }
  285.  
  286.     if (hTemplate != NULL)
  287.     {
  288.         pTemplate = (LPCDLGTEMPLATE)hTemplate;
  289.         m_hDialogTemplate = hTemplate;
  290.     }
  291. #else
  292.     UNUSED_ALWAYS(bWizard); // unused in Mac builds
  293. #endif //!_MAC
  294.  
  295.     psp.pResource = pTemplate;
  296.     psp.dwFlags |= PSP_DLGINDIRECT;
  297. }
  298.  
  299. void CPropertyPage::CancelToClose()
  300. {
  301.     ASSERT(::IsWindow(m_hWnd));
  302.     ASSERT(GetParent() != NULL);
  303.  
  304.     GetParent()->SendMessage(PSM_CANCELTOCLOSE);
  305. }
  306.  
  307. void CPropertyPage::SetModified(BOOL bChanged)
  308. {
  309.     if (m_hWnd == NULL) // allowed for backward compatibility
  310.         return;
  311.  
  312.     ASSERT(::IsWindow(m_hWnd));
  313.     ASSERT(GetParent() != NULL);
  314.  
  315.     CWnd* pParentWnd = GetParent();
  316.     if (bChanged)
  317.         pParentWnd->SendMessage(PSM_CHANGED, (WPARAM)m_hWnd);
  318.     else
  319.         pParentWnd->SendMessage(PSM_UNCHANGED, (WPARAM)m_hWnd);
  320. }
  321.  
  322. LRESULT CPropertyPage::QuerySiblings(WPARAM wParam, LPARAM lParam)
  323. {
  324.     ASSERT(::IsWindow(m_hWnd));
  325.     ASSERT(GetParent() != NULL);
  326.  
  327.     return GetParent()->SendMessage(PSM_QUERYSIBLINGS, wParam, lParam);
  328. }
  329.  
  330. BOOL CPropertyPage::OnApply()
  331. {
  332.     ASSERT_VALID(this);
  333.  
  334.     OnOK();
  335.     return TRUE;
  336. }
  337.  
  338. void CPropertyPage::OnReset()
  339. {
  340.     ASSERT_VALID(this);
  341.  
  342.     OnCancel();
  343. }
  344.  
  345. void CPropertyPage::OnOK()
  346. {
  347.     ASSERT_VALID(this);
  348. }
  349.  
  350. void CPropertyPage::OnCancel()
  351. {
  352.     ASSERT_VALID(this);
  353. }
  354.  
  355. BOOL CPropertyPage::OnSetActive()
  356. {
  357.     ASSERT_VALID(this);
  358.  
  359.     if (m_bFirstSetActive)
  360.         m_bFirstSetActive = FALSE;
  361.     else
  362.         UpdateData(FALSE);
  363.     return TRUE;
  364. }
  365.  
  366. BOOL CPropertyPage::OnKillActive()
  367. {
  368.     ASSERT_VALID(this);
  369.  
  370.     if (!UpdateData())
  371.     {
  372.         TRACE0("UpdateData failed during page deactivation\n");
  373.         return FALSE;
  374.     }
  375.     return TRUE;
  376. }
  377.  
  378. BOOL CPropertyPage::OnQueryCancel()
  379. {
  380.     return TRUE;    // ok to cancel
  381. }
  382.  
  383. LRESULT CPropertyPage::OnWizardBack()
  384. {
  385.     return 0;
  386. }
  387.  
  388. LRESULT CPropertyPage::OnWizardNext()
  389. {
  390.     return 0;
  391. }
  392.  
  393. BOOL CPropertyPage::OnWizardFinish()
  394. {
  395.     return TRUE;
  396. }
  397.  
  398. LRESULT CPropertyPage::MapWizardResult(LRESULT lToMap)
  399. {
  400.     // -1 and 0 are special
  401.     if (lToMap == -1 || lToMap == 0)
  402.         return lToMap;
  403.  
  404.     // only do special stuff if MFC owns the property sheet
  405.     CPropertySheet* pSheet = DYNAMIC_DOWNCAST(CPropertySheet, GetParent());
  406.     if (pSheet != NULL)
  407.     {
  408.         // search the pages for a matching ID
  409.         for (int i = 0; i < pSheet->m_pages.GetSize(); i++)
  410.         {
  411.             CPropertyPage* pPage = pSheet->GetPage(i);
  412.             if ((LRESULT)pPage->m_psp.pszTemplate == lToMap)
  413.                 return (LRESULT)pSheet->m_psh.ppsp[i].pResource;
  414.         }
  415.     }
  416.     // otherwise, just use the original value
  417.     return lToMap;
  418. }
  419.  
  420. BOOL CPropertyPage::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
  421. {
  422.     ASSERT(pResult != NULL);
  423.     NMHDR* pNMHDR = (NMHDR*)lParam;
  424.  
  425.     // allow message map to override
  426.     if (CDialog::OnNotify(wParam, lParam, pResult))
  427.         return TRUE;
  428.  
  429.     // don't handle messages not from the page/sheet itself
  430.     if (pNMHDR->hwndFrom != m_hWnd && pNMHDR->hwndFrom != ::GetParent(m_hWnd))
  431.         return FALSE;
  432.  
  433.     // handle default
  434.     switch (pNMHDR->code)
  435.     {
  436.     case PSN_SETACTIVE:
  437.         *pResult = OnSetActive() ? 0 : -1;
  438.         break;
  439.     case PSN_KILLACTIVE:
  440.         *pResult = !OnKillActive();
  441.         break;
  442.  
  443.     case PSN_APPLY:
  444.         *pResult = OnApply() ? PSNRET_NOERROR : PSNRET_INVALID_NOCHANGEPAGE;
  445.         break;
  446.     case PSN_RESET:
  447.         OnReset();
  448.         break;
  449.     case PSN_QUERYCANCEL:
  450.         *pResult = !OnQueryCancel();
  451.         break;
  452.  
  453.     case PSN_WIZNEXT:
  454.         *pResult = MapWizardResult(OnWizardNext());
  455.         break;
  456.     case PSN_WIZBACK:
  457.         *pResult = MapWizardResult(OnWizardBack());
  458.         break;
  459.     case PSN_WIZFINISH:
  460.         *pResult = !OnWizardFinish();
  461.         break;
  462.  
  463.     case PSN_HELP:
  464.         SendMessage(WM_COMMAND, ID_HELP);
  465.         break;
  466.  
  467.     default:
  468.         return FALSE;   // not handled
  469.     }
  470.  
  471.     return TRUE;    // handled
  472. }
  473.  
  474. /////////////////////////////////////////////////////////////////////////////
  475. // CPropertyPage message Handlers
  476.  
  477. BOOL CPropertyPage::PreTranslateMessage(MSG* pMsg)
  478. {
  479.     VERIFY(!CWnd::PreTranslateMessage(pMsg));
  480.  
  481.     return FALSE;   // handled by CPropertySheet::PreTranslateMessage
  482. }
  483.  
  484. HBRUSH CPropertyPage::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
  485. {
  486.     LRESULT lResult;
  487.     if (pWnd->SendChildNotifyLastMsg(&lResult))
  488.         return (HBRUSH)lResult;
  489.  
  490. #ifndef _MAC
  491.     if (afxData.bWin4)
  492. #endif
  493.         return CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
  494.  
  495. #ifdef _MAC
  496.     DWORD dwFlags;
  497.     SystemParametersInfo(SPI_GET3D, 0, (LPVOID) &dwFlags, 0);
  498.     HBRUSH hbrGray = (dwFlags & F3D_OFFICE3D) ? afxData.hbrBtnFace : afxData.hbr3DLight;
  499. #endif
  500.  
  501.     if (!GrayCtlColor(pDC->m_hDC, pWnd->GetSafeHwnd(), nCtlColor,
  502. #ifndef _MAC
  503.       afxData.hbrBtnFace, afxData.clrBtnText))
  504.         return (HBRUSH)Default();
  505.     return afxData.hbrBtnFace;
  506. #else
  507.       hbrGray, afxData.clrBtnText))
  508.         return (HBRUSH)Default();
  509.     return hbrGray;
  510. #endif
  511. }
  512.  
  513. /////////////////////////////////////////////////////////////////////////////
  514. // CPropertyPage Diagnostics
  515.  
  516. #ifdef _DEBUG
  517. void CPropertyPage::AssertValid() const
  518. {
  519.     CDialog::AssertValid();
  520.     ASSERT(m_psp.dwSize == sizeof(PROPSHEETPAGE));
  521.     ASSERT(m_psp.dwFlags & PSP_USECALLBACK);
  522.     ASSERT(m_psp.pfnDlgProc == AfxDlgProc);
  523.     ASSERT(m_psp.lParam == (LPARAM)this);
  524. }
  525.  
  526. void CPropertyPage::Dump(CDumpContext& dc) const
  527. {
  528.     CDialog::Dump(dc);
  529.  
  530.     dc << "m_strCaption = " << m_strCaption << "\n";
  531.     dc << "m_psp.dwFlags = " << m_psp.dwFlags << "\n";
  532. }
  533.  
  534. void CPropertyPage::EndDialog(int nID)
  535. {
  536.     // Normally you shouldn't call EndDialog from a page. But in case it does
  537.     // happen during error situations, call CPropertySheet::EndDialog instead.
  538.  
  539.     CPropertySheet* pParent = (CPropertySheet*)GetParent();
  540.     if (pParent != NULL)
  541.         pParent->EndDialog(nID);
  542. }
  543. #endif //_DEBUG
  544.  
  545. /////////////////////////////////////////////////////////////////////////////
  546. // CPropertySheet -- a tabbed "dialog" (really a popup-window)
  547.  
  548. BEGIN_MESSAGE_MAP(CPropertySheet, CWnd)
  549.     //{{AFX_MSG_MAP(CPropertySheet)
  550.     ON_WM_CTLCOLOR()
  551.     ON_WM_NCCREATE()
  552.     ON_MESSAGE(WM_INITDIALOG, HandleInitDialog)
  553.     ON_MESSAGE(WM_COMMANDHELP, OnCommandHelp)
  554.     ON_WM_CLOSE()
  555.     ON_WM_SYSCOMMAND()
  556.     ON_MESSAGE(DM_SETDEFID, OnSetDefID)
  557.     //}}AFX_MSG_MAP
  558. END_MESSAGE_MAP()
  559.  
  560. LRESULT CPropertySheet::OnSetDefID(WPARAM wParam, LPARAM lParam)
  561. {
  562.     // WINBUG -- A wrong or invalid ID may be passed in here.  If this is the
  563.     // case, then look for a valid one.
  564.     HWND hWnd;
  565.     if ((m_psh.dwFlags & PSH_WIZARD) &&
  566.         (
  567.             ((hWnd = ::GetDlgItem(m_hWnd, wParam)) == NULL) ||
  568.             !(::GetWindowLong(hWnd, GWL_STYLE) & WS_VISIBLE) ||
  569.             !::IsWindowEnabled(hWnd)
  570.         ))
  571.     {
  572.         static const int ids[4] = {ID_WIZNEXT, ID_WIZFINISH, ID_WIZBACK, IDCANCEL };
  573.  
  574.         for (int i = 0; i < 4; i++)
  575.         {
  576.             // find first button that is visible and  enabled
  577.             HWND hWnd = ::GetDlgItem(m_hWnd, ids[i]);
  578.             if ((GetWindowLong(hWnd, GWL_STYLE) & WS_VISIBLE) &&
  579.                 ::IsWindowEnabled(hWnd))
  580.             {
  581.                 //WINBUG -- focus could be incorrect as well in this case
  582.                 // so ... let's set it to the default button
  583.                 HWND hWndFocus = ::GetFocus();
  584.                 if (!::IsWindowEnabled(hWndFocus))
  585.                     ::SetFocus(hWnd);
  586.                 return DefWindowProc(DM_SETDEFID, ids[i], lParam);
  587.             }
  588.         }
  589.     }
  590.     return Default();
  591. }
  592.  
  593. CPropertySheet::CPropertySheet()
  594. {
  595.     CommonConstruct(NULL, 0);
  596. }
  597.  
  598. CPropertySheet::CPropertySheet(UINT nIDCaption, CWnd* pParentWnd,
  599.     UINT iSelectPage)
  600. {
  601.     ASSERT(nIDCaption != 0);
  602.  
  603.     VERIFY(m_strCaption.LoadString(nIDCaption) != 0);
  604.     CommonConstruct(pParentWnd, iSelectPage);
  605. }
  606.  
  607. CPropertySheet::CPropertySheet(LPCTSTR pszCaption, CWnd* pParentWnd,
  608.     UINT iSelectPage)
  609. {
  610.     ASSERT(pszCaption != NULL);
  611.  
  612.     m_strCaption = pszCaption;
  613.     CommonConstruct(pParentWnd, iSelectPage);
  614. }
  615.  
  616. void CPropertySheet::Construct(UINT nIDCaption, CWnd* pParentWnd,
  617.     UINT iSelectPage)
  618. {
  619.     ASSERT(nIDCaption != 0);
  620.  
  621.     VERIFY(m_strCaption.LoadString(nIDCaption) != 0);
  622.     CommonConstruct(pParentWnd, iSelectPage);
  623. }
  624.  
  625. void CPropertySheet::Construct(LPCTSTR pszCaption, CWnd* pParentWnd,
  626.     UINT iSelectPage)
  627. {
  628.     ASSERT(pszCaption != NULL);
  629.  
  630.     m_strCaption = pszCaption;
  631.     CommonConstruct(pParentWnd, iSelectPage);
  632. }
  633.  
  634. void CPropertySheet::CommonConstruct(CWnd* pParentWnd, UINT iSelectPage)
  635. {
  636.     memset(&m_psh, 0, sizeof(PROPSHEETHEADER));
  637.     m_psh.dwSize = sizeof(PROPSHEETHEADER);
  638.     m_psh.dwFlags = PSH_PROPSHEETPAGE;
  639.     m_psh.pszCaption = m_strCaption;
  640.     m_psh.nStartPage = iSelectPage;
  641.     m_bStacked = TRUE;
  642.     m_bModeless = FALSE;
  643.  
  644.     if (AfxHelpEnabled())
  645.         m_psh.dwFlags |= PSH_HASHELP;
  646.  
  647.     m_pParentWnd = pParentWnd;  // m_psh.hwndParent set in DoModal/create
  648. }
  649.  
  650. void CPropertySheet::EnableStackedTabs(BOOL bStacked)
  651. {
  652.     m_bStacked = bStacked;
  653. }
  654.  
  655. void CPropertySheet::SetTitle(LPCTSTR lpszText, UINT nStyle)
  656. {
  657.     ASSERT((nStyle & ~PSH_PROPTITLE) == 0); // only PSH_PROPTITLE is valid
  658.     ASSERT(lpszText == NULL || AfxIsValidString(lpszText));
  659.  
  660.     if (m_hWnd == NULL)
  661.     {
  662.         // set internal state
  663.         m_strCaption = lpszText;
  664.         m_psh.pszCaption = m_strCaption;
  665.         m_psh.dwFlags &= ~PSH_PROPTITLE;
  666.         m_psh.dwFlags |= nStyle;
  667.     }
  668.     else
  669.     {
  670.         // set external state
  671.         SendMessage(PSM_SETTITLE, nStyle, (LPARAM)lpszText);
  672.     }
  673. }
  674.  
  675. CPropertySheet::~CPropertySheet()
  676. {
  677.     delete[] (PROPSHEETPAGE*)m_psh.ppsp;
  678. }
  679.  
  680. BOOL CPropertySheet::PreTranslateMessage(MSG* pMsg)
  681. {
  682.     ASSERT_VALID(this);
  683.  
  684.     // allow tooltip messages to be filtered
  685.     if (CWnd::PreTranslateMessage(pMsg))
  686.         return TRUE;
  687.  
  688.     // allow sheet to translate Ctrl+Tab, Shift+Ctrl+Tab,
  689.     //  Ctrl+PageUp, and Ctrl+PageDown
  690.     if (pMsg->message == WM_KEYDOWN && GetAsyncKeyState(VK_CONTROL) < 0 &&
  691.         (pMsg->wParam == VK_TAB || pMsg->wParam == VK_PRIOR || pMsg->wParam == VK_NEXT))
  692.     {
  693.         if (SendMessage(PSM_ISDIALOGMESSAGE, 0, (LPARAM)pMsg))
  694.             return TRUE;
  695.     }
  696.  
  697.     // handle rest with IsDialogMessage
  698.     return PreTranslateInput(pMsg);
  699. }
  700.  
  701. BOOL CPropertySheet::OnCmdMsg(UINT nID, int nCode, void* pExtra,
  702.     AFX_CMDHANDLERINFO* pHandlerInfo)
  703. {
  704.     if (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
  705.         return TRUE;
  706.  
  707.     if ((nCode != CN_COMMAND && nCode != CN_UPDATE_COMMAND_UI) ||
  708.             !IS_COMMAND_ID(nID) || nID >= 0xf000)
  709.     {
  710.         // control notification or non-command button or system command
  711.         return FALSE;       // not routed any further
  712.     }
  713.  
  714.     // if we have an owner window, give it second crack
  715.     CWnd* pOwner = GetParent();
  716.     if (pOwner != NULL)
  717.     {
  718. #ifdef _DEBUG
  719.         if (afxTraceFlags & traceCmdRouting)
  720.             TRACE1("Routing command id 0x%04X to owner window.\n", nID);
  721. #endif
  722.         ASSERT(pOwner != this);
  723.         if (pOwner->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
  724.             return TRUE;
  725.     }
  726.  
  727.     // last crack goes to the current CWinThread object
  728.     CWinThread* pThread = AfxGetThread();
  729.     if (pThread != NULL)
  730.     {
  731. #ifdef _DEBUG
  732.         if (afxTraceFlags & traceCmdRouting)
  733.             TRACE1("Routing command id 0x%04X to app.\n", nID);
  734. #endif
  735.         if (pThread->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
  736.             return TRUE;
  737.     }
  738.  
  739. #ifdef _DEBUG
  740.     if (afxTraceFlags & traceCmdRouting)
  741.     {
  742.         TRACE2("IGNORING command id 0x%04X sent to %hs dialog.\n", nID,
  743.                 GetRuntimeClass()->m_lpszClassName);
  744.     }
  745. #endif
  746.     return FALSE;
  747. }
  748.  
  749. CPropertyPage* CPropertySheet::GetActivePage() const
  750. {
  751.     ASSERT_VALID(this);
  752.  
  753.     CPropertyPage* pPage;
  754.     if (m_hWnd != NULL)
  755.         pPage = STATIC_DOWNCAST(CPropertyPage,
  756.             CWnd::FromHandle((HWND)::SendMessage(m_hWnd, PSM_GETCURRENTPAGEHWND, 0, 0)));
  757.     else
  758.         pPage = GetPage(GetActiveIndex());
  759.     return pPage;
  760. }
  761.  
  762. BOOL CPropertySheet::ContinueModal()
  763. {
  764.     // allow CWnd::EndModalLoop to be used
  765.     if (!CWnd::ContinueModal())
  766.         return FALSE;
  767.  
  768.     // when active page is NULL, the modal loop should end
  769.     ASSERT(::IsWindow(m_hWnd));
  770.     BOOL bResult = SendMessage(PSM_GETCURRENTPAGEHWND);
  771.     return bResult;
  772. }
  773.  
  774. int CPropertySheet::DoModal()
  775. {
  776.     ASSERT_VALID(this);
  777.     ASSERT(m_hWnd == NULL);
  778.  
  779.     // register common controls
  780.     VERIFY(AfxDeferRegisterClass(AFX_WNDCOMMCTLS_REG));
  781.  
  782.     // finish building PROPSHEETHEADER structure
  783.     BuildPropPageArray();
  784.  
  785.     // allow OLE servers to disable themselves
  786.     AfxGetApp()->EnableModeless(FALSE);
  787.  
  788.     // find parent HWND
  789.     HWND hWndTop;
  790.     CWnd* pParentWnd = CWnd::GetSafeOwner(m_pParentWnd, &hWndTop);
  791.     HWND hWndParent = pParentWnd->GetSafeHwnd();
  792.     m_psh.hwndParent = hWndParent;
  793.     BOOL bEnableParent = FALSE;
  794.     if (pParentWnd != NULL && pParentWnd->IsWindowEnabled())
  795.     {
  796.         pParentWnd->EnableWindow(FALSE);
  797.         bEnableParent = TRUE;
  798.     }
  799.     HWND hWndCapture = ::GetCapture();
  800.     if (hWndCapture != NULL)
  801.         ::SendMessage(hWndCapture, WM_CANCELMODE, 0, 0);
  802.  
  803.     // setup for modal loop and creation
  804.     m_nModalResult = 0;
  805.     m_nFlags |= WF_CONTINUEMODAL;
  806.  
  807.     // hook for creation of window
  808.     AfxHookWindowCreate(this);
  809.     m_psh.dwFlags |= PSH_MODELESS;
  810.     m_nFlags |= WF_CONTINUEMODAL;
  811.     HWND hWnd = (HWND)::PropertySheet(&m_psh);
  812.     m_psh.dwFlags &= ~PSH_MODELESS;
  813.     AfxUnhookWindowCreate();
  814.  
  815.     // handle error
  816.     if (hWnd == NULL || hWnd == (HWND)-1)
  817.     {
  818.         m_nFlags &= ~WF_CONTINUEMODAL;
  819.         m_nModalResult = -1;
  820.     }
  821.     int nResult = m_nModalResult;
  822.     if (m_nFlags & WF_CONTINUEMODAL)
  823.     {
  824.         // enter modal loop
  825.         DWORD dwFlags = MLF_SHOWONIDLE;
  826.         if (GetStyle() & DS_NOIDLEMSG)
  827.             dwFlags |= MLF_NOIDLEMSG;
  828.         nResult = RunModalLoop(dwFlags);
  829.     }
  830.  
  831.     // hide the window before enabling parent window, etc.
  832.     if (m_hWnd != NULL)
  833.     {
  834.         SetWindowPos(NULL, 0, 0, 0, 0, SWP_HIDEWINDOW|
  835.             SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOZORDER);
  836.     }
  837.     if (bEnableParent)
  838.         ::EnableWindow(hWndParent, TRUE);
  839.     if (pParentWnd != NULL && ::GetActiveWindow() == m_hWnd)
  840.         ::SetActiveWindow(hWndParent);
  841.  
  842.     // cleanup
  843.     DestroyWindow();
  844.  
  845.     // allow OLE servers to enable themselves
  846.     AfxGetApp()->EnableModeless(TRUE);
  847.     if (hWndTop != NULL)
  848.         ::EnableWindow(hWndTop, TRUE);
  849.  
  850.     return nResult;
  851. }
  852.  
  853. int CALLBACK
  854. AfxPropSheetCallback(HWND, UINT message, LPARAM lParam)
  855. {
  856.     switch (message)
  857.     {
  858.     case PSCB_PRECREATE:
  859.         {
  860.             _AFX_THREAD_STATE* pState = AfxGetThreadState();
  861.             LPDLGTEMPLATE lpTemplate = (LPDLGTEMPLATE)lParam;
  862.             if (lpTemplate->style != pState->m_dwPropStyle ||
  863.                 lpTemplate->dwExtendedStyle != pState->m_dwPropExStyle)
  864.             {
  865. #ifndef _MAC
  866.                 // Mark the dialog template as read-write.
  867.                 DWORD dwOldProtect;
  868.                 VirtualProtect(lpTemplate, sizeof(DLGTEMPLATE), PAGE_READWRITE, &dwOldProtect);
  869. #endif //!_MAC
  870.  
  871.                 // Ensure DS_SETFONT is set correctly.
  872.                 lpTemplate->style = lpTemplate->style & DS_SETFONT ?
  873.                                     pState->m_dwPropStyle | DS_SETFONT :
  874.                                     pState->m_dwPropStyle & ~DS_SETFONT;
  875.  
  876.                 lpTemplate->dwExtendedStyle = pState->m_dwPropExStyle;
  877.                 return TRUE;
  878.             }
  879.             return FALSE;
  880.         }
  881.     }
  882.  
  883.     return 0;
  884. }
  885.  
  886. BOOL CPropertySheet::Create(CWnd* pParentWnd, DWORD dwStyle, DWORD dwExStyle)
  887. {
  888.     _AFX_THREAD_STATE* pState = AfxGetThreadState();
  889.  
  890.     // Calculate the default window style.
  891.     if (dwStyle == (DWORD)-1)
  892.     {
  893.         pState->m_dwPropStyle = DS_MODALFRAME | DS_3DLOOK | DS_CONTEXTHELP |
  894.                                 DS_SETFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION;
  895.  
  896.         // Wizards don't have WS_SYSMENU.
  897.         if ((m_psh.dwFlags & PSH_WIZARD) == 0)
  898.             pState->m_dwPropStyle |= WS_SYSMENU;
  899.     }
  900.     else
  901.     {
  902.         pState->m_dwPropStyle = dwStyle;
  903.     }
  904.     pState->m_dwPropExStyle = dwExStyle;
  905.  
  906.     ASSERT_VALID(this);
  907.     ASSERT(m_hWnd == NULL);
  908.  
  909.     // finish building PROPSHEETHEADER structure
  910.     BuildPropPageArray();
  911.     m_bModeless = TRUE;
  912.     m_psh.dwFlags |= (PSH_MODELESS|PSH_USECALLBACK);
  913.     m_psh.pfnCallback = AfxPropSheetCallback;
  914.     m_psh.hwndParent = pParentWnd->GetSafeHwnd();
  915.  
  916.     // hook the window creation process
  917.     AfxHookWindowCreate(this);
  918.     HWND hWnd = (HWND)PropertySheet(&m_psh);
  919.  
  920.     // cleanup on failure, otherwise return TRUE
  921.     if (!AfxUnhookWindowCreate())
  922.         PostNcDestroy();    // cleanup if Create fails
  923.  
  924.     if (hWnd == NULL || hWnd == (HWND)-1)
  925.         return FALSE;
  926.     ASSERT(hWnd == m_hWnd);
  927.  
  928.     return TRUE;
  929. }
  930.  
  931. void CPropertySheet::BuildPropPageArray()
  932. {
  933.     // delete existing prop page array
  934.     delete[] (PROPSHEETPAGE*)m_psh.ppsp;
  935.     m_psh.ppsp = NULL;
  936.  
  937.     // build new prop page array
  938.     LPPROPSHEETPAGE ppsp = new PROPSHEETPAGE[m_pages.GetSize()];
  939.     m_psh.ppsp = ppsp;
  940.     BOOL bWizard = (m_psh.dwFlags & PSH_WIZARD);
  941.     for (int i = 0; i < m_pages.GetSize(); i++)
  942.     {
  943.         CPropertyPage* pPage = GetPage(i);
  944.         memcpy(&ppsp[i], &pPage->m_psp, sizeof(PROPSHEETPAGE));
  945.         pPage->PreProcessPageTemplate(ppsp[i], bWizard);
  946.     }
  947.  
  948.     m_psh.nPages = m_pages.GetSize();
  949. }
  950.  
  951. ////////////////////////////////////////////////////////////////////////////
  952.  
  953. int CPropertySheet::GetPageCount() const
  954. {
  955.     ASSERT_VALID(this);
  956.  
  957.     if (m_hWnd == NULL)
  958.         return m_pages.GetSize();
  959.  
  960.     CTabCtrl* pTab = GetTabControl();
  961.     ASSERT_VALID(pTab);
  962.     return pTab->GetItemCount();
  963. }
  964.  
  965. int CPropertySheet::GetActiveIndex() const
  966. {
  967.     if (m_hWnd == NULL)
  968.         return m_psh.nStartPage;
  969.  
  970.     CTabCtrl* pTab = GetTabControl();
  971.     ASSERT_VALID(pTab);
  972.     return pTab->GetCurSel();
  973. }
  974.  
  975. BOOL CPropertySheet::SetActivePage(int nPage)
  976. {
  977.     if (m_hWnd == NULL)
  978.     {
  979.         m_psh.nStartPage = nPage;
  980.         return TRUE;
  981.     }
  982.     return (BOOL)SendMessage(PSM_SETCURSEL, nPage);
  983. }
  984.  
  985. int CPropertySheet::GetPageIndex(CPropertyPage* pPage)
  986. {
  987.     for (int i = 0; i < GetPageCount(); i++)
  988.     {
  989.         if (GetPage(i) == pPage)
  990.             return i;
  991.     }
  992.     return -1;  // pPage not found
  993. }
  994.  
  995. BOOL CPropertySheet::SetActivePage(CPropertyPage* pPage)
  996. {
  997.     ASSERT_VALID(this);
  998.     ASSERT(pPage != NULL);
  999.     ASSERT_KINDOF(CPropertyPage, pPage);
  1000.  
  1001.     int nPage = GetPageIndex(pPage);
  1002.     ASSERT(pPage >= 0);
  1003.  
  1004.     return SetActivePage(nPage);
  1005. }
  1006.  
  1007. void CPropertySheet::AddPage(CPropertyPage* pPage)
  1008. {
  1009.     ASSERT_VALID(this);
  1010.     ASSERT(pPage != NULL);
  1011.     ASSERT_KINDOF(CPropertyPage, pPage);
  1012.     ASSERT_VALID(pPage);
  1013.  
  1014.     // add page to internal list
  1015.     m_pages.Add(pPage);
  1016.  
  1017.     // add page externally
  1018.     if (m_hWnd != NULL)
  1019.     {
  1020.         PROPSHEETPAGE psp;
  1021.         memcpy(&psp, &pPage->m_psp, sizeof(PROPSHEETPAGE));
  1022.         pPage->PreProcessPageTemplate(psp, m_psh.dwFlags & PSH_WIZARD);
  1023.         HPROPSHEETPAGE hPSP = CreatePropertySheetPage(&psp);
  1024.         if (hPSP == NULL)
  1025.             AfxThrowMemoryException();
  1026.  
  1027.         if (!SendMessage(PSM_ADDPAGE, 0, (LPARAM)hPSP))
  1028.         {
  1029.             DestroyPropertySheetPage(hPSP);
  1030.             AfxThrowMemoryException();
  1031.         }
  1032.     }
  1033. }
  1034.  
  1035. void CPropertySheet::RemovePage(CPropertyPage* pPage)
  1036. {
  1037.     ASSERT_VALID(this);
  1038.     ASSERT(pPage != NULL);
  1039.     ASSERT_KINDOF(CPropertyPage, pPage);
  1040.  
  1041.     int nPage = GetPageIndex(pPage);
  1042.     ASSERT(nPage >= 0);
  1043.  
  1044.     RemovePage(nPage);
  1045. }
  1046.  
  1047. void CPropertySheet::RemovePage(int nPage)
  1048. {
  1049.     ASSERT_VALID(this);
  1050.  
  1051.     // remove the page externally
  1052.     if (m_hWnd != NULL)
  1053.         SendMessage(PSM_REMOVEPAGE, nPage);
  1054.  
  1055.     // remove the page from internal list
  1056.     m_pages.RemoveAt(nPage);
  1057. }
  1058.  
  1059. void CPropertySheet::EndDialog(int nEndID)
  1060. {
  1061.     ASSERT_VALID(this);
  1062.  
  1063.     m_nModalResult = nEndID;
  1064.     if (m_bModeless)
  1065.         DestroyWindow();
  1066.     else
  1067.         PostMessage(PSM_PRESSBUTTON, IDCANCEL);
  1068. }
  1069.  
  1070. void CPropertySheet::OnClose()
  1071. {
  1072.     if (m_bModeless)
  1073.         DestroyWindow();
  1074.     else
  1075.         Default();
  1076. }
  1077.  
  1078. void CPropertySheet::OnSysCommand(UINT nID, LPARAM)
  1079. {
  1080.     switch (nID & 0xFFF0)
  1081.     {
  1082.     case SC_CLOSE:
  1083.         if (m_bModeless)
  1084.         {
  1085.             SendMessage(WM_CLOSE);
  1086.             return;
  1087.         }
  1088.     }
  1089.     Default();
  1090. }
  1091.  
  1092. /////////////////////////////////////////////////////////////////////////////
  1093. // CPropertySheet message handlers
  1094.  
  1095. static int rgiButtons[] = { IDOK, IDCANCEL, ID_APPLY_NOW, IDHELP };
  1096.  
  1097. BOOL CPropertySheet::OnInitDialog()
  1098. {
  1099.     if (!(m_psh.dwFlags & PSH_WIZARD))
  1100.     {
  1101.         // resize the tab control so the layout is less restrictive
  1102.         HWND hWnd = (HWND)::GetDlgItem(m_hWnd, AFX_IDC_TAB_CONTROL);
  1103.         ASSERT(hWnd != NULL);
  1104.         CRect rectOld;
  1105.         ::GetWindowRect(hWnd, &rectOld);
  1106.         ScreenToClient(rectOld);
  1107.         CRect rectNew(0, 0, 0, 32);
  1108.         ::MapDialogRect(m_hWnd, &rectNew);
  1109.         if (rectNew.bottom < rectOld.bottom)
  1110.         {
  1111.             // move tab control
  1112.             int cyDiff = rectOld.Height() - rectNew.bottom;
  1113.             ::SetWindowPos(hWnd, NULL, 0, 0, rectOld.Width(), rectNew.bottom,
  1114.                 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
  1115.  
  1116.             // move buttons by similar amount
  1117.             for (int i = 0; i < _countof(rgiButtons); i++)
  1118.             {
  1119.                 hWnd = ::GetDlgItem(m_hWnd, rgiButtons[i]);
  1120.                 if (hWnd != NULL)
  1121.                 {
  1122.                     ::GetWindowRect(hWnd, &rectOld);
  1123.                     ScreenToClient(&rectOld);
  1124.                     ::SetWindowPos(hWnd, NULL,
  1125.                         rectOld.left, rectOld.top - cyDiff,
  1126.                         0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
  1127.                 }
  1128.             }
  1129.  
  1130.             // resize property sheet itself similarly
  1131.             GetWindowRect(&rectOld);
  1132.             SetWindowPos(NULL, 0, 0, rectOld.Width(), rectOld.Height() - cyDiff,
  1133.                 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
  1134.         }
  1135.     }
  1136.  
  1137.     BOOL bResult = (BOOL)Default();
  1138.  
  1139.     // change tab style if scrolling tabs desired (stacked tabs are default)
  1140.     if (!m_bStacked)
  1141.     {
  1142.         HWND hWndTab = (HWND)SendMessage(PSM_GETTABCONTROL);
  1143.         if (hWndTab != NULL)
  1144.             CWnd::ModifyStyle(hWndTab, TCS_MULTILINE, TCS_SINGLELINE, 0);
  1145.     }
  1146.  
  1147.     if (m_bModeless && !(m_psh.dwFlags & PSH_WIZARD))
  1148.     {
  1149.         // layout property sheet so button area is not accounted for
  1150.         CRect rectWnd;
  1151.         GetWindowRect(rectWnd);
  1152.         CRect rectButton;
  1153.         HWND hWnd = ::GetDlgItem(m_hWnd, IDOK);
  1154.         ASSERT(hWnd != NULL);
  1155.         ::GetWindowRect(hWnd, rectButton);
  1156.         SetWindowPos(NULL, 0, 0,
  1157.             rectWnd.Width(), rectButton.top - rectWnd.top,
  1158.             SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
  1159.  
  1160.         // remove standard buttons for modeless dialogs
  1161.         for (int i = 0; i < _countof(rgiButtons); i++)
  1162.         {
  1163.             HWND hWnd = ::GetDlgItem(m_hWnd, rgiButtons[i]);
  1164.             if (hWnd != NULL)
  1165.             {
  1166.                 ::ShowWindow(hWnd, SW_HIDE);
  1167.                 ::EnableWindow(hWnd, FALSE);
  1168.             }
  1169.         }
  1170.     }
  1171.  
  1172.     // center the property sheet relative to the parent window
  1173.     if (!(GetStyle() & WS_CHILD))
  1174.         CenterWindow();
  1175.  
  1176.     return bResult;
  1177. }
  1178.  
  1179. BOOL CPropertySheet::OnNcCreate(LPCREATESTRUCT)
  1180. {
  1181.     // By default, MFC does not directly support the new style
  1182.     // help button in the caption, so it is turned off here.
  1183.     // It can be added back in and implemented by derived classes
  1184.     // from CPropertySheet.
  1185.     ModifyStyleEx(WS_EX_CONTEXTHELP, 0);
  1186.  
  1187.     return (BOOL)Default();
  1188. }
  1189.  
  1190. LRESULT CPropertySheet::HandleInitDialog(WPARAM, LPARAM)
  1191. {
  1192.     LRESULT lResult = OnInitDialog();
  1193.     return lResult;
  1194. }
  1195.  
  1196. BOOL CPropertySheet::OnCommand(WPARAM wParam, LPARAM lParam)
  1197. {
  1198.     // allow message map override
  1199.     if (CWnd::OnCommand(wParam, lParam))
  1200.         return TRUE;
  1201.  
  1202.     // crack message parameters
  1203.     UINT nID = LOWORD(wParam);
  1204.     HWND hWndCtrl = (HWND)lParam;
  1205.     int nCode = HIWORD(wParam);
  1206.  
  1207.     // set m_nModalResult to ID of button, whenever button is clicked
  1208.     if (hWndCtrl != NULL && nCode == BN_CLICKED)
  1209.     {
  1210.         if (::SendMessage(hWndCtrl, WM_GETDLGCODE, 0, 0) &
  1211.             (DLGC_BUTTON|DLGC_DEFPUSHBUTTON))
  1212.         {
  1213.             LONG lStyle = ::GetWindowLong(hWndCtrl, GWL_STYLE) & 0x0F;
  1214.             if (lStyle == BS_PUSHBUTTON || lStyle == BS_DEFPUSHBUTTON ||
  1215.                 lStyle == BS_USERBUTTON || lStyle == BS_OWNERDRAW)
  1216.             {
  1217.                 m_nModalResult = nID;
  1218.             }
  1219.         }
  1220.     }
  1221.     return FALSE;
  1222. }
  1223.  
  1224. LRESULT CPropertySheet::OnCommandHelp(WPARAM wParam, LPARAM lParam)
  1225. {
  1226.     ASSERT_VALID(this);
  1227.  
  1228.     CPropertyPage* pPage = GetActivePage();
  1229.     ASSERT_VALID(pPage);
  1230.     return AfxCallWndProc(pPage, pPage->m_hWnd, WM_COMMANDHELP, wParam, lParam);
  1231. }
  1232.  
  1233. HBRUSH CPropertySheet::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
  1234. {
  1235.     LRESULT lResult;
  1236.     if (pWnd->SendChildNotifyLastMsg(&lResult))
  1237.         return (HBRUSH)lResult;
  1238.  
  1239. #ifndef _MAC    // REVIEW: can remove #ifndef once WLM reports version as 4.0
  1240.     if (afxData.bWin4)
  1241. #endif
  1242.         return CWnd::OnCtlColor(pDC, pWnd, nCtlColor);
  1243.  
  1244. #ifdef _MAC
  1245.     DWORD dwFlags;
  1246.     SystemParametersInfo(SPI_GET3D, 0, (LPVOID) &dwFlags, 0);
  1247.     HBRUSH hbrGray = (dwFlags & F3D_OFFICE3D) ? afxData.hbrBtnFace : afxData.hbr3DLight;
  1248. #endif
  1249.  
  1250.     if (!GrayCtlColor(pDC->m_hDC, pWnd->GetSafeHwnd(), nCtlColor,
  1251. #ifndef _MAC
  1252.       afxData.hbrBtnFace, afxData.clrBtnText))
  1253.         return (HBRUSH)Default();
  1254.     return afxData.hbrBtnFace;
  1255. #else
  1256.       hbrGray, afxData.clrBtnText))
  1257.         return (HBRUSH)Default();
  1258.     return hbrGray;
  1259. #endif
  1260. }
  1261.  
  1262. /////////////////////////////////////////////////////////////////////////////
  1263. // CPropertySheet Diagnostics
  1264.  
  1265. #ifdef _DEBUG
  1266. void CPropertySheet::AssertValid() const
  1267. {
  1268.     CWnd::AssertValid();
  1269.     m_pages.AssertValid();
  1270.     ASSERT(m_psh.dwSize == sizeof(PROPSHEETHEADER));
  1271.     ASSERT((m_psh.dwFlags & PSH_PROPSHEETPAGE) == PSH_PROPSHEETPAGE);
  1272. }
  1273.  
  1274. void CPropertySheet::Dump(CDumpContext& dc) const
  1275. {
  1276.     CWnd::Dump(dc);
  1277.  
  1278.     dc << "m_strCaption = " << m_strCaption << "\n";
  1279.     dc << "Number of Pages = " << m_pages.GetSize() << "\n";
  1280.     dc << "Stacked = " << m_bStacked << "\n";
  1281.     dc << "Modeless = " << m_bModeless << "\n";
  1282. }
  1283. #endif //_DEBUG
  1284.  
  1285. #ifdef AFX_INIT_SEG
  1286. #pragma code_seg(AFX_INIT_SEG)
  1287. #endif
  1288.  
  1289. IMPLEMENT_DYNAMIC(CPropertyPage, CDialog)
  1290. IMPLEMENT_DYNAMIC(CPropertySheet, CWnd)
  1291.  
  1292. /////////////////////////////////////////////////////////////////////////////
  1293.