--- /dev/null
+// Win32++ Version 7.3\r
+// Released: 30th November 2011\r
+//\r
+// David Nash\r
+// url: https://sourceforge.net/projects/win32-framework\r
+//\r
+//\r
+// Copyright (c) 2005-2011 David Nash\r
+//\r
+// Permission is hereby granted, free of charge, to\r
+// any person obtaining a copy of this software and\r
+// associated documentation files (the "Software"),\r
+// to deal in the Software without restriction, including\r
+// without limitation the rights to use, copy, modify,\r
+// merge, publish, distribute, sublicense, and/or sell\r
+// copies of the Software, and to permit persons to whom\r
+// the Software is furnished to do so, subject to the\r
+// following conditions:\r
+//\r
+// The above copyright notice and this permission notice\r
+// shall be included in all copies or substantial portions\r
+// of the Software.\r
+//\r
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF\r
+// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED\r
+// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A\r
+// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT\r
+// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR\r
+// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE\r
+// OR OTHER DEALINGS IN THE SOFTWARE.\r
+//\r
+////////////////////////////////////////////////////////\r
+\r
+\r
+///////////////////////////////////////////////////////\r
+// propertysheet.h\r
+// Declaration of the following classes:\r
+// CPropertyPage and CPropertySheet\r
+\r
+// These classes add support for property sheets to Win32++. A property sheet\r
+// will have one or more property pages. These pages are much like dialogs\r
+// which are presented within a tabbed dialog or within a wizard. The data\r
+// on a property page can be validated before the next page is presented.\r
+// Property sheets have three modes of use: Modal, Modeless, and Wizard.\r
+//\r
+// Refer to the PropertySheet demo program for an example of how propert sheets\r
+// can be used.\r
+\r
+\r
+#ifndef _WIN32XX_PROPERTYSHEET_H_\r
+#define _WIN32XX_PROPERTYSHEET_H_\r
+\r
+#include "dialog.h"\r
+\r
+#define ID_APPLY_NOW 0x3021\r
+#define ID_WIZBACK 0x3023\r
+#define ID_WIZNEXT 0x3024\r
+#define ID_WIZFINISH 0x3025\r
+#define ID_HELP 0xE146\r
+\r
+#ifndef PROPSHEETHEADER_V1_SIZE\r
+ #define PROPSHEETHEADER_V1_SIZE 40\r
+#endif\r
+\r
+namespace Win32xx\r
+{\r
+ class CPropertyPage;\r
+ typedef Shared_Ptr<CPropertyPage> PropertyPagePtr;\r
+\r
+ class CPropertyPage : public CWnd\r
+ {\r
+ public:\r
+ CPropertyPage (UINT nIDTemplate, LPCTSTR szTitle = NULL);\r
+ virtual ~CPropertyPage() {}\r
+\r
+ virtual INT_PTR DialogProc(UINT uMsg, WPARAM wParam, LPARAM lParam);\r
+ virtual INT_PTR DialogProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam);\r
+ virtual int OnApply();\r
+ virtual void OnCancel();\r
+ virtual void OnHelp();\r
+ virtual BOOL OnInitDialog();\r
+ virtual BOOL OnKillActive();\r
+ virtual LRESULT OnNotify(WPARAM wParam, LPARAM lParam);\r
+ virtual int OnOK();\r
+ virtual BOOL OnQueryCancel();\r
+ virtual BOOL OnQuerySiblings(WPARAM wParam, LPARAM lParam);\r
+ virtual int OnSetActive();\r
+ virtual int OnWizardBack();\r
+ virtual INT_PTR OnWizardFinish();\r
+ virtual int OnWizardNext();\r
+ virtual BOOL PreTranslateMessage(MSG* pMsg);\r
+\r
+ static UINT CALLBACK StaticPropSheetPageProc(HWND hwnd, UINT uMsg, LPPROPSHEETPAGE ppsp);\r
+ static INT_PTR CALLBACK StaticDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);\r
+\r
+ void CancelToClose() const;\r
+ PROPSHEETPAGE GetPSP() const {return m_PSP;}\r
+ BOOL IsButtonEnabled(int iButton) const;\r
+ LRESULT QuerySiblings(WPARAM wParam, LPARAM lParam) const;\r
+ void SetModified(BOOL bChanged) const;\r
+ void SetTitle(LPCTSTR szTitle);\r
+ void SetWizardButtons(DWORD dwFlags) const;\r
+\r
+ protected:\r
+ PROPSHEETPAGE m_PSP;\r
+\r
+ private:\r
+ CPropertyPage(const CPropertyPage&); // Disable copy construction\r
+ CPropertyPage& operator = (const CPropertyPage&); // Disable assignment operator\r
+\r
+ CString m_Title;\r
+ };\r
+\r
+ class CPropertySheet : public CWnd\r
+ {\r
+ public:\r
+ CPropertySheet(UINT nIDCaption, CWnd* pParent = NULL);\r
+ CPropertySheet(LPCTSTR pszCaption = NULL, CWnd* pParent = NULL);\r
+ virtual ~CPropertySheet() {}\r
+\r
+ // Operations\r
+ virtual CPropertyPage* AddPage(CPropertyPage* pPage);\r
+ virtual HWND Create(CWnd* pParent = 0);\r
+ virtual INT_PTR CreatePropertySheet(LPCPROPSHEETHEADER ppsph);\r
+ virtual void DestroyButton(int iButton);\r
+ virtual void Destroy();\r
+ virtual int DoModal();\r
+ virtual void RemovePage(CPropertyPage* pPage);\r
+\r
+ // State functions\r
+ BOOL IsModeless() const;\r
+ BOOL IsWizard() const;\r
+\r
+ //Attributes\r
+ CPropertyPage* GetActivePage() const;\r
+ int GetPageCount() const;\r
+ int GetPageIndex(CPropertyPage* pPage) const;\r
+ HWND GetTabControl() const;\r
+ virtual BOOL SetActivePage(int nPage);\r
+ virtual BOOL SetActivePage(CPropertyPage* pPage);\r
+ virtual void SetIcon(UINT idIcon);\r
+ virtual void SetTitle(LPCTSTR szTitle);\r
+ virtual void SetWizardMode(BOOL bWizard);\r
+\r
+ protected:\r
+ virtual BOOL PreTranslateMessage(MSG* pMsg);\r
+ virtual LRESULT WndProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam);\r
+\r
+ private:\r
+ CPropertySheet(const CPropertySheet&); // Disable copy construction\r
+ CPropertySheet& operator = (const CPropertySheet&); // Disable assignment operator\r
+ void BuildPageArray();\r
+ static void CALLBACK Callback(HWND hwnd, UINT uMsg, LPARAM lParam);\r
+\r
+ CString m_Title;\r
+ std::vector<PropertyPagePtr> m_vPages; // vector of CPropertyPage\r
+ std::vector<PROPSHEETPAGE> m_vPSP; // vector of PROPSHEETPAGE\r
+ BOOL m_bInitialUpdate;\r
+ PROPSHEETHEADER m_PSH;\r
+ };\r
+\r
+}\r
+\r
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//\r
+\r
+namespace Win32xx\r
+{\r
+\r
+ //////////////////////////////////////////\r
+ // Definitions for the CPropertyPage class\r
+ //\r
+ inline CPropertyPage::CPropertyPage(UINT nIDTemplate, LPCTSTR szTitle /* = NULL*/)\r
+ {\r
+ ZeroMemory(&m_PSP, sizeof(PROPSHEETPAGE));\r
+ SetTitle(szTitle);\r
+\r
+ m_PSP.dwSize = sizeof(PROPSHEETPAGE);\r
+ m_PSP.dwFlags |= PSP_USECALLBACK;\r
+ m_PSP.hInstance = GetApp()->GetResourceHandle();\r
+ m_PSP.pszTemplate = MAKEINTRESOURCE(nIDTemplate);\r
+ m_PSP.pszTitle = m_Title;\r
+ m_PSP.pfnDlgProc = (DLGPROC)CPropertyPage::StaticDialogProc;\r
+ m_PSP.lParam = (LPARAM)this;\r
+ m_PSP.pfnCallback = CPropertyPage::StaticPropSheetPageProc;\r
+ }\r
+\r
+ inline void CPropertyPage::CancelToClose() const\r
+ // Disables the Cancel button and changes the text of the OK button to "Close."\r
+ {\r
+ assert(::IsWindow(m_hWnd));\r
+ SendMessage(PSM_CANCELTOCLOSE, 0L, 0L);\r
+ }\r
+\r
+\r
+ inline INT_PTR CPropertyPage::DialogProc(UINT uMsg, WPARAM wParam, LPARAM lParam)\r
+ {\r
+ // Override this function in your class derrived from CPropertyPage if you wish to handle messages\r
+ // A typical function might look like this:\r
+\r
+ // switch (uMsg)\r
+ // {\r
+ // case MESSAGE1: // Some Win32 API message\r
+ // OnMessage1(); // A user defined function\r
+ // break; // Also do default processing\r
+ // case MESSAGE2:\r
+ // OnMessage2();\r
+ // return x; // Don't do default processing, but instead return\r
+ // // a value recommended by the Win32 API documentation\r
+ // }\r
+\r
+ // Always pass unhandled messages on to DialogProcDefault\r
+ return DialogProcDefault(uMsg, wParam, lParam);\r
+ }\r
+\r
+ inline INT_PTR CPropertyPage::DialogProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam)\r
+ // All DialogProc functions should pass unhandled messages to this function\r
+ {\r
+ LRESULT lr = 0L;\r
+\r
+ switch (uMsg)\r
+ {\r
+ case UWM_CLEANUPTEMPS:\r
+ {\r
+ TLSData* pTLSData = (TLSData*)TlsGetValue(GetApp()->GetTlsIndex());\r
+ pTLSData->vTmpWnds.clear();\r
+ }\r
+ break;\r
+\r
+ case WM_INITDIALOG:\r
+ return OnInitDialog();\r
+\r
+ case PSM_QUERYSIBLINGS:\r
+ return (BOOL)OnQuerySiblings(wParam, lParam);\r
+\r
+ case WM_COMMAND:\r
+ {\r
+ // Refelect this message if it's from a control\r
+ CWnd* pWnd = GetApp()->GetCWndFromMap((HWND)lParam);\r
+ if (pWnd != NULL)\r
+ lr = pWnd->OnCommand(wParam, lParam);\r
+\r
+ // Handle user commands\r
+ if (!lr)\r
+ lr = OnCommand(wParam, lParam);\r
+\r
+ if (lr) return 0L;\r
+ }\r
+ break;\r
+\r
+ case WM_NOTIFY:\r
+ {\r
+ // Do Notification reflection if it came from a CWnd object\r
+ HWND hwndFrom = ((LPNMHDR)lParam)->hwndFrom;\r
+ CWnd* pWndFrom = GetApp()->GetCWndFromMap(hwndFrom);\r
+\r
+ if (pWndFrom != NULL)\r
+ lr = pWndFrom->OnNotifyReflect(wParam, lParam);\r
+ else\r
+ {\r
+ // Some controls (eg ListView) have child windows.\r
+ // Reflect those notifications too.\r
+ CWnd* pWndFromParent = GetApp()->GetCWndFromMap(::GetParent(hwndFrom));\r
+ if (pWndFromParent != NULL)\r
+ lr = pWndFromParent->OnNotifyReflect(wParam, lParam);\r
+ }\r
+\r
+ // Handle user notifications\r
+ if (!lr) lr = OnNotify(wParam, lParam);\r
+\r
+ // Set the return code for notifications\r
+ if (IsWindow())\r
+ SetWindowLongPtr(DWLP_MSGRESULT, (LONG_PTR)lr);\r
+\r
+ return (BOOL)lr;\r
+ }\r
+\r
+ case WM_PAINT:\r
+ {\r
+ if (::GetUpdateRect(m_hWnd, NULL, FALSE))\r
+ {\r
+ CPaintDC dc(this);\r
+ OnDraw(&dc);\r
+ }\r
+ else\r
+ // RedrawWindow can require repainting without an update rect\r
+ {\r
+ CClientDC dc(this);\r
+ OnDraw(&dc);\r
+ }\r
+\r
+ break;\r
+ }\r
+ \r
+ case WM_ERASEBKGND:\r
+ {\r
+ CDC dc((HDC)wParam);\r
+ BOOL bResult = OnEraseBkgnd(&dc);\r
+ dc.Detach();\r
+ if (bResult) return TRUE;\r
+ }\r
+ break;\r
+\r
+ // A set of messages to be reflected back to the control that generated them\r
+ case WM_CTLCOLORBTN:\r
+ case WM_CTLCOLOREDIT:\r
+ case WM_CTLCOLORDLG:\r
+ case WM_CTLCOLORLISTBOX:\r
+ case WM_CTLCOLORSCROLLBAR:\r
+ case WM_CTLCOLORSTATIC:\r
+ case WM_DRAWITEM:\r
+ case WM_MEASUREITEM:\r
+ case WM_DELETEITEM:\r
+ case WM_COMPAREITEM:\r
+ case WM_CHARTOITEM:\r
+ case WM_VKEYTOITEM:\r
+ case WM_HSCROLL:\r
+ case WM_VSCROLL:\r
+ case WM_PARENTNOTIFY:\r
+ return MessageReflect(m_hWnd, uMsg, wParam, lParam);\r
+\r
+ } // switch(uMsg)\r
+ return FALSE;\r
+\r
+ } // INT_PTR CALLBACK CPropertyPage::DialogProc(...)\r
+\r
+ inline BOOL CPropertyPage::IsButtonEnabled(int iButton) const\r
+ {\r
+ assert(::IsWindow(m_hWnd));\r
+ return GetParent()->GetDlgItem(iButton)->IsWindowEnabled();\r
+ }\r
+\r
+ inline int CPropertyPage::OnApply()\r
+ {\r
+ // This function is called for each page when the Apply button is pressed\r
+ // Override this function in your derived class if required.\r
+\r
+ // The possible return values are:\r
+ // PSNRET_NOERROR. The changes made to this page are valid and have been applied\r
+ // PSNRET_INVALID. The property sheet will not be destroyed, and focus will be returned to this page.\r
+ // PSNRET_INVALID_NOCHANGEPAGE. The property sheet will not be destroyed, and focus will be returned;\r
+\r
+ return PSNRET_NOERROR;\r
+ }\r
+\r
+ inline void CPropertyPage::OnCancel()\r
+ {\r
+ // This function is called for each page when the Cancel button is pressed\r
+ // Override this function in your derived class if required.\r
+ }\r
+\r
+ inline void CPropertyPage::OnHelp()\r
+ {\r
+ // This function is called in response to the PSN_HELP notification.\r
+ SendMessage(m_hWnd, WM_COMMAND, ID_HELP, 0L);\r
+ }\r
+\r
+ inline BOOL CPropertyPage::OnQueryCancel()\r
+ {\r
+ // Called when the cancel button is pressed, and before the cancel has taken place\r
+ // Returns TRUE to prevent the cancel operation, or FALSE to allow it.\r
+\r
+ return FALSE; // Allow cancel to proceed\r
+ }\r
+\r
+ inline BOOL CPropertyPage::OnQuerySiblings(WPARAM wParam, LPARAM lParam)\r
+ {\r
+ UNREFERENCED_PARAMETER(wParam);\r
+ UNREFERENCED_PARAMETER(lParam);\r
+\r
+ // Responds to a query request from the Property Sheet.\r
+ // The values for wParam and lParam are the ones set by\r
+ // the CPropertySheet::QuerySiblings call\r
+\r
+ // return FALSE to allow other siblings to be queried, or\r
+ // return TRUE to stop query at this page.\r
+\r
+ return FALSE;\r
+ }\r
+\r
+ inline BOOL CPropertyPage::OnInitDialog()\r
+ {\r
+ // Called when the property page is created\r
+ // Override this function in your derived class if required.\r
+\r
+ return TRUE; // Pass Keyboard control to handle in WPARAM\r
+ }\r
+\r
+ inline BOOL CPropertyPage::OnKillActive()\r
+ {\r
+ // This is called in response to a PSN_KILLACTIVE notification, which\r
+ // is sent whenever the OK or Apply button is pressed.\r
+ // It provides an opportunity to validate the page contents before it's closed.\r
+ // Return TRUE to prevent the page from losing the activation, or FALSE to allow it.\r
+\r
+ return FALSE;\r
+ }\r
+\r
+ inline int CPropertyPage::OnOK()\r
+ {\r
+ // Called for each page when the OK button is pressed\r
+ // Override this function in your derived class if required.\r
+\r
+ // The possible return values are:\r
+ // PSNRET_NOERROR. The changes made to this page are valid and have been applied\r
+ // PSNRET_INVALID. The property sheet will not be destroyed, and focus will be returned to this page.\r
+ // PSNRET_INVALID_NOCHANGEPAGE. The property sheet will not be destroyed, and focus will be returned;\r
+\r
+ return PSNRET_NOERROR;\r
+ }\r
+\r
+ inline LRESULT CPropertyPage::OnNotify(WPARAM wParam, LPARAM lParam)\r
+ {\r
+ UNREFERENCED_PARAMETER(wParam);\r
+\r
+ LPPSHNOTIFY pNotify = (LPPSHNOTIFY)lParam;\r
+ switch(pNotify->hdr.code)\r
+ {\r
+ case PSN_SETACTIVE:\r
+ return OnSetActive();\r
+ case PSN_KILLACTIVE:\r
+ return OnKillActive();\r
+ case PSN_APPLY:\r
+ if (pNotify->lParam)\r
+ return OnOK();\r
+ else\r
+ return OnApply();\r
+ case PSN_RESET:\r
+ OnCancel();\r
+ return FALSE;\r
+ case PSN_QUERYCANCEL:\r
+ return OnQueryCancel();\r
+ case PSN_WIZNEXT:\r
+ return OnWizardNext();\r
+ case PSN_WIZBACK:\r
+ return OnWizardBack();\r
+ case PSN_WIZFINISH:\r
+ return OnWizardFinish();\r
+ case PSN_HELP:\r
+ OnHelp();\r
+ return TRUE;\r
+ }\r
+ return FALSE;\r
+ }\r
+\r
+ inline int CPropertyPage::OnSetActive()\r
+ {\r
+ // Called when a page becomes active\r
+ // Override this function in your derived class if required.\r
+\r
+ // Returns zero to accept the activation, or -1 to activate the next or the previous page (depending\r
+ // on whether the user clicked the Next or Back button). To set the activation to a particular page,\r
+ // return the resource identifier of the page.\r
+\r
+ return 0;\r
+ }\r
+\r
+ inline int CPropertyPage::OnWizardBack()\r
+ {\r
+ // This function is called when the Back button is pressed on a wizard page\r
+ // Override this function in your derived class if required.\r
+\r
+ // Returns 0 to allow the wizard to go to the previous page. Returns -1 to prevent the wizard\r
+ // from changing pages. To display a particular page, return its dialog resource identifier.\r
+\r
+ return 0;\r
+ }\r
+\r
+ inline INT_PTR CPropertyPage::OnWizardFinish()\r
+ {\r
+ // This function is called when the Finish button is pressed on a wizard page\r
+ // Override this function in your derived class if required.\r
+\r
+ // Return Value:\r
+ // Return non-zero to prevent the wizard from finishing.\r
+ // Version 5.80. and later. Return a window handle to prevent the wizard from finishing. The wizard will set the focus to that window. The window must be owned by the wizard page.\r
+ // Return 0 to allow the wizard to finish.\r
+\r
+ return 0; // Allow wizard to finish\r
+ }\r
+\r
+ inline int CPropertyPage::OnWizardNext()\r
+ {\r
+ // This function is called when the Next button is pressed on a wizard page\r
+ // Override this function in your derived class if required.\r
+\r
+ // Return 0 to allow the wizard to go to the next page. Return -1 to prevent the wizard from\r
+ // changing pages. To display a particular page, return its dialog resource identifier.\r
+\r
+ return 0;\r
+ }\r
+\r
+ inline BOOL CPropertyPage::PreTranslateMessage(MSG* pMsg)\r
+ {\r
+ // allow the tab control to translate keyboard input\r
+ if (pMsg->message == WM_KEYDOWN && GetAsyncKeyState(VK_CONTROL) < 0 &&\r
+ (pMsg->wParam == VK_TAB || pMsg->wParam == VK_PRIOR || pMsg->wParam == VK_NEXT))\r
+ {\r
+ CWnd* pWndParent = GetParent();\r
+ if (pWndParent->SendMessage(PSM_ISDIALOGMESSAGE, 0L, (LPARAM)pMsg))\r
+ return TRUE;\r
+ }\r
+\r
+ // allow the dialog to translate keyboard input\r
+ if ((pMsg->message >= WM_KEYFIRST) && (pMsg->message <= WM_KEYLAST))\r
+ {\r
+ if (IsDialogMessage(pMsg))\r
+ return TRUE;\r
+ }\r
+\r
+ return CWnd::PreTranslateMessage(pMsg);\r
+ }\r
+\r
+ inline LRESULT CPropertyPage::QuerySiblings(WPARAM wParam, LPARAM lParam) const\r
+ {\r
+ // Sent to a property sheet, which then forwards the message to each of its pages.\r
+ // Set wParam and lParam to values you want passed to the property pages.\r
+ // Returns the nonzero value from a page in the property sheet, or zero if no page returns a nonzero value.\r
+\r
+ assert(::IsWindow(m_hWnd));\r
+ return GetParent()->SendMessage(PSM_QUERYSIBLINGS, wParam, lParam);\r
+ }\r
+\r
+ inline void CPropertyPage::SetModified(BOOL bChanged) const\r
+ {\r
+ // The property sheet will enable the Apply button if bChanged is TRUE.\r
+\r
+ assert(::IsWindow(m_hWnd));\r
+\r
+ if (bChanged)\r
+ GetParent()->SendMessage(PSM_CHANGED, (WPARAM)m_hWnd, 0L);\r
+ else\r
+ GetParent()->SendMessage(PSM_UNCHANGED, (WPARAM)m_hWnd, 0L);\r
+ }\r
+\r
+ inline void CPropertyPage::SetTitle(LPCTSTR szTitle)\r
+ {\r
+ if (szTitle)\r
+ {\r
+ m_Title = szTitle;\r
+ m_PSP.dwFlags |= PSP_USETITLE;\r
+ }\r
+ else\r
+ {\r
+ m_Title.Empty();\r
+ m_PSP.dwFlags &= ~PSP_USETITLE;\r
+ }\r
+\r
+ m_PSP.pszTitle = m_Title;\r
+ }\r
+\r
+ inline void CPropertyPage::SetWizardButtons(DWORD dwFlags) const\r
+ {\r
+ // dwFlags: A value that specifies which wizard buttons are enabled. You can combine one or more of the following flags.\r
+ // PSWIZB_BACK Enable the Back button. If this flag is not set, the Back button is displayed as disabled.\r
+ // PSWIZB_DISABLEDFINISH Display a disabled Finish button.\r
+ // PSWIZB_FINISH Display an enabled Finish button.\r
+ // PSWIZB_NEXT Enable the Next button. If this flag is not set, the Next button is displayed as disabled.\r
+\r
+ assert (::IsWindow(m_hWnd));\r
+ PropSheet_SetWizButtons(::GetParent(m_hWnd), dwFlags);\r
+ }\r
+\r
+ inline UINT CALLBACK CPropertyPage::StaticPropSheetPageProc(HWND hwnd, UINT uMsg, LPPROPSHEETPAGE ppsp)\r
+ {\r
+ assert( GetApp() );\r
+ UNREFERENCED_PARAMETER(hwnd);\r
+\r
+ // Note: the hwnd is always NULL\r
+\r
+ switch (uMsg)\r
+ {\r
+ case PSPCB_CREATE:\r
+ {\r
+ TLSData* pTLSData = (TLSData*)TlsGetValue(GetApp()->GetTlsIndex());\r
+ assert(pTLSData);\r
+\r
+ // Store the CPropertyPage pointer in Thread Local Storage\r
+ pTLSData->pCWnd = (CWnd*)ppsp->lParam;\r
+ }\r
+ break;\r
+ }\r
+\r
+ return TRUE;\r
+ }\r
+\r
+ inline INT_PTR CALLBACK CPropertyPage::StaticDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)\r
+ {\r
+ assert( GetApp() );\r
+\r
+ // Find matching CWnd pointer for this HWND\r
+ CPropertyPage* pPage = (CPropertyPage*)GetApp()->GetCWndFromMap(hwndDlg);\r
+ if (0 == pPage)\r
+ {\r
+ // matching CWnd pointer not found, so add it to HWNDMap now\r
+ TLSData* pTLSData = (TLSData*)TlsGetValue(GetApp()->GetTlsIndex());\r
+ pPage = (CPropertyPage*)pTLSData->pCWnd;\r
+\r
+ // Set the hWnd members and call DialogProc for this message\r
+ pPage->m_hWnd = hwndDlg;\r
+ pPage->AddToMap();\r
+ }\r
+\r
+ return pPage->DialogProc(uMsg, wParam, lParam);\r
+ }\r
+\r
+\r
+ ///////////////////////////////////////////\r
+ // Definitions for the CPropertySheet class\r
+ //\r
+ inline CPropertySheet::CPropertySheet(UINT nIDCaption, CWnd* pParent /* = NULL*/)\r
+ {\r
+ ZeroMemory(&m_PSH, sizeof (PROPSHEETHEADER));\r
+ SetTitle(LoadString(nIDCaption));\r
+ m_bInitialUpdate = FALSE;\r
+\r
+#ifdef _WIN32_WCE\r
+ m_PSH.dwSize = sizeof(PROPSHEETHEADER);\r
+#else\r
+ if (GetComCtlVersion() >= 471)\r
+ m_PSH.dwSize = sizeof(PROPSHEETHEADER);\r
+ else\r
+ m_PSH.dwSize = PROPSHEETHEADER_V1_SIZE;\r
+#endif\r
+\r
+ m_PSH.dwFlags = PSH_PROPSHEETPAGE | PSH_USECALLBACK;\r
+ m_PSH.hwndParent = pParent? pParent->GetHwnd() : 0;\r
+ m_PSH.hInstance = GetApp()->GetInstanceHandle();\r
+ m_PSH.pfnCallback = (PFNPROPSHEETCALLBACK)CPropertySheet::Callback;\r
+ }\r
+\r
+ inline CPropertySheet::CPropertySheet(LPCTSTR pszCaption /*= NULL*/, CWnd* pParent /* = NULL*/)\r
+ {\r
+ ZeroMemory(&m_PSH, sizeof (PROPSHEETHEADER));\r
+ SetTitle(pszCaption);\r
+ m_bInitialUpdate = FALSE;\r
+\r
+#ifdef _WIN32_WCE\r
+ m_PSH.dwSize = PROPSHEETHEADER_V1_SIZE;\r
+#else\r
+ if (GetComCtlVersion() >= 471)\r
+ m_PSH.dwSize = sizeof(PROPSHEETHEADER);\r
+ else\r
+ m_PSH.dwSize = PROPSHEETHEADER_V1_SIZE;\r
+#endif\r
+\r
+ m_PSH.dwFlags = PSH_PROPSHEETPAGE | PSH_USECALLBACK;\r
+ m_PSH.hwndParent = pParent? pParent->GetHwnd() : 0;;\r
+ m_PSH.hInstance = GetApp()->GetInstanceHandle();\r
+ m_PSH.pfnCallback = (PFNPROPSHEETCALLBACK)CPropertySheet::Callback;\r
+ }\r
+\r
+ inline CPropertyPage* CPropertySheet::AddPage(CPropertyPage* pPage)\r
+ // Adds a Property Page to the Property Sheet\r
+ {\r
+ assert(NULL != pPage);\r
+\r
+ m_vPages.push_back(PropertyPagePtr(pPage));\r
+\r
+ if (m_hWnd)\r
+ {\r
+ // property sheet already exists, so add page to it\r
+ PROPSHEETPAGE psp = pPage->GetPSP();\r
+ HPROPSHEETPAGE hpsp = ::CreatePropertySheetPage(&psp);\r
+ PropSheet_AddPage(m_hWnd, hpsp);\r
+ }\r
+\r
+ m_PSH.nPages = (int)m_vPages.size();\r
+\r
+ return pPage;\r
+ }\r
+\r
+ inline void CPropertySheet::BuildPageArray()\r
+ // Builds the PROPSHEETPAGE array\r
+ {\r
+ m_vPSP.clear();\r
+ std::vector<PropertyPagePtr>::iterator iter;\r
+ for (iter = m_vPages.begin(); iter < m_vPages.end(); ++iter)\r
+ m_vPSP.push_back((*iter)->GetPSP());\r
+\r
+ PROPSHEETPAGE* pPSPArray = &m_vPSP.front(); // Array of PROPSHEETPAGE\r
+ m_PSH.ppsp = pPSPArray;\r
+ }\r
+\r
+ inline void CALLBACK CPropertySheet::Callback(HWND hwnd, UINT uMsg, LPARAM lParam)\r
+ {\r
+ assert( GetApp() );\r
+\r
+ switch(uMsg)\r
+ {\r
+ //called before the dialog is created, hwnd = NULL, lParam points to dialog resource\r
+ case PSCB_PRECREATE:\r
+ {\r
+ LPDLGTEMPLATE lpTemplate = (LPDLGTEMPLATE)lParam;\r
+\r
+ if(!(lpTemplate->style & WS_SYSMENU))\r
+ {\r
+ lpTemplate->style |= WS_SYSMENU;\r
+ }\r
+ }\r
+ break;\r
+\r
+ //called after the dialog is created\r
+ case PSCB_INITIALIZED:\r
+ {\r
+ // Retrieve pointer to CWnd object from Thread Local Storage\r
+ TLSData* pTLSData = (TLSData*)TlsGetValue(GetApp()->GetTlsIndex());\r
+ assert(pTLSData);\r
+\r
+ CPropertySheet* w = (CPropertySheet*)pTLSData->pCWnd;\r
+ assert(w);\r
+\r
+ w->Attach(hwnd);\r
+ w->OnCreate();\r
+ }\r
+ break;\r
+ }\r
+ }\r
+\r
+\r
+ inline HWND CPropertySheet::Create(CWnd* pParent /*= 0*/)\r
+ // Creates a modeless Property Sheet\r
+ {\r
+ assert( GetApp() );\r
+\r
+ if (pParent)\r
+ {\r
+ m_PSH.hwndParent = pParent->GetHwnd();\r
+ }\r
+\r
+ BuildPageArray();\r
+ PROPSHEETPAGE* pPSPArray = &m_vPSP.front();\r
+ m_PSH.ppsp = pPSPArray;\r
+\r
+ // Create a modeless Property Sheet\r
+ m_PSH.dwFlags &= ~PSH_WIZARD;\r
+ m_PSH.dwFlags |= PSH_MODELESS;\r
+ HWND hWnd = (HWND)CreatePropertySheet(&m_PSH);\r
+\r
+ return hWnd;\r
+ }\r
+\r
+ inline INT_PTR CPropertySheet::CreatePropertySheet(LPCPROPSHEETHEADER ppsph)\r
+ {\r
+ assert( GetApp() );\r
+\r
+ INT_PTR ipResult = 0;\r
+\r
+ // Only one window per CWnd instance allowed\r
+ assert(!::IsWindow(m_hWnd));\r
+\r
+ // Ensure this thread has the TLS index set\r
+ TLSData* pTLSData = GetApp()->SetTlsIndex();\r
+\r
+ // Store the 'this' pointer in Thread Local Storage\r
+ pTLSData->pCWnd = this;\r
+\r
+ // Create the property sheet\r
+ ipResult = PropertySheet(ppsph);\r
+\r
+ return ipResult;\r
+ }\r
+\r
+ inline void CPropertySheet::DestroyButton(int IDButton)\r
+ {\r
+ assert(::IsWindow(m_hWnd));\r
+\r
+ HWND hwndButton = ::GetDlgItem(m_hWnd, IDButton);\r
+ if (hwndButton != NULL)\r
+ {\r
+ // Hide and disable the button\r
+ ::ShowWindow(hwndButton, SW_HIDE);\r
+ ::EnableWindow(hwndButton, FALSE);\r
+ }\r
+ }\r
+\r
+ inline void CPropertySheet::Destroy()\r
+ {\r
+ CWnd::Destroy();\r
+ m_vPages.clear();\r
+ }\r
+\r
+ inline int CPropertySheet::DoModal()\r
+ {\r
+ assert( GetApp() );\r
+\r
+ BuildPageArray();\r
+ PROPSHEETPAGE* pPSPArray = &m_vPSP.front();\r
+ m_PSH.ppsp = pPSPArray;\r
+\r
+ // Create the Property Sheet\r
+ int nResult = (int)CreatePropertySheet(&m_PSH);\r
+\r
+ m_vPages.clear();\r
+\r
+ return nResult;\r
+ }\r
+\r
+ inline CPropertyPage* CPropertySheet::GetActivePage() const\r
+ {\r
+ assert(::IsWindow(m_hWnd));\r
+\r
+ CPropertyPage* pPage = NULL;\r
+ if (m_hWnd != NULL)\r
+ {\r
+ HWND hPage = (HWND)SendMessage(PSM_GETCURRENTPAGEHWND, 0L, 0L);\r
+ pPage = (CPropertyPage*)FromHandle(hPage);\r
+ }\r
+\r
+ return pPage;\r
+ }\r
+\r
+ inline int CPropertySheet::GetPageCount() const\r
+ // Returns the number of Property Pages in this Property Sheet\r
+ {\r
+ assert(::IsWindow(m_hWnd));\r
+ return (int)m_vPages.size();\r
+ }\r
+\r
+ inline int CPropertySheet::GetPageIndex(CPropertyPage* pPage) const\r
+ {\r
+ assert(::IsWindow(m_hWnd));\r
+\r
+ for (int i = 0; i < GetPageCount(); i++)\r
+ {\r
+ if (m_vPages[i].get() == pPage)\r
+ return i;\r
+ }\r
+ return -1;\r
+ }\r
+\r
+ inline HWND CPropertySheet::GetTabControl() const\r
+ // Returns the handle to the Property Sheet's tab control\r
+ {\r
+ assert(::IsWindow(m_hWnd));\r
+ return (HWND)SendMessage(PSM_GETTABCONTROL, 0L, 0L);\r
+ }\r
+\r
+ inline BOOL CPropertySheet::IsModeless() const\r
+ {\r
+ return (m_PSH.dwFlags & PSH_MODELESS);\r
+ }\r
+\r
+ inline BOOL CPropertySheet::IsWizard() const\r
+ {\r
+ return (m_PSH.dwFlags & PSH_WIZARD);\r
+ }\r
+\r
+ inline void CPropertySheet::RemovePage(CPropertyPage* pPage)\r
+ // Removes a Property Page from the Property Sheet\r
+ {\r
+ assert(::IsWindow(m_hWnd));\r
+\r
+ int nPage = GetPageIndex(pPage);\r
+ if (m_hWnd != NULL)\r
+ SendMessage(m_hWnd, PSM_REMOVEPAGE, nPage, 0L);\r
+\r
+ m_vPages.erase(m_vPages.begin() + nPage, m_vPages.begin() + nPage+1);\r
+ m_PSH.nPages = (int)m_vPages.size();\r
+ }\r
+\r
+ inline BOOL CPropertySheet::PreTranslateMessage(MSG* pMsg)\r
+ {\r
+ // allow sheet to translate Ctrl+Tab, Shift+Ctrl+Tab, Ctrl+PageUp, and Ctrl+PageDown\r
+ if (pMsg->message == WM_KEYDOWN && GetAsyncKeyState(VK_CONTROL) < 0 &&\r
+ (pMsg->wParam == VK_TAB || pMsg->wParam == VK_PRIOR || pMsg->wParam == VK_NEXT))\r
+ {\r
+ if (SendMessage(PSM_ISDIALOGMESSAGE, 0L, (LPARAM)pMsg))\r
+ return TRUE;\r
+ }\r
+\r
+ // allow the dialog to translate keyboard input\r
+ if ((pMsg->message >= WM_KEYFIRST) && (pMsg->message <= WM_KEYLAST))\r
+ {\r
+ return GetActivePage()->PreTranslateMessage(pMsg);\r
+ }\r
+\r
+ return CWnd::PreTranslateMessage(pMsg);\r
+ }\r
+\r
+ inline BOOL CPropertySheet::SetActivePage(int nPage)\r
+ {\r
+ assert(::IsWindow(m_hWnd));\r
+ return (BOOL)SendMessage(m_hWnd, PSM_SETCURSEL, nPage, 0L);\r
+ }\r
+\r
+ inline BOOL CPropertySheet::SetActivePage(CPropertyPage* pPage)\r
+ {\r
+ assert(::IsWindow(m_hWnd));\r
+ int nPage = GetPageIndex(pPage);\r
+ if ((nPage >= 0))\r
+ return SetActivePage(nPage);\r
+\r
+ return FALSE;\r
+ }\r
+\r
+ inline void CPropertySheet::SetIcon(UINT idIcon)\r
+ {\r
+ m_PSH.pszIcon = MAKEINTRESOURCE(idIcon);\r
+ m_PSH.dwFlags |= PSH_USEICONID;\r
+ }\r
+\r
+ inline void CPropertySheet::SetTitle(LPCTSTR szTitle)\r
+ {\r
+ if (szTitle)\r
+ m_Title = szTitle;\r
+ else\r
+ m_Title.Empty();\r
+\r
+ m_PSH.pszCaption = m_Title;\r
+ }\r
+\r
+ inline void CPropertySheet::SetWizardMode(BOOL bWizard)\r
+ {\r
+ if (bWizard)\r
+ m_PSH.dwFlags |= PSH_WIZARD;\r
+ else\r
+ m_PSH.dwFlags &= ~PSH_WIZARD;\r
+ }\r
+\r
+ inline LRESULT CPropertySheet::WndProcDefault(UINT uMsg, WPARAM wParam, LPARAM lParam)\r
+ {\r
+ switch (uMsg)\r
+ {\r
+\r
+ case WM_WINDOWPOSCHANGED:\r
+ {\r
+ LPWINDOWPOS lpWinPos = (LPWINDOWPOS)lParam;\r
+ if (lpWinPos->flags & SWP_SHOWWINDOW)\r
+ {\r
+ if (!m_bInitialUpdate)\r
+ // The first window positioning with the window visible\r
+ OnInitialUpdate();\r
+ m_bInitialUpdate = TRUE;\r
+ }\r
+ }\r
+ break;\r
+\r
+ case WM_DESTROY:\r
+ m_bInitialUpdate = FALSE;\r
+ break;\r
+\r
+ case WM_SYSCOMMAND:\r
+ if ((SC_CLOSE == wParam) && (m_PSH.dwFlags & PSH_MODELESS))\r
+ {\r
+ Destroy();\r
+ return 0L;\r
+ }\r
+ break;\r
+ }\r
+\r
+ // pass unhandled messages on for default processing\r
+ return CWnd::WndProcDefault(uMsg, wParam, lParam);\r
+ }\r
+\r
+}\r
+\r
+#endif // _WIN32XX_PROPERTYSHEET_H_\r