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