Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

673 lines
19 KiB

//////////////////////////////////////////////////////////////////////////////
//
// 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