/**********************************************************************/ /** Microsoft Windows/NT **/ /** Copyright(c) Microsoft Corporation, 1997 - 1999 **/ /**********************************************************************/ /* proppage.cpp Implementation for property pages in MMC FILE HISTORY: */ #include "stdafx.h" #include "dialog.h" // for FixupIpAddressHelp #include #ifdef DEBUG_ALLOCATOR #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #endif ////////////////////////////////////////////////////////////////////////// // private helper functions BOOL CALLBACK EnumThreadWndProc(HWND hwnd, /* enumerated HWND */ LPARAM lParam /* pass a HWND* for return value*/ ) { Assert(hwnd); HWND hParentWnd = GetParent(hwnd); // the main window of the MMC console should staitsfy this condition if ( ((hParentWnd == GetDesktopWindow()) || (hParentWnd == NULL)) && IsWindowVisible(hwnd) ) { HWND* pH = (HWND*)lParam; *pH = hwnd; return FALSE; // stop enumerating } else if(hParentWnd) { HWND hGrandParentWnd = GetParent(hParentWnd); // the main window of the MMC console should staitsfy this condition if ( ((hGrandParentWnd == GetDesktopWindow()) || (hGrandParentWnd == NULL)) && IsWindowVisible(hParentWnd) ) { HWND* pH = (HWND*)lParam; *pH = hParentWnd; return FALSE; // stop enumerating } } return TRUE; } HWND FindMMCMainWindow() { DWORD dwThreadID = ::GetCurrentThreadId(); Assert(dwThreadID != 0); HWND hWnd = NULL; BOOL bEnum = EnumThreadWindows(dwThreadID, EnumThreadWndProc,(LPARAM)&hWnd); Assert(hWnd != NULL); return hWnd; } ///////////////////////////////////////////////////////////////////////////// // CPropertyPageHolderBase CPropertyPageHolderBase::CPropertyPageHolderBase ( ITFSNode * pNode, IComponentData *pComponentData, LPCTSTR pszSheetName, BOOL bIsScopePane ) { m_stSheetTitle = pszSheetName; // default setting for a self deleting modeless property sheet, // automatically deleting all the pages m_bWizardMode = TRUE; m_bAutoDelete = TRUE; m_bAutoDeletePages = TRUE; m_nCreatedCount = 0; m_hSheetWindow = NULL; m_hConsoleHandle = 0; m_hEventHandle = NULL; m_bCalledFromConsole = FALSE; m_cDirty = 0; // setup from arguments SetNode(pNode); //Assert(pComponentData != NULL); m_spComponentData.Set(pComponentData); m_pPropChangePage = NULL; m_dwLastErr = 0; m_bSheetPosSet = FALSE; m_bIsScopePane = bIsScopePane; m_hThread = NULL; m_bWiz97 = FALSE; // by WeiJiang 5/11/98, PeekMessageDuringNotifyConsole flag m_bPeekMessageDuringNotifyConsole = FALSE; m_fSetDefaultSheetPos = TRUE; } CPropertyPageHolderBase::CPropertyPageHolderBase ( ITFSNode * pNode, IComponent * pComponent, LPCTSTR pszSheetName, BOOL bIsScopePane ) { m_stSheetTitle = pszSheetName; // default setting for a self deleting modeless property sheet, // automatically deleting all the pages m_bWizardMode = TRUE; m_bAutoDelete = TRUE; m_bAutoDeletePages = TRUE; m_nCreatedCount = 0; m_hSheetWindow = NULL; m_hConsoleHandle = 0; m_hEventHandle = NULL; m_bCalledFromConsole = FALSE; m_cDirty = 0; // setup from arguments SetNode(pNode); m_spComponent.Set(pComponent); m_pPropChangePage = NULL; m_dwLastErr = 0; m_bSheetPosSet = FALSE; m_bIsScopePane = bIsScopePane; m_hThread = NULL; m_bWiz97 = FALSE; // by WeiJiang 5/11/98, PeekMessageDuringNotifyConsole flag m_bPeekMessageDuringNotifyConsole = FALSE; } CPropertyPageHolderBase::~CPropertyPageHolderBase() { // Remove this assert, we could be dirty if we cancelled the page // Assert(m_cDirty == 0); FinalDestruct(); m_spSheetCallback.Release(); if (m_hEventHandle != NULL) { VERIFY(::CloseHandle(m_hEventHandle)); m_hEventHandle = NULL; } } HRESULT CPropertyPageHolderBase::CreateModelessSheet ( LPPROPERTYSHEETCALLBACK pSheetCallback, LONG_PTR hConsoleHandle ) { Assert(pSheetCallback != NULL); Assert(m_spSheetCallback == NULL); Assert( (hConsoleHandle != NULL) && (m_hConsoleHandle == NULL) ); m_hConsoleHandle = hConsoleHandle; m_bCalledFromConsole = TRUE; m_bWizardMode = FALSE; // we go modeless // notify the node it has a sheet up int nMessage = m_bIsScopePane ? TFS_NOTIFY_CREATEPROPSHEET : TFS_NOTIFY_RESULT_CREATEPROPSHEET; if (m_spNode) m_spNode->Notify(nMessage, (LPARAM) this); // temporarily attach the sheet callback to this object to add pages // do not addref, we will not hold on to it; m_spSheetCallback = pSheetCallback; HRESULT hr = AddAllPagesToSheet(); m_spSheetCallback.Transfer(); // detach return hr; } HRESULT CPropertyPageHolderBase::DoModelessSheet() { AFX_MANAGE_STATE(AfxGetStaticModuleState()); SPIPropertySheetProvider spSheetProvider; SPIPropertySheetCallback spSheetCallback; SPIConsole spConsole; SPIDataObject spDataObject; MMC_COOKIE cookie; HRESULT hr = hrOK; HWND hWnd; int nMessage; m_bWizardMode = FALSE; // get an interface to a sheet provider CORg (::CoCreateInstance(CLSID_NodeManager, NULL, CLSCTX_INPROC, IID_IPropertySheetProvider, reinterpret_cast(&spSheetProvider))); Assert(spSheetProvider != NULL); // get an interface to a sheet callback CORg( spSheetCallback.HrQuery(spSheetProvider) ); Assert(spSheetCallback != NULL); m_spSheetCallback.Set(spSheetCallback); // save to add/remove pages // create a data object for this node cookie = m_spNode->GetData(TFS_DATA_COOKIE); if (m_bIsScopePane) { CORg( m_spComponentData->QueryDataObject(cookie, CCT_SCOPE, &spDataObject) ); Assert(spDataObject != NULL); } else { CORg( m_spComponent->QueryDataObject(cookie, CCT_RESULT, &spDataObject) ); Assert(spDataObject != NULL); } // create sheet // CODEWORK: ericdav -- need to possible set options flag -- 0 for now CORg( spSheetProvider->CreatePropertySheet(m_stSheetTitle, TRUE /* prop page */, cookie, spDataObject, 0) ); // add pages to sheet CORg( AddAllPagesToSheet() ); // add pages // HRESULT AddPrimaryPages(LPUNKNOWN lpUnknown, BOOL bCreateHandle, // HWND hNotifyWindow, BOOL bScopePane); if (m_bIsScopePane) { //Assert(m_spComponentData != NULL); CORg( spSheetProvider->AddPrimaryPages(NULL, FALSE, NULL, TRUE) ); } else { //Assert(m_spComponent != NULL); CORg( spSheetProvider->AddPrimaryPages(NULL, FALSE, NULL, FALSE) ); } spSheetProvider->AddExtensionPages(); // for further dynamic page manipulation, don't use the Console's // sheet callback interface but resurt to the Win32 API's m_spSheetCallback.Release(); hWnd = ::FindMMCMainWindow(); Assert(hWnd != NULL); CORg( spSheetProvider->Show((LONG_PTR) hWnd, 0) ); // notify the node it has a sheet up nMessage = m_bIsScopePane ? TFS_NOTIFY_CREATEPROPSHEET : TFS_NOTIFY_RESULT_CREATEPROPSHEET; m_spNode->Notify(nMessage, (LPARAM) this); Error: return hr; } // use this function for property pages on the scope pane HRESULT DoPropertiesOurselvesSinceMMCSucks(ITFSNode * pNode, IComponentData * pComponentData, LPCTSTR pszSheetTitle) { Assert(pComponentData != NULL); AFX_MANAGE_STATE(AfxGetStaticModuleState()); SPIPropertySheetProvider spSheetProvider; SPIDataObject spDataObject; MMC_COOKIE cookie; HRESULT hr = hrOK; HWND hWnd = NULL; // get an interface to a sheet provider CORg (::CoCreateInstance(CLSID_NodeManager, NULL, CLSCTX_INPROC, IID_IPropertySheetProvider, reinterpret_cast(&spSheetProvider))); Assert(spSheetProvider != NULL); // create a data object for this node cookie = pNode->GetData(TFS_DATA_COOKIE); CORg( pComponentData->QueryDataObject(cookie, CCT_SCOPE, &spDataObject) ); Assert(spDataObject != NULL); // create sheet // CODEWORK: ericdav -- need to possible set options flag -- 0 for now CORg( spSheetProvider->CreatePropertySheet(pszSheetTitle, TRUE /* prop page */, cookie, spDataObject, 0) ); // add pages // HRESULT AddPrimaryPages(LPUNKNOWN lpUnknown, BOOL bCreateHandle, // HWND hNotifyWindow, BOOL bScopePane); // This needs to be fixed. Right now it only works if there is // one view of the snapin. // // As of 5/21/99, we no longer need to do this. // ---------------------------------------------------------------- // hWnd = ::FindMMCMainWindow(); // hWnd = ::FindWindowEx(hWnd, NULL, L"MDIClient", NULL); // hWnd = ::FindWindowEx(hWnd, NULL, L"MMCChildFrm", NULL); // hWnd = ::FindWindowEx(hWnd, NULL, L"MMCView", NULL); // Assert(hWnd != NULL); CORg( spSheetProvider->AddPrimaryPages(pComponentData, TRUE, hWnd, TRUE) ); spSheetProvider->AddExtensionPages(); CORg( spSheetProvider->Show((LONG_PTR) hWnd, 0) ); Error: return hr; } // Use this function for property pages on the result pane HRESULT DoPropertiesOurselvesSinceMMCSucks(ITFSNode * pNode, IComponent * pComponent, LPCTSTR pszSheetTitle, int nVirtualIndex) { Assert(pComponent != NULL); AFX_MANAGE_STATE(AfxGetStaticModuleState()); SPIPropertySheetProvider spSheetProvider; SPIDataObject spDataObject; MMC_COOKIE cookie; HRESULT hr = hrOK; HWND hWnd; // get an interface to a sheet provider CORg (::CoCreateInstance(CLSID_NodeManager, NULL, CLSCTX_INPROC, IID_IPropertySheetProvider, reinterpret_cast(&spSheetProvider))); Assert(spSheetProvider != NULL); // create a data object for this node if (nVirtualIndex == -1) { cookie = pNode->GetData(TFS_DATA_COOKIE); } else { cookie = nVirtualIndex; } CORg( pComponent->QueryDataObject(cookie, CCT_RESULT, &spDataObject) ); Assert(spDataObject != NULL); // create sheet // CODEWORK: ericdav -- need to possible set options flag -- 0 for now CORg( spSheetProvider->CreatePropertySheet(pszSheetTitle, TRUE /* prop page */, cookie, spDataObject, 0) ); // add pages // HRESULT AddPrimaryPages(LPUNKNOWN lpUnknown, BOOL bCreateHandle, // HWND hNotifyWindow, BOOL bScopePane); // This needs to be fixed. Right now it only works if there is // one view of the snapin. hWnd = ::FindMMCMainWindow(); hWnd = ::FindWindowEx(hWnd, NULL, L"MDIClient", NULL); hWnd = ::FindWindowEx(hWnd, NULL, L"MMCChildFrm", NULL); hWnd = ::FindWindowEx(hWnd, NULL, L"MMCView", NULL); Assert(hWnd != NULL); CORg( spSheetProvider->AddPrimaryPages(pComponent, TRUE, hWnd, FALSE) ); spSheetProvider->AddExtensionPages(); CORg( spSheetProvider->Show((LONG_PTR) hWnd, 0) ); Error: return hr; } HRESULT CPropertyPageHolderBase::DoModalWizard() { Assert(m_spComponentData != NULL); AFX_MANAGE_STATE(AfxGetStaticModuleState()); SPIPropertySheetProvider spSheetProvider; SPITFSComponentData spTFSCompData; SPIConsole spConsole; SPIPropertySheetCallback spSheetCallback; SPIDataObject spDataObject; HRESULT hr = hrOK; HWND hWnd; MMC_COOKIE cookie; DWORD dwOptions = 0; m_bWizardMode = TRUE; CORg( spTFSCompData.HrQuery(m_spComponentData) ); CORg( spTFSCompData->GetConsole(&spConsole) ); // get an interface to a sheet provider CORg( spSheetProvider.HrQuery(spConsole) ); Assert(spSheetProvider != NULL); // get an interface to a sheet callback CORg( spSheetCallback.HrQuery(spConsole) ); Assert(spSheetCallback != NULL); m_spSheetCallback.Set(spSheetCallback); // save to add/remove pages // create a data object for this node cookie = m_spNode->GetData(TFS_DATA_COOKIE); // Create a dummy data object. AddPrimaryPages will call // IextendPropertySheet2::QueryPagesFor() and // IextendPropertySheet2::CreatePropertyPages() // that will ignore the un-initialized data object CORg( m_spComponentData->QueryDataObject(-1, CCT_UNINITIALIZED, &spDataObject) ); Assert(spDataObject != NULL); // create sheet dwOptions = (m_bWiz97) ? MMC_PSO_NEWWIZARDTYPE : 0; dwOptions &= ~PSH_WIZARDCONTEXTHELP; CORg( spSheetProvider->CreatePropertySheet( m_stSheetTitle, FALSE /* wizard*/, cookie, spDataObject, dwOptions) ); // add pages to sheet CORg( AddAllPagesToSheet() ); // add pages // HRESULT AddPrimaryPages(LPUNKNOWN lpUnknown, BOOL bCreateHandle, HWND hNotifyWindow, BOOL bScopePane); if (m_bWiz97) CORg( spSheetProvider->AddPrimaryPages(spTFSCompData, FALSE, NULL, FALSE) ); else CORg( spSheetProvider->AddPrimaryPages(NULL, FALSE, NULL, FALSE) ); // for further dynamic page manipulation, don't use the Console's sheet callback interface // but resurt to the Win32 API's m_spSheetCallback.Release(); //hWnd = ::FindMMCMainWindow(); // To Support scripting of the MMC console, we need to get the parent from either the // active window or the desktop... hWnd = ::GetActiveWindow(); if (hWnd == NULL) { hWnd = GetDesktopWindow(); } Assert(hWnd != NULL); CORg( spSheetProvider->Show((LONG_PTR)hWnd, 0) ); Error: return hr; } void CPropertyPageHolderBase::SetSheetWindow ( HWND hSheetWindow ) { Assert(hSheetWindow != NULL); Assert( (m_hSheetWindow == NULL) || ((m_hSheetWindow == hSheetWindow)) ); m_hSheetWindow = hSheetWindow; if (!m_hThread) { HANDLE hPseudohandle; hPseudohandle = GetCurrentThread(); BOOL bRet = DuplicateHandle(GetCurrentProcess(), hPseudohandle, GetCurrentProcess(), &m_hThread, 0, FALSE, DUPLICATE_SAME_ACCESS); if (!bRet) { DWORD dwLastErr = GetLastError(); } Trace1("PROPERTY PAGE HOLDER BASE - Thread ID = %lx\n", GetCurrentThreadId()); } if (m_hSheetWindow && m_fSetDefaultSheetPos) SetDefaultSheetPos(); // turn of context sensitive help in the wizard... for some reason // mmc turns it on and we don't want it if (m_bWizardMode && m_hSheetWindow) { CWnd * pWnd = CWnd::FromHandle(m_hSheetWindow); if (pWnd) pWnd->ModifyStyleEx(WS_EX_CONTEXTHELP, 0, 0); } } BOOL CPropertyPageHolderBase::SetDefaultSheetPos() { HRESULT hr = hrOK; HWND hwndMMC; RECT rectSheet, rectMMC, rectWorkArea; SPITFSComponentData spTFSCompData; SPITFSComponent spTFSComponent; SPIConsole spConsole; int nX, nY; if (m_bSheetPosSet) return TRUE; if (m_bIsScopePane) { CORg( spTFSCompData.HrQuery(m_spComponentData) ); Assert(spTFSCompData); CORg( spTFSCompData->GetConsole(&spConsole) ); } else { CORg( spTFSComponent.HrQuery(m_spComponent) ); Assert(spTFSComponent); CORg( spTFSComponent->GetConsole(&spConsole) ); } spConsole->GetMainWindow(&hwndMMC); // get the MMC window and the PropSheet if (!GetWindowRect(hwndMMC, &rectMMC)) return FALSE; if (!GetWindowRect(m_hSheetWindow, &rectSheet)) return FALSE; nX = rectMMC.left + (((rectMMC.right - rectMMC.left) - (rectSheet.right - rectSheet.left)) / 2); nY = rectMMC.top + (((rectMMC.bottom - rectMMC.top) - (rectSheet.bottom - rectSheet.top)) / 2); // now check to make sure we're visible SystemParametersInfo(SPI_GETWORKAREA, 0, &rectWorkArea, 0); nX = (nX < 0) ? 1 : nX; nY = (nY < 0) ? 1 : nY; nX = (nX > (rectWorkArea.right - (rectSheet.right - rectSheet.left))) ? (rectWorkArea.right - (rectSheet.right - rectSheet.left)) : nX; nY = (nY > (rectWorkArea.bottom - (rectSheet.bottom - rectSheet.top))) ? (rectWorkArea.bottom - (rectSheet.bottom - rectSheet.top)) : nY; if (!SetWindowPos(m_hSheetWindow, HWND_TOP, nX, nY, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW)) return FALSE; m_bSheetPosSet = TRUE; Error: return hr == hrOK; } void CPropertyPageHolderBase::Release() { m_nCreatedCount--; if ( m_bAutoDelete && (m_nCreatedCount == 0) ) delete this; } void CPropertyPageHolderBase::ForceDestroy() { Assert(!m_bWizardMode); // should never occur on modal wizard Assert(m_bAutoDelete); // should be self deleting sheet Assert(::IsWindow(m_hSheetWindow)); HWND hSheetWindow = m_hSheetWindow; if (hSheetWindow != NULL) { // this message will cause the sheet to close all the pages, // and eventually the destruction of "this" VERIFY(::PostMessage(hSheetWindow, WM_COMMAND, IDCANCEL, 0L) != 0); //VERIFY(::SendMessage(hSheetWindow, WM_CLOSE, 0, 0) == 0); } else { // explicitely delete "this", there is no sheet created delete this; return; } // now, if we've been initialized then wait for the property sheet thread // to terminate. The property sheet provider is holding onto our dataobject // that needs to be freed up before we can continue our cleanup. Also, // the cleanup does a sendmessage which will block if we don't forward // messages along. if (m_hThread) { DWORD dwRet; MSG msg; while(1) { dwRet = MsgWaitForMultipleObjects(1, &m_hThread, FALSE, INFINITE, QS_ALLINPUT); if (dwRet == WAIT_OBJECT_0) return; // The event was signaled if (dwRet != WAIT_OBJECT_0 + 1) break; // Something else happened // There is one or more window message available. Dispatch them while(PeekMessage(&msg,NULL,NULL,NULL,PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); if (WaitForSingleObject(m_hThread, 0) == WAIT_OBJECT_0) return; // Event is now signaled. } } } } DWORD CPropertyPageHolderBase::NotifyConsole(CPropertyPageBase* pPage) { MSG msg; Assert(m_spNode != NULL); if (m_bWizardMode) { Assert(m_hConsoleHandle == NULL); return 0; } m_pPropChangePage = pPage; // to pass to the main thread m_dwLastErr = 0x0; Assert(m_hConsoleHandle != NULL); if (m_hEventHandle == NULL) { m_hEventHandle = ::CreateEvent(NULL,TRUE /*bManualReset*/,FALSE /*signalled*/, NULL); Assert(m_hEventHandle != NULL); } MMCPropertyChangeNotify(m_hConsoleHandle, reinterpret_cast(this)); Trace0("before wait\n"); while ( WAIT_OBJECT_0 != ::WaitForSingleObject(m_hEventHandle, 500) ) { // by WeiJiang 5/11/98, PeekMessageDuringNotifyConsole flag if(m_bPeekMessageDuringNotifyConsole) { // clean out the message queue while we wait while (PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } } } Trace0("after wait\n"); VERIFY(0 != ::ResetEvent(m_hEventHandle)); return m_dwLastErr; } void CPropertyPageHolderBase::AcknowledgeNotify() { Assert(!m_bWizardMode); Assert(m_hEventHandle != NULL); Trace0("before SetEvent\n"); VERIFY(0 != ::SetEvent(m_hEventHandle)); Trace0("after SetEvent\n"); } BOOL CPropertyPageHolderBase::SetWizardButtons ( DWORD dwFlags ) { Assert(m_bWizardMode); Assert(::IsWindow(m_hSheetWindow)); return (BOOL)SendMessage(m_hSheetWindow, PSM_SETWIZBUTTONS, 0, dwFlags); } BOOL CPropertyPageHolderBase::PressButton ( int nButton ) { Assert(m_bWizardMode); Assert(::IsWindow(m_hSheetWindow)); return (BOOL) SendMessage(m_hSheetWindow, PSM_PRESSBUTTON, nButton, 0); } HRESULT CPropertyPageHolderBase::AddPageToSheet ( CPropertyPageBase* pPage ) { // remove the help button if (m_bWiz97) pPage->m_psp97.dwFlags &= ~PSP_HASHELP; else pPage->m_psp.dwFlags &= ~PSP_HASHELP; // call the MMC function because we are using MFC based pages if (!m_bWizardMode) { // if we are doing a property sheet then tell MMC to hook // the proc because we are running on a separate, non MFC thread. // Wizards don't run on a separate thread and therefore // don't need to make this call. if (m_bWiz97) VERIFY(SUCCEEDED(MMCPropPageCallback(&pPage->m_psp97))); else VERIFY(SUCCEEDED(MMCPropPageCallback(&pPage->m_psp))); } HPROPSHEETPAGE hPage; if (m_bWiz97) hPage = ::CreatePropertySheetPage(&pPage->m_psp97); else hPage = ::CreatePropertySheetPage(&pPage->m_psp); if (hPage == NULL) return E_UNEXPECTED; pPage->m_hPage = hPage; if (m_spSheetCallback != NULL) return m_spSheetCallback->AddPage(hPage); else { Assert(::IsWindow(m_hSheetWindow)); return PropSheet_AddPage(m_hSheetWindow, hPage) ? S_OK : E_FAIL; } } HRESULT CPropertyPageHolderBase::RemovePageFromSheet ( CPropertyPageBase* pPage ) { Assert(pPage->m_hPage != NULL); if (m_spSheetCallback != NULL) return m_spSheetCallback->RemovePage(pPage->m_hPage); else { Assert(::IsWindow(m_hSheetWindow)); return PropSheet_RemovePage(m_hSheetWindow, 0, pPage->m_hPage) ? S_OK : E_FAIL; } } HRESULT CPropertyPageHolderBase::AddAllPagesToSheet() { POSITION pos; for( pos = m_pageList.GetHeadPosition(); pos != NULL; ) { CPropertyPageBase* pPropPage = m_pageList.GetNext(pos); HRESULT hr = AddPageToSheet(pPropPage); Assert(SUCCEEDED(hr)); if (FAILED(hr)) return hr; } return S_OK; } void CPropertyPageHolderBase::AddPageToList ( CPropertyPageBase* pPage ) { Assert(pPage != NULL); pPage->SetHolder(this); m_pageList.AddTail(pPage); } BOOL CPropertyPageHolderBase::RemovePageFromList ( CPropertyPageBase* pPage, BOOL bDeleteObject ) { Assert(pPage != NULL); POSITION pos = m_pageList.Find(pPage); if (pos == NULL) return FALSE; m_pageList.RemoveAt(pos); if (bDeleteObject) delete pPage; return TRUE; } void CPropertyPageHolderBase::DeleteAllPages() { if (!m_bAutoDeletePages) return; // assume all pages out of the heap while (!m_pageList.IsEmpty()) { delete m_pageList.RemoveTail(); } } void CPropertyPageHolderBase::FinalDestruct() { DeleteAllPages(); if (m_bWizardMode) return; // if we were a modeless sheet, have to cleanup if (m_bCalledFromConsole) { Assert(m_hConsoleHandle != NULL); MMCFreeNotifyHandle(m_hConsoleHandle); } // Notify the node that this sheet is going away // int nMessage = m_bIsScopePane ? TFS_NOTIFY_DELETEPROPSHEET : TFS_NOTIFY_RESULT_DELETEPROPSHEET; if (m_spNode) { m_spNode->Notify(nMessage, (LPARAM) this); } } HWND CPropertyPageHolderBase::SetActiveWindow() { return ::SetActiveWindow(m_hSheetWindow); } BOOL CPropertyPageHolderBase::OnPropertyChange(BOOL bScopePane, LONG_PTR * pChangeMask) { ASSERT(!IsWizardMode()); CPropertyPageBase* pPage = GetPropChangePage(); if (pPage == NULL) return FALSE; return pPage->OnPropertyChange(bScopePane, pChangeMask); } ///////////////////////////////////////////////////////////////////////////// // CPropertyPageBase IMPLEMENT_DYNCREATE(CPropertyPageBase, CPropertyPage) BEGIN_MESSAGE_MAP(CPropertyPageBase, CPropertyPage) ON_WM_CREATE() ON_WM_DESTROY() // help overrides ON_WM_HELPINFO() ON_WM_CONTEXTMENU() END_MESSAGE_MAP() CPropertyPageBase::CPropertyPageBase ( UINT nIDTemplate, UINT nIDCaption ) : CPropertyPage(nIDTemplate, nIDCaption) { m_hPage = NULL; m_pPageHolder = NULL; m_bIsDirty = FALSE; } CPropertyPageBase::~CPropertyPageBase() { } int CPropertyPageBase::OnCreate ( LPCREATESTRUCT lpCreateStruct ) { if (m_pPageHolder) m_pPageHolder->AddRef(); int res = CPropertyPage::OnCreate(lpCreateStruct); Assert(res == 0); Assert(m_hWnd != NULL); Assert(::IsWindow(m_hWnd)); HWND hParent = ::GetParent(m_hWnd); Assert(hParent); if (m_pPageHolder) m_pPageHolder->SetSheetWindow(hParent); return res; } void CPropertyPageBase::OnDestroy() { Assert(m_hWnd != NULL); CPropertyPage::OnDestroy(); if (m_pPageHolder) m_pPageHolder->Release(); } BOOL CPropertyPageBase::OnApply() { if (IsDirty()) { if (!m_pPageHolder || m_pPageHolder->NotifyConsole(this) == 0x0) { SetDirty(FALSE); return TRUE; } else { return FALSE; } } return TRUE; } void CPropertyPageBase::CancelApply() { if (m_pPageHolder) m_pPageHolder->NotifyConsole(this); } // NOTE: This function must be called for all wizard 97 pages. // Since there are different sizes of the psp struct, depending // on how the project was compiled (common lib is compiled with // the wiz97 propsheet header and the snapin directory may not) // this function should only be called when running wizard 97 pages. // This allows us to have snapins that use the same code for both // old and new style wizards. void CPropertyPageBase::InitWiz97(BOOL bHideHeader, UINT nIDHeaderTitle, UINT nIDHeaderSubTitle) { // hack to have new struct size with old MFC and new NT 5.0 headers ZeroMemory(&m_psp97, sizeof(PROPSHEETPAGE)); memcpy(&m_psp97, &m_psp, m_psp.dwSize); m_psp97.dwSize = sizeof(PROPSHEETPAGE); if (bHideHeader) { // for first and last page of the wizard m_psp97.dwFlags |= PSP_HIDEHEADER; } else { // for intermediate pages AFX_MANAGE_STATE(AfxGetStaticModuleState()); m_szHeaderTitle.LoadString(nIDHeaderTitle); m_szHeaderSubTitle.LoadString(nIDHeaderSubTitle); m_psp97.dwFlags |= PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE; m_psp97.pszHeaderTitle = (LPCTSTR)m_szHeaderTitle; m_psp97.pszHeaderSubTitle = (LPCTSTR)m_szHeaderSubTitle; } } /*!-------------------------------------------------------------------------- CPropertyPageBase::OnHelpInfo Brings up the context-sensitive help for the controls. Author: EricDav ---------------------------------------------------------------------------*/ BOOL CPropertyPageBase::OnHelpInfo(HELPINFO* pHelpInfo) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); int i; DWORD dwCtrlId; if (pHelpInfo->iContextType == HELPINFO_WINDOW) { DWORD * pdwHelp = GetHelpMapInternal(); if (pdwHelp) { // Ok to fix the f**king help for the f**king IP address // controls, we will need to add special case code. If we // can't find the id of our control in our list, then we look // to see if this is the child of the "RtrIpAddress" control, if // so then we change the pHelpInfo->hItemHandle to point to the // handle of the ip address control rather than the control in // the ip addrss control. *SIGH* dwCtrlId = ::GetDlgCtrlID((HWND) pHelpInfo->hItemHandle); for (i=0; pdwHelp[i]; i+=2) { if (pdwHelp[i] == dwCtrlId) break; } if (pdwHelp[i] == 0) { // Ok, we didn't find the control in our list, so let's // check to see if it's part of the IP address control. pHelpInfo->hItemHandle = FixupIpAddressHelp((HWND) pHelpInfo->hItemHandle); } ::WinHelp ((HWND)pHelpInfo->hItemHandle, AfxGetApp()->m_pszHelpFilePath, HELP_WM_HELP, (ULONG_PTR)pdwHelp); } } return TRUE; } /*!-------------------------------------------------------------------------- CBaseDialog::OnContextMenu Brings up the help context menu for those controls that don't usually have context menus (i.e. buttons). Note that this won't work for static controls since they just eat up all messages. Author: KennT ---------------------------------------------------------------------------*/ void CPropertyPageBase::OnContextMenu(CWnd* pWnd, CPoint point) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); DWORD * pdwHelp = GetHelpMapInternal(); if (pdwHelp) { ::WinHelp (pWnd->m_hWnd, AfxGetApp()->m_pszHelpFilePath, HELP_CONTEXTMENU, (ULONG_PTR)pdwHelp); } } // This can be found in dialog.cpp extern PFN_FINDHELPMAP g_pfnHelpMap; DWORD * CPropertyPageBase::GetHelpMapInternal() { DWORD * pdwHelpMap = NULL; DWORD dwIDD = 0; if ((ULONG_PTR) m_lpszTemplateName < 0xFFFF) dwIDD = (WORD) m_lpszTemplateName; // If there is no dialog IDD, give up // If there is no global help map function, give up if ((dwIDD == 0) || (g_pfnHelpMap == NULL) || ((pdwHelpMap = g_pfnHelpMap(dwIDD)) == NULL)) return GetHelpMap(); return pdwHelpMap; } struct EnableChildControlsEnumParam { HWND m_hWndParent; DWORD m_dwFlags; }; BOOL CALLBACK EnableChildControlsEnumProc(HWND hWnd, LPARAM lParam) { EnableChildControlsEnumParam * pParam; pParam = reinterpret_cast(lParam); // Enable/disable only if this is an immediate descendent if (GetParent(hWnd) == pParam->m_hWndParent) { if (pParam->m_dwFlags & PROPPAGE_CHILD_SHOW) ::ShowWindow(hWnd, SW_SHOW); else if (pParam->m_dwFlags & PROPPAGE_CHILD_HIDE) ::ShowWindow(hWnd, SW_HIDE); if (pParam->m_dwFlags & PROPPAGE_CHILD_ENABLE) ::EnableWindow(hWnd, TRUE); else if (pParam->m_dwFlags & PROPPAGE_CHILD_DISABLE) ::EnableWindow(hWnd, FALSE); } return TRUE; } HRESULT EnableChildControls(HWND hWnd, DWORD dwFlags) { EnableChildControlsEnumParam param; param.m_hWndParent = hWnd; param.m_dwFlags = dwFlags; EnumChildWindows(hWnd, EnableChildControlsEnumProc, (LPARAM) ¶m); return hrOK; } HRESULT MultiEnableWindow(HWND hWndParent, BOOL fEnable, UINT first, ...) { UINT nCtrlId = first; HWND hWndCtrl; va_list marker; va_start(marker, first); while (nCtrlId != 0) { hWndCtrl = ::GetDlgItem(hWndParent, nCtrlId); Assert(hWndCtrl); if (hWndCtrl) ::EnableWindow(hWndCtrl, fEnable); // get the next item nCtrlId = va_arg(marker, UINT); } va_end(marker); return hrOK; }