Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2627 lines
67 KiB

  1. /////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1996-2000 Microsoft Corporation
  4. //
  5. // Module Name:
  6. // Group.cpp
  7. //
  8. // Abstract:
  9. // Implementation of the CGroup class.
  10. //
  11. // Author:
  12. // David Potter (davidp) May 3, 1996
  13. //
  14. // Revision History:
  15. //
  16. // Notes:
  17. //
  18. /////////////////////////////////////////////////////////////////////////////
  19. #include "stdafx.h"
  20. #include "CluAdmin.h"
  21. #include "ConstDef.h"
  22. #include "Group.h"
  23. #include "ClusItem.inl"
  24. #include "GrpProp.h"
  25. #include "ExcOper.h"
  26. #include "TraceTag.h"
  27. #include "Cluster.h"
  28. #ifdef _DEBUG
  29. #define new DEBUG_NEW
  30. #undef THIS_FILE
  31. static char THIS_FILE[] = __FILE__;
  32. #endif
  33. /////////////////////////////////////////////////////////////////////////////
  34. // Global Variables
  35. /////////////////////////////////////////////////////////////////////////////
  36. #ifdef _DEBUG
  37. CTraceTag g_tagGroup(_T("Document"), _T("GROUP"), 0);
  38. CTraceTag g_tagGroupRead(_T("Document"), _T("GROUP READ"), 0);
  39. CTraceTag g_tagGroupDrag(_T("Drag&Drop"), _T("GROUP DRAG"), 0);
  40. CTraceTag g_tagGroupMenu(_T("Menu"), _T("GROUP MENU"), 0);
  41. CTraceTag g_tagGroupNotify(_T("Notify"), _T("GROUP NOTIFY"), 0);
  42. CTraceTag g_tagGroupRegNotify(_T("Notify"), _T("GROUP REG NOTIFY"), 0);
  43. #endif
  44. /////////////////////////////////////////////////////////////////////////////
  45. // CGroup
  46. /////////////////////////////////////////////////////////////////////////////
  47. IMPLEMENT_DYNCREATE(CGroup, CClusterItem)
  48. /////////////////////////////////////////////////////////////////////////////
  49. // Message Maps
  50. /////////////////////////////////////////////////////////////////////////////
  51. BEGIN_MESSAGE_MAP(CGroup, CClusterItem)
  52. //{{AFX_MSG_MAP(CGroup)
  53. ON_UPDATE_COMMAND_UI(ID_FILE_BRING_ONLINE, OnUpdateBringOnline)
  54. ON_UPDATE_COMMAND_UI(ID_FILE_TAKE_OFFLINE, OnUpdateTakeOffline)
  55. ON_UPDATE_COMMAND_UI(ID_FILE_MOVE_GROUP, OnUpdateMoveGroup)
  56. ON_UPDATE_COMMAND_UI(ID_FILE_MOVE_GROUP_1, OnUpdateMoveGroupRest)
  57. ON_UPDATE_COMMAND_UI(ID_FILE_DELETE, OnUpdateDelete)
  58. ON_UPDATE_COMMAND_UI(ID_FILE_MOVE_GROUP_2, OnUpdateMoveGroupRest)
  59. ON_UPDATE_COMMAND_UI(ID_FILE_MOVE_GROUP_3, OnUpdateMoveGroupRest)
  60. ON_UPDATE_COMMAND_UI(ID_FILE_MOVE_GROUP_4, OnUpdateMoveGroupRest)
  61. ON_UPDATE_COMMAND_UI(ID_FILE_MOVE_GROUP_5, OnUpdateMoveGroupRest)
  62. ON_UPDATE_COMMAND_UI(ID_FILE_MOVE_GROUP_6, OnUpdateMoveGroupRest)
  63. ON_UPDATE_COMMAND_UI(ID_FILE_MOVE_GROUP_7, OnUpdateMoveGroupRest)
  64. ON_UPDATE_COMMAND_UI(ID_FILE_MOVE_GROUP_8, OnUpdateMoveGroupRest)
  65. ON_UPDATE_COMMAND_UI(ID_FILE_MOVE_GROUP_9, OnUpdateMoveGroupRest)
  66. ON_UPDATE_COMMAND_UI(ID_FILE_MOVE_GROUP_10, OnUpdateMoveGroupRest)
  67. ON_UPDATE_COMMAND_UI(ID_FILE_MOVE_GROUP_11, OnUpdateMoveGroupRest)
  68. ON_UPDATE_COMMAND_UI(ID_FILE_MOVE_GROUP_12, OnUpdateMoveGroupRest)
  69. ON_UPDATE_COMMAND_UI(ID_FILE_MOVE_GROUP_13, OnUpdateMoveGroupRest)
  70. ON_UPDATE_COMMAND_UI(ID_FILE_MOVE_GROUP_14, OnUpdateMoveGroupRest)
  71. ON_UPDATE_COMMAND_UI(ID_FILE_MOVE_GROUP_15, OnUpdateMoveGroupRest)
  72. ON_UPDATE_COMMAND_UI(ID_FILE_MOVE_GROUP_16, OnUpdateMoveGroupRest)
  73. ON_UPDATE_COMMAND_UI(ID_FILE_PROPERTIES, OnUpdateProperties)
  74. ON_COMMAND(ID_FILE_BRING_ONLINE, OnCmdBringOnline)
  75. ON_COMMAND(ID_FILE_TAKE_OFFLINE, OnCmdTakeOffline)
  76. ON_COMMAND(ID_FILE_MOVE_GROUP, OnCmdMoveGroup)
  77. ON_COMMAND(ID_FILE_DELETE, OnCmdDelete)
  78. //}}AFX_MSG_MAP
  79. END_MESSAGE_MAP()
  80. /////////////////////////////////////////////////////////////////////////////
  81. //++
  82. //
  83. // CGroup::CGroup
  84. //
  85. // Routine Description:
  86. // Default constructor.
  87. //
  88. // Arguments:
  89. // None.
  90. //
  91. // Return Value:
  92. // None.
  93. //
  94. //--
  95. /////////////////////////////////////////////////////////////////////////////
  96. CGroup::CGroup(void) : CClusterItem(NULL, IDS_ITEMTYPE_GROUP)
  97. {
  98. CommonConstruct();
  99. } //*** CGroup::CGroup()
  100. /////////////////////////////////////////////////////////////////////////////
  101. //++
  102. //
  103. // CGroup::CGroup
  104. //
  105. // Routine Description:
  106. // Default constructor.
  107. //
  108. // Arguments:
  109. // bDocObj [IN] TRUE = object is part of the document.
  110. //
  111. // Return Value:
  112. // None.
  113. //
  114. //--
  115. /////////////////////////////////////////////////////////////////////////////
  116. CGroup::CGroup(IN BOOL bDocObj) : CClusterItem(NULL, IDS_ITEMTYPE_GROUP)
  117. {
  118. CommonConstruct();
  119. m_bDocObj = bDocObj;
  120. } //*** CGroup::CGroup(bDocObj)
  121. /////////////////////////////////////////////////////////////////////////////
  122. //++
  123. //
  124. // CGroup::CommonConstruct
  125. //
  126. // Routine Description:
  127. // Common construction.
  128. //
  129. // Arguments:
  130. // None.
  131. //
  132. // Return Value:
  133. // None.
  134. //
  135. //--
  136. /////////////////////////////////////////////////////////////////////////////
  137. void CGroup::CommonConstruct(void)
  138. {
  139. m_idmPopupMenu = IDM_GROUP_POPUP;
  140. m_hgroup = NULL;
  141. m_nFailoverThreshold = CLUSTER_GROUP_DEFAULT_FAILOVER_THRESHOLD;
  142. m_nFailoverPeriod = CLUSTER_GROUP_DEFAULT_FAILOVER_PERIOD;
  143. m_cgaftAutoFailbackType = CLUSTER_GROUP_DEFAULT_AUTO_FAILBACK_TYPE;
  144. m_nFailbackWindowStart = CLUSTER_GROUP_DEFAULT_FAILBACK_WINDOW_START;
  145. m_nFailbackWindowEnd = CLUSTER_GROUP_DEFAULT_FAILBACK_WINDOW_END;
  146. m_pciOwner = NULL;
  147. m_plpcires = NULL;
  148. m_plpcinodePreferredOwners = NULL;
  149. // Set the object type image.
  150. m_iimgObjectType = GetClusterAdminApp()->Iimg(IMGLI_GROUP);
  151. // Setup the property array.
  152. {
  153. m_rgProps[epropName].Set(CLUSREG_NAME_GRP_NAME, m_strName, m_strName);
  154. m_rgProps[epropDescription].Set(CLUSREG_NAME_GRP_DESC, m_strDescription, m_strDescription);
  155. m_rgProps[epropFailoverThreshold].Set(CLUSREG_NAME_GRP_FAILOVER_THRESHOLD, m_nFailoverThreshold, m_nFailoverThreshold);
  156. m_rgProps[epropFailoverPeriod].Set(CLUSREG_NAME_GRP_FAILOVER_PERIOD, m_nFailoverPeriod, m_nFailoverPeriod);
  157. m_rgProps[epropAutoFailbackType].Set(CLUSREG_NAME_GRP_FAILBACK_TYPE, (DWORD &) m_cgaftAutoFailbackType, (DWORD &) m_cgaftAutoFailbackType);
  158. m_rgProps[epropFailbackWindowStart].Set(CLUSREG_NAME_GRP_FAILBACK_WIN_START, m_nFailbackWindowStart, m_nFailbackWindowStart);
  159. m_rgProps[epropFailbackWindowEnd].Set(CLUSREG_NAME_GRP_FAILBACK_WIN_END, m_nFailbackWindowEnd, m_nFailbackWindowEnd);
  160. } // Setup the property array
  161. #ifdef _CLUADMIN_USE_OLE_
  162. EnableAutomation();
  163. #endif
  164. // To keep the application running as long as an OLE automation
  165. // object is active, the constructor calls AfxOleLockApp.
  166. // AfxOleLockApp();
  167. } //*** CGroup::CommonConstruct()
  168. /////////////////////////////////////////////////////////////////////////////
  169. //++
  170. //
  171. // CGroup::~CGroup
  172. //
  173. // Routine Description:
  174. // Destructor.
  175. //
  176. // Arguments:
  177. // None.
  178. //
  179. // Return Value:
  180. // None.
  181. //
  182. //--
  183. /////////////////////////////////////////////////////////////////////////////
  184. CGroup::~CGroup(void)
  185. {
  186. // Cleanup this object.
  187. Cleanup();
  188. delete m_plpcires;
  189. delete m_plpcinodePreferredOwners;
  190. // Close the group handle.
  191. if (Hgroup() != NULL)
  192. CloseClusterGroup(Hgroup());
  193. // To terminate the application when all objects created with
  194. // with OLE automation, the destructor calls AfxOleUnlockApp.
  195. // AfxOleUnlockApp();
  196. } //*** CGroup::~CGroup
  197. /////////////////////////////////////////////////////////////////////////////
  198. //++
  199. //
  200. // CGroup::Cleanup
  201. //
  202. // Routine Description:
  203. // Cleanup the item.
  204. //
  205. // Arguments:
  206. // None.
  207. //
  208. // Return Value:
  209. // None.
  210. //
  211. // Exceptions Thrown:
  212. // None.
  213. //
  214. //--
  215. /////////////////////////////////////////////////////////////////////////////
  216. void CGroup::Cleanup(void)
  217. {
  218. // Delete the resource list.
  219. if (m_plpcires != NULL)
  220. m_plpcires->RemoveAll();
  221. // Delete the PreferredOwners list.
  222. if (m_plpcinodePreferredOwners != NULL)
  223. m_plpcinodePreferredOwners->RemoveAll();
  224. // If we are active on a node, remove ourselves from that active list.
  225. if (PciOwner() != NULL)
  226. {
  227. if (BDocObj())
  228. PciOwner()->RemoveActiveGroup(this);
  229. PciOwner()->Release();
  230. m_pciOwner = NULL;
  231. } // if: there is an owner
  232. // Remove the item from the group list.
  233. if (BDocObj())
  234. {
  235. POSITION posPci;
  236. posPci = Pdoc()->LpciGroups().Find(this);
  237. if (posPci != NULL)
  238. {
  239. Pdoc()->LpciGroups().RemoveAt(posPci);
  240. } // if: found in the document's list
  241. } // if: this is a document object
  242. } //*** CGroup::Cleanup()
  243. /////////////////////////////////////////////////////////////////////////////
  244. //++
  245. //
  246. // CGroup::Create
  247. //
  248. // Routine Description:
  249. // Create a group.
  250. //
  251. // Arguments:
  252. // pdoc [IN OUT] Document to which this item belongs.
  253. // lpszName [IN] Name of the group.
  254. //
  255. // Return Value:
  256. // None.
  257. //
  258. // Exceptions Thrown:
  259. // CNTException Errors from CreateClusterResource.
  260. // Any exceptions thrown by CResource::Init(), CResourceList::new(),
  261. // or CNodeList::new().
  262. //
  263. //--
  264. /////////////////////////////////////////////////////////////////////////////
  265. void CGroup::Create(IN OUT CClusterDoc * pdoc, IN LPCTSTR lpszName)
  266. {
  267. DWORD dwStatus;
  268. HGROUP hgroup;
  269. CString strName(lpszName); // Required if built non-Unicode
  270. CWaitCursor wc;
  271. ASSERT(Hgroup() == NULL);
  272. ASSERT(Hkey() == NULL);
  273. ASSERT_VALID(pdoc);
  274. ASSERT(lpszName != NULL);
  275. // Create the group.
  276. hgroup = CreateClusterGroup(pdoc->Hcluster(), strName);
  277. if (hgroup == NULL)
  278. {
  279. dwStatus = GetLastError();
  280. ThrowStaticException(dwStatus, IDS_CREATE_GROUP_ERROR, lpszName);
  281. } // if: error creating the cluster group
  282. CloseClusterGroup(hgroup);
  283. // Open the group.
  284. Init(pdoc, lpszName);
  285. } //*** CGroup::Create()
  286. /////////////////////////////////////////////////////////////////////////////
  287. //++
  288. //
  289. // CGroup::Init
  290. //
  291. // Routine Description:
  292. // Initialize the item.
  293. //
  294. // Arguments:
  295. // pdoc [IN OUT] Document to which this item belongs.
  296. // lpszName [IN] Name of the item.
  297. //
  298. // Return Value:
  299. // None.
  300. //
  301. // Exceptions Thrown:
  302. // CNTException Errors from OpenClusterGroup() or GetClusterGroupKey().
  303. //
  304. //--
  305. /////////////////////////////////////////////////////////////////////////////
  306. void CGroup::Init(IN OUT CClusterDoc * pdoc, IN LPCTSTR lpszName)
  307. {
  308. DWORD dwStatus = ERROR_SUCCESS;
  309. LONG lResult;
  310. CString strName(lpszName); // Required if built non-Unicode
  311. CWaitCursor wc;
  312. ASSERT(Hgroup() == NULL);
  313. ASSERT(Hkey() == NULL);
  314. // Call the base class method.
  315. CClusterItem::Init(pdoc, lpszName);
  316. try
  317. {
  318. // Open the group.
  319. m_hgroup = OpenClusterGroup(Hcluster(), strName);
  320. if (Hgroup() == NULL)
  321. {
  322. dwStatus = GetLastError();
  323. ThrowStaticException(dwStatus, IDS_OPEN_GROUP_ERROR, lpszName);
  324. } // if: error opening the cluster group
  325. // Get the group registry key.
  326. m_hkey = GetClusterGroupKey(Hgroup(), MAXIMUM_ALLOWED);
  327. if (Hkey() == NULL)
  328. ThrowStaticException(GetLastError(), IDS_GET_GROUP_KEY_ERROR, lpszName);
  329. if (BDocObj())
  330. {
  331. ASSERT(Pcnk() != NULL);
  332. Trace(g_tagClusItemNotify, _T("CGroup::Init() - Registering for group notifications (%08.8x) for '%s'"), Pcnk(), StrName());
  333. // Register for group notifications.
  334. lResult = RegisterClusterNotify(
  335. GetClusterAdminApp()->HchangeNotifyPort(),
  336. (CLUSTER_CHANGE_GROUP_STATE
  337. | CLUSTER_CHANGE_GROUP_DELETED
  338. | CLUSTER_CHANGE_GROUP_PROPERTY),
  339. Hgroup(),
  340. (DWORD_PTR) Pcnk()
  341. );
  342. if (lResult != ERROR_SUCCESS)
  343. {
  344. dwStatus = lResult;
  345. ThrowStaticException(dwStatus, IDS_GROUP_NOTIF_REG_ERROR, lpszName);
  346. } // if: error registering for group notifications
  347. // Register for registry notifications.
  348. if (Hkey() != NULL)
  349. {
  350. lResult = RegisterClusterNotify(
  351. GetClusterAdminApp()->HchangeNotifyPort(),
  352. (CLUSTER_CHANGE_REGISTRY_NAME
  353. | CLUSTER_CHANGE_REGISTRY_ATTRIBUTES
  354. | CLUSTER_CHANGE_REGISTRY_VALUE
  355. | CLUSTER_CHANGE_REGISTRY_SUBTREE),
  356. Hkey(),
  357. (DWORD_PTR) Pcnk()
  358. );
  359. if (lResult != ERROR_SUCCESS)
  360. {
  361. dwStatus = lResult;
  362. ThrowStaticException(dwStatus, IDS_GROUP_NOTIF_REG_ERROR, lpszName);
  363. } // if: error registering for registry notifications
  364. } // if: there is a key
  365. } // if: document object
  366. // Allocate lists.
  367. m_plpcires = new CResourceList;
  368. if ( m_plpcires == NULL )
  369. {
  370. AfxThrowMemoryException();
  371. } // if: error allocating resource list
  372. m_plpcinodePreferredOwners = new CNodeList;
  373. if ( m_plpcinodePreferredOwners == NULL )
  374. {
  375. AfxThrowMemoryException();
  376. } // if: error allocating preferred owners list
  377. // Read the initial state.
  378. UpdateState();
  379. } // try
  380. catch (CException *)
  381. {
  382. if (Hkey() != NULL)
  383. {
  384. ClusterRegCloseKey(Hkey());
  385. m_hkey = NULL;
  386. } // if: registry key opened
  387. if (Hgroup() != NULL)
  388. {
  389. CloseClusterGroup(Hgroup());
  390. m_hgroup = NULL;
  391. } // if: group opened
  392. m_bReadOnly = TRUE;
  393. throw;
  394. } // catch: CException
  395. } //*** CGroup::Init()
  396. /////////////////////////////////////////////////////////////////////////////
  397. //++
  398. //
  399. // CGroup::ReadItem
  400. //
  401. // Routine Description:
  402. // Read the item parameters from the cluster database.
  403. //
  404. // Arguments:
  405. // None.
  406. //
  407. // Return Value:
  408. // None.
  409. //
  410. // Exceptions Thrown:
  411. // CNTException Errors from CClusterItem::DwReadValue() or
  412. // CGroup::ConstructList().
  413. //
  414. //--
  415. /////////////////////////////////////////////////////////////////////////////
  416. void CGroup::ReadItem(void)
  417. {
  418. DWORD dwStatus;
  419. DWORD dwRetStatus = ERROR_SUCCESS;
  420. CWaitCursor wc;
  421. ASSERT_VALID(this);
  422. if (Hgroup() != NULL)
  423. {
  424. m_rgProps[epropDescription].m_value.pstr = &m_strDescription;
  425. m_rgProps[epropFailoverThreshold].m_value.pdw = &m_nFailoverThreshold;
  426. m_rgProps[epropFailoverPeriod].m_value.pdw = &m_nFailoverPeriod;
  427. m_rgProps[epropAutoFailbackType].m_value.pdw = (DWORD *) &m_cgaftAutoFailbackType;
  428. m_rgProps[epropFailbackWindowStart].m_value.pdw = &m_nFailbackWindowStart;
  429. m_rgProps[epropFailbackWindowEnd].m_value.pdw = &m_nFailbackWindowEnd;
  430. // Call the base class method.
  431. CClusterItem::ReadItem();
  432. Trace(g_tagGroupRead, _T("ReadItem() - Name before reading properties: '%s'"), StrName());
  433. // Read and parse the common properties.
  434. {
  435. CClusPropList cpl;
  436. dwStatus = cpl.ScGetGroupProperties(
  437. Hgroup(),
  438. CLUSCTL_GROUP_GET_COMMON_PROPERTIES
  439. );
  440. if (dwStatus == ERROR_SUCCESS)
  441. dwStatus = DwParseProperties(cpl);
  442. if (dwStatus != ERROR_SUCCESS)
  443. dwRetStatus = dwStatus;
  444. } // Read and parse the common properties
  445. // Read and parse the read-only common properties.
  446. if (dwRetStatus == ERROR_SUCCESS)
  447. {
  448. CClusPropList cpl;
  449. dwStatus = cpl.ScGetGroupProperties(
  450. Hgroup(),
  451. CLUSCTL_GROUP_GET_RO_COMMON_PROPERTIES
  452. );
  453. if (dwStatus == ERROR_SUCCESS)
  454. dwStatus = DwParseProperties(cpl);
  455. if (dwStatus != ERROR_SUCCESS)
  456. dwRetStatus = dwStatus;
  457. } // if: no error yet
  458. Trace(g_tagGroupRead, _T("ReadItem() - Name after reading properties: '%s'"), StrName());
  459. // Read extension lists.
  460. ReadExtensions();
  461. if (dwRetStatus == ERROR_SUCCESS)
  462. {
  463. // Read the list of preferred owners.
  464. ASSERT(m_plpcinodePreferredOwners != NULL);
  465. ConstructList(*m_plpcinodePreferredOwners, CLUSTER_GROUP_ENUM_NODES);
  466. } // if: no error reading properties
  467. } // if: group is available
  468. // Read the initial state.
  469. UpdateState();
  470. // Construct the list of resources contained in the group.
  471. // ASSERT(m_plpcires != NULL);
  472. // ConstructList(*m_plpcires, CLUSTER_GROUP_ENUM_CONTAINS);
  473. // If any errors occurred, throw an exception.
  474. if (dwRetStatus != ERROR_SUCCESS)
  475. {
  476. m_bReadOnly = TRUE;
  477. if ( (dwRetStatus != ERROR_GROUP_NOT_AVAILABLE)
  478. && (dwRetStatus != ERROR_KEY_DELETED))
  479. ThrowStaticException(dwRetStatus, IDS_READ_GROUP_PROPS_ERROR, StrName());
  480. } // if: error reading properties
  481. MarkAsChanged(FALSE);
  482. } //*** CGroup::ReadItem()
  483. /////////////////////////////////////////////////////////////////////////////
  484. //++
  485. //
  486. // CGroup::PlstrExtensions
  487. //
  488. // Routine Description:
  489. // Return the list of admin extensions.
  490. //
  491. // Arguments:
  492. // None.
  493. //
  494. // Return Value:
  495. // plstr List of extensions.
  496. // NULL No extension associated with this object.
  497. //
  498. // Exceptions Thrown:
  499. // None.
  500. //
  501. //--
  502. /////////////////////////////////////////////////////////////////////////////
  503. const CStringList * CGroup::PlstrExtensions(void) const
  504. {
  505. return &Pdoc()->PciCluster()->LstrGroupExtensions();
  506. } //*** CGroup::PlstrExtensions()
  507. /////////////////////////////////////////////////////////////////////////////
  508. //++
  509. //
  510. // CGroup::ReadExtensions
  511. //
  512. // Routine Description:
  513. // Read extension lists.
  514. //
  515. // Arguments:
  516. // None.
  517. //
  518. // Return Value:
  519. // None.
  520. //
  521. // Exceptions Thrown:
  522. // None.
  523. //
  524. //--
  525. /////////////////////////////////////////////////////////////////////////////
  526. void CGroup::ReadExtensions(void)
  527. {
  528. } //*** CGroup::ReadExtensions()
  529. /////////////////////////////////////////////////////////////////////////////
  530. //++
  531. //
  532. // CGroup::ConstructList
  533. //
  534. // Routine Description:
  535. // Construct a list of node items which are enumerable on the group.
  536. //
  537. // Arguments:
  538. // rlpci [OUT] List to fill.
  539. // dwType [IN] Type of objects.
  540. //
  541. // Return Value:
  542. // None.
  543. //
  544. // Exceptions Thrown:
  545. // CNTException Errors from ClusterGroupOpenEnum or ClusterGroupEnum.
  546. // Any exceptions thrown by new or CList::AddTail.
  547. //
  548. //--
  549. /////////////////////////////////////////////////////////////////////////////
  550. void CGroup::ConstructList(
  551. OUT CNodeList & rlpci,
  552. IN DWORD dwType
  553. )
  554. {
  555. DWORD dwStatus;
  556. HGROUPENUM hgrpenum;
  557. int ienum;
  558. LPWSTR pwszName = NULL;
  559. DWORD cchName;
  560. DWORD cchmacName;
  561. DWORD dwRetType;
  562. CClusterNode * pciNode;
  563. CWaitCursor wc;
  564. ASSERT_VALID(Pdoc());
  565. ASSERT(Hgroup() != NULL);
  566. Trace(g_tagGroup, _T("(%s) (%s (%x)) - Constructing node list"), Pdoc()->StrNode(), StrName(), this);
  567. // Remove the previous contents of the list.
  568. rlpci.RemoveAll();
  569. if (Hgroup() != NULL)
  570. {
  571. // Open the enumeration.
  572. hgrpenum = ClusterGroupOpenEnum(Hgroup(), dwType);
  573. if (hgrpenum == NULL)
  574. ThrowStaticException(GetLastError(), IDS_ENUM_PREFERRED_OWNERS_ERROR, StrName());
  575. try
  576. {
  577. // Allocate a name buffer.
  578. cchmacName = 128;
  579. pwszName = new WCHAR[cchmacName];
  580. if ( pwszName == NULL )
  581. {
  582. AfxThrowMemoryException();
  583. } // if: error allocating name buffer
  584. // Loop through the enumeration and add each node to the list.
  585. for (ienum = 0 ; ; ienum++)
  586. {
  587. // Get the next item in the enumeration.
  588. cchName = cchmacName;
  589. dwStatus = ClusterGroupEnum(hgrpenum, ienum, &dwRetType, pwszName, &cchName);
  590. if (dwStatus == ERROR_MORE_DATA)
  591. {
  592. delete [] pwszName;
  593. cchmacName = ++cchName;
  594. pwszName = new WCHAR[cchmacName];
  595. if ( pwszName == NULL )
  596. {
  597. AfxThrowMemoryException();
  598. } // if: error allocating name buffer
  599. dwStatus = ClusterGroupEnum(hgrpenum, ienum, &dwRetType, pwszName, &cchName);
  600. } // if: name buffer was too small
  601. if (dwStatus == ERROR_NO_MORE_ITEMS)
  602. break;
  603. else if (dwStatus != ERROR_SUCCESS)
  604. ThrowStaticException(dwStatus, IDS_ENUM_PREFERRED_OWNERS_ERROR, StrName());
  605. ASSERT(dwRetType == dwType);
  606. // Find the item in the list of nodes on the document.
  607. pciNode = Pdoc()->LpciNodes().PciNodeFromName(pwszName);
  608. ASSERT_VALID(pciNode);
  609. // Add the node to the list.
  610. if (pciNode != NULL)
  611. {
  612. rlpci.AddTail(pciNode);
  613. } // if: found node in list
  614. } // for: each item in the group
  615. delete [] pwszName;
  616. ClusterGroupCloseEnum(hgrpenum);
  617. } // try
  618. catch (CException *)
  619. {
  620. delete [] pwszName;
  621. ClusterGroupCloseEnum(hgrpenum);
  622. throw;
  623. } // catch: any exception
  624. } // if: resource is available
  625. } //*** CGroup::ConstructList(CNodeList&)
  626. /////////////////////////////////////////////////////////////////////////////
  627. //++
  628. //
  629. // CGroup::ConstructList
  630. //
  631. // Routine Description:
  632. // Construct a list of resource items which are enumerable on the group.
  633. //
  634. // Arguments:
  635. // rlpci [OUT] List to fill.
  636. // dwType [IN] Type of objects.
  637. //
  638. // Return Value:
  639. // None.
  640. //
  641. // Exceptions Thrown:
  642. // CNTException Errors from ClusterGroupOpenEnum or ClusterGroupEnum.
  643. // Any exceptions thrown by new or CList::AddTail.
  644. //
  645. //--
  646. /////////////////////////////////////////////////////////////////////////////
  647. void CGroup::ConstructList(
  648. OUT CResourceList & rlpci,
  649. IN DWORD dwType
  650. )
  651. {
  652. DWORD dwStatus;
  653. HGROUPENUM hgrpenum;
  654. int ienum;
  655. LPWSTR pwszName = NULL;
  656. DWORD cchName;
  657. DWORD cchmacName;
  658. DWORD dwRetType;
  659. CResource * pciRes;
  660. CWaitCursor wc;
  661. ASSERT_VALID(Pdoc());
  662. ASSERT(Hgroup() != NULL);
  663. Trace(g_tagGroup, _T("(%s) (%s (%x)) - Constructing resource list"), Pdoc()->StrNode(), StrName(), this);
  664. // Remove the previous contents of the list.
  665. rlpci.RemoveAll();
  666. if (Hgroup() != NULL)
  667. {
  668. // Open the enumeration.
  669. hgrpenum = ClusterGroupOpenEnum(Hgroup(), dwType);
  670. if (hgrpenum == NULL)
  671. ThrowStaticException(GetLastError(), IDS_ENUM_CONTAINS_ERROR, StrName());
  672. try
  673. {
  674. // Allocate a name buffer.
  675. cchmacName = 128;
  676. pwszName = new WCHAR[cchmacName];
  677. if ( pwszName == NULL )
  678. {
  679. AfxThrowMemoryException();
  680. } // if: error allocating name buffer
  681. // Loop through the enumeration and add each resource to the list.
  682. for (ienum = 0 ; ; ienum++)
  683. {
  684. // Get the next item in the enumeration.
  685. cchName = cchmacName;
  686. dwStatus = ClusterGroupEnum(hgrpenum, ienum, &dwRetType, pwszName, &cchName);
  687. if (dwStatus == ERROR_MORE_DATA)
  688. {
  689. delete [] pwszName;
  690. cchmacName = ++cchName;
  691. pwszName = new WCHAR[cchmacName];
  692. if ( pwszName == NULL )
  693. {
  694. AfxThrowMemoryException();
  695. } // if: error allocating name buffer
  696. dwStatus = ClusterGroupEnum(hgrpenum, ienum, &dwRetType, pwszName, &cchName);
  697. } // if: name buffer was too small
  698. if (dwStatus == ERROR_NO_MORE_ITEMS)
  699. break;
  700. else if (dwStatus != ERROR_SUCCESS)
  701. ThrowStaticException(dwStatus, IDS_ENUM_CONTAINS_ERROR, StrName());
  702. ASSERT(dwRetType == dwType);
  703. // Find the item in the list of resources on the document.
  704. pciRes = Pdoc()->LpciResources().PciResFromName(pwszName);
  705. ASSERT_VALID(pciRes);
  706. // Add the resource to the list.
  707. if (pciRes != NULL)
  708. {
  709. rlpci.AddTail(pciRes);
  710. } // if: found resource in list
  711. } // for: each item in the group
  712. delete [] pwszName;
  713. ClusterGroupCloseEnum(hgrpenum);
  714. } // try
  715. catch (CException *)
  716. {
  717. delete [] pwszName;
  718. ClusterGroupCloseEnum(hgrpenum);
  719. throw;
  720. } // catch: any exception
  721. } // if: resource is available
  722. } //*** CGroup::ConstructList(CResourceList&)
  723. /////////////////////////////////////////////////////////////////////////////
  724. //++
  725. //
  726. // CGroup::ConstructPossibleOwnersList
  727. //
  728. // Routine Description:
  729. // Construct the list of nodes on which this group can run.
  730. //
  731. // Arguments:
  732. // rlpciNodes [OUT] List of nodes on which group can run.
  733. //
  734. // Return Value:
  735. // None.
  736. //
  737. //--
  738. /////////////////////////////////////////////////////////////////////////////
  739. void CGroup::ConstructPossibleOwnersList(OUT CNodeList & rlpciNodes)
  740. {
  741. POSITION posNode;
  742. POSITION posRes;
  743. POSITION posResNode;
  744. POSITION posCurResNode = NULL;
  745. CClusterNode * pciNode;
  746. CClusterNode * pciResNode;
  747. CResource * pciRes;
  748. CWaitCursor wc;
  749. ASSERT_VALID(Pdoc());
  750. // Remove the previous contents of the list.
  751. rlpciNodes.RemoveAll();
  752. posNode = Pdoc()->LpciNodes().GetHeadPosition();
  753. while (posNode != NULL)
  754. {
  755. pciNode = (CClusterNode *) Pdoc()->LpciNodes().GetNext(posNode);
  756. ASSERT_VALID(pciNode);
  757. if (Lpcires().GetCount() != 0)
  758. {
  759. posRes = Lpcires().GetHeadPosition();
  760. while (posRes != NULL)
  761. {
  762. pciRes = (CResource *) Lpcires().GetNext(posRes);
  763. ASSERT_VALID(pciRes);
  764. posResNode = pciRes->LpcinodePossibleOwners().GetHeadPosition();
  765. while (posResNode != NULL)
  766. {
  767. posCurResNode = posResNode;
  768. pciResNode = (CClusterNode *) pciRes->LpcinodePossibleOwners().GetNext(posResNode);
  769. ASSERT_VALID(pciResNode);
  770. if (pciNode->StrName() == pciResNode->StrName())
  771. break;
  772. posCurResNode = NULL;
  773. } // while: more possible owners in the list
  774. // If the node wasn't found, the group can't run here.
  775. if (posCurResNode == NULL)
  776. break;
  777. } // while: more resources in the list
  778. } // if: group has resources
  779. // If the node was found on a resource, the group can run here.
  780. if (posCurResNode != NULL)
  781. {
  782. rlpciNodes.AddTail(pciNode);
  783. } // if: node found on a resource
  784. } // while: more nodes in the document
  785. } //*** CGroup::ConstructPossibleOwnersList()
  786. /////////////////////////////////////////////////////////////////////////////
  787. //++
  788. //
  789. // CGroup::DeleteGroup
  790. //
  791. // Routine Description:
  792. // Delete the group.
  793. //
  794. // Arguments:
  795. // None.
  796. //
  797. // Return Value:
  798. // None.
  799. //
  800. // Exceptions Thrown:
  801. // CNTException Any errors from DeleteClusterGroup.
  802. //
  803. //--
  804. /////////////////////////////////////////////////////////////////////////////
  805. void CGroup::DeleteGroup(void)
  806. {
  807. CWaitCursor wc;
  808. if (Hgroup() != NULL)
  809. {
  810. DWORD dwStatus;
  811. CWaitCursor wc;
  812. // Delete the group itself.
  813. dwStatus = DeleteClusterGroup(Hgroup());
  814. if (dwStatus != ERROR_SUCCESS)
  815. ThrowStaticException(dwStatus, IDS_DELETE_GROUP_ERROR, StrName());
  816. UpdateState();
  817. } // if: group has been opened/created
  818. } //*** CGroup::DeleteGroup()
  819. /////////////////////////////////////////////////////////////////////////////
  820. //++
  821. //
  822. // CGroup::AddResource
  823. //
  824. // Routine Description:
  825. // Add a resource to the list of resources contained in this group.
  826. //
  827. // Arguments:
  828. // pciRes [IN OUT] New resource.
  829. //
  830. // Return Value:
  831. // None.
  832. //
  833. //--
  834. /////////////////////////////////////////////////////////////////////////////
  835. void CGroup::AddResource(IN OUT CResource * pciRes)
  836. {
  837. POSITION posPci;
  838. ASSERT_VALID(pciRes);
  839. Trace(g_tagGroup, _T("(%s) (%s (%x)) - Adding resource '%s'"), Pdoc()->StrNode(), StrName(), this, pciRes->StrName());
  840. // Make sure the resource is not already in the list.
  841. VERIFY((posPci = Lpcires().Find(pciRes)) == NULL);
  842. if (posPci == NULL)
  843. {
  844. POSITION posPtiGroup;
  845. CTreeItem * ptiGroup;
  846. // Loop through each tree item to update the group's list of resources.
  847. posPtiGroup = LptiBackPointers().GetHeadPosition();
  848. while (posPtiGroup != NULL)
  849. {
  850. ptiGroup = LptiBackPointers().GetNext(posPtiGroup);
  851. ASSERT_VALID(ptiGroup);
  852. // Add the new resource.
  853. VERIFY(ptiGroup->PliAddChild(pciRes) != NULL);
  854. } // while: more tree items for this group
  855. m_plpcires->AddTail(pciRes);
  856. } // if: resource not in the list yet
  857. } //*** CGroup::AddResource()
  858. /////////////////////////////////////////////////////////////////////////////
  859. //++
  860. //
  861. // CGroup::RemoveResource
  862. //
  863. // Routine Description:
  864. // Remove a resource from the list of resources contained in this group.
  865. //
  866. // Arguments:
  867. // pciRes [IN OUT] Resource that no is no longer contained in this group.
  868. //
  869. // Return Value:
  870. // None.
  871. //
  872. //--
  873. /////////////////////////////////////////////////////////////////////////////
  874. void CGroup::RemoveResource(IN OUT CResource * pciRes)
  875. {
  876. POSITION posPci;
  877. ASSERT_VALID(pciRes);
  878. Trace(g_tagGroup, _T("(%s) (%s (%x)) - Removing resource '%s'"), Pdoc()->StrNode(), StrName(), this, pciRes->StrName());
  879. // Make sure the resource is in the list.
  880. posPci = Lpcires().Find(pciRes);
  881. if (posPci != NULL)
  882. {
  883. POSITION posPtiGroup;
  884. CTreeItem * ptiGroup;
  885. // Loop through each tree item to update the group's list of resources.
  886. posPtiGroup = LptiBackPointers().GetHeadPosition();
  887. while (posPtiGroup != NULL)
  888. {
  889. ptiGroup = LptiBackPointers().GetNext(posPtiGroup);
  890. ASSERT_VALID(ptiGroup);
  891. // Remove the resource.
  892. ptiGroup->RemoveChild(pciRes);
  893. } // while: more tree items for this group
  894. m_plpcires->RemoveAt(posPci);
  895. } // if: resource in the list
  896. } //*** CGroup::RemoveResource()
  897. /////////////////////////////////////////////////////////////////////////////
  898. //++
  899. //
  900. // CGroup::SetName
  901. //
  902. // Routine Description:
  903. // Set the name of this group.
  904. //
  905. // Arguments:
  906. // pszName [IN] New name of the group.
  907. //
  908. // Return Value:
  909. // None.
  910. //
  911. // Exceptions Thrown:
  912. // CNTException IDS_RENAME_GROUP_ERROR - errors from
  913. // SetClusterGroupName().
  914. //--
  915. /////////////////////////////////////////////////////////////////////////////
  916. void CGroup::SetName(IN LPCTSTR pszName)
  917. {
  918. Rename(pszName);
  919. } //*** CGroup::SetName()
  920. /////////////////////////////////////////////////////////////////////////////
  921. //++
  922. //
  923. // CGroup::SetPreferredOwners
  924. //
  925. // Routine Description:
  926. // Set the list of preferred owners of this group in the cluster database.
  927. //
  928. // Arguments:
  929. // rlpci [IN] List of preferred owners (nodes).
  930. //
  931. // Return Value:
  932. // None.
  933. //
  934. // Exceptions Thrown:
  935. // Any exceptions thrown by CStringList::AddTail() or
  936. // CNodeList::AddTail().
  937. //
  938. //--
  939. /////////////////////////////////////////////////////////////////////////////
  940. void CGroup::SetPreferredOwners(IN const CNodeList & rlpci)
  941. {
  942. DWORD dwStatus;
  943. CWaitCursor wc;
  944. ASSERT(Hgroup() != NULL);
  945. if (Hgroup() != NULL)
  946. {
  947. BOOL bChanged = TRUE;
  948. // Determine if the list has changed.
  949. if (rlpci.GetCount() == LpcinodePreferredOwners().GetCount())
  950. {
  951. POSITION posOld;
  952. POSITION posNew;
  953. CClusterNode * pciOldNode;
  954. CClusterNode * pciNewNode;
  955. bChanged = FALSE;
  956. posOld = LpcinodePreferredOwners().GetHeadPosition();
  957. posNew = rlpci.GetHeadPosition();
  958. while (posOld != NULL)
  959. {
  960. pciOldNode = (CClusterNode *) LpcinodePreferredOwners().GetNext(posOld);
  961. ASSERT_VALID(pciOldNode);
  962. ASSERT(posNew != NULL);
  963. pciNewNode = (CClusterNode *) rlpci.GetNext(posNew);
  964. ASSERT_VALID(pciNewNode);
  965. if (pciOldNode->StrName() != pciNewNode->StrName())
  966. {
  967. bChanged = TRUE;
  968. break;
  969. } // if: name is not the same
  970. } // while: more items in the old list
  971. } // if: same number of items in the list
  972. if (bChanged)
  973. {
  974. HNODE * phnode = NULL;
  975. try
  976. {
  977. DWORD ipci;
  978. POSITION posPci;
  979. CClusterNode * pciNode;
  980. // Allocate an array for all the node handles.
  981. phnode = new HNODE[(DWORD)rlpci.GetCount()];
  982. if (phnode == NULL)
  983. {
  984. ThrowStaticException(GetLastError());
  985. } // if: error allocating the node handle array
  986. // Copy the handle of all the nodes in the node list to the handle aray.
  987. posPci = rlpci.GetHeadPosition();
  988. for (ipci = 0 ; posPci != NULL ; ipci++)
  989. {
  990. pciNode = (CClusterNode *) rlpci.GetNext(posPci);
  991. ASSERT_VALID(pciNode);
  992. phnode[ipci] = pciNode->Hnode();
  993. } // while: more nodes in the list
  994. // Set the property.
  995. dwStatus = SetClusterGroupNodeList(Hgroup(), (DWORD)rlpci.GetCount(), phnode);
  996. if (dwStatus != ERROR_SUCCESS)
  997. ThrowStaticException(dwStatus, IDS_SET_GROUP_NODE_LIST_ERROR, StrName());
  998. // Update the PCI list.
  999. m_plpcinodePreferredOwners->RemoveAll();
  1000. posPci = rlpci.GetHeadPosition();
  1001. while (posPci != NULL)
  1002. {
  1003. pciNode = (CClusterNode *) rlpci.GetNext(posPci);
  1004. m_plpcinodePreferredOwners->AddTail(pciNode);
  1005. } // while: more items in the list
  1006. } // try
  1007. catch (CException *)
  1008. {
  1009. delete [] phnode;
  1010. throw;
  1011. } // catch: CException
  1012. delete [] phnode;
  1013. } // if: list changed
  1014. } // if: key is available
  1015. } //*** CGroup::SetPreferredOwners(CNodeList*)
  1016. /////////////////////////////////////////////////////////////////////////////
  1017. //++
  1018. //
  1019. // CGroup::SetCommonProperties
  1020. //
  1021. // Routine Description:
  1022. // Set the common properties for this resource in the cluster database.
  1023. //
  1024. // Arguments:
  1025. // rstrDesc [IN] Description string.
  1026. // nThreshold [IN] Failover threshold.
  1027. // nPeriod [IN] Failover period.
  1028. // cgaft [IN] Auto Failback Type.
  1029. // nStart [IN] Start of failback window.
  1030. // nEnd [IN] End of failback window.
  1031. // bValidateOnly [IN] Only validate the data.
  1032. //
  1033. // Return Value:
  1034. // None.
  1035. //
  1036. // Exceptions Thrown:
  1037. // Any exceptions thrown by CClusterItem::SetCommonProperties().
  1038. //
  1039. //--
  1040. /////////////////////////////////////////////////////////////////////////////
  1041. void CGroup::SetCommonProperties(
  1042. IN const CString & rstrDesc,
  1043. IN DWORD nThreshold,
  1044. IN DWORD nPeriod,
  1045. IN CGAFT cgaft,
  1046. IN DWORD nStart,
  1047. IN DWORD nEnd,
  1048. IN BOOL bValidateOnly
  1049. )
  1050. {
  1051. CNTException nte(ERROR_SUCCESS, 0, NULL, NULL, FALSE /*bAutoDelete*/);
  1052. m_rgProps[epropDescription].m_value.pstr = (CString *) &rstrDesc;
  1053. m_rgProps[epropFailoverThreshold].m_value.pdw = &nThreshold;
  1054. m_rgProps[epropFailoverPeriod].m_value.pdw = &nPeriod;
  1055. m_rgProps[epropAutoFailbackType].m_value.pdw = (DWORD *) &cgaft;
  1056. m_rgProps[epropFailbackWindowStart].m_value.pdw = &nStart;
  1057. m_rgProps[epropFailbackWindowEnd].m_value.pdw = &nEnd;
  1058. try
  1059. {
  1060. CClusterItem::SetCommonProperties(bValidateOnly);
  1061. } // try
  1062. catch (CNTException * pnte)
  1063. {
  1064. nte.SetOperation(
  1065. pnte->Sc(),
  1066. pnte->IdsOperation(),
  1067. pnte->PszOperArg1(),
  1068. pnte->PszOperArg2()
  1069. );
  1070. } // catch: CNTException
  1071. m_rgProps[epropDescription].m_value.pstr = &m_strDescription;
  1072. m_rgProps[epropFailoverThreshold].m_value.pdw = &m_nFailoverThreshold;
  1073. m_rgProps[epropFailoverPeriod].m_value.pdw = &m_nFailoverPeriod;
  1074. m_rgProps[epropAutoFailbackType].m_value.pdw = (DWORD *) &m_cgaftAutoFailbackType;
  1075. m_rgProps[epropFailbackWindowStart].m_value.pdw = &m_nFailbackWindowStart;
  1076. m_rgProps[epropFailbackWindowEnd].m_value.pdw = &m_nFailbackWindowEnd;
  1077. if (nte.Sc() != ERROR_SUCCESS)
  1078. ThrowStaticException(
  1079. nte.Sc(),
  1080. nte.IdsOperation(),
  1081. nte.PszOperArg1(),
  1082. nte.PszOperArg2()
  1083. );
  1084. } //*** CGroup::SetCommonProperties()
  1085. /////////////////////////////////////////////////////////////////////////////
  1086. //++
  1087. //
  1088. // CGroup::DwSetCommonProperties
  1089. //
  1090. // Routine Description:
  1091. // Set the common properties for this group in the cluster database.
  1092. //
  1093. // Arguments:
  1094. // rcpl [IN] Property list to set.
  1095. // bValidateOnly [IN] Only validate the data.
  1096. //
  1097. // Return Value:
  1098. // Any status returned by ClusterGroupControl().
  1099. //
  1100. //--
  1101. /////////////////////////////////////////////////////////////////////////////
  1102. DWORD CGroup::DwSetCommonProperties(
  1103. IN const CClusPropList & rcpl,
  1104. IN BOOL bValidateOnly
  1105. )
  1106. {
  1107. DWORD dwStatus;
  1108. CWaitCursor wc;
  1109. ASSERT(Hgroup());
  1110. if ((rcpl.PbPropList() != NULL) && (rcpl.CbPropList() > 0))
  1111. {
  1112. DWORD cbProps;
  1113. DWORD dwControl;
  1114. if (bValidateOnly)
  1115. dwControl = CLUSCTL_GROUP_VALIDATE_COMMON_PROPERTIES;
  1116. else
  1117. dwControl = CLUSCTL_GROUP_SET_COMMON_PROPERTIES;
  1118. // Set private properties.
  1119. dwStatus = ClusterGroupControl(
  1120. Hgroup(),
  1121. NULL, // hNode
  1122. dwControl,
  1123. rcpl.PbPropList(),
  1124. rcpl.CbPropList(),
  1125. NULL, // lpOutBuffer
  1126. 0, // nOutBufferSize
  1127. &cbProps
  1128. );
  1129. } // if: there is data to set
  1130. else
  1131. dwStatus = ERROR_SUCCESS;
  1132. return dwStatus;
  1133. } //*** CGroup::DwSetCommonProperties()
  1134. /////////////////////////////////////////////////////////////////////////////
  1135. //++
  1136. //
  1137. // CGroup::UpdateState
  1138. //
  1139. // Routine Description:
  1140. // Update the current state of the item.
  1141. //
  1142. // Arguments:
  1143. // None.
  1144. //
  1145. // Return Value:
  1146. // None.
  1147. //
  1148. //--
  1149. /////////////////////////////////////////////////////////////////////////////
  1150. void CGroup::UpdateState(void)
  1151. {
  1152. CClusterAdminApp * papp = GetClusterAdminApp();
  1153. WCHAR * pwszOwner = NULL;
  1154. // This should probably be limited by MAX_COMPUTERNAME_LENGTH (31) for now, but
  1155. // if/when we go to DNS names we'll need at most 255 bytes for the name.
  1156. WCHAR rgwszOwner[256];
  1157. DWORD cchOwner = sizeof(rgwszOwner) / sizeof(WCHAR);
  1158. Trace(g_tagGroup, _T("(%s) (%s (%x)) - Updating state"), Pdoc()->StrNode(), StrName(), this);
  1159. // Get the current state of the group.
  1160. if (Hgroup() == NULL)
  1161. m_cgs = ClusterGroupStateUnknown;
  1162. else
  1163. {
  1164. CWaitCursor wc;
  1165. m_cgs = GetClusterGroupState(Hgroup(), rgwszOwner, &cchOwner);
  1166. pwszOwner = rgwszOwner;
  1167. } // else: group is available
  1168. // Save the current state image index.
  1169. switch (Cgs())
  1170. {
  1171. case ClusterGroupStateUnknown:
  1172. m_iimgState = papp->Iimg(IMGLI_GROUP_UNKNOWN);
  1173. pwszOwner = NULL;
  1174. break;
  1175. case ClusterGroupOnline:
  1176. m_iimgState = papp->Iimg(IMGLI_GROUP);
  1177. break;
  1178. case ClusterGroupPartialOnline:
  1179. m_iimgState = papp->Iimg(IMGLI_GROUP_PARTIALLY_ONLINE);
  1180. break;
  1181. case ClusterGroupPending:
  1182. m_iimgState = papp->Iimg(IMGLI_GROUP_PENDING);
  1183. break;
  1184. case ClusterGroupOffline:
  1185. m_iimgState = papp->Iimg(IMGLI_GROUP_OFFLINE);
  1186. break;
  1187. case ClusterGroupFailed:
  1188. m_iimgState = papp->Iimg(IMGLI_GROUP_FAILED);
  1189. break;
  1190. default:
  1191. Trace(g_tagGroup, _T("(%s) (%s (%x)) - UpdateState: Unknown state '%d' for group '%s'"), Pdoc()->StrNode(), StrName(), this, Cgs(), StrName());
  1192. m_iimgState = (UINT) -1;
  1193. break;
  1194. } // switch: Cgs()
  1195. SetOwnerState(pwszOwner);
  1196. // Update the state of all resources owned by this group.
  1197. if (m_plpcires != NULL)
  1198. {
  1199. POSITION posRes;
  1200. CResource * pciRes;
  1201. posRes = Lpcires().GetHeadPosition();
  1202. while (posRes != NULL)
  1203. {
  1204. pciRes = (CResource *) Lpcires().GetNext(posRes);
  1205. ASSERT_VALID(pciRes);
  1206. pciRes->UpdateState();
  1207. } // while: more items in the list
  1208. } // if: resource list exists
  1209. // Call the base class method.
  1210. CClusterItem::UpdateState();
  1211. } //*** CGroup::UpdateState()
  1212. /////////////////////////////////////////////////////////////////////////////
  1213. //++
  1214. //
  1215. // CGroup::SetOwnerState
  1216. //
  1217. // Routine Description:
  1218. // Set a new owner for this group.
  1219. //
  1220. // Arguments:
  1221. // pszNewOwner [IN] Name of the new owner.
  1222. //
  1223. // Return Value:
  1224. // None.
  1225. //
  1226. //--
  1227. /////////////////////////////////////////////////////////////////////////////
  1228. void CGroup::SetOwnerState(IN LPCTSTR pszNewOwner)
  1229. {
  1230. CClusterNode * pciOldOwner = PciOwner();
  1231. CClusterNode * pciNewOwner;
  1232. Trace(g_tagGroup, _T("(%s) (%s (%x)) - Setting owner to '%s'"), Pdoc()->StrNode(), StrName(), this, pszNewOwner);
  1233. if (pszNewOwner == NULL)
  1234. pciNewOwner = NULL;
  1235. else
  1236. pciNewOwner = Pdoc()->LpciNodes().PciNodeFromName(pszNewOwner);
  1237. if (pciNewOwner != pciOldOwner)
  1238. {
  1239. #ifdef _DEBUG
  1240. if (g_tagGroup.BAny())
  1241. {
  1242. CString strMsg;
  1243. CString strMsg2;
  1244. strMsg.Format(_T("(%s) (%s (%x)) - Changing owner from "), Pdoc()->StrNode(), StrName(), this);
  1245. if (pciOldOwner == NULL)
  1246. strMsg += _T("nothing ");
  1247. else
  1248. {
  1249. strMsg2.Format(_T("'%s' "), pciOldOwner->StrName());
  1250. strMsg += strMsg2;
  1251. } // else: previous owner
  1252. if (pciNewOwner == NULL)
  1253. strMsg += _T("to nothing");
  1254. else
  1255. {
  1256. strMsg2.Format(_T("to '%s'"), pciNewOwner->StrName());
  1257. strMsg += strMsg2;
  1258. } // else: new owner
  1259. Trace(g_tagGroup, strMsg);
  1260. } // if: trace tag turned on
  1261. #endif
  1262. m_strOwner = pszNewOwner;
  1263. m_pciOwner = pciNewOwner;
  1264. // Update reference counts.
  1265. if (pciOldOwner != NULL)
  1266. pciOldOwner->Release();
  1267. if (pciNewOwner != NULL)
  1268. pciNewOwner->AddRef();
  1269. if (BDocObj())
  1270. {
  1271. if (pciOldOwner != NULL)
  1272. pciOldOwner->RemoveActiveGroup(this);
  1273. if (pciNewOwner != NULL)
  1274. pciNewOwner->AddActiveGroup(this);
  1275. } // if: this is a document object
  1276. } // if: owner changed
  1277. else if ((pszNewOwner != NULL) && (StrOwner() != pszNewOwner))
  1278. m_strOwner = pszNewOwner;
  1279. } //*** CGroup::SetOwnerState()
  1280. /////////////////////////////////////////////////////////////////////////////
  1281. //++
  1282. //
  1283. // CGroup::OnFinalRelease
  1284. //
  1285. // Routine Description:
  1286. // Called when the last OLE reference to or from the object is released.
  1287. //
  1288. // Arguments:
  1289. // None.
  1290. //
  1291. // Return Value:
  1292. // None.
  1293. //
  1294. //--
  1295. /////////////////////////////////////////////////////////////////////////////
  1296. void CGroup::OnFinalRelease(void)
  1297. {
  1298. // When the last reference for an automation object is released
  1299. // OnFinalRelease is called. The base class will automatically
  1300. // deletes the object. Add additional cleanup required for your
  1301. // object before calling the base class.
  1302. CClusterItem::OnFinalRelease();
  1303. } //*** CGroup::OnFinalRelease()
  1304. /////////////////////////////////////////////////////////////////////////////
  1305. //++
  1306. //
  1307. // CGroup::BGetColumnData
  1308. //
  1309. // Routine Description:
  1310. // Returns a string with the column data.
  1311. //
  1312. // Arguments:
  1313. // colid [IN] Column ID.
  1314. // rstrText [OUT] String in which to return the text for the column.
  1315. //
  1316. // Return Value:
  1317. // TRUE Column data returned.
  1318. // FALSE Column ID not recognized.
  1319. //
  1320. //--
  1321. /////////////////////////////////////////////////////////////////////////////
  1322. BOOL CGroup::BGetColumnData(IN COLID colid, OUT CString & rstrText)
  1323. {
  1324. BOOL bSuccess;
  1325. switch (colid)
  1326. {
  1327. case IDS_COLTEXT_OWNER:
  1328. rstrText = StrOwner();
  1329. bSuccess = TRUE;
  1330. break;
  1331. case IDS_COLTEXT_STATE:
  1332. GetStateName(rstrText);
  1333. bSuccess = TRUE;
  1334. break;
  1335. default:
  1336. bSuccess = CClusterItem::BGetColumnData(colid, rstrText);
  1337. break;
  1338. } // switch: colid
  1339. return bSuccess;
  1340. } //*** CGroup::BGetColumnData()
  1341. /////////////////////////////////////////////////////////////////////////////
  1342. //++
  1343. //
  1344. // CGroup::GetTreeName
  1345. //
  1346. // Routine Description:
  1347. // Returns a string to be used in a tree control.
  1348. //
  1349. // Arguments:
  1350. // rstrName [OUT] String in which to return the name.
  1351. //
  1352. // Return Value:
  1353. // None.
  1354. //
  1355. //--
  1356. /////////////////////////////////////////////////////////////////////////////
  1357. #ifdef _DISPLAY_STATE_TEXT_IN_TREE
  1358. void CGroup::GetTreeName(OUT CString & rstrName) const
  1359. {
  1360. CString strState;
  1361. GetStateName(strState);
  1362. rstrName.Format(_T("%s (%s)"), StrName(), strState);
  1363. } //*** CGroup::GetTreeName()
  1364. #endif
  1365. /////////////////////////////////////////////////////////////////////////////
  1366. //++
  1367. //
  1368. // CGroup::GetStateName
  1369. //
  1370. // Routine Description:
  1371. // Returns a string with the name of the current state.
  1372. //
  1373. // Arguments:
  1374. // rstrState [OUT] String in which to return the name of the current state.
  1375. //
  1376. // Return Value:
  1377. // None.
  1378. //
  1379. //--
  1380. /////////////////////////////////////////////////////////////////////////////
  1381. void CGroup::GetStateName(OUT CString & rstrState) const
  1382. {
  1383. switch (Cgs())
  1384. {
  1385. case ClusterGroupStateUnknown:
  1386. rstrState.LoadString(IDS_UNKNOWN);
  1387. break;
  1388. case ClusterGroupOnline:
  1389. rstrState.LoadString(IDS_ONLINE);
  1390. break;
  1391. case ClusterGroupPartialOnline:
  1392. rstrState.LoadString(IDS_PARTIAL_ONLINE);
  1393. break;
  1394. case ClusterGroupPending:
  1395. rstrState.LoadString(IDS_PENDING);
  1396. break;
  1397. case ClusterGroupOffline:
  1398. rstrState.LoadString(IDS_OFFLINE);
  1399. break;
  1400. case ClusterGroupFailed:
  1401. rstrState.LoadString(IDS_FAILED);
  1402. break;
  1403. default:
  1404. rstrState.Empty();
  1405. break;
  1406. } // switch: Cgs()
  1407. } //*** CGroup::GetStateName()
  1408. /////////////////////////////////////////////////////////////////////////////
  1409. //++
  1410. //
  1411. // CGroup::BCanBeEdited
  1412. //
  1413. // Routine Description:
  1414. // Determines if the resource can be renamed.
  1415. //
  1416. // Arguments:
  1417. // None.
  1418. //
  1419. // Return Value:
  1420. // TRUE Resource can be renamed.
  1421. // FALSE Resource cannot be renamed.
  1422. //
  1423. //--
  1424. /////////////////////////////////////////////////////////////////////////////
  1425. BOOL CGroup::BCanBeEdited(void) const
  1426. {
  1427. BOOL bCanBeEdited;
  1428. if ( (Cgs() == ClusterGroupStateUnknown)
  1429. || BReadOnly())
  1430. bCanBeEdited = FALSE;
  1431. else
  1432. bCanBeEdited = TRUE;
  1433. return bCanBeEdited;
  1434. } //*** CGroup::BCanBeEdited()
  1435. /////////////////////////////////////////////////////////////////////////////
  1436. //++
  1437. //
  1438. // CGroup::Rename
  1439. //
  1440. // Routine Description:
  1441. // Rename the group.
  1442. //
  1443. // Arguments:
  1444. // pszName [IN] New name to give to the group.
  1445. //
  1446. // Return Value:
  1447. // None.
  1448. //
  1449. // Exceptions Thrown:
  1450. // CNTException Errors returned from SetClusterGroupName().
  1451. //
  1452. //--
  1453. /////////////////////////////////////////////////////////////////////////////
  1454. void CGroup::Rename(IN LPCTSTR pszName)
  1455. {
  1456. DWORD dwStatus;
  1457. CWaitCursor wc;
  1458. ASSERT(Hgroup() != NULL);
  1459. if (StrName() != pszName)
  1460. {
  1461. dwStatus = SetClusterGroupName(Hgroup(), pszName);
  1462. if (dwStatus != ERROR_SUCCESS)
  1463. ThrowStaticException(dwStatus, IDS_RENAME_GROUP_ERROR, StrName(), pszName);
  1464. m_strName = pszName;
  1465. } // if: the name changed
  1466. } //*** CGroup::Rename()
  1467. /////////////////////////////////////////////////////////////////////////////
  1468. //++
  1469. //
  1470. // CGroup::Move
  1471. //
  1472. // Routine Description:
  1473. // Move the group to another node.
  1474. //
  1475. // Arguments:
  1476. // pciNode [IN] Node to move the group to.
  1477. //
  1478. // Return Value:
  1479. // None.
  1480. //
  1481. //--
  1482. /////////////////////////////////////////////////////////////////////////////
  1483. void CGroup::Move(IN const CClusterNode * pciNode)
  1484. {
  1485. DWORD dwStatus;
  1486. CWaitCursor wc;
  1487. ASSERT_VALID(pciNode);
  1488. // Do this in case this object is deleted while we are operating on it.
  1489. AddRef();
  1490. if (pciNode->StrName() == StrOwner())
  1491. {
  1492. CString strMsg;
  1493. strMsg.FormatMessage(IDS_CANT_MOVE_GROUP_TO_SAME_NODE, StrName(), StrOwner());
  1494. AfxMessageBox(strMsg, MB_OK | MB_ICONSTOP);
  1495. } // if: trying to move to the same node
  1496. else
  1497. {
  1498. // Move the group.
  1499. dwStatus = MoveClusterGroup(Hgroup(), pciNode->Hnode());
  1500. if ((dwStatus != ERROR_SUCCESS)
  1501. && (dwStatus != ERROR_IO_PENDING))
  1502. {
  1503. CNTException nte(dwStatus, IDS_MOVE_GROUP_ERROR, StrName(), NULL, FALSE /*bAutoDelete*/);
  1504. nte.ReportError();
  1505. } // if: error moving the group
  1506. } // else: trying to move to a different node
  1507. Release();
  1508. } //*** CGroup::Move()
  1509. /////////////////////////////////////////////////////////////////////////////
  1510. //++
  1511. //
  1512. // CGroup::BCanBeDropTarget
  1513. //
  1514. // Routine Description:
  1515. // Determine if the specified item can be dropped on this item.
  1516. //
  1517. // Arguments:
  1518. // pci [IN OUT] Item to be dropped on this item.
  1519. //
  1520. // Return Value:
  1521. // TRUE Can be drop target.
  1522. // FALSE Can NOT be drop target.
  1523. //
  1524. //--
  1525. /////////////////////////////////////////////////////////////////////////////
  1526. BOOL CGroup::BCanBeDropTarget(IN const CClusterItem * pci) const
  1527. {
  1528. BOOL bCan;
  1529. // This group can be a drop target only if the specified item
  1530. // is a resource and it is not already a member of this group.
  1531. if (pci->IdsType() == IDS_ITEMTYPE_RESOURCE)
  1532. {
  1533. CResource * pciRes = (CResource *) pci;
  1534. ASSERT_KINDOF(CResource, pciRes);
  1535. if (pciRes->StrGroup() != StrName())
  1536. bCan = TRUE;
  1537. else
  1538. bCan = FALSE;
  1539. Trace(g_tagGroupDrag, _T("(%s) BCanBeDropTarget() - Dragging resource '%s' (%x) (group = '%s' (%x)) over group '%s' (%x)"), Pdoc()->StrNode(), pciRes->StrName(), pciRes, pciRes->StrGroup(), pciRes->PciGroup(), StrName(), this);
  1540. } // if: resource item
  1541. else
  1542. bCan = FALSE;
  1543. return bCan;
  1544. } //*** CGroup::BCanBeDropTarget()
  1545. /////////////////////////////////////////////////////////////////////////////
  1546. //++
  1547. //
  1548. // CGroup::DropItem
  1549. //
  1550. // Routine Description:
  1551. // Process an item being dropped on this item.
  1552. //
  1553. // Arguments:
  1554. // pci [IN OUT] Item dropped on this item.
  1555. //
  1556. // Return Value:
  1557. // None.
  1558. //
  1559. //--
  1560. /////////////////////////////////////////////////////////////////////////////
  1561. void CGroup::DropItem(IN OUT CClusterItem * pci)
  1562. {
  1563. if (BCanBeDropTarget(pci))
  1564. {
  1565. POSITION pos;
  1566. UINT imenu;
  1567. UINT idMenu;
  1568. CGroup * pciGroup;
  1569. CResource * pciRes;
  1570. // Calculate the ID of this group.
  1571. pos = Pdoc()->LpciGroups().GetHeadPosition();
  1572. for (imenu = 0, idMenu = ID_FILE_MOVE_RESOURCE_1
  1573. ; pos != NULL
  1574. ; idMenu++)
  1575. {
  1576. pciGroup = (CGroup *) Pdoc()->LpciGroups().GetNext(pos);
  1577. ASSERT_VALID(pciGroup);
  1578. if (pciGroup == this)
  1579. break;
  1580. } // for: each group
  1581. ASSERT(imenu < (UINT) Pdoc()->LpciGroups().GetCount());
  1582. // Change the group of the specified resource.
  1583. pciRes = (CResource *) pci;
  1584. ASSERT_KINDOF(CResource, pci);
  1585. ASSERT_VALID(pciRes);
  1586. pciRes->OnCmdMoveResource(idMenu);
  1587. } // if: item can be dropped on this item
  1588. else if (pci->IdsType() == IDS_ITEMTYPE_RESOURCE)
  1589. {
  1590. CString strMsg;
  1591. #ifdef _DEBUG
  1592. CResource * pciRes = (CResource *) pci;
  1593. ASSERT_KINDOF(CResource, pci);
  1594. ASSERT_VALID(pciRes);
  1595. ASSERT(pciRes->StrGroup() == StrName());
  1596. #endif // _DEBUG
  1597. strMsg.FormatMessage(
  1598. IDS_CANT_MOVE_RES_TO_GROUP,
  1599. pci->StrName(),
  1600. StrName()
  1601. );
  1602. AfxMessageBox(strMsg, MB_OK | MB_ICONSTOP);
  1603. } // else if: dropped item is a resource
  1604. else
  1605. CClusterItem::DropItem(pci);
  1606. } //*** CGroup::DropItem()
  1607. /////////////////////////////////////////////////////////////////////////////
  1608. //++
  1609. //
  1610. // CGroup::OnCmdMsg
  1611. //
  1612. // Routine Description:
  1613. // Processes command messages.
  1614. //
  1615. // Arguments:
  1616. // nID [IN] Command ID.
  1617. // nCode [IN] Notification code.
  1618. // pExtra [IN OUT] Used according to the value of nCode.
  1619. // pHandlerInfo [OUT] ???
  1620. //
  1621. // Return Value:
  1622. // TRUE Message has been handled.
  1623. // FALSE Message has NOT been handled.
  1624. //
  1625. //--
  1626. /////////////////////////////////////////////////////////////////////////////
  1627. BOOL CGroup::OnCmdMsg(
  1628. UINT nID,
  1629. int nCode,
  1630. void * pExtra,
  1631. AFX_CMDHANDLERINFO * pHandlerInfo
  1632. )
  1633. {
  1634. BOOL bHandled = FALSE;
  1635. // If this is a MOVE_GROUP command, process it here.
  1636. if ((ID_FILE_MOVE_GROUP_1 <= nID) && (nID <= ID_FILE_MOVE_GROUP_16))
  1637. {
  1638. Trace(g_tagGroup, _T("(%s) OnCmdMsg() %s (%x) - ID = %d, code = %d"), Pdoc()->StrNode(), StrName(), this, nID, nCode);
  1639. if (nCode == 0)
  1640. {
  1641. OnCmdMoveGroup(nID);
  1642. bHandled = TRUE;
  1643. } // if: code = 0
  1644. } // if: move resource
  1645. if (!bHandled)
  1646. bHandled = CClusterItem::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
  1647. return bHandled;
  1648. } //*** CGroup::OnCmdMsg()
  1649. /////////////////////////////////////////////////////////////////////////////
  1650. //++
  1651. //
  1652. // CGroup::OnUpdateBringOnline
  1653. //
  1654. // Routine Description:
  1655. // Determines whether menu items corresponding to ID_FILE_BRING_ONLINE
  1656. // should be enabled or not.
  1657. //
  1658. // Arguments:
  1659. // pCmdUI [IN OUT] Command routing object.
  1660. //
  1661. // Return Value:
  1662. // None.
  1663. //
  1664. //--
  1665. /////////////////////////////////////////////////////////////////////////////
  1666. void CGroup::OnUpdateBringOnline(CCmdUI * pCmdUI)
  1667. {
  1668. if ( (Cgs() != ClusterGroupOnline)
  1669. && (Cgs() != ClusterGroupPending)
  1670. && (Cgs() != ClusterGroupStateUnknown))
  1671. pCmdUI->Enable(TRUE);
  1672. else
  1673. pCmdUI->Enable(FALSE);
  1674. } //*** CGroup::OnUpdateBringOnline()
  1675. /////////////////////////////////////////////////////////////////////////////
  1676. //++
  1677. //
  1678. // CGroup::OnUpdateTakeOffline
  1679. //
  1680. // Routine Description:
  1681. // Determines whether menu items corresponding to ID_FILE_TAKE_OFFLINE
  1682. // should be enabled or not.
  1683. //
  1684. // Arguments:
  1685. // pCmdUI [IN OUT] Command routing object.
  1686. //
  1687. // Return Value:
  1688. // None.
  1689. //
  1690. //--
  1691. /////////////////////////////////////////////////////////////////////////////
  1692. void CGroup::OnUpdateTakeOffline(CCmdUI * pCmdUI)
  1693. {
  1694. if ( (Cgs() == ClusterGroupOnline)
  1695. || (Cgs() == ClusterGroupPartialOnline))
  1696. pCmdUI->Enable(TRUE);
  1697. else
  1698. pCmdUI->Enable(FALSE);
  1699. } //*** CGroup::OnUpdateTakeOffline()
  1700. /////////////////////////////////////////////////////////////////////////////
  1701. //++
  1702. //
  1703. // CGroup::OnUpdateMoveGroup
  1704. //
  1705. // Routine Description:
  1706. // Determines whether menu items corresponding to ID_FILE_MOVE_GROUP
  1707. // should be enabled or not.
  1708. //
  1709. // Arguments:
  1710. // pCmdUI [IN OUT] Command routing object.
  1711. //
  1712. // Return Value:
  1713. // None.
  1714. //
  1715. //--
  1716. /////////////////////////////////////////////////////////////////////////////
  1717. void CGroup::OnUpdateMoveGroup(CCmdUI * pCmdUI)
  1718. {
  1719. if ( (pCmdUI->m_pSubMenu == NULL)
  1720. && (pCmdUI->m_pParentMenu == NULL))
  1721. {
  1722. if ( (Cgs() == ClusterGroupStateUnknown)
  1723. || (Cgs() == ClusterGroupPending)
  1724. || (Pdoc()->LpciNodes().GetCount() < 2))
  1725. pCmdUI->Enable(FALSE);
  1726. else
  1727. pCmdUI->Enable(TRUE);
  1728. } // if: nested menu is being displayed
  1729. else
  1730. {
  1731. BOOL bEnabled;
  1732. CString strMenuName;
  1733. if (pCmdUI->m_pMenu != NULL)
  1734. {
  1735. pCmdUI->m_pMenu->GetMenuString(0, strMenuName, MF_BYPOSITION);
  1736. Trace(g_tagGroupMenu, _T("(%s) pMenu(0) = '%s'"), Pdoc()->StrNode(), strMenuName);
  1737. pCmdUI->m_pMenu->GetMenuString(pCmdUI->m_nIndex, strMenuName, MF_BYPOSITION);
  1738. Trace(g_tagGroupMenu, _T("(%s) pMenu(%d) = '%s'"), Pdoc()->StrNode(), pCmdUI->m_nIndex, strMenuName);
  1739. } // if: main menu
  1740. if (pCmdUI->m_pSubMenu != NULL)
  1741. {
  1742. pCmdUI->m_pSubMenu->GetMenuString(0, strMenuName, MF_BYPOSITION);
  1743. Trace(g_tagGroupMenu, _T("(%s) pSubMenu(0) = '%s'"), Pdoc()->StrNode(), strMenuName);
  1744. pCmdUI->m_pSubMenu->GetMenuString(pCmdUI->m_nIndex, strMenuName, MF_BYPOSITION);
  1745. Trace(g_tagGroupMenu, _T("(%s) pSubMenu(%d) = '%s'"), Pdoc()->StrNode(), pCmdUI->m_nIndex, strMenuName);
  1746. } // if: submenu
  1747. // Handle the menu item based on whether it is on the main menu
  1748. // or on the submenu.
  1749. if (pCmdUI->m_pSubMenu == NULL)
  1750. {
  1751. bEnabled = OnUpdateMoveGroupItem(pCmdUI);
  1752. pCmdUI->Enable(bEnabled);
  1753. } // if: on the main menu
  1754. else
  1755. {
  1756. bEnabled = OnUpdateMoveGroupSubMenu(pCmdUI);
  1757. } // else: on the submenu
  1758. // Enable or disable the Move menu.
  1759. pCmdUI->m_pMenu->EnableMenuItem(
  1760. pCmdUI->m_nIndex,
  1761. MF_BYPOSITION
  1762. | (bEnabled ? MF_ENABLED : MF_GRAYED)
  1763. );
  1764. } // else: top-level menu is being displayed
  1765. } //*** CGroup::OnUpdateMoveGroup()
  1766. /////////////////////////////////////////////////////////////////////////////
  1767. //++
  1768. //
  1769. // CGroup::OnUpdateMoveGroupItem
  1770. //
  1771. // Routine Description:
  1772. // Determines whether menu items corresponding to ID_FILE_MOVE_GROUP
  1773. // that are not popups should be enabled or not.
  1774. //
  1775. // Arguments:
  1776. // pCmdUI [IN OUT] Command routing object.
  1777. //
  1778. // Return Value:
  1779. // TRUE Item should be enabled.
  1780. // FALSE Item should be disabled.
  1781. //
  1782. //--
  1783. /////////////////////////////////////////////////////////////////////////////
  1784. BOOL CGroup::OnUpdateMoveGroupItem(CCmdUI * pCmdUI)
  1785. {
  1786. BOOL bEnabled;
  1787. // If there are more than two nodes, make the menu item a submenu.
  1788. if ( (Cgs() == ClusterGroupStateUnknown)
  1789. || (Cgs() == ClusterGroupPending)
  1790. || (Pdoc()->LpciNodes().GetCount() < 2))
  1791. bEnabled = FALSE;
  1792. else if (Pdoc()->LpciNodes().GetCount() == 2)
  1793. bEnabled = TRUE;
  1794. else
  1795. {
  1796. UINT idMenu;
  1797. POSITION pos;
  1798. CClusterNode * pciNode;
  1799. CString strMenuName;
  1800. CMenu menuMove;
  1801. CMenu * pmenu = pCmdUI->m_pMenu;
  1802. // Load the Move submenu.
  1803. VERIFY(menuMove.LoadMenu(IDM_MOVE_GROUP) != 0);
  1804. ASSERT(menuMove.GetMenuItemCount() == 2);
  1805. // Add all the nodes in the cluster to the end of the menu.
  1806. pos = Pdoc()->LpciNodes().GetHeadPosition();
  1807. for (idMenu = ID_FILE_MOVE_GROUP_1
  1808. ; pos != NULL
  1809. ; idMenu++)
  1810. {
  1811. pciNode = (CClusterNode *) Pdoc()->LpciNodes().GetNext(pos);
  1812. ASSERT_VALID(pciNode);
  1813. VERIFY(menuMove.AppendMenu(
  1814. MF_BYPOSITION | MF_STRING,
  1815. idMenu,
  1816. pciNode->StrName()
  1817. ));
  1818. } // for: each node
  1819. // Get the name of the menu.
  1820. pmenu->GetMenuString(pCmdUI->m_nIndex, strMenuName, MF_BYPOSITION);
  1821. Trace(g_tagGroupMenu, _T("(%s) Making item '%s' a submenu"), Pdoc()->StrNode(), strMenuName);
  1822. // Modify this menu item.
  1823. VERIFY(pmenu->ModifyMenu(
  1824. pCmdUI->m_nIndex,
  1825. MF_BYPOSITION | MF_STRING | MF_POPUP,
  1826. (UINT_PTR) menuMove.m_hMenu,
  1827. strMenuName
  1828. ));
  1829. // Detach the menu from the class since we don't own it anymore.
  1830. menuMove.Detach();
  1831. bEnabled = TRUE;
  1832. } // else: more than two nodes in the cluster
  1833. return bEnabled;
  1834. } //*** CGroup::OnUpdateMoveGroupItem()
  1835. /////////////////////////////////////////////////////////////////////////////
  1836. //++
  1837. //
  1838. // CGroup::OnUpdateMoveGroupSubMenu
  1839. //
  1840. // Routine Description:
  1841. // Determines whether menu items corresponding to ID_FILE_MOVE_GROUP
  1842. // that are on popups should be enabled or not.
  1843. //
  1844. // Arguments:
  1845. // pCmdUI [IN OUT] Command routing object.
  1846. //
  1847. // Return Value:
  1848. // TRUE Item should be enabled.
  1849. // FALSE Item should be disabled.
  1850. //
  1851. //--
  1852. /////////////////////////////////////////////////////////////////////////////
  1853. BOOL CGroup::OnUpdateMoveGroupSubMenu(CCmdUI * pCmdUI)
  1854. {
  1855. BOOL bEnabled;
  1856. // If there are not more than two nodes, make the menu item a normal item.
  1857. if (Pdoc()->LpciNodes().GetCount() > 2)
  1858. bEnabled = TRUE;
  1859. else
  1860. {
  1861. CString strMenuName;
  1862. CMenu * pmenu = pCmdUI->m_pMenu;
  1863. // Get the name of the menu.
  1864. pmenu->GetMenuString(pCmdUI->m_nIndex, strMenuName, MF_BYPOSITION);
  1865. Trace(g_tagGroupMenu, _T("(%s) Making item '%s' a non-submenu"), Pdoc()->StrNode(), strMenuName);
  1866. // Modify this menu item.
  1867. // We should be able to just modify the menu, but for some reason
  1868. // this doesn't work. So, instead, we will remove the previous item
  1869. // and add a new item.
  1870. #ifdef NEVER
  1871. VERIFY(pmenu->ModifyMenu(
  1872. pCmdUI->m_nIndex,
  1873. MF_BYPOSITION | MF_STRING,
  1874. ID_FILE_MOVE_GROUP,
  1875. strMenuName
  1876. ));
  1877. #else
  1878. VERIFY(pmenu->DeleteMenu(pCmdUI->m_nIndex, MF_BYPOSITION));
  1879. VERIFY(pmenu->InsertMenu(
  1880. pCmdUI->m_nIndex,
  1881. MF_BYPOSITION | MF_STRING,
  1882. ID_FILE_MOVE_GROUP,
  1883. strMenuName
  1884. ));
  1885. #endif
  1886. if ( (Cgs() == ClusterGroupStateUnknown)
  1887. || (Cgs() == ClusterGroupPending)
  1888. || (Pdoc()->LpciNodes().GetCount() < 2))
  1889. bEnabled = FALSE;
  1890. else
  1891. bEnabled = TRUE;
  1892. AfxGetMainWnd()->DrawMenuBar();
  1893. } // else: not more than two nodes in the cluster
  1894. return bEnabled;
  1895. } //*** CGroup::OnUpdateMoveGroupSubMenu()
  1896. /////////////////////////////////////////////////////////////////////////////
  1897. //++
  1898. //
  1899. // CGroup::OnUpdateMoveGroupRest
  1900. //
  1901. // Routine Description:
  1902. // Determines whether menu items corresponding to ID_FILE_MOVE_GROUP_1
  1903. // through ID_FILE_MOVE_GROUP_16 should be enabled or not.
  1904. //
  1905. // Arguments:
  1906. // pCmdUI [IN OUT] Command routing object.
  1907. //
  1908. // Return Value:
  1909. // None.
  1910. //
  1911. //--
  1912. /////////////////////////////////////////////////////////////////////////////
  1913. void CGroup::OnUpdateMoveGroupRest(CCmdUI * pCmdUI)
  1914. {
  1915. if ( (Cgs() == ClusterGroupStateUnknown)
  1916. || (Cgs() == ClusterGroupPending))
  1917. pCmdUI->Enable(FALSE);
  1918. else
  1919. pCmdUI->Enable(TRUE);
  1920. } //*** CGroup::OnUpdateMoveGroupRest()
  1921. /////////////////////////////////////////////////////////////////////////////
  1922. //++
  1923. //
  1924. // CGroup::OnUpdateDelete
  1925. //
  1926. // Routine Description:
  1927. // Determines whether menu items corresponding to ID_FILE_DELETE
  1928. // should be enabled or not.
  1929. //
  1930. // Arguments:
  1931. // pCmdUI [IN OUT] Command routing object.
  1932. //
  1933. // Return Value:
  1934. // None.
  1935. //
  1936. //--
  1937. /////////////////////////////////////////////////////////////////////////////
  1938. void CGroup::OnUpdateDelete(CCmdUI * pCmdUI)
  1939. {
  1940. if ( (Cgs() != ClusterGroupStateUnknown)
  1941. && (Cgs() != ClusterGroupPending)
  1942. && Lpcires().IsEmpty())
  1943. pCmdUI->Enable(TRUE);
  1944. else
  1945. pCmdUI->Enable(FALSE);
  1946. } //*** CGroup::OnUpdateDelete()
  1947. /////////////////////////////////////////////////////////////////////////////
  1948. //++
  1949. //
  1950. // CGroup::OnCmdBringOnline
  1951. //
  1952. // Routine Description:
  1953. // Processes the ID_FILE_BRING_ONLINE menu command.
  1954. //
  1955. // Arguments:
  1956. // None.
  1957. //
  1958. // Return Value:
  1959. // None.
  1960. //
  1961. //--
  1962. /////////////////////////////////////////////////////////////////////////////
  1963. void CGroup::OnCmdBringOnline(void)
  1964. {
  1965. DWORD dwStatus;
  1966. CWaitCursor wc;
  1967. ASSERT(Hgroup() != NULL);
  1968. // Do this in case this object is deleted while we are operating on it.
  1969. AddRef();
  1970. dwStatus = OnlineClusterGroup(Hgroup(), NULL);
  1971. if ((dwStatus != ERROR_SUCCESS)
  1972. && (dwStatus != ERROR_IO_PENDING))
  1973. {
  1974. CNTException nte(dwStatus, IDS_BRING_GROUP_ONLINE_ERROR, StrName(), NULL, FALSE /*bAutoDelete*/);
  1975. nte.ReportError();
  1976. } // if: error bringing the group online
  1977. UpdateState();
  1978. Release();
  1979. } //*** CGroup::OnCmdBringOnline()
  1980. /////////////////////////////////////////////////////////////////////////////
  1981. //++
  1982. //
  1983. // CGroup::OnCmdTakeOffline
  1984. //
  1985. // Routine Description:
  1986. // Processes the ID_FILE_TAKE_OFFLINE menu command.
  1987. //
  1988. // Arguments:
  1989. // None.
  1990. //
  1991. // Return Value:
  1992. // None.
  1993. //
  1994. //--
  1995. /////////////////////////////////////////////////////////////////////////////
  1996. void CGroup::OnCmdTakeOffline(void)
  1997. {
  1998. DWORD dwStatus;
  1999. CWaitCursor wc;
  2000. ASSERT(Hgroup() != NULL);
  2001. // Do this in case this object is deleted while we are operating on it.
  2002. AddRef();
  2003. dwStatus = OfflineClusterGroup(Hgroup());
  2004. if ((dwStatus != ERROR_SUCCESS)
  2005. && (dwStatus != ERROR_IO_PENDING))
  2006. {
  2007. CNTException nte(dwStatus, IDS_TAKE_GROUP_OFFLINE_ERROR, StrName(), NULL, FALSE /*bAUtoDelete*/);
  2008. nte.ReportError();
  2009. } // if: error taking the group offline
  2010. UpdateState();
  2011. Release();
  2012. } //*** CGroup::OnCmdTakeOffline()
  2013. /////////////////////////////////////////////////////////////////////////////
  2014. //++
  2015. //
  2016. // CGroup::OnCmdMoveGroup
  2017. //
  2018. // Routine Description:
  2019. // Processes the ID_FILE_MOVE_GROUP menu command.
  2020. //
  2021. // Arguments:
  2022. // None.
  2023. //
  2024. // Return Value:
  2025. // None.
  2026. //
  2027. //--
  2028. /////////////////////////////////////////////////////////////////////////////
  2029. void CGroup::OnCmdMoveGroup(void)
  2030. {
  2031. OnCmdMoveGroup((UINT) -1);
  2032. } //*** CGroup::OnCmdMoveGroup()
  2033. /////////////////////////////////////////////////////////////////////////////
  2034. //++
  2035. //
  2036. // CGroup::OnCmdMoveGroup
  2037. //
  2038. // Routine Description:
  2039. // Processes the ID_FILE_MOVE_GROUP_1 through ID_FILE_MOVE_GROUP_16 menu
  2040. // commands.
  2041. //
  2042. // Arguments:
  2043. // nID [IN] Command ID.
  2044. //
  2045. // Return Value:
  2046. // None.
  2047. //
  2048. //--
  2049. /////////////////////////////////////////////////////////////////////////////
  2050. void CGroup::OnCmdMoveGroup(IN UINT nID)
  2051. {
  2052. DWORD dwStatus;
  2053. HNODE hnode;
  2054. CClusterNode * pciNode;
  2055. CWaitCursor wc;
  2056. ASSERT(Hgroup() != NULL);
  2057. // Do this in case this object is deleted while we are operating on it.
  2058. AddRef();
  2059. do // do-while to prevent goto's
  2060. {
  2061. // Get the handle of the node to move the group to.
  2062. if ((int) nID >= 0)
  2063. {
  2064. int ipci;
  2065. ipci = (int) (nID - ID_FILE_MOVE_GROUP_1);
  2066. ASSERT(ipci < Pdoc()->LpciNodes().GetCount());
  2067. if (ipci < Pdoc()->LpciNodes().GetCount())
  2068. {
  2069. POSITION pos;
  2070. // Get the node.
  2071. pos = Pdoc()->LpciNodes().FindIndex(ipci);
  2072. ASSERT(pos);
  2073. pciNode = (CClusterNode *) Pdoc()->LpciNodes().GetAt(pos);
  2074. ASSERT_VALID(pciNode);
  2075. hnode = pciNode->Hnode();
  2076. } // if: valid node index
  2077. else
  2078. break;
  2079. } // if: non-default ID specified
  2080. else
  2081. {
  2082. hnode = NULL;
  2083. pciNode = NULL;
  2084. } // else: default ID specified
  2085. // Move the group.
  2086. dwStatus = MoveClusterGroup(Hgroup(), hnode);
  2087. if ((dwStatus != ERROR_SUCCESS)
  2088. && (dwStatus != ERROR_IO_PENDING))
  2089. {
  2090. CNTException nte(dwStatus, IDS_MOVE_GROUP_ERROR, StrName(), NULL, FALSE /*bAutoDelete*/);
  2091. nte.ReportError();
  2092. } // if: error moving the group
  2093. UpdateState();
  2094. } while (0); // do-while to prevent goto's
  2095. Release();
  2096. } //*** CGroup::OnCmdMoveGroup(nID)
  2097. /////////////////////////////////////////////////////////////////////////////
  2098. //++
  2099. //
  2100. // CGroup::OnCmdDelete
  2101. //
  2102. // Routine Description:
  2103. // Processes the ID_FILE_DELETE menu command.
  2104. //
  2105. // Arguments:
  2106. // None.
  2107. //
  2108. // Return Value:
  2109. // None.
  2110. //
  2111. //--
  2112. /////////////////////////////////////////////////////////////////////////////
  2113. void CGroup::OnCmdDelete(void)
  2114. {
  2115. ASSERT(Hgroup() != NULL);
  2116. // Do this in case this object is deleted while we are operating on it.
  2117. AddRef();
  2118. do // do-while to prevent goto's
  2119. {
  2120. // Verify that the user really wants to delete this resource.
  2121. {
  2122. CString strMsg;
  2123. strMsg.FormatMessage(IDS_VERIFY_DELETE_GROUP, StrName());
  2124. if (AfxMessageBox(strMsg, MB_YESNO | MB_ICONEXCLAMATION) == IDNO)
  2125. break;
  2126. } // Verify that the user really wants to delete this resource
  2127. try
  2128. {
  2129. DeleteGroup();
  2130. } // try
  2131. catch (CNTException * pnte)
  2132. {
  2133. if (pnte->Sc() != ERROR_GROUP_NOT_AVAILABLE)
  2134. pnte->ReportError();
  2135. pnte->Delete();
  2136. } // catch: CNTException
  2137. catch (CException * pe)
  2138. {
  2139. pe->ReportError();
  2140. pe->Delete();
  2141. } // catch: CException
  2142. } while (0); // do-while to prevent goto's
  2143. Release();
  2144. } //*** CGroup::OnCmdDelete()
  2145. /////////////////////////////////////////////////////////////////////////////
  2146. //++
  2147. //
  2148. // CGroup::OnUpdateProperties
  2149. //
  2150. // Routine Description:
  2151. // Determines whether menu items corresponding to ID_FILE_PROPERTIES
  2152. // should be enabled or not.
  2153. //
  2154. // Arguments:
  2155. // pCmdUI [IN OUT] Command routing object.
  2156. //
  2157. // Return Value:
  2158. // None.
  2159. //
  2160. //--
  2161. /////////////////////////////////////////////////////////////////////////////
  2162. void CGroup::OnUpdateProperties(CCmdUI * pCmdUI)
  2163. {
  2164. pCmdUI->Enable(TRUE);
  2165. } //*** CGroup::OnUpdateProperties()
  2166. /////////////////////////////////////////////////////////////////////////////
  2167. //++
  2168. //
  2169. // CGroup::BDisplayProperties
  2170. //
  2171. // Routine Description:
  2172. // Display properties for the object.
  2173. //
  2174. // Arguments:
  2175. // bReadOnly [IN] Don't allow edits to the object properties.
  2176. //
  2177. // Return Value:
  2178. // TRUE OK pressed.
  2179. // FALSE OK not pressed.
  2180. //
  2181. //--
  2182. /////////////////////////////////////////////////////////////////////////////
  2183. BOOL CGroup::BDisplayProperties(IN BOOL bReadOnly)
  2184. {
  2185. BOOL bChanged = FALSE;
  2186. CGroupPropSheet sht(AfxGetMainWnd());
  2187. // Do this in case this object is deleted while we are operating on it.
  2188. AddRef();
  2189. // If the object has changed, read it.
  2190. if (BChanged())
  2191. ReadItem();
  2192. // Display the property sheet.
  2193. try
  2194. {
  2195. sht.SetReadOnly(bReadOnly);
  2196. if (sht.BInit(this, IimgObjectType()))
  2197. bChanged = ((sht.DoModal() == IDOK) && !bReadOnly);
  2198. } // try
  2199. catch (CException * pe)
  2200. {
  2201. pe->Delete();
  2202. } // catch: CException
  2203. Release();
  2204. return bChanged;
  2205. } //*** CGroup::BDisplayProperties()
  2206. /////////////////////////////////////////////////////////////////////////////
  2207. //++
  2208. //
  2209. // CGroup::OnClusterNotify
  2210. //
  2211. // Routine Description:
  2212. // Handler for the WM_CAM_CLUSTER_NOTIFY message.
  2213. // Processes cluster notifications for this object.
  2214. //
  2215. // Arguments:
  2216. // pnotify [IN OUT] Object describing the notification.
  2217. //
  2218. // Return Value:
  2219. // Value returned from the application method.
  2220. //
  2221. //--
  2222. /////////////////////////////////////////////////////////////////////////////
  2223. LRESULT CGroup::OnClusterNotify(IN OUT CClusterNotify * pnotify)
  2224. {
  2225. ASSERT(pnotify != NULL);
  2226. ASSERT_VALID(this);
  2227. try
  2228. {
  2229. switch (pnotify->m_dwFilterType)
  2230. {
  2231. case CLUSTER_CHANGE_GROUP_STATE:
  2232. Trace(g_tagGroupNotify, _T("(%s) - Group '%s' (%x) state changed (%s)"), Pdoc()->StrNode(), StrName(), this, pnotify->m_strName);
  2233. UpdateState();
  2234. break;
  2235. case CLUSTER_CHANGE_GROUP_DELETED:
  2236. Trace(g_tagGroupNotify, _T("(%s) - Group '%s' (%x) deleted (%s)"), Pdoc()->StrNode(), StrName(), this, pnotify->m_strName);
  2237. if (Pdoc()->BClusterAvailable())
  2238. Delete();
  2239. break;
  2240. case CLUSTER_CHANGE_GROUP_PROPERTY:
  2241. Trace(g_tagGroupNotify, _T("(%s) - Group '%s' (%x) properties changed (%s)"), Pdoc()->StrNode(), StrName(), this, pnotify->m_strName);
  2242. if (Pdoc()->BClusterAvailable())
  2243. ReadItem();
  2244. break;
  2245. case CLUSTER_CHANGE_REGISTRY_NAME:
  2246. Trace(g_tagGroupRegNotify, _T("(%s) - Registry namespace '%s' changed (%s %s (%x))"), Pdoc()->StrNode(), pnotify->m_strName, StrType(), StrName(), this);
  2247. MarkAsChanged();
  2248. break;
  2249. case CLUSTER_CHANGE_REGISTRY_ATTRIBUTES:
  2250. Trace(g_tagGroupRegNotify, _T("(%s) - Registry attributes for '%s' changed (%s %s (%x))"), Pdoc()->StrNode(), pnotify->m_strName, StrType(), StrName());
  2251. MarkAsChanged();
  2252. break;
  2253. case CLUSTER_CHANGE_REGISTRY_VALUE:
  2254. Trace(g_tagGroupRegNotify, _T("(%s) - Registry value at '%s' changed (%s %s (%x))"), Pdoc()->StrNode(), pnotify->m_strName, StrType(), StrName(), this);
  2255. MarkAsChanged();
  2256. break;
  2257. default:
  2258. Trace(g_tagGroupNotify, _T("(%s) - Unknown group notification (%x) for '%s' (%x) (%s)"), Pdoc()->StrNode(), pnotify->m_dwFilterType, StrName(), this, pnotify->m_strName);
  2259. } // switch: dwFilterType
  2260. } // try
  2261. catch (CException * pe)
  2262. {
  2263. // Don't display anything on notification errors.
  2264. // If it's really a problem, the user will see it when
  2265. // refreshing the view.
  2266. //pe->ReportError();
  2267. pe->Delete();
  2268. } // catch: CException
  2269. delete pnotify;
  2270. return 0;
  2271. } //*** CGroup::OnClusterNotify()
  2272. //*************************************************************************//
  2273. /////////////////////////////////////////////////////////////////////////////
  2274. // Global Functions
  2275. /////////////////////////////////////////////////////////////////////////////
  2276. /////////////////////////////////////////////////////////////////////////////
  2277. //++
  2278. //
  2279. // DeleteAllItemData
  2280. //
  2281. // Routine Description:
  2282. // Deletes all item data in a CList.
  2283. //
  2284. // Arguments:
  2285. // rlp [IN OUT] List whose data is to be deleted.
  2286. //
  2287. // Return Value:
  2288. // None.
  2289. //
  2290. //--
  2291. /////////////////////////////////////////////////////////////////////////////
  2292. #ifdef NEVER
  2293. void DeleteAllItemData(IN OUT CGroupList & rlp)
  2294. {
  2295. POSITION pos;
  2296. CGroup * pci;
  2297. // Delete all the items in the list.
  2298. pos = rlp.GetHeadPosition();
  2299. while (pos != NULL)
  2300. {
  2301. pci = rlp.GetNext(pos);
  2302. ASSERT_VALID(pci);
  2303. // Trace(g_tagClusItemDelete, _T("DeleteAllItemData(rlpcigrp) - Deleting group cluster item '%s' (%x)"), pci->StrName(), pci);
  2304. pci->Delete();
  2305. } // while: more items in the list
  2306. } //*** DeleteAllItemData()
  2307. #endif