|
|
/////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 1996-2000 Microsoft Corporation
//
// Module Name:
// ClusProp.cpp
//
// Abstract:
// Implementation of the cluster property sheet and pages.
//
// Author:
// David Potter (davidp) May 13, 1996
//
// Revision History:
//
// Notes:
//
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "ClusProp.h"
#include "Cluster.h"
#include "Res.h"
#include "ClusDoc.h"
#include "ClusItem.inl"
//#include "EditAcl.h"
#include "DDxDDv.h"
#include "ExcOper.h"
#include "HelpData.h" // g_rghelpmapClusterGeneral
#include "WaitDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__; #endif
/////////////////////////////////////////////////////////////////////////////
// CClusterPropSheet
/////////////////////////////////////////////////////////////////////////////
IMPLEMENT_DYNAMIC(CClusterPropSheet, CBasePropertySheet)
/////////////////////////////////////////////////////////////////////////////
// Message Maps
BEGIN_MESSAGE_MAP(CClusterPropSheet, CBasePropertySheet) //{{AFX_MSG_MAP(CClusterPropSheet)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterPropSheet::CClusterPropSheet
//
// Routine Description:
// Constructor.
//
// Arguments:
// pci [IN OUT] Cluster item whose properties are to be displayed.
// pParentWnd [IN OUT] Parent window for this property sheet.
// iSelectPage [IN] Page to show first.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
CClusterPropSheet::CClusterPropSheet( IN OUT CWnd * pParentWnd, IN UINT iSelectPage ) : CBasePropertySheet(pParentWnd, iSelectPage) { m_rgpages[0] = &PageGeneral(); m_rgpages[1] = &PageQuorum(); m_rgpages[2] = &PageNetPriority();
} //*** CClusterPropSheet::CClusterPropSheet()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterPropSheet::BInit
//
// Routine Description:
// Initialize the property sheet.
//
// Arguments:
// pci [IN OUT] Cluster item whose properties are to be displayed.
// iimgIcon [IN] Index in the large image list for the image to use
// as the icon on each page.
//
// Return Value:
// TRUE Property sheet initialized successfully.
// FALSE Error initializing property sheet.
//
//--
/////////////////////////////////////////////////////////////////////////////
BOOL CClusterPropSheet::BInit( IN OUT CClusterItem * pci, IN IIMG iimgIcon ) { // Call the base class method.
if (!CBasePropertySheet::BInit(pci, iimgIcon)) return FALSE;
// Set the read-only flag if the handles are invalid.
if ((PciCluster()->Hcluster() == NULL) || (PciCluster()->Hkey() == NULL)) m_bReadOnly = TRUE;
return TRUE;
} //*** CClusterPropSheet::BInit()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterPropSheet::Ppages
//
// Routine Description:
// Returns the array of pages to add to the property sheet.
//
// Arguments:
// None.
//
// Return Value:
// Page array.
//
//--
/////////////////////////////////////////////////////////////////////////////
CBasePropertyPage ** CClusterPropSheet::Ppages(void) { return m_rgpages;
} //*** CClusterPropSheet::Ppages()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterPropSheet::Cpages
//
// Routine Description:
// Returns the count of pages in the array.
//
// Arguments:
// None.
//
// Return Value:
// Count of pages in the array.
//
//--
/////////////////////////////////////////////////////////////////////////////
int CClusterPropSheet::Cpages(void) { return sizeof(m_rgpages) / sizeof(CBasePropertyPage *);
} //*** CClusterPropSheet::Cpages()
//*************************************************************************//
/////////////////////////////////////////////////////////////////////////////
// CClusterGeneralPage property page
/////////////////////////////////////////////////////////////////////////////
IMPLEMENT_DYNCREATE(CClusterGeneralPage, CBasePropertyPage)
/////////////////////////////////////////////////////////////////////////////
// Message Maps
BEGIN_MESSAGE_MAP(CClusterGeneralPage, CBasePropertyPage) //{{AFX_MSG_MAP(CClusterGeneralPage)
// ON_BN_CLICKED(IDC_PP_CLUS_PERMISSIONS, OnBnClickedPermissions)
//}}AFX_MSG_MAP
ON_EN_CHANGE(IDC_PP_CLUS_NAME, CBasePropertyPage::OnChangeCtrl) ON_EN_CHANGE(IDC_PP_CLUS_DESC, CBasePropertyPage::OnChangeCtrl) END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterGeneralPage::CClusterGeneralPage
//
// Routine Description:
// Constructor.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
CClusterGeneralPage::CClusterGeneralPage(void) : CBasePropertyPage(IDD, g_aHelpIDs_IDD_PP_CLUSTER_GENERAL) { //{{AFX_DATA_INIT(CClusterGeneralPage)
m_strName = _T(""); m_strDesc = _T(""); m_strVendorID = _T(""); m_strVersion = _T(""); //}}AFX_DATA_INIT
// m_bSecurityChanged = FALSE;
} //*** CClusterGeneralPage::CClusterGeneralPage()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterGeneralPage::~CClusterGeneralPage
//
// Routine Description:
// Destructor.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
CClusterGeneralPage::~CClusterGeneralPage(void) { } //*** CClusterGeneralPage::~CClusterGeneralPage()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterGeneralPage::BInit
//
// Routine Description:
// Initialize the page.
//
// Arguments:
// psht [IN OUT] Property sheet to which this page belongs.
//
// Return Value:
// TRUE Page initialized successfully.
// FALSE Page failed to initialize.
//
//--
/////////////////////////////////////////////////////////////////////////////
BOOL CClusterGeneralPage::BInit(IN OUT CBaseSheet * psht) { BOOL bSuccess; CWaitCursor wc;
ASSERT_KINDOF(CClusterPropSheet, psht);
bSuccess = CBasePropertyPage::BInit(psht);
try { m_strName = PciCluster()->StrName(); m_strDesc = PciCluster()->StrDescription(); m_strVendorID = PciCluster()->Cvi().szVendorId; m_strVersion.Format( IDS_OP_VERSION_NUMBER_FORMAT, PciCluster()->Cvi().MajorVersion ); } // try
catch (CException * pe) { pe->ReportError(); pe->Delete(); m_bReadOnly = TRUE; } // catch: CException
return bSuccess;
} //*** CClusterGeneralPage::BInit()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterGeneralPage::DoDataExchange
//
// Routine Description:
// Do data exchange between the dialog and the class.
//
// Arguments:
// pDX [IN OUT] Data exchange object
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CClusterGeneralPage::DoDataExchange(CDataExchange * pDX) { CWaitCursor wc; CString strClusName;
CBasePropertyPage::DoDataExchange(pDX); //{{AFX_DATA_MAP(CClusterGeneralPage)
DDX_Control(pDX, IDC_PP_CLUS_NAME, m_editName); DDX_Control(pDX, IDC_PP_CLUS_DESC, m_editDesc); DDX_Text(pDX, IDC_PP_CLUS_DESC, m_strDesc); DDX_Text(pDX, IDC_PP_CLUS_VENDOR_ID, m_strVendorID); DDX_Text(pDX, IDC_PP_CLUS_VERSION, m_strVersion); //}}AFX_DATA_MAP
if (pDX->m_bSaveAndValidate) { CLRTL_NAME_STATUS cnStatus;
//
// get the name from the control into a temp variable
//
DDX_Text(pDX, IDC_PP_CLUS_NAME, strClusName);
if ( (strClusName != m_strName) && !ClRtlIsNetNameValid(strClusName, &cnStatus, FALSE /*CheckIfExists*/)) { CString strMsg; UINT idsError;
switch (cnStatus) { case NetNameTooLong: idsError = IDS_INVALID_CLUSTER_NAME_TOO_LONG; break; case NetNameInvalidChars: idsError = IDS_INVALID_CLUSTER_NAME_INVALID_CHARS; break; case NetNameInUse: idsError = IDS_INVALID_CLUSTER_NAME_IN_USE; break; case NetNameDNSNonRFCChars: idsError = IDS_INVALID_CLUSTER_NAME_INVALID_DNS_CHARS; break; case NetNameSystemError: { DWORD scError = GetLastError(); CNTException nte(scError, IDS_ERROR_VALIDATING_NETWORK_NAME, (LPCWSTR) strClusName); nte.ReportError(); pDX->Fail(); } default: idsError = IDS_INVALID_CLUSTER_NAME; break; } // switch: cnStatus
strMsg.LoadString(idsError);
if ( idsError == IDS_INVALID_CLUSTER_NAME_INVALID_DNS_CHARS ) { int id = AfxMessageBox(strMsg, MB_YESNO | MB_DEFBUTTON2 | MB_ICONEXCLAMATION );
if ( id == IDNO ) { strMsg.Empty(); pDX->Fail(); } } else { AfxMessageBox(strMsg, MB_ICONEXCLAMATION); strMsg.Empty(); // exception prep
pDX->Fail(); }
m_strName = strClusName; } // if: cluster name has changed and an invalid network name was specified
} // if: getting data from the dialog
else { //
// populate the control with data from the member variable
//
DDX_Text(pDX, IDC_PP_CLUS_NAME, m_strName); } // else: setting data to the dialog
} //*** CClusterGeneralPage::DoDataExchange()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterGeneralPage::OnInitDialog
//
// Routine Description:
// Handler for the WM_INITDIALOG message.
//
// Arguments:
// None.
//
// Return Value:
// TRUE Focus not set yet.
// FALSE Focus already set.
//
//--
/////////////////////////////////////////////////////////////////////////////
BOOL CClusterGeneralPage::OnInitDialog(void) { // Call the base class method.
CBasePropertyPage::OnInitDialog();
// Set limits on the edit controls.
m_editName.SetLimitText(MAX_CLUSTERNAME_LENGTH);
// If read-only, set all controls to be either disabled or read-only.
if (BReadOnly()) { m_editName.SetReadOnly(TRUE); m_editDesc.SetReadOnly(TRUE); } // if: sheet is read-only
return FALSE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
} //*** CClusterGeneralPage::OnInitDialog()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterGeneralPage::OnSetActive
//
// Routine Description:
// Handler for the PSN_SETACTIVE message.
//
// Arguments:
// None.
//
// Return Value:
// TRUE Page successfully initialized.
// FALSE Page not initialized.
//
//--
/////////////////////////////////////////////////////////////////////////////
BOOL CClusterGeneralPage::OnSetActive(void) { return CBasePropertyPage::OnSetActive();
} //*** CClusterGeneralPage::OnSetActive()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterGeneralPage::OnKillActive
//
// Routine Description:
// Handler for the PSN_KILLACTIVE message.
//
// Arguments:
// None.
//
// Return Value:
// TRUE Page focus successfully killed.
// FALSE Error killing page focus.
//
//--
/////////////////////////////////////////////////////////////////////////////
BOOL CClusterGeneralPage::OnKillActive(void) { return CBasePropertyPage::OnKillActive();
} //*** CClusterGeneralPage::OnKillActive()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterGeneralPage::OnApply
//
// Routine Description:
// Handler for the PSN_APPLY message.
//
// Arguments:
// None.
//
// Return Value:
// TRUE Page successfully applied.
// FALSE Error applying page.
//
//--
/////////////////////////////////////////////////////////////////////////////
BOOL CClusterGeneralPage::OnApply(void) { // Set the data from the page in the cluster item.
try { CWaitCursor wc;
PciCluster()->SetDescription(m_strDesc); PciCluster()->SetName(m_strName); } // try
catch (CException * pe) { pe->ReportError(); pe->Delete(); return FALSE; } // catch: CException
return CBasePropertyPage::OnApply();
} //*** CClusterGeneralPage::OnApply()
/*
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterGeneralPage::OnBnClickedPermissions
//
// Routine Description:
// Handler for the BN_CLICKED message on the Permissions push button.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CClusterGeneralPage::OnBnClickedPermissions(void) { LONG lResult; BOOL bSecDescModified; PSECURITY_DESCRIPTOR psec = NULL; CString strServer; CResource * pciRes = NULL; CWaitCursor wc;
// Find the cluster name resource.
{ POSITION pos;
pos = PciCluster()->Pdoc()->LpciResources().GetHeadPosition(); while (pos != NULL) { pciRes = (CResource *) PciCluster()->Pdoc()->LpciResources().GetNext(pos); ASSERT_VALID(pciRes);
if ( (pciRes->StrRealResourceType().CompareNoCase(CLUS_RESTYPE_NAME_NETNAME)) && pciRes->BCore() ) break; pciRes = NULL; } // while: more resources in the list
ASSERT(pciRes != NULL); } // Find the cluster name resource
strServer.Format(_T("\\\\%s"), PciCluster()->StrName());
lResult = EditClusterAcl( m_hWnd, strServer, PciCluster()->StrName(), pciRes->StrOwner(), m_psec, &bSecDescModified, &psec );
if (bSecDescModified) { delete [] m_psec; m_psec = psec; m_bSecurityChanged = TRUE; SetModified(TRUE); } // if: data changed
} //*** CClusterGeneralPage::OnBnClickedPermissions()
*/
//*************************************************************************//
/////////////////////////////////////////////////////////////////////////////
// CClusterQuorumPage property page
/////////////////////////////////////////////////////////////////////////////
IMPLEMENT_DYNCREATE(CClusterQuorumPage, CBasePropertyPage)
/////////////////////////////////////////////////////////////////////////////
// Message Maps
BEGIN_MESSAGE_MAP(CClusterQuorumPage, CBasePropertyPage) //{{AFX_MSG_MAP(CClusterQuorumPage)
ON_CBN_DBLCLK(IDC_PP_CLUS_QUORUM_RESOURCE, OnDblClkQuorumResource) ON_CBN_SELCHANGE(IDC_PP_CLUS_QUORUM_RESOURCE, OnChangeQuorumResource) ON_WM_DESTROY() //}}AFX_MSG_MAP
ON_CBN_SELCHANGE(IDC_PP_CLUS_QUORUM_PARTITION, CBasePropertyPage::OnChangeCtrl) ON_EN_CHANGE(IDC_PP_CLUS_QUORUM_ROOT_PATH, CBasePropertyPage::OnChangeCtrl) ON_EN_CHANGE(IDC_PP_CLUS_QUORUM_MAX_LOG_SIZE, CBasePropertyPage::OnChangeCtrl) END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterQuorumPage::CClusterQuorumPage
//
// Routine Description:
// Constructor.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
CClusterQuorumPage::CClusterQuorumPage(void) : CBasePropertyPage(IDD, g_aHelpIDs_IDD_PP_CLUSTER_QUORUM) { //{{AFX_DATA_INIT(CClusterQuorumPage)
m_strQuorumResource = _T(""); m_strPartition = _T(""); m_strRootPath = _T(""); m_nMaxLogSize = 0; //}}AFX_DATA_INIT
m_pbDiskInfo = NULL; m_cbDiskInfo = 0;
m_bControlsInitialized = FALSE; m_ppid = NULL;
} //*** CClusterQuorumPage::CClusterQuorumPage()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterQuorumPage::~CClusterQuorumPage
//
// Routine Description:
// Destructor.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
CClusterQuorumPage::~CClusterQuorumPage(void) { delete [] m_pbDiskInfo;
} //*** CClusterQuorumPage::~CClusterQuorumPage()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterQuorumPage::OnDestroy
//
// Routine Description:
// Handler for the WM_DESTROY message.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CClusterQuorumPage::OnDestroy(void) { // If the controls have been initialized, clear the resource combobox.
if ( BControlsInitialized() ) { ClearResourceList(); ClearPartitionList(); }
delete [] m_pbDiskInfo; m_pbDiskInfo = NULL; m_cbDiskInfo = 0;
// Call the base class method.
CBasePropertyPage::OnDestroy();
} //*** CClusterQuorumPage::OnDestroy()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterQuorumPage::BInit
//
// Routine Description:
// Initialize the page.
//
// Arguments:
// psht [IN OUT] Property sheet to which this page belongs.
//
// Return Value:
// TRUE Page initialized successfully.
// FALSE Page failed to initialize.
//
//--
/////////////////////////////////////////////////////////////////////////////
BOOL CClusterQuorumPage::BInit(IN OUT CBaseSheet * psht) { BOOL bSuccess; CWaitCursor wc;
ASSERT_KINDOF(CClusterPropSheet, psht);
bSuccess = CBasePropertyPage::BInit(psht);
try { // Get the current quorum resource.
m_strQuorumResource = PciCluster()->StrQuorumResource();
SplitDeviceName( PciCluster()->StrQuorumPath(), m_strPartition.GetBuffer( _MAX_PATH ), m_strRootPath.GetBuffer( _MAX_PATH ) );
m_strPartition.ReleaseBuffer(); m_strRootPath.ReleaseBuffer();
m_nMaxLogSize = (PciCluster()->NMaxQuorumLogSize() + 1023) / 1024;
m_strCurrentPartition = m_strPartition; m_strCurrentRootPath = m_strRootPath; } // try
catch (CException * pe) { pe->ReportError(); pe->Delete(); m_bReadOnly = TRUE; } // catch: CException
return bSuccess;
} //*** CClusterQuorumPage::BInit()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterQuorumPage::DoDataExchange
//
// Routine Description:
// Do data exchange between the dialog and the class.
//
// Arguments:
// pDX [IN OUT] Data exchange object
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CClusterQuorumPage::DoDataExchange(CDataExchange * pDX) { CWaitCursor wc;
CBasePropertyPage::DoDataExchange(pDX); //{{AFX_DATA_MAP(CClusterQuorumPage)
DDX_Control(pDX, IDC_PP_CLUS_QUORUM_MAX_LOG_SIZE, m_editMaxLogSize); DDX_Control(pDX, IDC_PP_CLUS_QUORUM_ROOT_PATH, m_editRootPath); DDX_Control(pDX, IDC_PP_CLUS_QUORUM_PARTITION, m_cboxPartition); DDX_Control(pDX, IDC_PP_CLUS_QUORUM_RESOURCE, m_cboxQuorumResource); DDX_CBString(pDX, IDC_PP_CLUS_QUORUM_RESOURCE, m_strQuorumResource); DDX_CBString(pDX, IDC_PP_CLUS_QUORUM_PARTITION, m_strPartition); DDX_Text(pDX, IDC_PP_CLUS_QUORUM_ROOT_PATH, m_strRootPath); DDX_Text(pDX, IDC_PP_CLUS_QUORUM_MAX_LOG_SIZE, m_nMaxLogSize); //}}AFX_DATA_MAP
if ( ! pDX->m_bSaveAndValidate ) { // Fill the quorum resource combobox with resource names.
FillResourceList(); } // if: setting data to the dialog
m_bControlsInitialized = TRUE;
if (pDX->m_bSaveAndValidate || !BReadOnly()) DDX_Number(pDX, IDC_PP_CLUS_QUORUM_MAX_LOG_SIZE, m_nMaxLogSize, 1, 0xffffffff / 1024);
if (pDX->m_bSaveAndValidate) { DDV_RequiredText(pDX, IDC_PP_CLUS_QUORUM_RESOURCE, IDC_PP_CLUS_QUORUM_RESOURCE_LABEL, m_strQuorumResource); DDV_RequiredText(pDX, IDC_PP_CLUS_QUORUM_PARTITION, IDC_PP_CLUS_QUORUM_PARTITION_LABEL, m_strPartition); DDV_RequiredText(pDX, IDC_PP_CLUS_QUORUM_ROOT_PATH, IDC_PP_CLUS_QUORUM_ROOT_PATH_LABEL, m_strRootPath); } // if: getting data from the dialog
} //*** CClusterQuorumPage::DoDataExchange()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterQuorumPage::OnInitDialog
//
// Routine Description:
// Handler for the WM_INITDIALOG message.
//
// Arguments:
// None.
//
// Return Value:
// TRUE Focus not set yet.
// FALSE Focus already set.
//
//--
/////////////////////////////////////////////////////////////////////////////
BOOL CClusterQuorumPage::OnInitDialog(void) { // Call the base class method.
CBasePropertyPage::OnInitDialog();
// If read-only, set all controls to be either disabled or read-only.
if (BReadOnly()) { m_cboxQuorumResource.EnableWindow(FALSE); m_cboxPartition.EnableWindow(FALSE); m_editRootPath.SetReadOnly(); m_editMaxLogSize.SetReadOnly(); } // if: sheet is read-only
else { m_editRootPath.SetLimitText(MAX_PATH); }
return FALSE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
} //*** CClusterQuorumPage::OnInitDialog()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterQuorumPage::OnApply
//
// Routine Description:
// Handler for the PSN_APPLY message.
//
// Arguments:
// None.
//
// Return Value:
// TRUE Page successfully applied.
// FALSE Error applying page.
//
//--
/////////////////////////////////////////////////////////////////////////////
BOOL CClusterQuorumPage::OnApply(void) { CWaitCursor wc; CString strQuorumPath; CString strTemp; DWORD nLen; CResource * pciRes = NULL; int nSelected; int nCount; CLUSTER_RESOURCE_STATE crs = ClusterResourceStateUnknown;
//
// Get the currently selected resource from the combo box.
//
nSelected = m_cboxQuorumResource.GetCurSel(); nCount = m_cboxQuorumResource.GetCount();
if ( CB_ERR != nSelected && 0 < nCount ) { pciRes = (CResource *) m_cboxQuorumResource.GetItemDataPtr(nSelected); }
//
// If we successfully retrieved a resource make sure it's online.
//
if ( NULL != pciRes ) { crs = pciRes->Crs(); if ( ClusterResourceOnline != crs ) { //
// Prompt the user whether or not they'd like to online the resource.
//
strTemp.FormatMessage( IDS_ONLINE_QUORUM_RESOURCE_PROMPT, pciRes->StrName() ); if ( IDYES == AfxMessageBox( strTemp, MB_YESNO | MB_ICONQUESTION ) ) { CWaitForResourceOnlineDlg dlg( pciRes, AfxGetMainWnd() ); pciRes->OnCmdBringOnline(); dlg.DoModal(); crs = pciRes->Crs(); } else { return FALSE; } } // if: resource !online
} // if: pciRes !NULL
else { // No resource was selected - this should never happen.
AfxMessageBox( IDS_SELECT_QUORUM_RESOURCE_ERROR, MB_OK | MB_ICONEXCLAMATION ); return FALSE; } // Set the data from the page in the cluster item.
if ( ClusterResourceOnline == crs ) { try { strTemp = _T(""); if( m_ppid != NULL && !m_strRootPath.IsEmpty() ) { nLen = _tcslen( m_ppid->szDeviceName ); //
// Concatenate the strings before calling SetQuorumResource, but make sure that
// there is only one backslash between them.
//
strTemp = m_ppid->szDeviceName; if( ( m_ppid->szDeviceName[nLen-1] != _T('\\') ) && ( m_strRootPath[0] != _T('\\') ) ) { strTemp += _T('\\'); } else if( ( m_ppid->szDeviceName[nLen-1] == _T('\\') ) && ( m_strRootPath[0] == _T('\\') ) ) { strTemp.SetAt( nLen-1, _T('\0') ); } } // if: neither string is empty
strQuorumPath.Format( _T("%s%s"), strTemp, m_strRootPath ); PciCluster()->SetQuorumResource( m_strQuorumResource, strQuorumPath, (m_nMaxLogSize * 1024) ); m_strCurrentPartition = m_strPartition; m_strCurrentRootPath = m_strRootPath; } // try
catch (CException * pe) { pe->ReportError(); pe->Delete(); strQuorumPath.Empty(); return FALSE; } // catch: CException
} // if: the resource is online
return CBasePropertyPage::OnApply();
} //*** CClusterQuorumPage::OnApply()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterQuorumPage::OnDblClkQuorumResource
//
// Routine Description:
// Handler for the CBN_DBLCLK message on the Quorum Resource combo box.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CClusterQuorumPage::OnDblClkQuorumResource(void) { int nSelected; CResource * pciRes;
// Get the selected resource.
nSelected = m_cboxQuorumResource.GetCurSel(); ASSERT(nSelected != CB_ERR);
// Get the resource object.
pciRes = (CResource *) m_cboxQuorumResource.GetItemDataPtr(nSelected); ASSERT_VALID(pciRes); ASSERT_KINDOF(CResource, pciRes);
// Display properties for the resource.
pciRes->OnCmdProperties();
} //*** CClusterQuorumPage::OnDblClkQuorumResource()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterQuorumPage::OnChangeQuorumResource
//
// Routine Description:
// Handler for the CBN_SELCHANGE message on the Quorum Resource combobox.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CClusterQuorumPage::OnChangeQuorumResource(void) { int nSelected; CResource * pciRes;
OnChangeCtrl();
// Get the selected resource.
nSelected = m_cboxQuorumResource.GetCurSel(); ASSERT(nSelected != CB_ERR);
// Get the resource object.
pciRes = (CResource *) m_cboxQuorumResource.GetItemDataPtr(nSelected); ASSERT_VALID(pciRes); ASSERT_KINDOF(CResource, pciRes);
// If the resource really did change and is the same as the currently
// saved resource, set the partition to the currently saved partition.
// Otherwise, clear the partition setting and use the first one.
if (pciRes->StrName() != m_strQuorumResource) { if (pciRes->StrName() == PciCluster()->StrQuorumResource()) { m_strPartition = m_strCurrentPartition; m_strRootPath = m_strCurrentRootPath; } // if: changed to previously set quorum resource
else { m_strPartition = _T(""); //m_strRootPath = _T("\\") CLUS_NAME_DEFAULT_FILESPATH;
} // else: changed to new quorum resource
m_strQuorumResource = pciRes->StrName(); } // if: resource really did change
UpdateData(FALSE /*bSaveAndValidate*/);
} //*** CClusterQuorumPage::OnChangeQuorumResource()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterQuorumPage::ClearResourceList
//
// Routine Description:
// Clear the resource list and release references to pointers.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CClusterQuorumPage::ClearResourceList(void) { int cItems; int iItem; CResource * pciRes;
cItems = m_cboxQuorumResource.GetCount(); for (iItem = 0 ; iItem < cItems ; iItem++) { pciRes = (CResource *) m_cboxQuorumResource.GetItemDataPtr(iItem); ASSERT_VALID(pciRes); ASSERT_KINDOF(CResource, pciRes); pciRes->Release(); } // for: each item in the list
m_cboxQuorumResource.ResetContent();
} //*** CClusterQuorumPage::ClearResourceList()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterQuorumPage::FillResourceList
//
// Routine Description:
// Fill the quorum resource combobox with all resources and select
// the quorum resource.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CClusterQuorumPage::FillResourceList(void) { POSITION pos; int nIndex; CResource * pciRes; CResource * pciSelected = NULL; CWaitCursor wc;
// Clear the list.
ClearResourceList();
pos = PciCluster()->Pdoc()->LpciResources().GetHeadPosition(); while (pos != NULL) { // Get the next resource.
pciRes = (CResource *) PciCluster()->Pdoc()->LpciResources().GetNext(pos); ASSERT_VALID(pciRes); ASSERT_KINDOF(CResource, pciRes);
// If it is quorum capable, add it to the list.
try { if (pciRes->BQuorumCapable()) { nIndex = m_cboxQuorumResource.AddString(pciRes->StrName()); ASSERT(nIndex != CB_ERR); m_cboxQuorumResource.SetItemDataPtr(nIndex, pciRes); pciRes->AddRef(); if (m_strQuorumResource == pciRes->StrName()) pciSelected = pciRes; } // if: resource can be a quorum resource
} // try
catch (...) { // Ignore all errors because there is really nothing we can do.
// Displaying a message isn't really very useful.
} // catch: Anything
} // while: more items in the list
// Select the current quorum resource in the list.
{ int istr;
istr = m_cboxQuorumResource.FindStringExact(-1, m_strQuorumResource); ASSERT(istr != CB_ERR); VERIFY(m_cboxQuorumResource.SetCurSel(istr) != CB_ERR); } // Select the current quorum resource in the list
// Check if the current quorum device is in the list of quorum capable resources
if (pciSelected != NULL) { // Fill the partition list.
FillPartitionList(pciSelected); } else { // There is nothing we can do in this case. There is something seriously wrong
// with the cluster.
CNTException nte( ERROR_QUORUM_DISK_NOT_FOUND, IDS_GET_QUORUM_DEVICES_ERROR ); nte.ReportError(); } // else: the current quorum device is not in the list of quorum capable resources
} //*** CClusterQuorumPage::FillResourceList()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterQuorumPage::ClearPartitionList
//
// Routine Description:
// Clear the partition list and release references to pointers.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CClusterQuorumPage::ClearPartitionList(void) { int cItems; int iItem; SPartitionItemData * ppid = NULL;
cItems = m_cboxPartition.GetCount(); for ( iItem = 0 ; iItem < cItems ; iItem++ ) { ppid = (SPartitionItemData *) m_cboxPartition.GetItemDataPtr( iItem ); delete ppid; } // for: each item in the list
m_cboxPartition.ResetContent();
} //*** CClusterQuorumPage::ClearPartitionList()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterQuorumPage::FillPartitionList
//
// Routine Description:
// Fill the partition combobox with all partitions available on the
// currently selected quorum resource.
//
// Arguments:
// pciRes [IN OUT] Currently selected quorum resource.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CClusterQuorumPage::FillPartitionList(IN OUT CResource * pciRes) { CString strPartitionInfo; CLUSPROP_BUFFER_HELPER buf; DWORD cbData; DWORD cbBuf; int nIndex; SPartitionItemData * ppid = NULL; CWaitCursor wc;
ASSERT_VALID(pciRes);
// Clear the list.
ClearPartitionList();
// Get disk info for this resource.
if (BGetDiskInfo(*pciRes)) { buf.pb = m_pbDiskInfo; cbBuf = m_cbDiskInfo;
while (buf.pSyntax->dw != CLUSPROP_SYNTAX_ENDMARK) { // Calculate the size of the value.
cbData = sizeof(*buf.pValue) + ALIGN_CLUSPROP(buf.pValue->cbLength); ASSERT(cbData <= cbBuf);
// Parse the value.
if (buf.pSyntax->dw == CLUSPROP_SYNTAX_PARTITION_INFO) { // Add the partition to the combobox if it is a usable partition
// and it hasn't been added already.
if ( (buf.pPartitionInfoValue->dwFlags & CLUSPROP_PIFLAG_USABLE) && (m_cboxPartition.FindString(-1, buf.pPartitionInfoValue->szDeviceName) == CB_ERR)) { try { // Construct the name to display to the user
// and add the item to the combobox.
strPartitionInfo.Format( ( buf.pPartitionInfoValue->szVolumeLabel[ 0 ] ? _T("%ls (%ls) ") : _T("%ls ") ), buf.pPartitionInfoValue->szDeviceName, buf.pPartitionInfoValue->szVolumeLabel ); nIndex = m_cboxPartition.AddString( strPartitionInfo ); ASSERT( nIndex != CB_ERR );
// Construct a partition item data structure,
// which consists of the device name, a partition
// name, and a root path name.
ppid = new SPartitionItemData; if ( ppid == NULL ) { AfxThrowMemoryException(); } ASSERT( ( _tcslen( buf.pPartitionInfoValue->szDeviceName ) + 1 ) * sizeof( TCHAR ) <= sizeof( ppid->szDeviceName ) ); _tcscpy( ppid->szDeviceName, buf.pPartitionInfoValue->szDeviceName ); SplitDeviceName( buf.pPartitionInfoValue->szDeviceName, ppid->szPartitionName, ppid->szBaseRootPath ); m_cboxPartition.SetItemDataPtr( nIndex, ppid ); } // try
catch (...) { // Ignore all errors because there is really nothing we can do.
// Displaying a message isn't really very useful.
} // catch: Anything
} // if: partition not added yet
} // if: partition info
// Advance the buffer pointer
buf.pb += cbData; cbBuf -= cbData; } // while: more values
} // if: got disk info successfully
// Select the current partition in the list.
if (m_strPartition.GetLength() > 0) { nIndex = m_cboxPartition.SelectString( -1, m_strPartition ); } // if: there is a current partition
else { if (m_cboxPartition.GetCount() > 0) { nIndex = m_cboxPartition.SetCurSel( 0 ); } // if: combobox has any entries
else { nIndex = -1; } // else: no entries in the list
} // else: no current selection
if ( nIndex != -1 ) { size_t cchBaseRootPath; LPTSTR pszRootPath;
// Save the item data.
// If the base root path is contained in the root path,
// remove the base root path from the root path.
m_ppid = (SPartitionItemData *) m_cboxPartition.GetItemDataPtr( nIndex ); if ( m_ppid != NULL ) { m_strPartition = m_ppid->szPartitionName; cchBaseRootPath = _tcslen( m_ppid->szBaseRootPath ); if ( ( cchBaseRootPath > 0 ) && ( _tcsncmp( m_strRootPath, m_ppid->szBaseRootPath, cchBaseRootPath ) == 0 ) ) { pszRootPath = m_strRootPath.GetBuffer( 1 ); _tcscpy( pszRootPath, &pszRootPath[ cchBaseRootPath ] ); m_strRootPath.ReleaseBuffer(); } // if: root path contains base root path
} // if: ppid retrieved successfully
} // if: an item is selected
else if ( m_cboxPartition.GetCount() > 0 ) { ASSERT( nIndex != CB_ERR ); } // else if: combobox is not empty
} //*** CClusterQuorumPage::FillPartitionList()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterQuorumPage::SplitDeviceName
//
// Routine Description:
// Split a device name into a partition name and a root path. It is
// expected that the output buffers are at least of size _MAX_PATH.
//
// Arguments:
// pszDeviceNameIn Device name to split.
// pszPartitionNameOut Partition name buffer to fill.
// pszRootPathOut Root path buffer to fill.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CClusterQuorumPage::SplitDeviceName( LPCTSTR pszDeviceNameIn, LPTSTR pszPartitionNameOut, LPTSTR pszRootPathOut ) { //
// Construct the partition name and base root path from the device name.
//
//
// If we have a UNC path it will end up looking like \\<X>\<Y>\. If
// it begins with "\\?\UNC\" we do a special case and pull out "\?\UNC".
// We then search for the second '\' beyond that to end the partition name,
// at which point we start grabbing the root path.
//
// If we have it pointing to a directory the partition should look like "c:"
// and the root path should look like "winnt\cluster\MSCS"
//
if ( ( pszDeviceNameIn[ 0 ] == _T('\\') ) && ( pszDeviceNameIn[ 1 ] == _T('\\') ) ) { int cSlashes = 0;
//
// pszDeviceNameIn contains a UNC path. Skip over any \\?\UNC\ prefix
//
if ( _tcsnicmp( pszDeviceNameIn, _T("\\\\?\\UNC\\"), 8 ) == 0 ) { pszDeviceNameIn += 8; } else { pszDeviceNameIn += 2; }
//
// Make sure out partition looks like a UNC path on output.
//
_sntprintf( pszPartitionNameOut, 2, _T("\\\\") ); pszPartitionNameOut += 2;
// Copy the server and share name to the partition string.
for ( ; *pszDeviceNameIn != _T('\0') ; pszPartitionNameOut++, pszDeviceNameIn++ ) { if ( *pszDeviceNameIn == _T('\\') ) { cSlashes++; if ( cSlashes == 2 ) { break; } // if: found the slash after the share name
} // if: found a slash
*pszPartitionNameOut = *pszDeviceNameIn; } // for: each character in the device name
// Copy the rest of the path to the root path string.
if ( *pszDeviceNameIn == _T('\0') ) { _tcscpy( pszRootPathOut, _T("\\") ); } // if: no root path
else { pszDeviceNameIn++; _tcscpy( pszRootPathOut, pszDeviceNameIn ); } // else: root path specified
} // if: UNC path
else { _tsplitpath( pszDeviceNameIn, pszPartitionNameOut, pszRootPathOut, NULL, NULL ); } // else: not a UNC path
} //*** CClusterQuorumPage::FillPartitionItemData()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterQuorumPage::BGetDiskInfo
//
// Routine Description:
// Get information about the currently selected disk.
//
// Arguments:
// rpciRes [IN OUT] Disk resource to get info about.
//
// Return Value:
// TRUE The operation was successful.
// FALSE The operation failed.
//
//--
/////////////////////////////////////////////////////////////////////////////
BOOL CClusterQuorumPage::BGetDiskInfo( IN OUT CResource & rpciRes ) { DWORD dwStatus = ERROR_SUCCESS; DWORD cbDiskInfo = sizeof( CLUSPROP_DWORD ) + sizeof( CLUSPROP_SCSI_ADDRESS ) + sizeof( CLUSPROP_DISK_NUMBER ) + sizeof( CLUSPROP_PARTITION_INFO ) + sizeof( CLUSPROP_SYNTAX ); PBYTE pbDiskInfo = NULL;
try { // Get disk info.
pbDiskInfo = new BYTE[ cbDiskInfo ]; if ( pbDiskInfo == NULL ) { AfxThrowMemoryException(); } // if: error allocating memory
dwStatus = ClusterResourceControl( rpciRes.Hresource(), NULL, CLUSCTL_RESOURCE_STORAGE_GET_DISK_INFO, NULL, 0, pbDiskInfo, cbDiskInfo, &cbDiskInfo ); if ( dwStatus == ERROR_MORE_DATA ) { delete [] pbDiskInfo; pbDiskInfo = new BYTE[ cbDiskInfo] ; if ( pbDiskInfo == NULL ) { AfxThrowMemoryException(); } // if: error allocating memory
dwStatus = ClusterResourceControl( rpciRes.Hresource(), NULL, CLUSCTL_RESOURCE_STORAGE_GET_DISK_INFO, NULL, 0, pbDiskInfo, cbDiskInfo, &cbDiskInfo ); } // if: buffer is too small
} // try
catch ( CMemoryException * pme ) { pme->Delete(); dwStatus = ERROR_NOT_ENOUGH_MEMORY; } // catch: CMemoryException
if ( dwStatus != ERROR_SUCCESS ) { CNTException nte( dwStatus, IDS_GET_DISK_INFO_ERROR, rpciRes.StrName(), NULL, FALSE /*bAutoDelete*/ ); delete [] pbDiskInfo; nte.ReportError(); nte.Delete(); return FALSE; } // if: error getting disk info
delete [] m_pbDiskInfo; m_pbDiskInfo = pbDiskInfo; m_cbDiskInfo = cbDiskInfo;
return TRUE;
} //*** CClusterQuorumPage::BGetDiskInfo()
//*************************************************************************//
/////////////////////////////////////////////////////////////////////////////
// CClusterNetPriorityPage property page
/////////////////////////////////////////////////////////////////////////////
IMPLEMENT_DYNCREATE(CClusterNetPriorityPage, CBasePropertyPage)
/////////////////////////////////////////////////////////////////////////////
// Message Maps
BEGIN_MESSAGE_MAP(CClusterNetPriorityPage, CBasePropertyPage) //{{AFX_MSG_MAP(CClusterNetPriorityPage)
ON_LBN_SELCHANGE(IDC_PP_CLUS_PRIORITY_LIST, OnSelChangeList) ON_BN_CLICKED(IDC_PP_CLUS_PRIORITY_UP, OnUp) ON_BN_CLICKED(IDC_PP_CLUS_PRIORITY_DOWN, OnDown) ON_BN_CLICKED(IDC_PP_CLUS_PRIORITY_PROPERTIES, OnProperties) ON_WM_DESTROY() ON_WM_CONTEXTMENU() ON_LBN_DBLCLK(IDC_PP_CLUS_PRIORITY_LIST, OnDblClkList) //}}AFX_MSG_MAP
ON_COMMAND(ID_FILE_PROPERTIES, OnProperties) END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterNetPriorityPage::CClusterNetPriorityPage
//
// Routine Description:
// Constructor.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
CClusterNetPriorityPage::CClusterNetPriorityPage(void) : CBasePropertyPage(IDD, g_aHelpIDs_IDD_PP_CLUSTER_NET_PRIORITY) { //{{AFX_DATA_INIT(CClusterNetPriorityPage)
//}}AFX_DATA_INIT
m_bControlsInitialized = FALSE;
} //*** CClusterNetPriorityPage::CClusterNetPriorityPage()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterNetPriorityPage::OnDestroy
//
// Routine Description:
// Handler for the WM_DESTROY message.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CClusterNetPriorityPage::OnDestroy(void) { // If the controls have been initialized, clear the list box.
if (BControlsInitialized()) ClearNetworkList();
// Call the base class method.
CBasePropertyPage::OnDestroy();
} //*** CClusterNetPriorityPage::OnDestroy()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterNetPriorityPage::DoDataExchange
//
// Routine Description:
// Do data exchange between the dialog and the class.
//
// Arguments:
// pDX [IN OUT] Data exchange object
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CClusterNetPriorityPage::DoDataExchange(CDataExchange* pDX) { CBasePropertyPage::DoDataExchange(pDX); //{{AFX_DATA_MAP(CClusterNetPriorityPage)
DDX_Control(pDX, IDC_PP_CLUS_PRIORITY_PROPERTIES, m_pbProperties); DDX_Control(pDX, IDC_PP_CLUS_PRIORITY_DOWN, m_pbDown); DDX_Control(pDX, IDC_PP_CLUS_PRIORITY_UP, m_pbUp); DDX_Control(pDX, IDC_PP_CLUS_PRIORITY_LIST, m_lbList); //}}AFX_DATA_MAP
m_bControlsInitialized = TRUE;
if (pDX->m_bSaveAndValidate) { int nIndex; int cItems; CNetwork * pciNet;
ASSERT(!BReadOnly());
// Save the list.
LpciNetworkPriority().RemoveAll();
cItems = m_lbList.GetCount(); for (nIndex = 0 ; nIndex < cItems ; nIndex++) { pciNet = (CNetwork *) m_lbList.GetItemDataPtr(nIndex); ASSERT_VALID(pciNet); LpciNetworkPriority().AddTail(pciNet); } // for: each item in the list box
} // if: saving data from the dialog
} //*** CClusterNetPriorityPage::DoDataExchange()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterNetPriorityPage::OnInitDialog
//
// Routine Description:
// Handler for the WM_INITDIALOG message.
//
// Arguments:
// None.
//
// Return Value:
// TRUE Focus not set yet.
// FALSE Focus already set.
//
//--
/////////////////////////////////////////////////////////////////////////////
BOOL CClusterNetPriorityPage::OnInitDialog(void) { CBasePropertyPage::OnInitDialog();
if (BReadOnly()) { m_lbList.EnableWindow(FALSE); m_pbUp.EnableWindow(FALSE); m_pbDown.EnableWindow(FALSE); } // if: object is read only
try { // Duplicate the network priority list.
{ POSITION pos; CNetwork * pciNet;
pos = PciCluster()->LpciNetworkPriority().GetHeadPosition(); while (pos != NULL) { pciNet = (CNetwork *) PciCluster()->LpciNetworkPriority().GetNext(pos); ASSERT_VALID(pciNet); m_lpciNetworkPriority.AddTail(pciNet); } // while: more networks in the list
} // Duplicate the network priority list
} // try
catch (CException * pe) { pe->ReportError(); pe->Delete(); } // catch: CException
// Fill the list.
FillList();
// Set button states.
OnSelChangeList();
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
} //*** CClusterNetPriorityPage::OnInitDialog()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterNetPriorityPage::OnApply
//
// Routine Description:
// Handler for the PSN_APPLY message.
//
// Arguments:
// None.
//
// Return Value:
// TRUE Page successfully applied.
// FALSE Error applying page.
//
//--
/////////////////////////////////////////////////////////////////////////////
BOOL CClusterNetPriorityPage::OnApply(void) { ASSERT(!BReadOnly());
try { PciCluster()->SetNetworkPriority(LpciNetworkPriority()); } // try
catch (CException * pe) { pe->ReportError(); pe->Delete(); return FALSE; } // catch: CException
return CPropertyPage::OnApply();
} //*** CClusterNetPriorityPage::OnApply()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterNetPriorityPage::OnSelChangeList
//
// Routine Description:
// Handler for the LBN_SELCHANGE message on the list box.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CClusterNetPriorityPage::OnSelChangeList(void) { BOOL bEnableUp; BOOL bEnableDown; BOOL bEnableProperties; int isel; int cItems;
isel = m_lbList.GetCurSel(); cItems = m_lbList.GetCount();
// Enable buttons only if there is a selection and there
// is more than one item in the list.
if (BReadOnly() || (isel == LB_ERR) || (cItems <= 1)) { bEnableUp = FALSE; bEnableDown = FALSE; } // if: no selection or only 0 or 1 items in the list
else { bEnableUp = (isel > 0); bEnableDown = (isel < cItems - 1); } // else: buttons allowed to be enabled
bEnableProperties = (isel != LB_ERR);
m_pbUp.EnableWindow(bEnableUp); m_pbDown.EnableWindow(bEnableDown); m_pbProperties.EnableWindow(bEnableProperties);
} //*** CClusterNetPriorityPage::OnSelChangeList()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterNetPriorityPage::OnUp
//
// Routine Description:
// Handler for the BN_CLICKED message on the Up push button.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CClusterNetPriorityPage::OnUp(void) { int isel; CNetwork * pciNet;
isel = m_lbList.GetCurSel(); ASSERT(isel != LB_ERR);
pciNet = (CNetwork *) m_lbList.GetItemDataPtr(isel); ASSERT_VALID(pciNet);
VERIFY(m_lbList.DeleteString(isel) != LB_ERR); isel = m_lbList.InsertString(isel - 1, pciNet->StrName()); ASSERT(isel != LB_ERR); VERIFY(m_lbList.SetItemDataPtr(isel, pciNet) != LB_ERR); VERIFY(m_lbList.SetCurSel(isel) != LB_ERR);
OnSelChangeList(); m_lbList.SetFocus();
SetModified(TRUE);
} //*** CClusterNetPriorityPage::OnUp()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterNetPriorityPage::OnDown
//
// Routine Description:
// Handler for the BN_CLICKED message on the Down push button.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CClusterNetPriorityPage::OnDown(void) { int isel; CNetwork * pciNet;
isel = m_lbList.GetCurSel(); ASSERT(isel != LB_ERR);
pciNet = (CNetwork *) m_lbList.GetItemDataPtr(isel); ASSERT_VALID(pciNet);
VERIFY(m_lbList.DeleteString(isel) != LB_ERR); isel = m_lbList.InsertString(isel + 1, pciNet->StrName()); ASSERT(isel != LB_ERR); VERIFY(m_lbList.SetItemDataPtr(isel, pciNet) != LB_ERR); VERIFY(m_lbList.SetCurSel(isel) != LB_ERR);
OnSelChangeList(); m_lbList.SetFocus();
SetModified(TRUE);
} //*** CClusterNetPriorityPage::OnDown()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterNetPriorityPage::OnProperties
//
// Routine Description:
// Handler for the BN_CLICKED message on the Properties push button.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CClusterNetPriorityPage::OnProperties(void) { DisplayProperties();
} //*** CClusterNetPriorityPage::OnProperties()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterNetPriorityPage::FillList
//
// Routine Description:
// Fill the network list.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CClusterNetPriorityPage::FillList(void) { int nIndex; POSITION pos; CNetwork * pciNet; CWaitCursor wc;
ClearNetworkList(); PciCluster()->CollectNetworkPriority(NULL);
pos = LpciNetworkPriority().GetHeadPosition(); while (pos != NULL) { pciNet = (CNetwork *) LpciNetworkPriority().GetNext(pos); ASSERT_VALID(pciNet);
try { nIndex = m_lbList.AddString(pciNet->StrName()); ASSERT(nIndex != LB_ERR); m_lbList.SetItemDataPtr(nIndex, pciNet); pciNet->AddRef(); } // try
catch (...) { // Ignore all errors because there is really nothing we can do.
// Displaying a message isn't really very useful.
} // catch: Anything
} // while: more items in the list
} // CClusterNetPriorityPage::FillList
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterNetPriorityPage::ClearNetworkList
//
// Routine Description:
// Clear the network list and release references to pointers.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CClusterNetPriorityPage::ClearNetworkList(void) { int cItems; int iItem; CNetwork * pciNet;
cItems = m_lbList.GetCount(); for (iItem = 0 ; iItem < cItems ; iItem++) { pciNet = (CNetwork *) m_lbList.GetItemDataPtr(iItem); ASSERT_VALID(pciNet); ASSERT_KINDOF(CNetwork, pciNet); pciNet->Release(); } // for: each item in the list
m_lbList.ResetContent();
} //*** CClusterNetPriorityPage::ClearNetworkList()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResourceDependsPage::DisplayProperties
//
// Routine Description:
// Display properties of the item with the focus.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CClusterNetPriorityPage::DisplayProperties() { int isel; CNetwork * pciNet;
isel = m_lbList.GetCurSel(); ASSERT(isel != LB_ERR);
if (isel != LB_ERR) { // Get the network pointer.
pciNet = (CNetwork *) m_lbList.GetItemDataPtr(isel); ASSERT_VALID(pciNet);
// Set properties of that item.
if (pciNet->BDisplayProperties()) { // Remove the item. If it is still used for internal cluster
// communications, add it back in.
VERIFY(m_lbList.DeleteString(isel) != LB_ERR); if (pciNet->Cnr() & ClusterNetworkRoleInternalUse) { isel = m_lbList.InsertString(isel, pciNet->StrName()); ASSERT(isel != LB_ERR); VERIFY(m_lbList.SetItemDataPtr(isel, pciNet) != LB_ERR); VERIFY(m_lbList.SetCurSel(isel) != LB_ERR); } // if: still used for internal cluster communications
else pciNet->Release();
// Make sure only appropriate buttons are enabled.
OnSelChangeList(); } // if: properties changed
m_lbList.SetFocus(); } // if: found an item with focus
} //*** CClusterNetPriorityPage::DisplayProperties()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterNetPriorityPage::OnContextMenu
//
// Routine Description:
// Handler for the WM_CONTEXTMENU method.
//
// Arguments:
// pWnd Window in which the user right clicked the mouse.
// point Position of the cursor, in screen coordinates.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CClusterNetPriorityPage::OnContextMenu( CWnd * pWnd, CPoint point ) { BOOL bHandled = FALSE; CMenu * pmenu = NULL; CListBox * pListBox = (CListBox *) pWnd; CString strMenuName; CWaitCursor wc;
// If focus is not in the list box, don't handle the message.
if ( pWnd == &m_lbList ) { // Create the menu to display.
try { pmenu = new CMenu; if ( pmenu == NULL ) { AfxThrowMemoryException(); } // if: error allocating memory
if ( pmenu->CreatePopupMenu() ) { UINT nFlags = MF_STRING;
// If there are no items in the list, disable the menu item.
if ( pListBox->GetCount() == 0 ) { nFlags |= MF_GRAYED; } // if: no items in the list
// Add the Properties item to the menu.
strMenuName.LoadString( IDS_MENU_PROPERTIES ); if ( pmenu->AppendMenu( nFlags, ID_FILE_PROPERTIES, strMenuName ) ) { bHandled = TRUE; } // if: successfully added menu item
} // if: menu created successfully
} // try
catch ( CException * pe ) { pe->ReportError(); pe->Delete(); } // catch: CException
} // if: focus is on the list control
if ( bHandled ) { // Display the menu.
if ( ! pmenu->TrackPopupMenu( TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this ) ) { } // if: unsuccessfully displayed the menu
} // if: there is a menu to display
else { CBasePropertyPage::OnContextMenu( pWnd, point ); } // else: no menu to display
delete pmenu;
} //*** CClusterNetPriorityPage::OnContextMenu()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CClusterNetPriorityPage::OnDblClkList
//
// Routine Description:
// Handler method for the NM_DBLCLK message.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CClusterNetPriorityPage::OnDblClkList() { DisplayProperties();
} //*** CClusterNetPriorityPage::OnDblClkList()
|