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.

812 lines
20 KiB

  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 2000-2001 Microsoft Corporation
  4. //
  5. // Module Name:
  6. // TaskGatherNodeInfo.cpp
  7. //
  8. // Description:
  9. // CTaskGatherNodeInfo implementation.
  10. //
  11. // Maintained By:
  12. // Galen Barbee (GalenB) 02-FEB-2000
  13. //
  14. //////////////////////////////////////////////////////////////////////////////
  15. #include "pch.h"
  16. #include "TaskGatherNodeInfo.h"
  17. DEFINE_THISCLASS("CTaskGatherNodeInfo")
  18. //
  19. // Failure code.
  20. //
  21. #define SSR_FAILURE( _minor, _hr ) THR( SendStatusReport( m_bstrName, TASKID_Major_Client_And_Server_Log, _minor, 0, 1, 1, _hr, NULL, NULL, NULL ) );
  22. // ************************************************************************
  23. //
  24. // Constructor / Destructor
  25. //
  26. // ************************************************************************
  27. //////////////////////////////////////////////////////////////////////////////
  28. //
  29. // HRESULT
  30. // CTaskGatherNodeInfo::S_HrCreateInstance(
  31. // IUnknown ** ppunkOut
  32. // )
  33. //
  34. //////////////////////////////////////////////////////////////////////////////
  35. HRESULT
  36. CTaskGatherNodeInfo::S_HrCreateInstance(
  37. IUnknown ** ppunkOut
  38. )
  39. {
  40. TraceFunc( "" );
  41. Assert( ppunkOut != NULL );
  42. HRESULT hr;
  43. CTaskGatherNodeInfo * ptgni = new CTaskGatherNodeInfo;
  44. if ( ptgni != NULL )
  45. {
  46. hr = THR( ptgni->Init() );
  47. if ( SUCCEEDED( hr ) )
  48. {
  49. hr = THR( ptgni->TypeSafeQI( IUnknown, ppunkOut ) );
  50. }
  51. ptgni->Release();
  52. // This gets passed to other threads.
  53. TraceMoveToMemoryList( ptgni, g_GlobalMemoryList );
  54. }
  55. else
  56. {
  57. hr = E_OUTOFMEMORY;
  58. }
  59. HRETURN( hr );
  60. } // S_HrCreateInstance()
  61. //////////////////////////////////////////////////////////////////////////////
  62. //
  63. // CTaskGatherNodeInfo::CTaskGatherNodeInfo( void )
  64. //
  65. //////////////////////////////////////////////////////////////////////////////
  66. CTaskGatherNodeInfo::CTaskGatherNodeInfo( void )
  67. {
  68. TraceFunc( "" );
  69. InterlockedIncrement( &g_cObjects );
  70. TraceFuncExit();
  71. } // CTaskGatherNodeInfo()
  72. //////////////////////////////////////////////////////////////////////////////
  73. //
  74. // STDMETHODIMP
  75. // CTaskGatherNodeInfo::Init( void )
  76. //
  77. //////////////////////////////////////////////////////////////////////////////
  78. STDMETHODIMP
  79. CTaskGatherNodeInfo::Init( void )
  80. {
  81. TraceFunc( "" );
  82. HRESULT hr = S_OK;
  83. // IUnknown stuff
  84. Assert( m_cRef == 0 );
  85. AddRef(); // Add one count
  86. // IDoTask / ITaskGatherNodeInfo
  87. Assert( m_cookie == NULL );
  88. Assert( m_cookieCompletion == NULL );
  89. Assert( m_bstrName == NULL );
  90. // IClusCfgCallback
  91. Assert( m_pcccb == NULL );
  92. HRETURN( hr );
  93. } // Init()
  94. //////////////////////////////////////////////////////////////////////////////
  95. //
  96. // CTaskGatherNodeInfo::~CTaskGatherNodeInfo()
  97. //
  98. //////////////////////////////////////////////////////////////////////////////
  99. CTaskGatherNodeInfo::~CTaskGatherNodeInfo()
  100. {
  101. TraceFunc( "" );
  102. if ( m_pcccb != NULL )
  103. {
  104. m_pcccb->Release();
  105. }
  106. TraceSysFreeString( m_bstrName );
  107. //
  108. // This keeps the per thread memory tracking from screaming.
  109. //
  110. TraceMoveFromMemoryList( this, g_GlobalMemoryList );
  111. InterlockedDecrement( &g_cObjects );
  112. TraceFuncExit();
  113. } // ~CTaskGatherNodeInfo()
  114. // ************************************************************************
  115. //
  116. // IUnknown
  117. //
  118. // ************************************************************************
  119. //////////////////////////////////////////////////////////////////////////////
  120. //
  121. // STDMETHODIMP
  122. // CTaskGatherNodeInfo::QueryInterface(
  123. // REFIID riid,
  124. // LPVOID *ppv
  125. // )
  126. //
  127. //////////////////////////////////////////////////////////////////////////////
  128. STDMETHODIMP
  129. CTaskGatherNodeInfo::QueryInterface(
  130. REFIID riid,
  131. LPVOID *ppv
  132. )
  133. {
  134. TraceQIFunc( riid, ppv );
  135. HRESULT hr = E_NOINTERFACE;
  136. if ( IsEqualIID( riid, IID_IUnknown ) )
  137. {
  138. *ppv = static_cast< ITaskGatherNodeInfo * >( this );
  139. hr = S_OK;
  140. } // if: IUnknown
  141. else if ( IsEqualIID( riid, IID_IDoTask ) )
  142. {
  143. *ppv = TraceInterface( __THISCLASS__, IDoTask, this, 0 );
  144. hr = S_OK;
  145. } // else if: IDoTask
  146. else if ( IsEqualIID( riid, IID_ITaskGatherNodeInfo ) )
  147. {
  148. *ppv = TraceInterface( __THISCLASS__, ITaskGatherNodeInfo, this, 0 );
  149. hr = S_OK;
  150. } // else if: ITaskGatherNodeInfo
  151. if ( SUCCEEDED( hr ) )
  152. {
  153. ((IUnknown*) *ppv)->AddRef();
  154. } // if: success
  155. QIRETURN_IGNORESTDMARSHALLING( hr, riid );
  156. } // QueryInterface()
  157. //////////////////////////////////////////////////////////////////////////////
  158. //
  159. // STDMETHODIMP_(ULONG)
  160. // CTaskGatherNodeInfo::AddRef( void )
  161. //
  162. //////////////////////////////////////////////////////////////////////////////
  163. STDMETHODIMP_(ULONG)
  164. CTaskGatherNodeInfo::AddRef( void )
  165. {
  166. TraceFunc( "[IUnknown]" );
  167. InterlockedIncrement( &m_cRef );
  168. RETURN( m_cRef );
  169. } // AddRef()
  170. //////////////////////////////////////////////////////////////////////////////
  171. //
  172. // STDMETHODIMP_(ULONG)
  173. // CTaskGatherNodeInfo::Release( void )
  174. //
  175. //////////////////////////////////////////////////////////////////////////////
  176. STDMETHODIMP_(ULONG)
  177. CTaskGatherNodeInfo::Release( void )
  178. {
  179. TraceFunc( "[IUnknown]" );
  180. InterlockedDecrement( &m_cRef );
  181. if ( m_cRef )
  182. RETURN( m_cRef );
  183. TraceDo( delete this );
  184. RETURN(0);
  185. } // Release()
  186. // ************************************************************************
  187. //
  188. // IDoTask / ITaskGatherNodeInfo
  189. //
  190. // ************************************************************************
  191. //////////////////////////////////////////////////////////////////////////////
  192. //
  193. // STDMETHODIMP
  194. // CTaskGatherNodeInfo::BeginTask( void );
  195. //
  196. //////////////////////////////////////////////////////////////////////////////
  197. STDMETHODIMP
  198. CTaskGatherNodeInfo::BeginTask( void )
  199. {
  200. TraceFunc( "[IDoTask]" );
  201. HRESULT hr;
  202. OBJECTCOOKIE cookieParent;
  203. BSTR bstrNotification = NULL;
  204. IServiceProvider * psp = NULL;
  205. IUnknown * punk = NULL;
  206. IObjectManager * pom = NULL;
  207. IConnectionManager * pcm = NULL;
  208. IConnectionPointContainer * pcpc = NULL;
  209. IConnectionPoint * pcp = NULL;
  210. INotifyUI * pnui = NULL;
  211. IClusCfgNodeInfo * pccni = NULL;
  212. IClusCfgServer * pccs = NULL;
  213. IGatherData * pgd = NULL;
  214. IStandardInfo * psi = NULL;
  215. TraceInitializeThread( L"TaskGatherNodeInfo" );
  216. //
  217. // Collect the manager we need to complete this task.
  218. //
  219. hr = THR( CoCreateInstance( CLSID_ServiceManager,
  220. NULL,
  221. CLSCTX_INPROC_SERVER,
  222. TypeSafeParams( IServiceProvider, &psp )
  223. ) );
  224. if ( FAILED( hr ) )
  225. {
  226. SSR_FAILURE( TASKID_Minor_GatherNodeInfo_CoCreate_ServiceManager, hr );
  227. goto Cleanup;
  228. }
  229. hr = THR( psp->TypeSafeQS( CLSID_ObjectManager,
  230. IObjectManager,
  231. &pom
  232. ) );
  233. if ( FAILED( hr ) )
  234. {
  235. SSR_FAILURE( TASKID_Minor_GatherNodeInfo_QS_ObjectManager, hr );
  236. goto Cleanup;
  237. }
  238. hr = THR( psp->TypeSafeQS( CLSID_ClusterConnectionManager,
  239. IConnectionManager,
  240. &pcm
  241. ) );
  242. if ( FAILED( hr ) )
  243. {
  244. SSR_FAILURE( TASKID_Minor_BeginTask_QS_ConnectionManager, hr );
  245. goto Cleanup;
  246. }
  247. hr = THR( psp->TypeSafeQS( CLSID_NotificationManager,
  248. IConnectionPointContainer,
  249. &pcpc
  250. ) );
  251. if ( FAILED( hr ) )
  252. {
  253. SSR_FAILURE( TASKID_Minor_GatherNodeInfo_QS_NotificationManager, hr );
  254. goto Cleanup;
  255. }
  256. hr = THR( pcpc->FindConnectionPoint( IID_INotifyUI,
  257. &pcp
  258. ) );
  259. if ( FAILED( hr ) )
  260. {
  261. SSR_FAILURE( TASKID_Minor_GatherNodeInfo_FindConnectionPoint, hr );
  262. goto Cleanup;
  263. }
  264. pcp = TraceInterface( L"CTaskGatherNodeInfo!IConnectionPoint", IConnectionPoint, pcp, 1 );
  265. hr = THR( pcp->TypeSafeQI( INotifyUI, &pnui ) );
  266. if ( FAILED( hr ) )
  267. {
  268. SSR_FAILURE( TASKID_Minor_GatherNodeInfo_FindConnectionPoint_QI, hr );
  269. goto Cleanup;
  270. }
  271. pnui = TraceInterface( L"CTaskGatherNodeInfo!INotifyUI", INotifyUI, pnui, 1 );
  272. // release promptly
  273. psp->Release();
  274. psp = NULL;
  275. //
  276. // Retrieve the node's standard info.
  277. //
  278. hr = THR( pom->GetObject( DFGUID_StandardInfo,
  279. m_cookie,
  280. &punk
  281. ) );
  282. if ( FAILED( hr ) )
  283. {
  284. SSR_FAILURE( TASKID_Minor_GatherNodeInfo_GetObject_StandardInfo, hr );
  285. goto Cleanup;
  286. }
  287. hr = THR( punk->TypeSafeQI( IStandardInfo, &psi ) );
  288. if ( FAILED( hr ) )
  289. {
  290. SSR_FAILURE( TASKID_Minor_GatherNodeInfo_GetObject_StandardInfo_QI_psi, hr );
  291. goto Cleanup;
  292. }
  293. psi = TraceInterface( L"TaskGatherNodeInfo!IStandardInfo", IStandardInfo, psi, 1 );
  294. //
  295. // Get the node's name to display a status message.
  296. //
  297. hr = THR( psi->GetName( &m_bstrName ) );
  298. if ( FAILED( hr ) )
  299. {
  300. SSR_FAILURE( TASKID_Minor_GatherNodeInfo_GetName, hr );
  301. goto Cleanup;
  302. }
  303. //
  304. // Create a progress message.
  305. //
  306. hr = THR( HrLoadStringIntoBSTR( g_hInstance,
  307. IDS_TASKID_MINOR_CONNECTING_TO_NODES,
  308. &bstrNotification
  309. ) );
  310. if ( FAILED( hr ) )
  311. {
  312. SSR_FAILURE( TASKID_Minor_BeginTask_LoadString_Connecting, hr );
  313. goto Cleanup;
  314. }
  315. //
  316. // Tell the UI layer what's going on.
  317. //
  318. hr = THR( SendStatusReport( m_bstrName,
  319. TASKID_Major_Establish_Connection,
  320. TASKID_Minor_Connecting,
  321. 0,
  322. 1,
  323. 0,
  324. S_OK,
  325. bstrNotification,
  326. NULL,
  327. NULL
  328. ) );
  329. if ( FAILED( hr ) )
  330. goto Cleanup;
  331. //
  332. // Ask the Connection Manager for a connection to the object.
  333. //
  334. hr = pcm->GetConnectionToObject( m_cookie, &punk );
  335. if ( hr == HR_S_RPC_S_CLUSTER_NODE_DOWN )
  336. {
  337. goto Cleanup;
  338. }
  339. else if ( FAILED( hr ) )
  340. {
  341. THR( hr );
  342. SSR_FAILURE( TASKID_Minor_BeginTask_GetConnectionToObject, hr );
  343. goto Cleanup;
  344. }
  345. //
  346. // If this comes up from a Node, this is bad so change the error code
  347. // back and bail.
  348. //
  349. if ( hr == HR_S_RPC_S_SERVER_UNAVAILABLE )
  350. {
  351. hr = THR( HRESULT_FROM_WIN32( RPC_S_SERVER_UNAVAILABLE ) );
  352. goto Cleanup;
  353. }
  354. hr = THR( punk->TypeSafeQI( IClusCfgServer, &pccs ) );
  355. if ( FAILED( hr ) )
  356. {
  357. SSR_FAILURE( TASKID_Minor_BeginTask_GetConnectionToObject_QI_pccs, hr );
  358. goto Cleanup;
  359. }
  360. punk->Release();
  361. punk = NULL;
  362. hr = THR( pccs->GetClusterNodeInfo( &pccni ) );
  363. if ( FAILED( hr ) )
  364. {
  365. SSR_FAILURE( TASKID_Minor_BeginTask_GetClusterNodeInfo, hr );
  366. goto Cleanup;
  367. }
  368. //
  369. // Ask the Object Manager to retrieve the data format to store the information.
  370. //
  371. hr = THR( pom->GetObject( DFGUID_NodeInformation,
  372. m_cookie,
  373. &punk
  374. ) );
  375. if ( FAILED( hr ) )
  376. {
  377. SSR_FAILURE( TASKID_Minor_BeginTask_GetObject_NodeInformation, hr );
  378. goto Cleanup;
  379. }
  380. hr = THR( punk->TypeSafeQI( IGatherData, &pgd ) );
  381. if ( FAILED( hr ) )
  382. {
  383. SSR_FAILURE( TASKID_Minor_BeginTask_GetObject_NodeInformation_QI_pgd, hr );
  384. goto Cleanup;
  385. }
  386. punk->Release();
  387. punk = NULL;
  388. //
  389. // Find out our parent.
  390. //
  391. hr = THR( psi->GetParent( &cookieParent ) );
  392. if ( FAILED( hr ) )
  393. {
  394. SSR_FAILURE( TASKID_Minor_BeginTask_GetParent, hr );
  395. goto Cleanup;
  396. }
  397. //
  398. // Start sucking.
  399. //
  400. hr = THR( pgd->Gather( cookieParent, pccni ) );
  401. if ( FAILED( hr ) )
  402. {
  403. SSR_FAILURE( TASKID_Minor_BeginTask_Gather, hr );
  404. //
  405. // Don't goto cleanup - we need to single that the information possibly changed.
  406. //
  407. }
  408. //
  409. // At this point, we don't care if the "Gather" succeeded or failed. We
  410. // need to single that the object potentially changed.
  411. //
  412. THR( pnui->ObjectChanged( m_cookie ) );
  413. Cleanup:
  414. // Tell the UI layer we are done and the results of what was done.
  415. THR( SendStatusReport( m_bstrName,
  416. TASKID_Major_Establish_Connection,
  417. TASKID_Minor_Connecting,
  418. 0,
  419. 1,
  420. 1,
  421. hr,
  422. NULL,
  423. NULL,
  424. NULL
  425. ) );
  426. // don't care about errors from SSR at this point
  427. if ( psp != NULL )
  428. {
  429. psp->Release();
  430. }
  431. if ( pcm != NULL )
  432. {
  433. pcm->Release();
  434. }
  435. if ( pccs != NULL )
  436. {
  437. pccs->Release();
  438. }
  439. if ( pccni != NULL )
  440. {
  441. pccni->Release();
  442. }
  443. if ( punk != NULL )
  444. {
  445. punk->Release();
  446. }
  447. if ( pom != NULL )
  448. {
  449. //
  450. // Update the cookie's status indicating the result of our task.
  451. //
  452. IUnknown * punk;
  453. HRESULT hr2;
  454. hr2 = THR( pom->GetObject( DFGUID_StandardInfo, m_cookie, &punk ) );
  455. if ( SUCCEEDED( hr2 ) )
  456. {
  457. IStandardInfo * psi;
  458. hr2 = THR( punk->TypeSafeQI( IStandardInfo, &psi ) );
  459. punk->Release();
  460. if ( SUCCEEDED( hr2 ) )
  461. {
  462. // if ( hr == HR_S_RPC_S_CLUSTER_NODE_DOWN )
  463. // {
  464. // hr = HRESULT_FROM_WIN32( ERROR_CLUSTER_NODE_DOWN );
  465. // }
  466. hr2 = THR( psi->SetStatus( hr ) );
  467. psi->Release();
  468. }
  469. }
  470. hr2 = THR( pom->GetObject( DFGUID_StandardInfo, m_cookieCompletion, &punk ) );
  471. if ( SUCCEEDED( hr2 ) )
  472. {
  473. IStandardInfo * psi;
  474. hr2 = THR( punk->TypeSafeQI( IStandardInfo, &psi ) );
  475. punk->Release();
  476. if ( SUCCEEDED( hr2 ) )
  477. {
  478. hr2 = THR( psi->SetStatus( hr ) );
  479. psi->Release();
  480. }
  481. }
  482. pom->Release();
  483. }
  484. if ( pcpc != NULL )
  485. {
  486. pcpc->Release();
  487. }
  488. if ( pcp != NULL )
  489. {
  490. pcp->Release();
  491. }
  492. if ( pnui != NULL )
  493. {
  494. if ( m_cookieCompletion != NULL )
  495. {
  496. //
  497. // Signal the cookie to indicate that we are done.
  498. //
  499. THR( pnui->ObjectChanged( m_cookieCompletion ) );
  500. }
  501. pnui->Release();
  502. }
  503. if ( pgd != NULL )
  504. {
  505. pgd->Release();
  506. }
  507. if ( psi != NULL )
  508. {
  509. psi->Release();
  510. }
  511. TraceSysFreeString( bstrNotification );
  512. HRETURN( hr );
  513. } // BeginTask
  514. //////////////////////////////////////////////////////////////////////////////
  515. //
  516. // STDMETHODIMP
  517. // CTaskGatherNodeInfo::StopTask( void )
  518. //
  519. //////////////////////////////////////////////////////////////////////////////
  520. STDMETHODIMP
  521. CTaskGatherNodeInfo::StopTask( void )
  522. {
  523. TraceFunc( "[IDoTask]" );
  524. HRESULT hr = S_OK;
  525. HRETURN( hr );
  526. } //*** StopTask
  527. //////////////////////////////////////////////////////////////////////////////
  528. //
  529. // STDMETHODIMP
  530. // CTaskGatherNodeInfo::SetCookie(
  531. // OBJECTCOOKIE cookieIn
  532. // )
  533. //
  534. //////////////////////////////////////////////////////////////////////////////
  535. STDMETHODIMP
  536. CTaskGatherNodeInfo::SetCookie(
  537. OBJECTCOOKIE cookieIn
  538. )
  539. {
  540. TraceFunc( "[ITaskGatherNodeInfo]" );
  541. HRESULT hr = S_OK;
  542. m_cookie = cookieIn;
  543. HRETURN( hr );
  544. } //*** SetCookie
  545. //////////////////////////////////////////////////////////////////////////////
  546. //
  547. // STDMETHODIMP
  548. // CTaskGatherNodeInfo::SetCompletionCookie(
  549. // OBJECTCOOKIE cookieIn
  550. // )
  551. //
  552. //////////////////////////////////////////////////////////////////////////////
  553. STDMETHODIMP
  554. CTaskGatherNodeInfo::SetCompletionCookie(
  555. OBJECTCOOKIE cookieIn
  556. )
  557. {
  558. TraceFunc( "..." );
  559. HRESULT hr = S_OK;
  560. m_cookieCompletion = cookieIn;
  561. HRETURN( hr );
  562. } // SetGatherPunk()
  563. //****************************************************************************
  564. //
  565. // IClusCfgCallback
  566. //
  567. //****************************************************************************
  568. //////////////////////////////////////////////////////////////////////////////
  569. //
  570. // STDMETHODIMP
  571. // CTaskGatherNodeInfo::SendStatusReport(
  572. // LPCWSTR pcszNodeNameIn
  573. // , CLSID clsidTaskMajorIn
  574. // , CLSID clsidTaskMinorIn
  575. // , ULONG ulMinIn
  576. // , ULONG ulMaxIn
  577. // , ULONG ulCurrentIn
  578. // , HRESULT hrStatusIn
  579. // , LPCWSTR pcszDescriptionIn
  580. // , FILETIME * pftTimeIn
  581. // , LPCWSTR pcszReferenceIn
  582. // )
  583. //
  584. //////////////////////////////////////////////////////////////////////////////
  585. STDMETHODIMP
  586. CTaskGatherNodeInfo::SendStatusReport(
  587. LPCWSTR pcszNodeNameIn
  588. , CLSID clsidTaskMajorIn
  589. , CLSID clsidTaskMinorIn
  590. , ULONG ulMinIn
  591. , ULONG ulMaxIn
  592. , ULONG ulCurrentIn
  593. , HRESULT hrStatusIn
  594. , LPCWSTR pcszDescriptionIn
  595. , FILETIME * pftTimeIn
  596. , LPCWSTR pcszReferenceIn
  597. )
  598. {
  599. TraceFunc( "[IClusCfgCallback]" );
  600. HRESULT hr = S_OK;
  601. IServiceProvider * psp = NULL;
  602. IConnectionPointContainer * pcpc = NULL;
  603. IConnectionPoint * pcp = NULL;
  604. FILETIME ft;
  605. if ( m_pcccb == NULL )
  606. {
  607. //
  608. // Collect the manager we need to complete this task.
  609. //
  610. hr = THR( CoCreateInstance( CLSID_ServiceManager,
  611. NULL,
  612. CLSCTX_INPROC_SERVER,
  613. TypeSafeParams( IServiceProvider, &psp )
  614. ) );
  615. if ( FAILED( hr ) )
  616. goto Cleanup;
  617. hr = THR( psp->TypeSafeQS( CLSID_NotificationManager,
  618. IConnectionPointContainer,
  619. &pcpc
  620. ) );
  621. if ( FAILED( hr ) )
  622. goto Cleanup;
  623. hr = THR( pcpc->FindConnectionPoint( IID_IClusCfgCallback, &pcp ) );
  624. if ( FAILED( hr ) )
  625. goto Cleanup;
  626. pcp = TraceInterface( L"CConfigurationConnection!IConnectionPoint", IConnectionPoint, pcp, 1 );
  627. hr = THR( pcp->TypeSafeQI( IClusCfgCallback, &m_pcccb ) );
  628. if ( FAILED( hr ) )
  629. goto Cleanup;
  630. m_pcccb = TraceInterface( L"CConfigurationConnection!IClusCfgCallback", IClusCfgCallback, m_pcccb, 1 );
  631. psp->Release();
  632. psp = NULL;
  633. }
  634. if ( pftTimeIn == NULL )
  635. {
  636. GetSystemTimeAsFileTime( &ft );
  637. pftTimeIn = &ft;
  638. } // if:
  639. //
  640. // Send the message!
  641. //
  642. hr = THR( m_pcccb->SendStatusReport( pcszNodeNameIn,
  643. clsidTaskMajorIn,
  644. clsidTaskMinorIn,
  645. ulMinIn,
  646. ulMaxIn,
  647. ulCurrentIn,
  648. hrStatusIn,
  649. pcszDescriptionIn,
  650. pftTimeIn,
  651. pcszReferenceIn
  652. ) );
  653. Cleanup:
  654. if ( psp != NULL )
  655. {
  656. psp->Release();
  657. }
  658. if ( pcpc != NULL )
  659. {
  660. pcpc->Release();
  661. }
  662. if ( pcp != NULL )
  663. {
  664. pcp->Release();
  665. }
  666. HRETURN( hr );
  667. } // SendStatusReport()