// This is a part of the Active Template Library. // Copyright (C) Microsoft Corporation, 1996 - 1999 // All rights reserved. // // This source code is only intended as a supplement to the // Active Template Library Reference and related // electronic documentation provided with the library. // See these sources for detailed information regarding the // Active Template Library product. // Original file obtained from Nenad Stefanovic (ATL Team) as // part of WTL (Windows Template Library) // Kept just all the property page and property sheet classes #ifndef __ATLDLGS_H__ #define __ATLDLGS_H__ #ifndef __cplusplus #error ATL requires C++ compilation (use a .cpp suffix) #endif #ifndef __ATLWIN_H__ #error atldlgs.h requires atlwin.h to be included first #endif #include #include // copied from the new ATLWIN.H file to work with standard ATL 2.1 #define DECLARE_EMPTY_MSG_MAP() \ public: \ BOOL ProcessWindowMessage(HWND, UINT, WPARAM, LPARAM, LRESULT&, DWORD) \ { \ return FALSE; \ } namespace ATL { ///////////////////////////////////////////////////////////////////////////// // Forward declarations template class CPropertySheetImpl; class CPropertySheet; template class CPropertyPageImpl; ///////////////////////////////////////////////////////////////////////////// // CPropertySheetImpl - implements a property sheet template class ATL_NO_VTABLE CPropertySheetImpl : public CWindowImplBase { public: PROPSHEETHEADER m_psh; // Construction/Destruction CPropertySheetImpl(LPCTSTR lpszTitle = NULL, UINT uStartPage = 0) { memset(&m_psh, 0, sizeof(PROPSHEETHEADER)); m_psh.dwSize = sizeof(PROPSHEETHEADER); m_psh.dwFlags = PSH_USECALLBACK; m_psh.phpage = NULL; m_psh.nPages = 0; m_psh.pszCaption = lpszTitle; m_psh.nStartPage = uStartPage; m_psh.hwndParent = NULL; // will be set in DoModal/Create m_psh.hInstance = _Module.GetResourceInstance(); m_psh.pfnCallback = T::PropSheetCallback; } ~CPropertySheetImpl() { if(m_psh.phpage != NULL) delete[] m_psh.phpage; } static int CALLBACK PropSheetCallback(HWND hWnd, UINT uMsg, LPARAM) { if(uMsg == PSCB_INITIALIZED) { _ASSERTE(hWnd != NULL); CWindowImplBase* pT = (CWindowImplBase*)_Module.ExtractCreateWndData(); pT->SubclassWindow(hWnd); } return 0; } HWND Create(HWND hWndParent = NULL) { _ASSERTE(m_hWnd == NULL); m_psh.dwFlags |= PSH_MODELESS; m_psh.hwndParent = hWndParent; _Module.AddCreateWndData(&m_thunk.cd, (CWindowImplBase*)this); HWND hWnd = (HWND)::PropertySheet(&m_psh); _ASSERTE(m_hWnd == hWnd); return hWnd; } int DoModal(HWND hWndParent = ::GetActiveWindow()) { _ASSERTE(m_hWnd == NULL); m_psh.dwFlags &= ~PSH_MODELESS; m_psh.hwndParent = hWndParent; _Module.AddCreateWndData(&m_thunk.cd, (CWindowImplBase*)this); int nRet = ::PropertySheet(&m_psh); m_hWnd = NULL; return nRet; } // Attributes UINT GetPageCount() const { if(m_hWnd == NULL) return m_psh.nPages; HWND hWndTabCtrl = GetTabControl(); _ASSERTE(hWndTabCtrl != NULL); return (UINT)::SendMessage(hWndTabCtrl, TCM_GETITEMCOUNT, 0, 0L); } HWND GetActivePage() const { _ASSERTE(::IsWindow(m_hWnd)); return (HWND)::SendMessage(m_hWnd, PSM_GETCURRENTPAGEHWND, 0, 0L); } UINT GetActiveIndex() const { if(m_hWnd == NULL) return m_psh.nStartPage; HWND hWndTabCtrl = GetTabControl(); _ASSERTE(hWndTabCtrl != NULL); return (UINT)::SendMessage(hWndTabCtrl, TCM_GETCURSEL, 0, 0L); } HPROPSHEETPAGE GetPage(UINT uPageIndex) { _ASSERTE(uPageIndex < m_psh.nPages); return m_psh.phpage[uPageIndex]; } UINT GetPageIndex(HPROPSHEETPAGE hPage) { for(UINT i = 0; i < m_psh.nPages; i++) { if(m_psh.phpage[i] == hPage) return i; } return (UINT)-1; // hPage not found } BOOL SetActivePage(UINT uPageIndex) { if(m_hWnd == NULL) { m_psh.nStartPage = uPageIndex; return TRUE; } return (BOOL)SendMessage(PSM_SETCURSEL, uPageIndex); } BOOL SetActivePage(HPROPSHEETPAGE hPage) { _ASSERTE(hPage != NULL); UINT uPageIndex = GetPageIndex(hPage); if(uPageIndex == (UINT)-1) return FALSE; return SetActivePage(uPageIndex); } void SetTitle(LPCTSTR lpszText, UINT nStyle = 0) { _ASSERTE((nStyle & ~PSH_PROPTITLE) == 0); // only PSH_PROPTITLE is valid _ASSERTE(lpszText == NULL); if(m_hWnd == NULL) { // set internal state m_psh.pszCaption = lpszText; m_psh.dwFlags &= ~PSH_PROPTITLE; m_psh.dwFlags |= nStyle; } else { // set external state SendMessage(PSM_SETTITLE, nStyle, (LPARAM)lpszText); } } HWND GetTabControl() const { _ASSERTE(::IsWindow(m_hWnd)); return (HWND)::SendMessage(m_hWnd, PSM_GETTABCONTROL, 0, 0L); } void SetWizardMode() { m_psh.dwFlags |= PSH_WIZARD; } void SetFinishText(LPCTSTR lpszText) { _ASSERTE(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, PSM_SETFINISHTEXT, 0, (LPARAM)lpszText); } void SetWizardButtons(DWORD dwFlags) { _ASSERTE(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, PSM_SETWIZBUTTONS, 0, dwFlags); } // Operations BOOL AddPage(HPROPSHEETPAGE hPage) { _ASSERTE(hPage != NULL); // add page to internal list HPROPSHEETPAGE* php = (HPROPSHEETPAGE*)realloc(m_psh.phpage, (m_psh.nPages + 1) * sizeof(HPROPSHEETPAGE)); if(php == NULL) return FALSE; m_psh.phpage = php; m_psh.phpage[m_psh.nPages] = hPage; m_psh.nPages++; if(m_hWnd != NULL) ::SendMessage(m_hWnd, PSM_ADDPAGE, 0, (LPARAM)hPage); return TRUE; } BOOL AddPage(LPCPROPSHEETPAGE pPage) { _ASSERTE(pPage != NULL); HPROPSHEETPAGE hPSP = ::CreatePropertySheetPage(pPage); if(hPSP == NULL) return FALSE; AddPage(hPSP); return TRUE; } BOOL RemovePage(HPROPSHEETPAGE hPage) { _ASSERTE(hPage != NULL); int nPage = GetPageIndex(hPage); if(nPage == -1) return FALSE; return RemovePage(nPage); } BOOL RemovePage(UINT uPageIndex) { // remove the page externally if(m_hWnd != NULL) SendMessage(PSM_REMOVEPAGE, uPageIndex); // remove the page from internal list if(uPageIndex >= m_psh.nPages) return FALSE; if(!DestroyPropertySheetPage(m_psh.phpage[uPageIndex])) return FALSE; for(UINT i = uPageIndex; i < m_psh.nPages - 1; i++) m_psh.phpage[i] = m_psh.phpage[i+1]; m_psh.phpage = (HPROPSHEETPAGE*)realloc(m_psh.phpage, (m_psh.nPages - 1) * sizeof(HPROPSHEETPAGE)); m_psh.nPages--; return TRUE; } BOOL PressButton(int nButton) { _ASSERTE(::IsWindow(m_hWnd)); return (BOOL)::SendMessage(m_hWnd, PSM_PRESSBUTTON, nButton, 0L); } }; class CPropertySheet : public CPropertySheetImpl { public: CPropertySheet(LPCTSTR lpszTitle = NULL, UINT uStartPage = 0) : CPropertySheetImpl(lpszTitle, uStartPage) { } DECLARE_EMPTY_MSG_MAP() }; ///////////////////////////////////////////////////////////////////////////// // CPropertyPageImpl - implements a property page template class ATL_NO_VTABLE CPropertyPageImpl : public CDialogImplBase { public: PROPSHEETPAGE m_psp; operator PROPSHEETPAGE*() { return &m_psp; } // Construction CPropertyPageImpl(LPCTSTR lpszTitle = NULL) { // initialize PROPSHEETPAGE struct memset(&m_psp, 0, sizeof(PROPSHEETPAGE)); m_psp.dwSize = sizeof(PROPSHEETPAGE); m_psp.dwFlags = PSP_USECALLBACK; m_psp.hInstance = _Module.GetResourceInstance(); m_psp.pszTemplate = MAKEINTRESOURCE(T::IDD); m_psp.pfnDlgProc = StartDialogProc; m_psp.pfnCallback = T::PropPageCallback; m_psp.lParam = (LPARAM)this; if(lpszTitle != NULL) { m_psp.pszTitle = lpszTitle; m_psp.dwFlags |= PSP_USETITLE; } } static UINT CALLBACK PropPageCallback(HWND hWnd, UINT uMsg, LPPROPSHEETPAGE ppsp) { if(uMsg == PSPCB_CREATE) { _ASSERTE(hWnd == NULL); CDialogImplBase* pPage = (CDialogImplBase*)ppsp->lParam; _Module.AddCreateWndData(&pPage->m_thunk.cd, pPage); } return 1; } HPROPSHEETPAGE Create() { return ::CreatePropertySheetPage(&m_psp); } BOOL EndDialog(int) { // do nothing here, calling ::EndDialog will close the whole sheet _ASSERTE(FALSE); return FALSE; } // Operations void CancelToClose() { _ASSERTE(::IsWindow(m_hWnd)); _ASSERTE(GetParent() != NULL); ::SendMessage(GetParent(), PSM_CANCELTOCLOSE, 0, 0L); } void SetModified(BOOL bChanged = TRUE) { _ASSERTE(::IsWindow(m_hWnd)); _ASSERTE(GetParent() != NULL); if(bChanged) ::SendMessage(GetParent(), PSM_CHANGED, (WPARAM)m_hWnd, 0L); else ::SendMessage(GetParent(), PSM_UNCHANGED, (WPARAM)m_hWnd, 0L); } LRESULT QuerySiblings(WPARAM wParam, LPARAM lParam) { _ASSERTE(::IsWindow(m_hWnd)); _ASSERTE(GetParent() != NULL); return ::SendMessage(GetParent(), PSM_QUERYSIBLINGS, wParam, lParam); } BEGIN_MSG_MAP(CPropertyPageImpl< T >) MESSAGE_HANDLER(WM_NOTIFY, OnNotify) END_MSG_MAP() // Message handler LRESULT OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { _ASSERTE(::IsWindow(m_hWnd)); NMHDR* pNMHDR = (NMHDR*)lParam; // don't handle messages not from the page/sheet itself if(pNMHDR->hwndFrom != m_hWnd && pNMHDR->hwndFrom != ::GetParent(m_hWnd)) { bHandled = FALSE; return 1; } T* pT = static_cast(this); LRESULT lResult = 0; // handle default switch(pNMHDR->code) { case PSN_SETACTIVE: //? other values lResult = pT->OnSetActive() ? 0 : -1; break; case PSN_KILLACTIVE: lResult = !pT->OnKillActive(); break; case PSN_APPLY: lResult = pT->OnApply() ? PSNRET_NOERROR : PSNRET_INVALID_NOCHANGEPAGE; break; case PSN_RESET: pT->OnReset(); break; case PSN_QUERYCANCEL: lResult = !pT->OnQueryCancel(); break; case PSN_WIZNEXT: //? other values lResult = pT->OnWizardNext(); break; case PSN_WIZBACK: lResult = pT->OnWizardBack(); break; case PSN_WIZFINISH: lResult = !pT->OnWizardFinish(); break; case PSN_HELP: /**/ lResult = pT->OnHelp(); break; default: bHandled = FALSE; // not handled } return lResult; } // Overridables BOOL OnSetActive() { return TRUE; } BOOL OnKillActive() { return TRUE; } BOOL OnApply() { return TRUE; } void OnReset() { } BOOL OnQueryCancel() { return TRUE; // ok to cancel } LRESULT OnWizardBack() { return 0; // default go to previous page } LRESULT OnWizardNext() { return 0; // default go to next page } BOOL OnWizardFinish() { return TRUE; } BOOL OnHelp() { return TRUE; } }; }; //namespace ATL #endif // __ATLDLGS_H__