windows-nt/Source/XPSP1/NT/net/mmc/common/proppage.cpp
2020-09-26 16:20:57 +08:00

1178 lines
29 KiB
C++

/**********************************************************************/
/** 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 <prsht.h>
#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<void **>(&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<void **>(&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<void **>(&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<LONG_PTR>(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<EnableChildControlsEnumParam *>(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) &param);
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;
}