///////////////////////////////////////////////////////////////////////////// // // Copyright (c) 1996-2000 Microsoft Corporation // // Module Name: // Disks.cpp // // Abstract: // Implementation of the CPhysDiskParamsPage class. // // Author: // David Potter (davidp) June 28, 1996 // // Revision History: // // Notes: // ///////////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "CluAdmX.h" #include "ExtObj.h" #include "Disks.h" #include "DDxDDv.h" #include "PropList.h" #include "HelpData.h" #include "ExcOper.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CPhysDiskParamsPage property page ///////////////////////////////////////////////////////////////////////////// IMPLEMENT_DYNCREATE(CPhysDiskParamsPage, CBasePropertyPage) ///////////////////////////////////////////////////////////////////////////// // Message Maps BEGIN_MESSAGE_MAP(CPhysDiskParamsPage, CBasePropertyPage) //{{AFX_MSG_MAP(CPhysDiskParamsPage) ON_CBN_SELCHANGE(IDC_PP_DISKS_PARAMS_DISK, OnChangeDisk) //}}AFX_MSG_MAP // TODO: Modify the following lines to represent the data displayed on this page. END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// //++ // // CPhysDiskParamsPage::CPhysDiskParamsPage // // Routine Description: // Default constructor. // // Arguments: // None. // // Return Value: // None. // //-- ///////////////////////////////////////////////////////////////////////////// CPhysDiskParamsPage::CPhysDiskParamsPage(void) : CBasePropertyPage(g_aHelpIDs_IDD_PP_DISKS_PARAMETERS, g_aHelpIDs_IDD_WIZ_DISKS_PARAMETERS) { // TODO: Modify the following lines to represent the data displayed on this page. //{{AFX_DATA_INIT(CPhysDiskParamsPage) m_strDisk = _T(""); //}}AFX_DATA_INIT m_dwSignature = 0; m_pbAvailDiskInfo = NULL; m_cbAvailDiskInfo = 0; m_pbDiskInfo = NULL; m_cbDiskInfo = 0; // Setup the property array. { m_rgProps[epropSignature].Set(REGPARAM_DISKS_SIGNATURE, m_dwSignature, m_dwPrevSignature); } // Setup the property array m_iddPropertyPage = IDD_PP_DISKS_PARAMETERS; m_iddWizardPage = IDD_WIZ_DISKS_PARAMETERS; } //*** CPhysDiskParamsPage::CPhysDiskParamsPage() ///////////////////////////////////////////////////////////////////////////// //++ // // CPhysDiskParamsPage::~CPhysDiskParamsPage // // Routine Description: // Destructor. // // Arguments: // None. // // Return Value: // None. // //-- ///////////////////////////////////////////////////////////////////////////// CPhysDiskParamsPage::~CPhysDiskParamsPage(void) { delete [] m_pbAvailDiskInfo; delete [] m_pbDiskInfo; } //*** CPhysDiskParamsPage::~CPhysDiskParamsPage() ///////////////////////////////////////////////////////////////////////////// //++ // // CPhysDiskParamsPage::HrInit // // Routine Description: // Initialize the page. // // Arguments: // peo [IN OUT] Pointer to the extension object. // // Return Value: // S_OK Page initialized successfully. // hr Page failed to initialize. // //-- ///////////////////////////////////////////////////////////////////////////// HRESULT CPhysDiskParamsPage::HrInit(IN OUT CExtObject * peo) { HRESULT _hr; CWaitCursor _wc; do { // Call the base class method. _hr = CBasePropertyPage::HrInit(peo); if ( FAILED( _hr ) ) { break; } // if: error from base class method // Collect available disk information. BGetAvailableDisks(); // If creating a new resource, select the first disk. // Otherwise, collect information about the selected disk. if (BWizard()) { CLUSPROP_BUFFER_HELPER buf; buf.pb = m_pbAvailDiskInfo; if (m_cbAvailDiskInfo > 0) { while (buf.pSyntax->dw != CLUSPROP_SYNTAX_ENDMARK) { if (BStringFromDiskInfo(buf, m_cbAvailDiskInfo, m_strDisk)) break; ASSERT( (buf.pSyntax->dw == CLUSPROP_SYNTAX_ENDMARK) || (buf.pSyntax->dw == CLUSPROP_SYNTAX_DISK_SIGNATURE)); } // while: more entries in the list } // if: there are available disks } // if: creating a new resource else { // Don't return false because that will prevent the page from showing up. BGetDiskInfo(); // Get the current state of the resource. m_crs = GetClusterResourceState(Peo()->PrdResData()->m_hresource, NULL, NULL, NULL, NULL ); } // else: viewing an existing resource } while ( 0 ); return _hr; } //*** CPhysDiskParamsPage::HrInit() ///////////////////////////////////////////////////////////////////////////// //++ // // CPhysDiskParamsPage::DoDataExchange // // Routine Description: // Do data exchange between the dialog and the class. // // Arguments: // pDX [IN OUT] Data exchange object // // Return Value: // None. // //-- ///////////////////////////////////////////////////////////////////////////// void CPhysDiskParamsPage::DoDataExchange(CDataExchange * pDX) { if (!pDX->m_bSaveAndValidate || !BSaved()) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); // TODO: Modify the following lines to represent the data displayed on this page. //{{AFX_DATA_MAP(CPhysDiskParamsPage) DDX_Control(pDX, IDC_PP_DISKS_PARAMS_DISK, m_cboxDisk); DDX_Text(pDX, IDC_PP_DISKS_PARAMS_DISK, m_strDisk); //}}AFX_DATA_MAP if (pDX->m_bSaveAndValidate) { if (!BBackPressed()) { if (BWizard() && !( (m_strDisk.GetLength() == 0) && (m_crs == ClusterResourceOffline))) { DDV_RequiredText(pDX, IDC_PP_DISKS_PARAMS_DISK, IDC_PP_DISKS_PARAMS_DISK_LABEL, m_strDisk); m_dwSignature = (DWORD)m_cboxDisk.GetItemData(m_cboxDisk.GetCurSel()); ASSERT(m_dwSignature != 0); } // if: not offline with an empty disk string } // if: Back button not pressed } // if: saving data } // if: not saving or haven't saved yet CBasePropertyPage::DoDataExchange(pDX); } //*** CPhysDiskParamsPage::DoDataExchange() ///////////////////////////////////////////////////////////////////////////// //++ // // CPhysDiskParamsPage::OnInitDialog // // Routine Description: // Handler for the WM_INITDIALOG message. // // Arguments: // None. // // Return Value: // TRUE We need the focus to be set for us. // FALSE We already set the focus to the proper control. // //-- ///////////////////////////////////////////////////////////////////////////// BOOL CPhysDiskParamsPage::OnInitDialog(void) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); CBasePropertyPage::OnInitDialog(); // Set the combobox as read-only if not creating a new resource. m_cboxDisk.EnableWindow(BWizard()); // Fill the disks list. FillList(); return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } //*** CPhysDiskParamsPage::OnInitDialog() ///////////////////////////////////////////////////////////////////////////// //++ // // CPhysDiskParamsPage::OnSetActive // // Routine Description: // Handler for the PSN_SETACTIVE message. // // Arguments: // None. // // Return Value: // TRUE Page successfully initialized. // FALSE Page not initialized. // //-- ///////////////////////////////////////////////////////////////////////////// BOOL CPhysDiskParamsPage::OnSetActive(void) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); // Enable/disable the Next/Finish button. if (BWizard()) { if (m_strDisk.GetLength() == 0) EnableNext(FALSE); else EnableNext(TRUE); } // if: enable/disable the Next button return CBasePropertyPage::OnSetActive(); } //*** CPhysDiskParamsPage::OnSetActive() ///////////////////////////////////////////////////////////////////////////// //++ // // CPhysDiskParamsPage::BApplyChanges // // Routine Description: // Apply changes made on the page. // // Arguments: // None. // // Return Value: // TRUE Page successfully applied. // FALSE Error applying page. // //-- ///////////////////////////////////////////////////////////////////////////// BOOL CPhysDiskParamsPage::BApplyChanges(void) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); CWaitCursor wc; if (!( (m_strDisk.GetLength() == 0) && (m_crs == ClusterResourceOffline))) { // Call the base class method. if (!CBasePropertyPage::BApplyChanges()) return FALSE; // Reread the disk info and the available disks. // Ignore errors because we can't do anything about it at this point anyway. BGetAvailableDisks(); BGetDiskInfo(); // Refill the combobox. FillList(); } // if: not offline with an empty disk string return TRUE; } //*** CPhysDiskParamsPage::BApplyChanges() ///////////////////////////////////////////////////////////////////////////// //++ // // CPhysDiskParamsPage::OnChangeDisk // // Routine Description: // Handler for the CBN_SELCHANGE message on the Disks combobox. // // Arguments: // None. // // Return Value: // None. // //-- ///////////////////////////////////////////////////////////////////////////// void CPhysDiskParamsPage::OnChangeDisk(void) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); OnChangeCtrl(); if (BWizard()) { if (m_cboxDisk.GetWindowTextLength() == 0) EnableNext(FALSE); else EnableNext(TRUE); } // if: in a wizard } //*** CPhysDiskParamsPage::OnChangeDisk() ///////////////////////////////////////////////////////////////////////////// //++ // // CPhysDiskParamsPage::BGetAvailableDisks // // Routine Description: // Get the list of disks for this type of resource that can be assigned // to a resource. // // Arguments: // None. // // Return Value: // TRUE The operation was successful. // FALSE The operation failed. // //-- ///////////////////////////////////////////////////////////////////////////// BOOL CPhysDiskParamsPage::BGetAvailableDisks(void) { 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]; dwStatus = ClusterResourceTypeControl( Peo()->Hcluster(), Peo()->PrdResData()->m_strResTypeName, NULL, CLUSCTL_RESOURCE_TYPE_STORAGE_GET_AVAILABLE_DISKS, NULL, 0, pbDiskInfo, cbDiskInfo, &cbDiskInfo ); if (dwStatus == ERROR_MORE_DATA) { delete [] pbDiskInfo; pbDiskInfo = new BYTE[cbDiskInfo]; dwStatus = ClusterResourceTypeControl( Peo()->Hcluster(), Peo()->PrdResData()->m_strResTypeName, NULL, CLUSCTL_RESOURCE_TYPE_STORAGE_GET_AVAILABLE_DISKS, NULL, 0, pbDiskInfo, cbDiskInfo, &cbDiskInfo ); } // if: buffer too small } // try catch (CMemoryException * pme) { pme->Delete(); dwStatus = ERROR_NOT_ENOUGH_MEMORY; } // catch: CMemoryException if (dwStatus != ERROR_SUCCESS) { CNTException nte( dwStatus, IDS_GET_AVAILABLE_DISKS_ERROR, Peo()->PrdResData()->m_strResTypeName, NULL, FALSE /*bAutoDelete*/ ); delete [] pbDiskInfo; nte.ReportError(); nte.Delete(); return FALSE; } // if: error getting disk info delete [] m_pbAvailDiskInfo; m_pbAvailDiskInfo = pbDiskInfo; m_cbAvailDiskInfo = cbDiskInfo; return TRUE; } //*** CPhysDiskParamsPage::BGetAvailableDisks() ///////////////////////////////////////////////////////////////////////////// //++ // // CPhysDiskParamsPage::BGetDiskInfo // // Routine Description: // Get information about the currently selected disk. // // Arguments: // None. // // Return Value: // TRUE The operation was successful. // FALSE The operation failed. // //-- ///////////////////////////////////////////////////////////////////////////// BOOL CPhysDiskParamsPage::BGetDiskInfo(void) { 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]; dwStatus = ClusterResourceControl( Peo()->PrdResData()->m_hresource, NULL, CLUSCTL_RESOURCE_STORAGE_GET_DISK_INFO, NULL, 0, pbDiskInfo, cbDiskInfo, &cbDiskInfo ); if (dwStatus == ERROR_MORE_DATA) { delete [] pbDiskInfo; pbDiskInfo = new BYTE[cbDiskInfo]; dwStatus = ClusterResourceControl( Peo()->PrdResData()->m_hresource, NULL, CLUSCTL_RESOURCE_STORAGE_GET_DISK_INFO, NULL, 0, pbDiskInfo, cbDiskInfo, &cbDiskInfo ); } // if: buffer 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, Peo()->PrdResData()->m_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; } //*** CPhysDiskParamsPage::BGetDiskInfo() ///////////////////////////////////////////////////////////////////////////// //++ // // CPhysDiskParamsPage::BStringFromDiskInfo // // Routine Description: // Convert disk information to a string for display. // // Arguments: // rbuf [IN OUT] Buffer pointer. // cbBuf [IN] Number of bytes in the buffer. // rstr [OUT] String to fill. // pdwSignature [OUT] Signature associated with the disk info being // returned. // // Return Value: // TRUE A string was produced from disk info. // FALSE No string could be produced. // //-- ///////////////////////////////////////////////////////////////////////////// BOOL CPhysDiskParamsPage::BStringFromDiskInfo( IN OUT CLUSPROP_BUFFER_HELPER & rbuf, IN DWORD cbBuf, OUT CString & rstr, OUT DWORD * pdwSignature // = NULL ) const { CString strPartitionInfo; DWORD dwSignature = 0; DWORD cbData; BOOL bDisplay; ASSERT(cbBuf > 0); ASSERT(rbuf.pSyntax->dw != CLUSPROP_SYNTAX_ENDMARK); rstr = _T(""); if (rbuf.pSyntax->dw != CLUSPROP_SYNTAX_ENDMARK) { do { // Calculate the size of the value. cbData = sizeof(*rbuf.pValue) + ALIGN_CLUSPROP(rbuf.pValue->cbLength); ASSERT(cbData <= cbBuf); // Parse the value. if (rbuf.pSyntax->dw == CLUSPROP_SYNTAX_DISK_SIGNATURE) { // Save the signature. dwSignature = rbuf.pDwordValue->dw; ASSERT(dwSignature != 0); } // if: signature else if (rbuf.pSyntax->dw == CLUSPROP_SYNTAX_PARTITION_INFO) { // Add the partition to the string if it is a usable partition // and hasn't been added already. If the resource is offline, // don't check the usable flag. bDisplay = ( rstr.Find(rbuf.pPartitionInfoValue->szDeviceName) == -1 ); if ( bDisplay && ( m_crs == ClusterResourceOnline ) ) { bDisplay = (rbuf.pPartitionInfoValue->dwFlags & CLUSPROP_PIFLAG_USABLE) == CLUSPROP_PIFLAG_USABLE; } // if: resource is online if (bDisplay) { try { strPartitionInfo.Format( (rbuf.pPartitionInfoValue->szVolumeLabel[0] ? _T("%ls (%ls) ") : _T("%ls ")), rbuf.pPartitionInfoValue->szDeviceName, rbuf.pPartitionInfoValue->szVolumeLabel ); rstr += strPartitionInfo; if (pdwSignature != NULL) { _ASSERTE(dwSignature != 0); *pdwSignature = dwSignature; } // if: caller wants signature as well } // 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 should be displayed } // else if: partition info // Advance the buffer pointer rbuf.pb += cbData; cbBuf -= cbData; } while ( (rbuf.pSyntax->dw != CLUSPROP_SYNTAX_ENDMARK) && (rbuf.pSyntax->dw != CLUSPROP_SYNTAX_DISK_SIGNATURE)); } // if: not an endmark return (rstr.GetLength() > 0); } //*** CPhysDiskParamsPage::BStringFromDiskInfo() ///////////////////////////////////////////////////////////////////////////// //++ // // CPhysDiskParamsPage::FillList // // Routine Description: // Fill the list of disks. // // Arguments: // None. // // Return Value: // None. // //-- ///////////////////////////////////////////////////////////////////////////// void CPhysDiskParamsPage::FillList(void) { CString strDisk; DWORD dwSignature; int icbox; // Clear the list first. m_cboxDisk.ResetContent(); // Add the disk info first. if (m_cbDiskInfo > 0) { CLUSPROP_BUFFER_HELPER buf; buf.pb = m_pbDiskInfo; if (BStringFromDiskInfo(buf, m_cbDiskInfo, m_strDisk, &dwSignature)) { ASSERT(dwSignature != 0); icbox = m_cboxDisk.AddString(m_strDisk); m_cboxDisk.SetItemData(icbox, dwSignature); } // if: disk info was found } // if: there is disk info // Now add the available disk info. if (m_cbAvailDiskInfo > 0) { CString strDisk; CLUSPROP_BUFFER_HELPER buf; buf.pb = m_pbAvailDiskInfo; while (buf.pSyntax->dw != CLUSPROP_SYNTAX_ENDMARK) { if (BStringFromDiskInfo(buf, m_cbAvailDiskInfo, strDisk, &dwSignature)) { ASSERT(dwSignature != 0); icbox = m_cboxDisk.AddString(strDisk); m_cboxDisk.SetItemData(icbox, dwSignature); } // if: disk info was found } // while: more entries in the list } // if: there is available disk info // Now select an item in the list. if (m_strDisk.GetLength() > 0) { int nIndex; nIndex = m_cboxDisk.FindStringExact(-1, m_strDisk); m_cboxDisk.SetCurSel(nIndex); } // if: there is a selected item } //*** CPhysDiskParamsPage::FillList()