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.

891 lines
19 KiB

  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1999-2002 Microsoft Corporation
  4. //
  5. // Module Name:
  6. // EnumCPINotifyUI.cpp
  7. //
  8. // Description:
  9. // INotifyUI Connection Point Enumerator implementation.
  10. //
  11. // Maintained By:
  12. // David Potter (DavidP) 14-JUN-2001
  13. // Geoffrey Pease (GPease) 04-AUG-2000
  14. //
  15. //////////////////////////////////////////////////////////////////////////////
  16. #include "Pch.h"
  17. #include "EnumCPINotifyUI.h"
  18. DEFINE_THISCLASS("CEnumCPINotifyUI")
  19. #define PUNK_BUFFER_GROW_SIZE 10
  20. //*************************************************************************//
  21. /////////////////////////////////////////////////////////////////////////////
  22. // CEnumCPINotifyUI class
  23. /////////////////////////////////////////////////////////////////////////////
  24. //////////////////////////////////////////////////////////////////////////////
  25. //++
  26. //
  27. // CEnumCPINotifyUI::S_HrCreateInstance
  28. //
  29. // Description:
  30. // Create a CEnumCPINotifyUI instance.
  31. //
  32. // Arguments:
  33. // None.
  34. //
  35. // Return Values:
  36. // S_OK
  37. // Success.
  38. //
  39. // E_POINTER
  40. // The passed in ppunk is NULL.
  41. //
  42. // other HRESULTs
  43. // Object creation failed.
  44. //
  45. //--
  46. //////////////////////////////////////////////////////////////////////////////
  47. HRESULT
  48. CEnumCPINotifyUI::S_HrCreateInstance(
  49. IUnknown ** ppunkOut
  50. )
  51. {
  52. TraceFunc( "" );
  53. HRESULT hr = S_OK;
  54. CEnumCPINotifyUI * pecnui = NULL;
  55. Assert( ppunkOut != NULL );
  56. if ( ppunkOut == NULL )
  57. {
  58. hr = THR( E_POINTER );
  59. goto Cleanup;
  60. } // if:
  61. pecnui = new CEnumCPINotifyUI();
  62. if ( pecnui == NULL )
  63. {
  64. hr = THR( E_OUTOFMEMORY );
  65. goto Cleanup;
  66. } // if:
  67. hr = THR( pecnui->HrInit() ); // fIsCloneIn = FALSE
  68. if ( FAILED( hr ) )
  69. {
  70. goto Cleanup;
  71. } // if:
  72. hr = THR( pecnui->TypeSafeQI( IUnknown, ppunkOut ) );
  73. if ( FAILED( hr ) )
  74. {
  75. goto Cleanup;
  76. } // if:
  77. Cleanup:
  78. if ( pecnui != NULL )
  79. {
  80. pecnui->Release();
  81. } // if:
  82. HRETURN( hr );
  83. } //*** CEnumCPINotifyUI::S_HrCreateInstance
  84. //////////////////////////////////////////////////////////////////////////////
  85. //++
  86. //
  87. // CEnumCPINotifyUI::CEnumCPINotifyUI
  88. //
  89. // Description:
  90. // Default constructor.
  91. //
  92. // Arguments:
  93. // None.
  94. //
  95. // Return Values:
  96. // None.
  97. //
  98. //--
  99. //////////////////////////////////////////////////////////////////////////////
  100. CEnumCPINotifyUI::CEnumCPINotifyUI( void )
  101. : m_cRef( 1 )
  102. {
  103. TraceFunc( "" );
  104. InterlockedIncrement( &g_cObjects );
  105. TraceFuncExit();
  106. } //*** CEnumCPINotifyUI::CEnumCPINotifyUI
  107. //////////////////////////////////////////////////////////////////////////////
  108. //++
  109. //
  110. // CEnumCPINotifyUI::~CEnumCPINotifyUI
  111. //
  112. // Description:
  113. // Destructor.
  114. //
  115. // Arguments:
  116. // None.
  117. //
  118. // Return Values:
  119. // None.
  120. //
  121. //--
  122. //////////////////////////////////////////////////////////////////////////////
  123. CEnumCPINotifyUI::~CEnumCPINotifyUI( void )
  124. {
  125. TraceFunc( "" );
  126. IUnknown * punk = NULL;
  127. if ( m_pList != NULL )
  128. {
  129. while ( m_cAlloced != 0 )
  130. {
  131. m_cAlloced --;
  132. punk = m_pList[ m_cAlloced ];
  133. AssertMsg( m_fIsClone || punk == NULL, "Someone didn't Unadvise before releasing the last Reference." );
  134. if ( punk != NULL )
  135. {
  136. punk->Release();
  137. } // if:
  138. } // while: m_cAlloced
  139. TraceFree( m_pList );
  140. } // if:
  141. InterlockedDecrement( &g_cObjects );
  142. TraceFuncExit();
  143. } //*** CEnumCPINotifyUI::~CEnumCPINotifyUI
  144. //*************************************************************************//
  145. /////////////////////////////////////////////////////////////////////////////
  146. // CEnumCPINotifyUI -- IUnknown interface.
  147. /////////////////////////////////////////////////////////////////////////////
  148. //////////////////////////////////////////////////////////////////////////////
  149. //++
  150. //
  151. // CEnumCPINotifyUI::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. CEnumCPINotifyUI::AddRef( void )
  169. {
  170. TraceFunc( "[IUnknown]" );
  171. InterlockedIncrement( &m_cRef );
  172. CRETURN( m_cRef );
  173. } //*** CEnumCPINotifyUI::AddRef
  174. //////////////////////////////////////////////////////////////////////////////
  175. //++
  176. //
  177. // CTaskCancelCleanup::Release
  178. //
  179. // Description:
  180. // Decrement the reference count of this object by one.
  181. //
  182. // Arguments:
  183. // None.
  184. //
  185. // Return Value:
  186. // The new reference count.
  187. //
  188. // Remarks:
  189. // None.
  190. //
  191. //--
  192. //////////////////////////////////////////////////////////////////////////////
  193. STDMETHODIMP_(ULONG)
  194. CEnumCPINotifyUI::Release( void )
  195. {
  196. TraceFunc( "[IUnknown]" );
  197. LONG cRef;
  198. cRef = InterlockedDecrement( &m_cRef );
  199. if ( cRef == 0 )
  200. {
  201. TraceDo( delete this );
  202. } // if:
  203. CRETURN( cRef );
  204. } //*** CEnumCPINotifyUI::Release
  205. //////////////////////////////////////////////////////////////////////////////
  206. //++
  207. //
  208. // CEnumCPINotifyUI::QueryInterface
  209. //
  210. // Description:
  211. // Query this object for the passed in interface.
  212. //
  213. // Arguments:
  214. // riidIn
  215. // Id of interface requested.
  216. //
  217. // ppvOut
  218. // Pointer to the requested interface.
  219. //
  220. // Return Value:
  221. // S_OK
  222. // If the interface is available on this object.
  223. //
  224. // E_NOINTERFACE
  225. // If the interface is not available.
  226. //
  227. // E_POINTER
  228. // ppvOut was NULL.
  229. //
  230. // Remarks:
  231. // None.
  232. //
  233. //--
  234. //////////////////////////////////////////////////////////////////////////////
  235. STDMETHODIMP
  236. CEnumCPINotifyUI::QueryInterface(
  237. REFIID riidIn
  238. , LPVOID * ppvOut
  239. )
  240. {
  241. TraceQIFunc( riidIn, ppvOut );
  242. HRESULT hr = S_OK;
  243. //
  244. // Validate arguments.
  245. //
  246. Assert( ppvOut != NULL );
  247. if ( ppvOut == NULL )
  248. {
  249. hr = THR( E_POINTER );
  250. goto Cleanup;
  251. } // if:
  252. //
  253. // Handle known interfaces.
  254. //
  255. if ( IsEqualIID( riidIn, IID_IUnknown ) )
  256. {
  257. *ppvOut = static_cast< IEnumConnections * >( this );
  258. } // if: IUnknown
  259. else if ( IsEqualIID( riidIn, IID_IEnumConnections ) )
  260. {
  261. *ppvOut = TraceInterface( __THISCLASS__, IEnumConnections, this, 0 );
  262. } // else if: IEnumConnections
  263. else
  264. {
  265. *ppvOut = NULL;
  266. hr = E_NOINTERFACE;
  267. } // else
  268. //
  269. // Add a reference to the interface if successful.
  270. //
  271. if ( SUCCEEDED( hr ) )
  272. {
  273. ((IUnknown *) *ppvOut)->AddRef();
  274. } // if: success
  275. Cleanup:
  276. QIRETURN_IGNORESTDMARSHALLING( hr, riidIn );
  277. } //*** CEnumCPINotifyUI::QueryInterface
  278. //*************************************************************************//
  279. /////////////////////////////////////////////////////////////////////////////
  280. // CEnumCPINotifyUI -- IEnumConnectionPoints interface.
  281. /////////////////////////////////////////////////////////////////////////////
  282. //////////////////////////////////////////////////////////////////////////////
  283. //++
  284. //
  285. // CEnumCPINotifyUI::Next
  286. //
  287. // Description:
  288. // Enumerator Next method.
  289. //
  290. // Arguments:
  291. // cConnectionsIn
  292. // How many items requested. Also tells us how bing rgcd.
  293. //
  294. // rgcdOut
  295. // Array that gets the data.
  296. //
  297. // pcFetchedOut
  298. // How many did we place in the array.
  299. //
  300. // Return Values:
  301. // S_OK
  302. // Success.
  303. //
  304. // S_FALSE
  305. // cConnectionsIn > *pcFetchedOut. Did not return as many items
  306. // as the caller asked for.
  307. //
  308. // Other HRESULT errors.
  309. //
  310. //--
  311. //////////////////////////////////////////////////////////////////////////////
  312. STDMETHODIMP
  313. CEnumCPINotifyUI::Next(
  314. ULONG cConnectionsIn
  315. , LPCONNECTDATA rgcdOut
  316. , ULONG * pcFetchedOut
  317. )
  318. {
  319. TraceFunc( "[IEnumConnectionPoints]" );
  320. ULONG cIter;
  321. HRESULT hr = S_FALSE;
  322. if ( pcFetchedOut != NULL )
  323. {
  324. *pcFetchedOut = 0;
  325. } // if:
  326. for( cIter = 0
  327. ; ( cIter < cConnectionsIn ) && ( m_cIter < m_cCurrent )
  328. ; m_cIter ++
  329. )
  330. {
  331. IUnknown * punk = m_pList[ m_cIter ];
  332. if ( punk != NULL )
  333. {
  334. hr = THR( punk->TypeSafeQI( IUnknown, &rgcdOut[ cIter ].pUnk ) );
  335. if ( FAILED( hr ) )
  336. {
  337. goto Error;
  338. } // if:
  339. rgcdOut[ cIter ].pUnk = TraceInterface( L"EnumCPINotifyUI!IUnknown", IUnknown, rgcdOut[ cIter ].pUnk, 1 );
  340. rgcdOut[ cIter ].dwCookie = m_cIter + 1;
  341. cIter ++;
  342. } // if:
  343. } // for: cIter
  344. if ( cIter != cConnectionsIn )
  345. {
  346. hr = S_FALSE;
  347. } // if:
  348. else
  349. {
  350. hr = S_OK;
  351. } // else:
  352. if ( pcFetchedOut != NULL )
  353. {
  354. *pcFetchedOut = cIter;
  355. } // if:
  356. Cleanup:
  357. HRETURN( hr );
  358. Error:
  359. while ( cIter != 0 )
  360. {
  361. cIter--;
  362. rgcdOut[ cIter ].pUnk->Release();
  363. } // while:
  364. goto Cleanup;
  365. } //*** CEnumCPINotifyUI::Next
  366. //////////////////////////////////////////////////////////////////////////////
  367. //++
  368. //
  369. // CEnumCPINotifyUI::Skip
  370. //
  371. // Description:
  372. // Enumerator Skip method.
  373. //
  374. // Arguments:
  375. // cConnectionsIn
  376. // Number of items to skip.
  377. //
  378. // Return Values:
  379. // S_OK
  380. // Success.
  381. //
  382. // S_FALSE
  383. // The number to skip put us at the end of the list.
  384. //
  385. // Other HRESULT errors.
  386. //
  387. //--
  388. //////////////////////////////////////////////////////////////////////////////
  389. STDMETHODIMP
  390. CEnumCPINotifyUI::Skip(
  391. ULONG cConnectionsIn
  392. )
  393. {
  394. TraceFunc( "[IEnumConnectionPoints]" );
  395. HRESULT hr = S_OK;
  396. m_cIter += cConnectionsIn;
  397. if ( m_cIter >= m_cCurrent )
  398. {
  399. m_cIter = m_cCurrent;
  400. hr = S_FALSE;
  401. } // if:
  402. HRETURN( hr );
  403. } //*** CEnumCPINotifyUI::Skip
  404. //////////////////////////////////////////////////////////////////////////////
  405. //++
  406. //
  407. // CEnumCPINotifyUI::Reset
  408. //
  409. // Description:
  410. // Enumerator Reset method.
  411. //
  412. // Arguments:
  413. // None.
  414. //
  415. // Return Values:
  416. // S_OK
  417. // Success.
  418. //
  419. //--
  420. //////////////////////////////////////////////////////////////////////////////
  421. STDMETHODIMP
  422. CEnumCPINotifyUI::Reset( void )
  423. {
  424. TraceFunc( "[IEnumConnectionPoints]" );
  425. HRESULT hr = S_OK;
  426. m_cIter = 0;
  427. HRETURN( hr );
  428. } //*** CEnumCPINotifyUI::Reset
  429. //////////////////////////////////////////////////////////////////////////////
  430. //++
  431. //
  432. // CEnumCPINotifyUI::Clone
  433. //
  434. // Description:
  435. // Enumerator Clone method.
  436. //
  437. // Arguments:
  438. // ppEnumOut
  439. // The new enumerator that we are cloning ourselves into.
  440. //
  441. // Return Values:
  442. // S_OK
  443. // Success.
  444. //
  445. // Other HRESULT errors.
  446. //
  447. //--
  448. //////////////////////////////////////////////////////////////////////////////
  449. STDMETHODIMP
  450. CEnumCPINotifyUI::Clone(
  451. IEnumConnections ** ppEnumOut
  452. )
  453. {
  454. TraceFunc( "[IEnumConnectionPoints]" );
  455. HRESULT hr = S_OK;
  456. CEnumCPINotifyUI * pecp = new CEnumCPINotifyUI();
  457. if ( pecp == NULL )
  458. {
  459. hr = THR( E_OUTOFMEMORY );
  460. goto Cleanup;
  461. } // if:
  462. hr = THR( pecp->HrInit( TRUE ) ); // fIsCloneIn = TRUE
  463. if ( FAILED( hr ) )
  464. {
  465. goto Cleanup;
  466. } // if:
  467. hr = THR( pecp->HrCopy( this ) );
  468. if ( FAILED( hr ) )
  469. {
  470. goto Cleanup;
  471. } // if:
  472. hr = THR( pecp->TypeSafeQI( IEnumConnections, ppEnumOut ) );
  473. if ( FAILED( hr ) )
  474. {
  475. goto Cleanup;
  476. } // if:
  477. *ppEnumOut = TraceInterface( L"EnumCPINotifyUI!IEnumConnections", IEnumConnections, *ppEnumOut, 1 );
  478. pecp->Release();
  479. pecp = NULL;
  480. Cleanup:
  481. if ( pecp != NULL )
  482. {
  483. delete pecp;
  484. } // if:
  485. HRETURN( hr );
  486. } //*** CEnumCPINotifyUI::Clone
  487. //*************************************************************************//
  488. /////////////////////////////////////////////////////////////////////////////
  489. // CEnumCPINotifyUI -- Public methods.
  490. /////////////////////////////////////////////////////////////////////////////
  491. //////////////////////////////////////////////////////////////////////////////
  492. //++
  493. //
  494. // CEnumCPINotifyUI::HrAddConnection
  495. //
  496. // Description:
  497. // Add a connection point container to our list of clients.
  498. //
  499. // Arguments:
  500. // punkIn
  501. // The new client object.
  502. //
  503. // pdwCookieOut
  504. // Cookie used to find this client object in our list.
  505. //
  506. // Return Values:
  507. // S_OK
  508. // Success.
  509. //
  510. // Other HRESULT errors.
  511. //
  512. //--
  513. //////////////////////////////////////////////////////////////////////////////
  514. HRESULT
  515. CEnumCPINotifyUI::HrAddConnection(
  516. IUnknown * punkIn
  517. , DWORD * pdwCookieOut
  518. )
  519. {
  520. TraceFunc( "" );
  521. HRESULT hr = S_FALSE;
  522. ULONG cIter;
  523. if ( pdwCookieOut == NULL )
  524. {
  525. hr = THR( E_POINTER );
  526. goto Cleanup;
  527. } // if:
  528. //
  529. // See if there is an openning in the currently allocated list.
  530. //
  531. for ( cIter = 0; cIter < m_cCurrent; cIter ++ )
  532. {
  533. if ( m_pList[ cIter ] == NULL )
  534. {
  535. //
  536. // Found an openning... try to use it.
  537. //
  538. hr = THR( punkIn->TypeSafeQI( IUnknown, &m_pList[ cIter ] ) );
  539. m_pList[ cIter ] = TraceInterface( L"CEnumCPINotifyUI!IUnknown", IUnknown, m_pList[ cIter ], 1 );
  540. *pdwCookieOut = cIter + 1;
  541. // Doesn't matter if it succeeded or fail, exit.
  542. goto Cleanup;
  543. } // if:
  544. } // for:
  545. if ( m_cCurrent == m_cAlloced )
  546. {
  547. IUnknown ** pNewList;
  548. //
  549. // Try making some more space.
  550. //
  551. pNewList = (IUnknown **) TraceAlloc( HEAP_ZERO_MEMORY, ( m_cAlloced + PUNK_BUFFER_GROW_SIZE ) * sizeof( IUnknown * ) );
  552. if ( pNewList == NULL )
  553. {
  554. hr = THR( E_OUTOFMEMORY );
  555. goto Cleanup;
  556. }
  557. CopyMemory( pNewList, m_pList, m_cCurrent * sizeof( IUnknown * ) );
  558. TraceFree( m_pList );
  559. m_pList = pNewList;
  560. m_cAlloced += PUNK_BUFFER_GROW_SIZE;
  561. } // if:
  562. //
  563. // Add it to the list.
  564. //
  565. hr = THR( punkIn->TypeSafeQI( IUnknown, &m_pList[ m_cCurrent ] ) );
  566. if ( FAILED( hr ) )
  567. {
  568. goto Cleanup;
  569. } // if:
  570. m_pList[ m_cCurrent ] = TraceInterface( L"CEnumCPINotifyUI!IUnknown", IUnknown, m_pList[ m_cCurrent ], 1 );
  571. m_cCurrent ++;
  572. *pdwCookieOut = m_cCurrent; // starts at ONE, not ZERO
  573. Cleanup:
  574. HRETURN( hr );
  575. } //*** CEnumCPINotifyUI::HrAddConnection
  576. //////////////////////////////////////////////////////////////////////////////
  577. //++
  578. //
  579. // CEnumCPINotifyUI::HrRemoveConnection
  580. //
  581. // Description:
  582. // Remove the client identified by the passed in cookie from the list.
  583. //
  584. // Arguments:
  585. // dwCookieIn
  586. // The cookie of the client that is to be removed from the list.
  587. //
  588. // Return Values:
  589. // S_OK
  590. // Success.
  591. //
  592. // Other HRESULT errors.
  593. //
  594. //--
  595. //////////////////////////////////////////////////////////////////////////////
  596. HRESULT
  597. CEnumCPINotifyUI::HrRemoveConnection(
  598. DWORD dwCookieIn
  599. )
  600. {
  601. TraceFunc( "" );
  602. HRESULT hr;
  603. if ( dwCookieIn == 0 || dwCookieIn > m_cCurrent )
  604. {
  605. hr = THR( E_INVALIDARG );
  606. goto Cleanup;
  607. } // if:
  608. if ( m_pList[ dwCookieIn - 1 ] == NULL )
  609. {
  610. hr = THR( E_INVALIDARG );
  611. goto Cleanup;
  612. } // if:
  613. m_pList[ dwCookieIn - 1 ]->Release();
  614. m_pList[ dwCookieIn - 1 ] = NULL;
  615. hr = S_OK;
  616. Cleanup:
  617. HRETURN( hr );
  618. } //*** CEnumCPINotifyUI::HrRemoveConnection
  619. //*************************************************************************//
  620. /////////////////////////////////////////////////////////////////////////////
  621. // CEnumCPINotifyUI -- Private methods.
  622. /////////////////////////////////////////////////////////////////////////////
  623. //////////////////////////////////////////////////////////////////////////////
  624. //++
  625. //
  626. // CEnumCPINotifyUI::HrInt
  627. //
  628. // Description:
  629. // Do any initialization that may fail here.
  630. //
  631. // Arguments:
  632. // fIsCloneIn
  633. // Is this instance a clone?
  634. //
  635. // Return Values:
  636. // S_OK
  637. // Success.
  638. //
  639. // Other HRESULT errors.
  640. //
  641. //--
  642. //////////////////////////////////////////////////////////////////////////////
  643. HRESULT
  644. CEnumCPINotifyUI::HrInit(
  645. BOOL fIsCloneIn // = FALSE
  646. )
  647. {
  648. TraceFunc( "" );
  649. // IUnknown stuff
  650. Assert( m_cRef == 1 );
  651. // IEnumConnectionPoints
  652. Assert( m_cAlloced == 0 );
  653. Assert( m_cCurrent == 0 );
  654. Assert( m_cIter == 0 );
  655. Assert( m_pList == NULL );
  656. Assert( m_fIsClone == FALSE );
  657. m_fIsClone = fIsCloneIn;
  658. // INotifyUI
  659. HRETURN( S_OK );
  660. } //*** CEnumCPINotifyUI::HrInit
  661. //////////////////////////////////////////////////////////////////////////////
  662. //++
  663. //
  664. // CEnumCPINotifyUI::HrCopy
  665. //
  666. // Description:
  667. // Copy from the passed in enumerator.
  668. //
  669. // Arguments:
  670. // pecpIn
  671. // The source that we are to copy from.
  672. //
  673. // Return Values:
  674. // S_OK
  675. // Success.
  676. //
  677. // Other HRESULT errors.
  678. //
  679. //--
  680. //////////////////////////////////////////////////////////////////////////////
  681. HRESULT
  682. CEnumCPINotifyUI::HrCopy(
  683. CEnumCPINotifyUI * pecpIn
  684. )
  685. {
  686. TraceFunc( "" );
  687. HRESULT hr = S_FALSE;
  688. ULONG cIter;
  689. Assert( m_cAlloced == 0 );
  690. Assert( m_cCurrent == 0 );
  691. Assert( m_pList == NULL );
  692. m_pList = (IUnknown **) TraceAlloc( HEAP_ZERO_MEMORY, pecpIn->m_cCurrent * sizeof( IUnknown * ) );
  693. if ( m_pList == NULL )
  694. {
  695. hr = THR( E_OUTOFMEMORY );
  696. goto Cleanup;
  697. } // if:
  698. m_cCurrent = m_cAlloced = pecpIn->m_cCurrent;
  699. m_cIter = 0;
  700. for ( cIter = 0; cIter < pecpIn->m_cCurrent; cIter++ )
  701. {
  702. //
  703. // Does the source have a pointer at the current index? If it does then "copy" it,
  704. // otherwise NULL out that index in our copy...
  705. //
  706. if ( pecpIn->m_pList[ cIter ] != NULL )
  707. {
  708. hr = THR( pecpIn->m_pList[ cIter ]->TypeSafeQI( IUnknown, &m_pList[ cIter ] ) );
  709. if ( FAILED( hr ) )
  710. {
  711. goto Cleanup;
  712. } // if:
  713. m_pList[ cIter ] = TraceInterface( L"EnumCPINotifyUI!IUnknown", IUnknown, m_pList[ cIter ], 1 );
  714. } // if:
  715. else
  716. {
  717. m_pList[ cIter ] = NULL;
  718. } // else:
  719. } // for:
  720. hr = S_OK;
  721. Cleanup:
  722. HRETURN( hr );
  723. } //*** CEnumCPINotifyUI::HrCopy