////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2000-2001 Microsoft Corporation // // Module Name: // CBCAInterface.cpp // // Description: // This file contains the implementation of the CBCAInterface // class. // // Documentation: // TODO: fill in pointer to external documentation // // Header File: // CBCAInterface.h // // Maintained By: // Vij Vasu (VVasu) 07-MAR-2000 // ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // Include Files ////////////////////////////////////////////////////////////////////////////// // The precompiled header for this library #include "pch.h" // The header file for this class #include "CBCAInterface.h" // For TraceInterface #include "CITracker.h" // Needed by Dll.h #include "CFactory.h" // For g_cObjects #include "Dll.h" // For the CBaseClusterForm class #include "CBaseClusterForm.h" // For the CBaseClusterJoin class #include "CBaseClusterJoin.h" // For the CBaseClusterCleanup class #include "CBaseClusterCleanup.h" // For the exception classes #include "Exceptions.h" ////////////////////////////////////////////////////////////////////////////// // Macro Definitions ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // Constant Definitions ////////////////////////////////////////////////////////////////////////////// DEFINE_THISCLASS( "CBCAInterface" ); ////////////////////////////////////////////////////////////////////////////// //++ // // CBCAInterface::CBCAInterface( void ) // // Description: // Constructor of the CBCAInterface class. This initializes // the m_cRef variable to 1 instead of 0 to account of possible // QueryInterface failure in DllGetClassObject. // // Arguments: // None. // // Return Value: // None. // // Remarks: // None. // //-- ////////////////////////////////////////////////////////////////////////////// CBCAInterface::CBCAInterface( void ) : m_cRef( 1 ) , m_fCommitComplete( false ) , m_fRollbackPossible( false ) , m_lcid( LOCALE_SYSTEM_DEFAULT ) , m_fCallbackSupported( false ) { BCATraceScope( "" ); // Increment the count of components in memory so the DLL hosting this // object cannot be unloaded. InterlockedIncrement( &g_cObjects ); BCATraceMsg1( "Component count = %d.", g_cObjects ); } //*** CBCAInterface::CBCAInterface ////////////////////////////////////////////////////////////////////////////// //++ // // CBCAInterface::~CBCAInterface( void) // // Description: // Destructor of the CBCAInterface class. // // Arguments: // None. // // Return Value: // None. // // Remarks: // None. // //-- ////////////////////////////////////////////////////////////////////////////// CBCAInterface::~CBCAInterface( void ) { BCATraceScope( "" ); // There's going to be one less component in memory. Decrement component count. InterlockedDecrement( &g_cObjects ); BCATraceMsg1( "Component count = %d.", g_cObjects ); } //*** CBCAInterface::~CBCAInterface ////////////////////////////////////////////////////////////////////////////// //++ // // HRESULT // CBCAInterface::S_HrCreateInstance( // IUnknown ** ppunkOut // ) // // Description: // Creates a CBCAInterface instance. // // Arguments: // ppunkOut // The IUnknown interface of the new object. // // Return Values: // S_OK // Success. // // E_OUTOFMEMORY // Not enough memory to create the object. // // other HRESULTs // Object initialization failed. // //-- ////////////////////////////////////////////////////////////////////////////// HRESULT CBCAInterface::S_HrCreateInstance( IUnknown ** ppunkOut ) { BCATraceScope( "" ); HRESULT hr = E_INVALIDARG; CBCAInterface * pbcaInterface; pbcaInterface = new CBCAInterface(); if ( pbcaInterface != NULL ) { hr = THR( pbcaInterface->QueryInterface( IID_IUnknown , reinterpret_cast< void ** >( ppunkOut ) ) ); pbcaInterface->Release( ); } // if: error allocating object else { hr = THR( E_OUTOFMEMORY ); } // else: out of memory BCATraceMsg1( "*ppunkOut = %p.", *ppunkOut ); BCATraceMsg1( "hr = %#08x", hr ); return hr; } //*** CBCAInterface::S_HrCreateInstance() ////////////////////////////////////////////////////////////////////////////// //++ // // STDMETHODIMP_( ULONG ) // CBCAInterface::AddRef() // // Description: // Increment the reference count of this object by one. // // Arguments: // None. // // Return Value: // The new reference count. // // Remarks: // None. // //-- ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP_( ULONG ) CBCAInterface::AddRef( void ) { BCATraceScope( "[IUnknown]" ); InterlockedIncrement( &m_cRef ); BCATraceMsg1( "m_cRef = %d", m_cRef ); return m_cRef; } //*** CBCAInterface::AddRef() ////////////////////////////////////////////////////////////////////////////// //++ // // STDMETHODIMP_( ULONG ) // CBCAInterface::Release() // // Description: // Decrement the reference count of this object by one. // // Arguments: // None. // // Return Value: // The new reference count. // // Remarks: // None. // //-- ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP_( ULONG ) CBCAInterface::Release( void ) { BCATraceScope( "[IUnknown]" ); InterlockedDecrement( &m_cRef ); BCATraceMsg1( "m_cRef = %d", m_cRef ); if ( m_cRef == 0 ) { TraceDo( delete this ); return 0; } // if: reference count decremented to zero return m_cRef; } //*** CBCAInterface::Release() ////////////////////////////////////////////////////////////////////////////// //++ // // STDMETHODIMP // CBCAInterface::QueryInterface() // // Description: // Decrement the reference count of this object by one. // // Arguments: // IN REFIID riidIn, // Id of interface requested. // // OUT void ** ppvOut // Pointer to the requested interface. // // Return Value: // S_OK // If the interface is available on this object. // // E_NOINTERFACE // If the interface is not available. // // Remarks: // None. // //-- ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CBCAInterface::QueryInterface( REFIID riidIn, void ** ppvOut ) { BCATraceQIScope( riidIn, ppvOut ); HRESULT hr = S_OK; if ( ppvOut != NULL ) { if ( IsEqualIID( riidIn, IID_IUnknown ) ) { *ppvOut = static_cast< IClusCfgBaseCluster * >( this ); } // if: IUnknown else if ( IsEqualIID( riidIn, IID_IClusCfgBaseCluster ) ) { *ppvOut = TraceInterface( __THISCLASS__, IClusCfgBaseCluster, this, 0 ); } // else if: else if ( IsEqualIID( riidIn, IID_IClusCfgInitialize ) ) { *ppvOut = TraceInterface( __THISCLASS__, IClusCfgInitialize, this, 0 ); } // else if: else { hr = THR( E_NOINTERFACE ); } // else if ( SUCCEEDED( hr ) ) { ((IUnknown *) *ppvOut)->AddRef( ); } // if: success else { *ppvOut = NULL; } // else: something failed } // if: the output pointer was valid else { hr = THR( E_INVALIDARG ); } // else: the output pointer is invalid return hr; } //*** CBCAInterface::QueryInterface() ////////////////////////////////////////////////////////////////////////////// //++ // // CBCAInterface::Initialize() // // Description: // Initialize this component. // // Arguments: // punkCallbackIn // Pointer to the IUnknown interface of a component that implements // the IClusCfgCallback interface. // // lcidIn // Locale id for this component. // // Return Value: // S_OK // If the call succeeded // // Other HRESULTs // If the call failed. // //-- ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CBCAInterface::Initialize( IUnknown * punkCallbackIn, LCID lcidIn ) { BCATraceScope( "[IClusCfgInitialize]" ); HRESULT hrRetVal = S_OK; // Store the locale id in the member variable. m_lcid = lcidIn; do { // Indicate that SendStatusReports will not be supported unless a non- // NULL callback interface pointer was specified. This is done in // the constructor as well, but is also done here since this method // could be called multiple times. SetCallbackSupported( false ); if ( punkCallbackIn == NULL ) { BCATraceMsg( "Callback pointer is NULL. No notifications will be sent." ); LogMsg( "No notifications will be sent." ); break; } BCATraceMsg( "The callback pointer is not NULL." ); // Try and get the "normal" callback interface. hrRetVal = THR( m_spcbCallback.HrQueryAndAssign( punkCallbackIn ) ); if ( FAILED( hrRetVal ) ) { BCATraceMsg( "Could not get pointer to the callback interface. No notifications will be sent." ); LogMsg( "An error occurred trying to get a pointer to the callback interface. No notifications will be sent." ); break; } // if: we could not get the callback interface SetCallbackSupported( true ); BCATraceMsg( "Progress messages will be sent." ); LogMsg( "Progress messages will be sent." ); } while( false ); // Dummy do-while loop to avoid gotos BCATraceMsg1( "hrRetVal = %#08x", hrRetVal ); return hrRetVal; } //*** CBCAInterface::Initialize() ////////////////////////////////////////////////////////////////////////////// //++ // // STDMETHODIMP // CBCAInterface::SetForm() // // Description: // Indicate that a cluster is to be formed with this computer as the first node. // // Arguments: // const WCHAR * pcszClusterNameIn // Name of the cluster to be formed. // // const WCHAR * pcszClusterAccountNameIn // const WCHAR * pcszClusterAccountPwdIn // const WCHAR * pcszClusterAccountDomainIn // Information about the cluster service account. // // const DWORD dwClusterIPAddressIn // const DWORD dwClusterIPSubnetMaskIn // const WCHAR * pcszClusterIPNetworkIn // Information about the cluster IP address // // Return Value: // S_OK // If the call succeeded // // Other HRESULTs // If the call failed. // //-- ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CBCAInterface::SetForm( const WCHAR * pcszClusterNameIn , const WCHAR * pcszClusterBindingStringIn , const WCHAR * pcszClusterAccountNameIn , const WCHAR * pcszClusterAccountPwdIn , const WCHAR * pcszClusterAccountDomainIn , const DWORD dwClusterIPAddressIn , const DWORD dwClusterIPSubnetMaskIn , const WCHAR * pcszClusterIPNetworkIn ) { BCATraceScope( "[IClusCfgBaseCluster]" ); HRESULT hrRetVal = S_OK; // Set the thread locale. if ( SetThreadLocale( m_lcid ) == FALSE ) { DWORD dwError = TW32( GetLastError() ); // If SetThreadLocale() fails, do not abort. Just log the error. BCATraceMsg1( "Error %#08x occurred trying to set the thread locale.", dwError ); LogMsg( "Error %#08x occurred trying to set the thread locale.", dwError ); } // if: SetThreadLocale() failed try { BCATraceMsg( "Initializing cluster formation." ); LogMsg( "Initializing cluster formation." ); // Reset these state variables, to account for exceptions. SetRollbackPossible( false ); // Setting this to true prevents Commit from being called while we are // in this routine or if this routine doesn't complete successfully. SetCommitCompleted( true ); { // Create a CBaseClusterForm object and assign it to a smart pointer. SmartBCAPointer spbcaTemp( new CBaseClusterForm( this , pcszClusterNameIn , pcszClusterBindingStringIn , pcszClusterAccountNameIn , pcszClusterAccountPwdIn , pcszClusterAccountDomainIn , dwClusterIPAddressIn , dwClusterIPSubnetMaskIn , pcszClusterIPNetworkIn ) ); if ( spbcaTemp.FIsEmpty() ) { BCATraceMsg( "Could not allocate memory for the CBaseClusterForm() object. Throwing an exception." ); LogMsg( "Could not initialize cluster formation. A memory allocation failure occurred." ); THROW_RUNTIME_ERROR( E_OUTOFMEMORY, IDS_ERROR_CLUSTER_FORM_INIT ); } // if: the memory allocation failed. // // If the creation succeeded store the pointer in a member variable for // use during commit. // m_spbcaCurrentAction = spbcaTemp; } LogMsg( "Initialization completed. A cluster will be formed on commit." ); // Indicate if rollback is possible. SetRollbackPossible( m_spbcaCurrentAction->FIsRollbackPossible() ); // Indicate that this action has not been committed. SetCommitCompleted( false ); } // try: to initialize cluster formation catch( CAssert & raExceptionObject ) { // Process the exception. hrRetVal = THR( HrProcessException( raExceptionObject ) ); } // catch( CAssert & ) catch( CExceptionWithString & resExceptionObject ) { // Process the exception. hrRetVal = THR( HrProcessException( resExceptionObject ) ); } // catch( CExceptionWithString & ) catch( CException & reExceptionObject ) { // Process the exception. hrRetVal = THR( HrProcessException( reExceptionObject ) ); } // catch( CException & ) catch( ... ) { // Catch everything. Do not let any exceptions pass out of this function. hrRetVal = THR( HrProcessException() ); } // catch all BCATraceMsg1( "hrRetVal = %#08x", hrRetVal ); return hrRetVal; } //*** CBCAInterface::SetForm() ////////////////////////////////////////////////////////////////////////////// //++ // // STDMETHODIMP // CBCAInterface::SetJoin() // // Description: // Indicate that this computer should be added to a cluster. // // Arguments: // const WCHAR * pcszClusterNameIn // Name of the cluster to be joined. // // const WCHAR * pcszClusterAccountNameIn // const WCHAR * pcszClusterAccountPwdIn // const WCHAR * pcszClusterAccountDomainIn // Information about the cluster service account. // // Return Value: // S_OK // If the call succeeded // // Other HRESULTs // If the call failed. // //-- ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CBCAInterface::SetJoin( const WCHAR * pcszClusterNameIn , const WCHAR * pcszClusterBindingStringIn , const WCHAR * pcszClusterAccountNameIn , const WCHAR * pcszClusterAccountPwdIn , const WCHAR * pcszClusterAccountDomainIn ) { BCATraceScope( "[IClusCfgBaseCluster]" ); HRESULT hrRetVal = S_OK; // Set the thread locale. if ( SetThreadLocale( m_lcid ) == FALSE ) { DWORD dwError = TW32( GetLastError() ); // If SetThreadLocale() fails, do not abort. Just log the error. BCATraceMsg1( "Error %#08x occurred trying to set the thread locale.", dwError ); LogMsg( "Error %#08x occurred trying to set the thread locale.", dwError ); } // if: SetThreadLocale() failed try { BCATraceMsg( "Initializing cluster join." ); LogMsg( "Initializing cluster join." ); // Reset these state variables, to account for exceptions. SetRollbackPossible( false ); // Setting this to true prevents Commit from being called while we are // in this routine or if this routine doesn't complete successfully. SetCommitCompleted( true ); { // Create a CBaseClusterJoin object and assign it to a smart pointer. SmartBCAPointer spbcaTemp( new CBaseClusterJoin( this , pcszClusterNameIn , pcszClusterBindingStringIn , pcszClusterAccountNameIn , pcszClusterAccountPwdIn , pcszClusterAccountDomainIn ) ); if ( spbcaTemp.FIsEmpty() ) { BCATraceMsg( "Could not allocate memory for the CBaseClusterJoin() object. Throwing an exception." ); LogMsg( "Could not initialize cluster join. A memory allocation failure occurred." ); THROW_RUNTIME_ERROR( E_OUTOFMEMORY, IDS_ERROR_CLUSTER_JOIN_INIT ); } // if: the memory allocation failed. // // If the creation succeeded store the pointer in a member variable for // use during commit. // m_spbcaCurrentAction = spbcaTemp; } LogMsg( "Initialization completed. This computer will join a cluster on commit." ); // Indicate if rollback is possible. SetRollbackPossible( m_spbcaCurrentAction->FIsRollbackPossible() ); // Indicate that this action has not been committed. SetCommitCompleted( false ); } // try: to initialize cluster join catch( CAssert & raExceptionObject ) { // Process the exception. hrRetVal = THR( HrProcessException( raExceptionObject ) ); } // catch( CAssert & ) catch( CExceptionWithString & resExceptionObject ) { // Process the exception. hrRetVal = THR( HrProcessException( resExceptionObject ) ); } // catch( CExceptionWithString & ) catch( CException & reExceptionObject ) { // Process the exception. hrRetVal = THR( HrProcessException( reExceptionObject ) ); } // catch( CException & ) catch( ... ) { // Catch everything. Do not let any exceptions pass out of this function. hrRetVal = THR( HrProcessException() ); } // catch all BCATraceMsg1( "hrRetVal = %#08x", hrRetVal ); return hrRetVal; } //*** CBCAInterface::SetJoin() ////////////////////////////////////////////////////////////////////////////// //++ // // STDMETHODIMP // CBCAInterface::SetCleanup() // // Description: // Indicate that this node needs to be cleaned up. The ClusSvc service // should not be running when this action is committed. // // Arguments: // None. // // Return Value: // S_OK // If the call succeeded // // Other HRESULTs // If the call failed. // //-- ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CBCAInterface::SetCleanup() { BCATraceScope( "[IClusCfgBaseCluster]" ); HRESULT hrRetVal = S_OK; // Set the thread locale. if ( SetThreadLocale( m_lcid ) == FALSE ) { DWORD dwError = TW32( GetLastError() ); // If SetThreadLocale() fails, do not abort. Just log the error. BCATraceMsg1( "Error %#08x occurred trying to set the thread locale.", dwError ); LogMsg( "Error %#08x occurred trying to set the thread locale.", dwError ); } // if: SetThreadLocale() failed try { BCATraceMsg( "Initializing node clean up." ); LogMsg( "Initializing node clean up." ); // Reset these state variables, to account for exceptions. SetRollbackPossible( false ); // Setting this to true prevents Commit from being called while we are // in this routine or if this routine doesn't complete successfully. SetCommitCompleted( true ); { // Create a CBaseClusterCleanup object and assign it to a smart pointer. SmartBCAPointer spbcaTemp( new CBaseClusterCleanup( this ) ); if ( spbcaTemp.FIsEmpty() ) { BCATraceMsg( "Could not allocate memory for the CBaseClusterCleanup() object. Throwing an exception." ); LogMsg( "Could not initialize node clean up. A memory allocation failure occurred." ); THROW_RUNTIME_ERROR( E_OUTOFMEMORY, IDS_ERROR_CLUSTER_CLEANUP_INIT ); } // if: the memory allocation failed. // // If the creation succeeded store the pointer in a member variable for // use during commit. // m_spbcaCurrentAction = spbcaTemp; } LogMsg( "Initialization completed. This node will be cleaned up on commit." ); // Indicate if rollback is possible. SetRollbackPossible( m_spbcaCurrentAction->FIsRollbackPossible() ); // Indicate that this action has not been committed. SetCommitCompleted( false ); } // try: to initialize node clean up catch( CAssert & raExceptionObject ) { // Process the exception. hrRetVal = THR( HrProcessException( raExceptionObject ) ); } // catch( CAssert & ) catch( CExceptionWithString & resExceptionObject ) { // Process the exception. hrRetVal = THR( HrProcessException( resExceptionObject ) ); } // catch( CExceptionWithString & ) catch( CException & reExceptionObject ) { // Process the exception. hrRetVal = THR( HrProcessException( reExceptionObject ) ); } // catch( CException & ) catch( ... ) { // Catch everything. Do not let any exceptions pass out of this function. hrRetVal = THR( HrProcessException() ); } // catch all BCATraceMsg1( "hrRetVal = %#08x", hrRetVal ); return hrRetVal; } //*** CBCAInterface::SetCleanup() ////////////////////////////////////////////////////////////////////////////// //++ // // STDMETHODIMP // CBCAInterface::Commit( void ) // // Description: // Perform the action indicated by a previous call to one of the SetXXX // routines. // // Arguments: // None. // // Return Value: // S_OK // If the call succeeded // // E_FAIL // If this commit has already been performed. // // E_INVALIDARG // If no action has been set using a SetXXX call. // // Other HRESULTs // If the call failed. // // Remarks: // None. // //-- ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CBCAInterface::Commit( void ) { BCATraceScope( "[IClusCfgBaseCluster]" ); HRESULT hrRetVal = S_OK; // Set the thread locale. if ( SetThreadLocale( m_lcid ) == FALSE ) { DWORD dwError = TW32( GetLastError() ); // If SetThreadLocale() fails, do not abort. Just log the error. BCATraceMsg1( "Error %#08x occurred trying to set the thread locale.", dwError ); LogMsg( "Error %#08x occurred trying to set the thread locale.", dwError ); } // if: SetThreadLocale() failed do { // Has this action already been committed? if ( FIsCommitComplete() ) { BCATraceMsg( "The desired cluster configuration has already been performed." ); LogMsg( "The desired cluster configuration has already been performed." ); hrRetVal = THR( E_FAIL ); // BUGBUG: 29-JAN-2001 DavidP Replace E_FAIL break; } // if: already committed // Check if the arguments to commit have been set. if ( m_spbcaCurrentAction.FIsEmpty() ) { BCATraceMsg( "Commit was called when an operation has not been specified." ); LogMsg( "Commit was called when an operation has not been specified." ); hrRetVal = THR( E_INVALIDARG ); // BUGBUG: 29-JAN-2001 DavidP Replace E_INVALIDARG break; } // if: the pointer to the action to be committed is NULL LogMsg( "About to perform the desired cluster configuration." ); // Commit the desired action. try { m_spbcaCurrentAction->Commit(); LogMsg( "Cluster configuration completed successfully." ); // If we are here, then everything has gone well. SetCommitCompleted( true ); } // try: to commit the desired action. catch( CAssert & raExceptionObject ) { // Process the exception. hrRetVal = THR( HrProcessException( raExceptionObject ) ); } // catch( CAssert & ) catch( CExceptionWithString & resExceptionObject ) { // Process the exception. hrRetVal = THR( HrProcessException( resExceptionObject ) ); } // catch( CExceptionWithString & ) catch( CException & reExceptionObject ) { // Process the exception. hrRetVal = THR( HrProcessException( reExceptionObject ) ); } // catch( CException & ) catch( ... ) { // Catch everything. Do not let any exceptions pass out of this function. hrRetVal = THR( HrProcessException() ); } // catch all } while( false ); // dummy do-while loop to avoid gotos BCATraceMsg1( "hrRetVal = %#08x", hrRetVal ); return hrRetVal; } //*** CBCAInterface::Commit() ////////////////////////////////////////////////////////////////////////////// //++ // // STDMETHODIMP // CBCAInterface::Rollback( void ) // // Description: // Rollback a committed configuration. // // Arguments: // None. // // Return Value: // S_OK // If the call succeeded // // E_FAIL // If this action cannot be rolled back or if it has not yet been // committed successfully. // // E_INVALIDARG // If no action has been set using a SetXXX call. // // Other HRESULTs // If the call failed. // // Remarks: // None. // //-- ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CBCAInterface::Rollback( void ) { BCATraceScope( "[IClusCfgCallback]" ); HRESULT hrRetVal = S_OK; do { // Check if this action list has completed successfully. if ( !FIsCommitComplete() ) { // Cannot rollback an incomplete action. BCATraceMsg( "Cannot rollback - action not yet committed." ); LogMsg( "Cannot rollback - action not yet committed." ); hrRetVal = THR( E_FAIL ); // BUGBUG: 29-JAN-2001 DavidP Replace E_FAIL break; } // if: this action was not completed successfully // Check if this action can be rolled back. if ( !FIsRollbackPossible() ) { // Cannot rollback an incompleted action. BCATraceMsg( "This action cannot be rolled back." ); LogMsg( "This action cannot be rolled back." ); // BUGBUG: 29-JAN-2001 DavidP Why? hrRetVal = THR( E_FAIL ); // BUGBUG: 29-JAN-2001 DavidP Replace E_FAIL break; } // if: this action was not completed successfully // Check if the arguments to rollback have been set. if ( m_spbcaCurrentAction.FIsEmpty() ) { BCATraceMsg( "Rollback was called when an operation has not been specified." ); LogMsg( "Rollback was called when an operation has not been specified." ); hrRetVal = THR( E_INVALIDARG ); // BUGBUG: 29-JAN-2001 DavidP Replace E_INVALIDARG break; } // if: the pointer to the action to be committed is NULL LogMsg( "About to rollback the cluster configuration just committed." ); // Commit the desired action. try { m_spbcaCurrentAction->Rollback(); LogMsg( "Cluster configuration rolled back." ); // If we are here, then everything has gone well. SetCommitCompleted( false ); } // try: to rollback the desired action. catch( CAssert & raExceptionObject ) { // Process the exception. hrRetVal = THR( HrProcessException( raExceptionObject ) ); } // catch( CAssert & ) catch( CExceptionWithString & resExceptionObject ) { // Process the exception. hrRetVal = THR( HrProcessException( resExceptionObject ) ); } // catch( CExceptionWithString & ) catch( CException & reExceptionObject ) { // Process the exception. hrRetVal = THR( HrProcessException( reExceptionObject ) ); } // catch( CException & ) catch( ... ) { // Catch everything. Do not let any exceptions pass out of this function. hrRetVal = THR( HrProcessException() ); } // catch all } while( false ); // dummy do-while loop to avoid gotos BCATraceMsg1( "hrRetVal = %#08x", hrRetVal ); return hrRetVal; } //*** CBCAInterface::Rollback() ////////////////////////////////////////////////////////////////////////////// //++ // // void // CBCAInterface::SendStatusReport // // Description: // Send a progress notification [ string id overload ]. // // Arguments: // clsidTaskMajorIn // clsidTaskMinorIn // GUIDs identifying the notification. // // ulMinIn // ulMaxIn // ulCurrentIn // Values that indicate the percentage of this task that is // completed. // // hrStatusIn // Error code. // // uiDescriptionStringIdIn // String ID of the description of the notification. // // Return Value: // None. // // Exceptions Thrown: // CRuntimeError // If any of the APIs fail. // // CAbortException // If the configuration was aborted. // // Remarks: // In the current implementation, IClusCfgCallback::SendStatusReport // returns E_ABORT to indicate that the user wants to abort // the cluster configuration. //-- ////////////////////////////////////////////////////////////////////////////// void CBCAInterface::SendStatusReport( const CLSID & clsidTaskMajorIn , const CLSID & clsidTaskMinorIn , ULONG ulMinIn , ULONG ulMaxIn , ULONG ulCurrentIn , HRESULT hrStatusIn , UINT uiDescriptionStringIdIn , bool fIsAbortAllowedIn // = true ) { BCATraceScope( "uiDescriptionStringIdIn" ); HRESULT hrRetVal = S_OK; if ( FIsCallbackSupported() ) { CStr strDescription; // Lookup the string using the string Id. strDescription.LoadString( g_hInstance, uiDescriptionStringIdIn ); // Send progress notification ( call the overloaded function ) SendStatusReport( clsidTaskMajorIn , clsidTaskMinorIn , ulMinIn , ulMaxIn , ulCurrentIn , hrStatusIn , strDescription.PszData() , fIsAbortAllowedIn ); } // if: callbacks are supported else { BCATraceMsg( "Callbacks are not supported. Doing nothing." ); } // else: callbacks are not supported } //*** CBCAInterface::SendStatusReport() ////////////////////////////////////////////////////////////////////////////// //++ // // void // CBCAInterface::SendStatusReport // // Description: // Send a progress notification [ string overload ]. // // Arguments: // clsidTaskMajorIn // clsidTaskMinorIn // GUIDs identifying the notification. // // ulMinIn // ulMaxIn // ulCurrentIn // Values that indicate the percentage of this task that is // completed. // // hrStatusIn // Error code. // // pcszDescriptionStringIn // String ID of the description of the notification. // // fIsAbortAllowedIn // An optional parameter indicating if this configuration step can // be aborted or not. Default value is true. // // Return Value: // None. // // Exceptions Thrown: // CRuntimeError // If any of the APIs fail. // // CAbortException // If the configuration was aborted. // // Remarks: // In the current implementation, IClusCfgCallback::SendStatusReport // returns E_ABORT to indicate that the user wants to abort // the cluster configuration. //-- ////////////////////////////////////////////////////////////////////////////// void CBCAInterface::SendStatusReport( const CLSID & clsidTaskMajorIn , const CLSID & clsidTaskMinorIn , ULONG ulMinIn , ULONG ulMaxIn , ULONG ulCurrentIn , HRESULT hrStatusIn , const WCHAR * pcszDescriptionStringIn , bool fIsAbortAllowedIn // = true ) { BCATraceScope1( "pcszDescriptionStringIn = '%ls'", pcszDescriptionStringIn ); HRESULT hrRetVal = S_OK; FILETIME ft; do { CSmartResource< CHandleTrait< BSTR , void , SysFreeString , reinterpret_cast< LPOLESTR >( NULL ) > > sbstrDescription; if ( !FIsCallbackSupported() ) { // Nothing needs to be done. break; } // if: callbacks are not supported if ( pcszDescriptionStringIn != NULL ) { // Convert the string to a BSTR. sbstrDescription.Assign( SysAllocString( pcszDescriptionStringIn ) ); // Did the conversion succeed? if ( sbstrDescription.FIsInvalid() ) { BCATraceMsg( "Could not convert description string to BSTR." ); LogMsg( "Could not convert description string to BSTR." ); hrRetVal = E_OUTOFMEMORY; break; } // if: the string lookup failed. } // if: the description string is not NULL GetSystemTimeAsFileTime( &ft ); // // TODO: 21 NOV 2000 GalenB // // I don't know why the two new args cannot be NULL? // When they are NULL something throws and exception from // somewhere... // Send progress notification hrRetVal = THR( m_spcbCallback->SendStatusReport( NULL , clsidTaskMajorIn , clsidTaskMinorIn , ulMinIn , ulMaxIn , ulCurrentIn , hrStatusIn , sbstrDescription.HHandle() , &ft , L"" ) ); // Has the user requested an abort? if ( hrRetVal == E_ABORT ) { LogMsg( "A request to abort the configuration has been recieved." ); if ( fIsAbortAllowedIn ) { LogMsg( "Configuration will be aborted." ); BCATraceMsg( "Aborting configuration." ); THROW_ABORT( E_ABORT, IDS_USER_ABORT ); } // if: this operation can be aborted else { LogMsg( "This configuration operation cannot be aborted. Request will be ignored." ); BCATraceMsg( "This configuration operation cannot be aborted. Request will be ignored." ); } // else: this operation cannot be aborted } // if: the user has indicated that that configuration should be aborted else { if ( FAILED( hrRetVal ) ) { LogMsg( "Error %#08x has occurred - no more status messages will be sent.", hrRetVal ); BCATraceMsg1( "Error %#08x occurred - no more status messages will be sent.", hrRetVal ); // Disable all further callbacks. SetCallbackSupported( false ); } // if: something went wrong trying to send a status report } // else: abort was not requested } while( false ); // dummy do-while loop to avoid gotos if ( FAILED( hrRetVal ) ) { LogMsg( "Error %#08x occurred trying send a status message.", hrRetVal ); BCATraceMsg1( "Error %#08x occurred trying send a status message. Throwing exception.", hrRetVal ); THROW_RUNTIME_ERROR( hrRetVal, IDS_ERROR_SENDING_REPORT ); } // if: an error occurred } //*** CBCAInterface::SendStatusReport() ////////////////////////////////////////////////////////////////////////////// //++ // // void // CBCAInterface::QueueStatusReportCompletion // // Description: // Queue a status report for sending when an exception is caught. // // Arguments: // clsidTaskMajorIn // clsidTaskMinorIn // GUIDs identifying the notification. // // ulMinIn // ulMaxIn // Values that indicate the range of steps for this report. // // uiDescriptionStringIdIn // String ID of the description of the notification. // // Return Value: // None. // // Exceptions Thrown: // Any thrown by CList::Append() //-- ////////////////////////////////////////////////////////////////////////////// void CBCAInterface::QueueStatusReportCompletion( const CLSID & clsidTaskMajorIn , const CLSID & clsidTaskMinorIn , ULONG ulMinIn , ULONG ulMaxIn , UINT uiDescriptionStringIdIn ) { BCATraceScope( "" ); // Queue the status report only if callbacks are supported. if ( m_fCallbackSupported ) { // Append this status report to the end of the pending list. m_prlPendingReportList.Append( SPendingStatusReport( clsidTaskMajorIn , clsidTaskMinorIn , ulMinIn , ulMaxIn , uiDescriptionStringIdIn ) ); } } //*** CBCAInterface::QueueStatusReportCompletion() ////////////////////////////////////////////////////////////////////////////// //++ // // void // CBCAInterface::CompletePendingStatusReports // // Description: // Send all the status reports that were queued for sending when an // exception occurred. This function is meant to be called from an exception // handler when an exception is caught. // // Arguments: // hrStatusIn // The error code to be sent with the pending status reports. // // Return Value: // None. // // Exceptions Thrown: // None, since this function is usually called in an exception handler. // //-- ////////////////////////////////////////////////////////////////////////////// void CBCAInterface::CompletePendingStatusReports( HRESULT hrStatusIn ) throw() { BCATraceScope( "" ); if ( m_fCallbackSupported ) { try { PendingReportList::CIterator ciCurrent = m_prlPendingReportList.CiBegin(); PendingReportList::CIterator ciLast = m_prlPendingReportList.CiEnd(); // Iterate through the list of pending status reports and send each pending report. while ( ciCurrent != ciLast ) { // Send the current status report. SendStatusReport( ciCurrent->m_clsidTaskMajor , ciCurrent->m_clsidTaskMinor , ciCurrent->m_ulMin , ciCurrent->m_ulMax , ciCurrent->m_ulMax , hrStatusIn , ciCurrent->m_uiDescriptionStringId , false ); // Move to the next one. m_prlPendingReportList.DeleteAndMoveToNext( ciCurrent ); } // while: the pending status report list is not empty } // try: to send status report catch( ... ) { THR( E_UNEXPECTED ); // Nothing can be done here if the sending of the status report fails. BCATraceMsg( "An exception has occurred trying to complete pending status messages. It will not be propagated." ); LogMsg( "An unexpected error has occurred trying to complete pending status messages. It will not be propagated." ); } // catch: all exceptions } // if: callbacks are supported // Empty the pending status report list. m_prlPendingReportList.Empty(); } //*** CBCAInterface::CompletePendingStatusReports() ////////////////////////////////////////////////////////////////////////////// //++ // // HRESULT // CBCAInterface::HrProcessException // // Description: // Process an exception that should be shown to the user. // // Arguments: // CExceptionWithString & resExceptionObjectInOut // The exception object that has been caught. // // Return Value: // The error code stored in the exception object. // // Exceptions Thrown: // None. // //-- ////////////////////////////////////////////////////////////////////////////// HRESULT CBCAInterface::HrProcessException( CExceptionWithString & resExceptionObjectInOut ) throw() { BCATraceScope( "resExceptionObjectInOut" ); LogMsg( TEXT("A runtime error has occurred in file '%s', line %d. Error code is %#08x.") SZ_NEWLINE TEXT(" The error string is '%s'.") , resExceptionObjectInOut.PszGetThrowingFile() , resExceptionObjectInOut.UiGetThrowingLine() , resExceptionObjectInOut.HrGetErrorCode() , resExceptionObjectInOut.StrGetErrorString().PszData() ); BCATraceMsg3( "A runtime error has occurred in file '%s', line %d. Error code is %#08x." , resExceptionObjectInOut.PszGetThrowingFile() , resExceptionObjectInOut.UiGetThrowingLine() , resExceptionObjectInOut.HrGetErrorCode() ); BCATraceMsg1( " The error string is '%s'." , resExceptionObjectInOut.StrGetErrorString().PszData() ); // If the user has not been notified if ( !resExceptionObjectInOut.FHasUserBeenNotified() ) { try { SendStatusReport( TASKID_Major_Configure_Cluster_Services , TASKID_Minor_Rolling_Back_Cluster_Configuration , 1, 1, 1 , resExceptionObjectInOut.HrGetErrorCode() , resExceptionObjectInOut.StrGetErrorString().PszData() , false // fIsAbortAllowedIn ); resExceptionObjectInOut.SetUserNotified(); } // try: to send status report catch( ... ) { THR( E_UNEXPECTED ); // Nothing can be done here if the sending of the status report fails. BCATraceMsg( "An exception has occurred trying to send a progress notification. It will not be propagated." ); LogMsg( "An unexpected error has occurred trying to send a progress notification. It will not be propagated." ); } // catch: all exceptions } // if: the user has not been notified of this exception // Complete sending pending status reports. CompletePendingStatusReports( resExceptionObjectInOut.HrGetErrorCode() ); return resExceptionObjectInOut.HrGetErrorCode(); } //*** CBCAInterface::HrProcessException() ////////////////////////////////////////////////////////////////////////////// //++ // // HRESULT // CBCAInterface::HrProcessException // // Description: // Process an assert exception. // // Arguments: // const CAssert & rcaExceptionObjectIn // The exception object that has been caught. // // Return Value: // The error code stored in the exception object. // // Exceptions Thrown: // None. // //-- ////////////////////////////////////////////////////////////////////////////// HRESULT CBCAInterface::HrProcessException( const CAssert & rcaExceptionObjectIn ) throw() { BCATraceScope( "rcaExceptionObjectIn" ); LogMsg( TEXT("An assertion has failed in file '%s', line %d. Error code is %#08x.") SZ_NEWLINE TEXT(" The error string is '%s'.") , rcaExceptionObjectIn.PszGetThrowingFile() , rcaExceptionObjectIn.UiGetThrowingLine() , rcaExceptionObjectIn.HrGetErrorCode() , rcaExceptionObjectIn.StrGetErrorString().PszData() ); BCATraceMsg3( "An assertion has failed in file '%s', line %d. Error code is %#08x." , rcaExceptionObjectIn.PszGetThrowingFile() , rcaExceptionObjectIn.UiGetThrowingLine() , rcaExceptionObjectIn.HrGetErrorCode() ); BCATraceMsg1( " The error string is '%s'." , rcaExceptionObjectIn.StrGetErrorString().PszData() ); // Complete sending pending status reports. CompletePendingStatusReports( rcaExceptionObjectIn.HrGetErrorCode() ); return rcaExceptionObjectIn.HrGetErrorCode(); } //*** CBCAInterface::HrProcessException() ////////////////////////////////////////////////////////////////////////////// //++ // // HRESULT // CBCAInterface::HrProcessException // // Description: // Process a general exception. // // Arguments: // const CException & rceExceptionObjectIn // The exception object that has been caught. // // Return Value: // The error code stored in the exception object. // // Exceptions Thrown: // None. // //-- ////////////////////////////////////////////////////////////////////////////// HRESULT CBCAInterface::HrProcessException( const CException & rceExceptionObjectIn ) throw() { BCATraceScope( "roeExceptionObjectIn" ); LogMsg( "An exception has occurred in file '%s', line %d. Error code is %#08x." , rceExceptionObjectIn.PszGetThrowingFile() , rceExceptionObjectIn.UiGetThrowingLine() , rceExceptionObjectIn.HrGetErrorCode() ); BCATraceMsg3( "An exception has occurred in file '%s', line %d. Error code is %#08x." , rceExceptionObjectIn.PszGetThrowingFile() , rceExceptionObjectIn.UiGetThrowingLine() , rceExceptionObjectIn.HrGetErrorCode() ); // Complete sending pending status reports. CompletePendingStatusReports( rceExceptionObjectIn.HrGetErrorCode() ); return rceExceptionObjectIn.HrGetErrorCode(); } //*** CBCAInterface::HrProcessException() ////////////////////////////////////////////////////////////////////////////// //++ // // HRESULT // CBCAInterface::HrProcessException // // Description: // Process an unknown exception. // // Arguments: // None. // Return Value: // E_UNEXPECTED // // Exceptions Thrown: // None. // //-- ////////////////////////////////////////////////////////////////////////////// HRESULT CBCAInterface::HrProcessException( void ) throw() { BCATraceScope( "void" ); LogMsg( "An unknown exception (for example, an access violation) has occurred." ); BCATraceMsg( "An unknown exception (for example, an access violation) has occurred." ); // Complete sending pending status reports. CompletePendingStatusReports( E_UNEXPECTED ); return E_UNEXPECTED; } //*** CBCAInterface::HrProcessException()