|
|
//////////////////////////////////////////////////////////////////////////////
//
// Module Name:
// CIISClusCfg.cpp
//
// Description:
// Main implementation for the IClusCfgStartupListener sample program.
//
// Maintained By:
// Galen Barbee (GalenB) 24-SEP-2001
//
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
// Include Files
//////////////////////////////////////////////////////////////////////////////
#include "Pch.h"
#include "IISClusCfg.h"
#include <lm.h> // Required for the references in this module.
//////////////////////////////////////////////////////////////////////////////
// Globals
//////////////////////////////////////////////////////////////////////////////
static PCWSTR g_apszResourceTypesToDelete[] = { L"IIS Server Instance", L"SMTP Server Instance", L"NNTP Server Instance", L"IIS Virtual Root",
//
// KB: 18-JUN-2002 GalenB
//
// Since we don't think we are going to be sending this component to
// IIS it is simpler and faster to add this non IIS resource type to this
// component. If this component is ever handed off to IIS then we
// need to remove this resource type from this table.
//
L"Time Service", NULL };
//***************************************************************************
//
// CIISClusCfg class
//
//***************************************************************************
//////////////////////////////////////////////////////////////////////////////
//++
//
// static
// CIISClusCfg::S_HrCreateInstance
//
// Description:
// Create a CIISClusCfg instance.
//
// Arguments:
// riidIn - ID of the interface to return.
// ppunkOut - The IUnknown interface of the new object.
//
// Return Values:
// S_OK
// Success.
//
// E_POINTER
// ppunkOut was NULL.
//
// E_OUTOFMEMORY
// Not enough memory to create the object.
//
// other HRESULTs
// Object initialization failed.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT CIISClusCfg::S_HrCreateInstance( IUnknown ** ppunkOut ) { HRESULT hr = S_OK; CIISClusCfg * pmsl = NULL;
if ( ppunkOut == NULL ) { hr = E_POINTER; goto Cleanup; } // if:
pmsl = new CIISClusCfg(); if ( pmsl == NULL ) { hr = E_OUTOFMEMORY; goto Cleanup; } // if: error allocating object
hr = pmsl->HrInit(); if ( FAILED( hr ) ) { goto Cleanup; } // if: HrInit() failed
hr = pmsl->QueryInterface( IID_IUnknown, reinterpret_cast< void ** >( ppunkOut ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if: QI failed
Cleanup:
if ( pmsl != NULL ) { pmsl->Release(); } // if:
return hr;
} //*** CIISClusCfg::S_HrCreateInstance
//////////////////////////////////////////////////////////////////////////////
//++
//
// CIISClusCfg::S_HrRegisterCatIDSupport
//
// Description:
// Registers/unregisters this class with the categories that it
// belongs to.
//
// Arguments:
// picrIn
// Used to register/unregister our CATID support.
//
// fCreateIn
// When true we are registering the server. When false we are
// un-registering the server.
//
// Return Values:
// S_OK
// Success.
//
// E_INVALIDARG
// The passed in ICatRgister pointer was NULL.
//
// other HRESULTs
// Registration/Unregistration failed.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT CIISClusCfg::S_HrRegisterCatIDSupport( ICatRegister * picrIn, BOOL fCreateIn ) { HRESULT hr = S_OK; CATID rgCatIds[ 2 ];
if ( picrIn == NULL ) { hr = E_INVALIDARG; goto Cleanup; } // if:
rgCatIds[ 0 ] = CATID_ClusCfgStartupListeners; rgCatIds[ 1 ] = CATID_ClusCfgEvictListeners;
if ( fCreateIn ) { hr = picrIn->RegisterClassImplCategories( CLSID_IISClusCfg, RTL_NUMBER_OF( rgCatIds ), rgCatIds ); } // if: registering
//
// KB: 24-SEP-2001 GalenB
//
// This code is not needed since this component has been temporarily placed in ClusCfgSrv.dll. Our
// cleanup code does a tree delete the whole registry key and that cleanups up the CATID stuff.
//
/*
else { hr = picrIn->UnRegisterClassImplCategories( CLSID_IISClusCfg, ARRAYSIZE( rgCatIds ), rgCatIds ); } // else: unregistering
*/
Cleanup:
return hr;
} //*** CIISClusCfg::S_HrRegisterCatIDSupport
//////////////////////////////////////////////////////////////////////////////
//++
//
// CIISClusCfg::CIISClusCfg
//
// Description:
// Constructor of CIISClusCfg. Initializes m_cRef to 1 to avoid
// problems when called from DllGetClassObject. Increments the global
// object count to avoid DLL unload.
//
// Arguments:
// None.
//
// Return Values:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
CIISClusCfg::CIISClusCfg( void ) : m_cRef( 1 ) { //
// Increment the count of components in memory so the DLL hosting this
// object cannot be unloaded.
//
InterlockedIncrement( &g_cObjects );
} //*** CIISClusCfg::CIISClusCfg
/////////////////////////////////////////////////////////////////////////////
//++
//
// CIISClusCfg::~CIISClusCfg
//
// Description:
// Destructor of CIISClusCfg. Decrements the global object count.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
CIISClusCfg::~CIISClusCfg( void ) { // There's going to be one less component in memory.
// Decrement component count.
InterlockedDecrement( &g_cObjects );
} //*** CIISClusCfg::~CIISClusCfg
//***************************************************************************
//
// IUnknown interface
//
//***************************************************************************
//////////////////////////////////////////////////////////////////////////////
//++
//
// [IUnknown]
// CIISClusCfg::AddRef
//
// Description:
// Increment the reference count of this object by one.
//
// Arguments:
// None.
//
// Return Value:
// The new reference count.
//
//--
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP_( ULONG ) CIISClusCfg::AddRef( void ) { return InterlockedIncrement( &m_cRef );
} //*** CIISClusCfg::AddRef
//////////////////////////////////////////////////////////////////////////////
//++
//
// [IUnknown]
// CIISClusCfg::Release
//
// Description:
// Decrement the reference count of this object by one.
// If this reaches 0, the object will be automatically deleted.
//
// Arguments:
// None.
//
// Return Value:
// The new reference count.
//
//--
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP_( ULONG ) CIISClusCfg::Release( void ) { LONG cRef;
cRef = InterlockedDecrement( &m_cRef ); if ( cRef == 0 ) { delete this; } // if:
return cRef;
} //*** CIISClusCfg::Release
//////////////////////////////////////////////////////////////////////////////
//++
//
// [IUnknown]
// CIISClusCfg::QueryInterface
//
// Description:
// Query this object for the passed in interface.
// This class implements the following interfaces:
//
// IUnknown
// IClusCfgStarutpListener
//
// Arguments:
// riidIn - Id of interface requested.
// ppvOut - Pointer to the requested interface. NULL if unsupported.
//
// Return Value:
// S_OK - If the interface is available on this object.
// E_POINTER - ppvOut was NULL.
// E_NOINTERFACE - If the interface is not available.
//
//--
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CIISClusCfg::QueryInterface( REFIID riidIn , void ** ppvOut ) { HRESULT hr = S_OK;
//
// Validate arguments.
//
if ( ppvOut == NULL ) { hr = E_POINTER; goto Cleanup; } // if:
//
// Handle known interfaces.
//
if ( IsEqualIID( riidIn, IID_IUnknown ) ) { //
// We static_cast to IClusCfgStartupListener* to avoid conflicts
// if this class should inherit IUnknown from more than one
// interface.
//
*ppvOut = static_cast< IClusCfgStartupListener * >( this ); } // if:
else if ( IsEqualIID( riidIn, IID_IClusCfgStartupListener ) ) { *ppvOut = static_cast< IClusCfgStartupListener * >( this ); } // else if:
else if ( IsEqualIID( riidIn, IID_IClusCfgEvictListener ) ) { *ppvOut = static_cast< IClusCfgEvictListener * >( this ); } // else if:
else { *ppvOut = NULL; hr = E_NOINTERFACE; } // else:
//
// Add a reference to the interface if successful.
//
if ( SUCCEEDED( hr ) ) { //
// We will return an interface pointer, so the reference counter needs to
// be incremented.
//
((IUnknown *) *ppvOut)->AddRef(); } // if:
Cleanup:
return hr;
} //*** CIISClusCfg::QueryInterface
//////////////////////////////////////////////////////////////////////////////
//++
//
// CIISClusCfg::HrCleanupResourceTypes
//
// Description:
// This function will clean up any resource types leftover from a Windows 2000
// cluster installation which are no longer supported.
//
// Arguments:
// none
//
// Return Value:
// S_OK
// Operation completed successfully.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT CIISClusCfg::HrCleanupResourceTypes( void ) { HRESULT hr = S_OK; DWORD sc = ERROR_SUCCESS; HCLUSTER hCluster = NULL; WCHAR szClusterName[ MAX_PATH ]; DWORD cchClusterName = RTL_NUMBER_OF( szClusterName ); CLUSTERVERSIONINFO clusterInfo; PCWSTR * ppszResType;
//
// Open the local cluster service. We can do this since we are running on the
// node that evicted the node, not the node that was evicted...
//
hCluster = OpenCluster( NULL ); if ( hCluster == NULL ) { sc = GetLastError(); hr = HRESULT_FROM_WIN32( sc ); LogMsg( L"[IISCLUSCFG] Error opening connection to local cluster service. (hr = %#08x)", hr ); goto Cleanup; } // if:
//
// Check if the entire cluster is running Windows Server 2003 (NT 5.1).
//
sc = GetClusterInformation( hCluster, szClusterName, &cchClusterName, &clusterInfo ); if ( sc != ERROR_SUCCESS ) { hr = HRESULT_FROM_WIN32( sc ); LogMsg( L"[IISCLUSCFG] Error getting the cluster version information. (hr = %#08x)", hr ); goto Cleanup; } // if:
//
// If the whole cluster is Windows Server 2003, then the highest version will be NT51, and
// the lowest version will be NT5. This is because ClusterHighestVersion is set to the
// min of the highest version that all nodes can "speak", and ClusterLowestVersion is set to the
// max of the lowest version that all nodes can speak.
//
if ( ( CLUSTER_GET_MAJOR_VERSION( clusterInfo.dwClusterHighestVersion ) == NT51_MAJOR_VERSION ) && ( CLUSTER_GET_MAJOR_VERSION( clusterInfo.dwClusterLowestVersion ) == NT5_MAJOR_VERSION ) ) { //
// We don't need to enumerate resources to make sure
// that no IIS resources exist before we delete the resource types. The deletion
// of a resource type will fail if resources of that type exist.
//
for ( ppszResType = g_apszResourceTypesToDelete; *ppszResType != NULL; ++ppszResType ) { //
// ERROR_SUCCESS: successful deletion.
//
// ERROR_CLUSTER_RESOURCE_TYPE_NOT_FOUND: no problem. The resource type didn't exist,
// so this must be a fresh Windows Server 2003 installation, not an upgrade.
//
// ERROR_DIR_NOT_EMPTY: a resource of that type exists. In this case we require manual
// intervention by an administrator.
sc = DeleteClusterResourceType( hCluster, *ppszResType ); if ( sc == ERROR_SUCCESS ) { LogMsg( L"[IISCLUSCFG] Successfully deleted resource type \"%ws\". (hr = %#08x)", *ppszResType, HRESULT_FROM_WIN32( sc ) ); continue; } // if: resource type was deleted.
else if ( sc == ERROR_DIR_NOT_EMPTY ) { LogMsg( L"[IISCLUSCFG] Could not delete resource type \"%ws\" because there are resources of this type. Trying the next resource type in the table... (hr = %#08x)", *ppszResType, HRESULT_FROM_WIN32( sc ) ); continue; } // else if: resources of this type exist.
else if ( sc == ERROR_CLUSTER_RESOURCE_TYPE_NOT_FOUND ) { LogMsg( L"[IISCLUSCFG] Could not delete resource type \"%ws\" because the resource type was not found. Trying the next resource type in the table... (hr = %#08x)", *ppszResType, HRESULT_FROM_WIN32( sc ) ); continue; } // else if: resource type was not found.
else { //
// We failed to delete the resource type.
//
//
// Keep track of the last failure.
// But don't bail out. Keep deleting the other types.
//
hr = HRESULT_FROM_WIN32( sc ); LogMsg( L"[IISCLUSCFG] Unexpected error deleting resource type \"%ws\". Trying the next resource type in the table... (hr = %#08x)", *ppszResType, hr ); } // else: some unknown error.
} // for: each resource type in the table.
} // if: this cluster is 100% Windows Server 2003.
Cleanup:
if ( hCluster != NULL ) { CloseCluster( hCluster ); } // if:
return hr;
} //*** CIISClusCfg::HrCleanupResourceTypes
//////////////////////////////////////////////////////////////////////////////
//++
//
// [IClusCfgStartupListener]
// CIISClusCfg::Notify
//
// Description:
// This function gets called just after the cluster service has started.
//
// Arguments:
// punkIn
// Pointer to a COM object that implements
// IClusCfgResourceTypeCreate.
//
// Return Value:
// S_OK
// Operation completed successfully.
//
//--
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CIISClusCfg::Notify( IUnknown * /*unused: punkIn*/ ) { HRESULT hr = S_OK;
LogMsg( L"[IISCLUSCFG] Entering startup notify... (hr = %#08x)", hr );
hr = HrCleanupResourceTypes();
LogMsg( L"[IISCLUSCFG] Leaving startup notify... (hr = %#08x)", hr );
return hr;
} //*** IISClusCfg::Notify
//////////////////////////////////////////////////////////////////////////////
//++
//
// [IClusCfgEvictListener]
// CIISClusCfg::EvictNotify
//
// Description:
// This function gets called after a node has been evicted.
//
// Arguments:
// pcszNodeNameIn
// The name of the node that has been evicted.
//
// Return Value:
// S_OK
// Operation completed successfully.
//
//--
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP CIISClusCfg::EvictNotify( PCWSTR /* unused: pcszNodeNameIn */ ) { HRESULT hr = S_OK;
LogMsg( L"[IISCLUSCFG] Entering evict cleanup notify... (hr = %#08x)", hr );
hr = HrCleanupResourceTypes();
LogMsg( L"[IISCLUSCFG] Leaving evict cleanup notify... (hr = %#08x)", hr );
return hr;
} //*** IISClusCfg::EvictNotify
//***************************************************************************
//
// Private methods
//
//***************************************************************************
//////////////////////////////////////////////////////////////////////////////
//++
//
// CIISClusCfg::HrInit
//
// Description:
// Initialize this component.
//
// Arguments:
// None.
//
// Return Value:
// S_OK - Operation completed successfully.
//
// Remarks:
// None.
//
//--
//////////////////////////////////////////////////////////////////////////////
HRESULT CIISClusCfg::HrInit( void ) { HRESULT hr = S_OK;
// IUnknown
//Assert( m_cRef == 1 );
return hr;
} //*** CIISClusCfg::HrInit
|