Leaked source code of windows server 2003
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.

1442 lines
44 KiB

  1. /////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1996-2002 Microsoft Corporation
  4. //
  5. // Module Name:
  6. // Cluster.cpp
  7. //
  8. // Abstract:
  9. // Implementation of the CCluster class.
  10. //
  11. // Author:
  12. // David Potter (davidp) May 13, 1996
  13. //
  14. // Revision History:
  15. //
  16. // Notes:
  17. //
  18. /////////////////////////////////////////////////////////////////////////////
  19. #include "stdafx.h"
  20. #include "CluAdmin.h"
  21. #include "ConstDef.h"
  22. #include "Cluster.h"
  23. #include "CASvc.h"
  24. #include "ClusDoc.h"
  25. #include "ClusProp.h"
  26. #include "ExcOper.h"
  27. #include "ClusItem.inl"
  28. #include "resource.h"
  29. #ifdef _DEBUG
  30. #define new DEBUG_NEW
  31. #undef THIS_FILE
  32. static char THIS_FILE[] = __FILE__;
  33. #endif
  34. /////////////////////////////////////////////////////////////////////////////
  35. // Global Variables
  36. /////////////////////////////////////////////////////////////////////////////
  37. #ifdef _DEBUG
  38. CTraceTag g_tagCluster( _T("Document"), _T("CLUSTER"), 0 );
  39. #endif
  40. /////////////////////////////////////////////////////////////////////////////
  41. // CCluster
  42. /////////////////////////////////////////////////////////////////////////////
  43. IMPLEMENT_DYNCREATE( CCluster, CClusterItem )
  44. /////////////////////////////////////////////////////////////////////////////
  45. // Message Maps
  46. /////////////////////////////////////////////////////////////////////////////
  47. BEGIN_MESSAGE_MAP( CCluster, CClusterItem )
  48. //{{AFX_MSG_MAP(CCluster)
  49. ON_UPDATE_COMMAND_UI(ID_FILE_PROPERTIES, OnUpdateProperties)
  50. //}}AFX_MSG_MAP
  51. END_MESSAGE_MAP()
  52. /////////////////////////////////////////////////////////////////////////////
  53. //++
  54. //
  55. // CCluster::CCluster
  56. //
  57. // Routine Description:
  58. // Default construtor.
  59. //
  60. // Arguments:
  61. // None.
  62. //
  63. // Return Value:
  64. // None.
  65. //
  66. //--
  67. /////////////////////////////////////////////////////////////////////////////
  68. CCluster::CCluster( void ) : CClusterItem( NULL, IDS_ITEMTYPE_CLUSTER )
  69. {
  70. m_idmPopupMenu = IDM_CLUSTER_POPUP;
  71. ZeroMemory( &m_cvi, sizeof( m_cvi ) );
  72. m_nMaxQuorumLogSize = 0;
  73. m_plpciNetworkPriority = NULL;
  74. // Set the object type and state images.
  75. m_iimgObjectType = GetClusterAdminApp()->Iimg( IMGLI_CLUSTER );
  76. m_iimgState = m_iimgObjectType;
  77. // Setup the property array.
  78. {
  79. m_rgProps[epropDefaultNetworkRole].Set(CLUSREG_NAME_CLUS_DEFAULT_NETWORK_ROLE, m_nDefaultNetworkRole, m_nDefaultNetworkRole);
  80. m_rgProps[epropDescription].Set(CLUSREG_NAME_CLUS_DESC, m_strDescription, m_strDescription);
  81. m_rgProps[epropEnableEventLogReplication].Set(CLUSREG_NAME_CLUS_EVTLOG_PROPAGATION, m_bEnableEventLogReplication, m_bEnableEventLogReplication);
  82. m_rgProps[epropQuorumArbitrationTimeMax].Set(CLUSREG_NAME_QUORUM_ARBITRATION_TIMEOUT, m_nQuorumArbitrationTimeMax, m_nQuorumArbitrationTimeMax);
  83. m_rgProps[epropQuorumArbitrationTimeMin].Set(CLUSREG_NAME_QUORUM_ARBITRATION_EQUALIZER, m_nQuorumArbitrationTimeMin, m_nQuorumArbitrationTimeMin);
  84. } // Setup the property array
  85. } //*** CCluster::CCluster()
  86. /////////////////////////////////////////////////////////////////////////////
  87. //++
  88. //
  89. // CCluster::~CCluster
  90. //
  91. // Routine Description:
  92. // Destructor.
  93. //
  94. // Arguments:
  95. // None.
  96. //
  97. // Return Value:
  98. // None.
  99. //
  100. //--
  101. /////////////////////////////////////////////////////////////////////////////
  102. CCluster::~CCluster( void )
  103. {
  104. Cleanup();
  105. } //*** CCluster::~CCluster()
  106. /////////////////////////////////////////////////////////////////////////////
  107. //++
  108. //
  109. // CCluster::Cleanup
  110. //
  111. // Routine Description:
  112. // Cleanup the item.
  113. //
  114. // Arguments:
  115. // None.
  116. //
  117. // Return Value:
  118. // None.
  119. //
  120. // Exceptions Thrown:
  121. // None.
  122. //
  123. //--
  124. /////////////////////////////////////////////////////////////////////////////
  125. void CCluster::Cleanup( void )
  126. {
  127. // Delete the NetworkPriority list.
  128. if ( m_plpciNetworkPriority != NULL )
  129. {
  130. m_plpciNetworkPriority->RemoveAll();
  131. delete m_plpciNetworkPriority;
  132. m_plpciNetworkPriority = NULL;
  133. } // if: NetworkPriority list exists
  134. m_hkey = NULL;
  135. } //*** CCluster::Cleanup()
  136. /////////////////////////////////////////////////////////////////////////////
  137. //++
  138. //
  139. // CCluster::Init
  140. //
  141. // Routine Description:
  142. // Initialize the item.
  143. //
  144. // Arguments:
  145. // pdoc [IN OUT] Document to which this item belongs.
  146. // lpszName [IN] Name of the item.
  147. // hOpenedCluster [IN] Handle to cluster to use that is already open.
  148. //
  149. // Return Value:
  150. // None.
  151. //
  152. // Exceptions Thrown:
  153. // CNTException Errors from OpenCluster(), GetClusterKey(), or
  154. // CreateClusterNotifyPort().
  155. // Any exceptions thrown by CCluster::ReadClusterInfo().
  156. //--
  157. /////////////////////////////////////////////////////////////////////////////
  158. void CCluster::Init(
  159. IN OUT CClusterDoc * pdoc,
  160. IN LPCTSTR lpszName,
  161. IN HCLUSTER hOpenedCluster // = NULL
  162. )
  163. {
  164. CWaitCursor wc;
  165. TCHAR szClusterName[ MAX_PATH ];
  166. DWORD scLastError;
  167. ASSERT( Hkey() == NULL );
  168. ASSERT( _tcslen( lpszName ) < RTL_NUMBER_OF( szClusterName ) );
  169. try
  170. {
  171. // If connecting the local machine, get its name.
  172. if ( _tcscmp( lpszName, _T(".") ) == 0 )
  173. {
  174. DWORD nSize = sizeof( szClusterName ) / sizeof( TCHAR );
  175. GetComputerName( szClusterName, &nSize );
  176. } // if: connecting to the local machine
  177. else
  178. {
  179. HRESULT hr = StringCchCopy( szClusterName, RTL_NUMBER_OF( szClusterName ), lpszName );
  180. ASSERT( SUCCEEDED( hr ) );
  181. } // else: not connecting to the local machine
  182. // Open the cluster.
  183. if ( hOpenedCluster == NULL )
  184. {
  185. pdoc->m_hcluster = HOpenCluster( lpszName );
  186. if ( pdoc->m_hcluster == NULL )
  187. {
  188. //
  189. // GPotts - 7/25/2001
  190. //
  191. // HOpenCluster could return NULL and last error = 0 if GetNodeClusterState
  192. // returned either ClusterStateNotInstalled or ClusterStateNotConfigured.
  193. //
  194. scLastError = GetLastError();
  195. ThrowStaticException( scLastError, IDS_OPEN_CLUSTER_ERROR, szClusterName );
  196. } // if: error opening the cluster
  197. } // if: no opened cluster passed in
  198. else
  199. {
  200. pdoc->m_hcluster = hOpenedCluster;
  201. } // if: cluster already opened
  202. // Get the cluster registry key.
  203. pdoc->m_hkeyCluster = GetClusterKey( pdoc->m_hcluster, MAXIMUM_ALLOWED );
  204. if ( pdoc->m_hkeyCluster == NULL )
  205. {
  206. ThrowStaticException( GetLastError(), IDS_GET_CLUSTER_KEY_ERROR, szClusterName );
  207. } // if: error opening the cluster key
  208. // Call the base class method. We can use Hcluster() after calling this.
  209. CClusterItem::Init( pdoc, szClusterName );
  210. // Get the cluster registry key.
  211. m_hkey = pdoc->m_hkeyCluster;
  212. // Register this cluster with the notification port.
  213. {
  214. HCHANGE hchange;
  215. // We want these notifications to go to the document, not us.
  216. ASSERT( Pcnk() != NULL );
  217. m_pcnk->m_cnkt = cnktDoc;
  218. m_pcnk->m_pdoc = pdoc;
  219. Trace( g_tagClusItemNotify, _T("CCluster::Init() - Registering for cluster notifications (%08.8x)"), Pcnk() );
  220. // Create the notification port.
  221. hchange = CreateClusterNotifyPort(
  222. GetClusterAdminApp()->HchangeNotifyPort(),
  223. Hcluster(),
  224. (CLUSTER_CHANGE_NODE_ADDED
  225. | CLUSTER_CHANGE_GROUP_ADDED
  226. | CLUSTER_CHANGE_RESOURCE_ADDED
  227. | CLUSTER_CHANGE_RESOURCE_TYPE_ADDED
  228. | CLUSTER_CHANGE_RESOURCE_TYPE_DELETED
  229. | CLUSTER_CHANGE_RESOURCE_TYPE_PROPERTY
  230. | CLUSTER_CHANGE_NETWORK_ADDED
  231. | CLUSTER_CHANGE_NETINTERFACE_ADDED
  232. | CLUSTER_CHANGE_QUORUM_STATE
  233. | CLUSTER_CHANGE_CLUSTER_STATE
  234. | CLUSTER_CHANGE_CLUSTER_PROPERTY
  235. | CLUSTER_CHANGE_REGISTRY_NAME
  236. | CLUSTER_CHANGE_REGISTRY_ATTRIBUTES
  237. | CLUSTER_CHANGE_REGISTRY_VALUE
  238. | CLUSTER_CHANGE_REGISTRY_SUBTREE),
  239. (DWORD_PTR) Pcnk()
  240. );
  241. if ( hchange == NULL )
  242. {
  243. ThrowStaticException( GetLastError(), IDS_CLUSTER_NOTIF_REG_ERROR, szClusterName );
  244. } // if: error creating the notify port
  245. ASSERT( hchange == GetClusterAdminApp()->HchangeNotifyPort() );
  246. } // Register this cluster with the notification port
  247. // Get the name of the cluster as recorded by the cluster.
  248. ReadClusterInfo();
  249. // Allocate lists.
  250. m_plpciNetworkPriority = new CNetworkList;
  251. if ( m_plpciNetworkPriority == NULL )
  252. {
  253. AfxThrowMemoryException();
  254. } // if: error allocating the network list
  255. // Read the initial state.
  256. UpdateState();
  257. } // try
  258. catch ( CException * )
  259. {
  260. if ( pdoc->m_hkeyCluster != NULL )
  261. {
  262. ClusterRegCloseKey( pdoc->m_hkeyCluster );
  263. pdoc->m_hkeyCluster = NULL;
  264. m_hkey = NULL;
  265. } // if: registry key opened
  266. if ( ( pdoc->m_hcluster != NULL ) && ( pdoc->m_hcluster != hOpenedCluster ) )
  267. {
  268. CloseCluster( pdoc->m_hcluster );
  269. pdoc->m_hcluster = NULL;
  270. } // if: group opened
  271. m_bReadOnly = TRUE;
  272. throw;
  273. } // catch: CException
  274. } //*** CCluster::Init()
  275. /////////////////////////////////////////////////////////////////////////////
  276. //++
  277. //
  278. // CCluster::ReadItem
  279. //
  280. // Routine Description:
  281. // Read the item parameters from the cluster database.
  282. //
  283. // Arguments:
  284. // None.
  285. //
  286. // Return Value:
  287. // None.
  288. //
  289. // Exceptions Thrown:
  290. // CNTException Errors from CClusterItem::DwReadValue() or
  291. // CClusterItem::ReadItem().
  292. // Any exceptions thrown by CCluster::ReadExtensions().
  293. //
  294. //--
  295. /////////////////////////////////////////////////////////////////////////////
  296. void CCluster::ReadItem( void )
  297. {
  298. DWORD dwStatus;
  299. DWORD dwRetStatus = ERROR_SUCCESS;
  300. CWaitCursor wc;
  301. ASSERT( Hcluster() != NULL );
  302. ASSERT( Hkey() != NULL );
  303. if ( Hcluster() != NULL )
  304. {
  305. m_rgProps[epropDefaultNetworkRole].m_value.pdw = &m_nDefaultNetworkRole;
  306. m_rgProps[epropDescription].m_value.pstr = &m_strDescription;
  307. m_rgProps[epropEnableEventLogReplication].m_value.pb = &m_bEnableEventLogReplication;
  308. m_rgProps[epropQuorumArbitrationTimeMax].m_value.pdw = &m_nQuorumArbitrationTimeMax;
  309. m_rgProps[epropQuorumArbitrationTimeMin].m_value.pdw = &m_nQuorumArbitrationTimeMin;
  310. // Call the base class method.
  311. try
  312. {
  313. CClusterItem::ReadItem();
  314. } // try
  315. catch ( CNTException * pnte )
  316. {
  317. dwRetStatus = pnte->Sc();
  318. pnte->Delete();
  319. } // catch: CNTException
  320. // Get the name of the cluster as recorded by the cluster.
  321. ReadClusterInfo();
  322. // Read and parse the common properties.
  323. {
  324. CClusPropList cpl;
  325. Trace( g_tagCluster, _T("(%x) - CCluster::ReadItem() - Getting common properties"), this );
  326. dwStatus = cpl.ScGetClusterProperties(
  327. Hcluster(),
  328. CLUSCTL_CLUSTER_GET_COMMON_PROPERTIES
  329. );
  330. if (dwStatus == ERROR_SUCCESS)
  331. {
  332. Trace( g_tagCluster, _T("(%x) - CCluster::ReadItem() - Parsing common properties"), this );
  333. dwStatus = DwParseProperties(cpl);
  334. } // if: properties read successfully
  335. if (dwStatus != ERROR_SUCCESS)
  336. {
  337. Trace( g_tagError, _T("(%x) - CCluster::ReadItem() - Error 0x%08.8x getting or parsing common properties"), this, dwStatus );
  338. // PROCNUM_OUT_OF_RANGE occurs when the server side
  339. // (clussvc.exe) doesn't support the ClusterControl( )
  340. // API. In this case, read the data using the cluster
  341. // registry APIs.
  342. if ( dwStatus == RPC_S_PROCNUM_OUT_OF_RANGE )
  343. {
  344. if ( Hkey() != NULL )
  345. {
  346. // Read the Description
  347. dwStatus = DwReadValue( CLUSREG_NAME_CLUS_DESC, m_strDescription );
  348. if ( ( dwStatus != ERROR_SUCCESS )
  349. && ( dwStatus != ERROR_FILE_NOT_FOUND ) )
  350. {
  351. dwRetStatus = dwStatus;
  352. } // if: error reading the value
  353. } // if: key is available
  354. } // if: must be talking to an NT4 node
  355. else
  356. {
  357. dwRetStatus = dwStatus;
  358. } // else: not talking to an NT4 node
  359. } // if: error reading or parsing properties
  360. } // Read and parse the common properties
  361. // Get quorum resource information.
  362. {
  363. LPWSTR pwszQResName = NULL;
  364. LPWSTR pwszQuorumPath = NULL;
  365. DWORD cchQResName;
  366. DWORD cchQuorumPath;
  367. // Get the size of the resource name.
  368. cchQResName = 0;
  369. cchQuorumPath = 0;
  370. dwStatus = GetClusterQuorumResource(
  371. Hcluster(),
  372. NULL,
  373. &cchQResName,
  374. NULL,
  375. &cchQuorumPath,
  376. &m_nMaxQuorumLogSize
  377. );
  378. if ( ( dwStatus == ERROR_SUCCESS ) || ( dwStatus == ERROR_MORE_DATA ) )
  379. {
  380. // Allocate enough space for the data.
  381. cchQResName++; // Don't forget the final null-terminator.
  382. pwszQResName = new WCHAR[ cchQResName ];
  383. cchQuorumPath++;
  384. pwszQuorumPath = new WCHAR[ cchQuorumPath ];
  385. ASSERT( pwszQResName != NULL && pwszQuorumPath != NULL );
  386. // Read the resource name.
  387. dwStatus = GetClusterQuorumResource(
  388. Hcluster(),
  389. pwszQResName,
  390. &cchQResName,
  391. pwszQuorumPath,
  392. &cchQuorumPath,
  393. &m_nMaxQuorumLogSize
  394. );
  395. } // if: got the size successfully
  396. if ( dwStatus != ERROR_SUCCESS )
  397. {
  398. dwRetStatus = dwStatus;
  399. } // if: error occurred
  400. else
  401. {
  402. m_strQuorumResource = pwszQResName;
  403. m_strQuorumPath = pwszQuorumPath;
  404. ASSERT( m_strQuorumPath[ m_strQuorumPath.GetLength() - 1 ] == _T('\\') );
  405. } // else: quorum resource info retrieved successfully
  406. delete [] pwszQResName;
  407. delete [] pwszQuorumPath;
  408. } // Get the quorum resource name
  409. } // if: cluster is available
  410. // If any errors occurred, throw an exception.
  411. if ( dwRetStatus != ERROR_SUCCESS )
  412. {
  413. ThrowStaticException( dwRetStatus, IDS_READ_CLUSTER_PROPS_ERROR, StrName() );
  414. } // if: error occurred
  415. // Read extension lists.
  416. ReadClusterExtensions();
  417. ReadNodeExtensions();
  418. ReadGroupExtensions();
  419. ReadResourceExtensions();
  420. ReadResTypeExtensions();
  421. ReadNetworkExtensions();
  422. ReadNetInterfaceExtensions();
  423. // Read the initial state.
  424. UpdateState();
  425. MarkAsChanged( FALSE );
  426. } //*** CCluster::ReadItem()
  427. /////////////////////////////////////////////////////////////////////////////
  428. //++
  429. //
  430. // CCluster::PlstrExtensions
  431. //
  432. // Routine Description:
  433. // Return the list of admin extensions.
  434. //
  435. // Arguments:
  436. // None.
  437. //
  438. // Return Value:
  439. // plstr List of extensions.
  440. // NULL No extension associated with this object.
  441. //
  442. // Exceptions Thrown:
  443. // None.
  444. //
  445. //--
  446. /////////////////////////////////////////////////////////////////////////////
  447. const CStringList * CCluster::PlstrExtensions( void ) const
  448. {
  449. return &LstrClusterExtensions();
  450. } //*** CCluster::PlstrExtensions()
  451. /////////////////////////////////////////////////////////////////////////////
  452. //++
  453. //
  454. // CCluster::ReadClusterInfo
  455. //
  456. // Routine Description:
  457. // Get the name of the cluster as recorded by the cluster and the
  458. // version of the cluster software.
  459. //
  460. // Arguments:
  461. // None.
  462. //
  463. // Return Value:
  464. // None.
  465. //
  466. // Exceptions Thrown:
  467. // Any exceptions thrown by new.
  468. //
  469. //--
  470. /////////////////////////////////////////////////////////////////////////////
  471. void CCluster::ReadClusterInfo( void )
  472. {
  473. CWaitCursor wc;
  474. GetClusterInformation( Hcluster(), m_strName, &m_cvi );
  475. Pdoc()->m_strName = m_strName;
  476. } //*** CCluster::ReadClusterInfo()
  477. /////////////////////////////////////////////////////////////////////////////
  478. //++
  479. //
  480. // CCluster::ReadClusterExtensions
  481. //
  482. // Routine Description:
  483. // Read the extension list for the cluster object.
  484. //
  485. // Arguments:
  486. // None.
  487. //
  488. // Return Value:
  489. // None.
  490. //
  491. // Exceptions Thrown:
  492. // CNTException Errors from CClusterItem::DwReadValue().
  493. //
  494. //--
  495. /////////////////////////////////////////////////////////////////////////////
  496. void CCluster::ReadClusterExtensions( void )
  497. {
  498. DWORD dwStatus;
  499. CWaitCursor wc;
  500. ASSERT( Hkey() != NULL );
  501. if ( Hkey() != NULL )
  502. {
  503. // Read the Cluster extension string.
  504. dwStatus = DwReadValue( CLUSREG_NAME_ADMIN_EXT, m_lstrClusterExtensions );
  505. if ( ( dwStatus != ERROR_SUCCESS )
  506. && ( dwStatus != ERROR_FILE_NOT_FOUND ) )
  507. {
  508. ThrowStaticException( dwStatus );
  509. } // if: error reading the value
  510. } // if: key is available
  511. else
  512. {
  513. m_lstrClusterExtensions.RemoveAll();
  514. } // else: key is not available
  515. } //*** CCluster::ReadClusterExtensions()
  516. /////////////////////////////////////////////////////////////////////////////
  517. //++
  518. //
  519. // CCluster::ReadNodeExtensions
  520. //
  521. // Routine Description:
  522. // Read the extension list for all nodes.
  523. //
  524. // Arguments:
  525. // None.
  526. //
  527. // Return Value:
  528. // None.
  529. //
  530. // Exceptions Thrown:
  531. // CNTException Errors from CClusterItem::DwReadValue().
  532. //
  533. //--
  534. /////////////////////////////////////////////////////////////////////////////
  535. void CCluster::ReadNodeExtensions( void )
  536. {
  537. DWORD dwStatus;
  538. CWaitCursor wc;
  539. ASSERT( Hkey() != NULL );
  540. if ( Hkey() != NULL )
  541. {
  542. // Read the Nodes extension string.
  543. dwStatus = DwReadValue( CLUSREG_NAME_ADMIN_EXT, CLUSREG_KEYNAME_NODES, m_lstrNodeExtensions );
  544. if ( ( dwStatus != ERROR_SUCCESS )
  545. && ( dwStatus != ERROR_FILE_NOT_FOUND ) )
  546. {
  547. ThrowStaticException( dwStatus );
  548. } // if: error reading the value
  549. } // if: key is available
  550. else
  551. {
  552. m_lstrNodeExtensions.RemoveAll();
  553. } // else: key is not available
  554. } //*** CCluster::ReadNodeExtensions()
  555. /////////////////////////////////////////////////////////////////////////////
  556. //++
  557. //
  558. // CCluster::ReadGroupExtensions
  559. //
  560. // Routine Description:
  561. // Read the extension list for all groups.
  562. //
  563. // Arguments:
  564. // None.
  565. //
  566. // Return Value:
  567. // None.
  568. //
  569. // Exceptions Thrown:
  570. // CNTException Errors from CClusterItem::DwReadValue().
  571. //
  572. //--
  573. /////////////////////////////////////////////////////////////////////////////
  574. void CCluster::ReadGroupExtensions( void )
  575. {
  576. DWORD dwStatus;
  577. CWaitCursor wc;
  578. ASSERT( Hkey() != NULL );
  579. if ( Hkey() != NULL )
  580. {
  581. // Read the Groups extension string.
  582. dwStatus = DwReadValue( CLUSREG_NAME_ADMIN_EXT, CLUSREG_KEYNAME_GROUPS, m_lstrGroupExtensions );
  583. if ( ( dwStatus != ERROR_SUCCESS )
  584. && ( dwStatus != ERROR_FILE_NOT_FOUND ) )
  585. {
  586. ThrowStaticException( dwStatus );
  587. } // if: error reading the value
  588. } // if: key is available
  589. else
  590. {
  591. m_lstrGroupExtensions.RemoveAll();
  592. } // else: key is not available
  593. } //*** CCluster::ReadGroupExtensions()
  594. /////////////////////////////////////////////////////////////////////////////
  595. //++
  596. //
  597. // CCluster::ReadResourceExtensions
  598. //
  599. // Routine Description:
  600. // Read the extension list for all resources.
  601. //
  602. // Arguments:
  603. // None.
  604. //
  605. // Return Value:
  606. // None.
  607. //
  608. // Exceptions Thrown:
  609. // CNTException Errors from CClusterItem::DwReadValue().
  610. //
  611. //--
  612. /////////////////////////////////////////////////////////////////////////////
  613. void CCluster::ReadResourceExtensions( void )
  614. {
  615. DWORD dwStatus;
  616. CWaitCursor wc;
  617. ASSERT( Hkey() != NULL );
  618. if ( Hkey() != NULL )
  619. {
  620. // Read the Resources extension string.
  621. dwStatus = DwReadValue( CLUSREG_NAME_ADMIN_EXT, CLUSREG_KEYNAME_RESOURCES, m_lstrResourceExtensions );
  622. if ( ( dwStatus != ERROR_SUCCESS )
  623. && ( dwStatus != ERROR_FILE_NOT_FOUND ) )
  624. {
  625. ThrowStaticException( dwStatus );
  626. } // if: error reading the value
  627. } // if: key is available
  628. else
  629. {
  630. m_lstrResourceExtensions.RemoveAll();
  631. } // else: key is not available
  632. } //*** CCluster::ReadResourceExtensions()
  633. /////////////////////////////////////////////////////////////////////////////
  634. //++
  635. //
  636. // CCluster::ReadResTypeExtensions
  637. //
  638. // Routine Description:
  639. // Read the extension list for all resouce types.
  640. //
  641. // Arguments:
  642. // None.
  643. //
  644. // Return Value:
  645. // None.
  646. //
  647. // Exceptions Thrown:
  648. // CNTException Errors from CClusterItem::DwReadValue().
  649. //
  650. //--
  651. /////////////////////////////////////////////////////////////////////////////
  652. void CCluster::ReadResTypeExtensions( void )
  653. {
  654. DWORD dwStatus;
  655. CWaitCursor wc;
  656. ASSERT( Hkey() != NULL );
  657. if ( Hkey() != NULL )
  658. {
  659. // Read the Resource Types extension string.
  660. dwStatus = DwReadValue( CLUSREG_NAME_ADMIN_EXT, CLUSREG_KEYNAME_RESOURCE_TYPES, m_lstrResTypeExtensions );
  661. if ( ( dwStatus != ERROR_SUCCESS )
  662. && ( dwStatus != ERROR_FILE_NOT_FOUND ) )
  663. {
  664. ThrowStaticException( dwStatus );
  665. } // if: error reading the value
  666. } // if: key is available
  667. else
  668. {
  669. m_lstrResTypeExtensions.RemoveAll();
  670. } // else: key is not available
  671. } //*** CCluster::ReadResTypeExtensions()
  672. /////////////////////////////////////////////////////////////////////////////
  673. //++
  674. //
  675. // CCluster::ReadNetworkExtensions
  676. //
  677. // Routine Description:
  678. // Read the extension list for all networks.
  679. //
  680. // Arguments:
  681. // None.
  682. //
  683. // Return Value:
  684. // None.
  685. //
  686. // Exceptions Thrown:
  687. // CNTException Errors from CClusterItem::DwReadValue().
  688. //
  689. //--
  690. /////////////////////////////////////////////////////////////////////////////
  691. void CCluster::ReadNetworkExtensions( void )
  692. {
  693. DWORD dwStatus;
  694. CWaitCursor wc;
  695. ASSERT( Hkey() != NULL );
  696. if ( Hkey() != NULL )
  697. {
  698. // Read the Networks extension string.
  699. dwStatus = DwReadValue( CLUSREG_NAME_ADMIN_EXT, CLUSREG_KEYNAME_NETWORKS, m_lstrNetworkExtensions );
  700. if ( ( dwStatus != ERROR_SUCCESS )
  701. && ( dwStatus != ERROR_FILE_NOT_FOUND ) )
  702. {
  703. ThrowStaticException( dwStatus );
  704. } // if: error reading the value
  705. } // if: key is available
  706. else
  707. {
  708. m_lstrNetworkExtensions.RemoveAll();
  709. } // else: key is not available
  710. } //*** CCluster::ReadNetworkExtensions()
  711. /////////////////////////////////////////////////////////////////////////////
  712. //++
  713. //
  714. // CCluster::ReadNetInterfaceExtensions
  715. //
  716. // Routine Description:
  717. // Read the extension list for all network interfaces.
  718. //
  719. // Arguments:
  720. // None.
  721. //
  722. // Return Value:
  723. // None.
  724. //
  725. // Exceptions Thrown:
  726. // CNTException Errors from CClusterItem::DwReadValue().
  727. //
  728. //--
  729. /////////////////////////////////////////////////////////////////////////////
  730. void CCluster::ReadNetInterfaceExtensions( void )
  731. {
  732. DWORD dwStatus;
  733. CWaitCursor wc;
  734. ASSERT( Hkey() != NULL );
  735. if ( Hkey() != NULL )
  736. {
  737. // Read the Network Intefaces extension string.
  738. dwStatus = DwReadValue( CLUSREG_NAME_ADMIN_EXT, CLUSREG_KEYNAME_NETINTERFACES, m_lstrNetInterfaceExtensions );
  739. if ( ( dwStatus != ERROR_SUCCESS )
  740. && ( dwStatus != ERROR_FILE_NOT_FOUND ) )
  741. {
  742. ThrowStaticException( dwStatus );
  743. } // if: error reading the value
  744. } // if: key is available
  745. else
  746. {
  747. m_lstrNetInterfaceExtensions.RemoveAll();
  748. } // else: key is not available
  749. } //*** CCluster::ReadNetInterfaceExtensions()
  750. /////////////////////////////////////////////////////////////////////////////
  751. //++
  752. //
  753. // CCluster::CollecNetworkPriority
  754. //
  755. // Routine Description:
  756. // Construct the network priority list.
  757. //
  758. // Arguments:
  759. // plpci [IN OUT] List to fill.
  760. //
  761. // Return Value:
  762. // None.
  763. //
  764. // Exceptions Thrown:
  765. // CNTException Errors from ClusterOpenEnum() or ClusterEnum().
  766. // Any exceptions thrown by new or CList::AddTail().
  767. //
  768. //--
  769. /////////////////////////////////////////////////////////////////////////////
  770. void CCluster::CollectNetworkPriority( IN OUT CNetworkList * plpci )
  771. {
  772. DWORD dwStatus;
  773. HCLUSENUM hclusenum;
  774. int ienum;
  775. LPWSTR pwszName = NULL;
  776. DWORD cchName;
  777. DWORD cchmacName;
  778. DWORD dwRetType;
  779. CNetwork * pciNet;
  780. CWaitCursor wc;
  781. ASSERT_VALID( Pdoc() );
  782. ASSERT( Hcluster() != NULL );
  783. if ( plpci == NULL )
  784. {
  785. plpci = m_plpciNetworkPriority;
  786. } // if: no list specified
  787. ASSERT( plpci != NULL );
  788. // Remove the previous contents of the list.
  789. plpci->RemoveAll();
  790. if ( Hcluster() != NULL )
  791. {
  792. // Open the enumeration.
  793. hclusenum = ClusterOpenEnum( Hcluster(), (DWORD) CLUSTER_ENUM_INTERNAL_NETWORK );
  794. if ( hclusenum == NULL )
  795. {
  796. ThrowStaticException( GetLastError(), IDS_ENUM_NETWORK_PRIORITY_ERROR, StrName() );
  797. } // if: error opening the enmeration
  798. try
  799. {
  800. // Allocate a name buffer.
  801. cchmacName = 128;
  802. pwszName = new WCHAR[ cchmacName ];
  803. if ( pwszName == NULL )
  804. {
  805. AfxThrowMemoryException();
  806. } // if: error allocating the name buffer
  807. // Loop through the enumeration and add each network to the list.
  808. for ( ienum = 0 ; ; ienum++ )
  809. {
  810. // Get the next item in the enumeration.
  811. cchName = cchmacName;
  812. dwStatus = ClusterEnum( hclusenum, ienum, &dwRetType, pwszName, &cchName );
  813. if ( dwStatus == ERROR_MORE_DATA )
  814. {
  815. delete [] pwszName;
  816. cchmacName = ++cchName;
  817. pwszName = new WCHAR[ cchmacName ];
  818. if ( pwszName == NULL )
  819. {
  820. AfxThrowMemoryException();
  821. } // if: error allocating the name buffer
  822. dwStatus = ClusterEnum( hclusenum, ienum, &dwRetType, pwszName, &cchName );
  823. } // if: name buffer was too small
  824. if ( dwStatus == ERROR_NO_MORE_ITEMS )
  825. {
  826. break;
  827. } // if: done with the enumeraiton
  828. else if ( dwStatus != ERROR_SUCCESS )
  829. {
  830. ThrowStaticException( dwStatus, IDS_ENUM_NETWORK_PRIORITY_ERROR, StrName() );
  831. } // else if: error getting the next enumeration value
  832. ASSERT( dwRetType == CLUSTER_ENUM_INTERNAL_NETWORK );
  833. // Find the item in the list of networks on the document.
  834. pciNet = Pdoc()->LpciNetworks().PciNetworkFromName( pwszName );
  835. ASSERT_VALID( pciNet );
  836. // Add the network to the list.
  837. if ( pciNet != NULL )
  838. {
  839. plpci->AddTail( pciNet );
  840. } // if: found network in list
  841. } // for: each item in the group
  842. ClusterCloseEnum( hclusenum );
  843. } // try
  844. catch ( CException * )
  845. {
  846. delete [] pwszName;
  847. ClusterCloseEnum( hclusenum );
  848. throw;
  849. } // catch: any exception
  850. } // if: cluster is available
  851. delete [] pwszName;
  852. } //*** CCluster::CollecNetworkPriority()
  853. /////////////////////////////////////////////////////////////////////////////
  854. //++
  855. //
  856. // CCluster::OnUpdateProperties
  857. //
  858. // Routine Description:
  859. // Determines whether menu items corresponding to ID_FILE_PROPERTIES
  860. // should be enabled or not.
  861. //
  862. // Arguments:
  863. // pCmdUI [IN OUT] Command routing object.
  864. //
  865. // Return Value:
  866. // None.
  867. //
  868. //--
  869. /////////////////////////////////////////////////////////////////////////////
  870. void CCluster::OnUpdateProperties( CCmdUI * pCmdUI )
  871. {
  872. pCmdUI->Enable(TRUE);
  873. } //*** CCluster::OnUpdateProperties()
  874. /////////////////////////////////////////////////////////////////////////////
  875. //++
  876. //
  877. // CCluster::BDisplayProperties
  878. //
  879. // Routine Description:
  880. // Display properties for the object.
  881. //
  882. // Arguments:
  883. // bReadOnly [IN] Don't allow edits to the object properties.
  884. //
  885. // Return Value:
  886. // TRUE OK pressed.
  887. // FALSE OK not pressed.
  888. //
  889. //--
  890. /////////////////////////////////////////////////////////////////////////////
  891. BOOL CCluster::BDisplayProperties( IN BOOL bReadOnly )
  892. {
  893. BOOL bChanged = FALSE;
  894. CClusterPropSheet sht( AfxGetMainWnd() );
  895. // Do this in case this object is deleted while we are operating on it.
  896. AddRef();
  897. // If the object has changed, read it.
  898. if ( BChanged() )
  899. {
  900. ReadItem();
  901. } // if: object changed
  902. // Display the property sheet.
  903. try
  904. {
  905. sht.SetReadOnly( bReadOnly );
  906. if ( sht.BInit( this, IimgObjectType() ) )
  907. {
  908. bChanged = ( ( sht.DoModal() == IDOK ) && ! bReadOnly );
  909. } // if: initialized successfully
  910. } // try
  911. catch ( CException * pe )
  912. {
  913. pe->Delete();
  914. } // catch: CException
  915. Release();
  916. return bChanged;
  917. } //*** CCluster::BDisplayProperties()
  918. /////////////////////////////////////////////////////////////////////////////
  919. //++
  920. //
  921. // CCluster::SetName
  922. //
  923. // Routine Description:
  924. // Set the name of the cluster.
  925. //
  926. // Arguments:
  927. // pszName [IN] New name of the cluster.
  928. //
  929. // Return Value:
  930. // None.
  931. //
  932. // Exceptions Thrown:
  933. // Any exceptions thrown by WriteItem().
  934. //
  935. //--
  936. /////////////////////////////////////////////////////////////////////////////
  937. void CCluster::SetName( IN LPCTSTR pszName )
  938. {
  939. Rename( pszName );
  940. } //*** CCluster::SetName()
  941. /////////////////////////////////////////////////////////////////////////////
  942. //++
  943. //
  944. // CCluster::SetDescription
  945. //
  946. // Routine Description:
  947. // Set the description in the cluster database.
  948. //
  949. // Arguments:
  950. // pszDesc [IN] Description to set.
  951. //
  952. // Return Value:
  953. // None.
  954. //
  955. // Exceptions Thrown:
  956. // Any exceptions thrown by WriteItem().
  957. //
  958. //--
  959. /////////////////////////////////////////////////////////////////////////////
  960. void CCluster::SetDescription( IN LPCTSTR pszDesc )
  961. {
  962. ASSERT( Hkey() != NULL );
  963. if ( ( Hkey() != NULL ) && ( m_strDescription != pszDesc ) )
  964. {
  965. WriteValue( CLUSREG_NAME_CLUS_DESC, NULL, pszDesc );
  966. m_strDescription = pszDesc;
  967. } // if: a change occured
  968. } //*** CCluster::SetDescription()
  969. /////////////////////////////////////////////////////////////////////////////
  970. //++
  971. //
  972. // CCluster::SetQuorumResource
  973. //
  974. // Routine Description:
  975. // Set the quorum resource for the cluster.
  976. //
  977. // Arguments:
  978. // pszResource [IN] Name of resource to make the quorum resource.
  979. // pszQuorumPath [IN] Path for storing cluster files.
  980. // nMaxLogSize [IN] Maximum size of the quorum log.
  981. //
  982. // Return Value:
  983. // None.
  984. //
  985. // Exceptions Thrown:
  986. // CNTException IDS_SET_QUORUM_RESOURCE_ERROR - errors from
  987. // SetClusterQuorumResource().
  988. //--
  989. /////////////////////////////////////////////////////////////////////////////
  990. void CCluster::SetQuorumResource(
  991. IN LPCTSTR pszResource,
  992. IN LPCTSTR pszQuorumPath,
  993. IN DWORD nMaxLogSize
  994. )
  995. {
  996. DWORD dwStatus;
  997. CResource * pciRes;
  998. CString strRes( pszResource ); // Required if built non-Unicode
  999. CWaitCursor wc;
  1000. ASSERT( pszResource != NULL );
  1001. if ( ( StrQuorumResource() != pszResource )
  1002. || ( StrQuorumPath() != pszQuorumPath )
  1003. || ( NMaxQuorumLogSize() != nMaxLogSize ) )
  1004. {
  1005. // Find the resource.
  1006. pciRes = Pdoc()->LpciResources().PciResFromName( pszResource );
  1007. ASSERT_VALID( pciRes );
  1008. ASSERT( pciRes->Hresource() != NULL );
  1009. if ( pciRes->Hresource() != NULL )
  1010. {
  1011. // Change the quorum resource.
  1012. dwStatus = SetClusterQuorumResource( pciRes->Hresource(), pszQuorumPath, nMaxLogSize );
  1013. if ( dwStatus != ERROR_SUCCESS )
  1014. {
  1015. ThrowStaticException( dwStatus, IDS_SET_QUORUM_RESOURCE_ERROR, pciRes->StrName() );
  1016. } // if: error setting the quorum resource
  1017. m_strQuorumResource = pszResource;
  1018. m_strQuorumPath = pszQuorumPath;
  1019. m_nMaxQuorumLogSize = nMaxLogSize;
  1020. } // if: resource is available
  1021. } // if: the quorum resource changed
  1022. } //*** CCluster::SetQuorumResource()
  1023. /////////////////////////////////////////////////////////////////////////////
  1024. //++
  1025. //
  1026. // CCluster::SetNetworkPriority
  1027. //
  1028. // Routine Description:
  1029. // Set the network priority list.
  1030. //
  1031. // Arguments:
  1032. // rlpci [IN] List of networks in priority order.
  1033. //
  1034. // Return Value:
  1035. // None.
  1036. //
  1037. // Exceptions Thrown:
  1038. // Any exceptions thrown by HNETWORK::new.
  1039. //
  1040. //--
  1041. /////////////////////////////////////////////////////////////////////////////
  1042. void CCluster::SetNetworkPriority( IN const CNetworkList & rlpci )
  1043. {
  1044. DWORD dwStatus;
  1045. CWaitCursor wc;
  1046. ASSERT( Hcluster() != NULL );
  1047. if ( Hcluster() != NULL )
  1048. {
  1049. BOOL bChanged = TRUE;
  1050. // Determine if the list has changed.
  1051. if ( rlpci.GetCount() == LpciNetworkPriority().GetCount() )
  1052. {
  1053. POSITION posOld;
  1054. POSITION posNew;
  1055. CNetwork * pciOldNet;
  1056. CNetwork * pciNewNet;
  1057. bChanged = FALSE;
  1058. posOld = LpciNetworkPriority().GetHeadPosition();
  1059. posNew = rlpci.GetHeadPosition();
  1060. while ( posOld != NULL )
  1061. {
  1062. pciOldNet = (CNetwork *) LpciNetworkPriority().GetNext( posOld );
  1063. ASSERT_VALID( pciOldNet );
  1064. ASSERT( posNew != NULL );
  1065. pciNewNet = (CNetwork *) rlpci.GetNext( posNew );
  1066. ASSERT_VALID( pciNewNet );
  1067. if ( pciOldNet->StrName() != pciNewNet->StrName() )
  1068. {
  1069. bChanged = TRUE;
  1070. break;
  1071. } // if: name is not the same
  1072. } // while: more items in the old list
  1073. } // if: same number of items in the list
  1074. if ( bChanged )
  1075. {
  1076. HNETWORK * phnetwork = NULL;
  1077. try
  1078. {
  1079. DWORD ipci;
  1080. POSITION posPci;
  1081. CNetwork * pciNet;
  1082. // Allocate an array for all the node handles.
  1083. phnetwork = new HNETWORK[ (DWORD) rlpci.GetCount() ];
  1084. if ( phnetwork == NULL )
  1085. {
  1086. ThrowStaticException( GetLastError() );
  1087. } // if: error allocating network handle array
  1088. // Copy the handle of all the networks in the networks list to the handle aray.
  1089. posPci = rlpci.GetHeadPosition();
  1090. for ( ipci = 0 ; posPci != NULL ; ipci++ )
  1091. {
  1092. pciNet = (CNetwork *) rlpci.GetNext( posPci );
  1093. ASSERT_VALID( pciNet );
  1094. phnetwork[ ipci ] = pciNet->Hnetwork();
  1095. } // while: more networks in the list
  1096. // Set the property.
  1097. dwStatus = SetClusterNetworkPriorityOrder( Hcluster(), (DWORD) rlpci.GetCount(), phnetwork );
  1098. if ( dwStatus != ERROR_SUCCESS )
  1099. {
  1100. ThrowStaticException( dwStatus, IDS_SET_NET_PRIORITY_ERROR, StrName() );
  1101. } // if: error setting network priority
  1102. // Update the PCI list.
  1103. m_plpciNetworkPriority->RemoveAll();
  1104. posPci = rlpci.GetHeadPosition();
  1105. while ( posPci != NULL )
  1106. {
  1107. pciNet = (CNetwork *) rlpci.GetNext( posPci );
  1108. m_plpciNetworkPriority->AddTail( pciNet );
  1109. } // while: more items in the list
  1110. } // try
  1111. catch ( CException * )
  1112. {
  1113. delete [] phnetwork;
  1114. throw;
  1115. } // catch: CException
  1116. delete [] phnetwork;
  1117. } // if: list changed
  1118. } // if: key is available
  1119. } //*** CCluster::SetNetworkPriority(CNetworkList*)
  1120. /////////////////////////////////////////////////////////////////////////////
  1121. //++
  1122. //
  1123. // CCluster::Rename
  1124. //
  1125. // Routine Description:
  1126. // Change the name of the cluster..
  1127. //
  1128. // Arguments:
  1129. // pszName [IN] New name to give to the cluster.
  1130. //
  1131. // Return Value:
  1132. // None.
  1133. //
  1134. // Exceptions Thrown:
  1135. // CNTException Errors returned from SetClusterName().
  1136. //
  1137. //--
  1138. /////////////////////////////////////////////////////////////////////////////
  1139. void CCluster::Rename( IN LPCTSTR pszName )
  1140. {
  1141. DWORD dwStatus;
  1142. CWaitCursor wc;
  1143. ASSERT( Hcluster() != NULL );
  1144. if ( StrName() != pszName )
  1145. {
  1146. // Set the name.
  1147. dwStatus = SetClusterName( Hcluster(), pszName );
  1148. if ( dwStatus != ERROR_SUCCESS )
  1149. {
  1150. if ( dwStatus == ERROR_RESOURCE_PROPERTIES_STORED )
  1151. {
  1152. AfxMessageBox( IDS_RESTART_CLUSTER_NAME, MB_OK | MB_ICONEXCLAMATION );
  1153. } // if: properties stored but not in use yet
  1154. else
  1155. {
  1156. ThrowStaticException( dwStatus, IDS_RENAME_CLUSTER_ERROR, StrName(), pszName );
  1157. } // else: error occurred
  1158. } // if: error occurred setting cluster name
  1159. m_strName = pszName;
  1160. } // if: the name changed
  1161. } //*** CCluster::Rename()
  1162. /////////////////////////////////////////////////////////////////////////////
  1163. //++
  1164. //
  1165. // CCluster::BIsLabelEditValueValid
  1166. //
  1167. // Routine Description:
  1168. // Validate the label edit value as a cluster name
  1169. //
  1170. // Arguments:
  1171. // pszName [IN] New name to give to the cluster.
  1172. //
  1173. // Return Value:
  1174. // TRUE name is valid
  1175. // FALSE name is invalid
  1176. //
  1177. //--
  1178. /////////////////////////////////////////////////////////////////////////////
  1179. BOOL CCluster::BIsLabelEditValueValid( IN LPCTSTR pszName )
  1180. {
  1181. BOOL bSuccess = TRUE;
  1182. if ( StrName() != pszName )
  1183. {
  1184. CLRTL_NAME_STATUS cnStatus;
  1185. UINT idsError;
  1186. // Validate the name.
  1187. if ( ! ClRtlIsNetNameValid( pszName, &cnStatus, FALSE /*CheckIfExists*/ ) )
  1188. {
  1189. switch ( cnStatus )
  1190. {
  1191. case NetNameTooLong:
  1192. idsError = IDS_INVALID_CLUSTER_NAME_TOO_LONG;
  1193. break;
  1194. case NetNameInvalidChars:
  1195. idsError = IDS_INVALID_CLUSTER_NAME_INVALID_CHARS;
  1196. break;
  1197. case NetNameInUse:
  1198. idsError = IDS_INVALID_CLUSTER_NAME_IN_USE;
  1199. break;
  1200. case NetNameDNSNonRFCChars:
  1201. idsError = IDS_INVALID_CLUSTER_NAME_INVALID_DNS_CHARS;
  1202. break;
  1203. case NetNameSystemError:
  1204. {
  1205. DWORD scError = GetLastError();
  1206. ThrowStaticException( scError, IDS_ERROR_VALIDATING_NETWORK_NAME, pszName );
  1207. }
  1208. default:
  1209. idsError = IDS_INVALID_CLUSTER_NAME;
  1210. break;
  1211. } // switch: cnStatus
  1212. if ( idsError == IDS_INVALID_CLUSTER_NAME_INVALID_DNS_CHARS )
  1213. {
  1214. int id = AfxMessageBox(IDS_INVALID_CLUSTER_NAME_INVALID_DNS_CHARS, MB_YESNO | MB_DEFBUTTON2 | MB_ICONEXCLAMATION );
  1215. if ( id == IDNO )
  1216. {
  1217. bSuccess = FALSE;
  1218. }
  1219. }
  1220. else
  1221. {
  1222. bSuccess = FALSE;
  1223. }
  1224. } // if: error validating the name
  1225. } // if: the name changed
  1226. return bSuccess;
  1227. } //*** CCluster::BIsLabelEditValueValid()
  1228. /////////////////////////////////////////////////////////////////////////////
  1229. //++
  1230. //
  1231. // CCluster::OnBeginLabelEdit
  1232. //
  1233. // Routine Description:
  1234. // Prepare an edit control in a view for editing the cluster name.
  1235. //
  1236. // Arguments:
  1237. // pedit [IN OUT] Edit control to prepare.
  1238. //
  1239. // Return Value:
  1240. // None.
  1241. //
  1242. //--
  1243. /////////////////////////////////////////////////////////////////////////////
  1244. void CCluster::OnBeginLabelEdit( IN OUT CEdit * pedit )
  1245. {
  1246. ASSERT_VALID(pedit);
  1247. pedit->SetLimitText( MAX_CLUSTERNAME_LENGTH );
  1248. pedit->ModifyStyle( 0 /*dwRemove*/, ES_UPPERCASE | ES_OEMCONVERT /*dwAdd*/ );
  1249. } //*** CCluster::OnBeginLabelEdit()
  1250. /////////////////////////////////////////////////////////////////////////////
  1251. //++
  1252. //
  1253. // CCluster::UpdateState
  1254. //
  1255. // Routine Description:
  1256. // Update the current state of the item.
  1257. //
  1258. // Arguments:
  1259. // None.
  1260. //
  1261. // Return Value:
  1262. // None.
  1263. //
  1264. //--
  1265. /////////////////////////////////////////////////////////////////////////////
  1266. void CCluster::UpdateState( void )
  1267. {
  1268. // NOTENOTE: not referneced
  1269. //CClusterAdminApp * papp = GetClusterAdminApp();
  1270. CString strTitle;
  1271. GetClusterAdminApp();
  1272. Trace( g_tagCluster, _T("(%s) - Updating state"), StrName() );
  1273. // Update the title of the document.
  1274. ASSERT_VALID( Pdoc() );
  1275. try
  1276. {
  1277. Pdoc()->UpdateTitle();
  1278. } // try
  1279. catch ( CException * pe )
  1280. {
  1281. pe->Delete();
  1282. } // catch: CException
  1283. // Call the base class method.
  1284. CClusterItem::UpdateState();
  1285. } //*** CCluster::UpdateState()