|
|
//////////////////////////////////////////////////////////////////////////////
//
// 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"
#include "WizardHelp.h"
#include "SummaryPage.h"
#include <HtmlHelp.h>
//////////////////////////////////////////////////////////////////////////////
// Context-sensitive help table.
//////////////////////////////////////////////////////////////////////////////
const DWORD g_rgidQuorumDlgHelpIDs[] = { IDC_QUORUM_S_QUORUM, IDH_QUORUM_S_QUORUM, IDC_QUORUM_CB_QUORUM, IDH_QUORUM_S_QUORUM, 0, 0 };
//////////////////////////////////////////////////////////////////////////////
// Static Function Prototypes
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//++
//
// CQuorumDlg::S_HrDisplayModalDialog
//
// Description:
// Display the dialog box.
//
// Arguments:
// hwndParentIn - Parent window for the dialog box.
// pccwIn - CClusCfgWizard pointer for talking to the middle tier.
// pssaOut - array of all the initial IsManaged states
//
// Return Values:
// S_OK - Operation completed successfully.
//
// Remarks:
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT CQuorumDlg::S_HrDisplayModalDialog( HWND hwndParentIn , CClusCfgWizard * pccwIn , SStateArray * pssaOut ) { TraceFunc( "" );
Assert( pccwIn != NULL ); Assert( pssaOut != NULL );
HRESULT hr = S_OK; INT_PTR dlgResult = IDOK;
// Display the dialog.
{ CQuorumDlg dlg( pccwIn, pssaOut );
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
//////////////////////////////////////////////////////////////////////////////
//++
//
// FIsValidResource
//
// Description:
// Determines whether the resource is a valid selection as a quorum
// resource.
//
// 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 FIsValidResource( IClusCfgManagedResourceInfo * pResourceIn ) { TraceFunc( "" );
HRESULT hr = S_OK; bool fValid = false; BSTR bstrDeviceID = NULL;
hr = STHR( pResourceIn->IsQuorumCapable() ); if ( FAILED( hr ) ) { goto Cleanup; } // if:
//
// The resource is not quorum capable so there is no reason
// to continue.
//
if ( hr == S_FALSE ) { goto Cleanup; } // if:
hr = THR( pResourceIn->GetUID( &bstrDeviceID ) ); if ( FAILED( hr ) ) { LogMsg( L"[WIZ] FIsValidResource() cannot get the UID for the passed in managed resource. (hr = %#08x)" ); goto Cleanup; } // if:
TraceMemoryAddBSTR( bstrDeviceID );
//
// If this is the "Unknown Quorum" resource then we don't want to show it
// in the drop down list.
//
if ( NStringCchCompareCase( g_szUnknownQuorumUID, RTL_NUMBER_OF( g_szUnknownQuorumUID ), bstrDeviceID, SysStringLen( bstrDeviceID ) + 1 ) == 0 ) { goto Cleanup; } // if:
fValid = true;
Cleanup:
TraceSysFreeString( bstrDeviceID );
RETURN( fValid );
} //*** FIsValidResource
//////////////////////////////////////////////////////////////////////////////
//++
//
// CQuorumDlg::CQuorumDlg
//
// Description:
// Constructor.
//
// Arguments:
// pccwIn - CClusCfgWizard for talking to the middle tier.
// pssaOut - array of all the initial IsManaged states.
//
// Return Values:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
CQuorumDlg::CQuorumDlg( CClusCfgWizard * pccwIn , SStateArray * pssaOut ) : m_pccw( pccwIn ) , m_pssa( pssaOut ) , m_rgpResources( NULL ) , m_cValidResources( 0 ) , m_idxQuorumResource( 0 ) , m_hComboBox( NULL ) , m_fQuorumAlreadySet( false ) { TraceFunc( "" );
Assert( pccwIn != NULL ); Assert( pssaOut != NULL );
// m_hwnd
m_pccw->AddRef();
TraceFuncExit();
} //*** CQuorumDlg::CQuorumDlg
//////////////////////////////////////////////////////////////////////////////
//++
//
// CQuorumDlg::~CQuorumDlg
//
// Description:
// Destructor.
//
// Arguments:
// None.
//
// Return Values:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
CQuorumDlg::~CQuorumDlg( void ) { TraceFunc( "" );
DWORD idxResource = 0;
for ( idxResource = 0; idxResource < m_cValidResources; idxResource += 1 ) m_rgpResources[ idxResource ]->Release();
delete [] m_rgpResources;
if ( m_pccw != NULL ) { m_pccw->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;
case WM_HELP: WinHelp( (HWND)((LPHELPINFO) lParam)->hItemHandle, CLUSCFG_HELP_FILE, HELP_WM_HELP, (ULONG_PTR) g_rgidQuorumDlgHelpIDs ); break;
case WM_CONTEXTMENU: WinHelp( (HWND)wParam, CLUSCFG_HELP_FILE, HELP_CONTEXTMENU, (ULONG_PTR) g_rgidQuorumDlgHelpIDs ); 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
HRESULT hr = S_OK; DWORD sc; DWORD 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 ]->IsQuorumResource() ); 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; BOOL fState; IClusCfgManagedResourceInfo * pQuorum = NULL; IClusCfgManagedResourceInfo * pCurrent = NULL; BSTR bstrTemp = NULL; BOOL bLocalQuorum;
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( (DWORD) CB_ERR ) ); goto Error; }
//
// if original quorum resource is different, or had not been set.
//
if ( ( idxCurrentSelection != m_idxQuorumResource ) || !m_fQuorumAlreadySet ) { pQuorum = m_rgpResources[ m_idxQuorumResource ]; pCurrent = m_rgpResources[ idxCurrentSelection ];
//
// First, is the new resource Local Quorum? (Special processing -
// unfortunate but necessary.)
//
hr = THR( pCurrent->GetUID( &bstrTemp ) ); if ( FAILED( hr ) ) { goto Error; } // if:
bLocalQuorum = ( NStringCchCompareCase( bstrTemp, SysStringLen( bstrTemp ) + 1, CLUS_RESTYPE_NAME_LKQUORUM, RTL_NUMBER_OF( CLUS_RESTYPE_NAME_LKQUORUM ) ) == 0 );
SysFreeString( bstrTemp ); bstrTemp = NULL;
//
// Clear original quorum resource.
//
hr = THR( pQuorum->SetQuorumResource( FALSE ) );
//
// Set the managed state back to it's original state.
//
if ( SUCCEEDED( hr ) ) { fState = m_pssa->prsArray[ m_idxQuorumResource ].fState; hr = THR( pQuorum->SetManaged( fState ) ); } // if:
//
// If we successfully ran PrepareToHostQuorum on this resource the last time
// this dialog was up we now need to clean it up.
//
if ( m_pssa->prsArray[ m_idxQuorumResource ].fNeedCleanup ) { THR( HrCleanupQuorumResource( pQuorum ) ); } // if:
//
// Set new quorum resource.
//
if ( SUCCEEDED( hr ) ) { //
// This function returns S_FALSE when the resource does not support
// the IClusCfgVerifyQuorum interface. If the resource doesn't
// support the interface then there is no need to clean it up later.
//
hr = STHR( HrInitQuorumResource( pCurrent ) ); if ( FAILED( hr ) ) { goto Error; } // if:
if ( hr == S_OK ) { m_pssa->prsArray[ idxCurrentSelection ].fNeedCleanup = TRUE; hr = THR( pCurrent->SetQuorumResource( TRUE ) ); } // if:
} // if:
//
// Local Quorum resources should never be SetManaged( TRUE ).
//
if ( SUCCEEDED( hr ) && !bLocalQuorum ) { hr = THR( m_rgpResources[ idxCurrentSelection ]->SetManaged( TRUE ) ); } // if:
if ( FAILED( hr ) ) { fState = m_pssa->prsArray[ idxCurrentSelection ].fState; THR( pCurrent->SetManaged( fState ) ); THR( pCurrent->SetQuorumResource( FALSE ) ); THR( pQuorum->SetQuorumResource( TRUE ) ); THR( pQuorum->SetManaged( bLocalQuorum == FALSE ) );
goto Error; } // if:
EndDialog( m_hwnd, IDOK ); } else // (combo box selection is same as original)
{ EndDialog( m_hwnd, IDCANCEL ); } break;
case IDCANCEL: EndDialog( m_hwnd, IDCANCEL ); break;
case IDHELP: HtmlHelp( m_hwnd, L"mscsconcepts.chm::/SAG_MSCS2planning_6.htm", HH_DISPLAY_TOPIC, 0 ); 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; IUnknown * punkEnum = NULL; IEnumClusCfgManagedResources * peccmr = NULL; DWORD idxResCurrent = 0; ULONG cFetchedResources = 0; DWORD cTotalResources = 0; BOOL fState;
Assert( m_pccw != NULL );
//
// get resource enumerator
//
hr = THR( m_pccw->HrGetClusterChild( CLSID_ManagedResourceType, DFGUID_EnumManageableResources, &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; }
//
// allocate the m_pssa arrays
//
if ( m_pssa->bInitialized == FALSE ) { m_pssa->prsArray = new SResourceState[ cTotalResources ]; if ( m_pssa->prsArray == NULL ) { hr = THR( E_OUTOFMEMORY ); goto Cleanup; }
for ( idxResCurrent = 0 ; idxResCurrent < cTotalResources ; idxResCurrent++ ) { m_pssa->prsArray[ idxResCurrent ].fState = FALSE; m_pssa->prsArray[ idxResCurrent ].fNeedCleanup = FALSE; } } // if: m_pssa ! already initialized
//
// 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 ( !FIsValidResource( 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 ];
if ( m_pssa->bInitialized == FALSE ) { fState = ( m_rgpResources[ m_cValidResources ]->IsManaged() == S_OK ) ? TRUE : FALSE; m_pssa->prsArray[ m_cValidResources ].fState = fState; }
m_cValidResources++; } // if: current element !NULL
} // for: compact the array
if ( m_pssa->bInitialized == FALSE ) { m_pssa->cCount = m_cValidResources; m_pssa->bInitialized = TRUE; }
Cleanup:
if ( m_pssa->bInitialized == FALSE ) { delete [] m_pssa->prsArray; m_pssa->prsArray = NULL;
m_pssa->cCount = 0; }
if ( punkEnum != NULL ) { punkEnum->Release(); }
if ( peccmr != NULL ) { peccmr->Release(); }
HRETURN( hr );
} //*** CQuorumDlg::HrCreateResourceList
//////////////////////////////////////////////////////////////////////////////
//++
//
// CQuorumDlg::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 );
TraceFuncExit();
} //*** CQuorumDlg::UpdateButtons
//////////////////////////////////////////////////////////////////////////////
//++
//
// CDetailsDlg::HrInitQuorumResource
//
// Description:
// Initialize the just chosen quorum resource.
//
// Arguments:
// pResourceIn
// The resource that was chosen as the quorum.
//
// Return Values:
// S_OK
// Success.
//
// Other HRESULT failures.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT CQuorumDlg::HrInitQuorumResource( IClusCfgManagedResourceInfo * pResourceIn ) { TraceFunc( "" ); Assert( pResourceIn != NULL );
HRESULT hr = S_OK; IClusCfgVerifyQuorum * piccvq = NULL; BSTR bstrResource = NULL;
//
// Does this resource implement the IClusCfgVerifyQuorum interface?
//
hr = pResourceIn->TypeSafeQI( IClusCfgVerifyQuorum, &piccvq ); if ( hr == E_NOINTERFACE ) { hr = S_FALSE; goto Cleanup; } // if:
else if ( FAILED( hr ) ) { goto Cleanup; } // else if:
hr = THR( pResourceIn->GetName( &bstrResource ) ); if ( FAILED( hr ) ) { bstrResource = TraceSysAllocString( L"<unknown>" ); } // if:
else { TraceMemoryAddBSTR( bstrResource ); } // else:
//
// The resource did implement the IClusCfgVerifyQuorum interface...
//
Assert( ( hr == S_OK ) && ( piccvq != NULL ) );
hr = STHR( piccvq->PrepareToHostQuorumResource() ); if ( FAILED( hr ) ) { LogMsg( L"[WIZ] PrepareToHostQuorum() failed for resource %ws. (hr = %#08x)", bstrResource, hr ); goto Cleanup; } // if:
Cleanup:
TraceSysFreeString( bstrResource );
if ( piccvq != NULL ) { piccvq->Release(); } // if:
HRETURN( hr );
} //*** CQuorumDlg::HrInitQuorumResource
//////////////////////////////////////////////////////////////////////////////
//++
//
// CDetailsDlg::HrCleanupQuorumResource
//
// Description:
// Cleanup the passed in quorum resource.
//
// Arguments:
// pResourceIn
// The resource that used to be selected as the quorum.
//
// Return Values:
// S_OK
// Success.
//
// Other HRESULT failures.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT CQuorumDlg::HrCleanupQuorumResource( IClusCfgManagedResourceInfo * pResourceIn ) { TraceFunc( "" ); Assert( pResourceIn != NULL );
HRESULT hr = S_OK; IClusCfgVerifyQuorum * piccvq = NULL; BSTR bstrResource = NULL;
//
// Does this resource implement the IClusCfgVerifyQuorum interface?
//
hr = pResourceIn->TypeSafeQI( IClusCfgVerifyQuorum, &piccvq ); if ( hr == E_NOINTERFACE ) { hr = S_OK; goto Cleanup; } // if:
else if ( FAILED( hr ) ) { goto Cleanup; } // else if:
hr = THR( pResourceIn->GetName( &bstrResource ) ); if ( FAILED( hr ) ) { bstrResource = TraceSysAllocString( L"<unknown>" ); } // if:
else { TraceMemoryAddBSTR( bstrResource ); } // else:
//
// The resource did implement the IClusCfgVerifyQuorum interface...
//
Assert( ( hr == S_OK ) && ( piccvq != NULL ) );
hr = STHR( piccvq->Cleanup( crCANCELLED ) ); if ( FAILED( hr ) ) { LogMsg( L"[WIZ] Cleanup() failed for resource %ws. (hr = %#08x)", bstrResource, hr ); goto Cleanup; } // if:
Cleanup:
TraceSysFreeString( bstrResource );
if ( piccvq != NULL ) { piccvq->Release(); } // if:
HRETURN( hr );
} //*** CQuorumDlg::HrCleanupQuorumResource
|