windows-nt/Source/XPSP1/NT/base/cluster/admin/cluadmin/res.cpp

3655 lines
113 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
/////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 1996-2000 Microsoft Corporation
//
// Module Name:
// Res.cpp
//
// Abstract:
// Implementation of the CResource class.
//
// Author:
// David Potter (davidp) May 6, 1996
//
// Revision History:
//
// Notes:
//
/////////////////////////////////////////////////////////////////////////////
#include "StdAfx.h"
#include "CluAdmin.h"
#include "ConstDef.h"
#include "Res.h"
#include "ClusItem.inl"
#include "ResProp.h"
#include "ExcOper.h"
#include "TraceTag.h"
#include "Cluster.h"
#include "DelRes.h"
#include "MoveRes.h"
#include "WaitDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// Global Variables
/////////////////////////////////////////////////////////////////////////////
#ifdef _DEBUG
CTraceTag g_tagResource(_T("Document"), _T("RESOURCE"), 0);
CTraceTag g_tagResNotify(_T("Notify"), _T("RES NOTIFY"), 0);
CTraceTag g_tagResRegNotify(_T("Notify"), _T("RES REG NOTIFY"), 0);
#endif
/////////////////////////////////////////////////////////////////////////////
// CResource
/////////////////////////////////////////////////////////////////////////////
IMPLEMENT_DYNCREATE(CResource, CClusterItem)
/////////////////////////////////////////////////////////////////////////////
// Message Maps
BEGIN_MESSAGE_MAP(CResource, CClusterItem)
//{{AFX_MSG_MAP(CResource)
ON_UPDATE_COMMAND_UI(ID_FILE_BRING_ONLINE, OnUpdateBringOnline)
ON_UPDATE_COMMAND_UI(ID_FILE_TAKE_OFFLINE, OnUpdateTakeOffline)
ON_UPDATE_COMMAND_UI(ID_FILE_INITIATE_FAILURE, OnUpdateInitiateFailure)
ON_UPDATE_COMMAND_UI(ID_FILE_MOVE_RESOURCE_1, OnUpdateMoveResource1)
ON_UPDATE_COMMAND_UI(ID_FILE_MOVE_RESOURCE_2, OnUpdateMoveResourceRest)
ON_UPDATE_COMMAND_UI(ID_FILE_MOVE_RESOURCE_3, OnUpdateMoveResourceRest)
ON_UPDATE_COMMAND_UI(ID_FILE_MOVE_RESOURCE_4, OnUpdateMoveResourceRest)
ON_UPDATE_COMMAND_UI(ID_FILE_MOVE_RESOURCE_5, OnUpdateMoveResourceRest)
ON_UPDATE_COMMAND_UI(ID_FILE_MOVE_RESOURCE_6, OnUpdateMoveResourceRest)
ON_UPDATE_COMMAND_UI(ID_FILE_MOVE_RESOURCE_7, OnUpdateMoveResourceRest)
ON_UPDATE_COMMAND_UI(ID_FILE_MOVE_RESOURCE_8, OnUpdateMoveResourceRest)
ON_UPDATE_COMMAND_UI(ID_FILE_MOVE_RESOURCE_9, OnUpdateMoveResourceRest)
ON_UPDATE_COMMAND_UI(ID_FILE_MOVE_RESOURCE_10, OnUpdateMoveResourceRest)
ON_UPDATE_COMMAND_UI(ID_FILE_MOVE_RESOURCE_11, OnUpdateMoveResourceRest)
ON_UPDATE_COMMAND_UI(ID_FILE_MOVE_RESOURCE_12, OnUpdateMoveResourceRest)
ON_UPDATE_COMMAND_UI(ID_FILE_MOVE_RESOURCE_13, OnUpdateMoveResourceRest)
ON_UPDATE_COMMAND_UI(ID_FILE_MOVE_RESOURCE_14, OnUpdateMoveResourceRest)
ON_UPDATE_COMMAND_UI(ID_FILE_MOVE_RESOURCE_15, OnUpdateMoveResourceRest)
ON_UPDATE_COMMAND_UI(ID_FILE_MOVE_RESOURCE_16, OnUpdateMoveResourceRest)
ON_UPDATE_COMMAND_UI(ID_FILE_MOVE_RESOURCE_17, OnUpdateMoveResourceRest)
ON_UPDATE_COMMAND_UI(ID_FILE_MOVE_RESOURCE_18, OnUpdateMoveResourceRest)
ON_UPDATE_COMMAND_UI(ID_FILE_MOVE_RESOURCE_19, OnUpdateMoveResourceRest)
ON_UPDATE_COMMAND_UI(ID_FILE_MOVE_RESOURCE_20, OnUpdateMoveResourceRest)
ON_UPDATE_COMMAND_UI(ID_FILE_DELETE, OnUpdateDelete)
ON_UPDATE_COMMAND_UI(ID_FILE_PROPERTIES, OnUpdateProperties)
ON_COMMAND(ID_FILE_BRING_ONLINE, OnCmdBringOnline)
ON_COMMAND(ID_FILE_TAKE_OFFLINE, OnCmdTakeOffline)
ON_COMMAND(ID_FILE_INITIATE_FAILURE, OnCmdInitiateFailure)
ON_COMMAND(ID_FILE_DELETE, OnCmdDelete)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::CResource
//
// Routine Description:
// Default constructor.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
CResource::CResource(void)
: CClusterItem(NULL, IDS_ITEMTYPE_RESOURCE)
{
CommonConstruct();
} //*** CResoruce::CResource()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::CResource
//
// Routine Description:
// Constructor.
//
// Arguments:
// bDocObj [IN] TRUE = object is part of the document.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
CResource::CResource(IN BOOL bDocObj)
: CClusterItem(NULL, IDS_ITEMTYPE_RESOURCE)
{
CommonConstruct();
m_bDocObj = bDocObj;
} //*** CResource::CResource(bDocObj)
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::CommonConstruct
//
// Routine Description:
// Common construction.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CResource::CommonConstruct(void)
{
m_idmPopupMenu = IDM_RESOURCE_POPUP;
m_bInitializing = FALSE;
m_bDeleting = FALSE;
m_hresource = NULL;
m_bSeparateMonitor = FALSE;
m_nLooksAlive = CLUSTER_RESOURCE_DEFAULT_LOOKS_ALIVE;
m_nIsAlive = CLUSTER_RESOURCE_DEFAULT_IS_ALIVE;
m_crraRestartAction = CLUSTER_RESOURCE_DEFAULT_RESTART_ACTION;
m_nRestartThreshold = CLUSTER_RESOURCE_DEFAULT_RESTART_THRESHOLD;
m_nRestartPeriod = CLUSTER_RESOURCE_DEFAULT_RESTART_PERIOD;
m_nPendingTimeout = CLUSTER_RESOURCE_DEFAULT_PENDING_TIMEOUT;
m_rciResClassInfo.rc = CLUS_RESCLASS_UNKNOWN;
m_rciResClassInfo.SubClass = 0;
m_dwCharacteristics = CLUS_CHAR_UNKNOWN;
m_dwFlags = 0;
m_pciOwner = NULL;
m_pciGroup = NULL;
m_pciResourceType = NULL;
m_pcrd = NULL;
m_plpciresDependencies = NULL;
m_plpcinodePossibleOwners = NULL;
// Set the object type image.
m_iimgObjectType = GetClusterAdminApp()->Iimg(IMGLI_RES);
// Setup the property array.
{
m_rgProps[epropName].Set(CLUSREG_NAME_RES_NAME, m_strName, m_strName);
m_rgProps[epropType].Set(CLUSREG_NAME_RES_TYPE, m_strResourceType, m_strResourceType);
m_rgProps[epropDescription].Set(CLUSREG_NAME_RES_DESC, m_strDescription, m_strDescription);
m_rgProps[epropSeparateMonitor].Set(CLUSREG_NAME_RES_SEPARATE_MONITOR, m_bSeparateMonitor, m_bSeparateMonitor);
m_rgProps[epropLooksAlive].Set(CLUSREG_NAME_RES_LOOKS_ALIVE, m_nLooksAlive, m_nLooksAlive);
m_rgProps[epropIsAlive].Set(CLUSREG_NAME_RES_IS_ALIVE, m_nIsAlive, m_nIsAlive);
m_rgProps[epropRestartAction].Set(CLUSREG_NAME_RES_RESTART_ACTION, (DWORD &) m_crraRestartAction, (DWORD &) m_crraRestartAction);
m_rgProps[epropRestartThreshold].Set(CLUSREG_NAME_RES_RESTART_THRESHOLD, m_nRestartThreshold, m_nRestartThreshold);
m_rgProps[epropRestartPeriod].Set(CLUSREG_NAME_RES_RESTART_PERIOD, m_nRestartPeriod, m_nRestartPeriod);
m_rgProps[epropPendingTimeout].Set(CLUSREG_NAME_RES_PENDING_TIMEOUT, m_nPendingTimeout, m_nPendingTimeout);
} // Setup the property array
#ifdef _CLUADMIN_USE_OLE_
EnableAutomation();
#endif
// To keep the application running as long as an OLE automation
// object is active, the constructor calls AfxOleLockApp.
// AfxOleLockApp();
} //*** CResource::CommonConstruct()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::~CResource
//
// Routine Description:
// Destructor.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
CResource::~CResource(void)
{
// Cleanup this object.
Cleanup();
delete m_plpciresDependencies;
delete m_plpcinodePossibleOwners;
delete [] (PBYTE) m_pcrd;
// Close the resource handle.
if (Hresource() != NULL)
{
CloseClusterResource(Hresource());
m_hresource = NULL;
} // if: resource is open
// To terminate the application when all objects created with
// with OLE automation, the destructor calls AfxOleUnlockApp.
// AfxOleUnlockApp();
} //*** CResource::~CResource
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::Cleanup
//
// Routine Description:
// Cleanup the item.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CResource::Cleanup(void)
{
// Delete the Dependencies list.
if (m_plpciresDependencies != NULL)
m_plpciresDependencies->RemoveAll();
// Delete the PossibleOwners list.
if (m_plpcinodePossibleOwners != NULL)
m_plpcinodePossibleOwners->RemoveAll();
// If we are active on a node, remove ourselves from that active list.
if (PciOwner() != NULL)
{
if (BDocObj())
PciOwner()->RemoveActiveResource(this);
PciOwner()->Release();
m_pciOwner = NULL;
} // if: there is an owner
// Remove ourselves from the group's list.
if (PciGroup() != NULL)
{
if (BDocObj())
PciGroup()->RemoveResource(this);
PciGroup()->Release();
m_pciGroup = NULL;
} // if: there is a group
// Update the reference count to the resource type
if (PciResourceType() != NULL)
{
PciResourceType()->Release();
m_pciResourceType = NULL;
} // if: there is a resource type
// Remove the item from the resource list.
if (BDocObj())
{
POSITION posPci;
posPci = Pdoc()->LpciResources().Find(this);
if (posPci != NULL)
{
Pdoc()->LpciResources().RemoveAt(posPci);
} // if: found in the document's list
} // if: this is a document object
} //*** CResource::Cleanup()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::Create
//
// Routine Description:
// Create a resource.
//
// Arguments:
// pdoc [IN OUT] Document to which this item belongs.
// lpszName [IN] Name of the resource.
// lpszType [IN] Type of the resource.
// lpszGroup [IN] Group in which to create the resource.
// bSeparateMonitor [IN] TRUE = run resource in separate monitor.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// CNTException Errors from CreateClusterResource.
// Any exceptions thrown by CResource::Init(), CResourceList::new(),
// or CNodeList::new().
//
//--
/////////////////////////////////////////////////////////////////////////////
void CResource::Create(
IN OUT CClusterDoc * pdoc,
IN LPCTSTR lpszName,
IN LPCTSTR lpszType,
IN LPCTSTR lpszGroup,
IN BOOL bSeparateMonitor
)
{
DWORD dwStatus;
DWORD dwFlags;
HRESOURCE hresource;
CGroup * pciGroup;
CString strName(lpszName); // Required if built non-Unicode
CString strType(lpszType); // Required if built non-Unicode
CWaitCursor wc;
ASSERT(Hresource() == NULL);
ASSERT(Hkey() == NULL);
ASSERT_VALID(pdoc);
ASSERT(lpszName != NULL);
ASSERT(lpszType != NULL);
ASSERT(lpszGroup != NULL);
// Find the specified group.
pciGroup = pdoc->LpciGroups().PciGroupFromName(lpszGroup);
ASSERT_VALID(pciGroup);
// Set the flags.
if (bSeparateMonitor)
dwFlags = CLUSTER_RESOURCE_SEPARATE_MONITOR;
else
dwFlags = 0;
// Create the resource.
hresource = CreateClusterResource(pciGroup->Hgroup(), strName, strType, dwFlags);
if (hresource == NULL)
{
dwStatus = GetLastError();
ThrowStaticException(dwStatus, IDS_CREATE_RESOURCE_ERROR, lpszName);
} // if: error creating the cluster resource
CloseClusterResource(hresource);
// Open the resource.
Init(pdoc, lpszName);
} //*** CResource::Create()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::Init
//
// Routine Description:
// Initialize the item.
//
// Arguments:
// pdoc [IN OUT] Document to which this item belongs.
// lpszName [IN] Name of the item.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// CNTException Errors from OpenClusterResource or GetClusterResourceKey.
// Any exceptions thrown by new.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CResource::Init(IN OUT CClusterDoc * pdoc, IN LPCTSTR lpszName)
{
DWORD dwStatus = ERROR_SUCCESS;
LONG lResult;
CString strName(lpszName); // Required if built non-Unicode
CWaitCursor wc;
ASSERT(Hresource() == NULL);
ASSERT(Hkey() == NULL);
// Call the base class method.
CClusterItem::Init(pdoc, lpszName);
try
{
// Open the resource.
m_hresource = OpenClusterResource(Hcluster(), strName);
if (Hresource() == NULL)
{
dwStatus = GetLastError();
ThrowStaticException(dwStatus, IDS_OPEN_RESOURCE_ERROR, lpszName);
} // if: error opening the cluster resource
// Get the resource registry key.
m_hkey = GetClusterResourceKey(Hresource(), MAXIMUM_ALLOWED);
if (Hkey() == NULL)
ThrowStaticException(GetLastError(), IDS_GET_RESOURCE_KEY_ERROR, lpszName);
if (BDocObj())
{
ASSERT(Pcnk() != NULL);
Trace(g_tagClusItemNotify, _T("CResource::Init() - Registering for resource notifications (%08.8x) for '%s'"), Pcnk(), StrName());
// Register for resource notifications.
lResult = RegisterClusterNotify(
GetClusterAdminApp()->HchangeNotifyPort(),
(CLUSTER_CHANGE_RESOURCE_STATE
| CLUSTER_CHANGE_RESOURCE_DELETED
| CLUSTER_CHANGE_RESOURCE_PROPERTY),
Hresource(),
(DWORD_PTR) Pcnk()
);
if (lResult != ERROR_SUCCESS)
{
dwStatus = lResult;
ThrowStaticException(dwStatus, IDS_RES_NOTIF_REG_ERROR, lpszName);
} // if: error registering for resource notifications
// Register for registry notifications.
if (Hkey != NULL)
{
lResult = RegisterClusterNotify(
GetClusterAdminApp()->HchangeNotifyPort(),
(CLUSTER_CHANGE_REGISTRY_NAME
| CLUSTER_CHANGE_REGISTRY_ATTRIBUTES
| CLUSTER_CHANGE_REGISTRY_VALUE
| CLUSTER_CHANGE_REGISTRY_SUBTREE),
Hkey(),
(DWORD_PTR) Pcnk()
);
if (lResult != ERROR_SUCCESS)
{
dwStatus = lResult;
ThrowStaticException(dwStatus, IDS_RES_NOTIF_REG_ERROR, lpszName);
} // if: error registering for registry notifications
} // if: there is a key
} // if: document object
// Allocate lists.
m_plpciresDependencies = new CResourceList;
if ( m_plpciresDependencies == NULL )
{
AfxThrowMemoryException();
} // if: error allocating the dependency list
m_plpcinodePossibleOwners = new CNodeList;
if ( m_plpcinodePossibleOwners == NULL )
{
AfxThrowMemoryException();
} // if: error allocating the possible owners list
// Read the initial state.
UpdateState();
} // try
catch (CException *)
{
if (Hkey() != NULL)
{
ClusterRegCloseKey(Hkey());
m_hkey = NULL;
} // if: registry key opened
if (Hresource() != NULL)
{
CloseClusterResource(Hresource());
m_hresource = NULL;
} // if: resource opened
m_bReadOnly = TRUE;
throw;
} // catch: CException
} //*** CResource::Init()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::ReadItem
//
// Routine Description:
// Read the item parameters from the cluster database.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// CNTException Errors from CClusterItem::DwReadValue().
//
//--
/////////////////////////////////////////////////////////////////////////////
void CResource::ReadItem(void)
{
DWORD dwStatus;
DWORD dwRetStatus = ERROR_SUCCESS;
CWaitCursor wc;
ASSERT_VALID(this);
m_bInitializing = FALSE;
if (Hresource() != NULL)
{
m_rgProps[epropDescription].m_value.pstr = &m_strDescription;
m_rgProps[epropSeparateMonitor].m_value.pb = &m_bSeparateMonitor;
m_rgProps[epropLooksAlive].m_value.pdw = &m_nLooksAlive;
m_rgProps[epropIsAlive].m_value.pdw = &m_nIsAlive;
m_rgProps[epropRestartAction].m_value.pdw = (DWORD *) &m_crraRestartAction;
m_rgProps[epropRestartThreshold].m_value.pdw = &m_nRestartThreshold;
m_rgProps[epropRestartPeriod].m_value.pdw = &m_nRestartPeriod;
m_rgProps[epropPendingTimeout].m_value.pdw = &m_nPendingTimeout;
// Call the base class method.
Trace( g_tagResource, _T("(%s) (%s (%x)) - CResource::ReadItem() - Calling CClusterItem::ReadItem()"), Pdoc()->StrNode(), StrName(), this );
CClusterItem::ReadItem();
// Read and parse the common properties.
{
CClusPropList cpl;
Trace( g_tagResource, _T("(%s) (%s (%x)) - CResource::ReadItem() - Getting common properties"), Pdoc()->StrNode(), StrName(), this );
dwStatus = cpl.ScGetResourceProperties(
Hresource(),
CLUSCTL_RESOURCE_GET_COMMON_PROPERTIES
);
if (dwStatus == ERROR_SUCCESS)
{
Trace( g_tagResource, _T("(%s) (%s (%x)) - CResource::ReadItem() - Parsing common properties"), Pdoc()->StrNode(), StrName(), this );
dwStatus = DwParseProperties(cpl);
} // if: properties read successfully
if (dwStatus != ERROR_SUCCESS)
{
Trace( g_tagError, _T("(%s) (%s (%x)) - CResource::ReadItem() - Error 0x%08.8x getting or parsing common properties"), Pdoc()->StrNode(), StrName(), this, dwStatus );
dwRetStatus = dwStatus;
} // if: error reading or parsing properties
} // Read and parse the common properties
// Read and parse the read-only common properties.
if (dwRetStatus == ERROR_SUCCESS)
{
CClusPropList cpl;
Trace( g_tagResource, _T("(%s) (%s (%x)) - CResource::ReadItem() - Getting common RO properties"), Pdoc()->StrNode(), StrName(), this );
dwStatus = cpl.ScGetResourceProperties(
Hresource(),
CLUSCTL_RESOURCE_GET_RO_COMMON_PROPERTIES
);
if (dwStatus == ERROR_SUCCESS)
{
Trace( g_tagResource, _T("(%s) (%s (%x)) - CResource::ReadItem() - Parsing common RO properties"), Pdoc()->StrNode(), StrName(), this );
dwStatus = DwParseProperties(cpl);
} // if: properties read successfully
if (dwStatus != ERROR_SUCCESS)
{
Trace( g_tagError, _T("(%s) (%s (%x)) - CResource::ReadItem() - Error 0x%08.8x getting or parsing common RO properties"), Pdoc()->StrNode(), StrName(), this, dwStatus );
dwRetStatus = dwStatus;
} // if: error reading or parsing properties
} // if: no error yet
// Find the resource type object.
{
CResourceType * pciResType;
pciResType = Pdoc()->LpciResourceTypes().PciResTypeFromName(StrResourceType());
if (m_pciResourceType != NULL)
m_pciResourceType->Release();
m_pciResourceType = pciResType;
if (m_pciResourceType != NULL)
m_pciResourceType->AddRef();
} // Find the resource type object
// Read the required dependencies.
if (dwRetStatus == ERROR_SUCCESS)
{
PCLUSPROP_REQUIRED_DEPENDENCY pcrd;
Trace( g_tagResource, _T("(%s) (%s (%x)) - CResource::ReadItem() - Getting required dependencies"), Pdoc()->StrNode(), StrName(), this );
dwStatus = DwResourceControlGet(CLUSCTL_RESOURCE_GET_REQUIRED_DEPENDENCIES, (PBYTE *) &pcrd);
if (dwStatus != ERROR_SUCCESS)
{
Trace( g_tagError, _T("(%s) (%s (%x)) - CResource::ReadItem() - Error 0x%08.8x getting required dependencies"), Pdoc()->StrNode(), StrName(), this, dwStatus );
dwRetStatus = dwStatus;
} // if: error getting required dependencies
delete [] (PBYTE) m_pcrd;
m_pcrd = pcrd;
} // if: no error yet
// Read the resource class.
if (dwRetStatus == ERROR_SUCCESS)
{
DWORD cbReturned;
dwStatus = ClusterResourceControl(
Hresource(),
NULL,
CLUSCTL_RESOURCE_GET_CLASS_INFO,
NULL,
NULL,
&m_rciResClassInfo,
sizeof(m_rciResClassInfo),
&cbReturned
);
if (dwStatus != ERROR_SUCCESS)
dwRetStatus = dwStatus;
else
{
ASSERT(cbReturned == sizeof(m_rciResClassInfo));
} // else: data retrieved successfully
} // if: no error yet
// Read the characteristics.
if (dwRetStatus == ERROR_SUCCESS)
{
DWORD cbReturned;
dwStatus = ClusterResourceControl(
Hresource(),
NULL,
CLUSCTL_RESOURCE_GET_CHARACTERISTICS,
NULL,
NULL,
&m_dwCharacteristics,
sizeof(m_dwCharacteristics),
&cbReturned
);
if (dwStatus != ERROR_SUCCESS)
dwRetStatus = dwStatus;
else
{
ASSERT(cbReturned == sizeof(m_dwCharacteristics));
} // else: data retrieved successfully
} // if: no error yet
// Read the flags.
if (dwRetStatus == ERROR_SUCCESS)
{
DWORD cbReturned;
dwStatus = ClusterResourceControl(
Hresource(),
NULL,
CLUSCTL_RESOURCE_GET_FLAGS,
NULL,
NULL,
&m_dwFlags,
sizeof(m_dwFlags),
&cbReturned
);
if (dwStatus != ERROR_SUCCESS)
dwRetStatus = dwStatus;
else
{
ASSERT(cbReturned == sizeof(m_dwFlags));
} // else: data retrieved successfully
} // if: no error yet
// Construct the list of extensions.
ReadExtensions();
if (dwRetStatus == ERROR_SUCCESS)
{
// Construct the lists.
CollectPossibleOwners(NULL);
CollectDependencies(NULL);
} // if: no error reading properties
} // if: resource is available
// Read the initial state.
UpdateState();
// If any errors occurred, throw an exception.
if (dwRetStatus != ERROR_SUCCESS)
{
m_bReadOnly = TRUE;
if ( (dwRetStatus != ERROR_RESOURCE_NOT_AVAILABLE)
&& (dwRetStatus != ERROR_KEY_DELETED))
ThrowStaticException(dwRetStatus, IDS_READ_RESOURCE_PROPS_ERROR, StrName());
} // if: error reading properties
MarkAsChanged(FALSE);
} //*** CResource::ReadItem()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::DwResourceControlGet
//
// Routine Description:
// Send a control function to the resource to get information from it.
//
// Arguments:
// dwFunctionCode [IN] Control function code.
// pbInBuf [IN] Input buffer to pass to the resource.
// cbInBuf [IN] Size of data in input buffer.
// ppbOutBuf [OUT] Output buffer.
//
// Return Value:
// Any status returned from ClusterResourceControl().
//
//--
/////////////////////////////////////////////////////////////////////////////
DWORD CResource::DwResourceControlGet(
IN DWORD dwFunctionCode,
IN PBYTE pbInBuf,
IN DWORD cbInBuf,
OUT PBYTE * ppbOutBuf
)
{
DWORD dwStatus = ERROR_SUCCESS;
DWORD cbOutBuf = 512;
CWaitCursor wc;
ASSERT(ppbOutBuf != NULL);
*ppbOutBuf = NULL;
// Allocate memory for the buffer.
try
{
*ppbOutBuf = new BYTE[cbOutBuf];
if ( *ppbOutBuf == NULL )
{
AfxThrowMemoryException();
} // if: error allocating the output buffer
} // try
catch (CMemoryException * pme)
{
*ppbOutBuf = NULL;
dwStatus = ERROR_NOT_ENOUGH_MEMORY;
pme->Delete();
} // catch: CMemoryException
if (dwStatus != ERROR_SUCCESS)
return dwStatus;
// Call the control function to get the data.
dwStatus = ClusterResourceControl(
Hresource(),
NULL,
dwFunctionCode,
pbInBuf,
cbInBuf,
*ppbOutBuf,
cbOutBuf,
&cbOutBuf
);
if (dwStatus == ERROR_MORE_DATA)
{
// Allocate more memory for the buffer.
try
{
dwStatus = ERROR_SUCCESS;
delete [] *ppbOutBuf;
*ppbOutBuf = new BYTE[cbOutBuf];
if ( *ppbOutBuf == NULL )
{
AfxThrowMemoryException();
} // if: error allocating the output buffer
} // try
catch (CMemoryException * pme)
{
*ppbOutBuf = NULL;
dwStatus = ERROR_NOT_ENOUGH_MEMORY;
pme->Delete();
} // catch: CMemoryException
if (dwStatus != ERROR_SUCCESS)
return dwStatus;
// Call the control function again to get the data.
dwStatus = ClusterResourceControl(
Hresource(),
NULL,
dwFunctionCode,
pbInBuf,
cbInBuf,
*ppbOutBuf,
cbOutBuf,
&cbOutBuf
);
} // if: our buffer is too small
if ((dwStatus != ERROR_SUCCESS) || (cbOutBuf == 0))
{
delete [] *ppbOutBuf;
*ppbOutBuf = NULL;
} // if: error getting data or no data returned
return dwStatus;
} //*** CResource::DwResourceControlGet()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::PlstrExtension
//
// Routine Description:
// Return the list of admin extensions.
//
// Arguments:
// None.
//
// Return Value:
// plstr List of extensions.
// NULL No extension associated with this object.
//
// Exceptions Thrown:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
const CStringList * CResource::PlstrExtensions(void) const
{
return &LstrCombinedExtensions();
} //*** CResource::PlstrExtensions()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::ReadExtensions
//
// Routine Description:
// Read extension lists.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CResource::ReadExtensions(void)
{
CWaitCursor wc;
// Construct the list of extensions.
{
POSITION posStr;
const CStringList * plstr;
ASSERT_VALID(Pdoc());
m_lstrCombinedExtensions.RemoveAll();
// Add resource-specific extensions first.
if (PciResourceType() != NULL)
{
ASSERT_VALID(PciResourceType());
plstr = &PciResourceType()->LstrAdminExtensions();
posStr = plstr->GetHeadPosition();
while (posStr != NULL)
{
m_lstrCombinedExtensions.AddTail(plstr->GetNext(posStr));
} // while: more extensions available
} // if: valid resource type found
// Add extensions for all resources next.
plstr = &Pdoc()->PciCluster()->LstrResourceExtensions();
posStr = plstr->GetHeadPosition();
while (posStr != NULL)
{
m_lstrCombinedExtensions.AddTail(plstr->GetNext(posStr));
} // while: more extensions available
} // Construct the list of extensions
} //*** CResource::ReadExtensions()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::CollecPossibleOwners
//
// Routine Description:
// Construct a list of node items which are enumerable on the
// resource.
//
// Arguments:
// plpci [IN OUT] List to fill.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// CNTException Errors from ClusterResourceOpenEnum() or
// ClusterResourceEnum().
// Any exceptions thrown by new or CList::AddTail().
//
//--
/////////////////////////////////////////////////////////////////////////////
void CResource::CollectPossibleOwners(IN OUT CNodeList * plpci) const
{
DWORD dwStatus;
HRESENUM hresenum;
int ienum;
LPWSTR pwszName = NULL;
DWORD cchName;
DWORD cchmacName;
DWORD dwRetType;
CClusterNode * pciNode;
CWaitCursor wc;
ASSERT_VALID(Pdoc());
ASSERT(Hresource() != NULL);
if (plpci == NULL)
plpci = m_plpcinodePossibleOwners;
ASSERT(plpci != NULL);
// Remove the previous contents of the list.
plpci->RemoveAll();
if (Hresource() != NULL)
{
// Open the enumeration.
hresenum = ClusterResourceOpenEnum(Hresource(), CLUSTER_RESOURCE_ENUM_NODES);
if (hresenum == NULL)
ThrowStaticException(GetLastError(), IDS_ENUM_POSSIBLE_OWNERS_ERROR, StrName());
try
{
// Allocate a name buffer.
cchmacName = 128;
pwszName = new WCHAR[cchmacName];
if ( pwszName == NULL )
{
AfxThrowMemoryException();
} // if: error allocating the name buffer
// Loop through the enumeration and add each dependent resource to the list.
for (ienum = 0 ; ; ienum++)
{
// Get the next item in the enumeration.
cchName = cchmacName;
dwStatus = ClusterResourceEnum(hresenum, ienum, &dwRetType, pwszName, &cchName);
if (dwStatus == ERROR_MORE_DATA)
{
delete [] pwszName;
cchmacName = ++cchName;
pwszName = new WCHAR[cchmacName];
if ( pwszName == NULL )
{
AfxThrowMemoryException();
} // if: error allocating the name buffer
dwStatus = ClusterResourceEnum(hresenum, ienum, &dwRetType, pwszName, &cchName);
} // if: name buffer was too small
if (dwStatus == ERROR_NO_MORE_ITEMS)
break;
else if (dwStatus != ERROR_SUCCESS)
ThrowStaticException(dwStatus, IDS_ENUM_POSSIBLE_OWNERS_ERROR, StrName());
ASSERT(dwRetType == CLUSTER_RESOURCE_ENUM_NODES);
// Find the item in the list of resources on the document.
pciNode = Pdoc()->LpciNodes().PciNodeFromName(pwszName);
ASSERT_VALID(pciNode);
// Add the resource to the list.
if (pciNode != NULL)
{
plpci->AddTail(pciNode);
} // if: found node in list
} // for: each item in the group
delete [] pwszName;
ClusterResourceCloseEnum(hresenum);
} // try
catch (CException *)
{
delete [] pwszName;
ClusterResourceCloseEnum(hresenum);
throw;
} // catch: any exception
} // if: resource is available
} //*** CResource::CollecPossibleOwners()
/*
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::RemoveNodeFromPossibleOwners
//
// Routine Description:
// Remove the passed in node from the possible owners list.
//
// Arguments:
// plpci [IN OUT] List to fill.
// pNode [IN] The node to remove from the list
//
// Return Value:
// None.
//
// Exceptions Thrown:
// Any exceptions thrown by CList.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CResource::RemoveNodeFromPossibleOwners(
IN OUT CNodeList * plpci,
IN const CClusterNode * pNode
)
{
if (plpci == NULL)
{
plpci = m_plpcinodePossibleOwners;
} // if: plpci is NULL
ASSERT(plpci != NULL);
POSITION _pos;
CClusterNode * _pnode = plpci->PciNodeFromName(pNode->StrName(), &_pos);
if ((_pnode != NULL) && (_pos != NULL))
{
plpci->RemoveAt(_pos);
} // if: node was found in the list
} //*** CResource::RemoveNodeFromPossibleOwners()
*/
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::CollectDependencies
//
// Routine Description:
// Collect the resources on which this resource is dependent.
//
// Arguments:
// plpci [IN OUT] List to fill.
// bFullTree [IN] TRUE = collect dependencies of dependencies.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// CNTException Errors from ClusterResourceOpenEnum() or
// ClusterResourceEnum().
// Any exceptions thrown by new or CList::AddTail().
//
//--
/////////////////////////////////////////////////////////////////////////////
void CResource::CollectDependencies(
IN OUT CResourceList * plpci,
IN BOOL bFullTree
) const
{
DWORD dwStatus;
HRESENUM hresenum;
int ienum;
LPWSTR pwszName = NULL;
DWORD cchName;
DWORD cchmacName;
DWORD dwRetType;
CResource * pciRes;
CWaitCursor wc;
ASSERT_VALID(Pdoc());
ASSERT(Hresource() != NULL);
if (plpci == NULL)
plpci = m_plpciresDependencies;
ASSERT(plpci != NULL);
// Remove the previous contents of the list.
if (!bFullTree)
plpci->RemoveAll();
if (Hresource() != NULL)
{
// Open the enumeration.
hresenum = ClusterResourceOpenEnum(Hresource(), CLUSTER_RESOURCE_ENUM_DEPENDS);
if (hresenum == NULL)
ThrowStaticException(GetLastError(), IDS_ENUM_DEPENDENCIES_ERROR, StrName());
try
{
// Allocate a name buffer.
cchmacName = 128;
pwszName = new WCHAR[cchmacName];
if ( pwszName == NULL )
{
AfxThrowMemoryException();
} // if: error allocating the name buffer
// Loop through the enumeration and add each dependent resource to the list.
for (ienum = 0 ; ; ienum++)
{
// Get the next item in the enumeration.
cchName = cchmacName;
dwStatus = ClusterResourceEnum(hresenum, ienum, &dwRetType, pwszName, &cchName);
if (dwStatus == ERROR_MORE_DATA)
{
delete [] pwszName;
cchmacName = ++cchName;
pwszName = new WCHAR[cchmacName];
if ( pwszName == NULL )
{
AfxThrowMemoryException();
} // if: error allocating the name buffer
dwStatus = ClusterResourceEnum(hresenum, ienum, &dwRetType, pwszName, &cchName);
} // if: name buffer was too small
if (dwStatus == ERROR_NO_MORE_ITEMS)
break;
else if (dwStatus != ERROR_SUCCESS)
ThrowStaticException(dwStatus, IDS_ENUM_DEPENDENCIES_ERROR, StrName());
ASSERT(dwRetType == CLUSTER_RESOURCE_ENUM_DEPENDS);
// Find the item in the list of resources on the document and
// add its dependencies to the list.
pciRes = Pdoc()->LpciResources().PciResFromName(pwszName);
if (pciRes != NULL)
{
// Add this resource to the list.
if (plpci->Find(pciRes) == NULL)
{
plpci->AddTail(pciRes);
} // if: resource not in the list yet
// Add the resources on which this resource is dependent to the list.
if (bFullTree)
pciRes->CollectDependencies(plpci, bFullTree);
} // if: resource found in the list
} // for: each item in the group
delete [] pwszName;
ClusterResourceCloseEnum(hresenum);
} // try
catch (CException *)
{
delete [] pwszName;
if (hresenum != NULL)
ClusterResourceCloseEnum(hresenum);
throw;
} // catch: any exception
} // if: resource is available
} //*** CResource::CollectDependencies()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::CollectProvidesFor
//
// Routine Description:
// Collect the list of resources which are dependent on this resource.
//
// Arguments:
// plpci [IN OUT] List of resources.
// bFullTree [IN] TRUE = collect dependencies of dependencies.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// CNTException Errors from ClusterResourceOpenEnum() or
// ClusterResourceEnum().
// Any exceptions thrown by CList::AddHead().
//
//--
/////////////////////////////////////////////////////////////////////////////
void CResource::CollectProvidesFor(
IN OUT CResourceList * plpci,
IN BOOL bFullTree
) const
{
DWORD dwStatus;
HRESENUM hresenum = NULL;
WCHAR * pwszName = NULL;
int ienum;
DWORD cchName;
DWORD cchmacName;
DWORD dwType;
CResource * pciRes;
CWaitCursor wc;
ASSERT_VALID(this);
ASSERT(Hresource != NULL);
ASSERT(plpci != NULL);
// Remove the previous contents of the list.
if (!bFullTree)
plpci->RemoveAll();
if (Hresource() != NULL)
{
try
{
// Allocate a name buffer.
cchmacName = 128;
pwszName = new WCHAR[cchmacName];
if ( pwszName == NULL )
{
AfxThrowMemoryException();
} // if: error allocating the name buffer
// Open the enumeration.
hresenum = ClusterResourceOpenEnum(Hresource(), CLUSTER_RESOURCE_ENUM_PROVIDES);
if (hresenum == NULL)
ThrowStaticException(GetLastError(), IDS_ENUM_PROVIDES_FOR_ERROR, StrName());
// Loop through the enumeration and add each one's providers to the list.
for (ienum = 0 ; ; ienum++)
{
// Get the next item in the enumeration.
cchName = cchmacName;
dwStatus = ClusterResourceEnum(hresenum, ienum, &dwType, pwszName, &cchName);
if (dwStatus == ERROR_MORE_DATA)
{
delete [] pwszName;
cchmacName = ++cchName;
pwszName = new WCHAR[cchmacName];
if ( pwszName == NULL )
{
AfxThrowMemoryException();
} // if: error allocating the name buffer
dwStatus = ClusterResourceEnum(hresenum, ienum, &dwType, pwszName, &cchName);
} // if: name buffer was too small
if (dwStatus == ERROR_NO_MORE_ITEMS)
break;
else if (dwStatus != ERROR_SUCCESS)
ThrowStaticException(dwStatus, IDS_ENUM_PROVIDES_FOR_ERROR, StrName());
ASSERT(dwType == CLUSTER_RESOURCE_ENUM_PROVIDES);
// Find the item in the list of resources on the document and
// add its providers to the list.
pciRes = Pdoc()->LpciResources().PciResFromName(pwszName);
if (pciRes != NULL)
{
// Add this resource to the list.
if (plpci->Find(pciRes) == NULL)
{
plpci->AddHead(pciRes);
} // if: resource not in the list yet
// Add the resources this resource provides for to the list.
if (bFullTree)
pciRes->CollectProvidesFor(plpci, bFullTree);
} // if: resource found in the list
} // for: each dependent resource
// Close the enumeration.
delete [] pwszName;
pwszName = NULL;
ClusterResourceCloseEnum(hresenum);
hresenum = NULL;
} // try
catch (CException *)
{
delete [] pwszName;
if (hresenum != NULL)
ClusterResourceCloseEnum(hresenum);
throw;
} // catch: CException
} // if: resource is available
} //*** CResource::CollectProvidesFor()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::CollectDependencyTree
//
// Routine Description:
// Collect the resources on which this resource is dependent and which
// are dependent on it.
//
// Arguments:
// plpci [IN OUT] List to fill.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// CNTException Errors from ClusterResourceOpenEnum() or
// ClusterResourceEnum().
// Any exceptions thrown by new or CList::AddTail().
//
//--
/////////////////////////////////////////////////////////////////////////////
void CResource::CollectDependencyTree(
IN OUT CResourceList * plpci
) const
{
DWORD dwStatus;
HRESENUM hresenum = NULL;
int ienum;
LPWSTR pwszName = NULL;
DWORD cchName;
DWORD cchmacName;
DWORD dwRetType;
CResource * pciRes;
CWaitCursor wc;
int iType;
static DWORD rgdwType[] = { CLUSTER_RESOURCE_ENUM_DEPENDS, CLUSTER_RESOURCE_ENUM_PROVIDES };
static IDS rgidsTypeError[] = { IDS_ENUM_DEPENDENCIES_ERROR, IDS_ENUM_PROVIDES_FOR_ERROR };
ASSERT_VALID(Pdoc());
ASSERT(Hresource() != NULL);
ASSERT(plpci != NULL);
if (Hresource() != NULL)
{
try
{
// Allocate a name buffer.
cchmacName = 128;
pwszName = new WCHAR[cchmacName];
if ( pwszName == NULL )
{
AfxThrowMemoryException();
} // if: error allocating the name buffer
for (iType = 0 ; iType < sizeof(rgdwType) / sizeof(DWORD) ; iType++)
{
// Open the enumeration.
hresenum = ClusterResourceOpenEnum(Hresource(), rgdwType[iType]);
if (hresenum == NULL)
ThrowStaticException(GetLastError(), rgidsTypeError[iType], StrName());
// Loop through the enumeration and add each dependent or
// provider resource to the list.
for (ienum = 0 ; ; ienum++)
{
// Get the next item in the enumeration.
cchName = cchmacName;
dwStatus = ClusterResourceEnum(hresenum, ienum, &dwRetType, pwszName, &cchName);
if (dwStatus == ERROR_MORE_DATA)
{
delete [] pwszName;
cchmacName = ++cchName;
pwszName = new WCHAR[cchmacName];
if ( pwszName == NULL )
{
AfxThrowMemoryException();
} // if: error allocating the name buffer
dwStatus = ClusterResourceEnum(hresenum, ienum, &dwRetType, pwszName, &cchName);
} // if: name buffer was too small
if (dwStatus == ERROR_NO_MORE_ITEMS)
break;
else if (dwStatus != ERROR_SUCCESS)
ThrowStaticException(dwStatus, rgidsTypeError[iType], StrName());
ASSERT(dwRetType == rgdwType[iType]);
// Find the item in the list of resources on the document and
// add its dependencies and providers to the list.
pciRes = Pdoc()->LpciResources().PciResFromName(pwszName);
if (pciRes != NULL)
{
// Add this resource to the list.
if (plpci->Find(pciRes) == NULL)
{
plpci->AddTail(pciRes);
pciRes->CollectDependencyTree(plpci);
} // if: resource not in the list yet
} // if: resource found in the list
} // for: each item in the group
ClusterResourceCloseEnum(hresenum);
hresenum = NULL;
} // for: each type of enumeration
delete [] pwszName;
} // try
catch (CException *)
{
delete [] pwszName;
if (hresenum != NULL)
ClusterResourceCloseEnum(hresenum);
throw;
} // catch: any exception
} // if: resource is available
} //*** CResource::CollectDependencyTree()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::SetName
//
// Routine Description:
// Set the name of this resource.
//
// Arguments:
// pszName [IN] New name of the resource.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// Any exceptions thrown by Rename.
//--
/////////////////////////////////////////////////////////////////////////////
void CResource::SetName(IN LPCTSTR pszName)
{
Rename(pszName);
} //*** CResource::SetName()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::SetGroup
//
// Routine Description:
// Set the group to which this resource belongs.
//
// Arguments:
// pszGroup [IN] New group for the resource.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// CNTException IDS_MOVE_RESOURCE_ERROR - errors from
// ChangeClusterResourceGroup().
//--
/////////////////////////////////////////////////////////////////////////////
void CResource::SetGroup(IN LPCTSTR pszGroup)
{
DWORD dwStatus;
CGroup * pciGroup;
CString strGroup(pszGroup); // Required if built non-Unicode
CWaitCursor wc;
ASSERT(pszGroup != NULL);
ASSERT(Hresource() != NULL);
if ((Hresource() != NULL) && (StrGroup() != pszGroup))
{
// Find the group.
pciGroup = Pdoc()->LpciGroups().PciGroupFromName(pszGroup);
ASSERT_VALID(pciGroup);
// Change the group.
dwStatus = ChangeClusterResourceGroup(Hresource(), pciGroup->Hgroup());
if (dwStatus != ERROR_SUCCESS)
ThrowStaticException(dwStatus, IDS_MOVE_RESOURCE_ERROR, StrName(), pszGroup);
SetGroupState(pciGroup->StrName());
} // if: the name changed
} //*** CResource::SetGroup()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::SetDependencies
//
// Routine Description:
// Set the list of resources on which this resource depends on
// in the cluster database.
//
// Arguments:
// rlpci [IN] List of resources on which this resource depends on.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// CNTException(dwStatus) Errors from AddClusterResourceDependency()
// and RemoveClusterResourceDependency().
//--
/////////////////////////////////////////////////////////////////////////////
void CResource::SetDependencies(IN const CResourceList & rlpci)
{
DWORD dwStatus;
CWaitCursor wc;
ASSERT(Hresource() != NULL);
if (Hresource() != NULL)
{
// Add any entries that are in the new last but not in the old list as
// new dependencies.
{
POSITION posPci;
CResource * pciRes;
posPci = rlpci.GetHeadPosition();
while (posPci != NULL)
{
pciRes = (CResource *) rlpci.GetNext(posPci);
ASSERT_VALID(pciRes);
if (LpciresDependencies().Find(pciRes) == NULL)
{
// Add the resource as a dependency of this one.
dwStatus = AddClusterResourceDependency(Hresource(), pciRes->Hresource());
if (dwStatus != ERROR_SUCCESS)
ThrowStaticException(dwStatus, IDS_ADD_DEPENDENCY_ERROR, pciRes->StrName(), StrName());
// Add the resource into our list.
m_plpciresDependencies->AddTail(pciRes);
} // if: item not found in existing list
} // while: more items in the list
} // Add new dependencies
// Delete any entries that are in the new old but not in the new list.
{
POSITION posPci;
POSITION posPrev;
CResource * pciRes;
posPci = LpciresDependencies().GetHeadPosition();
while (posPci != NULL)
{
posPrev = posPci;
pciRes = (CResource *) LpciresDependencies().GetNext(posPci);
if (rlpci.Find(pciRes) == NULL)
{
// Remove the resource as a dependency of this one.
dwStatus = RemoveClusterResourceDependency(Hresource(), pciRes->Hresource());
if (dwStatus != ERROR_SUCCESS)
ThrowStaticException(dwStatus, IDS_REMOVE_DEPENDENCY_ERROR, pciRes->StrName(), StrName());
// Remove the resource from our list.
m_plpciresDependencies->RemoveAt(posPrev);
} // if: item not found in new list
} // while: more items in the list
} // Remove old dependencies
} // if: resource is available
} //*** CResource::SetDependencies()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::SetPossibleOwners
//
// Routine Description:
// Set the list of possible owners of this resource in the cluster
// database.
//
// Arguments:
// rlpci [IN] List of possible owners (nodes).
//
// Return Value:
// None.
//
// Exceptions Thrown:
// CNTException IDS_TAKE_RESOURCE_OFFLINE_ERROR.
// CNTException(dwStatus) Errors from AddClusterResourceNode()
// and RemoveClusterResourceNode().
//--
/////////////////////////////////////////////////////////////////////////////
void CResource::SetPossibleOwners(IN const CNodeList & rlpci)
{
DWORD dwStatus;
CWaitCursor wc;
ASSERT(Hresource() != NULL);
if (Hresource() != NULL)
{
// If the list of possible owners is empty, make sure this resource
// is offline.
if ((rlpci.GetCount() == 0) && (Crs() == ClusterResourceOnline))
{
dwStatus = OfflineClusterResource(Hresource());
if ((dwStatus != ERROR_SUCCESS)
&& (dwStatus != ERROR_IO_PENDING))
ThrowStaticException(dwStatus, IDS_TAKE_RESOURCE_OFFLINE_ERROR, StrName());
} // if: no possible owners
// Add any entries that are in the new list but not in the old list as
// new owners.
{
POSITION posPci;
CClusterNode * pciNode;
posPci = rlpci.GetHeadPosition();
while (posPci != NULL)
{
pciNode = (CClusterNode *) rlpci.GetNext(posPci);
ASSERT_VALID(pciNode);
if (LpcinodePossibleOwners().Find(pciNode) == NULL)
{
// Add the node as an owner of this resource.
dwStatus = AddClusterResourceNode(Hresource(), pciNode->Hnode());
if (dwStatus != ERROR_SUCCESS)
ThrowStaticException(dwStatus, IDS_ADD_RES_OWNER_ERROR, pciNode->StrName(), StrName());
// Add the node into our list.
m_plpcinodePossibleOwners->AddTail(pciNode);
} // if: item not found in existing list
} // while: more items in the list
} // Add new owner
// Delete any entries that are in the old but not in the new list.
{
POSITION posPci;
POSITION posPrev;
CClusterNode * pciNode;
posPci = LpcinodePossibleOwners().GetHeadPosition();
while (posPci != NULL)
{
posPrev = posPci;
pciNode = (CClusterNode *) LpcinodePossibleOwners().GetNext(posPci);
if (rlpci.Find(pciNode) == NULL)
{
// Remove the node as an owner of this resource.
dwStatus = RemoveClusterResourceNode(Hresource(), pciNode->Hnode());
if (dwStatus != ERROR_SUCCESS)
ThrowStaticException(dwStatus, IDS_REMOVE_RES_OWNER_ERROR, pciNode->StrName(), StrName());
// Remove the node from our list.
m_plpcinodePossibleOwners->RemoveAt(posPrev);
} // if: item not found in new list
} // while: more items in the list
} // Remove old owners
} // if: resource is available
} //*** CResource::SetPossibleOwners()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::SetCommonProperties
//
// Routine Description:
// Set the common properties for this resource in the cluster database.
//
// Arguments:
// rstrDesc [IN] Description string.
// bSeparate [IN] TRUE = run resource in separate monitor, FALSE = run with other resources.
// nLooksAlive [IN] Looks Alive poll interval.
// nIsAlive [IN] Is Alive poll interval.
// crra [IN] Restart action.
// nThreshold [IN] Restart threshold.
// nPeriod [IN] Restart period.
// nTimeout [IN] Pending timeout in minutes.
// bValidateOnly [IN] Only validate the data.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// Any exceptions thrown by CClusterItem::SetCommonProperties().
//
//--
/////////////////////////////////////////////////////////////////////////////
void CResource::SetCommonProperties(
IN const CString & rstrDesc,
IN BOOL bSeparate,
IN DWORD nLooksAlive,
IN DWORD nIsAlive,
IN CRRA crra,
IN DWORD nThreshold,
IN DWORD nPeriod,
IN DWORD nTimeout,
IN BOOL bValidateOnly
)
{
CNTException nte(ERROR_SUCCESS, 0, NULL, NULL, FALSE /*bAutoDelete*/);
m_rgProps[epropDescription].m_value.pstr = (CString *) &rstrDesc;
m_rgProps[epropSeparateMonitor].m_value.pb = &bSeparate;
m_rgProps[epropLooksAlive].m_value.pdw = &nLooksAlive;
m_rgProps[epropIsAlive].m_value.pdw = &nIsAlive;
m_rgProps[epropRestartAction].m_value.pdw = (DWORD *) &crra;
m_rgProps[epropRestartThreshold].m_value.pdw = &nThreshold;
m_rgProps[epropRestartPeriod].m_value.pdw = &nPeriod;
m_rgProps[epropPendingTimeout].m_value.pdw = &nTimeout;
try
{
CClusterItem::SetCommonProperties(bValidateOnly);
} // try
catch (CNTException * pnte)
{
nte.SetOperation(
pnte->Sc(),
pnte->IdsOperation(),
pnte->PszOperArg1(),
pnte->PszOperArg2()
);
} // catch: CNTException
m_rgProps[epropDescription].m_value.pstr = &m_strDescription;
m_rgProps[epropSeparateMonitor].m_value.pb = &m_bSeparateMonitor;
m_rgProps[epropLooksAlive].m_value.pdw = &m_nLooksAlive;
m_rgProps[epropIsAlive].m_value.pdw = &m_nIsAlive;
m_rgProps[epropRestartAction].m_value.pdw = (DWORD *) &m_crraRestartAction;
m_rgProps[epropRestartThreshold].m_value.pdw = &m_nRestartThreshold;
m_rgProps[epropRestartPeriod].m_value.pdw = &m_nRestartPeriod;
m_rgProps[epropPendingTimeout].m_value.pdw = &m_nPendingTimeout;
if (nte.Sc() != ERROR_SUCCESS)
ThrowStaticException(
nte.Sc(),
nte.IdsOperation(),
nte.PszOperArg1(),
nte.PszOperArg2()
);
} //*** CResource::SetCommonProperties()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::DwSetCommonProperties
//
// Routine Description:
// Set the common properties for this resource in the cluster database.
//
// Arguments:
// rcpl [IN] Property list to set.
// bValidateOnly [IN] Only validate the data.
//
// Return Value:
// Any status returned by ClusterResourceControl().
//
//--
/////////////////////////////////////////////////////////////////////////////
DWORD CResource::DwSetCommonProperties(
IN const CClusPropList & rcpl,
IN BOOL bValidateOnly
)
{
DWORD dwStatus;
CWaitCursor wc;
ASSERT(Hresource());
if ((rcpl.PbPropList() != NULL) && (rcpl.CbPropList() > 0))
{
DWORD cbProps;
DWORD dwControl;
if (bValidateOnly)
dwControl = CLUSCTL_RESOURCE_VALIDATE_COMMON_PROPERTIES;
else
dwControl = CLUSCTL_RESOURCE_SET_COMMON_PROPERTIES;
// Set common properties.
dwStatus = ClusterResourceControl(
Hresource(),
NULL, // hNode
dwControl,
rcpl.PbPropList(),
rcpl.CbPropList(),
NULL, // lpOutBuffer
0, // nOutBufferSize
&cbProps
);
} // if: there is data to set
else
dwStatus = ERROR_SUCCESS;
return dwStatus;
} //*** CResource::DwSetCommonProperties()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::BRequiredDependenciesPresent
//
// Routine Description:
// Determine if the specified list contains each required resource
// for this type of resource.
//
// Arguments:
// rlpciRes [IN] List of resources.
// rstrMissing [OUT] String in which to return a missing resource
// class name or type name.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// Any exceptions thrown by CString::LoadString() or CString::operator=().
//
//--
/////////////////////////////////////////////////////////////////////////////
BOOL CResource::BRequiredDependenciesPresent(
IN const CResourceList & rlpciRes,
OUT CString & rstrMissing
)
{
POSITION pos;
BOOL bFound = TRUE;
const CResource * pciRes;
CLUSPROP_BUFFER_HELPER props;
if (Pcrd() == NULL)
return TRUE;
// Collect the list of required dependencies.
props.pRequiredDependencyValue = Pcrd();
// Loop through each required dependency and make sure
// there is a dependency on a resource of that type.
while (props.pSyntax->dw != CLUSPROP_SYNTAX_ENDMARK)
{
bFound = FALSE;
pos = rlpciRes.GetHeadPosition();
while (pos != NULL)
{
// Get the next resource.
pciRes = (CResource *) rlpciRes.GetNext(pos);
ASSERT_VALID(pciRes);
ASSERT_KINDOF(CResource, pciRes);
// If this is the right type, we've satisfied the
// requirement so exit the loop.
if (props.pSyntax->dw == CLUSPROP_SYNTAX_RESCLASS)
{
if (props.pResourceClassValue->rc == pciRes->ResClass())
{
bFound = TRUE;
props.pb += sizeof(*props.pResourceClassValue);
} // if: match found
} // if: resource class
else if (props.pSyntax->dw == CLUSPROP_SYNTAX_NAME)
{
if (pciRes->StrRealResourceType().CompareNoCase(props.pStringValue->sz) == 0)
{
bFound = TRUE;
props.pb += sizeof(*props.pStringValue) + ALIGN_CLUSPROP(props.pStringValue->cbLength);
} // if: match found
} // else if: resource name
else
{
ASSERT(0);
break;
} // else: unknown data type
if (bFound)
break;
} // while: more items in the list
// If a match was not found, changes cannot be applied.
if (!bFound)
{
if (props.pSyntax->dw == CLUSPROP_SYNTAX_RESCLASS)
{
if (!rstrMissing.LoadString(IDS_RESCLASS_UNKNOWN + props.pResourceClassValue->rc))
rstrMissing.LoadString(IDS_RESCLASS_UNKNOWN);
} // if: resource class not found
else if (props.pSyntax->dw == CLUSPROP_SYNTAX_NAME)
{
CResourceType * pciResType;
// Find the resource type in our list.
pciResType = (CResourceType *) Pdoc()->LpciResourceTypes().PciFromName(props.pStringValue->sz);
if (pciResType != NULL)
rstrMissing = pciResType->StrDisplayName();
else
rstrMissing = props.pStringValue->sz;
} // else if: resource type name not found
break;
} // if: not found
} // while: more dependencies required
return bFound;
} //*** CResource::BRequiredDependenciesPresent()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::DeleteResource
//
// Routine Description:
// Delete this resource and all dependent resources.
//
// Arguments:
// rlpci [IN] List of resources to delete in addition to this one.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// Any exceptions thrown by CResource::DeleteResource().
//
//--
/////////////////////////////////////////////////////////////////////////////
void CResource::DeleteResource(IN const CResourceList & rlpci)
{
CWaitCursor wc;
// Delete each resource in the list.
{
POSITION pos;
CResource * pciRes;
pos = rlpci.GetHeadPosition();
while (pos != NULL)
{
pciRes = (CResource *) rlpci.GetNext(pos);
if (pciRes != NULL)
pciRes->DeleteResource();
} // while: more items in the list
} // Delete each resource in the list
// Delete this resource.
DeleteResource();
} //*** CResource::DeleteResource(rlpci)
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::DeleteResource
//
// Routine Description:
// Delete this resource.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// CNTException Errors from DeleteClusterResource().
//
//--
/////////////////////////////////////////////////////////////////////////////
void CResource::DeleteResource(void)
{
DWORD dwStatus;
BOOL bWeTookOffline = FALSE;
CWaitCursor wc;
ASSERT(!BDeleting());
if (Hresource() != NULL)
{
// Make sure the resource is offline.
if ( (Crs() != ClusterResourceOffline)
&& (Crs() != ClusterResourceFailed))
{
dwStatus = OfflineClusterResource(Hresource());
if (dwStatus == ERROR_IO_PENDING)
{
WaitForOffline();
if ( (Crs() != ClusterResourceOffline)
&& (Crs() != ClusterResourceFailed))
{
ThrowStaticException(IDS_DELETE_RESOURCE_ERROR_OFFLINE_PENDING, StrName());
} // if: resource still not offline
} // if: offline pending
else if ( (dwStatus != ERROR_SUCCESS)
&& (dwStatus != ERROR_FILE_NOT_FOUND)
&& (dwStatus != ERROR_RESOURCE_NOT_AVAILABLE))
{
ThrowStaticException(dwStatus, IDS_TAKE_RESOURCE_OFFLINE_ERROR, StrName());
}
bWeTookOffline = TRUE;
} // if: resource is not offline
// Delete the resource itself.
Trace(g_tagResource, _T("(%s) DeleteResource() - Deleting '%s' (%x)"), Pdoc()->StrNode(), StrName(), this);
dwStatus = DeleteClusterResource(Hresource());
if ( (dwStatus != ERROR_SUCCESS)
&& (dwStatus != ERROR_FILE_NOT_FOUND)
&& (dwStatus != ERROR_RESOURCE_NOT_AVAILABLE))
{
if (bWeTookOffline)
{
OnlineClusterResource(Hresource());
}
ThrowStaticException(dwStatus, IDS_DELETE_RESOURCE_ERROR, StrName());
} // if: error occurred
m_bDeleting = TRUE;
UpdateState();
} // if: resource has been opened/created
} //*** CResource::DeleteResource()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::WaitForOffline
//
// Routine Description:
// Wait for the resource to go offline.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// Any exceptions thrown by CResource::Move().
//
//--
/////////////////////////////////////////////////////////////////////////////
void CResource::WaitForOffline( void )
{
CWaitForResourceOfflineDlg dlg( this, AfxGetMainWnd() );
dlg.DoModal();
UpdateState();
} //*** CResource::WaitForOffline()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::Move
//
// Routine Description:
// Move this resource and all dependent and depending resources to
// another group.
//
// Arguments:
// pciGroup [IN] Group to move resources to.
// rlpci [IN] List of resources to move in addition to this one.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// Any exceptions thrown by CResource::Move().
//
//--
/////////////////////////////////////////////////////////////////////////////
void CResource::Move(
IN const CGroup * pciGroup,
IN const CResourceList & rlpci
)
{
CWaitCursor wc;
// Move each resource in the list.
{
POSITION pos;
CResource * pciRes;
pos = rlpci.GetHeadPosition();
while (pos != NULL)
{
pciRes = (CResource *) rlpci.GetNext(pos);
if (pciRes != NULL)
pciRes->Move(pciGroup);
} // while: more items in the list
} // Move each resource in the list
// Move this resource.
Move(pciGroup);
} //*** CResource::Move(rlpci)
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::Move
//
// Routine Description:
// Move this resource.
//
// Arguments:
// pciGroup [IN] Group to move resources to.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// CNTException Errors from ChangeClusterResourceGroup().
//
//--
/////////////////////////////////////////////////////////////////////////////
void CResource::Move(IN const CGroup * pciGroup)
{
DWORD dwStatus;
ASSERT_VALID(pciGroup);
if ((Hresource() != NULL)
&& (pciGroup != NULL)
&& (pciGroup->Hgroup() != NULL))
{
// Move the resource.
Trace(g_tagResource, _T("(%s) Move() - moving '%s' (%x) from '%s' (%x) to '%s' (%x)"), Pdoc()->StrNode(), StrName(), this, StrGroup(), PciGroup(), pciGroup->StrName(), pciGroup);
dwStatus = ChangeClusterResourceGroup(Hresource(), pciGroup->Hgroup());
if ((dwStatus != ERROR_SUCCESS)
&& (dwStatus != ERROR_FILE_NOT_FOUND))
ThrowStaticException(dwStatus, IDS_MOVE_RESOURCE_ERROR, StrName(), pciGroup->StrName());
UpdateState();
} // if: resource has been opened/created
} //*** CResource::Move()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::OnFinalRelease
//
// Routine Description:
// Called when the last OLE reference to or from the object is released.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CResource::OnFinalRelease(void)
{
// When the last reference for an automation object is released
// OnFinalRelease is called. The base class will automatically
// deletes the object. Add additional cleanup required for your
// object before calling the base class.
CClusterItem::OnFinalRelease();
} //*** CResource::OnFinalRelease()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::BCanBeDependent
//
// Routine Description:
// Determine whether this resource can be dependent on the specified one.
//
// Arguments:
// pciRes [IN] Resource to check.
//
// Return Value:
// TRUE Resource can be a dependent.
// FALSE Resource can NOT be a dependent.
//
//--
/////////////////////////////////////////////////////////////////////////////
BOOL CResource::BCanBeDependent(IN CResource * pciRes)
{
CWaitCursor wc;
ASSERT_VALID(pciRes);
if ((Hresource() != NULL)
&& (pciRes->Hresource() != NULL)
&& (pciRes != this)
&& (StrGroup() == pciRes->StrGroup())
)
return ::CanResourceBeDependent(Hresource(), pciRes->Hresource());
else
return FALSE;
} //*** CResource::BCanBeDependent()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::BIsDependent
//
// Routine Description:
// Determine whether this resource is dependent on the specified one.
//
// Arguments:
// pciRes [IN] Resource to check.
//
// Return Value:
// TRUE Resource is a dependent.
// FALSE Resource is NOT a dependent.
//
//--
/////////////////////////////////////////////////////////////////////////////
BOOL CResource::BIsDependent(IN CResource * pciRes)
{
ASSERT_VALID(pciRes);
if ((m_plpciresDependencies != NULL)
&& (LpciresDependencies().Find(pciRes) != NULL))
return TRUE;
else
return FALSE;
} //*** CResource::BIsDependent()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::BGetNetworkName
//
// Routine Description:
// Returns the name of the network name of the first Network Name
// resource on which the specified resource depends.
//
// Arguments:
// lpszNetName [OUT] String in which to return the network name.
// pcchNetName [IN OUT] Points to a variable that specifies the
// maximum size, in characters, of the buffer. This
// value should be large enough to contain
// MAX_COMPUTERNAME_LENGTH + 1 characters. Upon
// return it contains the actual number of characters
// copied.
//
// Return Value:
// TRUE Resource is dependent on a network name resource.
// FALSE Resource is NOT dependent on a network name resource.
//
//--
/////////////////////////////////////////////////////////////////////////////
BOOL CResource::BGetNetworkName(
OUT WCHAR * lpszNetName,
IN OUT DWORD * pcchNetName
)
{
CWaitCursor wc;
ASSERT_VALID(this);
ASSERT(m_hresource != NULL);
ASSERT(lpszNetName != NULL);
ASSERT(pcchNetName != NULL);
return GetClusterResourceNetworkName(m_hresource, lpszNetName, pcchNetName);
} //*** CResource::BGetNetworkName()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::BGetNetworkName
//
// Routine Description:
// Returns the name of the network name of the first Network Name
// resource on which the specified resource depends.
//
// Arguments:
// rstrNetName [OUT] String in which to return the network name.
//
// Return Value:
// TRUE Resource is dependent on a network name resource.
// FALSE Resource is NOT dependent on a network name resource.
//
//--
/////////////////////////////////////////////////////////////////////////////
BOOL CResource::BGetNetworkName(OUT CString & rstrNetName)
{
BOOL bSuccess;
WCHAR szNetName[MAX_COMPUTERNAME_LENGTH + 1];
DWORD nSize = sizeof(szNetName) / sizeof(WCHAR);
bSuccess = BGetNetworkName(szNetName, &nSize);
if (bSuccess)
rstrNetName = szNetName;
else
rstrNetName = _T("");
return bSuccess;
} //*** CResource::BGetNetworkName()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::UpdateState
//
// Routine Description:
// Update the current state of the item.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CResource::UpdateState(void)
{
CClusterAdminApp * papp = GetClusterAdminApp();
WCHAR * pwszOwner = NULL;
WCHAR * pwszGroup = NULL;
WCHAR * prgwszOwner = NULL;
WCHAR * prgwszGroup = NULL;
DWORD cchOwner;
DWORD cchGroup;
DWORD sc;
DWORD oldcchOwner;
DWORD oldcchGroup;
Trace(g_tagResource, _T("(%s) (%s (%x)) - Updating state"), Pdoc()->StrNode(), StrName(), this);
// Get the current state of the resource.
if (Hresource() == NULL)
m_crs = ClusterResourceStateUnknown;
else
{
CWaitCursor wc;
cchOwner = 100;
oldcchOwner = cchOwner;
prgwszOwner = new WCHAR[cchOwner];
if( prgwszOwner == NULL )
{
AfxThrowMemoryException();
} // if: error allocating the buffer
cchGroup = 100;
oldcchGroup = cchGroup;
prgwszGroup = new WCHAR[cchGroup];
if( prgwszGroup == NULL )
{
AfxThrowMemoryException();
} // if: error allocating the buffer
m_crs = GetClusterResourceState(Hresource(), prgwszOwner, &cchOwner, prgwszGroup, &cchGroup);
sc = GetLastError();
if( sc == ERROR_MORE_DATA )
{
//
// Increment before the check. This way we'll know whether we'll need to resize the buffer,
// and if not then we report it as being just big enough.
//
cchOwner++;
if( cchOwner > oldcchOwner )
{
delete [] prgwszOwner;
oldcchOwner = cchOwner;
prgwszOwner = new WCHAR[cchOwner];
if( prgwszOwner == NULL )
{
AfxThrowMemoryException();
} // if: error allocating the buffer
}
cchGroup++;
if( cchGroup > oldcchGroup )
{
delete [] prgwszGroup;
oldcchGroup = cchGroup;
prgwszGroup = new WCHAR[cchGroup];
if( prgwszGroup == NULL )
{
AfxThrowMemoryException();
} // if: error allocating the buffer
}
//
// Note that it's possible that the owning group or node changed since the last call to
// GetClusterResourceState. In that case our buffers may still be too small. Hit F5 to refresh.
//
m_crs = GetClusterResourceState(Hresource(), prgwszOwner, &cchOwner, prgwszGroup, &cchGroup);
}
pwszOwner = prgwszOwner;
pwszGroup = prgwszGroup;
} // else: resource is available
// Save the current state image index.
switch (Crs())
{
case ClusterResourceStateUnknown:
m_iimgState = papp->Iimg(IMGLI_RES_UNKNOWN);
pwszOwner = NULL;
pwszGroup = NULL;
break;
case ClusterResourceOnline:
m_iimgState = papp->Iimg(IMGLI_RES);
break;
case ClusterResourceOnlinePending:
m_iimgState = papp->Iimg(IMGLI_RES_PENDING);
break;
case ClusterResourceOffline:
m_iimgState = papp->Iimg(IMGLI_RES_OFFLINE);
break;
case ClusterResourceOfflinePending:
m_iimgState = papp->Iimg(IMGLI_RES_PENDING);
break;
case ClusterResourceFailed:
m_iimgState = papp->Iimg(IMGLI_RES_FAILED);
break;
default:
Trace(g_tagResource, _T("(%s) (%s (%x)) - UpdateState: Unknown state '%d' for resource '%s'"), Pdoc()->StrNode(), StrName(), this, Crs(), StrName());
m_iimgState = (UINT) -1;
break;
} // switch: Crs()
SetOwnerState(pwszOwner);
SetGroupState(pwszGroup);
if( NULL != prgwszOwner )
{
delete [] prgwszOwner;
}
if( NULL != prgwszGroup )
{
delete [] prgwszGroup;
}
// Call the base class method.
CClusterItem::UpdateState();
} //*** CResource::UpdateState()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::SetOwnerState
//
// Routine Description:
// Set a new owner for this resource.
//
// Arguments:
// pszNewOwner [IN] Name of the new owner.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CResource::SetOwnerState(IN LPCTSTR pszNewOwner)
{
CClusterNode * pciOldOwner = PciOwner();
CClusterNode * pciNewOwner;
Trace(g_tagResource, _T("(%s) (%s (%x)) - Setting owner to '%s'"), Pdoc()->StrNode(), StrName(), this, pszNewOwner);
if (pszNewOwner == NULL)
pciNewOwner = NULL;
else
pciNewOwner = Pdoc()->LpciNodes().PciNodeFromName(pszNewOwner);
if (pciNewOwner != pciOldOwner)
{
#ifdef _DEBUG
if (g_tagResource.BAny())
{
CString strMsg;
CString strMsg2;
strMsg.Format(_T("(%s) (%s (%x)) - Changing owner from "), Pdoc()->StrNode(), StrName(), this);
if (pciOldOwner == NULL)
strMsg += _T("nothing ");
else
{
strMsg2.Format(_T("'%s' "), pciOldOwner->StrName());
strMsg += strMsg2;
} // else: previous owner
if (pciNewOwner == NULL)
strMsg += _T("to nothing");
else
{
strMsg2.Format(_T("to '%s'"), pciNewOwner->StrName());
strMsg += strMsg2;
} // else: new owner
Trace(g_tagResource, strMsg);
} // if: trace tag turned on
#endif
m_strOwner = pszNewOwner;
m_pciOwner = pciNewOwner;
// Update reference counts.
if (pciOldOwner != NULL)
pciOldOwner->Release();
if (pciNewOwner != NULL)
pciNewOwner->AddRef();
if (BDocObj())
{
if (pciOldOwner != NULL)
pciOldOwner->RemoveActiveResource(this);
if (pciNewOwner != NULL)
pciNewOwner->AddActiveResource(this);
} // if: this is a document object
} // if: owner changed
else if ((pszNewOwner != NULL) && (StrOwner() != pszNewOwner))
m_strOwner = pszNewOwner;
} //*** CResource::SetOwnerState()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::SetGroupState
//
// Routine Description:
// Set a new group for this resource.
//
// Arguments:
// pszNewGroup [IN] Name of the new group.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CResource::SetGroupState(IN LPCTSTR pszNewGroup)
{
CGroup * pciOldGroup = PciGroup();
CGroup * pciNewGroup;
Trace(g_tagResource, _T("(%s) (%s (%x)) - Setting group to '%s'"), Pdoc()->StrNode(), StrName(), this, (pszNewGroup == NULL ? _T("") : pszNewGroup));
if (pszNewGroup == NULL)
pciNewGroup = NULL;
else
pciNewGroup = Pdoc()->LpciGroups().PciGroupFromName(pszNewGroup);
if (pciNewGroup != pciOldGroup)
{
#ifdef _DEBUG
if (g_tagResource.BAny())
{
CString strMsg;
CString strMsg2;
strMsg.Format(_T("(%s) (%s (%x)) - Changing group from "), Pdoc()->StrNode(), StrName(), this);
if (pciOldGroup == NULL)
strMsg += _T("nothing ");
else
{
strMsg2.Format(_T("'%s' "), pciOldGroup->StrName());
strMsg += strMsg2;
} // else: previous group
if (pciNewGroup == NULL)
strMsg += _T("to nothing");
else
{
strMsg2.Format(_T("to '%s'"), pciNewGroup->StrName());
strMsg += strMsg2;
} // else: new group
Trace(g_tagResource, strMsg);
} // if: trace tag turned on
#endif
m_strGroup = pszNewGroup;
m_pciGroup = pciNewGroup;
// Update reference counts.
if (pciOldGroup != NULL)
pciOldGroup->Release();
if (pciNewGroup != NULL)
pciNewGroup->AddRef();
if (BDocObj())
{
if (pciOldGroup != NULL)
pciOldGroup->RemoveResource(this);
if (pciNewGroup != NULL)
pciNewGroup->AddResource(this);
} // if: this is a document object
} // if: owner changed
else if ((pszNewGroup != NULL) && (StrGroup() != pszNewGroup))
m_strGroup = pszNewGroup;
} //*** CResource::SetGroupState()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::BGetColumnData
//
// Routine Description:
// Returns a string with the column data.
//
// Arguments:
// colid [IN] Column ID.
// rstrText [OUT] String in which to return the text for the column.
//
// Return Value:
// TRUE Column data returned.
// FALSE Column ID not recognized.
//
//--
/////////////////////////////////////////////////////////////////////////////
BOOL CResource::BGetColumnData(IN COLID colid, OUT CString & rstrText)
{
BOOL bSuccess;
switch (colid)
{
case IDS_COLTEXT_STATE:
GetStateName(rstrText);
bSuccess = TRUE;
break;
case IDS_COLTEXT_RESTYPE:
rstrText = StrRealResourceTypeDisplayName();
bSuccess = TRUE;
break;
case IDS_COLTEXT_OWNER:
rstrText = StrOwner();
bSuccess = TRUE;
break;
case IDS_COLTEXT_GROUP:
if (PciGroup() == NULL)
rstrText = StrGroup();
else
rstrText = PciGroup()->StrName();
bSuccess = TRUE;
break;
case IDS_COLTEXT_RESOURCE: // This is for showing dependencies
colid = IDS_COLTEXT_NAME;
// FALL THROUGH
default:
bSuccess = CClusterItem::BGetColumnData(colid, rstrText);
break;
} // switch: colid
return bSuccess;
} //*** CResource::BGetColumnData()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::GetTreeName
//
// Routine Description:
// Returns a string to be used in a tree control.
//
// Arguments:
// rstrName [OUT] String in which to return the name.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
#ifdef _DISPLAY_STATE_TEXT_IN_TREE
void CResource::GetTreeName(OUT CString & rstrName) const
{
CString strState;
GetStateName(strState);
rstrName.Format(_T("%s (%s)"), StrName(), strState);
} //*** CResource::GetTreeName()
#endif
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::GetStateName
//
// Routine Description:
// Returns a string with the name of the current state.
//
// Arguments:
// rstrState [OUT] String in which to return the name of the current state.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CResource::GetStateName(OUT CString & rstrState) const
{
switch (Crs())
{
case ClusterResourceStateUnknown:
rstrState.LoadString(IDS_UNKNOWN);
break;
case ClusterResourceOnline:
rstrState.LoadString(IDS_ONLINE);
break;
case ClusterResourceOnlinePending:
rstrState.LoadString(IDS_ONLINE_PENDING);
break;
case ClusterResourceOffline:
rstrState.LoadString(IDS_OFFLINE);
break;
case ClusterResourceOfflinePending:
rstrState.LoadString(IDS_OFFLINE_PENDING);
break;
case ClusterResourceFailed:
rstrState.LoadString(IDS_FAILED);
break;
default:
rstrState.Empty();
break;
} // switch: Crs()
} //*** CResource::GetStateName()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::BCanBeEdited
//
// Routine Description:
// Determines if the resource can be renamed.
//
// Arguments:
// None.
//
// Return Value:
// TRUE Resource can be renamed.
// FALSE Resource cannot be renamed.
//
//--
/////////////////////////////////////////////////////////////////////////////
BOOL CResource::BCanBeEdited(void) const
{
BOOL bCanBeEdited;
if ( (Crs() == ClusterResourceStateUnknown)
|| BReadOnly())
bCanBeEdited = FALSE;
else
bCanBeEdited = TRUE;
return bCanBeEdited;
} //*** CResource::BCanBeEdited()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::Rename
//
// Routine Description:
// Rename the resource.
//
// Arguments:
// pszName [IN] New name to give to the resource.
//
// Return Value:
// None.
//
// Exceptions Thrown:
// CNTException Errors returned from SetClusterResourceName().
//
//--
/////////////////////////////////////////////////////////////////////////////
void CResource::Rename(IN LPCTSTR pszName)
{
DWORD dwStatus;
CWaitCursor wc;
ASSERT(Hresource() != NULL);
if (StrName() != pszName)
{
dwStatus = SetClusterResourceName(Hresource(), pszName);
if (dwStatus != ERROR_SUCCESS)
ThrowStaticException(dwStatus, IDS_RENAME_RESOURCE_ERROR, StrName(), pszName);
m_strName = pszName;
} // if: the name changed
} //*** CResource::Rename()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::OnCmdMsg
//
// Routine Description:
// Processes command messages.
//
// Arguments:
// nID [IN] Command ID.
// nCode [IN] Notification code.
// pExtra [IN OUT] Used according to the value of nCode.
// pHandlerInfo [OUT] ???
//
// Return Value:
// TRUE Message has been handled.
// FALSE Message has NOT been handled.
//
//--
/////////////////////////////////////////////////////////////////////////////
BOOL CResource::OnCmdMsg(
UINT nID,
int nCode,
void * pExtra,
AFX_CMDHANDLERINFO * pHandlerInfo
)
{
BOOL bHandled = FALSE;
// If this is a MOVE_RESOURCE command, process it here.
if ((ID_FILE_MOVE_RESOURCE_1 <= nID) && (nID <= ID_FILE_MOVE_RESOURCE_20))
{
Trace(g_tagResource, _T("(%s) OnCmdMsg() %s (%x) - ID = %d, code = %d"), Pdoc()->StrNode(), StrName(), this, nID, nCode);
if (nCode == 0)
{
OnCmdMoveResource(nID);
bHandled = TRUE;
} // if: code = 0
} // if: move resource
if (!bHandled)
bHandled = CClusterItem::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
return bHandled;
} //*** CResource::OnCmdMsg()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::OnUpdateBringOnline
//
// Routine Description:
// Determines whether menu items corresponding to ID_FILE_BRING_ONLINE
// should be enabled or not.
//
// Arguments:
// pCmdUI [IN OUT] Command routing object.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CResource::OnUpdateBringOnline(CCmdUI * pCmdUI)
{
if ((Crs() != ClusterResourceOnline)
&& (Crs() != ClusterResourceOnlinePending)
&& (Crs() != ClusterResourceStateUnknown))
pCmdUI->Enable(TRUE);
else
pCmdUI->Enable(FALSE);
} //*** CResource::OnUpdateBringOnline()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::OnUpdateTakeOffline
//
// Routine Description:
// Determines whether menu items corresponding to ID_FILE_TAKE_OFFLINE
// should be enabled or not.
//
// Arguments:
// pCmdUI [IN OUT] Command routing object.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CResource::OnUpdateTakeOffline(CCmdUI * pCmdUI)
{
if (Crs() == ClusterResourceOnline)
pCmdUI->Enable(TRUE);
else
pCmdUI->Enable(FALSE);
} //*** CResource::OnUpdateTakeOffline()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::OnUpdateInitiateFailure
//
// Routine Description:
// Determines whether menu items corresponding to ID_FILE_INITIATE_FAILURE
// should be enabled or not.
//
// Arguments:
// pCmdUI [IN OUT] Command routing object.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CResource::OnUpdateInitiateFailure(CCmdUI * pCmdUI)
{
if (Crs() == ClusterResourceOnline)
pCmdUI->Enable(TRUE);
else
pCmdUI->Enable(FALSE);
} //*** CResource::OnUpdateInitiateFailure()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::OnUpdateMoveResource1
//
// Routine Description:
// Determines whether menu items corresponding to
// ID_FILE_MOVE_RESOURCE_1 should be enabled or not.
//
// Arguments:
// pCmdUI [IN OUT] Command routing object.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CResource::OnUpdateMoveResource1(CCmdUI * pCmdUI)
{
if (pCmdUI->m_pSubMenu == NULL)
{
CString strMenuName;
if ((pCmdUI->m_pMenu != NULL) && (pCmdUI->m_pSubMenu == NULL))
pCmdUI->m_pMenu->GetMenuString(pCmdUI->m_nID, strMenuName, MF_BYCOMMAND);
if ((strMenuName != StrGroup())
&& ((Crs() == ClusterResourceOnline)
|| (Crs() == ClusterResourceOffline)))
pCmdUI->Enable(TRUE);
else
pCmdUI->Enable(FALSE);
} // if: nested menu is being displayed
else
{
BOOL bEnabled;
if (Pdoc()->LpciGroups().GetCount() < 2)
bEnabled = FALSE;
else
{
POSITION pos;
UINT imenu;
UINT idMenu;
UINT cmenu;
CGroup * pciGroup;
CMenu * pmenu = pCmdUI->m_pSubMenu;
bEnabled = TRUE;
// Delete the items in the menu.
cmenu = pmenu->GetMenuItemCount();
while (cmenu-- > 0)
pmenu->DeleteMenu(0, MF_BYPOSITION);
// Add each group to the menu.
pos = Pdoc()->LpciGroups().GetHeadPosition();
for (imenu = 0, idMenu = ID_FILE_MOVE_RESOURCE_1
; pos != NULL
; idMenu++)
{
pciGroup = (CGroup *) Pdoc()->LpciGroups().GetNext(pos);
ASSERT_VALID(pciGroup);
pmenu->InsertMenu(
imenu++,
MF_BYPOSITION,
idMenu,
pciGroup->StrName()
);
} // for: each group
} // else: move user is available
// Enable or disable the Move menu.
pCmdUI->m_pMenu->EnableMenuItem(
pCmdUI->m_nIndex,
MF_BYPOSITION
| (bEnabled ? MF_ENABLED : MF_GRAYED)
);
} // else: top-level menu is being displayed
} //*** CResource::OnUpdateMoveResource1()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::OnUpdateMoveResourceRest
//
// Routine Description:
// Determines whether menu items corresponding to
// ID_FILE_MOVE_RESOURCE_2 through ID_FILE_MOVE_RESOURCE_20
// should be enabled or not.
//
// Arguments:
// pCmdUI [IN OUT] Command routing object.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CResource::OnUpdateMoveResourceRest(CCmdUI * pCmdUI)
{
CString strMenuName;
if ((pCmdUI->m_pMenu != NULL) && (pCmdUI->m_pSubMenu == NULL))
pCmdUI->m_pMenu->GetMenuString(pCmdUI->m_nID, strMenuName, MF_BYCOMMAND);
if ((strMenuName != StrGroup())
&& ((Crs() == ClusterResourceOnline)
|| (Crs() == ClusterResourceOffline)))
pCmdUI->Enable(TRUE);
else
pCmdUI->Enable(FALSE);
} //*** CResource::OnUpdateMoveResourceRest()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::OnUpdateDelete
//
// Routine Description:
// Determines whether menu items corresponding to ID_FILE_DELETE
// should be enabled or not.
//
// Arguments:
// pCmdUI [IN OUT] Command routing object.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CResource::OnUpdateDelete(CCmdUI * pCmdUI)
{
if (Crs() != ClusterResourceStateUnknown)
pCmdUI->Enable(TRUE);
else
pCmdUI->Enable(FALSE);
} //*** CResource::OnUpdateDelete()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::OnCmdBringOnline
//
// Routine Description:
// Processes the ID_FILE_BRING_ONLINE menu command.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CResource::OnCmdBringOnline(void)
{
DWORD dwStatus;
CWaitCursor wc;
ASSERT(Hresource() != NULL);
// Do this in case this object is deleted while we are operating on it.
AddRef();
// If there are no possible owners for this resource, display a message.
if (LpcinodePossibleOwners().GetCount() == 0)
AfxMessageBox(IDS_NO_POSSIBLE_OWNERS, MB_OK | MB_ICONINFORMATION);
else
{
dwStatus = OnlineClusterResource(Hresource());
if ((dwStatus != ERROR_SUCCESS)
&& (dwStatus != ERROR_IO_PENDING))
{
CNTException nte(dwStatus, IDS_BRING_RESOURCE_ONLINE_ERROR, StrName(), NULL, FALSE /*bAutoDelete*/);
nte.ReportError();
} // if: error bringing the resource online
UpdateState();
} // else: resource has at least one possible owner
Release();
} //*** CResource::OnCmdBringOnline()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::OnCmdTakeOffline
//
// Routine Description:
// Processes the ID_FILE_TAKE_OFFLINE menu command.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CResource::OnCmdTakeOffline(void)
{
DWORD dwStatus;
CWaitCursor wc;
ASSERT(Hresource() != NULL);
// Do this in case this object is deleted while we are operating on it.
AddRef();
do // do-while to prevent goto's
{
// If this connection was made through the cluster name and this is
// either the cluster name resource or one of the resources on which
// it is dependent, warn the user.
if (!BAllowedToTakeOffline())
break;
dwStatus = OfflineClusterResource(Hresource());
if ((dwStatus != ERROR_SUCCESS)
&& (dwStatus != ERROR_IO_PENDING))
{
CNTException nte(dwStatus, IDS_TAKE_RESOURCE_OFFLINE_ERROR, StrName(), NULL, FALSE /*bAutoDelete*/);
nte.ReportError();
} // if: error taking the resource offline
UpdateState();
} while (0); // do-while to prevent goto's
Release();
} //*** CResource::OnCmdTakeOffline()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::OnCmdInitiateFailure
//
// Routine Description:
// Processes the ID_FILE_INITIATE_FAILURE menu command.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CResource::OnCmdInitiateFailure(void)
{
DWORD dwStatus;
CWaitCursor wc;
ASSERT(Hresource() != NULL);
dwStatus = FailClusterResource(Hresource());
if (dwStatus != ERROR_SUCCESS)
{
CNTException nte(dwStatus, IDS_INIT_RESOURCE_FAILURE_ERROR, StrName(), NULL /*bAutoDelete*/);
nte.ReportError();
} // if: error initiating failure
UpdateState();
} //*** CResource::OnCmdInitiateFailure()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::OnCmdMoveResource
//
// Routine Description:
// Processes the ID_FILE_MOVE_RESOURCE_# menu commands.
//
// Arguments:
// nID [IN] Command ID.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CResource::OnCmdMoveResource(IN UINT nID)
{
int ipci;
ASSERT(Hresource() != NULL);
// Do this in case this object is deleted while we are operating on it.
AddRef();
do // do-while to prevent goto's
{
ipci = (int) (nID - ID_FILE_MOVE_RESOURCE_1);
ASSERT(ipci < Pdoc()->LpciGroups().GetCount());
if (ipci < Pdoc()->LpciGroups().GetCount())
{
POSITION pos;
CResourceList lpciMove;
CString strMsg;
CGroup * pciGroup;
// Get the group.
pos = Pdoc()->LpciGroups().FindIndex(ipci);
ASSERT(pos != NULL);
pciGroup = (CGroup *) Pdoc()->LpciGroups().GetAt(pos);
ASSERT_VALID(pciGroup);
try
{
// Verify that the user really wants to move this resource.
strMsg.FormatMessage(IDS_VERIFY_MOVE_RESOURCE, StrName(), StrGroup(), pciGroup->StrName());
if (AfxMessageBox(strMsg, MB_YESNO | MB_ICONEXCLAMATION | MB_DEFBUTTON2) == IDNO)
break;
// Collect the list of resources which will be moved if confirmed.
lpciMove.AddTail(this);
CollectDependencyTree(&lpciMove);
// If this resource is dependent on or is a dependent of any other resource,
// display another warning message.
if (lpciMove.GetCount() > 0)
{
CMoveResourcesDlg dlg(this, &lpciMove, AfxGetMainWnd());
if (dlg.DoModal() != IDOK)
break;
} // if: resource is dependent of another resource
// Move the resource.
{
CWaitCursor wc;
Move(pciGroup);
} // Move the resource
} // try
catch (CException * pe)
{
pe->ReportError();
pe->Delete();
} // catch: CException
} // if: valid index
} while (0); // do-while to prevent goto's
Release();
} //*** CResource::OnCmdMoveResource()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::OnCmdDelete
//
// Routine Description:
// Processes the ID_FILE_DELETE menu command.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CResource::OnCmdDelete(void)
{
CResourceList lpci;
CString strMsg;
ASSERT(Hresource() != NULL);
// Do this in case this object is deleted while we are operating on it.
AddRef();
do // do-while to prevent goto's
{
try
{
// If this is a core resource, we can't delete it.
if (BCore())
{
AfxMessageBox(IDS_CANT_DELETE_CORE_RESOURCE, MB_OK | MB_ICONSTOP);
break;
} // If this is a core resource
// Verify that the user really wants to delete this resource.
strMsg.FormatMessage(IDS_VERIFY_DELETE_RESOURCE, StrName());
if (AfxMessageBox(strMsg, MB_YESNO | MB_ICONEXCLAMATION | MB_DEFBUTTON2) == IDNO)
break;
if (Hresource() != NULL)
{
// Collect the list of resources which will be deleted if confirmed.
CollectProvidesFor(&lpci, TRUE /*bFullTree*/);
// If any of these resources are core resources, we can't
// delete any of the resources.
{
POSITION pos;
CResource * pciRes = NULL;
pos = lpci.GetHeadPosition();
while (pos != NULL)
{
pciRes = (CResource *) lpci.GetNext(pos);
ASSERT_VALID(pciRes);
if (pciRes->BCore())
{
AfxMessageBox(IDS_CANT_DELETE_CORE_RESOURCE, MB_OK | MB_ICONSTOP);
break;
} // if: found a core resource
pciRes = NULL;
} // while: more items in the list
if (pciRes != NULL)
break;
} // Check for core resources
// If this resource is a dependent of any other resource, display
// another warning message.
if (lpci.GetCount() > 0)
{
CDeleteResourcesDlg dlg(this, &lpci, AfxGetMainWnd());
if (dlg.DoModal() != IDOK)
break;
} // if: resource is dependent of another resource
// Delete the resource.
{
CWaitCursor wc;
DeleteResource(lpci);
} // Delete the resource
} // if: resource still exists
} // try
catch (CNTException * pnte)
{
if (pnte->Sc() != ERROR_RESOURCE_NOT_AVAILABLE)
pnte->ReportError();
pnte->Delete();
} // catch: CNTException
catch (CException * pe)
{
pe->ReportError();
pe->Delete();
} // catch: CException
} while (0); // do-while to prevent goto's
Release();
} //*** CResource::OnCmdDelete()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::OnUpdateProperties
//
// Routine Description:
// Determines whether menu items corresponding to ID_FILE_PROPERTIES
// should be enabled or not.
//
// Arguments:
// pCmdUI [IN OUT] Command routing object.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CResource::OnUpdateProperties(CCmdUI * pCmdUI)
{
pCmdUI->Enable(TRUE);
} //*** CResource::OnUpdateProperties()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::BDisplayProperties
//
// Routine Description:
// Display properties for the object.
//
// Arguments:
// bReadOnly [IN] Don't allow edits to the object properties.
//
// Return Value:
// TRUE OK pressed.
// FALSE OK not pressed.
//
//--
/////////////////////////////////////////////////////////////////////////////
BOOL CResource::BDisplayProperties(IN BOOL bReadOnly)
{
BOOL bChanged = FALSE;
CResourcePropSheet sht(AfxGetMainWnd());
// Do this in case this object is deleted while we are operating on it.
AddRef();
// If the object has changed, read it.
if (BChanged())
ReadItem();
// Display the property sheet.
try
{
sht.SetReadOnly(bReadOnly);
if (sht.BInit(this, IimgObjectType()))
bChanged = ((sht.DoModal() == IDOK) && !bReadOnly);
} // try
catch (CException * pe)
{
pe->Delete();
} // catch: CException
Release();
return bChanged;
} //*** CResource::BDisplayProperties()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::BAllowedToTakeOffline
//
// Routine Description:
// Determine if this resource is allowed to be taken offline.
//
// Arguments:
// None.
//
// Return Value:
// TRUE Resource is allowed to be taken offline.
// FALSE Resource is NOT allowed to be taken offline.
//
//--
/////////////////////////////////////////////////////////////////////////////
BOOL CResource::BAllowedToTakeOffline(void)
{
BOOL bAllowed = TRUE;
ASSERT_VALID(Pdoc());
// Do this in case this object is deleted while we are operating on it.
AddRef();
// Check to see if document is connected via the cluster name.
if (Pdoc()->StrName() == Pdoc()->StrNode())
{
// If this is the core network name resource, we need to ask
// the user first.
if ( (StrRealResourceType().CompareNoCase(CLUS_RESTYPE_NAME_NETNAME) == 0)
&& BCore() )
bAllowed = FALSE;
else
{
CResourceList lpci;
CResource * pciRes;
POSITION pos;
// Collect all the resources above this resource in the
// dependency tree. If one of them is the cluster name
// resource, we need to ask the user first.
try
{
CollectProvidesFor(&lpci, TRUE /*bFullTree*/);
pos = lpci.GetHeadPosition();
while (pos != NULL)
{
pciRes = (CResource *) lpci.GetNext(pos);
ASSERT_VALID(pciRes);
if ( (pciRes->StrRealResourceType().CompareNoCase(CLUS_RESTYPE_NAME_NETNAME) == 0)
&& pciRes->BCore() )
bAllowed = FALSE;
} // while: more resources in the list
} // try
catch (CException * pe)
{
pe->Delete();
} // catch: CException
} // else: not the cluster name resource
} // if: connected via the cluster name
// If not allowed to take offline, ask the user to confirm.
if (!bAllowed)
{
ID id;
CString strMsg;
strMsg.FormatMessage(IDS_TAKE_CLUSTER_NAME_OFFLINE_QUERY, StrName(), Pdoc()->StrName());
id = AfxMessageBox(strMsg, MB_OKCANCEL | MB_ICONEXCLAMATION);
bAllowed = (id == IDOK);
} // if: not allowed to atake offline
Release();
return bAllowed;
} //*** CResource::BAllowedToTakeOffline()
/////////////////////////////////////////////////////////////////////////////
//++
//
// CResource::OnClusterNotify
//
// Routine Description:
// Handler for the WM_CAM_CLUSTER_NOTIFY message.
// Processes cluster notifications for this object.
//
// Arguments:
// pnotify [IN OUT] Object describing the notification.
//
// Return Value:
// Value returned from the application method.
//
//--
/////////////////////////////////////////////////////////////////////////////
LRESULT CResource::OnClusterNotify(IN OUT CClusterNotify * pnotify)
{
ASSERT(pnotify != NULL);
ASSERT_VALID(this);
try
{
switch (pnotify->m_dwFilterType)
{
case CLUSTER_CHANGE_RESOURCE_STATE:
Trace(g_tagResNotify, _T("(%s) - Resource '%s' (%x) state changed (%s)"), Pdoc()->StrNode(), StrName(), this, pnotify->m_strName);
UpdateState();
break;
case CLUSTER_CHANGE_RESOURCE_DELETED:
Trace(g_tagResNotify, _T("(%s) - Resource '%s' (%x) deleted (%s)"), Pdoc()->StrNode(), StrName(), this, pnotify->m_strName);
if (Pdoc()->BClusterAvailable())
Delete();
break;
case CLUSTER_CHANGE_RESOURCE_PROPERTY:
Trace(g_tagResNotify, _T("(%s) - Resource '%s' (%x) properties changed (%s)"), Pdoc()->StrNode(), StrName(), this, pnotify->m_strName);
if (!BDeleting() && Pdoc()->BClusterAvailable())
ReadItem();
break;
case CLUSTER_CHANGE_REGISTRY_NAME:
Trace(g_tagResRegNotify, _T("(%s) - Registry namespace '%s' changed (%s %s (%x))"), Pdoc()->StrNode(), pnotify->m_strName, StrType(), StrName(), this);
MarkAsChanged();
break;
case CLUSTER_CHANGE_REGISTRY_ATTRIBUTES:
Trace(g_tagResRegNotify, _T("(%s) - Registry attributes for '%s' changed (%s %s (%x))"), Pdoc()->StrNode(), pnotify->m_strName, StrType(), StrName(), this);
MarkAsChanged();
break;
case CLUSTER_CHANGE_REGISTRY_VALUE:
Trace(g_tagResRegNotify, _T("(%s) - Registry value '%s' changed (%s %s (%x))"), Pdoc()->StrNode(), pnotify->m_strName, StrType(), StrName(), this);
MarkAsChanged();
break;
default:
Trace(g_tagResNotify, _T("(%s) - Unknown resource notification (%x) for '%s' (%x) (%s)"), Pdoc()->StrNode(), pnotify->m_dwFilterType, StrName(), this, pnotify->m_strName);
} // switch: dwFilterType
} // try
catch (CException * pe)
{
// Don't display anything on notification errors.
// If it's really a problem, the user will see it when
// refreshing the view.
//pe->ReportError();
pe->Delete();
} // catch: CException
delete pnotify;
return 0;
} //*** CResource::OnClusterNotify()
//*************************************************************************//
/////////////////////////////////////////////////////////////////////////////
// Global Functions
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
//++
//
// DeleteAllItemData
//
// Routine Description:
// Deletes all item data in a CList.
//
// Arguments:
// rlp [IN OUT] List whose data is to be deleted.
//
// Return Value:
// None.
//
//--
/////////////////////////////////////////////////////////////////////////////
#ifdef NEVER
void DeleteAllItemData(IN OUT CResourceList & rlp)
{
POSITION pos;
CResource * pci;
// Delete all the items in the Contained list.
pos = rlp.GetHeadPosition();
while (pos != NULL)
{
pci = rlp.GetNext(pos);
ASSERT_VALID(pci);
// Trace(g_tagClusItemDelete, _T("DeleteAllItemData(rlpcires) - Deleting resource cluster item '%s' (%x)"), pci->StrName(), pci);
pci->Delete();
} // while: more items in the list
} //*** DeleteAllItemData()
#endif