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.

1953 lines
64 KiB

  1. /////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1996-2002 Microsoft Corporation
  4. //
  5. // Module Name:
  6. // CluAdmin.cpp
  7. //
  8. // Abstract:
  9. // Implementation of the CClusterAdminApp class.
  10. // Defines the class behaviors for the application.
  11. //
  12. // Author:
  13. // David Potter (davidp) May 1, 1996
  14. //
  15. // Revision History:
  16. //
  17. // Notes:
  18. //
  19. /////////////////////////////////////////////////////////////////////////////
  20. #include "stdafx.h"
  21. #include "CluAdmin.h"
  22. #include "ConstDef.h"
  23. #include "CASvc.h"
  24. #include "MainFrm.h"
  25. #include "SplitFrm.h"
  26. #include "ClusDoc.h"
  27. #include "TreeView.h"
  28. #include "OpenClus.h"
  29. #include "ClusMru.h"
  30. #include "ExcOper.h"
  31. #include "Notify.h"
  32. #include "TraceTag.h"
  33. #include "TraceDlg.h"
  34. #include "Barf.h"
  35. #include "BarfDlg.h"
  36. #include "About.h"
  37. #include "CmdLine.h"
  38. #include "VerInfo.h"
  39. #ifdef _DEBUG
  40. #define new DEBUG_NEW
  41. #undef THIS_FILE
  42. static char THIS_FILE[] = __FILE__;
  43. #endif
  44. /////////////////////////////////////////////////////////////////////////////
  45. // Global Variables
  46. /////////////////////////////////////////////////////////////////////////////
  47. static LPCTSTR g_pszProfileName = _T("Cluster Administrator");
  48. #ifdef _DEBUG
  49. CTraceTag g_tagApp( _T("App"), _T("APP"), 0 );
  50. CTraceTag g_tagAppMenu( _T("Menu"), _T("APP"), 0 );
  51. CTraceTag g_tagAppNotify( _T("Notify"), _T("APP NOTIFY"), 0 );
  52. CTraceTag g_tagNotifyThread( _T("Notify"), _T("NOTIFY THREAD"), 0 );
  53. CTraceTag g_tagNotifyThreadReg( _T("Notify"), _T("NOTIFY THREAD (REG)"), 0 );
  54. #endif
  55. /////////////////////////////////////////////////////////////////////////////
  56. // CClusterAdminApp
  57. /////////////////////////////////////////////////////////////////////////////
  58. /////////////////////////////////////////////////////////////////////////////
  59. // The one and only CClusterAdminApp object
  60. CClusterAdminApp theApp;
  61. IMPLEMENT_DYNAMIC( CClusterNotifyContext, CObject );
  62. IMPLEMENT_DYNAMIC( CClusterAdminApp, CWinApp );
  63. /////////////////////////////////////////////////////////////////////////////
  64. // Message Maps
  65. BEGIN_MESSAGE_MAP( CClusterAdminApp, CWinApp )
  66. //{{AFX_MSG_MAP(CClusterAdminApp)
  67. ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
  68. ON_COMMAND(ID_FILE_OPEN, OnFileOpen)
  69. ON_COMMAND(ID_FILE_NEW_CLUSTER, OnFileNewCluster)
  70. ON_COMMAND(ID_WINDOW_CLOSE_ALL, OnWindowCloseAll)
  71. ON_UPDATE_COMMAND_UI(ID_WINDOW_CLOSE_ALL, OnUpdateWindowCloseAll)
  72. //}}AFX_MSG_MAP
  73. // Standard file based document commands
  74. ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)
  75. #ifdef _DEBUG
  76. ON_COMMAND(ID_DEBUG_TRACE_SETTINGS, OnTraceSettings)
  77. ON_COMMAND(ID_DEBUG_BARF_SETTINGS, OnBarfSettings)
  78. ON_COMMAND(ID_DEBUG_BARF_ALL, OnBarfAllSettings)
  79. #endif // _DEBUG
  80. END_MESSAGE_MAP()
  81. /////////////////////////////////////////////////////////////////////////////
  82. //++
  83. //
  84. // CClusterAdminApp::CClusterAdminApp
  85. //
  86. // Routine Description:
  87. // Default constructor.
  88. //
  89. // Arguments:
  90. // None.
  91. //
  92. // Return Value:
  93. // None.
  94. //
  95. //--
  96. /////////////////////////////////////////////////////////////////////////////
  97. CClusterAdminApp::CClusterAdminApp( void )
  98. {
  99. // TODO: add construction code here,
  100. // Place all significant initialization in InitInstance
  101. m_pDocTemplate = NULL;
  102. m_hchangeNotifyPort = NULL;
  103. m_lcid = MAKELCID( MAKELANGID( LANG_NEUTRAL, SUBLANG_NEUTRAL ), SORT_DEFAULT );
  104. m_hOpenedCluster = NULL;
  105. m_nIdleCount = 0;
  106. m_punkClusCfgClient = NULL;
  107. FillMemory( m_rgiimg, sizeof( m_rgiimg ), 0xFF );
  108. } //*** CClusterAdminApp::CClusterAdminApp
  109. /////////////////////////////////////////////////////////////////////////////
  110. //++
  111. //
  112. // CClusterAdminApp::InitInstance
  113. //
  114. // Routine Description:
  115. // Initialize this instance of the application.
  116. //
  117. // Arguments:
  118. // None.
  119. //
  120. // Return Value:
  121. // TRUE Application successfully initialized.
  122. // FALSE Failed to initialize the application.
  123. //
  124. //--
  125. /////////////////////////////////////////////////////////////////////////////
  126. BOOL CClusterAdminApp::InitInstance( void )
  127. {
  128. BOOL bSuccess = FALSE;
  129. CMainFrame * pMainFrame = NULL;
  130. CCluAdminCommandLineInfo cmdInfo;
  131. HRESULT hr;
  132. size_t cch;
  133. // CG: The following block was added by the Splash Screen component.
  134. {
  135. // CCluAdminCommandLineInfo cmdInfo;
  136. // ParseCommandLine(cmdInfo);
  137. }
  138. // Initialize OLE libraries
  139. if ( ! AfxOleInit() )
  140. {
  141. AfxMessageBox( IDP_OLE_INIT_FAILED );
  142. goto Cleanup;
  143. }
  144. if ( CoInitializeSecurity(
  145. NULL,
  146. -1,
  147. NULL,
  148. NULL,
  149. RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
  150. RPC_C_IMP_LEVEL_IMPERSONATE,
  151. NULL,
  152. EOAC_NONE,
  153. 0
  154. ) != S_OK )
  155. {
  156. goto Cleanup;
  157. } // if:
  158. // Construct the help path.
  159. {
  160. TCHAR szPath[ _MAX_PATH ];
  161. TCHAR szDrive[ _MAX_PATH ];
  162. TCHAR szDir[ _MAX_DIR ];
  163. size_t cchPath;
  164. VERIFY( ::GetSystemWindowsDirectory( szPath, _MAX_PATH ) );
  165. cchPath = _tcslen( szPath );
  166. if ( szPath[ cchPath - 1 ] != _T('\\') )
  167. {
  168. szPath[ cchPath++ ] = _T('\\');
  169. szPath[ cchPath ] = _T('\0');
  170. } // if: no backslash on the end of the path
  171. hr = StringCchCopy( &szPath[ cchPath ], RTL_NUMBER_OF( szPath ) - cchPath, _T("Help\\") );
  172. ASSERT( SUCCEEDED( hr ) );
  173. _tsplitpath( szPath, szDrive, szDir, NULL, NULL );
  174. _tmakepath( szPath, szDrive, szDir, _T("cluadmin"), _T(".hlp") );
  175. free( (void *) m_pszHelpFilePath );
  176. BOOL bEnable;
  177. bEnable = AfxEnableMemoryTracking( FALSE );
  178. m_pszHelpFilePath = _tcsdup( szPath );
  179. AfxEnableMemoryTracking( bEnable );
  180. } // Construct the help path
  181. // Standard initialization
  182. // If you are not using these features and wish to reduce the size
  183. // of your final executable, you should remove from the following
  184. // the specific initialization routines you do not need.
  185. SetRegistryKey( IDS_REGKEY_COMPANY ); // Set the registry key for the program.
  186. //
  187. // Override the profile name because we don't want to localize it.
  188. //
  189. free( (void *) m_pszProfileName );
  190. cch = _tcslen( g_pszProfileName ) + 1;
  191. m_pszProfileName = (LPTSTR) malloc( cch * sizeof( *m_pszProfileName ) );
  192. if ( m_pszProfileName == NULL )
  193. {
  194. goto MemoryError;
  195. } // if: error allocating the profile name buffer
  196. hr = StringCchCopy( const_cast< LPTSTR >( m_pszProfileName ), cch, g_pszProfileName );
  197. ASSERT( SUCCEEDED( hr ) );
  198. InitAllTraceTags(); // Initialize all trace tags.
  199. InitBarf(); // Initialize Basic Artificial Resource Failure system.
  200. // Load version information.
  201. #if 0
  202. {
  203. CVersionInfo verinfo;
  204. DWORD dwValue;
  205. // Initialize the version info.
  206. verinfo.Init();
  207. // Get the Locale ID.
  208. if ( verinfo.BQueryValue( _T("\\VarFileInfo\\Translation"), dwValue ) )
  209. {
  210. m_lcid = MAKELCID( dwValue, SORT_DEFAULT );
  211. } // if: locale ID is available
  212. } // Load version information
  213. #else
  214. // Get the locale ID from the system to support MUI.
  215. m_lcid = GetUserDefaultLCID();
  216. #endif
  217. // Initialize global CImageList
  218. InitGlobalImageList();
  219. #ifdef _AFXDLL
  220. Enable3dControls(); // Call this when using MFC in a shared DLL
  221. #else
  222. Enable3dControlsStatic(); // Call this when linking to MFC statically
  223. #endif
  224. LoadStdProfileSettings( 0 ); // Load standard INI file options (including MRU)
  225. // Create cluster MRU.
  226. m_pRecentFileList = new CRecentClusterList( 0, _T("Recent Cluster List"), _T("Cluster%d"), 4 );
  227. if ( m_pRecentFileList == NULL )
  228. {
  229. goto MemoryError;
  230. } // if: error allocating memory
  231. m_pRecentFileList->ReadList();
  232. // Register the application's document templates. Document templates
  233. // serve as the connection between documents, frame windows and views.
  234. m_pDocTemplate = new CMultiDocTemplate(
  235. IDR_CLUADMTYPE,
  236. RUNTIME_CLASS( CClusterDoc ),
  237. RUNTIME_CLASS( CSplitterFrame ), // custom MDI child frame
  238. RUNTIME_CLASS( CClusterTreeView )
  239. );
  240. if ( m_pDocTemplate == NULL )
  241. {
  242. goto MemoryError;
  243. } // if: error allocating memory
  244. AddDocTemplate( m_pDocTemplate );
  245. // create main MDI Frame window
  246. pMainFrame = new CMainFrame;
  247. if ( pMainFrame == NULL )
  248. {
  249. goto MemoryError;
  250. } // if: error allocating memory
  251. ASSERT( pMainFrame != NULL );
  252. if ( ! pMainFrame->LoadFrame( IDR_MAINFRAME ) )
  253. {
  254. goto Cleanup;
  255. } // if: error loading the frame
  256. m_pMainWnd = pMainFrame;
  257. // Parse command line for standard shell commands, DDE, file open
  258. // cmdInfo.m_nShellCommand = CCommandLineInfo::FileNothing; // Don't want to do a FileNew.
  259. ParseCommandLine( cmdInfo );
  260. // If no commands were specified on the command line, restore the desktop.
  261. if ( cmdInfo.m_nShellCommand == CCommandLineInfo::FileNothing )
  262. {
  263. pMainFrame->PostMessage( WM_CAM_RESTORE_DESKTOP, cmdInfo.m_bReconnect );
  264. } // if: no commands specified on the command line
  265. // Create the cluster notification thread.
  266. if ( ! BInitNotifyThread() )
  267. {
  268. goto Cleanup;
  269. } // if: error creating the cluster notification thread
  270. // The main window has been initialized, so show and update it.
  271. {
  272. WINDOWPLACEMENT wp;
  273. // Set the placement of the window.
  274. if ( ReadWindowPlacement( &wp, REGPARAM_SETTINGS, 0 ) )
  275. {
  276. pMainFrame->SetWindowPlacement( &wp );
  277. m_nCmdShow = wp.showCmd; // set the show command.
  278. } // if: read from profile
  279. // Activate and update the frame window.
  280. pMainFrame->ActivateFrame( m_nCmdShow );
  281. pMainFrame->UpdateWindow();
  282. } // The main window has been initialized, so show and update it
  283. // Dispatch commands specified on the command line
  284. if ( ! ProcessShellCommand( cmdInfo ) )
  285. {
  286. goto Cleanup;
  287. } // if: error processing the command line
  288. TraceMenu( g_tagAppMenu, AfxGetMainWnd()->GetMenu(), _T("InitInstance menu: ") );
  289. bSuccess = TRUE;
  290. Cleanup:
  291. if ( m_pMainWnd != pMainFrame )
  292. {
  293. delete pMainFrame;
  294. } // if: main frame windows allocated but not saved yet
  295. return bSuccess;
  296. MemoryError:
  297. CNTException nte(
  298. ERROR_NOT_ENOUGH_MEMORY,
  299. 0, // idsOperation
  300. NULL, // pszOperArg1
  301. NULL, // pszOperArg2
  302. FALSE // bAutoDelete
  303. );
  304. nte.ReportError();
  305. nte.Delete();
  306. goto Cleanup;
  307. } //*** CClusterAdminApp::InitInstance
  308. /////////////////////////////////////////////////////////////////////////////
  309. //++
  310. //
  311. // CClusterAdminApp::OnIdle
  312. //
  313. // Routine Description:
  314. // Process the command line or shell command.
  315. //
  316. // Arguments:
  317. // LONG [IN] Number of time we have been called before the next
  318. // message arrives in the queue
  319. //
  320. // Return Value:
  321. // TRUE if more idle processing
  322. //
  323. //--
  324. /////////////////////////////////////////////////////////////////////////////
  325. BOOL CClusterAdminApp::OnIdle(IN LONG lCount)
  326. {
  327. BOOL bMore = CWinApp::OnIdle(lCount);
  328. //
  329. // Since the MFC framework processing many messages lCount was never getting
  330. // higher than 1. Since this work should not be done everytime we are idle
  331. // I added my own counter that determines when the work is done.
  332. //
  333. if ((++m_nIdleCount % 200) == 0)
  334. {
  335. POSITION posDoc; // position in the documents collection
  336. POSITION posDel; // position in the to be deleted list
  337. POSITION posRemove; // position in the to be deleted list to remove
  338. CClusterDoc * pdoc;
  339. CClusterItem * pitem;
  340. CWaitCursor cw;
  341. posDoc = PdocTemplate()->GetFirstDocPosition();
  342. while (posDoc != NULL)
  343. {
  344. pdoc = (CClusterDoc *) PdocTemplate()->GetNextDoc(posDoc);
  345. ASSERT_VALID(pdoc);
  346. try
  347. {
  348. posDel = pdoc->LpciToBeDeleted().GetHeadPosition();
  349. while (posDel != NULL)
  350. {
  351. posRemove = posDel; // save posDel to posRemove since the next call is going to inc posDel
  352. pitem = (CClusterItem *) pdoc->LpciToBeDeleted().GetNext(posDel);
  353. ASSERT_VALID(pitem);
  354. if ((pitem != NULL) && ( pitem->NReferenceCount() == 1))
  355. {
  356. pdoc->LpciToBeDeleted().RemoveAt(posRemove); // the saved position posRemove
  357. } // if: the list's refence is the only one
  358. } // while: more items in the to be deleted list
  359. }
  360. catch (CException * pe)
  361. {
  362. pe->Delete();
  363. } // catch: CException
  364. } // while: more items in the list
  365. m_nIdleCount = 0;
  366. bMore = FALSE; // don't want any more calls until some new messages are received
  367. } // if: every 200th time...
  368. return bMore;
  369. } //*** CClusterAdminApp::OnIdle
  370. /////////////////////////////////////////////////////////////////////////////
  371. //++
  372. //
  373. // CClusterAdminApp::ProcessShellCommand
  374. //
  375. // Routine Description:
  376. // Process the command line or shell command.
  377. //
  378. // Arguments:
  379. // rCmdInfo [IN OUT] Command line info.
  380. //
  381. // Return Value:
  382. // 0 Error.
  383. // !0 No error.
  384. //
  385. //--
  386. /////////////////////////////////////////////////////////////////////////////
  387. BOOL CClusterAdminApp::ProcessShellCommand(IN OUT CCluAdminCommandLineInfo & rCmdInfo)
  388. {
  389. BOOL bSuccess = TRUE;
  390. if (rCmdInfo.m_nShellCommand == CCommandLineInfo::FileOpen)
  391. {
  392. POSITION pos;
  393. try
  394. {
  395. pos = rCmdInfo.LstrClusters().GetHeadPosition();
  396. while (pos != NULL)
  397. {
  398. OpenDocumentFile(rCmdInfo.LstrClusters().GetNext(pos));
  399. } // while: more clusters in the list
  400. } // try
  401. catch (CException * pe)
  402. {
  403. pe->ReportError();
  404. pe->Delete();
  405. bSuccess = FALSE;
  406. } // catch: CException
  407. } // if: we are opening clusters
  408. else
  409. bSuccess = CWinApp::ProcessShellCommand(rCmdInfo);
  410. return bSuccess;
  411. } //*** CClusterAdminApp::ProcessShellCommand
  412. /////////////////////////////////////////////////////////////////////////////
  413. //++
  414. //
  415. // CClusterAdminApp::ExitInstance
  416. //
  417. // Routine Description:
  418. // Exit this instance of the application.
  419. //
  420. // Arguments:
  421. // None.
  422. //
  423. // Return Value:
  424. // 0 No errors.
  425. //
  426. //--
  427. /////////////////////////////////////////////////////////////////////////////
  428. int CClusterAdminApp::ExitInstance(void)
  429. {
  430. // Close the notification port.
  431. if (HchangeNotifyPort() != NULL)
  432. {
  433. ::CloseClusterNotifyPort(HchangeNotifyPort());
  434. m_hchangeNotifyPort = NULL;
  435. // Allow the notification port threads to clean themselves up.
  436. ::Sleep(100);
  437. } // if: notification port is open
  438. // Delete all the items in the notification key list.
  439. DeleteAllItemData( Cnkl() );
  440. Cnkl().RemoveAll();
  441. // Delete all the items in the notification list.
  442. m_cnlNotifications.RemoveAll();
  443. CleanupAllTraceTags(); // Cleanup trace tags.
  444. CleanupBarf(); // Cleanup Basic Artificial Resource Failure system.
  445. // Release the ClusCfg client object.
  446. if ( m_punkClusCfgClient != NULL )
  447. {
  448. m_punkClusCfgClient->Release();
  449. }
  450. return CWinApp::ExitInstance();
  451. } //*** CClusterAdminApp::ExitInstance
  452. /////////////////////////////////////////////////////////////////////////////
  453. //++
  454. //
  455. // CClusterAdminApp::InitGlobalImageList
  456. //
  457. // Routine Description:
  458. // Initialize the global image list.
  459. //
  460. // Arguments:
  461. // None.
  462. //
  463. // Return Value:
  464. // None.
  465. //
  466. //--
  467. /////////////////////////////////////////////////////////////////////////////
  468. void CClusterAdminApp::InitGlobalImageList(void)
  469. {
  470. // Create small image list.
  471. VERIFY(PilSmallImages()->Create(
  472. (int) 16, // cx
  473. 16, // cy
  474. TRUE, // bMask
  475. 17, // nInitial
  476. 4 // nGrow
  477. ));
  478. PilSmallImages()->SetBkColor(::GetSysColor(COLOR_WINDOW));
  479. // Load the images into the small image list.
  480. LoadImageIntoList(PilSmallImages(), IDB_FOLDER_16, IMGLI_FOLDER);
  481. LoadImageIntoList(PilSmallImages(), IDB_CLUSTER_16, IMGLI_CLUSTER);
  482. LoadImageIntoList(PilSmallImages(), IDB_CLUSTER_UNKNOWN_16, IMGLI_CLUSTER_UNKNOWN);
  483. LoadImageIntoList(PilSmallImages(), IDB_NODE_16, IMGLI_NODE);
  484. LoadImageIntoList(PilSmallImages(), IDB_NODE_DOWN_16, IMGLI_NODE_DOWN);
  485. LoadImageIntoList(PilSmallImages(), IDB_NODE_PAUSED_16, IMGLI_NODE_PAUSED);
  486. LoadImageIntoList(PilSmallImages(), IDB_NODE_UNKNOWN_16, IMGLI_NODE_UNKNOWN);
  487. LoadImageIntoList(PilSmallImages(), IDB_GROUP_16, IMGLI_GROUP);
  488. LoadImageIntoList(PilSmallImages(), IDB_GROUP_PARTIAL_ONLINE_16, IMGLI_GROUP_PARTIALLY_ONLINE);
  489. LoadImageIntoList(PilSmallImages(), IDB_GROUP_PENDING_16, IMGLI_GROUP_PENDING);
  490. LoadImageIntoList(PilSmallImages(), IDB_GROUP_OFFLINE_16, IMGLI_GROUP_OFFLINE);
  491. LoadImageIntoList(PilSmallImages(), IDB_GROUP_FAILED_16, IMGLI_GROUP_FAILED);
  492. LoadImageIntoList(PilSmallImages(), IDB_GROUP_UNKNOWN_16, IMGLI_GROUP_UNKNOWN);
  493. LoadImageIntoList(PilSmallImages(), IDB_RES_16, IMGLI_RES);
  494. LoadImageIntoList(PilSmallImages(), IDB_RES_OFFLINE_16, IMGLI_RES_OFFLINE);
  495. LoadImageIntoList(PilSmallImages(), IDB_RES_PENDING_16, IMGLI_RES_PENDING);
  496. LoadImageIntoList(PilSmallImages(), IDB_RES_FAILED_16, IMGLI_RES_FAILED);
  497. LoadImageIntoList(PilSmallImages(), IDB_RES_UNKNOWN_16, IMGLI_RES_UNKNOWN);
  498. LoadImageIntoList(PilSmallImages(), IDB_RESTYPE_16, IMGLI_RESTYPE);
  499. LoadImageIntoList(PilSmallImages(), IDB_RESTYPE_UNKNOWN_16, IMGLI_RESTYPE_UNKNOWN);
  500. LoadImageIntoList(PilSmallImages(), IDB_NETWORK_16, IMGLI_NETWORK);
  501. LoadImageIntoList(PilSmallImages(), IDB_NETWORK_PARTITIONED_16, IMGLI_NETWORK_PARTITIONED);
  502. LoadImageIntoList(PilSmallImages(), IDB_NETWORK_DOWN_16, IMGLI_NETWORK_DOWN);
  503. LoadImageIntoList(PilSmallImages(), IDB_NETWORK_UNKNOWN_16, IMGLI_NETWORK_UNKNOWN);
  504. LoadImageIntoList(PilSmallImages(), IDB_NETIFACE_16, IMGLI_NETIFACE);
  505. LoadImageIntoList(PilSmallImages(), IDB_NETIFACE_UNREACHABLE_16, IMGLI_NETIFACE_UNREACHABLE);
  506. LoadImageIntoList(PilSmallImages(), IDB_NETIFACE_FAILED_16, IMGLI_NETIFACE_FAILED);
  507. LoadImageIntoList(PilSmallImages(), IDB_NETIFACE_UNKNOWN_16, IMGLI_NETIFACE_UNKNOWN);
  508. // Create large image list.
  509. VERIFY(PilLargeImages()->Create(
  510. (int) 32, // cx
  511. 32, // cy
  512. TRUE, // bMask
  513. 17, // nInitial
  514. 4 // nGrow
  515. ));
  516. PilLargeImages()->SetBkColor(::GetSysColor(COLOR_WINDOW));
  517. // Load the images into the large image list.
  518. LoadImageIntoList(PilLargeImages(), IDB_FOLDER_32, IMGLI_FOLDER);
  519. LoadImageIntoList(PilLargeImages(), IDB_CLUSTER_32, IMGLI_CLUSTER);
  520. LoadImageIntoList(PilLargeImages(), IDB_CLUSTER_UNKNOWN_32, IMGLI_CLUSTER_UNKNOWN);
  521. LoadImageIntoList(PilLargeImages(), IDB_NODE_32, IMGLI_NODE);
  522. LoadImageIntoList(PilLargeImages(), IDB_NODE_DOWN_32, IMGLI_NODE_DOWN);
  523. LoadImageIntoList(PilLargeImages(), IDB_NODE_PAUSED_32, IMGLI_NODE_PAUSED);
  524. LoadImageIntoList(PilLargeImages(), IDB_NODE_UNKNOWN_32, IMGLI_NODE_UNKNOWN);
  525. LoadImageIntoList(PilLargeImages(), IDB_GROUP_32, IMGLI_GROUP);
  526. LoadImageIntoList(PilLargeImages(), IDB_GROUP_PARTIAL_ONLINE_32, IMGLI_GROUP_PARTIALLY_ONLINE);
  527. LoadImageIntoList(PilLargeImages(), IDB_GROUP_PENDING_32, IMGLI_GROUP_PENDING);
  528. LoadImageIntoList(PilLargeImages(), IDB_GROUP_OFFLINE_32, IMGLI_GROUP_OFFLINE);
  529. LoadImageIntoList(PilLargeImages(), IDB_GROUP_FAILED_32, IMGLI_GROUP_FAILED);
  530. LoadImageIntoList(PilLargeImages(), IDB_GROUP_UNKNOWN_32, IMGLI_GROUP_UNKNOWN);
  531. LoadImageIntoList(PilLargeImages(), IDB_RES_32, IMGLI_RES);
  532. LoadImageIntoList(PilLargeImages(), IDB_RES_OFFLINE_32, IMGLI_RES_OFFLINE);
  533. LoadImageIntoList(PilLargeImages(), IDB_RES_PENDING_32, IMGLI_RES_PENDING);
  534. LoadImageIntoList(PilLargeImages(), IDB_RES_FAILED_32, IMGLI_RES_FAILED);
  535. LoadImageIntoList(PilLargeImages(), IDB_RES_UNKNOWN_32, IMGLI_RES_UNKNOWN);
  536. LoadImageIntoList(PilLargeImages(), IDB_RESTYPE_32, IMGLI_RESTYPE);
  537. LoadImageIntoList(PilLargeImages(), IDB_RESTYPE_UNKNOWN_32, IMGLI_RESTYPE_UNKNOWN);
  538. LoadImageIntoList(PilLargeImages(), IDB_NETWORK_32, IMGLI_NETWORK);
  539. LoadImageIntoList(PilLargeImages(), IDB_NETWORK_PARTITIONED_32, IMGLI_NETWORK_PARTITIONED);
  540. LoadImageIntoList(PilLargeImages(), IDB_NETWORK_DOWN_32, IMGLI_NETWORK_DOWN);
  541. LoadImageIntoList(PilLargeImages(), IDB_NETWORK_UNKNOWN_32, IMGLI_NETWORK_UNKNOWN);
  542. LoadImageIntoList(PilLargeImages(), IDB_NETIFACE_32, IMGLI_NETIFACE);
  543. LoadImageIntoList(PilLargeImages(), IDB_NETIFACE_UNREACHABLE_32, IMGLI_NETIFACE_UNREACHABLE);
  544. LoadImageIntoList(PilLargeImages(), IDB_NETIFACE_FAILED_32, IMGLI_NETIFACE_FAILED);
  545. LoadImageIntoList(PilLargeImages(), IDB_NETIFACE_UNKNOWN_32, IMGLI_NETIFACE_UNKNOWN);
  546. } //*** CClusterAdminApp::InitGlobalImageList
  547. /////////////////////////////////////////////////////////////////////////////
  548. //++
  549. //
  550. // CClusterAdminApp::LoadImageIntoList
  551. //
  552. // Routine Description:
  553. // Load images into an image list.
  554. //
  555. // Arguments:
  556. // pil [IN OUT] Image list into which to load the image.
  557. // idbImage [IN] Resource ID for the image bitmap.
  558. // imgli [IN] Index into the index array.
  559. //
  560. // Return Value:
  561. // None.
  562. //
  563. //--
  564. /////////////////////////////////////////////////////////////////////////////
  565. void CClusterAdminApp::LoadImageIntoList(
  566. IN OUT CImageList * pil,
  567. IN ID idbImage,
  568. IN UINT imgli
  569. )
  570. {
  571. CBitmap bm;
  572. UINT iimg;
  573. LoadImageIntoList(pil, idbImage, &iimg);
  574. if (m_rgiimg[imgli] == (UINT) -1)
  575. m_rgiimg[imgli] = iimg;
  576. #ifdef DEBUG
  577. else
  578. ASSERT(m_rgiimg[imgli] == iimg);
  579. #endif
  580. } //*** CClusterAdminApp::LoadImageIntoList
  581. /////////////////////////////////////////////////////////////////////////////
  582. //++
  583. //
  584. // static
  585. // CClusterAdminApp::LoadImageIntoList
  586. //
  587. // Routine Description:
  588. // Load images into an image list.
  589. //
  590. // Arguments:
  591. // pil [IN OUT] Image list into which to load the image.
  592. // idbImage [IN] Resource ID for the image bitmap.
  593. // piimg [OUT] Pointer to image index.
  594. //
  595. // Return Value:
  596. // None.
  597. //
  598. //--
  599. /////////////////////////////////////////////////////////////////////////////
  600. void CClusterAdminApp::LoadImageIntoList(
  601. IN OUT CImageList * pil,
  602. IN ID idbImage,
  603. OUT UINT * piimg
  604. )
  605. {
  606. CBitmap bm;
  607. UINT iimg;
  608. COLORREF crMaskColor = RGB(255,0,255);
  609. ASSERT(pil != NULL);
  610. ASSERT(idbImage != 0);
  611. if (piimg == NULL)
  612. piimg = &iimg;
  613. bm.LoadBitmap(idbImage);
  614. *piimg = pil->Add(&bm, crMaskColor);
  615. } //*** CClusterAdminApp::LoadImageIntoList
  616. /////////////////////////////////////////////////////////////////////////////
  617. //++
  618. //
  619. // CClusterAdminApp::OnRestoreDesktop
  620. //
  621. // Routine Description:
  622. // Handler for the WM_CAM_RESTORE_DESKTOP message.
  623. // Restores the desktop from the saved parameters.
  624. //
  625. // Arguments:
  626. // wparam TRUE = reconnect, FALSE, don't reconnect.
  627. // lparam Unused.
  628. //
  629. // Return Value:
  630. // 0
  631. //
  632. //--
  633. /////////////////////////////////////////////////////////////////////////////
  634. LRESULT CClusterAdminApp::OnRestoreDesktop(WPARAM wparam, LPARAM lparam)
  635. {
  636. CString strConnections;
  637. WPARAM bReconnect = wparam;
  638. if (bReconnect)
  639. {
  640. // Read the connections the user had last time they exited.
  641. try
  642. {
  643. strConnections = GetProfileString(REGPARAM_CONNECTIONS, REGPARAM_CONNECTIONS);
  644. } // try
  645. catch (CException * pe)
  646. {
  647. pe->ReportError();
  648. pe->Delete();
  649. } // catch: CException
  650. // If there were any connections, restore them.
  651. if (strConnections.GetLength() > 0)
  652. {
  653. LPTSTR pszConnections;
  654. LPTSTR pszConnection;
  655. TCHAR szSep[] = _T(",");
  656. ASSERT(m_pMainWnd != NULL);
  657. try
  658. {
  659. pszConnections = strConnections.GetBuffer(1);
  660. pszConnection = _tcstok(pszConnections, szSep);
  661. while (pszConnection != NULL)
  662. {
  663. // Open a connection to this cluster.
  664. OpenDocumentFile(pszConnection);
  665. // Find the next connection.
  666. pszConnection = _tcstok(NULL, szSep);
  667. } // while: more connections
  668. } // try
  669. catch (CException * pe)
  670. {
  671. pe->ReportError();
  672. pe->Delete();
  673. } // catch: CException
  674. strConnections.ReleaseBuffer();
  675. } // if: connections saved previously
  676. else
  677. bReconnect = FALSE;
  678. } // if: reconnect is desired
  679. if (!bReconnect)
  680. {
  681. CWaitCursor wc;
  682. Sleep(1500);
  683. } // if: not reconnecting
  684. // If there were no previous connections and we are not minimized, do a standard file open.
  685. if (!bReconnect && !AfxGetMainWnd()->IsIconic())
  686. OnFileOpen();
  687. // Otherwise, restore the desktop.
  688. return 0;
  689. } //*** CClusterAdminApp::OnRestoreDesktop
  690. /////////////////////////////////////////////////////////////////////////////
  691. //++
  692. //
  693. // CClusterAdminApp::SaveConnections
  694. //
  695. // Routine Description:
  696. // Save the current connections so they can be restored later.
  697. //
  698. // Arguments:
  699. // None.
  700. //
  701. // Return Value:
  702. // None.
  703. //
  704. //--
  705. /////////////////////////////////////////////////////////////////////////////
  706. void CClusterAdminApp::SaveConnections(void)
  707. {
  708. POSITION pos;
  709. CClusterDoc * pdoc;
  710. CString strConnections;
  711. TCHAR szSep[] = _T("\0");
  712. pos = PdocTemplate()->GetFirstDocPosition();
  713. while (pos != NULL)
  714. {
  715. pdoc = (CClusterDoc *) PdocTemplate()->GetNextDoc(pos);
  716. ASSERT_VALID(pdoc);
  717. try
  718. {
  719. strConnections += szSep + pdoc->StrNode();
  720. szSep[0] = _T(','); // Subsequent connections are preceded by a separator
  721. }
  722. catch (CException * pe)
  723. {
  724. pe->Delete();
  725. } // catch: CException
  726. // Save connection-specific settings as well.
  727. pdoc->SaveSettings();
  728. } // while: more items in the list
  729. WriteProfileString(REGPARAM_CONNECTIONS, REGPARAM_CONNECTIONS, strConnections);
  730. } //*** CClusterAdminApp::SaveConnections
  731. /////////////////////////////////////////////////////////////////////////////
  732. //++
  733. //
  734. // CClusterAdminApp::OnFileOpen
  735. //
  736. // Routine Description:
  737. // Prompt the user for the name of a cluster or server and then open it.
  738. //
  739. // Arguments:
  740. // None.
  741. //
  742. // Return Value:
  743. // None.
  744. //
  745. //--
  746. /////////////////////////////////////////////////////////////////////////////
  747. void CClusterAdminApp::OnFileOpen(void)
  748. {
  749. COpenClusterDialog dlg;
  750. ID idDlgStatus;
  751. CDocument * pdoc = NULL;
  752. HCLUSTER hCluster = NULL;
  753. DWORD scLastError = 0;
  754. CString strClusterName;
  755. do
  756. {
  757. idDlgStatus = (ID) dlg.DoModal();
  758. if ( idDlgStatus != IDOK )
  759. {
  760. break;
  761. }
  762. switch ( dlg.m_nAction )
  763. {
  764. case OPEN_CLUSTER_DLG_CREATE_NEW_CLUSTER:
  765. OnFileNewCluster();
  766. break;
  767. case OPEN_CLUSTER_DLG_ADD_NODES:
  768. case OPEN_CLUSTER_DLG_OPEN_CONNECTION:
  769. if ( hCluster != NULL )
  770. {
  771. CloseCluster( hCluster );
  772. } // if: previous cluster opened
  773. hCluster = HOpenCluster( dlg.m_strName );
  774. if ( hCluster == NULL )
  775. {
  776. scLastError = GetLastError();
  777. if( scLastError != ERROR_SUCCESS )
  778. {
  779. //
  780. // GPotts - 6/22/2001 - BUG 410912
  781. //
  782. // HOpenCluster could return NULL and last error = 0 if GetNodeClusterState
  783. // returned either ClusterStateNotInstalled or ClusterStateNotConfigured.
  784. //
  785. CNTException nte( scLastError, IDS_OPEN_CLUSTER_ERROR, dlg.m_strName );
  786. nte.ReportError();
  787. } // if: last error != 0
  788. } // if: error opening the cluster
  789. else
  790. {
  791. Trace( g_tagApp, _T("OnFileOpen() - Opening the cluster document on '%s'"), dlg.m_strName );
  792. m_hOpenedCluster = hCluster;
  793. pdoc = OpenDocumentFile( dlg.m_strName );
  794. strClusterName = StrGetClusterName( hCluster );
  795. m_hOpenedCluster = NULL;
  796. hCluster = NULL;
  797. } // else: cluster opened successfully
  798. if ( ( pdoc != NULL ) && ( dlg.m_nAction == OPEN_CLUSTER_DLG_ADD_NODES ) )
  799. {
  800. NewNodeWizard(
  801. strClusterName,
  802. FALSE // fIgnoreErrors
  803. );
  804. } // if: add a node to the cluster
  805. break;
  806. } // switch: dialog action
  807. } while ( ( pdoc == NULL )
  808. && ( dlg.m_nAction != OPEN_CLUSTER_DLG_CREATE_NEW_CLUSTER ) );
  809. if ( hCluster != NULL )
  810. {
  811. CloseCluster( hCluster );
  812. }
  813. } //*** CClusterAdminApp::OnFileOpen
  814. /////////////////////////////////////////////////////////////////////////////
  815. //++
  816. //
  817. // CClusterAdminApp::OpenDocumentFile
  818. //
  819. // Routine Description:
  820. // Open a cluster.
  821. //
  822. // Arguments:
  823. // lpszFileName The name of the cluster or a server in that cluster.
  824. //
  825. // Return Value:
  826. // NULL Invalid cluster or server name.
  827. // pOpenDocument The document instance for the open cluster.
  828. //
  829. //--
  830. /////////////////////////////////////////////////////////////////////////////
  831. CDocument * CClusterAdminApp::OpenDocumentFile(LPCTSTR lpszFileName)
  832. {
  833. // find the highest confidence
  834. CDocTemplate::Confidence bestMatch = CDocTemplate::noAttempt;
  835. CDocTemplate * pBestTemplate = NULL;
  836. CDocument * pOpenDocument = NULL;
  837. {
  838. ASSERT_KINDOF(CDocTemplate, m_pDocTemplate);
  839. CDocTemplate::Confidence match;
  840. ASSERT(pOpenDocument == NULL);
  841. match = m_pDocTemplate->MatchDocType(lpszFileName, pOpenDocument);
  842. if (match > bestMatch)
  843. {
  844. bestMatch = match;
  845. pBestTemplate = m_pDocTemplate;
  846. }
  847. }
  848. if (pOpenDocument != NULL)
  849. {
  850. POSITION pos = pOpenDocument->GetFirstViewPosition();
  851. if (pos != NULL)
  852. {
  853. CView * pView = pOpenDocument->GetNextView(pos); // get first one
  854. ASSERT_VALID(pView);
  855. CFrameWnd * pFrame = pView->GetParentFrame();
  856. if (pFrame != NULL)
  857. pFrame->ActivateFrame();
  858. else
  859. Trace(g_tagApp, _T("Error: Can not find a frame for document to activate."));
  860. CFrameWnd * pAppFrame;
  861. if (pFrame != (pAppFrame = (CFrameWnd*)AfxGetApp()->m_pMainWnd))
  862. {
  863. ASSERT_KINDOF(CFrameWnd, pAppFrame);
  864. pAppFrame->ActivateFrame();
  865. }
  866. }
  867. else
  868. {
  869. Trace(g_tagApp, _T("Error: Can not find a view for document to activate."));
  870. }
  871. return pOpenDocument;
  872. }
  873. if (pBestTemplate == NULL)
  874. {
  875. TCHAR szMsg[1024];
  876. AfxLoadString(AFX_IDP_FAILED_TO_OPEN_DOC, szMsg, sizeof(szMsg)/sizeof(szMsg[0]));
  877. AfxMessageBox(szMsg);
  878. return NULL;
  879. }
  880. return pBestTemplate->OpenDocumentFile(lpszFileName);
  881. } //*** CClusterAdminApp::OpenDocumentFile
  882. /////////////////////////////////////////////////////////////////////////////
  883. //++
  884. //
  885. // CClusterAdminApp::AddToRecentFileList
  886. //
  887. // Routine Description:
  888. // Adds a file to the Most Recently Used file list. Overridden to
  889. // prevent the cluster name from being fully qualified as a file.
  890. //
  891. // Arguments:
  892. // lpszPathName [IN] The path of the file.
  893. //
  894. // Return Value:
  895. // None.
  896. //
  897. //--
  898. /////////////////////////////////////////////////////////////////////////////
  899. void CClusterAdminApp::AddToRecentFileList(LPCTSTR lpszPathName)
  900. {
  901. ASSERT_VALID(this);
  902. ASSERT(lpszPathName != NULL);
  903. ASSERT(AfxIsValidString(lpszPathName));
  904. if (m_pRecentFileList != NULL)
  905. {
  906. // Don't fully qualify the path name.
  907. m_pRecentFileList->Add(lpszPathName);
  908. }
  909. } //*** CClusterAdminApp::AddToRecentFileList
  910. /////////////////////////////////////////////////////////////////////////////
  911. //++
  912. //
  913. // CClusterAdminApp::OnFileNewCluster
  914. //
  915. // Routine Description:
  916. // Processes the ID_FILE_NEW_CLUSTER menu command.
  917. //
  918. // Arguments:
  919. // None.
  920. //
  921. // Return Value:
  922. // None.
  923. //
  924. //--
  925. /////////////////////////////////////////////////////////////////////////////
  926. void CClusterAdminApp::OnFileNewCluster( void )
  927. {
  928. HRESULT hr = S_OK;
  929. IClusCfgCreateClusterWizard * piWiz;
  930. VARIANT_BOOL fCommitted = VARIANT_FALSE;
  931. // Get an interface pointer for the wizard.
  932. hr = CoCreateInstance(
  933. CLSID_ClusCfgCreateClusterWizard,
  934. NULL,
  935. CLSCTX_INPROC_SERVER,
  936. IID_IClusCfgCreateClusterWizard,
  937. (LPVOID *) &piWiz
  938. );
  939. if ( FAILED( hr ) )
  940. {
  941. CNTException nte( hr, IDS_CREATE_CLUSCFGWIZ_OBJ_ERROR, NULL, NULL, FALSE /*bAutoDelete*/ );
  942. nte.ReportError();
  943. return;
  944. } // if: error getting the interface pointer
  945. // Display the wizard.
  946. hr = piWiz->ShowWizard( HandleToLong( AfxGetMainWnd()->m_hWnd ), &fCommitted );
  947. if ( FAILED( hr ) )
  948. {
  949. CNTException nte( hr, IDS_CREATE_CLUSTER_ERROR, NULL, NULL, FALSE /*bAutoDelete*/ );
  950. nte.ReportError();
  951. } // if: error adding cluster nodes
  952. if ( fCommitted == VARIANT_TRUE )
  953. {
  954. BSTR bstrClusterName;
  955. hr = piWiz->get_ClusterName( &bstrClusterName );
  956. if ( FAILED( hr ) )
  957. {
  958. CNTException nte( hr, IDS_CREATE_CLUSTER_ERROR, NULL, NULL, FALSE /*bAutoDelete*/ );
  959. nte.ReportError();
  960. }
  961. else
  962. {
  963. if ( hr == S_OK )
  964. {
  965. HCLUSTER hCluster;
  966. ASSERT( bstrClusterName != NULL );
  967. // Open the cluster with the cluster name specified by the
  968. // wizard. If it not successful, translate this to a NetBIOS
  969. // name in case that is more reliable.
  970. hCluster = OpenCluster( bstrClusterName );
  971. if ( hCluster == NULL )
  972. {
  973. WCHAR szClusterNetBIOSName[ MAX_COMPUTERNAME_LENGTH + 1 ];
  974. DWORD nSize = sizeof( szClusterNetBIOSName ) / sizeof( szClusterNetBIOSName[ 0 ] );
  975. DnsHostnameToComputerName( bstrClusterName, szClusterNetBIOSName, &nSize );
  976. SysFreeString( bstrClusterName );
  977. bstrClusterName = SysAllocString( szClusterNetBIOSName );
  978. }
  979. else
  980. {
  981. CloseCluster( hCluster );
  982. }
  983. OpenDocumentFile( bstrClusterName );
  984. } // if: retrieved cluster name successfully
  985. SysFreeString( bstrClusterName );
  986. } // else: retrieving cluster name didn't fail
  987. } // if: user didn't cancel the wizard
  988. piWiz->Release();
  989. } //*** CClusterAdminApp::OnFileNewCluster
  990. /////////////////////////////////////////////////////////////////////////////
  991. //++
  992. //
  993. // CClusterAdminApp::OnAppAbout
  994. //
  995. // Routine Description:
  996. // Displays the about box.
  997. //
  998. // Arguments:
  999. // None.
  1000. //
  1001. // Return Value:
  1002. // None.
  1003. //
  1004. //--
  1005. /////////////////////////////////////////////////////////////////////////////
  1006. void CClusterAdminApp::OnAppAbout(void)
  1007. {
  1008. CAboutDlg aboutDlg;
  1009. aboutDlg.DoModal();
  1010. } //*** CClusterAdminApp::OnAppAbout
  1011. /////////////////////////////////////////////////////////////////////////////
  1012. //++
  1013. //
  1014. // CClusterAdminApp::OnUpdateWindowCloseAll
  1015. //
  1016. // Routine Description:
  1017. // Determines whether menu items corresponding to ID_WINDOW_CLOSE_ALL
  1018. // should be enabled or not.
  1019. //
  1020. // Arguments:
  1021. // pCmdUI [IN OUT] Command routing object.
  1022. //
  1023. // Return Value:
  1024. // None.
  1025. //
  1026. //--
  1027. /////////////////////////////////////////////////////////////////////////////
  1028. void CClusterAdminApp::OnUpdateWindowCloseAll(CCmdUI * pCmdUI)
  1029. {
  1030. pCmdUI->Enable(m_pDocTemplate->GetFirstDocPosition() != NULL);
  1031. } //*** CClusterAdminApp::OnUpdateWindowCloseAll
  1032. /////////////////////////////////////////////////////////////////////////////
  1033. //++
  1034. //
  1035. // CClusterAdminApp::OnWindowCloseAll
  1036. //
  1037. // Routine Description:
  1038. // Processes the ID_WINDOW_CLOSE_ALL menu command.
  1039. //
  1040. // Arguments:
  1041. // None.
  1042. //
  1043. // Return Value:
  1044. // None.
  1045. //
  1046. //--
  1047. /////////////////////////////////////////////////////////////////////////////
  1048. void CClusterAdminApp::OnWindowCloseAll(void)
  1049. {
  1050. CloseAllDocuments(FALSE /*bEndSession*/);
  1051. } //*** CClusterAdminApp::OnWindowCloseAll
  1052. #ifdef _DEBUG
  1053. /////////////////////////////////////////////////////////////////////////////
  1054. //++
  1055. //
  1056. // CClusterAdminApp::OnTraceSettings
  1057. //
  1058. // Routine Description:
  1059. // Displays the Trace Settings dialog.
  1060. //
  1061. // Arguments:
  1062. // None.
  1063. //
  1064. // Return Value:
  1065. // None.
  1066. //
  1067. //--
  1068. /////////////////////////////////////////////////////////////////////////////
  1069. void CClusterAdminApp::OnTraceSettings(void)
  1070. {
  1071. CTraceDialog dlgTraceSettings;
  1072. dlgTraceSettings.DoModal();
  1073. } //*** CClusterAdminApp::OnTraceSettings
  1074. /////////////////////////////////////////////////////////////////////////////
  1075. //++
  1076. //
  1077. // CClusterAdminApp::OnBarfSettings
  1078. //
  1079. // Routine Description:
  1080. // Displays the BARF Settings dialog.
  1081. //
  1082. // Arguments:
  1083. // None.
  1084. //
  1085. // Return Value:
  1086. // None.
  1087. //
  1088. //--
  1089. /////////////////////////////////////////////////////////////////////////////
  1090. void CClusterAdminApp::OnBarfSettings(void)
  1091. {
  1092. DoBarfDialog();
  1093. } //*** CClusterAdminApp::OnBarfSettings
  1094. /////////////////////////////////////////////////////////////////////////////
  1095. //++
  1096. //
  1097. // CClusterAdminApp::OnBarfAllSettings
  1098. //
  1099. // Routine Description:
  1100. // Displays the BARF All Settings dialog.
  1101. //
  1102. // Arguments:
  1103. // None.
  1104. //
  1105. // Return Value:
  1106. // None.
  1107. //
  1108. //--
  1109. /////////////////////////////////////////////////////////////////////////////
  1110. void CClusterAdminApp::OnBarfAllSettings(void)
  1111. {
  1112. BarfAll();
  1113. } //*** CClusterAdminApp::OnBarfAllSettings
  1114. #endif // _DEBUG
  1115. /////////////////////////////////////////////////////////////////////////////
  1116. //++
  1117. //
  1118. // CClusterAdminApp::OnClusterNotify
  1119. //
  1120. // Routine Description:
  1121. // Handler for the WM_CAM_CLUSTER_NOTIFY message.
  1122. // Processes cluster notifications.
  1123. //
  1124. // Arguments:
  1125. // wparam WPARAM.
  1126. // lparam LPARAM
  1127. //
  1128. // Return Value:
  1129. // Value returned from the application method.
  1130. //
  1131. //--
  1132. /////////////////////////////////////////////////////////////////////////////
  1133. LRESULT CClusterAdminApp::OnClusterNotify( WPARAM wparam, LPARAM lparam )
  1134. {
  1135. CClusterNotify * pnotify = NULL;
  1136. BOOL fHandled;
  1137. #if 0
  1138. BOOL fWindowRepaintsStopped = FALSE;
  1139. #endif
  1140. ASSERT( m_cnlNotifications.IsEmpty() == FALSE );
  1141. // Process notifications until the list is empty.
  1142. while ( m_cnlNotifications.IsEmpty() == FALSE )
  1143. {
  1144. #if 0
  1145. // If the number of notifications waiting to be processed exceeds
  1146. // a certain threshold, turn off window repaints on the main window.
  1147. if ( ( fWindowRepaintsStopped == FALSE )
  1148. && ( m_cnlNotifications.GetCount() > 5 )
  1149. )
  1150. {
  1151. fWindowRepaintsStopped = AfxGetMainWnd()->LockWindowUpdate();
  1152. } // if: too many notifications in the list
  1153. #endif
  1154. // Get the next notification.
  1155. pnotify = m_cnlNotifications.Remove();
  1156. ASSERT( pnotify != NULL );
  1157. ASSERT( pnotify->m_dwNotifyKey != 0 );
  1158. if ( pnotify == NULL )
  1159. {
  1160. // This should NEVER happen.
  1161. break;
  1162. } // if: no notification returned
  1163. fHandled = FALSE;
  1164. //
  1165. // If this is a normal notify message, send it to the object
  1166. // that registered it.
  1167. //
  1168. if ( pnotify->m_emt == CClusterNotify::EMessageType::mtNotify )
  1169. {
  1170. // Send change notifications to the object that registered it.
  1171. if ( pnotify->m_pcnk != NULL )
  1172. {
  1173. // Find the notification key in our list of keys. If it is not
  1174. // found, ignore it. Otherwise, ask the object that registered
  1175. // the notification to handle it.
  1176. if ( Cnkl().Find( pnotify->m_pcnk ) != NULL )
  1177. {
  1178. switch ( pnotify->m_pcnk->m_cnkt )
  1179. {
  1180. case cnktDoc:
  1181. ASSERT_VALID( pnotify->m_pcnk->m_pdoc );
  1182. pnotify->m_pcnk->m_pdoc->OnClusterNotify( pnotify );
  1183. pnotify = NULL;
  1184. break;
  1185. case cnktClusterItem:
  1186. ASSERT_VALID( pnotify->m_pcnk->m_pci );
  1187. ASSERT_VALID( pnotify->m_pcnk->m_pci->Pdoc() );
  1188. pnotify->m_pcnk->m_pci->OnClusterNotify( pnotify );
  1189. pnotify = NULL;
  1190. break;
  1191. } // switch: notification key type
  1192. } // if: notification key found in the list
  1193. } // if: non-NULL object pointer
  1194. // Notification not handled.
  1195. if ( fHandled == FALSE )
  1196. {
  1197. Trace( g_tagError, _T("*** Unhandled notification: key %08.8x, filter %x (%s) - '%s'"), pnotify->m_dwNotifyKey, pnotify->m_dwFilterType, PszNotificationName( pnotify->m_dwFilterType ), pnotify->m_strName );
  1198. }
  1199. } // if: normal notify message
  1200. else if ( pnotify->m_emt == CClusterNotify::EMessageType::mtRefresh )
  1201. {
  1202. //
  1203. // This is a refresh notify message. Refresh all connections.
  1204. //
  1205. POSITION pos;
  1206. CClusterDoc * pdoc;
  1207. pos = PdocTemplate()->GetFirstDocPosition();
  1208. while ( pos != NULL )
  1209. {
  1210. pdoc = (CClusterDoc *) PdocTemplate()->GetNextDoc(pos);
  1211. ASSERT_VALID(pdoc);
  1212. try
  1213. {
  1214. pdoc->OnCmdRefresh();
  1215. }
  1216. catch ( CException * pe )
  1217. {
  1218. pe->Delete();
  1219. } // catch: CException
  1220. } // while: more documents in the list
  1221. } // else if: refresh notify message
  1222. delete pnotify;
  1223. pnotify = NULL;
  1224. } // while: more notifications
  1225. #if 0
  1226. // If we stopped window repaints, turn them on again.
  1227. if ( fWindowRepaintsStopped )
  1228. {
  1229. AfxGetMainWnd()->UnlockWindowUpdate();
  1230. } // if: we stopped window repaints
  1231. #endif
  1232. delete pnotify;
  1233. return 0;
  1234. } //*** CClusterAdminApp::OnClusterNotify
  1235. /////////////////////////////////////////////////////////////////////////////
  1236. //++
  1237. //
  1238. // CClusterAdminApp::BInitNotifyThread
  1239. //
  1240. // Routine Description:
  1241. // Initialize the cluster notification thread.
  1242. //
  1243. // Arguments:
  1244. // None.
  1245. //
  1246. // Return Value:
  1247. // TRUE Thread initialized successfully.
  1248. // FALSE Thread NOT initialized successfully.
  1249. //
  1250. //--
  1251. /////////////////////////////////////////////////////////////////////////////
  1252. BOOL CClusterAdminApp::BInitNotifyThread(void)
  1253. {
  1254. try
  1255. {
  1256. // Create the notification port.
  1257. m_hchangeNotifyPort = ::CreateClusterNotifyPort(
  1258. (HCHANGE) INVALID_HANDLE_VALUE, // hChange
  1259. (HCLUSTER) INVALID_HANDLE_VALUE, // hCluster
  1260. 0, // dwFilter
  1261. 0 // dwNotifyKey
  1262. );
  1263. if (HchangeNotifyPort() == NULL)
  1264. {
  1265. ThrowStaticException(GetLastError());
  1266. }
  1267. // Construct the context object.
  1268. Pcnctx()->m_hchangeNotifyPort = HchangeNotifyPort();
  1269. Pcnctx()->m_hwndFrame = m_pMainWnd->m_hWnd;
  1270. Pcnctx()->m_pcnlList = &Cnl();
  1271. // Begin the thread.
  1272. m_wtNotifyThread = AfxBeginThread(NotifyThreadProc, Pcnctx());
  1273. if (WtNotifyThread() == NULL)
  1274. {
  1275. ThrowStaticException(GetLastError());
  1276. }
  1277. } // try
  1278. catch (CException * pe)
  1279. {
  1280. // Close the notify port.
  1281. if (HchangeNotifyPort() != NULL)
  1282. {
  1283. ::CloseClusterNotifyPort(HchangeNotifyPort());
  1284. m_hchangeNotifyPort = NULL;
  1285. } // if: notify port is open
  1286. pe->ReportError();
  1287. pe->Delete();
  1288. return FALSE;
  1289. } // catch: CException
  1290. return TRUE;
  1291. } //*** CClusterAdminApp::BInitNotifyThread
  1292. /////////////////////////////////////////////////////////////////////////////
  1293. //++
  1294. //
  1295. // CClusterAdminApp::NotifyThreadProc (static)
  1296. //
  1297. // Routine Description:
  1298. // Notification thread procedure.
  1299. //
  1300. // Arguments:
  1301. // pParam [IN OUT] Thread procedure parameter -- a notification
  1302. // context object.
  1303. //
  1304. // Return Value:
  1305. // None.
  1306. //
  1307. //--
  1308. /////////////////////////////////////////////////////////////////////////////
  1309. UINT AFX_CDECL CClusterAdminApp::NotifyThreadProc(LPVOID pParam)
  1310. {
  1311. DWORD dwStatus;
  1312. WCHAR* pwszName;
  1313. DWORD cchName;
  1314. DWORD cchBuffer;
  1315. DWORD_PTR dwNotifyKey;
  1316. DWORD dwFilterType;
  1317. DWORD nTimeout;
  1318. BOOL fQueueIsFull = FALSE;
  1319. CClusterNotify * pnotify = NULL;
  1320. CClusterNotifyContext * pnctx = (CClusterNotifyContext *) pParam;
  1321. CClusterNotify::EMessageType emt = CClusterNotify::EMessageType::mtNotify;
  1322. ASSERT( pParam != NULL );
  1323. ASSERT_KINDOF( CClusterNotifyContext, pnctx );
  1324. ASSERT( pnctx->m_hchangeNotifyPort != NULL );
  1325. ASSERT( pnctx->m_hwndFrame != NULL );
  1326. //
  1327. // Allocate a buffer that should be large enough for most notifications.
  1328. // If it isn't, it will be reallocated in the loop below.
  1329. //
  1330. cchBuffer = 1024;
  1331. pwszName = new WCHAR[ 1024 ];
  1332. ASSERT( pwszName != NULL );
  1333. if ( pwszName == NULL )
  1334. {
  1335. AfxThrowMemoryException();
  1336. } // if: memory exception
  1337. //
  1338. // Default to waiting an infinite amount of time for the next notification
  1339. // to be delivered. We will change this if we ever get too many
  1340. // notifications in the queue.
  1341. //
  1342. nTimeout = INFINITE;
  1343. for (;;)
  1344. {
  1345. //
  1346. // Get the next notification.
  1347. // Wait for one if there isn't one waiting for us.
  1348. //
  1349. cchName = cchBuffer;
  1350. dwStatus = GetClusterNotify(
  1351. pnctx->m_hchangeNotifyPort,
  1352. &dwNotifyKey,
  1353. &dwFilterType,
  1354. pwszName,
  1355. &cchName,
  1356. nTimeout
  1357. );
  1358. if ( dwStatus == ERROR_INVALID_HANDLE )
  1359. {
  1360. //
  1361. // The notification port was closed.
  1362. break;
  1363. } // if: invalid handle error
  1364. if ( dwStatus == ERROR_MORE_DATA )
  1365. {
  1366. //
  1367. // The name buffer was too small.
  1368. // Allocate a new one.
  1369. //
  1370. cchName++; // Add one for NULL
  1371. ASSERT( cchName > cchBuffer );
  1372. cchBuffer = cchName;
  1373. // Reallocate the name buffer.
  1374. delete [] pwszName;
  1375. pwszName = new WCHAR[ cchBuffer ];
  1376. ASSERT( pwszName != NULL );
  1377. if ( pwszName == NULL )
  1378. {
  1379. AfxThrowMemoryException();
  1380. } // if: memory exception
  1381. // Loop around and try again.
  1382. continue;
  1383. } // if: buffer too small
  1384. if ( dwStatus == WAIT_TIMEOUT )
  1385. {
  1386. //
  1387. // The call to GetClusterNotify timed out. This will only happen
  1388. // if we detected that there were too many notifications in the
  1389. // queue and stopped saving them. Send a refresh message to the
  1390. // main window and reset the timeout to INFINITE so that
  1391. // we will wait until there is another event to get.
  1392. //
  1393. nTimeout = INFINITE;
  1394. emt = CClusterNotify::EMessageType::mtRefresh;
  1395. fQueueIsFull = FALSE;
  1396. } // if: GetClusterNotify timed out
  1397. else if ( dwStatus != ERROR_SUCCESS )
  1398. {
  1399. // Some other failure occurred getting the notification.
  1400. TraceError(_T("CClusterAdminApp::NotifyThreadProc() %s"), dwStatus);
  1401. continue;
  1402. } // else if: error getting notification
  1403. //
  1404. // If we have exceeded the max queue size threshold, don't send this
  1405. // notification to the main UI thread. Instead change the timeout
  1406. // value so that we will just keep getting notifications off the
  1407. // queue until there aren't anymore. Once that has happened,
  1408. // we will send a refresh event to the main UI thread and it will
  1409. // refresh all the connections.
  1410. //
  1411. if ( ( emt == CClusterNotify::EMessageType::mtNotify )
  1412. && ( pnctx->m_pcnlList->GetCount() > 500 )
  1413. )
  1414. {
  1415. nTimeout = 2000;
  1416. fQueueIsFull = TRUE;
  1417. } // if: queue is full
  1418. if ( fQueueIsFull == FALSE )
  1419. {
  1420. //
  1421. // Package the notification info up to send to the main UI thread.
  1422. //
  1423. try
  1424. {
  1425. // Allocate the notification object and initialize it.
  1426. pnotify = new CClusterNotify( emt, dwNotifyKey, dwFilterType, pwszName );
  1427. ASSERT( pnotify != NULL );
  1428. if ( pnotify == NULL )
  1429. {
  1430. // Failed to allocate, so ignore this notification.
  1431. continue;
  1432. } // if: error allocating and initialize the notify object
  1433. #ifdef _DEBUG
  1434. if ( emt == CClusterNotify::EMessageType::mtNotify )
  1435. {
  1436. TCHAR * pszTracePrefix;
  1437. CTraceTag * ptag;
  1438. pszTracePrefix = _T("");
  1439. if ( ( dwNotifyKey == NULL )
  1440. || ( dwNotifyKey == 0xfeeefeee )
  1441. || ( dwNotifyKey == 0xbaadf00d ) )
  1442. {
  1443. ptag = &g_tagError;
  1444. pszTracePrefix = _T("*** NOTIFY THREAD ");
  1445. } // if: bad notification key
  1446. else if ( dwFilterType & (CLUSTER_CHANGE_REGISTRY_NAME | CLUSTER_CHANGE_REGISTRY_ATTRIBUTES | CLUSTER_CHANGE_REGISTRY_VALUE) )
  1447. {
  1448. ptag = &g_tagNotifyThreadReg;
  1449. }
  1450. else
  1451. {
  1452. ptag = &g_tagNotifyThread;
  1453. }
  1454. Trace( *ptag, _T("%sNotification - key %08.8x, filter %x (%s), %s"), pszTracePrefix, dwNotifyKey, dwFilterType, PszNotificationName(dwFilterType), pnotify->m_strName );
  1455. } // if: normal notification
  1456. #endif
  1457. // Add the item to the list.
  1458. // The pointer is NULL upon return.
  1459. pnctx->m_pcnlList->Add( &pnotify );
  1460. // Release the list lock.
  1461. // Post a message to the main window to tell the main thread
  1462. // there is new information in the list.
  1463. if ( ! ::PostMessage( pnctx->m_hwndFrame, WM_CAM_CLUSTER_NOTIFY, NULL, NULL ) )
  1464. {
  1465. } // if: PostMessage failed
  1466. emt = CClusterNotify::EMessageType::mtNotify;
  1467. fQueueIsFull = FALSE;
  1468. } // try
  1469. catch ( ... )
  1470. {
  1471. if ( pnotify != NULL )
  1472. {
  1473. delete pnotify;
  1474. pnotify = NULL;
  1475. } // if: notification record allocated
  1476. } // catch: any exception
  1477. } // if: notification queue is not full
  1478. } // forever: get notifications until the notification port is closed
  1479. delete [] pwszName;
  1480. delete pnotify;
  1481. return 0;
  1482. } //*** CClusterAdminApp::NotifyThreadProc
  1483. //*************************************************************************//
  1484. /////////////////////////////////////////////////////////////////////////////
  1485. // Global Functions
  1486. /////////////////////////////////////////////////////////////////////////////
  1487. /////////////////////////////////////////////////////////////////////////////
  1488. //++
  1489. //
  1490. // BCreateFont
  1491. //
  1492. // Routine Description:
  1493. // Create a font.
  1494. //
  1495. // Arguments:
  1496. // rfont [OUT] Font to create.
  1497. // nPoints [IN] Point size.
  1498. // bBold [IN] Flag specifying whether font is bold or not.
  1499. //
  1500. // Return Value:
  1501. // TRUE Font created successfully.
  1502. // FALSE Error creating font.
  1503. //
  1504. //--
  1505. /////////////////////////////////////////////////////////////////////////////
  1506. BOOL BCreateFont(OUT CFont & rfont, IN int nPoints, IN BOOL bBold)
  1507. {
  1508. return rfont.CreateFont(
  1509. -nPoints, // nHeight
  1510. 0, // nWidth
  1511. 0, // nEscapement
  1512. 0, // nOrientation
  1513. (bBold ? FW_BOLD : FW_DONTCARE), // nWeight
  1514. FALSE, // bItalic
  1515. FALSE, // bUnderline
  1516. FALSE, // cStrikeout
  1517. ANSI_CHARSET, // nCharSet
  1518. OUT_DEFAULT_PRECIS, // nOutPrecision
  1519. CLIP_DEFAULT_PRECIS, // nClipPrecision
  1520. DEFAULT_QUALITY, // nQuality
  1521. DEFAULT_PITCH | FF_DONTCARE, // nPitchAndFamily
  1522. _T("MS Shell Dlg") // lpszFaceName
  1523. );
  1524. } //*** BCreateFont
  1525. /////////////////////////////////////////////////////////////////////////////
  1526. //++
  1527. //
  1528. // NewNodeWizard
  1529. //
  1530. // Routine Description:
  1531. // Invoke the Add Nodes to Cluster Wizard.
  1532. //
  1533. // Arguments:
  1534. // pcszName -- Name of cluster to add nodes to.
  1535. // fIgnoreErrors -- TRUE = don't display error messages.
  1536. // Defaults to FALSE.
  1537. //
  1538. // Return Value:
  1539. // None.
  1540. //
  1541. //--
  1542. /////////////////////////////////////////////////////////////////////////////
  1543. void NewNodeWizard(
  1544. LPCTSTR pcszName,
  1545. BOOL fIgnoreErrors // = FALSE
  1546. )
  1547. {
  1548. HRESULT hr = S_OK;
  1549. IClusCfgAddNodesWizard * piWiz = NULL;
  1550. BSTR bstrConnectName = NULL;
  1551. VARIANT_BOOL fCommitted = VARIANT_FALSE;
  1552. // Get an interface pointer for the wizard.
  1553. hr = CoCreateInstance(
  1554. CLSID_ClusCfgAddNodesWizard,
  1555. NULL,
  1556. CLSCTX_INPROC_SERVER,
  1557. IID_IClusCfgAddNodesWizard,
  1558. (void **) &piWiz
  1559. );
  1560. if ( FAILED( hr ) )
  1561. {
  1562. if ( ! fIgnoreErrors )
  1563. {
  1564. CNTException nte( hr, IDS_CREATE_CLUSCFGWIZ_OBJ_ERROR, NULL, NULL, FALSE /*bAutoDelete*/ );
  1565. nte.ReportError();
  1566. }
  1567. return;
  1568. } // if: error getting the interface pointer
  1569. // Specify the name of the cluster we are going to add a node to.
  1570. bstrConnectName = SysAllocString( pcszName );
  1571. if ( bstrConnectName == NULL )
  1572. {
  1573. AfxThrowMemoryException();
  1574. }
  1575. hr = piWiz->put_ClusterName( bstrConnectName );
  1576. if ( FAILED( hr ) )
  1577. {
  1578. if ( ! fIgnoreErrors )
  1579. {
  1580. CNTException nte( hr, IDS_ADD_NODES_TO_CLUSTER_ERROR, bstrConnectName, NULL, FALSE /*bAutoDelete*/ );
  1581. nte.ReportError();
  1582. }
  1583. } // if: error setting the cluster name
  1584. // Display the wizard.
  1585. hr = piWiz->ShowWizard( HandleToLong( AfxGetMainWnd()->m_hWnd ), &fCommitted );
  1586. if ( FAILED( hr ) )
  1587. {
  1588. if ( ! fIgnoreErrors )
  1589. {
  1590. CNTException nte( hr, IDS_ADD_NODES_TO_CLUSTER_ERROR, bstrConnectName, NULL, FALSE /*bAutoDelete*/ );
  1591. nte.ReportError();
  1592. }
  1593. } // if: error adding cluster nodes
  1594. SysFreeString( bstrConnectName );
  1595. piWiz->Release();
  1596. } //*** NewNodeWizard
  1597. /////////////////////////////////////////////////////////////////////////////
  1598. //++
  1599. //
  1600. // GetClusterInformation
  1601. //
  1602. // Routine Description:
  1603. // Given a cluster handle, retrieve the cluster's hostname label and
  1604. // version information.
  1605. //
  1606. // Arguments:
  1607. // hClusterIn
  1608. // Handle to the cluster; must not be null.
  1609. //
  1610. // rstrNameOut
  1611. // On return, the cluster's hostname label.
  1612. //
  1613. // pcviOut
  1614. // Address for cluster's version info on return; can be null if
  1615. // the caller doesn't care.
  1616. //
  1617. // Return Value:
  1618. // None.
  1619. //
  1620. // Remarks:
  1621. // Throws an exception on failure.
  1622. //
  1623. //--
  1624. /////////////////////////////////////////////////////////////////////////////
  1625. void GetClusterInformation( HCLUSTER hClusterIn, CString& rstrNameOut, PCLUSTERVERSIONINFO pcviOut )
  1626. {
  1627. DWORD cchName = MAX_CLUSTERNAME_LENGTH; // Just a guess for the first try.
  1628. DWORD cchNameStash = cchName;
  1629. CString strClusterName;
  1630. DWORD scClusterInfo = ERROR_SUCCESS;
  1631. ASSERT( hClusterIn != NULL );
  1632. if ( pcviOut != NULL )
  1633. {
  1634. pcviOut->dwVersionInfoSize = sizeof( *pcviOut );
  1635. }
  1636. scClusterInfo = GetClusterInformation( hClusterIn, strClusterName.GetBuffer( cchName ), &cchName, pcviOut );
  1637. strClusterName.ReleaseBuffer( cchNameStash );
  1638. if ( scClusterInfo == ERROR_MORE_DATA )
  1639. {
  1640. cchNameStash = ++cchName; // KLUDGE: ++ because GetClusterInformation is STOOPID.
  1641. scClusterInfo = GetClusterInformation( hClusterIn, strClusterName.GetBuffer( cchName ), &cchName, pcviOut );
  1642. strClusterName.ReleaseBuffer( cchNameStash );
  1643. }
  1644. if ( scClusterInfo != ERROR_SUCCESS )
  1645. {
  1646. ThrowStaticException( scClusterInfo );
  1647. }
  1648. rstrNameOut = strClusterName;
  1649. } //*** GetClusterInformation
  1650. /////////////////////////////////////////////////////////////////////////////
  1651. //++
  1652. //
  1653. // StrGetClusterName
  1654. //
  1655. // Routine Description:
  1656. // Given a cluster handle, retrieve the cluster's FQDN if possible,
  1657. // or its IP address if not.
  1658. //
  1659. // Arguments:
  1660. // hClusterIn
  1661. // Handle to the cluster; must not be null.
  1662. //
  1663. // Return Value:
  1664. // The cluster's FQDN or its IP address.
  1665. //
  1666. // Remarks:
  1667. // Throws an exception on failure. To retrieve just the cluster's
  1668. // hostname label, use GetClusterInformation
  1669. //
  1670. //--
  1671. /////////////////////////////////////////////////////////////////////////////
  1672. CString StrGetClusterName( HCLUSTER hClusterIn )
  1673. {
  1674. CString strClusterName;
  1675. DWORD cchName = DNS_MAX_NAME_LENGTH;
  1676. DWORD sc = ERROR_SUCCESS;
  1677. ASSERT( hClusterIn != NULL );
  1678. //
  1679. // First, try to get the FQDN.
  1680. //
  1681. {
  1682. DWORD cbFQDN = cchName * sizeof( TCHAR );
  1683. DWORD cbBytesRequired = 0;
  1684. sc = ClusterControl(
  1685. hClusterIn,
  1686. NULL,
  1687. CLUSCTL_CLUSTER_GET_FQDN,
  1688. NULL,
  1689. NULL,
  1690. strClusterName.GetBuffer( cchName ),
  1691. cbFQDN,
  1692. &cbBytesRequired
  1693. );
  1694. strClusterName.ReleaseBuffer( cchName );
  1695. if ( sc == ERROR_MORE_DATA )
  1696. {
  1697. cchName = ( cbBytesRequired / sizeof( TCHAR ) ) + 1;
  1698. cbFQDN = cchName * sizeof( TCHAR );
  1699. sc = ClusterControl(
  1700. hClusterIn,
  1701. NULL,
  1702. CLUSCTL_CLUSTER_GET_FQDN,
  1703. NULL,
  1704. NULL,
  1705. strClusterName.GetBuffer( cchName ),
  1706. cbFQDN,
  1707. &cbBytesRequired
  1708. );
  1709. strClusterName.ReleaseBuffer( cchName );
  1710. }
  1711. }
  1712. //
  1713. // If ClusterControl returned ERROR_INVALID_FUNCTION, it's probably Win2k, so
  1714. // make do with just the hostname label; if it failed for some other reason,
  1715. // try to get the IP address.
  1716. //
  1717. if ( sc == ERROR_INVALID_FUNCTION )
  1718. {
  1719. GetClusterInformation( hClusterIn, strClusterName, NULL );
  1720. }
  1721. else if ( sc != ERROR_SUCCESS )
  1722. {
  1723. HRESOURCE hIPResource = NULL;
  1724. CClusPropList cpl;
  1725. CLUSPROP_BUFFER_HELPER cpbh;
  1726. sc = ResUtilGetCoreClusterResources( hClusterIn, NULL, &hIPResource, NULL );
  1727. if ( sc != ERROR_SUCCESS )
  1728. ThrowStaticException( sc );
  1729. sc = cpl.ScGetResourceProperties( hIPResource, CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES );
  1730. if ( sc != ERROR_SUCCESS )
  1731. ThrowStaticException( sc );
  1732. sc = cpl.ScMoveToPropertyByName( L"Address" );
  1733. if ( sc != ERROR_SUCCESS )
  1734. ThrowStaticException( sc );
  1735. cpbh = cpl.CbhCurrentValue();
  1736. ASSERT( cpbh.pSyntax->dw == CLUSPROP_SYNTAX_LIST_VALUE_SZ );
  1737. strClusterName = cpbh.pStringValue->sz;
  1738. }
  1739. return strClusterName;
  1740. } //*** StrGetClusterName