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

756 lines
22 KiB

  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 2000 Microsoft Corporation
  4. //
  5. // Module Name:
  6. // StartupNotify.cpp
  7. //
  8. // Description:
  9. // This file contains the implementation of the CStartupNotify
  10. // class.
  11. //
  12. // Documentation:
  13. // TODO: fill in pointer to external documentation
  14. //
  15. // Header File:
  16. // StartupNotify.h
  17. //
  18. // Maintained By:
  19. // Vij Vasu (VVasu) 15-JUN-2000
  20. //
  21. //////////////////////////////////////////////////////////////////////////////
  22. //////////////////////////////////////////////////////////////////////////////
  23. // Include Files
  24. //////////////////////////////////////////////////////////////////////////////
  25. // The precompiled header for this library
  26. #include "pch.h"
  27. // The header file for this class
  28. #include "StartupNotify.h"
  29. // For POSTCONFIG_COMPLETE_EVENT_NAME
  30. #include "EventName.h"
  31. //////////////////////////////////////////////////////////////////////////////
  32. // Macro Definitions
  33. //////////////////////////////////////////////////////////////////////////////
  34. DEFINE_THISCLASS( "CStartupNotify" );
  35. //////////////////////////////////////////////////////////////////////////////
  36. //++
  37. //
  38. // CStartupNotify::CStartupNotify()
  39. //
  40. // Description:
  41. // Constructor of the CStartupNotify class. This initializes
  42. // the m_cRef variable to 1 instead of 0 to account of possible
  43. // QueryInterface failure in DllGetClassObject.
  44. //
  45. // Arguments:
  46. // None.
  47. //
  48. // Return Value:
  49. // None.
  50. //
  51. // Remarks:
  52. // None.
  53. //
  54. //--
  55. //////////////////////////////////////////////////////////////////////////////
  56. CStartupNotify::CStartupNotify( void )
  57. : m_cRef( 1 )
  58. {
  59. TraceFunc( "" );
  60. // Increment the count of components in memory so the DLL hosting this
  61. // object cannot be unloaded.
  62. InterlockedIncrement( &g_cObjects );
  63. TraceFlow1( "Component count = %d.", g_cObjects );
  64. TraceFuncExit();
  65. } //*** CStartupNotify::CStartupNotify
  66. //////////////////////////////////////////////////////////////////////////////
  67. //++
  68. //
  69. // CStartupNotify::~CStartupNotify()
  70. //
  71. // Description:
  72. // Destructor of the CStartupNotify class.
  73. //
  74. // Arguments:
  75. // None.
  76. //
  77. // Return Value:
  78. // None.
  79. //
  80. // Remarks:
  81. // None.
  82. //
  83. //--
  84. //////////////////////////////////////////////////////////////////////////////
  85. CStartupNotify::~CStartupNotify( void )
  86. {
  87. TraceFunc( "" );
  88. // There's going to be one less component in memory. Decrement component count.
  89. InterlockedDecrement( &g_cObjects );
  90. TraceFlow1( "Component count = %d.", g_cObjects );
  91. TraceFuncExit();
  92. } //*** CStartupNotify::~CStartupNotify
  93. //////////////////////////////////////////////////////////////////////////////
  94. //++
  95. //
  96. // HRESULT
  97. // CStartupNotify::S_HrCreateInstance(
  98. // IUnknown ** ppunkOut
  99. // )
  100. //
  101. // Description:
  102. // Creates a CStartupNotify instance.
  103. //
  104. // Arguments:
  105. // ppunkOut
  106. // The IUnknown interface of the new object.
  107. //
  108. // Return Values:
  109. // S_OK
  110. // Success.
  111. //
  112. // E_OUTOFMEMORY
  113. // Not enough memory to create the object.
  114. //
  115. // other HRESULTs
  116. // Object initialization failed.
  117. //
  118. //--
  119. //////////////////////////////////////////////////////////////////////////////
  120. HRESULT
  121. CStartupNotify::S_HrCreateInstance( IUnknown ** ppunkOut )
  122. {
  123. TraceFunc( "" );
  124. HRESULT hr = E_INVALIDARG;
  125. CStartupNotify * pStartupNotify = NULL;
  126. do
  127. {
  128. // Allocate memory for the new object.
  129. pStartupNotify = new CStartupNotify();
  130. if ( pStartupNotify == NULL )
  131. {
  132. LogMsg( "Could not allocate memory for a evict cleanup object." );
  133. TraceFlow( "Could not allocate memory for a evict cleanup object." );
  134. hr = THR( E_OUTOFMEMORY );
  135. break;
  136. } // if: out of memory
  137. hr = THR( pStartupNotify->QueryInterface( IID_IUnknown, reinterpret_cast< void ** >( ppunkOut ) ) );
  138. TraceFlow1( "*ppunkOut = %#X.", *ppunkOut );
  139. }
  140. while( false ); // dummy do-while loop to avoid gotos.
  141. if ( pStartupNotify != NULL )
  142. {
  143. pStartupNotify->Release();
  144. } // if: the pointer to the notification object is not NULL
  145. HRETURN( hr );
  146. } //*** CStartupNotify::S_HrCreateInstance()
  147. //////////////////////////////////////////////////////////////////////////////
  148. //++
  149. //
  150. // STDMETHODIMP_( ULONG )
  151. // CStartupNotify::AddRef()
  152. //
  153. // Description:
  154. // Increment the reference count of this object by one.
  155. //
  156. // Arguments:
  157. // None.
  158. //
  159. // Return Value:
  160. // The new reference count.
  161. //
  162. // Remarks:
  163. // None.
  164. //
  165. //--
  166. //////////////////////////////////////////////////////////////////////////////
  167. STDMETHODIMP_( ULONG )
  168. CStartupNotify::AddRef( void )
  169. {
  170. TraceFunc( "[IUnknown]" );
  171. InterlockedIncrement( &m_cRef );
  172. TraceFlow1( "m_cRef = %d", m_cRef );
  173. RETURN( m_cRef );
  174. } //*** CStartupNotify::AddRef()
  175. //////////////////////////////////////////////////////////////////////////////
  176. //++
  177. //
  178. // STDMETHODIMP_( ULONG )
  179. // CStartupNotify::Release()
  180. //
  181. // Description:
  182. // Decrement the reference count of this object by one.
  183. //
  184. // Arguments:
  185. // None.
  186. //
  187. // Return Value:
  188. // The new reference count.
  189. //
  190. // Remarks:
  191. // None.
  192. //
  193. //--
  194. //////////////////////////////////////////////////////////////////////////////
  195. STDMETHODIMP_( ULONG )
  196. CStartupNotify::Release( void )
  197. {
  198. TraceFunc( "[IUnknown]" );
  199. InterlockedDecrement( &m_cRef );
  200. TraceFlow1( "m_cRef = %d", m_cRef );
  201. if ( m_cRef == 0 )
  202. {
  203. TraceDo( delete this );
  204. RETURN( 0 );
  205. } // if: reference count decremented to zero
  206. RETURN( m_cRef );
  207. } //*** CStartupNotify::Release()
  208. //////////////////////////////////////////////////////////////////////////////
  209. //++
  210. //
  211. // STDMETHODIMP
  212. // CStartupNotify::QueryInterface()
  213. //
  214. // Description:
  215. // Decrement the reference count of this object by one.
  216. //
  217. // Arguments:
  218. // IN REFIID riid
  219. // Id of interface requested.
  220. //
  221. // OUT void ** ppv
  222. // Pointer to the requested interface.
  223. //
  224. // Return Value:
  225. // S_OK
  226. // If the interface is available on this object.
  227. //
  228. // E_NOINTERFACE
  229. // If the interface is not available.
  230. //
  231. // Remarks:
  232. // None.
  233. //
  234. //--
  235. //////////////////////////////////////////////////////////////////////////////
  236. STDMETHODIMP
  237. CStartupNotify::QueryInterface( REFIID riid, void ** ppv )
  238. {
  239. TraceQIFunc( riid, ppv );
  240. HRESULT hr = S_OK;
  241. if ( ppv != NULL )
  242. {
  243. if ( IsEqualIID( riid, IID_IUnknown ) )
  244. {
  245. *ppv = static_cast< IClusCfgStartupNotify * >( this );
  246. } // if: IUnknown
  247. else if ( IsEqualIID( riid, IID_IClusCfgStartupNotify ) )
  248. {
  249. *ppv = TraceInterface( __THISCLASS__, IClusCfgStartupNotify, this, 0 );
  250. } // else if:
  251. else
  252. {
  253. hr = E_NOINTERFACE;
  254. } // else
  255. if ( SUCCEEDED( hr ) )
  256. {
  257. ((IUnknown *) *ppv)->AddRef( );
  258. } // if: success
  259. else
  260. {
  261. *ppv = NULL;
  262. } // else: something failed
  263. } // if: the output pointer was valid
  264. else
  265. {
  266. hr = E_INVALIDARG;
  267. } // else: the output pointer is invalid
  268. QIRETURN( hr, riid );
  269. } //*** CStartupNotify::QueryInterface()
  270. //////////////////////////////////////////////////////////////////////////////
  271. //++
  272. //
  273. // CStartupNotify::SendNotifications()
  274. //
  275. // Description:
  276. // This method is called by the Cluster Service to inform the implementor
  277. // of this interface to send out notification of cluster service startup
  278. // to interested listeners. If this method is being called for the first
  279. // time, the method waits till the post configuration steps are complete
  280. // before sending out the notifications.
  281. //
  282. // Arguments:
  283. // None.
  284. //
  285. // Return Values:
  286. // S_OK
  287. // Success.
  288. //
  289. // Other HRESULTs
  290. // The call failed.
  291. //
  292. //--
  293. //////////////////////////////////////////////////////////////////////////////
  294. STDMETHODIMP
  295. CStartupNotify::SendNotifications( void )
  296. {
  297. TraceFunc( "[IClusCfgStartupNotify]" );
  298. HRESULT hr = S_OK;
  299. HANDLE heventPostCfgCompletion = NULL;
  300. do
  301. {
  302. //
  303. // If the cluster service is being started for the first time, as a part
  304. // of adding this node to a cluster (forming or joining), then we have
  305. // to wait till the post-configuration steps are completed before we
  306. // can send out notifications.
  307. //
  308. TraceFlow1( "Trying to create an event named '%s'.", POSTCONFIG_COMPLETE_EVENT_NAME );
  309. // Create an event in the signalled state. If this event already existed
  310. // we get a handle to that event, and the state of the event is not changed.
  311. heventPostCfgCompletion = CreateEvent(
  312. NULL // event security attributes
  313. , TRUE // manual-reset event
  314. , TRUE // create in signaled state
  315. , POSTCONFIG_COMPLETE_EVENT_NAME
  316. );
  317. if ( heventPostCfgCompletion == NULL )
  318. {
  319. hr = HRESULT_FROM_WIN32( TW32( GetLastError() ) );
  320. LogMsg( "Error %#x occurred trying to create an event named '%s'.", hr, POSTCONFIG_COMPLETE_EVENT_NAME );
  321. TraceFlow2( "Error %#x occurred trying to create an event named '%s'.", hr, POSTCONFIG_COMPLETE_EVENT_NAME );
  322. break;
  323. } // if: we could not get a handle to the event
  324. TraceFlow( "Waiting for the event to be signaled." );
  325. //
  326. // Now, wait for this event to be signaled. If this method was called due to this
  327. // node being part of a cluster, this event would have been created in the unsignaled state
  328. // by the cluster configuration server. However, if this was not the first time that
  329. // the cluster service is starting on this node, the event would have been created in the
  330. // signaled state above, and so, the wait below will exit immediately.
  331. //
  332. do
  333. {
  334. DWORD dwStatus;
  335. // Wait for any message sent or posted to this queue
  336. // or for our event to be signaled.
  337. dwStatus = MsgWaitForMultipleObjects(
  338. 1
  339. , &heventPostCfgCompletion
  340. , FALSE
  341. , 900000 // If no one has signaled this event in 15 minutes, abort.
  342. , QS_ALLINPUT
  343. );
  344. // The result tells us the type of event we have.
  345. if ( dwStatus == ( WAIT_OBJECT_0 + 1 ) )
  346. {
  347. MSG msg;
  348. // Read all of the messages in this next loop,
  349. // removing each message as we read it.
  350. while ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) != 0 )
  351. {
  352. // If it is a quit message, we are done pumping messages.
  353. if ( msg.message == WM_QUIT)
  354. {
  355. TraceFlow( "Get a WM_QUIT message. Exit message pump loop." );
  356. break;
  357. } // if: we got a WM_QUIT message
  358. // Otherwise, dispatch the message.
  359. DispatchMessage( &msg );
  360. } // while: there are still messages in the window message queue
  361. } // if: we have a message in the window message queue
  362. else
  363. {
  364. if ( dwStatus == WAIT_OBJECT_0 )
  365. {
  366. TraceFlow( "Our event has been signaled. Exiting wait loop." );
  367. break;
  368. } // else if: our event is signaled
  369. else
  370. {
  371. if ( dwStatus == -1 )
  372. {
  373. hr = HRESULT_FROM_WIN32( TW32( GetLastError() ) );
  374. LogMsg( "Error %#x occurred trying to wait for an event to be signaled.", hr );
  375. TraceFlow1( "Error %#x occurred trying to wait for an event to be signaled.", hr );
  376. } // if: MsgWaitForMultipleObjects() returned an error
  377. else
  378. {
  379. hr = THR( HRESULT_FROM_WIN32( dwStatus ) );
  380. LogMsg( "An error occurred trying to wait for an event to be signaled. Status code is %d.", dwStatus );
  381. TraceFlow1( "An error occurred trying to wait for an event to be signaled. Status code is %d.", dwStatus );
  382. } // else: an unexpected value was returned by MsgWaitForMultipleObjects()
  383. break;
  384. } // else: an unexpected result
  385. } // else: MsgWaitForMultipleObjects() exited for a reason other than a waiting message
  386. }
  387. while( true ); // do-while: loop infinitely
  388. if ( FAILED( hr ) )
  389. {
  390. TraceFlow( "Something went wrong trying to wait for the event to be signaled." );
  391. break;
  392. } // if: something has gone wrong
  393. TraceFlow( "Our event has been signaled. Proceed with the notifications." );
  394. // Send out the notifications
  395. hr = THR( HrNotifyListeners() );
  396. if ( FAILED( hr ) )
  397. {
  398. TraceFlow1( "Error %#x occurred trying to notify cluster startup listeners.", hr );
  399. LogMsg( "Error %#x occurred trying to notify cluster startup listeners.", hr );
  400. break;
  401. } // if: something went wrong while sending out notifications
  402. TraceFlow( "Sending of cluster startup notifications complete." );
  403. LogMsg( "Sending of cluster startup notifications complete." );
  404. }
  405. while( false ); // dummy do-while loop to avoid gotos
  406. //
  407. // Clean up
  408. //
  409. if ( heventPostCfgCompletion != NULL )
  410. {
  411. CloseHandle( heventPostCfgCompletion );
  412. } // if: we had created the event
  413. HRETURN( hr );
  414. } //*** CStartupNotify::SendNotifications()
  415. //////////////////////////////////////////////////////////////////////////////
  416. //++
  417. //
  418. // HRESULT
  419. // CStartupNotify::HrNotifyListeners
  420. //
  421. // Description:
  422. // Enumerate all components on the local computer registered for cluster
  423. // startup notification.
  424. //
  425. // Arguments:
  426. // None.
  427. //
  428. // Return Values:
  429. // S_OK
  430. // Success.
  431. //
  432. // other HRESULTs
  433. // Something went wrong during the enumeration.
  434. //
  435. //--
  436. //////////////////////////////////////////////////////////////////////////////
  437. HRESULT
  438. CStartupNotify::HrNotifyListeners( void )
  439. {
  440. TraceFunc( "" );
  441. const UINT uiCHUNK_SIZE = 16;
  442. HRESULT hr = S_OK;
  443. ICatInformation * pciCatInfo = NULL;
  444. IEnumCLSID * psleStartupListenerClsidEnum = NULL;
  445. IUnknown * punkResTypeServices = NULL;
  446. do
  447. {
  448. ULONG cReturned = 0;
  449. CATID rgCatIdsImplemented[ 1 ];
  450. rgCatIdsImplemented[ 0 ] = CATID_ClusCfgStartupListeners;
  451. //
  452. // Enumerate all the enumerators registered in the
  453. // CATID_ClusCfgStartupListeners category
  454. //
  455. hr = THR(
  456. CoCreateInstance(
  457. CLSID_StdComponentCategoriesMgr
  458. , NULL
  459. , CLSCTX_SERVER
  460. , IID_ICatInformation
  461. , reinterpret_cast< void ** >( &pciCatInfo )
  462. )
  463. );
  464. if ( FAILED( hr ) )
  465. {
  466. TraceFlow1( "Error %#x occurred trying to get a pointer to the enumerator of the CATID_ClusCfgStartupListeners category.", hr );
  467. LogMsg( "Error %#x occurred trying to get a pointer to the enumerator of the CATID_ClusCfgStartupListeners category.", hr );
  468. break;
  469. } // if: we could not get a pointer to the ICatInformation interface
  470. // Get a pointer to the enumerator of the CLSIDs that belong to the CATID_ClusCfgStartupListeners category.
  471. hr = THR(
  472. pciCatInfo->EnumClassesOfCategories(
  473. 1
  474. , rgCatIdsImplemented
  475. , 0
  476. , NULL
  477. , &psleStartupListenerClsidEnum
  478. )
  479. );
  480. if ( FAILED( hr ) )
  481. {
  482. TraceFlow1( "Error %#x occurred trying to get a pointer to the enumerator of the CATID_ClusCfgStartupListeners category.", hr );
  483. LogMsg( "Error %#x occurred trying to get a pointer to the enumerator of the CATID_ClusCfgStartupListeners category.", hr );
  484. break;
  485. } // if: we could not get a pointer to the IEnumCLSID interface
  486. //
  487. // Create an instance of the resource type services component
  488. //
  489. hr = THR(
  490. CoCreateInstance(
  491. CLSID_ClusCfgResTypeServices
  492. , NULL
  493. , CLSCTX_INPROC_SERVER
  494. , __uuidof( punkResTypeServices )
  495. , reinterpret_cast< void ** >( &punkResTypeServices )
  496. )
  497. );
  498. if ( FAILED( hr ) )
  499. {
  500. TraceFlow1( "Error %#x occurred trying to create the resource type services component.", hr );
  501. LogMsg( "Error %#x occurred trying to create the resource type services component.", hr );
  502. break;
  503. } // if: we could not create the resource type services component
  504. // Enumerate the CLSIDs of the registered startup listeners
  505. do
  506. {
  507. CLSID rgStartupListenerClsids[ uiCHUNK_SIZE ];
  508. ULONG idxCLSID;
  509. cReturned = 0;
  510. hr = STHR(
  511. psleStartupListenerClsidEnum->Next(
  512. uiCHUNK_SIZE
  513. , rgStartupListenerClsids
  514. , &cReturned
  515. )
  516. );
  517. if ( FAILED( hr ) )
  518. {
  519. TraceFlow1( "Error %#x occurred trying enumerate startup listener components.", hr );
  520. LogMsg( "Error %#x occurred trying enumerate startup listener components.", hr );
  521. break;
  522. } // if: we could not get the next set of CLSIDs
  523. // hr may be S_FALSE here, so reset it.
  524. hr = S_OK;
  525. for ( idxCLSID = 0; idxCLSID < cReturned; ++idxCLSID )
  526. {
  527. hr = THR( HrProcessListener( rgStartupListenerClsids[ idxCLSID ], punkResTypeServices ) );
  528. if ( FAILED( hr ) )
  529. {
  530. // The processing of one of the listeners failed.
  531. // Log the error, but continue processing other listeners.
  532. TraceFlow1( "Error %#x occurred trying to process a cluster startup listener. Other listeners will be processed.", hr );
  533. TraceMsgGUID( mtfALWAYS, "The CLSID of the failed listener is ", rgStartupListenerClsids[ idxCLSID ] );
  534. LogMsg( "Error %#x occurred trying to process a cluster startup listener. Other listeners will be processed.", hr );
  535. hr = S_OK;
  536. } // if: this enumerator failed
  537. } // for: iterate through the returned CLSIDs
  538. }
  539. while( cReturned > 0 ); // while: there are still CLSIDs to be enumerated
  540. if ( FAILED( hr ) )
  541. {
  542. break;
  543. } // if: something went wrong in the loop above
  544. }
  545. while( false ); // dummy do-while loop to avoid gotos.
  546. //
  547. // Cleanup code
  548. //
  549. if ( pciCatInfo != NULL )
  550. {
  551. pciCatInfo->Release();
  552. } // if: we had obtained a pointer to the ICatInformation interface
  553. if ( psleStartupListenerClsidEnum != NULL )
  554. {
  555. psleStartupListenerClsidEnum->Release();
  556. } // if: we had obtained a pointer to the enumerator of startup listener CLSIDs
  557. if ( punkResTypeServices != NULL )
  558. {
  559. punkResTypeServices->Release();
  560. } // if: we had created the resource type services component
  561. HRETURN( hr );
  562. } //*** CStartupNotify::HrNotifyListeners()
  563. //////////////////////////////////////////////////////////////////////////////
  564. //++
  565. //
  566. // HRESULT
  567. // CStartupNotify::HrProcessListener
  568. //
  569. // Description:
  570. // This function instantiates a cluster startup listener component
  571. // and calls the appropriate methods.
  572. //
  573. // Arguments:
  574. // rclsidListenerCLSIDIn
  575. // CLSID of the startup listener component
  576. //
  577. // punkResTypeServicesIn
  578. // Pointer to the IUnknown interface on the resource type services
  579. // component. This interface provides methods that help configure
  580. // resource types.
  581. //
  582. // Return Values:
  583. // S_OK
  584. // Success.
  585. //
  586. // other HRESULTs
  587. // Something went wrong during the processing of the listener.
  588. //
  589. //--
  590. //////////////////////////////////////////////////////////////////////////////
  591. HRESULT
  592. CStartupNotify::HrProcessListener(
  593. const CLSID & rclsidListenerCLSIDIn
  594. , IUnknown * punkResTypeServicesIn
  595. )
  596. {
  597. TraceFunc( "" );
  598. HRESULT hr = S_OK;
  599. IClusCfgStartupListener * pcslStartupListener = NULL;
  600. TraceMsgGUID( mtfALWAYS, "The CLSID of this startup listener is ", rclsidListenerCLSIDIn );
  601. do
  602. {
  603. //
  604. // Create the component represented by the CLSID passed in
  605. //
  606. hr = THR(
  607. CoCreateInstance(
  608. rclsidListenerCLSIDIn
  609. , NULL
  610. , CLSCTX_INPROC_SERVER
  611. , __uuidof( pcslStartupListener )
  612. , reinterpret_cast< void ** >( &pcslStartupListener )
  613. )
  614. );
  615. if ( FAILED( hr ) )
  616. {
  617. TraceFlow1( "Error %#x occurred trying to create the cluster startup listener component.", hr );
  618. LogMsg( "Error %#x occurred trying to create a cluster startup listener component.", hr );
  619. break;
  620. } // if: we could not create the cluster startup listener component
  621. // Notify this listener.
  622. hr = THR( pcslStartupListener->Notify( punkResTypeServicesIn ) );
  623. if ( FAILED( hr ) )
  624. {
  625. TraceFlow1( "Error %#x occurred trying to notify this startup listener.", hr );
  626. LogMsg( "Error %#x occurred trying to notify a cluster startup listener.", hr );
  627. break;
  628. } // if: this notification
  629. }
  630. while( false ); // dummy do-while loop to avoid gotos.
  631. //
  632. // Cleanup code
  633. //
  634. if ( pcslStartupListener != NULL )
  635. {
  636. pcslStartupListener->Release();
  637. } // if: we had obtained a pointer to the startup listener interface
  638. HRETURN( hr );
  639. } //*** CStartupNotify::HrProcessListener()