2025-04-27 07:49:33 -04:00

745 lines
19 KiB
C++

//////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2000-2001 Microsoft Corporation
//
// Module Name:
// QuorumDlg.cpp
//
// Maintained By:
// David Potter (DavidP) 03-APR-2001
//
//////////////////////////////////////////////////////////////////////////////
#include "Pch.h"
#include "QuorumDlg.h"
#include "WizardUtils.h"
// provisional constant declaration until we figure out something better
#define UNKNOWN_QUORUM_UID L"Unknown Quorum"
DEFINE_THISCLASS("QuorumDlg");
//////////////////////////////////////////////////////////////////////////////
// Static Function Prototypes
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//++
//
// CQuorumDlg::S_HrDisplayModalDialog
//
// Description:
// Display the dialog box.
//
// Arguments:
// hwndParentIn - Parent window for the dialog box.
// pspIn - Service provider for talking to the middle tier.
// pszClusterNameIn - Name of the cluster.
//
// Return Values:
// S_OK - Operation completed successfully.
//
// Remarks:
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
CQuorumDlg::S_HrDisplayModalDialog(
HWND hwndParentIn
, IServiceProvider * pspIn
, BSTR bstrClusterNameIn
)
{
TraceFunc( "" );
Assert( pspIn != NULL );
Assert( bstrClusterNameIn != NULL );
Assert( SysStringLen( bstrClusterNameIn ) > 0 );
HRESULT hr = S_OK;
INT_PTR dlgResult = IDOK;
// Display the dialog.
{
CQuorumDlg dlg( pspIn, bstrClusterNameIn );
dlgResult = DialogBoxParam(
g_hInstance
, MAKEINTRESOURCE( IDD_QUORUM )
, hwndParentIn
, CQuorumDlg::S_DlgProc
, (LPARAM) &dlg
);
if ( dlgResult == IDOK )
hr = S_OK;
else
hr = S_FALSE;
}
HRETURN( hr );
} //*** CQuorumDlg::S_HrDisplayModalDialog()
//////////////////////////////////////////////////////////////////////////////
//++
//
// IsValidResource
//
// Description:
// Determines whether the resource is a valid selection as a quorum device.
//
// Arguments:
// pResourceIn - the resource in question.
//
// Return Values:
// true - the resource is valid.
// false - the resource is not valid.
//
// Remarks:
// A resource is valid if it is quorum capable and it is not an "unknown" quorum.
//
//--
//////////////////////////////////////////////////////////////////////////////
static bool IsValidResource( IClusCfgManagedResourceInfo * pResourceIn )
{
TraceFunc( "" );
bool fValid = false;
bool fQuorumCapable = false;
bool fUnknownQuorum = false;
BSTR bstrDeviceID = NULL;
HRESULT hr = S_OK;
hr = STHR( pResourceIn->IsQuorumCapable() );
if ( FAILED( hr ) )
{
goto Cleanup;
}
else
{
fQuorumCapable = ( hr == S_OK );
}
hr = THR( pResourceIn->GetUID( &bstrDeviceID ) );
if ( FAILED( hr ) )
{
goto Cleanup;
}
fUnknownQuorum = ( wcscmp( UNKNOWN_QUORUM_UID, bstrDeviceID ) == 0 );
fValid = fQuorumCapable && ( !fUnknownQuorum );
Cleanup:
if ( bstrDeviceID != NULL )
SysFreeString( bstrDeviceID );
RETURN( fValid );
}
//////////////////////////////////////////////////////////////////////////////
//++
//
// CQuorumDlg::CQuorumDlg
//
// Description:
// Constructor.
//
// Arguments:
// pspIn - Service provider for talking to the middle tier.
// pszClusterNameIn - Name of the cluster.
//
// Return Values:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
CQuorumDlg::CQuorumDlg(
IServiceProvider * pspIn
, BSTR bstrClusterNameIn
):
m_rgpResources( NULL )
, m_cValidResources( 0 )
, m_idxQuorumResource( 0 )
, m_hComboBox( NULL )
, m_fQuorumAlreadySet( false )
{
TraceFunc( "" );
Assert( pspIn != NULL );
Assert( bstrClusterNameIn != NULL );
Assert( SysStringLen( bstrClusterNameIn ) > 0 );
// m_hwnd
m_psp = pspIn;
m_psp->AddRef();
m_bstrClusterName = bstrClusterNameIn;
TraceFuncExit();
} //*** CQuorumDlg::CQuorumDlg()
//////////////////////////////////////////////////////////////////////////////
//++
//
// CQuorumDlg::~CQuorumDlg
//
// Description:
// Destructor.
//
// Arguments:
// None.
//
// Return Values:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
CQuorumDlg::~CQuorumDlg( void )
{
TraceFunc( "" );
size_t idxResource = 0;
for ( idxResource = 0; idxResource < m_cValidResources; idxResource += 1 )
m_rgpResources[ idxResource ]->Release();
delete [] m_rgpResources;
if ( m_psp != NULL )
{
m_psp->Release();
}
TraceFuncExit();
} //*** CQuorumDlg::~CQuorumDlg()
//////////////////////////////////////////////////////////////////////////////
//++
//
// CQuorumDlg::S_DlgProc
//
// Description:
// Dialog proc for the Quorum dialog box.
//
// Arguments:
// hwndDlgIn - Dialog box window handle.
// nMsgIn - Message ID.
// wParam - Message-specific parameter.
// lParam - Message-specific parameter.
//
// Return Values:
// TRUE - Message has been handled.
// FALSE - Message has not been handled yet.
//
// Remarks:
// It is expected that this dialog box is invoked by a call to
// DialogBoxParam() with the lParam argument set to the address of the
// instance of this class.
//
//--
//////////////////////////////////////////////////////////////////////////////
INT_PTR
CALLBACK
CQuorumDlg::S_DlgProc(
HWND hwndDlgIn
, UINT nMsgIn
, WPARAM wParam
, LPARAM lParam
)
{
// Don't do TraceFunc because every mouse movement
// will cause this function to be called.
WndMsg( hwndDlgIn, nMsgIn, wParam, lParam );
LRESULT lr = FALSE;
CQuorumDlg * pdlg;
//
// Get a pointer to the class.
//
if ( nMsgIn == WM_INITDIALOG )
{
SetWindowLongPtr( hwndDlgIn, GWLP_USERDATA, lParam );
pdlg = reinterpret_cast< CQuorumDlg * >( lParam );
pdlg->m_hwnd = hwndDlgIn;
}
else
{
pdlg = reinterpret_cast< CQuorumDlg * >( GetWindowLongPtr( hwndDlgIn, GWLP_USERDATA ) );
}
if ( pdlg != NULL )
{
Assert( hwndDlgIn == pdlg->m_hwnd );
switch( nMsgIn )
{
case WM_INITDIALOG:
lr = pdlg->OnInitDialog();
break;
case WM_COMMAND:
lr = pdlg->OnCommand( HIWORD( wParam ), LOWORD( wParam ), reinterpret_cast< HWND >( lParam ) );
break;
// no default clause needed
} // switch: nMsgIn
} // if: page is specified
return lr;
} //*** CQuorumDlg::S_DlgProc()
//////////////////////////////////////////////////////////////////////////////
//++
//
// CQuorumDlg::OnInitDialog
//
// Description:
// Handler for the WM_INITDIALOG message.
//
// Arguments:
// None.
//
// Return Values:
// TRUE Focus has been set.
// FALSE Focus has not been set.
//--
//////////////////////////////////////////////////////////////////////////////
LRESULT
CQuorumDlg::OnInitDialog( void )
{
TraceFunc( "" );
LRESULT lr = TRUE; // did set focus
HWND hComboBox = NULL;
HRESULT hr = S_OK;
DWORD sc;
size_t idxResource = 0;
BSTR bstrResourceName = NULL;
// create resource list
hr = THR( HrCreateResourceList() );
if ( FAILED( hr ) )
goto Error;
// get combo box handle
m_hComboBox = GetDlgItem( m_hwnd, IDC_QUORUM_CB_QUORUM );
if ( m_hComboBox == NULL )
{
sc = TW32( GetLastError() );
hr = HRESULT_FROM_WIN32( sc );
goto Error;
}
// fill combo box
for ( idxResource = 0 ; idxResource < m_cValidResources ; idxResource++ )
{
hr = THR( m_rgpResources[ idxResource ]->GetName( &bstrResourceName ) );
if ( FAILED( hr ) )
{
goto Error;
}
TraceMemoryAddBSTR( bstrResourceName );
sc = (DWORD) SendMessage( m_hComboBox, CB_ADDSTRING, 0, reinterpret_cast<LPARAM>( bstrResourceName ) );
if ( ( sc == CB_ERR ) || ( sc == CB_ERRSPACE ) )
{
hr = HRESULT_FROM_WIN32( TW32( sc ) );
goto Error;
}
TraceSysFreeString( bstrResourceName );
bstrResourceName = NULL;
// - remember which is quorum resource
hr = STHR( m_rgpResources[ idxResource ]->IsQuorumDevice() );
if ( FAILED( hr ) )
{
goto Error;
}
else if ( hr == S_OK )
{
m_idxQuorumResource = idxResource;
m_fQuorumAlreadySet = true;
}
} // for: each resource
// set combo box selection to current quorum resource
sc = (DWORD) SendMessage( m_hComboBox, CB_SETCURSEL, m_idxQuorumResource, 0 );
if ( sc == CB_ERR )
{
hr = HRESULT_FROM_WIN32( TW32( sc ) );
goto Error;
}
//
// Update the buttons based on what is selected.
//
UpdateButtons();
//
// Set focus to the combo box.
//
SetFocus( m_hComboBox );
goto Cleanup;
Error:
HrMessageBoxWithStatus(
m_hwnd
, IDS_ERR_RESOURCE_GATHER_FAILURE_TITLE
, IDS_ERR_RESOURCE_GATHER_FAILURE_TEXT
, hr
, 0
, MB_OK | MB_ICONERROR
, 0
);
EndDialog( m_hwnd, IDCANCEL ); // show message box?
lr = FALSE;
goto Cleanup;
Cleanup:
TraceSysFreeString( bstrResourceName );
RETURN( lr );
} //*** CQuorumDlg::OnInitDialog()
//////////////////////////////////////////////////////////////////////////////
//++
//
// CQuorumDlg::OnCommand
//
// Description:
// Handler for the WM_COMMAND message.
//
// Arguments:
// idNotificationIn - Notification code.
// idControlIn - Control ID.
// hwndSenderIn - Handle for the window that sent the message.
//
// Return Values:
// TRUE - Message has been handled.
// FALSE - Message has not been handled yet.
//
//--
//////////////////////////////////////////////////////////////////////////////
LRESULT
CQuorumDlg::OnCommand(
UINT idNotificationIn
, UINT idControlIn
, HWND hwndSenderIn
)
{
TraceFunc( "" );
LRESULT lr = FALSE;
size_t idxCurrentSelection = 0;
HRESULT hr = S_OK;
switch ( idControlIn )
{
case IDOK:
// get selection from combo box
idxCurrentSelection = SendMessage( m_hComboBox, CB_GETCURSEL, 0, 0 );
if ( idxCurrentSelection == CB_ERR )
{
hr = HRESULT_FROM_WIN32( TW32( CB_ERR ) );
goto Error;
}
// if original quorum resource is different, or had not been set,
if ( ( idxCurrentSelection != m_idxQuorumResource ) || !m_fQuorumAlreadySet )
{
// - clear original quorum resource
hr = THR( m_rgpResources[ m_idxQuorumResource ]->SetQuorumedDevice( FALSE ) );
if ( FAILED( hr ) )
{
goto Error;
}
// - set new quorum resource
hr = THR( m_rgpResources[ idxCurrentSelection ]->SetQuorumedDevice( TRUE ) );
if ( FAILED( hr ) )
{
// try to restore previous state
THR( m_rgpResources[ m_idxQuorumResource ]->SetQuorumedDevice( TRUE ) );
goto Error;
}
hr = THR( m_rgpResources[ idxCurrentSelection ]->SetManaged( TRUE ) );
if ( FAILED( hr ) )
{
// try to restore previous state
THR( m_rgpResources[ idxCurrentSelection ]->SetQuorumedDevice( FALSE ) );
THR( m_rgpResources[ m_idxQuorumResource ]->SetQuorumedDevice( TRUE ) );
goto Error;
}
// - end with IDOK
EndDialog( m_hwnd, IDOK );
}
else // (combo box selection is same as original)
{
// - end with IDCANCEL
EndDialog( m_hwnd, IDCANCEL );
}
break;
case IDCANCEL:
EndDialog( m_hwnd, IDCANCEL );
break;
} // switch: idControlIn
goto Cleanup;
Error:
HrMessageBoxWithStatus(
m_hwnd
, IDS_ERR_QUORUM_COMMIT_FAILURE_TITLE
, IDS_ERR_QUORUM_COMMIT_FAILURE_TEXT
, hr
, 0
, MB_OK | MB_ICONERROR
, 0
);
goto Cleanup;
Cleanup:
RETURN( lr );
} //*** CQuorumDlg::OnCommand()
//////////////////////////////////////////////////////////////////////////////
//++
//
// CQuorumDlg::HrCreateResourceList
//
// Description:
// Allocates and fills m_rgpResources array with quorum capable and
// joinable resources, and sets m_idxQuorumResource to the index of the
// resource that's currently the quorum resource.
//
// Supposedly at least one quorum capable and joinable resource always
// exists, and exactly one is marked as the quorum resource.
//
// Arguments:
// None.
//
// Return Values:
// S_OK - Success.
// S_FALSE - Didn't find current quorum resource.
// E_OUTOFMEMORY - Couldn't allocate memory for the list.
//
// Other possible error values from called methods.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT
CQuorumDlg::HrCreateResourceList( void )
{
TraceFunc( "" );
HRESULT hr = S_OK;
IObjectManager * pom = NULL;
IUnknown * punkEnum = NULL;
IUnknown * punkCluster = NULL;
IEnumClusCfgManagedResources * peccmr = NULL;
OBJECTCOOKIE cookieDummy;
OBJECTCOOKIE cookieCluster;
size_t idxResCurrent = 0;
ULONG cFetchedResources = 0;
DWORD cTotalResources = 0;
//
// get object manager from service provider
//
Assert( m_psp != NULL );
hr = THR( m_psp->TypeSafeQS( CLSID_ObjectManager, IObjectManager, &pom ) );
if ( FAILED( hr ) )
{
goto Cleanup;
}
//
// get resource enumerator from object manager
//
hr = THR( pom->FindObject( CLSID_ClusterConfigurationType,
NULL,
m_bstrClusterName,
DFGUID_ClusterConfigurationInfo,
&cookieCluster,
&punkCluster
) );
if ( FAILED( hr ) )
{
goto Cleanup;
}
hr = THR( pom->FindObject( CLSID_ManagedResourceType,
cookieCluster,
NULL,
DFGUID_EnumManageableResources,
&cookieDummy,
&punkEnum
) );
if ( FAILED( hr ) )
{
goto Cleanup;
}
hr = THR( punkEnum->TypeSafeQI( IEnumClusCfgManagedResources, &peccmr ) );
if ( FAILED( hr ) )
{
goto Cleanup;
}
//
// find out how many resources exist
//
hr = THR( peccmr->Count( &cTotalResources ) );
if ( FAILED( hr ) )
{
goto Cleanup;
}
//
// allocate memory for resources
//
m_rgpResources = new IClusCfgManagedResourceInfo*[ cTotalResources ];
if ( m_rgpResources == NULL )
{
hr = THR( E_OUTOFMEMORY );
goto Cleanup;
}
for ( idxResCurrent = 0 ; idxResCurrent < cTotalResources ; idxResCurrent++ )
{
m_rgpResources[ idxResCurrent ] = NULL;
}
//
// copy resources into array
//
hr = THR( peccmr->Next( cTotalResources, m_rgpResources, &cFetchedResources ) );
if ( FAILED( hr ) )
{
goto Cleanup;
}
Assert( cFetchedResources == cTotalResources ); // if not, something's wrong with the enum
cTotalResources = min( cTotalResources, cFetchedResources ); // playing it safe
//
// filter out invalid resources
//
for ( idxResCurrent = 0 ; idxResCurrent < cTotalResources ; idxResCurrent++ )
{
if ( !IsValidResource( m_rgpResources[ idxResCurrent ] ) )
{
m_rgpResources[ idxResCurrent ]->Release();
m_rgpResources[ idxResCurrent ] = NULL;
}
}
//
// compact array; might leave some non-null pointers after end,
// so always use m_cValidResources to determine length hereafter
//
for ( idxResCurrent = 0 ; idxResCurrent < cTotalResources ; idxResCurrent++ )
{
if ( m_rgpResources[ idxResCurrent ] != NULL )
{
m_rgpResources[ m_cValidResources++ ] = m_rgpResources[ idxResCurrent ];
}
}
Cleanup:
if ( pom != NULL )
{
pom->Release();
}
if ( punkCluster != NULL )
{
punkCluster->Release();
}
if ( punkEnum != NULL )
{
punkEnum->Release();
}
if ( peccmr != NULL )
{
peccmr->Release();
}
HRETURN( hr );
} //*** CQuorumDlg::HrCreateResourceList()
//////////////////////////////////////////////////////////////////////////////
//++
//
// CDetailsDlg::UpdateButtons
//
// Description:
// Update the OK and Cancel buttons.
//
// Arguments:
// None.
//
// Return Values:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
void
CQuorumDlg::UpdateButtons( void )
{
TraceFunc( "" );
BOOL fEnableOK;
LRESULT lrCurSel;
lrCurSel = SendMessage( GetDlgItem( m_hwnd, IDC_QUORUM_CB_QUORUM ), CB_GETCURSEL, 0, 0 );
fEnableOK = ( lrCurSel != CB_ERR );
EnableWindow( GetDlgItem( m_hwnd, IDOK ), fEnableOK );
} //*** CQuorumDlg::UpdateButtons()