/* * AUTHOR * N. Nielsen * * LICENSE * This software is in the public domain. * * The software is provided "as is", without warranty of any kind, * express or implied, including but not limited to the warranties * of merchantability, fitness for a particular purpose, and * noninfringement. In no event shall the author(s) be liable for any * claim, damages, or other liability, whether in an action of * contract, tort, or otherwise, arising from, out of, or in connection * with the software or the use or other dealings in the software. * * SUPPORT * Send bug reports to: */ // PropertyPage.h: interface for the CPropertyPage class. // Implements Property Pages and Sheets for ATL // By Stef 06/10/99 // // This class uses an MFC type Interface (CPropertySheet, CPropertyPage) // the only difference being that many of the virtual notify functions // are left for you to define in your derived classes using your message map // // Notes for CPropertySheet: // 1. If you define a WM_INITDIALOG handler in your derived class make // sure to either call the base handler (OnInitDialog) or set // bHandled to false. // // ////////////////////////////////////////////////////////////////////// #if !defined(AFX_PROPERTYPAGE_H__1508DAF4_7AD1_11D3_BF96_0020182B97FC__INCLUDED_) #define AFX_PROPERTYPAGE_H__1508DAF4_7AD1_11D3_BF96_0020182B97FC__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 #include #include #include // Property Sheet control id's (determined with Spy++) #define ID_APPLY_NOW 0x3021 #define ID_WIZBACK 0x3023 #define ID_WIZNEXT 0x3024 #define ID_WIZFINISH 0x3025 #define AFX_IDC_TAB_CONTROL 0x3020 // determine number of elements in an array (not bytes) #define _countof(array) (sizeof(array)/sizeof(array[0])) template class CPropertySheetT; template class CPropertyPageT; const int _PropSheetIDs[] = { ID_WIZNEXT, ID_WIZFINISH, ID_WIZBACK, IDCANCEL }; const int _PropSheetButtons[] = { IDOK, IDCANCEL, ID_APPLY_NOW, IDHELP }; //////////////////////////////////////////////////////////////////////// // Implements one page of a Property Sheet template class CPropertyPageT : public CDialogImplBaseT< TBase > { // Construction public: CPropertyPageT(UINT IDD) : m_szCaption(NULL) { Construct(IDD, _T("")); } // Caption from Resource CPropertyPageT(UINT IDD, UINT nIDCaption) : m_szCaption(NULL) { Construct(IDD, nIDCaption); } CPropertyPageT(UINT IDD, LPCTSTR szCaption) : m_szCaption(NULL) { Construct(IDD, szCaption); } void Construct(UINT IDD, LPCTSTR szCaption) { CommonConstruct(IDD, szCaption); } void Construct(UINT IDD, UINT nIDCaption) { ATLASSERT(nIDCaption != 0); USES_CONVERSION; CComBSTR bsCaption; bsCaption.LoadString(nIDCaption); CommonConstruct(IDD, OLE2T(bsCaption)); } // All Construction ends up here void CommonConstruct(UINT IDD, LPCTSTR szCaption); ~CPropertyPageT() { if(m_szCaption) delete[] m_szCaption; } // Operations void CancelToClose(); void SetModified(bool bChanged); void SetHelp(bool bHelp); LRESULT QuerySiblings(WPARAM wParam, LPARAM lParam); bool IsButtonEnabled(int iButton); void EndDialog(int nID); // Status CPropertySheetT* GetParentSheet(); // Implementaition protected: CPropertySheetT* m_pSheet; // Pointer to Sheet static UINT CALLBACK PropPageCallback(HWND hwnd, UINT uMsg, LPPROPSHEETPAGE ppsp); // Data public: PROPSHEETPAGE m_psp; // API Structure LPTSTR m_szCaption; // Caption friend class CPropertySheetT; }; // Common Construction template void CPropertyPageT::CommonConstruct(UINT IDD, LPCTSTR szCaption) { // Clear memset(&m_psp, 0, sizeof(m_psp)); m_psp.dwSize = sizeof(m_psp); m_psp.hInstance = _Module.m_hInstResource; m_psp.pszTemplate = MAKEINTRESOURCE(IDD); // Set to DialogProc m_psp.pfnDlgProc = (DLGPROC)StartDialogProc; // Use to hook up to ATL WndProc m_psp.pfnCallback = PropPageCallback; m_psp.dwFlags = PSP_USETITLE | PSP_USECALLBACK; // Passed to PropPageCallback m_psp.lParam = (LPARAM)this; // Allocate String if(m_szCaption && _tcslen(m_szCaption) < _tcslen(szCaption)) { delete[] m_szCaption; m_szCaption = NULL; } if(!m_szCaption) m_szCaption = new TCHAR[_tcslen(szCaption) + 1]; _tcscpy(m_szCaption, szCaption); m_psp.pszTitle = m_szCaption; // Set by CPropertySheetT::AddPage m_pSheet = NULL; } // Callback used during actual creation of page template UINT CALLBACK CPropertyPageT::PropPageCallback(HWND hwnd, UINT uMsg, LPPROPSHEETPAGE ppsp) { switch (uMsg) { case PSPCB_CREATE: { // Get ready for hooking up to an ATL WndProc CPropertyPageT* pPage = (CPropertyPageT*)ppsp->lParam; _Module.AddCreateWndData(&(pPage->m_thunk.cd), pPage); return TRUE; } case PSPCB_RELEASE: break; } return 0; } // Thin Wrapper template void CPropertyPageT::CancelToClose() { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(GetParent() != NULL); ::SendMessage(GetParent(), PSM_CANCELTOCLOSE, NULL, NULL); } // Thin Wrapper template void CPropertyPageT::SetModified(bool bChanged) { ATLASSERT(m_hWnd != NULL); ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(GetParent() != NULL); if (bChanged) ::SendMessage(GetParent(), PSM_CHANGED, (WPARAM)m_hWnd, NULL); else ::SendMessage(GetParent(), PSM_UNCHANGED, (WPARAM)m_hWnd, NULL); } // Thin Wrapper template LRESULT CPropertyPageT::QuerySiblings(WPARAM wParam, LPARAM lParam) { ATLASSERT(::IsWindow(m_hWnd)); ATLASSERT(GetParent() != NULL); return ::SendMessage(GetParent(), PSM_QUERYSIBLINGS, wParam, lParam); } template void CPropertyPageT::SetHelp(bool bHelp) { if(bHelp) m_psp.dwFlags |= PSP_HASHELP; else m_psp.dwFlags &= ~(PSP_HASHELP); } // Thin wrapper template bool CPropertyPageT::IsButtonEnabled(int iButton) { HWND hWnd = ::GetDlgItem(::GetParent(m_hWnd), iButton); if (hWnd == NULL) return false; return ::IsWindowEnabled(hWnd) ? true : false; } // Routes EndDialog calls to the Sheet template void CPropertyPageT::EndDialog(int nID) { // Normally you shouldn't call EndDialog from a page. But in case it does // happen during error situations, call CPropertySheetT::EndDialog instead. CPropertySheetT* pParent = GetParentSheet(); if (pParent != NULL) pParent->EndDialog(nID); } // Return Sheet Pointer (which is initialized in CPropertySheetT::AddPage) template CPropertySheetT* CPropertyPageT::GetParentSheet() { ATLASSERT(m_pSheet != NULL); return m_pSheet; } //////////////////////////////////////////////////////////////////////// // Implements and hooks into Actual Property Sheet Window template class CPropertySheetT : public CWindowImplBaseT< TBase > { // Construction public: CPropertySheetT() : m_szCaption(NULL) { CommonConstruct(_T(""), 0); } // Caption from Resource CPropertySheetT(UINT nIDCaption, HWND hwndParent = NULL, UINT iSelectPage = 0) : m_szCaption(NULL) { Construct(nIDCaption, hwndParent, iSelectPage); } CPropertySheetT(LPCTSTR pszCaption, HWND hwndParent = NULL, UINT iSelectPage = 0) : m_szCaption(NULL) { Construct(pszCaption, hwndParent, iSelectPage); } // Caption from Resource void Construct(UINT nIDCaption, HWND hwndParent = NULL, UINT iSelectPage = 0) { ATLASSERT(nIDCaption != 0); USES_CONVERSION; CComBSTR bsCaption; bsCaption.LoadString(nIDCaption); CommonConstruct(OLE2T(bsCaption), hwndParent, iSelectPage); } void Construct(LPCTSTR pszCaption, HWND hwndParent = NULL, UINT iSelectPage = 0) { CommonConstruct(pszCaption, hwndParent, iSelectPage); } // All actual initialization takes place here void CommonConstruct(LPCTSTR sCaption, HWND hwndParent = NULL, UINT iSelectPage = 0); virtual ~CPropertySheetT() { if(m_szCaption) delete[] m_szCaption; } // Creation public: // for modeless creation // the default style, expressed by passing -1 as dwStyle, is actually: // WS_SYSMENU | WS_POPUP | WS_CAPTION | DS_MODALFRAME | WS_VISIBLE bool Create(HWND hwndParent = NULL, DWORD dwStyle = (DWORD)-1, DWORD dwExStyle = 0); int DoModal(HWND hwndParent = NULL, DWORD dwStyle = (DWORD)-1, DWORD dwExStyle = 0); // Operations public: void AddPage(CPropertyPageT* pPage); void RemovePage(CPropertyPageT* pPage); void RemovePage(int nPage); void EndDialog(int nEndID); // used to terminate a modal dialog bool PressButton(int nButton); // Status and Settings public: int GetPageCount() const; int GetActiveIndex() const; CPropertyPageT* GetActivePage() const; CPropertyPageT* GetPage(int nPage) const; int GetPageIndex(CPropertyPageT* pPage); HWND GetTabControl() const; void SetWizardMode(); void SetHelp(bool bHelp); void SetFinishText(LPCTSTR lpszText); void SetWizardButtons(DWORD dwFlags); void EnableStackedTabs(BOOL bStacked); bool IsWizard() const; bool SetActivePage(int nPage); bool SetActivePage(CPropertyPageT* pPage); void SetTitle(LPCTSTR lpszText, UINT nStyle = 0); // Message Map protected: typedef CPropertySheetT sheetClass; BEGIN_MSG_MAP(sheetClass) MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) MESSAGE_HANDLER(WM_SYSCOMMAND, OnSysCommand) MESSAGE_HANDLER(WM_CLOSE, OnClose) COMMAND_HANDLER(IDCANCEL, BN_CLICKED, OnEndCode) COMMAND_HANDLER(IDOK, BN_CLICKED, OnEndCode) COMMAND_HANDLER(ID_WIZFINISH, BN_CLICKED, OnEndCode) END_MSG_MAP() // Message Handlers LRESULT OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); LRESULT OnSysCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); LRESULT OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); LRESULT OnEndCode(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled); // Implementation protected: void BuildPropPageArray(); // Finalizes the Array of Pages // Used during creation to set styles static int CALLBACK PropSheetCallback(HWND, UINT nMsg, LPARAM lParam); // For hooking into creation and subclassing the window DECLARE_HOOK_AND_SUBCLASS(sheetClass); // Style cache (used in PropSheetCallback) DWORD m_dwCurStyle; DWORD m_dwCurExStyle; // Data protected: CSimpleArray< CPropertyPageT* > m_pages; // array of CPropertyPageT pointers LPTSTR m_szCaption; // caption of the pseudo-dialog bool m_bStacked; // EnableStackedTabs sets this bool m_bModeless; // TRUE when Create called instead of DoModal int m_nDlgRet; // Result from EndDialog public: PROPSHEETHEADER m_psh; }; // All Initialization here template void CPropertySheetT::CommonConstruct(LPCTSTR szCaption, HWND hwndParent /*= NULL*/, UINT iSelectPage /*= 0*/) { // Clear memset(&m_psh, 0, sizeof(m_psh)); m_psh.dwSize = sizeof(m_psh); m_psh.dwFlags = PSH_PROPSHEETPAGE; m_psh.nStartPage = iSelectPage; // Allocate String if(m_szCaption && _tcslen(m_szCaption) < _tcslen(szCaption)) { delete[] m_szCaption; m_szCaption = NULL; } if(!m_szCaption) m_szCaption = new TCHAR[_tcslen(szCaption) + 1]; _tcscpy(m_szCaption, szCaption); m_psh.pszCaption = m_szCaption; m_bStacked = true; // Tab Control m_bModeless = false; m_dwCurStyle = 0; m_dwCurExStyle = 0; m_nDlgRet = 0; // m_psh.hwndParent set in DoModal/create } // Callback used to set styles of Property Sheet template int CALLBACK CPropertySheetT::PropSheetCallback(HWND hwnd, UINT nMsg, LPARAM lParam) { switch (nMsg) { case PSCB_PRECREATE: { // Extract Thunk Create (whatever) data CPropertySheetT* pThis = (CPropertySheetT*)_Module.ExtractCreateWndData(); // We need it later in the proces so add it back again _Module.AddCreateWndData(&(pThis->m_thunk.cd), pThis); LPDLGTEMPLATE lpTemplate = (LPDLGTEMPLATE)lParam; if (lpTemplate->style != pThis->m_dwCurStyle || lpTemplate->dwExtendedStyle != pThis->m_dwCurExStyle) { // Mark the dialog template as read-write. DWORD dwOldProtect; VirtualProtect(lpTemplate, sizeof(DLGTEMPLATE), PAGE_READWRITE, &dwOldProtect); // Ensure DS_SETFONT is set correctly. lpTemplate->style = lpTemplate->style & DS_SETFONT ? pThis->m_dwCurStyle | DS_SETFONT : pThis->m_dwCurStyle & ~DS_SETFONT; lpTemplate->dwExtendedStyle = pThis->m_dwCurExStyle; } return TRUE; } case PSCB_INITIALIZED: return TRUE; } return 0; } // Creates a Modeless Property Sheet template bool CPropertySheetT::Create(HWND hwndParent /*= NULL*/, DWORD dwStyle /*= (DWORD)-1*/, DWORD dwExStyle /*= 0*/) { // Calculate the default window style. if (dwStyle == (DWORD)-1) { dwStyle = DS_MODALFRAME | DS_3DLOOK | DS_SETFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION; // Wizards don't have WS_SYSMENU by default if (!IsWizard()) dwStyle |= WS_SYSMENU; } // Cache the styles (for use in PropSheetCallback) m_dwCurStyle = dwStyle; m_dwCurExStyle = dwExStyle; ATLASSERT(m_hWnd == NULL); // finish building PROPSHEETHEADER structure BuildPropPageArray(); // Some more settings m_bModeless = true; m_psh.dwFlags |= (PSH_MODELESS | PSH_USECALLBACK); m_psh.pfnCallback = PropSheetCallback; m_psh.hwndParent = hwndParent; // Add Create Thunk whatever Data _Module.AddCreateWndData(&m_thunk.cd, this); // Hook into creation so we can subclass before any messages come in HOOK_AND_SUBCLASS_NEXT(); // Do it! HWND hWnd = (HWND)::PropertySheet((PROPSHEETHEADER*)&m_psh); // Modeless so we return right away #ifdef _DEBUG DWORD dwError = ::GetLastError(); #endif if (hWnd == NULL || hWnd == (HWND)-1) { #ifdef _DEBUG ATLTRACE("PropertySheet() failed: GetLastError returned %d\n", dwError); #endif return false; } m_hWnd = hWnd; return true; } // Create a Modal Dialog template int CPropertySheetT::DoModal(HWND hwndParent /*= NULL*/, DWORD dwStyle /*= (DWORD)-1*/, DWORD dwExStyle /*= 0*/) { ATLASSERT(m_hWnd == NULL); // Calculate the default window style. if (dwStyle == (DWORD)-1) { dwStyle = DS_MODALFRAME | DS_3DLOOK | DS_SETFONT | WS_POPUP | WS_VISIBLE | WS_CAPTION; // Wizards don't have WS_SYSMENU by default if (!IsWizard()) dwStyle |= WS_SYSMENU; } // Cache the styles (for use in PropSheetCallback) m_dwCurStyle = dwStyle; m_dwCurExStyle = dwExStyle; // finish building PROPSHEETHEADER structure BuildPropPageArray(); // Set options m_bModeless = false; m_nDlgRet = -1; m_psh.dwFlags |= (PSH_USECALLBACK); m_psh.pfnCallback = PropSheetCallback; m_psh.hwndParent = hwndParent; // Add Create Thunk whatever Data _Module.AddCreateWndData(&m_thunk.cd, this); // Hook into creation so we can subclass before any messages come in HOOK_AND_SUBCLASS_NEXT(); // Do it. Doesn't come back until after the fact int nRet = ::PropertySheet((PROPSHEETHEADER*)&m_psh); if(nRet == -1) return nRet; return m_nDlgRet; } // Finalize the Array template void CPropertySheetT::BuildPropPageArray() { // delete existing prop page array delete[] (PROPSHEETPAGE*)m_psh.ppsp; m_psh.ppsp = NULL; // build new prop page array PROPSHEETPAGE* ppsp = new PROPSHEETPAGE[m_pages.GetSize()]; m_psh.ppsp = (PROPSHEETPAGE*)ppsp; BOOL bWizard = (m_psh.dwFlags & (PSH_WIZARD)); for (int i = 0; i < m_pages.GetSize(); i++) { CPropertyPageT* pPage = GetPage(i); memcpy(&ppsp[i], &pPage->m_psp, sizeof(pPage->m_psp)); // pPage->PreProcessPageTemplate((PROPSHEETPAGE&)ppsp[i], bWizard); } m_psh.nPages = m_pages.GetSize(); } // Adds a Page (either before or after we're on the screen) template void CPropertySheetT::AddPage(CPropertyPageT* pPage) { ATLASSERT(pPage != NULL); // Add page to internal list m_pages.Add(pPage); pPage->m_pSheet = this; // Add page externally if (m_hWnd != NULL) { // build new prop page array PROPSHEETPAGE* ppsp = new PROPSHEETPAGE[m_pages.GetSize()]; memcpy(ppsp, m_psh.ppsp, sizeof(PROPSHEETPAGE) * (m_pages.GetSize() - 1)); delete[] (PROPSHEETPAGE*)m_psh.ppsp; m_psh.ppsp = ppsp; ppsp += m_pages.GetSize() - 1; // copy processed PROPSHEETPAGE struct to end memcpy(ppsp, &(pPage->m_psp), sizeof(pPage->m_psp)); // pPage->PreProcessPageTemplate((PROPSHEETPAGE&)*ppsp, IsWizard()); HPROPSHEETPAGE hPSP = CreatePropertySheetPage((PROPSHEETPAGE*)ppsp); ATLASSERT(hPSP != NULL); // Tray and add it if (!SendMessage(PSM_ADDPAGE, 0, (LPARAM)hPSP)) { DestroyPropertySheetPage(hPSP); ATLASSERT(false); } } } // Removes a Page (either before or after we're on the screen) template void CPropertySheetT::RemovePage(CPropertyPageT* pPage) { ATLASSERT(pPage != NULL); // Get Index int nPage = GetPageIndex(pPage); pPage->m_pSheet = NULL; ATLASSERT(nPage >= 0); RemovePage(nPage); } // Removes a Page (either before or after we're on the screen) template void CPropertySheetT::RemovePage(int nPage) { // remove the page externally if (m_hWnd != NULL) SendMessage(PSM_REMOVEPAGE, nPage); // remove the page from internal list m_pages.RemoveAt(nPage); } // Closes the Property Sheet template void CPropertySheetT::EndDialog(int nEndID) { m_nDlgRet = nEndID; if (m_bModeless) DestroyWindow(); else PostMessage(PSM_PRESSBUTTON, PSBTN_CANCEL); } // Need to handle WM_CLOSE for Modeless Property Sheets template LRESULT CPropertySheetT::OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { if (m_bModeless) DestroyWindow(); else bHandled = false; return 0; } // Need to handle SC_CLOSE for Modeless Property Sheets template LRESULT CPropertySheetT::OnSysCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { switch (wParam & 0xFFF0) { case SC_CLOSE: if (m_bModeless) { SendMessage(WM_CLOSE); return 0; } } bHandled = false; return 0; } // Returns number of Pages template int CPropertySheetT::GetPageCount() const { if (m_hWnd == NULL) return m_pages.GetSize(); return TabCtrl_GetItemCount(GetTabControl()); } // Returns Current Page template int CPropertySheetT::GetActiveIndex() const { if (m_hWnd == NULL) return m_psh.nStartPage; return TabCtrl_GetCurSel(GetTabControl()); } // Moves to Page template bool CPropertySheetT::SetActivePage(int nPage) { if (m_hWnd == NULL) { m_psh.nStartPage = nPage; return true; } return (bool)SendMessage(PSM_SETCURSEL, nPage); } // Moves to Page template bool CPropertySheetT::SetActivePage(CPropertyPageT* pPage) { ATLASSERT(pPage != NULL); int nPage = GetPageIndex(pPage); ATLASSERT(pPage >= 0); return SetActivePage(nPage); } // Gets number of Page template int CPropertySheetT::GetPageIndex(CPropertyPageT* pPage) { ATLASSERT(pPage != NULL); for (int i = 0; i < GetPageCount(); i++) { if (GetPage(i) == pPage) return i; } return -1; // pPage not found } // Get a Page from Array template CPropertyPageT* CPropertySheetT::GetPage(int nPage) const { return m_pages[nPage]; } // Initdialog: Complete creation and setup for modeless etc... template LRESULT CPropertySheetT::OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { // Change tab style if scrolling tabs desired (stacked tabs are default) if (!m_bStacked) ((CWindow)GetTabControl()).ModifyStyle(TCS_MULTILINE, TCS_SINGLELINE, 0); // For Property Sheets if (!IsWizard()) { // Resize the tab control so the layout is less restrictive HWND hWndTab = ::GetDlgItem(m_hWnd, AFX_IDC_TAB_CONTROL); ATLASSERT(hWndTab != NULL); RECT rcOld; ::GetWindowRect(hWndTab, &rcOld); ScreenToClient(&rcOld); RECT rcNew = {0, 0, 0, 32}; ::MapDialogRect(m_hWnd, &rcNew); if (rcNew.bottom < rcNew.bottom) { // Move tab control int cyDiff = (rcOld.bottom - rcOld.top) - rcNew.bottom; ::SetWindowPos(hWndTab, NULL, 0, 0, rcOld.right - rcOld.left, rcNew.bottom, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); // Move buttons by similar amount for (int i = 0; i < _countof(_PropSheetButtons); i++) { HWND hWndBtn = ::GetDlgItem(m_hWnd, _PropSheetButtons[i]); if (hWndBtn != NULL) { ::GetWindowRect(hWndBtn, &rcOld); ScreenToClient(&rcOld); ::SetWindowPos(hWndBtn, NULL, rcOld.left, rcOld.top - cyDiff, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); } } // Resize property sheet itself similarly GetWindowRect(&rcOld); SetWindowPos(NULL, 0, 0, rcOld.right - rcOld.left, (rcOld.bottom - rcOld.top) - cyDiff, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); } } // For Modeless Sheets if (m_bModeless && !IsWizard()) { // Layout property sheet so button area is not accounted for RECT rcWnd; GetWindowRect(&rcWnd); RECT rcBtn; HWND hWndBtn = ::GetDlgItem(m_hWnd, IDOK); ATLASSERT(hWndBtn != NULL); ::GetWindowRect(hWndBtn, &rcBtn); SetWindowPos(NULL, 0, 0, rcWnd.right - rcWnd.left, (rcBtn.top - rcWnd.top) + ::GetSystemMetrics(SM_CYBORDER), SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); // Remove standard buttons for modeless dialogs for (int i = 0; i < _countof(_PropSheetButtons); i++) { hWndBtn = ::GetDlgItem(m_hWnd, _PropSheetButtons[i]); if (hWndBtn != NULL) { ::ShowWindow(hWndBtn, SW_HIDE); ::EnableWindow(hWndBtn, FALSE); } } } // Center the property sheet relative to the parent window if (!(GetStyle() & WS_CHILD)) CenterWindow(); // API implementation probably needs this message bHandled = FALSE; return 1; } // Gets the return code for DoModal template LRESULT CPropertySheetT::OnEndCode(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) { // API implementation probably needs this message bHandled = FALSE; m_nDlgRet = wID; return 0; } // Are we a wizard? template bool CPropertySheetT::IsWizard() const { return ((m_psh.dwFlags & PSH_WIZARD) != 0); } // Return HWND of Tab Control template HWND CPropertySheetT::GetTabControl() const { ATLASSERT(::IsWindow(m_hWnd)); return (HWND)::SendMessage(m_hWnd, PSM_GETTABCONTROL, 0, 0); } // Press Button on Property Sheet template bool CPropertySheetT::PressButton(int nButton) { ATLASSERT(::IsWindow(m_hWnd)); return ::SendMessage(m_hWnd, PSM_PRESSBUTTON, nButton, 0) ? true : false; } // Get the Active Page template CPropertyPageT* CPropertySheetT::GetActivePage() const { return GetPage(GetActiveIndex()); } // Change the Title template void CPropertySheetT::SetTitle(LPCTSTR lpszText, UINT nStyle) { ATLASSERT((nStyle & ~PSH_PROPTITLE) == 0); // only PSH_PROPTITLE is valid // Set Internal State if(m_szCaption && _tcslen(m_szCaption) < _tcslen(lpszText)) { delete[] m_szCaption; m_szCaption = NULL; } if(!m_szCaption) m_szCaption = new TCHAR[_tcslen(lpszText) + 1]; _tcscpy(m_szCaption, lpszText); m_psh.pszCaption = m_szCaption; // Set the options m_psh.dwFlags &= ~PSH_PROPTITLE; m_psh.dwFlags |= nStyle; if (m_hWnd != NULL) { // set external state SendMessage(PSM_SETTITLE, nStyle, (LPARAM)lpszText); } } // Make us a Wizard template void CPropertySheetT::SetWizardMode() { m_psh.dwFlags |= PSH_WIZARD; } template void CPropertySheetT::SetHelp(bool bHelp) { if(bHelp) m_psh.dwFlags |= PSH_HASHELP; else m_psh.dwFlags &= ~(PSH_HASHELP); } // Set Text of Finish Button template void CPropertySheetT::SetFinishText(LPCTSTR lpszText) { ATLASSERT(::IsWindow(m_hWnd)); ::SendMessage(m_hWnd, PSM_SETFINISHTEXT, 0, (LPARAM)lpszText); } // Choose which buttons to have in Wizard template void CPropertySheetT::SetWizardButtons(DWORD dwFlags) { ATLASSERT(::IsWindow(m_hWnd)); ::PostMessage(m_hWnd, PSM_SETWIZBUTTONS, 0, dwFlags); } // Stacked Tabs template void CPropertySheetT::EnableStackedTabs(BOOL bStacked) { m_bStacked = bStacked; } typedef CPropertySheetT CPropertySheet; typedef CPropertyPageT CPropertyPage; #endif // !defined(AFX_PROPERTYPAGE_H__1508DAF4_7AD1_11D3_BF96_0020182B97FC__INCLUDED_)