Leaked source code of windows server 2003
 
 
 
 
 
 

697 lines
18 KiB

// Copyright (c) 1995 - 1999 Microsoft Corporation. All Rights Reserved.
//
// propsht.cpp
//
#include "stdafx.h"
//
// Define the GUIDs for the property pages and their interfaces
//
#include <initguid.h>
#include <propguid.h>
BEGIN_MESSAGE_MAP(CVfWPropertySheet, CPropertySheet)
ON_WM_CREATE()
ON_COMMAND(IDOK, OnOK)
ON_COMMAND(IDCANCEL, OnCancel)
ON_COMMAND(IDC_APPLY, OnApply)
ON_COMMAND(IDC_PROP_HELP, OnHelp)
END_MESSAGE_MAP()
//
// Constructor
//
// Through the IUnknown pointer passed to us we might be able to
// get:
//
// IBaseFilter, IPin, IFileSourceFilter, IFileSinkFilter or ISpecifyPropertyPages
//
// each of these has at least one IPropertyPage interface for us.
// (the ones for IBaseFilter, IPin, IFileSinkFilter and IFileSourceFilter
// are provided by proppage.dll )
//
CVfWPropertySheet::CVfWPropertySheet(IUnknown *pUnknown, CString szCaption, CWnd * wnd)
: m_butOK(NULL)
, m_fButtonsCreated(FALSE)
, m_butApply(NULL)
, m_butCancel(NULL)
, m_butHelp(NULL)
, m_fAnyChanges(FALSE)
, CPropertySheet(szCaption, wnd)
{
UINT iPages = 0;
try {
//
// Create the four buttons
//
m_butOK = new CButton();
m_butCancel = new CButton();
m_butApply = new CButton();
m_butHelp = new CButton();
//
// First check whether this is a connected pin to make sure
// that we search both pins for SpecificPages
//
try {
CQCOMInt<IPin> pPin(IID_IPin, pUnknown);
IPin * pConnected = NULL;
HRESULT hr = pPin->ConnectedTo( &pConnected );
if( SUCCEEDED( hr ) )
{
// handle the connected pin first
iPages += AddSpecificPages(pConnected);
pConnected->Release();
}
}
catch (CHRESULTException) {
// do nothing
}
iPages += AddSpecificPages(pUnknown);
iPages += AddFilePage(pUnknown);
iPages += AddPinPages(pUnknown);
if (0 == iPages) {
throw CE_FAIL();
}
// compute dimensions large enough to hold largest
// proppage. tell all proppages.
//
SIZE sizeMax = {0, 0};
CPropertyPage *ppTmp;
for(int iPage = 0; iPage < GetPageCount() && (ppTmp = GetPage(iPage)); iPage++)
{
CPropertySite *pcps = (CPropertySite *)ppTmp;
SIZE size = pcps->GetSize();
sizeMax.cx = max(sizeMax.cx, size.cx);
sizeMax.cy = max(sizeMax.cy, size.cy);
}
for(iPage = 0; iPage < GetPageCount() && (ppTmp = GetPage(iPage)); iPage++)
{
CPropertySite *pcps = (CPropertySite *)ppTmp;
pcps->InitialiseSize(sizeMax);
}
// create the property sheet but leave it invisible as we
// will have to add the buttons to it
if (!Create(wnd, WS_SYSMENU | WS_POPUP | WS_CAPTION | DS_MODALFRAME)) {
throw CE_FAIL();
}
ASSERT( GetActivePage() );
ASSERT( GetActivePage()->m_hWnd );
CRect rcBoxSize(0, 0, 50, 14);
GetActivePage()->MapDialogRect(&rcBoxSize);
CString szTemp;
szTemp.LoadString(IDS_OK);
m_butOK->Create(szTemp,
BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE
| WS_TABSTOP | WS_GROUP,
rcBoxSize, this, IDOK);
szTemp.LoadString(IDS_CLOSE);
m_butCancel->Create(szTemp,
BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE
| WS_TABSTOP | WS_GROUP,
rcBoxSize, this, IDCANCEL);
szTemp.LoadString(IDS_APPLY);
m_butApply->Create(szTemp,
BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE
| WS_TABSTOP | WS_GROUP | WS_DISABLED,
rcBoxSize, this, IDC_APPLY);
szTemp.LoadString(IDS_HELP);
m_butHelp->Create(szTemp,
BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE
| WS_TABSTOP | WS_GROUP | WS_DISABLED,
rcBoxSize, this, IDC_PROP_HELP);
//
// Position the buttons on the property sheet
//
// The buttons are in the order Ok, Cancel, Apply and Help.
//
// The y-coordinate is 2 dialog units + the buttons size from the
// bottom of the client area.
//
// On the x-coordinate there is a gap of 4 dialog units before each
// button. Thus the x-ths button has a gap of
//
// x * iSpacing + (x-1) * ButtonWidth
//
// between itself and the lefthand corner.
//
CRect rc, rcClient;
GetWindowRect(&rc);
GetClientRect(&rcClient);
CRect rcSpacing(4, 2, 0, 0);
GetActivePage()->MapDialogRect(&rcSpacing);
const int iXSpacing = rcSpacing.left;
const int iYSpacing = rcSpacing.top;
// Make sure that the property page is wide enough for the buttons
int iRight = rcClient.left + ( rcBoxSize.Width() + iXSpacing) * 4;
if( rcClient.right < iRight )
rc.right += rcClient.left + (iRight - rcClient.right);
// increase the property sheet so there is space for our
// buttons
rc.bottom += rcBoxSize.Height() + iYSpacing * 2;
MoveWindow( &rc );
// to position the buttons we need the client rect (window - title)
GetClientRect( &rc );
m_butOK->MoveWindow( iXSpacing,
rc.Height() - rcBoxSize.Height() - iYSpacing,
rcBoxSize.Width(),
rcBoxSize.Height(),
SWP_SHOWWINDOW );
m_butCancel->MoveWindow( 2 * iXSpacing + rcBoxSize.Width(),
rc.Height() - rcBoxSize.Height() - iYSpacing,
rcBoxSize.Width(),
rcBoxSize.Height());
m_butApply->MoveWindow( 3* iXSpacing + 2 * rcBoxSize.Width(),
rc.Height() - rcBoxSize.Height() - iYSpacing,
rcBoxSize.Width(),
rcBoxSize.Height());
m_butHelp->MoveWindow( 4* iXSpacing + 3 * rcBoxSize.Width(),
rc.Height() - rcBoxSize.Height() - iYSpacing,
rcBoxSize.Width(),
rcBoxSize.Height());
m_fButtonsCreated = TRUE;
GetActiveSite()->UpdateButtons();
ShowWindow( SW_SHOW );
}
catch (CHRESULTException) {
Cleanup();
throw;
}
}
//
// Destructor
//
// Call Cleanup again - might have been missed.
//
CVfWPropertySheet::~CVfWPropertySheet()
{
Cleanup();
}
//
// AddSpecificPages
//
// Given an IUnknown pointer we try to obtain a ISpecifyPropertyPages inter-
// face.
//
// If successful, a CPropertySite object is created for each IPropertyPage
// interface we obtain and added to the property pages of CPropertySheet.
//
UINT CVfWPropertySheet::AddSpecificPages(IUnknown *pUnknown)
{
UINT iPages = 0;
CAUUID cauuid;
try {
HRESULT hr;
CQCOMInt<ISpecifyPropertyPages> IPages(IID_ISpecifyPropertyPages, pUnknown);
hr = IPages->GetPages(&cauuid);
if (FAILED(hr)) {
throw CHRESULTException(hr);
}
}
catch (CHRESULTException) {
// clean up in CVfWPropertySheet::CVfWPropertySheet (only place we get called from)
return(0); // no pages created
}
//
// Get the array of GUIDs for the property pages this object supports.
//
// Try to create as many as possible.
//
for (UINT count = 0; count < cauuid.cElems; count++) {
try {
CPropertySite* pPropSite;
try {
pPropSite = new CPropertySite( this, &cauuid.pElems[count] );
} catch( CMemoryException* pOutOfMemory ) {
pOutOfMemory->Delete();
continue;
}
// AddRef the site now else something in Initialise
// might cause the site to delete itself
pPropSite->AddRef();
if (FAILED(pPropSite->Initialise(1, &pUnknown))) {
pPropSite->CleanUp();
pPropSite->Release();
continue;
}
try {
AddPage(pPropSite);
} catch( CMemoryException* pOutOfMemory ) {
pPropSite->CleanUp();
pPropSite->Release();
pOutOfMemory->Delete();
continue;
}
iPages++;
}
catch (CHRESULTException) {
// continue with next iteration
}
}
// Free the memory allocated in ISpecifyPropertyPages::GetPages().
::CoTaskMemFree( cauuid.pElems );
return(iPages);
}
//
// AddFilePage
//
// Queries IUnknown on whether it supports IFileSourceFilter. If this is
// the case add a file property page (from proppage.dll)
//
UINT CVfWPropertySheet::AddFilePage(IUnknown * pUnknown)
{
UINT iPage = 0;
try {
CQCOMInt<IFileSourceFilter> IFileSource(IID_IFileSourceFilter, pUnknown);
CPropertySite * pPropSite =
new CPropertySite(this, &CLSID_FileSourcePropertyPage);
if (pPropSite == NULL) {
throw CE_OUTOFMEMORY();
}
pPropSite->AddRef();
if (FAILED(pPropSite->Initialise(1, &pUnknown))) {
pPropSite->CleanUp();
pPropSite->Release();
throw CE_FAIL();
}
AddPage(pPropSite);
iPage++;
}
catch (CHRESULTException) {
// clean up in CVfWPropertySheet::CVfWPropertySheet
}
try {
CQCOMInt<IFileSinkFilter> IFileSink(IID_IFileSinkFilter, pUnknown);
CPropertySite * pPropSite =
new CPropertySite(this, &CLSID_FileSinkPropertyPage);
if (pPropSite == NULL) {
throw CE_OUTOFMEMORY();
}
pPropSite->AddRef();
if (FAILED(pPropSite->Initialise(1, &pUnknown))) {
pPropSite->CleanUp();
pPropSite->Release();
throw CE_FAIL();
}
AddPage(pPropSite);
iPage++;
}
catch (CHRESULTException) {
// clean up in CVfWPropertySheet::CVfWPropertySheet
}
return(iPage);
}
//
// AddPinPages
//
// Try to obtain IBaseFilter or IPin from IUnknown.
//
// For IBaseFilter, enumerate all pins and add for each a media type property
// page (provided by proppage.dll)
//
// For IPin, provide just one media type property page.
//
UINT CVfWPropertySheet::AddPinPages(IUnknown * pUnknown)
{
UINT iPages = 0;
IPin *pPin = NULL;
//
// First try to obtain the IBaseFilter interface
//
try {
CQCOMInt<IBaseFilter> pFilter(IID_IBaseFilter, pUnknown);
for (CPinEnum Next(pFilter); 0 != (pPin = Next()); iPages++) {
CPropertySite *pPropSite =
new CPropertySite(this, &CLSID_MediaTypePropertyPage);
if (pPropSite == NULL) {
throw CE_OUTOFMEMORY();
}
pPropSite->AddRef();
if (FAILED(pPropSite->Initialise(1, (IUnknown **) &pPin))) {
pPropSite->CleanUp();
pPropSite->Release();
throw CE_FAIL();
}
AddPage(pPropSite);
iPages++;
pPin->Release();
pPin = NULL;
}
}
catch (CHRESULTException) {
if (pPin) {
pPin->Release();
pPin = NULL;
}
}
//
// Now try for IPin
//
try {
CQCOMInt<IPin> pPin(IID_IPin, pUnknown);
CPropertySite *pPropSite =
new CPropertySite(this, &CLSID_MediaTypePropertyPage);
if (pPropSite == NULL) {
throw CE_OUTOFMEMORY();
}
IPin * pIPin; // temporary pointer to get proper (IUnknown **)
pIPin = (IPin *) pPin;
pPropSite->AddRef();
if (FAILED(pPropSite->Initialise(1, (IUnknown **) &pIPin))) {
pPropSite->CleanUp();
pPropSite->Release();
throw CE_FAIL();
}
AddPage(pPropSite);
iPages++;
}
catch (CHRESULTException) {
// clean up in CVfWPropertySheet::CVfWPropertySheet
}
return(iPages);
}
//
// OnCreate
//
int CVfWPropertySheet::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CPropertySheet::OnCreate(lpCreateStruct) != 0) {
return -1;
}
// DO NOT add buttons here! Changes made to the window's size are
// reset after this call
return 0;
}
//
// Cleanup
//
// Cleanup deletes all created buttons and removes all CPropertySites from
// the CPropertySheet.
//
// This method can be run multiple times.
//
void CVfWPropertySheet::Cleanup()
{
//
// Delete all page sites. Note, we don't use delete, since the page
// sites will be deleted automatically through the Release method
// of their IUnknown interface.
//
while (GetPageCount() > 0) {
CPropertySite * pPropSite = (CPropertySite *) GetPage(0);
//
// NOTE NOTE NOTE
//
// Suspected MFC bug.
//
// Intended code:
//
// RemovePage(0);
//
// This asserts for every iteration. I believe that in mfc\src\dlgprop.cpp
// in CPropertySheet::RemovePage(int), the following change is necessary:
// ASSERT(m_nCurPage != nPage); -> ASSERT(m_hWnd == NULL || m_nCurPage != nPage);
//
// Until this is fixed I am deleting the page by myself. This uses
// the knowlegde that CPropertySheet is storing its CPropertyPages
// in the pointer array m_pages.
//
//
// <start hack>
m_pages.RemoveAt(0); // replace with "RemovePage(0);" once bug is fixed.
// <end hack>
pPropSite->CleanUp();
pPropSite->Release();
}
//
// Delete the buttons
//
delete m_butOK, m_butOK = NULL;
delete m_butCancel, m_butCancel = NULL;
delete m_butApply, m_butApply = NULL;
delete m_butHelp, m_butHelp = NULL;
}
//////////////////////////////////////////////////////////////////////////
//
// Button handlers
//
//////////////////////////////////////////////////////////////////////////
//
// OnOK
//
// We need to call IPropertyPage::Apply for the property page of each
// CPropertySite. If all return with S_OK we can close our property sheet.
// Otherwise we cannot close the sheet, since some changes might not been
// applied.
//
void CVfWPropertySheet::OnOK()
{
UINT iPages = GetPageCount();
BOOL fCanQuit = TRUE;
//
// Apply this site first, so we can stay on it if the data is not
// valid.
//
GetActiveSite()->OnSiteApply();
if (GetActiveSite()->IsPageDirty()) {
//
// Data on current page is not valid.
// The page stays active.
//
return;
}
//
// Apply each property page and verify that none remains dirty
// after the apply.
// If a page remains dirty we know that the data validation failed.
//
for (UINT count = 0; count < iPages; count++) {
((CPropertySite *) GetPage(count))->OnSiteApply();
if (((CPropertySite *) GetPage(count))->IsPageDirty()) {
fCanQuit = FALSE;
}
}
if (fCanQuit) {
//
// All pages have been applied. We can destroy our pages by calling
// the OnCancel method.
//
OnCancel();
return;
}
}
//
// OnCancel
//
// Just close the sheet. All changes since the last Apply() will not
// propagate to the objects.
//
void CVfWPropertySheet::OnCancel()
{
//
//
//
// don't use EndDialog, which is for modal dialog boxes
DestroyWindow();
// Do cleanup here, because in an OnDestroy method, we cannot
// remove all property pages, since the last one requires
// m_hWnd of CPropertySheet to be NULL.
Cleanup();
}
//
// OnApply
//
// Only apply changes of present visible property page to object.
//
void CVfWPropertySheet::OnApply()
{
//
// Apply the changes
//
GetActiveSite()->OnSiteApply();
//
// Are there any pages left which are dirty? Set the m_fAnyChanges
// flag accordingly.
//
m_fAnyChanges = FALSE;
UINT iPages = GetPageCount();
for (UINT count = 0; count < iPages; count++) {
if ( ((CPropertySite *) GetPage(count))->IsPageDirty() ) {
m_fAnyChanges = TRUE;
}
}
}
//
// OnHelp
//
// Delegate the call to CPropertySite::OnHelp
//
void CVfWPropertySheet::OnHelp()
{
GetActiveSite()->OnHelp();
}
//
// UpdateButtons
//
void CVfWPropertySheet::UpdateButtons(HRESULT hrIsDirty, BOOL fSupportHelp)
{
ASSERT(m_butApply && m_butCancel && m_butHelp);
if (!m_fButtonsCreated) {
return;
}
//
// We can use this method to obtain notifications of dirty pages.
//
if (hrIsDirty == S_OK) {
m_fAnyChanges = TRUE;
}
//
// Update Apply button
//
if (hrIsDirty == S_OK) {
// we have a dirty page - enable apply button
m_butApply->EnableWindow();
}
else {
m_butApply->EnableWindow(FALSE);
}
//
// Update Cancel/Close button
//
CString szLabel;
if (m_fAnyChanges) {
szLabel.LoadString(IDS_CANCEL);
}
else {
szLabel.LoadString(IDS_CLOSE);
}
m_butCancel->SetWindowText(szLabel);
//
// Update Help button
//
if (fSupportHelp) {
m_butHelp->EnableWindow();
}
else {
m_butHelp->EnableWindow(FALSE);
}
}