|
|
//////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2000-2001 Microsoft Corporation
//
// Module Name:
// SelNodesPageCommon.cpp
//
// Maintained By:
// David Potter (DavidP) 05-JUL-2001
//
//////////////////////////////////////////////////////////////////////////////
#include "Pch.h"
#include "SelNodesPageCommon.h"
#include "WizardUtils.h"
#include "DelimitedIterator.h"
DEFINE_THISCLASS("CSelNodesPageCommon");
//////////////////////////////////////////////////////////////////////////////
//++
//
// CSelNodesPageCommon::CSelNodesPageCommon
//
// Description:
// Constructor.
//
// Arguments:
// idcBrowseButtonIn - ID of the Browse pushbutton control.
//
// Return Values:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
CSelNodesPageCommon::CSelNodesPageCommon( void ) : m_hwnd( NULL ) , m_cfDsObjectPicker( 0 ) { TraceFunc( "" );
TraceFuncExit();
} //*** CSelNodesPageCommon::CSelNodesPageCommon
//////////////////////////////////////////////////////////////////////////////
//++
//
// CSelNodesPageCommon::~CSelNodesPageCommon
//
// Description:
// Destructor.
//
// Arguments:
// None.
//
// Return Values:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
CSelNodesPageCommon::~CSelNodesPageCommon( void ) { TraceFunc( "" );
TraceFuncExit();
} //*** CSelNodesPageCommon::~CSelNodesPageCommon
//////////////////////////////////////////////////////////////////////////////
//++
//
// CSelNodesPageCommon::OnInitDialog
//
// Description:
// Handle the WM_INITDIALOG window message.
//
// Arguments:
// hDlgIn
// pccwIn
//
// Return Values:
// FALSE - Didn't set the focus.
//
//-
//////////////////////////////////////////////////////////////////////////////
LRESULT CSelNodesPageCommon::OnInitDialog( HWND hDlgIn , CClusCfgWizard* pccwIn ) { TraceFunc( "" ); Assert( m_hwnd == NULL ); Assert( hDlgIn != NULL );
LRESULT lr = FALSE; // Didn't set the focus.
m_hwnd = hDlgIn;
//
// Get the Object Picker clipboard format.
// Enable or disable the Browse button based on the success of that operation.
//
m_cfDsObjectPicker = RegisterClipboardFormat( CFSTR_DSOP_DS_SELECTION_LIST ); if ( m_cfDsObjectPicker == 0 ) { TW32( GetLastError() ); //
// If registering the clipboard format fails, then disable the Browse
// button.
//
EnableWindow( GetDlgItem( hDlgIn, IDC_SELNODE_PB_BROWSE ), FALSE );
} // if: failed to get the object picker clipboard format
THR( HrInitNodeSelections( pccwIn ) );
RETURN( lr );
} //*** CSelNodesPageCommon::OnInitDialog
//////////////////////////////////////////////////////////////////////////////
//++
//
// CSelNodesPageCommon::HrBrowse
//
// Description:
// Browse for a computer or multiple computers using the Object Picker.
//
// Arguments:
// fMultipleNodesIn - TRUE = allow multiple nodes to be selected.
//
// Return Values:
// S_OK
// Other HRESULT values.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT CSelNodesPageCommon::HrBrowse( bool fMultipleNodesIn ) { TraceFunc( "" ); Assert( m_hwnd != NULL );
HRESULT hr = S_OK; IDsObjectPicker * piop = NULL; IDataObject * pido = NULL; HCURSOR hOldCursor = NULL;
hOldCursor = SetCursor( LoadCursor( g_hInstance, IDC_WAIT ) );
// Create an instance of the object picker.
hr = THR( CoCreateInstance( CLSID_DsObjectPicker, NULL, CLSCTX_INPROC_SERVER, IID_IDsObjectPicker, (void **) &piop ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if:
// Initialize the object picker instance.
hr = THR( HrInitObjectPicker( piop, fMultipleNodesIn ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if:
// Restore the old cursor.
SetCursor( hOldCursor ); hOldCursor = NULL;
// Invoke the modal dialog.
hr = THR( piop->InvokeDialog( m_hwnd, &pido ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if:
if ( hr == S_OK ) { hr = THR( HrGetSelections( pido, fMultipleNodesIn ) ); } // if:
else if ( hr == S_FALSE ) { hr = S_OK; // don't want to squawk in the caller...
} // else if:
Cleanup:
if ( pido != NULL ) { pido->Release(); } // if:
if ( piop != NULL ) { piop->Release(); } // if:
if ( hOldCursor != NULL ) { SetCursor( hOldCursor ); }
HRETURN( hr );
} //*** CSelNodesPageCommon::HrBrowse
//////////////////////////////////////////////////////////////////////////////
//++
//
// CSelNodesPageCommon::HrInitObjectPicker
//
// Description:
// Initialize the Object Picker dialog.
//
// Arguments:
// piopIn - IDsObjectPicker
// fMultipleNodesIn - TRUE = allow multiple nodes to be selected.
//
// Return Values:
// HRESULT values.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT CSelNodesPageCommon::HrInitObjectPicker( IDsObjectPicker * piopIn , bool fMultipleNodesIn ) { TraceFunc( "" ); Assert( piopIn != NULL );
DSOP_SCOPE_INIT_INFO rgScopeInit[ 1 ]; DSOP_INIT_INFO iiInfo;
ZeroMemory( rgScopeInit, sizeof( rgScopeInit ) );
rgScopeInit[ 0 ].cbSize = sizeof( DSOP_SCOPE_INIT_INFO ); rgScopeInit[ 0 ].flType = DSOP_SCOPE_TYPE_UPLEVEL_JOINED_DOMAIN | DSOP_SCOPE_TYPE_DOWNLEVEL_JOINED_DOMAIN; rgScopeInit[ 0 ].flScope = DSOP_SCOPE_FLAG_STARTING_SCOPE;
rgScopeInit[ 0 ].FilterFlags.Uplevel.flBothModes = DSOP_FILTER_COMPUTERS; rgScopeInit[ 0 ].FilterFlags.flDownlevel = DSOP_DOWNLEVEL_FILTER_COMPUTERS;
ZeroMemory( &iiInfo, sizeof( iiInfo ) );
iiInfo.cbSize = sizeof( iiInfo ); iiInfo.pwzTargetComputer = NULL; iiInfo.cDsScopeInfos = 1; iiInfo.aDsScopeInfos = rgScopeInit;
if ( fMultipleNodesIn ) { iiInfo.flOptions = DSOP_FLAG_MULTISELECT; } else { iiInfo.flOptions = 0; }
HRETURN( piopIn->Initialize( &iiInfo ) );
} //*** CSelNodesPageCommon::HrInitObjectPicker
//////////////////////////////////////////////////////////////////////////////
//++
//
// CSelNodesPageCommon::HrGetSelections
//
// Description:
// Get selections from the Object Picker dialog.
//
// Arguments:
// pidoIn - IDataObject
// fMultipleNodesIn - TRUE = allow multiple nodes to be selected.
//
// Return Values:
// S_OK
// E_OUTOFMEMORY
// Other HRESULT values.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT CSelNodesPageCommon::HrGetSelections( IDataObject * pidoIn , bool fMultipleNodesIn ) { TraceFunc( "" ); Assert( pidoIn != NULL ); Assert( m_hwnd != NULL );
HRESULT hr; STGMEDIUM stgmedium = { TYMED_HGLOBAL, NULL, NULL }; FORMATETC formatetc = { (CLIPFORMAT) m_cfDsObjectPicker, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; PDS_SELECTION_LIST pds = NULL; DWORD sc; HWND hwndEdit = GetDlgItem( m_hwnd, IDC_SELNODE_E_COMPUTERNAME ); BSTR bstrSelectionList = NULL; BSTR bstrOldSelectionList = NULL;
//
// Get the data from the data object.
//
hr = THR( pidoIn->GetData( &formatetc, &stgmedium ) ); if ( FAILED( hr ) ) { goto Cleanup; }
pds = (PDS_SELECTION_LIST) GlobalLock( stgmedium.hGlobal ); if ( pds == NULL ) { sc = TW32( GetLastError() ); hr = HRESULT_FROM_WIN32( sc ); goto Cleanup; } // if:
//
// Construct the string to write into the edit control.
//
Assert( pds->cItems > 0 );
if ( ! fMultipleNodesIn ) { Assert( pds->cItems == 1 ); Edit_SetText( hwndEdit, pds->aDsSelection[ 0 ].pwzName ); } // if: multiple items are NOT supported
else { ULONG idx;
for ( idx = 0 ; idx < pds->cItems; idx++ ) { if ( bstrSelectionList == NULL ) // First name in list.
{ bstrSelectionList = TraceSysAllocString( pds->aDsSelection[ idx ].pwzName ); if ( bstrSelectionList == NULL ) { hr = THR( E_OUTOFMEMORY ); goto Cleanup; } } else // Append another name to non-empty list.
{ TraceSysFreeString( bstrOldSelectionList ); bstrOldSelectionList = bstrSelectionList; bstrSelectionList = NULL; hr = THR( HrFormatStringIntoBSTR( L"%1!ws!; %2!ws!" , &bstrSelectionList , bstrOldSelectionList , pds->aDsSelection[ idx ].pwzName ) ); if ( FAILED( hr ) ) { goto Cleanup; } } // else: append name to non-empty list.
} // for each item in list
Edit_SetText( hwndEdit, bstrSelectionList ); } // else: multiple items are supported
goto Cleanup;
Cleanup:
TraceSysFreeString( bstrSelectionList ); TraceSysFreeString( bstrOldSelectionList );
if ( pds != NULL ) { GlobalUnlock( stgmedium.hGlobal ); } // if:
if ( stgmedium.hGlobal != NULL ) { ReleaseStgMedium( &stgmedium ); } // if:
HRETURN( hr );
} //*** CSelNodesPageCommon::HrGetSelections
//////////////////////////////////////////////////////////////////////////////
//++
//
// CSelNodesPageCommon::HrInitNodeSelections
//
// Description:
// Validate node selections the wizard had on startup, and populate the
// page's controls appropriately.
//
// Arguments:
// pccwIn - The wizard containing this page.
//
// Return Values:
// S_OK
// E_OUTOFMEMORY
// Other HRESULT values.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT CSelNodesPageCommon::HrInitNodeSelections( CClusCfgWizard* pccwIn ) { TraceFunc( "" );
HRESULT hr = S_OK; BSTR bstrNodeName = NULL; BSTR bstrComputerName = NULL; BSTR bstrBadNodeList = NULL; BSTR bstrLocalDomain = NULL; BSTR bstrShortName = NULL; bool fDefaultToLocalMachine = true; size_t cNodes = 0;
//
// Filter out any pre-loaded node FQDNs with bad domains.
//
hr = THR( pccwIn->HrFilterNodesWithBadDomains( &bstrBadNodeList ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if
if ( bstrBadNodeList != NULL ) { fDefaultToLocalMachine = false; // Give subclasses a look at the whole list.
OnFilteredNodesWithBadDomains( bstrBadNodeList );
// Loop through the list, notifying the user of each invalid node.
// This is destroys the list as it walks through it, so writing the
// list to the edit box needs to happen first.
{ CDelimitedIterator it( L" ,;", bstrBadNodeList, SysStringLen( bstrBadNodeList ) ); while ( it.Current() != NULL ) { THR( HrMessageBoxWithStatusString( m_hwnd , IDS_ERR_VALIDATING_NAME_TITLE , IDS_ERR_VALIDATING_NAME_TEXT , IDS_ERR_HOST_DOMAIN_DOESNT_MATCH_CLUSTER , 0 , MB_OK | MB_ICONSTOP , NULL , it.Current() ) );
// Give subclasses a look at the bad node.
OnProcessedNodeWithBadDomain( it.Current() ); it.Next(); }; // for each bad node
} // Notify user of each bad node.
} // if: some nodes have bad domains
//
// Process any remaining valid nodes.
//
hr = THR( pccwIn->HrGetNodeCount( &cNodes ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if
if ( cNodes > 0 ) { for ( size_t idxNode = 0; idxNode < cNodes; ++idxNode ) { hr = THR( pccwIn->HrGetNodeName( idxNode, &bstrNodeName ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if
hr = THR( HrGetFQNDisplayName( bstrNodeName, &bstrShortName ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if
// Give subclasses a look at the good node.
OnProcessedValidNode( bstrShortName );
TraceSysFreeString( bstrNodeName ); bstrNodeName = NULL; TraceSysFreeString( bstrShortName ); bstrShortName = NULL; } // for each valid node.
fDefaultToLocalMachine = false; } // if any valid nodes remain.
//
// Decide whether defaulting to the local machine is appropriate at this time.
//
if ( fDefaultToLocalMachine ) { DWORD dwStatus; DWORD dwClusterState;
//
// If the node is already in a cluster, don't have it default in the edit box.
// If there is an error getting the "NodeClusterState", then default the node
// name (it could be in the middle of cleaning up the node).
//
dwStatus = TW32( GetNodeClusterState( NULL, &dwClusterState ) ); fDefaultToLocalMachine = ( ( dwStatus != ERROR_SUCCESS ) || ( dwClusterState == ClusterStateNotConfigured ) );
if ( !fDefaultToLocalMachine ) { goto Cleanup; } // if
//
// ...but don't default if the local machine is not in the cluster's domain.
//
hr = THR( HrGetComputerName( ComputerNamePhysicalDnsDomain , &bstrLocalDomain , TRUE // fBestEffortIn
) ); if ( FAILED( hr ) ) { goto Cleanup; } // if
hr = STHR( pccwIn->HrIsCompatibleNodeDomain( bstrLocalDomain ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if
fDefaultToLocalMachine = ( hr == S_OK ); if ( !fDefaultToLocalMachine ) { goto Cleanup; } // if
//
// Now have cleared all the obstacles to defaulting to the local machine--hooray!
//
hr = THR( HrGetComputerName( ComputerNameDnsHostname , &bstrComputerName , TRUE // fBestEffortIn
) ); if ( FAILED( hr ) ) { goto Cleanup; } // if
THR( HrSetDefaultNode( bstrComputerName ) ); } // if defaulting to local machine is still an option.
Cleanup:
TraceSysFreeString( bstrNodeName ); TraceSysFreeString( bstrComputerName ); TraceSysFreeString( bstrBadNodeList ); TraceSysFreeString( bstrLocalDomain ); TraceSysFreeString( bstrShortName );
HRETURN( hr );
} //*** CSelNodesPageCommon::HrInitNodeSelections
//////////////////////////////////////////////////////////////////////////////
//++
//
// CSelNodesPageCommon::OnFilteredNodesWithBadDomains
//
// Description:
// Tells the subclass that the wizard had nodes with bad domains, and
// allows the subclass to inspect the list before the base class
// iterates through them.
//
// Arguments:
// pwcszNodeListIn
// The nodes with clashing domains, delimited by spaces, commas, or
// semicolons.
//
// Return Values:
// None.
//
// Remarks:
// This do-nothing default implementation allows subclasses
// to avoid having to implement do-nothing responses themselves if they
// don't want to do anything with the whole list at once.
//
//--
//////////////////////////////////////////////////////////////////////////////
void CSelNodesPageCommon::OnFilteredNodesWithBadDomains( PCWSTR pwcszNodeListIn ) { UNREFERENCED_PARAMETER( pwcszNodeListIn ); } //*** CSelNodesPageCommon::OnFilteredNodesWithBadDomains
//////////////////////////////////////////////////////////////////////////////
//++
//
// CSelNodesPageCommon::OnProcessedNodeWithBadDomain
//
// Description:
// Allows the subclass to process each node in the list of nodes with
// bad domains as the base class iterates through it.
//
// Arguments:
// pwcszNodeNameIn
// The node with a clashing domain.
//
// Return Values:
// None.
//
// Remarks:
// The base class notifies the user of each bad node name before calling
// this method, so the base class provides also this default do-nothing
// implementation for subclasses that don't need to do anything more.
//--
//////////////////////////////////////////////////////////////////////////////
void CSelNodesPageCommon::OnProcessedNodeWithBadDomain( PCWSTR pwcszNodeNameIn ) { UNREFERENCED_PARAMETER( pwcszNodeNameIn ); } //*** CSelNodesPageCommon::OnProcessedNodeWithBadDomain
//////////////////////////////////////////////////////////////////////////////
//++
//
// CSelNodesPageCommon::OnProcessedValidNode
//
// Description:
// Allows the subclass to process each node remaining in the wizard's
// list after those with bad domains have been removed.
//
// Arguments:
// pwcszNodeNameIn
// The IP address or hostname (NOT the FQDN) of a valid node in
// the wizard's list.
//
// Return Values:
// None.
//
// Remarks:
// This default do-nothing implementation allows subclasses to
// ignore the node if they choose.
//
//--
//////////////////////////////////////////////////////////////////////////////
void CSelNodesPageCommon::OnProcessedValidNode( PCWSTR pwcszNodeNameIn ) { UNREFERENCED_PARAMETER( pwcszNodeNameIn ); } //*** CSelNodesPageCommon::OnProcessedValidNode
|