///////////////////////////////////////////////////////////////////////////// // // 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 \\\\. 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()