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.

2100 lines
58 KiB

  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 2000-2001 Microsoft Corporation
  4. //
  5. // Module Name:
  6. // TaskTreeView.cpp
  7. //
  8. // Maintained By:
  9. // Galen Barbee (GalenB) 22-MAY-2000
  10. //
  11. //////////////////////////////////////////////////////////////////////////////
  12. #include "Pch.h"
  13. #include "TaskTreeView.h"
  14. #include "DetailsDlg.h"
  15. DEFINE_THISCLASS( "CTaskTreeView" )
  16. //****************************************************************************
  17. //
  18. // Constants
  19. //
  20. //****************************************************************************
  21. #define HIGH_TICK_COUNT 400
  22. //****************************************************************************
  23. //
  24. // Static Function Prototypes
  25. //
  26. //****************************************************************************
  27. static
  28. HRESULT
  29. HrCreateTreeItem(
  30. TVINSERTSTRUCT * ptvisOut
  31. , STreeItemLParamData * ptipdIn
  32. , HTREEITEM htiParentIn
  33. , int nImageIn
  34. , BSTR bstrTextIn
  35. );
  36. //////////////////////////////////////////////////////////////////////////////
  37. //++
  38. //
  39. // CTaskTreeView::CTaskTreeView(
  40. // HWND hwndParentIn,
  41. // UINT uIDTVIn,
  42. // UINT uIDProgressIn,
  43. // UINT uIDStatusIn
  44. // )
  45. //
  46. //--
  47. //////////////////////////////////////////////////////////////////////////////
  48. CTaskTreeView::CTaskTreeView(
  49. HWND hwndParentIn,
  50. UINT uIDTVIn,
  51. UINT uIDProgressIn,
  52. UINT uIDStatusIn
  53. )
  54. {
  55. TraceFunc( "" );
  56. Assert( m_htiSelected == NULL );
  57. m_hwndParent = hwndParentIn;
  58. m_hwndTV = GetDlgItem( hwndParentIn, uIDTVIn );
  59. Assert( m_hwndTV != NULL );
  60. m_hwndProg = GetDlgItem( hwndParentIn, uIDProgressIn );
  61. Assert( m_hwndProg != NULL );
  62. m_hwndStatus = GetDlgItem( hwndParentIn, uIDStatusIn );
  63. Assert( m_hwndStatus != NULL );
  64. m_hImgList = NULL;
  65. TraceFuncExit();
  66. } //*** CTaskTreeView::CTaskTreeView()
  67. //////////////////////////////////////////////////////////////////////////////
  68. //++
  69. //
  70. // CTaskTreeView::~CTaskTreeView( void )
  71. //
  72. //--
  73. //////////////////////////////////////////////////////////////////////////////
  74. CTaskTreeView::~CTaskTreeView( void )
  75. {
  76. TraceFunc( "" );
  77. TreeView_DeleteAllItems( m_hwndTV );
  78. if ( m_hImgList != NULL )
  79. {
  80. ImageList_Destroy( m_hImgList );
  81. }
  82. TraceFuncExit();
  83. } //*** CTaskTreeView::CTaskTreeView()
  84. //////////////////////////////////////////////////////////////////////////////
  85. //++
  86. //
  87. // HRESULT
  88. // CTaskTreeView::HrOnInitDialog( void )
  89. //
  90. //--
  91. //////////////////////////////////////////////////////////////////////////////
  92. HRESULT
  93. CTaskTreeView::HrOnInitDialog( void )
  94. {
  95. TraceFunc( "" );
  96. HRESULT hr = S_OK;
  97. DWORD sc;
  98. HICON hIcon;
  99. int idx;
  100. //
  101. // Build image list for icons in tree view.
  102. //
  103. m_hImgList = ImageList_Create( 16, 16, ILC_MASK, tsMAX, 0);
  104. if ( m_hImgList == NULL )
  105. {
  106. sc = TW32( GetLastError() );
  107. goto Win32Error;
  108. }
  109. //
  110. // Unknown Icon - Task Unknown.
  111. //
  112. hIcon = (HICON) LoadImage( g_hInstance,
  113. MAKEINTRESOURCE( IDI_SEL ),
  114. IMAGE_ICON,
  115. 16,
  116. 16,
  117. LR_SHARED
  118. );
  119. if ( hIcon == NULL )
  120. {
  121. sc = TW32( GetLastError() );
  122. goto Win32Error;
  123. }
  124. idx = ImageList_AddIcon( m_hImgList, hIcon );
  125. Assert( idx == tsUNKNOWN );
  126. //
  127. // Pending Icon - Task Pending.
  128. //
  129. hIcon = (HICON) LoadImage( g_hInstance,
  130. MAKEINTRESOURCE( IDI_PENDING ),
  131. IMAGE_ICON,
  132. 16,
  133. 16,
  134. LR_SHARED
  135. );
  136. if ( hIcon == NULL )
  137. {
  138. sc = TW32( GetLastError() );
  139. goto Win32Error;
  140. }
  141. idx = ImageList_AddIcon( m_hImgList, hIcon );
  142. Assert( idx == tsPENDING );
  143. //
  144. // Checkmark Icon - Task Done.
  145. //
  146. hIcon = (HICON) LoadImage( g_hInstance,
  147. MAKEINTRESOURCE( IDI_CHECK ),
  148. IMAGE_ICON,
  149. 16,
  150. 16,
  151. LR_SHARED
  152. );
  153. if ( hIcon == NULL )
  154. {
  155. sc = TW32( GetLastError() );
  156. goto Win32Error;
  157. }
  158. idx = ImageList_AddIcon( m_hImgList, hIcon );
  159. Assert( idx == tsDONE );
  160. //
  161. // Warning Icon - Task Warning.
  162. //
  163. hIcon = (HICON) LoadImage( g_hInstance,
  164. MAKEINTRESOURCE( IDI_WARN ),
  165. IMAGE_ICON,
  166. 16,
  167. 16,
  168. LR_SHARED
  169. );
  170. if ( hIcon == NULL )
  171. {
  172. sc = TW32( GetLastError() );
  173. goto Win32Error;
  174. }
  175. idx = ImageList_AddIcon( m_hImgList, hIcon );
  176. Assert( idx == tsWARNING );
  177. //
  178. // Fail Icon - Task Failed.
  179. //
  180. hIcon = (HICON) LoadImage( g_hInstance,
  181. MAKEINTRESOURCE( IDI_FAIL ),
  182. IMAGE_ICON,
  183. 16,
  184. 16,
  185. LR_SHARED
  186. );
  187. if ( hIcon == NULL )
  188. {
  189. sc = TW32( GetLastError() );
  190. goto Win32Error;
  191. }
  192. idx = ImageList_AddIcon( m_hImgList, hIcon );
  193. Assert( idx == tsFAILED );
  194. Assert( ImageList_GetImageCount( m_hImgList ) == tsMAX );
  195. //
  196. // Set the image list and background color.
  197. //
  198. TreeView_SetImageList( m_hwndTV, m_hImgList, TVSIL_NORMAL );
  199. TreeView_SetBkColor( m_hwndTV, GetSysColor( COLOR_3DFACE ) );
  200. goto Cleanup;
  201. Win32Error:
  202. hr = HRESULT_FROM_WIN32( sc );
  203. goto Cleanup;
  204. Cleanup:
  205. HRETURN( hr );
  206. } //*** CTaskTreeView::HrOnInitDialog()
  207. //////////////////////////////////////////////////////////////////////////////
  208. //++
  209. //
  210. // CTaskTreeView::HrAddTreeViewItem
  211. //
  212. // Description:
  213. // Add a tree view item. This method will return the item handle and
  214. // allows the caller to specify the parent item.
  215. //
  216. // Arguments:
  217. // phtiOut - Handle to the item being added (optional).
  218. // idsIn - String resource ID for description of the new item.
  219. // rclsidMinorTaskIDIn - Minor task ID for the item.
  220. // rclsidMajorTaskIDIn - Major task ID for the item. Defaults to IID_NULL.
  221. // htiParentIn - Parent item. Defaults to the root.
  222. //
  223. //--
  224. //////////////////////////////////////////////////////////////////////////////
  225. HRESULT
  226. CTaskTreeView::HrAddTreeViewItem(
  227. HTREEITEM * phtiOut
  228. , UINT idsIn
  229. , REFCLSID rclsidMinorTaskIDIn
  230. , REFCLSID rclsidMajorTaskIDIn // = IID_NULL
  231. , HTREEITEM htiParentIn // = TVI_ROOT
  232. )
  233. {
  234. TraceFunc( "" );
  235. HRESULT hr = S_OK;
  236. STreeItemLParamData * ptipd;
  237. SYSTEMTIME systemtime;
  238. TVINSERTSTRUCT tvis;
  239. HTREEITEM hti = NULL;
  240. //
  241. // Allocate an item data structure and initialize it.
  242. //
  243. ptipd = new STreeItemLParamData;
  244. if ( ptipd == NULL )
  245. {
  246. hr = THR( E_OUTOFMEMORY );
  247. goto Cleanup;
  248. }
  249. hr = THR( HrGetComputerName( ComputerNamePhysicalDnsFullyQualified, &ptipd->bstrNodeName ) );
  250. if ( FAILED( hr ) )
  251. {
  252. goto Cleanup;
  253. }
  254. hr = THR( HrLoadStringIntoBSTR( g_hInstance, idsIn, &ptipd->bstrDescription ) );
  255. if ( FAILED( hr ) )
  256. {
  257. goto Cleanup;
  258. }
  259. GetSystemTime( &systemtime );
  260. if ( ! SystemTimeToFileTime( &systemtime, &ptipd->ftTime ) )
  261. {
  262. DWORD sc = TW32( GetLastError() );
  263. hr = HRESULT_FROM_WIN32( sc );
  264. goto Cleanup;
  265. }
  266. CopyMemory( &ptipd->clsidMajorTaskId, &rclsidMajorTaskIDIn, sizeof( ptipd->clsidMajorTaskId ) );
  267. CopyMemory( &ptipd->clsidMinorTaskId, &rclsidMinorTaskIDIn, sizeof( ptipd->clsidMinorTaskId ) );
  268. //
  269. // Initialize the insert structure and insert the item into the tree.
  270. //
  271. tvis.hParent = htiParentIn;
  272. tvis.hInsertAfter = TVI_LAST;
  273. tvis.itemex.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM;
  274. tvis.itemex.cchTextMax = SysStringLen( ptipd->bstrDescription );
  275. tvis.itemex.pszText = ptipd->bstrDescription;
  276. tvis.itemex.iImage = tsUNKNOWN;
  277. tvis.itemex.iSelectedImage = tsUNKNOWN;
  278. tvis.itemex.lParam = reinterpret_cast< LPARAM >( ptipd );
  279. hti = TreeView_InsertItem( m_hwndTV, &tvis );
  280. Assert( hti != NULL );
  281. ptipd = NULL;
  282. if ( phtiOut != NULL )
  283. {
  284. *phtiOut = hti;
  285. }
  286. goto Cleanup;
  287. Cleanup:
  288. if ( ptipd != NULL )
  289. {
  290. TraceSysFreeString( ptipd->bstrNodeName );
  291. TraceSysFreeString( ptipd->bstrDescription );
  292. delete ptipd;
  293. }
  294. HRETURN( hr );
  295. } //*** CTaskTreeView::HrAddTreeViewRootItem()
  296. //////////////////////////////////////////////////////////////////////////////
  297. //++
  298. //
  299. // CTaskTreeView::OnNotify
  300. //
  301. // Description:
  302. // Handler for the WM_NOTIFY message.
  303. //
  304. // Arguments:
  305. // pnmhdrIn - Notification structure.
  306. //
  307. // Return Values:
  308. // Notification-specific return code.
  309. //
  310. //--
  311. //////////////////////////////////////////////////////////////////////////////
  312. LRESULT
  313. CTaskTreeView::OnNotify(
  314. LPNMHDR pnmhdrIn
  315. )
  316. {
  317. TraceFunc( "" );
  318. LRESULT lr = TRUE;
  319. switch( pnmhdrIn->code )
  320. {
  321. case TVN_DELETEITEM:
  322. OnNotifyDeleteItem( pnmhdrIn );
  323. break;
  324. case TVN_SELCHANGED:
  325. OnNotifySelChanged( pnmhdrIn );
  326. break;
  327. } // switch: notify code
  328. RETURN( lr );
  329. } //*** CTaskTreeView::OnNotify()
  330. //////////////////////////////////////////////////////////////////////////////
  331. //++
  332. //
  333. // CTaskTreeView::OnNotifyDeleteItem
  334. //
  335. // Description:
  336. // Handler for the TVN_DELETEITEM notification message.
  337. //
  338. // Arguments:
  339. // pnmhdrIn - Notification structure for the item being deleted.
  340. //
  341. // Return Values:
  342. // None.
  343. //
  344. //--
  345. //////////////////////////////////////////////////////////////////////////////
  346. void
  347. CTaskTreeView::OnNotifyDeleteItem(
  348. LPNMHDR pnmhdrIn
  349. )
  350. {
  351. TraceFunc( "" );
  352. LPNMTREEVIEW pnmtv = reinterpret_cast< LPNMTREEVIEW >( pnmhdrIn );
  353. if ( pnmtv->itemOld.lParam != NULL )
  354. {
  355. STreeItemLParamData * ptipd = reinterpret_cast< STreeItemLParamData * >( pnmtv->itemOld.lParam );
  356. TraceSysFreeString( ptipd->bstrNodeName );
  357. TraceSysFreeString( ptipd->bstrDescription );
  358. TraceSysFreeString( ptipd->bstrReference );
  359. delete ptipd;
  360. }
  361. TraceFuncExit();
  362. } //*** CTaskTreeView::OnNotifyDeleteItem()
  363. //////////////////////////////////////////////////////////////////////////////
  364. //++
  365. //
  366. // CTaskTreeView::OnNotifySelChanged
  367. //
  368. // Description:
  369. // Handler for the TVN_SELCHANGED notification message.
  370. //
  371. // Arguments:
  372. // pnmhdrIn - Notification structure for the item being deleted.
  373. //
  374. // Return Values:
  375. // None.
  376. //
  377. //--
  378. //////////////////////////////////////////////////////////////////////////////
  379. void
  380. CTaskTreeView::OnNotifySelChanged(
  381. LPNMHDR pnmhdrIn
  382. )
  383. {
  384. TraceFunc( "" );
  385. LPNMTREEVIEW pnmtv = reinterpret_cast< LPNMTREEVIEW >( pnmhdrIn );
  386. Assert( pnmtv->itemNew.mask & TVIF_HANDLE );
  387. m_htiSelected = pnmtv->itemNew.hItem;
  388. TraceFuncExit();
  389. } //*** CTaskTreeView::OnNotifySelChanged()
  390. //////////////////////////////////////////////////////////////////////////////
  391. //++
  392. //
  393. // HRESULT
  394. // CTaskTreeView::HrShowStatusAsDone( void )
  395. //
  396. //--
  397. //////////////////////////////////////////////////////////////////////////////
  398. HRESULT
  399. CTaskTreeView::HrShowStatusAsDone( void )
  400. {
  401. TraceFunc( "" );
  402. HRESULT hr = S_OK;
  403. BSTR bstrDescription = NULL;
  404. PBRANGE pbrange;
  405. #if defined( DEBUG )
  406. ULONG_PTR ulCurrent;
  407. ulCurrent = SendMessage( m_hwndProg, PBM_GETPOS, 0, 0 );
  408. AssertMsg( ulCurrent + 100 <= HIGH_TICK_COUNT, "Need to adjust HIGH_TICK_COUNT higher!" );
  409. #endif
  410. SendMessage( m_hwndProg, PBM_GETRANGE, FALSE, (LPARAM) &pbrange );
  411. SendMessage( m_hwndProg, PBM_SETPOS, pbrange.iHigh, 0 );
  412. hr = THR( HrLoadStringIntoBSTR( g_hInstance,
  413. IDS_TASKS_COMPLETED,
  414. &bstrDescription
  415. ) );
  416. if ( FAILED( hr ) )
  417. {
  418. SetWindowText( m_hwndStatus, L"" );
  419. goto Cleanup;
  420. }
  421. SetWindowText( m_hwndStatus, bstrDescription );
  422. Cleanup:
  423. TraceSysFreeString( bstrDescription );
  424. HRETURN( hr );
  425. } //*** CTaskTreeView::HrShowStatusAsDone()
  426. //////////////////////////////////////////////////////////////////////////////
  427. //++
  428. //
  429. // HRESULT
  430. // CTaskTreeView::HrOnNotifySetActive( void )
  431. //
  432. //--
  433. //////////////////////////////////////////////////////////////////////////////
  434. HRESULT
  435. CTaskTreeView::HrOnNotifySetActive( void )
  436. {
  437. TraceFunc( "" );
  438. HRESULT hr = S_OK;
  439. TreeView_DeleteAllItems( m_hwndTV );
  440. SetWindowText( m_hwndStatus, L"" );
  441. m_ulLowNibble = 0;
  442. m_ulHighNibble = HIGH_TICK_COUNT;
  443. SendMessage( m_hwndProg, PBM_SETRANGE, 0, MAKELPARAM( m_ulLowNibble, m_ulHighNibble ) );
  444. SendMessage( m_hwndProg, PBM_SETPOS, m_ulLowNibble, 0 );
  445. HRETURN( hr );
  446. } //*** CTaskTreeView::HrOnNotifySetActive()
  447. //////////////////////////////////////////////////////////////////////////////
  448. //++
  449. //
  450. // CTaskTreeView::HrOnSendStatusReport
  451. //
  452. // Description:
  453. // Handle a status report call.
  454. //
  455. // Arguments:
  456. // pcszNodeNameIn -
  457. // clsidTaskMajorIn -
  458. // clsidTaskMinorIn -
  459. // ulMinIn -
  460. // ulMaxIn -
  461. // ulCurrentIn -
  462. // hrStatusIn -
  463. // pcszDescriptionIn -
  464. // pftTimeIn -
  465. // pcszReferenceIn -
  466. //
  467. // Return Values:
  468. // S_OK - Operation completed successfully.
  469. //
  470. //--
  471. //////////////////////////////////////////////////////////////////////////////
  472. HRESULT
  473. CTaskTreeView::HrOnSendStatusReport(
  474. LPCWSTR pcszNodeNameIn
  475. , CLSID clsidTaskMajorIn
  476. , CLSID clsidTaskMinorIn
  477. , ULONG ulMinIn
  478. , ULONG ulMaxIn
  479. , ULONG ulCurrentIn
  480. , HRESULT hrStatusIn
  481. , LPCWSTR pcszDescriptionIn
  482. , FILETIME * pftTimeIn
  483. , LPCWSTR pcszReferenceIn
  484. )
  485. {
  486. TraceFunc( "" );
  487. HRESULT hr = S_OK;
  488. DWORD sc;
  489. int nImageChild;
  490. STreeItemLParamData tipd;
  491. HTREEITEM htiRoot;
  492. BSTR bstrStatus = NULL;
  493. //////////////////////////////////////////////////////////////////////////
  494. //
  495. // Update status text.
  496. // Don't do this if it is a log-only message.
  497. //
  498. //////////////////////////////////////////////////////////////////////////
  499. if ( ( pcszDescriptionIn != NULL )
  500. && ! IsEqualIID( clsidTaskMajorIn, TASKID_Major_Client_Log )
  501. && ! IsEqualIID( clsidTaskMajorIn, TASKID_Major_Server_Log )
  502. && ! IsEqualIID( clsidTaskMajorIn, TASKID_Major_Client_And_Server_Log )
  503. )
  504. {
  505. BOOL fReturn;
  506. if ( pcszNodeNameIn != NULL )
  507. {
  508. LPWSTR psz;
  509. //
  510. // Shorten the FDQN DNS name to only the hostname.
  511. //
  512. psz = wcschr( pcszNodeNameIn, L'.' );
  513. if ( psz != NULL )
  514. {
  515. *psz = L'\0';
  516. }
  517. hr = THR( HrFormatMessageIntoBSTR(
  518. g_hInstance
  519. , IDS_FORMAT_STATUS
  520. , &bstrStatus
  521. , pcszNodeNameIn
  522. , pcszDescriptionIn
  523. ) );
  524. //
  525. // Restore the FQDN DNS name.
  526. //
  527. if ( psz != NULL )
  528. {
  529. *psz = L'.';
  530. }
  531. //
  532. // Handle the formatting error if there was one.
  533. //
  534. if ( FAILED( hr ) )
  535. {
  536. // TODO: Display default description instead of exiting this function
  537. goto Error;
  538. }
  539. } // if: node name was specified
  540. else
  541. {
  542. bstrStatus = TraceSysAllocString( pcszDescriptionIn );
  543. if ( bstrStatus == NULL )
  544. {
  545. hr = THR( E_OUTOFMEMORY );
  546. goto Error;
  547. }
  548. }
  549. Assert( bstrStatus!= NULL );
  550. Assert( *bstrStatus!= L'\0' );
  551. fReturn = SetWindowText( m_hwndStatus, bstrStatus );
  552. Assert( fReturn );
  553. } // if: description specified, not log-only
  554. //////////////////////////////////////////////////////////////////////////
  555. //
  556. // Select the right icon.
  557. //
  558. //////////////////////////////////////////////////////////////////////////
  559. switch ( hrStatusIn )
  560. {
  561. case S_OK:
  562. if ( ulCurrentIn == ulMaxIn )
  563. {
  564. nImageChild = tsDONE;
  565. }
  566. else
  567. {
  568. nImageChild = tsPENDING;
  569. }
  570. break;
  571. case S_FALSE:
  572. nImageChild = tsWARNING;
  573. break;
  574. case E_PENDING:
  575. nImageChild = tsPENDING;
  576. break;
  577. default:
  578. if ( FAILED( hrStatusIn ) )
  579. {
  580. nImageChild = tsFAILED;
  581. }
  582. else
  583. {
  584. nImageChild = tsWARNING;
  585. }
  586. break;
  587. } // switch: hrStatusIn
  588. //////////////////////////////////////////////////////////////////////////
  589. //
  590. // Loop through each item at the top of the tree looking for an item
  591. // whose minor ID matches this report's major ID.
  592. //
  593. //////////////////////////////////////////////////////////////////////////
  594. //
  595. // Fill in the param data structure.
  596. //
  597. tipd.hr = hrStatusIn;
  598. tipd.ulMin = ulMinIn;
  599. tipd.ulMax = ulMaxIn;
  600. tipd.ulCurrent = ulCurrentIn;
  601. CopyMemory( &tipd.clsidMajorTaskId, &clsidTaskMajorIn, sizeof( tipd.clsidMajorTaskId ) );
  602. CopyMemory( &tipd.clsidMinorTaskId, &clsidTaskMinorIn, sizeof( tipd.clsidMinorTaskId ) );
  603. CopyMemory( &tipd.ftTime, pftTimeIn, sizeof( tipd.ftTime ) );
  604. // tipd.bstrDescription is set above.
  605. if ( pcszNodeNameIn == NULL )
  606. {
  607. tipd.bstrNodeName = NULL;
  608. }
  609. else
  610. {
  611. tipd.bstrNodeName = TraceSysAllocString( pcszNodeNameIn );
  612. if ( tipd.bstrNodeName == NULL )
  613. {
  614. hr = THR( E_OUTOFMEMORY );
  615. goto Error;
  616. }
  617. }
  618. if ( pcszDescriptionIn == NULL )
  619. {
  620. tipd.bstrDescription = NULL;
  621. }
  622. else
  623. {
  624. tipd.bstrDescription = TraceSysAllocString( pcszDescriptionIn );
  625. if ( tipd.bstrDescription == NULL )
  626. {
  627. hr = THR( E_OUTOFMEMORY );
  628. goto Error;
  629. }
  630. }
  631. if ( pcszReferenceIn == NULL )
  632. {
  633. tipd.bstrReference = NULL;
  634. }
  635. else
  636. {
  637. tipd.bstrReference = TraceSysAllocString( pcszReferenceIn );
  638. if ( tipd.bstrReference == NULL )
  639. {
  640. hr = THR( E_OUTOFMEMORY );
  641. goto Error;
  642. }
  643. }
  644. // Start with the first item in the tree view.
  645. htiRoot = TreeView_GetRoot( m_hwndTV );
  646. if ( htiRoot == NULL )
  647. {
  648. sc = TW32( ERROR_NOT_FOUND );
  649. goto Win32Error;
  650. }
  651. // Insert the status report into the tree view.
  652. hr = STHR( HrInsertTaskIntoTree( htiRoot, &tipd, nImageChild, bstrStatus ) );
  653. if ( FAILED( hr ) )
  654. {
  655. LogMsg( "[WIZ] Error inserting status report into the tree control. hr=%.08x, %ws", tipd.hr, pcszDescriptionIn );
  656. goto Error;
  657. }
  658. if ( hr == S_FALSE )
  659. {
  660. // Don't return S_FALSE to the caller since it won't mean anything there.
  661. hr = S_OK;
  662. // TODO: Should this be written to the log?
  663. #if defined( DEBUG )
  664. //
  665. // Check to make sure that if the major task ID wasn't recognized
  666. // that it is one of the known exceptions.
  667. //
  668. if ( ! IsEqualIID( clsidTaskMajorIn, TASKID_Major_Client_Log )
  669. && ! IsEqualIID( clsidTaskMajorIn, TASKID_Major_Server_Log )
  670. && ! IsEqualIID( clsidTaskMajorIn, TASKID_Major_Client_And_Server_Log ) )
  671. {
  672. BSTR bstrMsg = NULL;
  673. THR( HrFormatStringIntoBSTR(
  674. g_hInstance
  675. , IDS_UNKNOWN_TASK
  676. , &bstrMsg
  677. , clsidTaskMajorIn.Data1 // 1
  678. , clsidTaskMajorIn.Data2 // 2
  679. , clsidTaskMajorIn.Data3 // 3
  680. , clsidTaskMajorIn.Data4[ 0 ] // 4
  681. , clsidTaskMajorIn.Data4[ 1 ] // 5
  682. , clsidTaskMajorIn.Data4[ 2 ] // 6
  683. , clsidTaskMajorIn.Data4[ 3 ] // 7
  684. , clsidTaskMajorIn.Data4[ 4 ] // 8
  685. , clsidTaskMajorIn.Data4[ 5 ] // 9
  686. , clsidTaskMajorIn.Data4[ 6 ] // 10
  687. , clsidTaskMajorIn.Data4[ 7 ] // 11
  688. ) );
  689. AssertString( 0, bstrMsg );
  690. TraceSysFreeString( bstrMsg );
  691. }
  692. #endif // DEBUG
  693. } // if: S_FALSE returned from HrInsertTaskIntoTree
  694. goto Cleanup;
  695. Win32Error:
  696. // Don't return an error result since doing so will prevent the report
  697. // from being propagated to other subscribers.
  698. // hr = HRESULT_FROM_WIN32( sc );
  699. hr = S_OK;
  700. goto Cleanup;
  701. Error:
  702. // Don't return an error result since doing so will prevent the report
  703. // from being propagated to other subscribers.
  704. hr = S_OK;
  705. goto Cleanup;
  706. Cleanup:
  707. TraceSysFreeString( bstrStatus );
  708. TraceSysFreeString( tipd.bstrNodeName );
  709. TraceSysFreeString( tipd.bstrDescription );
  710. TraceSysFreeString( tipd.bstrReference );
  711. HRETURN( hr );
  712. } //*** CTaskTreeView::HrOnSendStatusReport()
  713. //////////////////////////////////////////////////////////////////////////////
  714. //++
  715. //
  716. // CTaskTreeView::HrInsertTaskIntoTree
  717. //
  718. // Description:
  719. // Insert the specified task into the tree based on the node, major
  720. // task, and minor task.
  721. //
  722. // Arguments:
  723. // htiFirstIn - First tree item to examine.
  724. // ptipdIn - Tree item parameter data for the task to be inserted.
  725. // nImageIn - Image identifier for the child item.
  726. // bstrDescriptionIn - Description string to display.
  727. //
  728. // Return Values:
  729. // S_OK - Task inserted successfully.
  730. // S_FALSE - Task not inserted.
  731. // hr - The operation failed.
  732. //
  733. //--
  734. //////////////////////////////////////////////////////////////////////////////
  735. HRESULT
  736. CTaskTreeView::HrInsertTaskIntoTree(
  737. HTREEITEM htiFirstIn
  738. , STreeItemLParamData * ptipdIn
  739. , int nImageIn
  740. , BSTR bstrDescriptionIn
  741. )
  742. {
  743. TraceFunc( "" );
  744. Assert( htiFirstIn != NULL );
  745. Assert( ptipdIn != NULL );
  746. //
  747. // LOCAL VARIABLES
  748. //
  749. HRESULT hr;
  750. DWORD sc;
  751. HTREEITEM htiParent;
  752. HTREEITEM htiChild = NULL;
  753. TVITEMEX tviParent;
  754. TVITEMEX tviChild;
  755. BOOL fReturn;
  756. BOOL fOnlyUpdateProgress;
  757. STreeItemLParamData * ptipdParent = NULL;
  758. STreeItemLParamData * ptipdChild = NULL;
  759. //
  760. // Determine if this report is only for updating progress.
  761. //
  762. fOnlyUpdateProgress = IsEqualIID( ptipdIn->clsidMinorTaskId, TASKID_Minor_Update_Progress );
  763. //
  764. // Loop through each item to determine if the task should be added below
  765. // that item. If not, attempt to traverse its children.
  766. //
  767. for ( htiParent = htiFirstIn, hr = S_FALSE
  768. ; ( htiParent != NULL ) && ( hr == S_FALSE )
  769. ; )
  770. {
  771. //
  772. // Get the information about this item in the tree.
  773. //
  774. tviParent.mask = TVIF_PARAM | TVIF_IMAGE;
  775. tviParent.hItem = htiParent;
  776. fReturn = TreeView_GetItem( m_hwndTV, &tviParent );
  777. if ( ! fReturn )
  778. {
  779. sc = TW32( ERROR_NOT_FOUND );
  780. goto Win32Error;
  781. }
  782. ptipdParent = reinterpret_cast< STreeItemLParamData * >( tviParent.lParam );
  783. Assert( ptipdParent != NULL );
  784. //
  785. // See if this item could be the parent.
  786. // If not, recurse through child items.
  787. //
  788. if ( IsEqualIID( ptipdIn->clsidMajorTaskId, ptipdParent->clsidMinorTaskId ) )
  789. {
  790. //
  791. // FOUND THE PARENT ITEM
  792. //
  793. // Is this report intended only for updating progress?
  794. //
  795. if ( fOnlyUpdateProgress )
  796. {
  797. //
  798. // REPORT ONLY TO UPDATE PROGRESS
  799. //
  800. Assert( ptipdIn->hr == S_OK );
  801. Assert( ptipdIn->bstrReference == NULL );
  802. //
  803. // Update the progress bar.
  804. //
  805. THR( HrUpdateProgressBar( ptipdIn, ptipdParent ) );
  806. // ignore failure.
  807. //
  808. // Copy data from the report to the tree view item.
  809. // Since this is a progress update, only progress fields
  810. // are allowed to be specified.
  811. //
  812. ptipdParent->ulMin = ptipdIn->ulMin;
  813. ptipdParent->ulMax = ptipdIn->ulMax;
  814. ptipdParent->ulCurrent = ptipdIn->ulCurrent;
  815. CopyMemory( &ptipdParent->ftTime, &ptipdIn->ftTime, sizeof( ptipdParent->ftTime ) );
  816. } // if: only updating progress
  817. else
  818. {
  819. BOOL fMinorTaskIdMatches;
  820. BOOL fBothNodeNamesPresent;
  821. BOOL fBothNodeNamesEmpty;
  822. BOOL fNodeNamesEqual;
  823. //
  824. // REPORT NOT JUST TO UPDATE PROGRESS
  825. //
  826. //////////////////////////////////////////////////////////////
  827. //
  828. // Loop through the child items looking for an item with
  829. // the same minor ID.
  830. //
  831. //////////////////////////////////////////////////////////////
  832. htiChild = TreeView_GetChild( m_hwndTV, htiParent );
  833. while ( htiChild != NULL )
  834. {
  835. //
  836. // Get the child item details.
  837. //
  838. tviChild.mask = TVIF_PARAM | TVIF_IMAGE;
  839. tviChild.hItem = htiChild;
  840. fReturn = TreeView_GetItem( m_hwndTV, &tviChild );
  841. if ( ! fReturn )
  842. {
  843. sc = TW32( ERROR_NOT_FOUND );
  844. goto Win32Error;
  845. }
  846. ptipdChild = reinterpret_cast< STreeItemLParamData * >( tviChild.lParam );
  847. Assert( ptipdChild != NULL );
  848. //
  849. // Does this child item match the minor ID and node name?
  850. //
  851. fMinorTaskIdMatches = IsEqualIID( ptipdIn->clsidMinorTaskId, ptipdChild->clsidMinorTaskId );
  852. fBothNodeNamesPresent = ( ptipdIn->bstrNodeName != NULL ) && ( ptipdChild->bstrNodeName != NULL );
  853. fBothNodeNamesEmpty = ( ptipdIn->bstrNodeName == NULL ) && ( ptipdChild->bstrNodeName == NULL );
  854. if ( fBothNodeNamesPresent )
  855. {
  856. fNodeNamesEqual = ( _wcsicmp( ptipdIn->bstrNodeName, ptipdChild->bstrNodeName ) == 0 );
  857. }
  858. else if ( fBothNodeNamesEmpty )
  859. {
  860. fNodeNamesEqual = TRUE;
  861. }
  862. else
  863. {
  864. fNodeNamesEqual = FALSE;
  865. }
  866. if ( fMinorTaskIdMatches && fNodeNamesEqual )
  867. {
  868. //
  869. // CHILD ITEM MATCHES.
  870. // Update the child item.
  871. //
  872. //
  873. // Update the progress bar.
  874. //
  875. THR( HrUpdateProgressBar( ptipdIn, ptipdChild ) );
  876. // ignore failure.
  877. //
  878. // Copy data from the report.
  879. // This must be done after the call to
  880. // HrUpdateProgressBar so that the previous values
  881. // can be compared to the new values.
  882. //
  883. ptipdChild->ulMin = ptipdIn->ulMin;
  884. ptipdChild->ulMax = ptipdIn->ulMax;
  885. ptipdChild->ulCurrent = ptipdIn->ulCurrent;
  886. CopyMemory( &ptipdChild->ftTime, &ptipdIn->ftTime, sizeof( ptipdChild->ftTime ) );
  887. // Update the error code if needed.
  888. if ( ptipdChild->hr == S_OK )
  889. {
  890. ptipdChild->hr = ptipdIn->hr;
  891. }
  892. //
  893. // If the new state is worse than the last state,
  894. // update the state of the item.
  895. //
  896. if ( tviChild.iImage < nImageIn )
  897. {
  898. tviChild.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE;
  899. tviChild.iImage = nImageIn;
  900. tviChild.iSelectedImage = nImageIn;
  901. TreeView_SetItem( m_hwndTV, &tviChild );
  902. } // if: new state is worse than the last state
  903. //
  904. // Update the text of the child item if needed.
  905. //
  906. if ( ( ptipdIn->bstrDescription != NULL )
  907. && ( ( ptipdChild->bstrDescription == NULL )
  908. || ( wcscmp( ptipdIn->bstrDescription, ptipdChild->bstrDescription ) != 0 )
  909. )
  910. )
  911. {
  912. fReturn = TraceSysReAllocString( &ptipdChild->bstrDescription, ptipdIn->bstrDescription );
  913. if ( ! fReturn )
  914. {
  915. hr = THR( E_OUTOFMEMORY );
  916. goto Cleanup;
  917. }
  918. tviChild.mask = TVIF_TEXT;
  919. tviChild.pszText = bstrDescriptionIn;
  920. tviChild.cchTextMax = SysStringLen( tviChild.pszText );
  921. TreeView_SetItem( m_hwndTV, &tviChild );
  922. } // if: description was specified and is different
  923. //
  924. // Copy the reference if it is different.
  925. //
  926. if ( ( ptipdIn->bstrReference != NULL )
  927. && ( ( ptipdChild->bstrReference == NULL )
  928. || ( wcscmp( ptipdChild->bstrReference, ptipdIn->bstrReference ) != 0 )
  929. )
  930. )
  931. {
  932. fReturn = TraceSysReAllocString( &ptipdChild->bstrReference, ptipdIn->bstrReference );
  933. if ( ! fReturn )
  934. {
  935. hr = THR( E_OUTOFMEMORY );
  936. goto Cleanup;
  937. }
  938. } // if: reference is different
  939. break; // exit loop
  940. } // if: found a matching child item
  941. //
  942. // Get the next item.
  943. //
  944. htiChild = TreeView_GetNextSibling( m_hwndTV, htiChild );
  945. } // while: more child items
  946. //////////////////////////////////////////////////////////////
  947. //
  948. // If the tree item was not found and the description was
  949. // specified, then we need to create the child item.
  950. //
  951. //////////////////////////////////////////////////////////////
  952. if ( ( htiChild == NULL )
  953. && ( ptipdIn->bstrDescription != NULL )
  954. )
  955. {
  956. //
  957. // ITEM NOT FOUND AND DESCRIPTION WAS SPECIFIED
  958. //
  959. // Insert a new item in the tree under the major's task.
  960. //
  961. TVINSERTSTRUCT tvis;
  962. // Create the item.
  963. hr = THR( HrCreateTreeItem(
  964. &tvis
  965. , ptipdIn
  966. , htiParent
  967. , nImageIn
  968. , bstrDescriptionIn
  969. ) );
  970. if ( FAILED( hr ) )
  971. {
  972. goto Cleanup;
  973. }
  974. // Insert the item in the tree.
  975. htiChild = TreeView_InsertItem( m_hwndTV, &tvis );
  976. Assert( htiChild != NULL );
  977. //
  978. // Update the progress bar.
  979. //
  980. ptipdChild = reinterpret_cast< STreeItemLParamData * >( tvis.itemex.lParam );
  981. Assert( ptipdChild != NULL );
  982. THR( HrUpdateProgressBar( ptipdIn, ptipdChild ) );
  983. // ignore failure.
  984. } // if: need to add new child
  985. //////////////////////////////////////////////////////////////
  986. //
  987. // If the child item was created and the child has an error
  988. // condition, then create a child of the child item
  989. // indicating the error code and system string.
  990. //
  991. //////////////////////////////////////////////////////////////
  992. if ( ( ptipdChild != NULL )
  993. && FAILED( ptipdIn->hr )
  994. )
  995. {
  996. //
  997. // CHILD ITEM FOUND OR CREATED FOR ERROR REPORT
  998. // CREATE ERROR ITEM IN THE TREE
  999. //
  1000. BSTR bstrError = NULL;
  1001. BSTR bstrErrorDescription = NULL;
  1002. HRESULT hrFormat;
  1003. TVINSERTSTRUCT tvis;
  1004. HTREEITEM htiChildStatus;
  1005. THR( HrFormatErrorIntoBSTR( ptipdIn->hr, &bstrError ) );
  1006. hrFormat = THR( HrFormatMessageIntoBSTR(
  1007. g_hInstance
  1008. , IDS_TASK_RETURNED_ERROR
  1009. , &bstrErrorDescription
  1010. , ptipdIn->hr
  1011. , ( bstrError == NULL ? L"" : bstrError )
  1012. ) );
  1013. if ( SUCCEEDED( hrFormat ) )
  1014. {
  1015. //
  1016. // Insert a new item in the tree under the minor's
  1017. // task explaining the ptipdIn->hr.
  1018. //
  1019. // Create the item.
  1020. hr = THR( HrCreateTreeItem(
  1021. &tvis
  1022. , ptipdIn
  1023. , htiChild
  1024. , nImageIn
  1025. , bstrErrorDescription
  1026. ) );
  1027. if ( SUCCEEDED( hr ) )
  1028. {
  1029. //
  1030. // Failures are handled below to make sure we free
  1031. // all the strings allocated by this section of
  1032. // the code.
  1033. //
  1034. // Insert the item.
  1035. htiChildStatus = TreeView_InsertItem( m_hwndTV, &tvis );
  1036. Assert( htiChildStatus != NULL );
  1037. } // if: tree item created successfully
  1038. TraceSysFreeString( bstrErrorDescription );
  1039. } // if: message formatted successfully
  1040. TraceSysFreeString( bstrError );
  1041. //
  1042. // This error handling is for the return value from
  1043. // HrCreateTreeItem above. It is here so that all the strings
  1044. // can be cleaned up without having to resort to hokey
  1045. // boolean variables or move the bstrs to a more global scope.
  1046. //
  1047. if ( FAILED( hr ) )
  1048. {
  1049. goto Cleanup;
  1050. }
  1051. } // if: child and error
  1052. //////////////////////////////////////////////////////////////
  1053. //
  1054. // If a child was found or created, propagate its state to
  1055. // the parent items.
  1056. //
  1057. //////////////////////////////////////////////////////////////
  1058. if ( htiChild != NULL )
  1059. {
  1060. hr = STHR( HrPropagateChildStateToParents(
  1061. htiChild
  1062. , nImageIn
  1063. , fOnlyUpdateProgress
  1064. ) );
  1065. if ( FAILED( hr ) )
  1066. {
  1067. goto Cleanup;
  1068. }
  1069. } // if: found or created a child
  1070. } // else: not just updating progress
  1071. //
  1072. // Return success since we found the parent for this report.
  1073. //
  1074. hr = S_OK;
  1075. break;
  1076. } // if: found an item to be the parent
  1077. else
  1078. {
  1079. //
  1080. // PARENT ITEM NOT FOUND
  1081. //
  1082. // Recurse through all the child items.
  1083. //
  1084. htiChild = TreeView_GetChild( m_hwndTV, htiParent );
  1085. while ( htiChild != NULL )
  1086. {
  1087. hr = STHR( HrInsertTaskIntoTree( htiChild, ptipdIn, nImageIn, bstrDescriptionIn ) );
  1088. if ( hr == S_OK )
  1089. {
  1090. // Found a match, so exit the loop.
  1091. break;
  1092. }
  1093. htiChild = TreeView_GetNextSibling( m_hwndTV, htiChild );
  1094. } // while: more child items
  1095. } // else: item not the parent
  1096. //
  1097. // Get the next sibling of the parent.
  1098. //
  1099. htiParent = TreeView_GetNextSibling( m_hwndTV, htiParent );
  1100. } // for: each item at this level in the tree
  1101. goto Cleanup;
  1102. Win32Error:
  1103. hr = HRESULT_FROM_WIN32( sc );
  1104. goto Cleanup;
  1105. Cleanup:
  1106. RETURN( hr );
  1107. } //*** CTaskTreeView::HrInsertTaskIntoTree()
  1108. //////////////////////////////////////////////////////////////////////////////
  1109. //++
  1110. //
  1111. // CTaskTreeView::HrUpdateProgressBar
  1112. //
  1113. // Description:
  1114. // Update the progress bar based on new tree item data.
  1115. //
  1116. // Arguments:
  1117. // ptipdNewIn - New values of the tree item data.
  1118. // ptipdPrevIn - Previous values of the tree item data.
  1119. //
  1120. // Return Values:
  1121. // S_OK - Operation completed successfully.
  1122. //
  1123. //--
  1124. //////////////////////////////////////////////////////////////////////////////
  1125. HRESULT
  1126. CTaskTreeView::HrUpdateProgressBar(
  1127. const STreeItemLParamData * ptipdNewIn
  1128. , const STreeItemLParamData * ptipdPrevIn
  1129. )
  1130. {
  1131. TraceFunc( "" );
  1132. Assert( ptipdNewIn != NULL );
  1133. Assert( ptipdPrevIn != NULL );
  1134. HRESULT hr = S_OK;
  1135. LRESULT lr;
  1136. ULONG ulCurrent;
  1137. PBRANGE pbrange;
  1138. //
  1139. // Evaluate max value.
  1140. //
  1141. if ( m_ulHighNibble < ( ptipdPrevIn->ulMax - ptipdNewIn->ulMax ) )
  1142. {
  1143. //
  1144. // Out of space and need to expand range.
  1145. //
  1146. m_ulHighNibble = 0;
  1147. SendMessage( m_hwndProg, PBM_GETRANGE, 0, (LPARAM) &pbrange );
  1148. pbrange.iHigh += ( ptipdPrevIn->ulMax - ptipdNewIn->ulMax );
  1149. SendMessage( m_hwndProg, PBM_SETRANGE, 0, (LPARAM) MAKELPARAM( pbrange.iLow, pbrange.iHigh ) );
  1150. }
  1151. else
  1152. {
  1153. //
  1154. // Keep nibbling away.
  1155. //
  1156. m_ulHighNibble -= ( ptipdPrevIn->ulMax - ptipdNewIn->ulMax );
  1157. }
  1158. //
  1159. // Evaluate min value.
  1160. //
  1161. if ( m_ulLowNibble < ( ptipdPrevIn->ulMin - ptipdNewIn->ulMin ) )
  1162. {
  1163. //
  1164. // Out of space and need to expand range.
  1165. //
  1166. m_ulLowNibble = 0;
  1167. SendMessage( m_hwndProg, PBM_GETRANGE, 0, (LPARAM) &pbrange );
  1168. pbrange.iLow += ( ptipdPrevIn->ulMin - ptipdNewIn->ulMin );
  1169. SendMessage( m_hwndProg, PBM_SETRANGE, 0, (LPARAM) MAKELPARAM( pbrange.iLow, pbrange.iHigh ) );
  1170. }
  1171. else
  1172. {
  1173. //
  1174. // Keep nibbling away.
  1175. //
  1176. m_ulLowNibble -= ( ptipdPrevIn->ulMin - ptipdNewIn->ulMin );
  1177. }
  1178. //
  1179. // Update the progress bar.
  1180. //
  1181. lr = SendMessage( m_hwndProg, PBM_GETPOS, 0, 0 );
  1182. ulCurrent = static_cast< ULONG >( lr );
  1183. ulCurrent += ( ptipdPrevIn->ulCurrent - ptipdNewIn->ulCurrent );
  1184. SendMessage( m_hwndProg, PBM_SETPOS, ulCurrent, 0 );
  1185. HRETURN( hr );
  1186. } //*** CTaskTreeView::HrUpdateProgressBar()
  1187. //////////////////////////////////////////////////////////////////////////////
  1188. //++
  1189. //
  1190. // CTaskTreeView::HrPropagateChildStateToParents
  1191. //
  1192. // Description:
  1193. // Extend the state of a child item to its parent items.
  1194. // If the state of the child is worse (higher priority) than the
  1195. // parent's, update the state of the parent.
  1196. //
  1197. // Arguments:
  1198. // htiChildIn - Child item whose state is to be extended.
  1199. // nImageIn - Image of the child item.
  1200. // fOnlyUpdateProgressIn - TRUE = only updating progress.
  1201. //
  1202. // Return Values:
  1203. // S_OK - Operation completed successfully.
  1204. // S_FALSE - No parent item.
  1205. //
  1206. //--
  1207. //////////////////////////////////////////////////////////////////////////////
  1208. HRESULT
  1209. CTaskTreeView::HrPropagateChildStateToParents(
  1210. HTREEITEM htiChildIn
  1211. , int nImageIn
  1212. , BOOL fOnlyUpdateProgressIn
  1213. )
  1214. {
  1215. TraceFunc( "" );
  1216. Assert( htiChildIn != NULL );
  1217. HRESULT hr = S_OK;
  1218. DWORD sc;
  1219. BOOL fReturn;
  1220. TVITEMEX tviParent;
  1221. TVITEMEX tviChild;
  1222. HTREEITEM htiParent;
  1223. HTREEITEM htiChild;
  1224. //
  1225. // Get the parent item.
  1226. //
  1227. htiParent = TreeView_GetParent( m_hwndTV, htiChildIn );
  1228. if ( htiParent == NULL )
  1229. {
  1230. hr = S_FALSE;
  1231. goto Cleanup;
  1232. }
  1233. tviParent.mask = TVIF_PARAM | TVIF_IMAGE;
  1234. tviParent.hItem = htiParent;
  1235. fReturn = TreeView_GetItem( m_hwndTV, &tviParent );
  1236. if ( ! fReturn )
  1237. {
  1238. sc = TW32( ERROR_NOT_FOUND );
  1239. goto Win32Error;
  1240. }
  1241. //
  1242. // If the state of the child is worse (higher priority) than the
  1243. // parent's, update the state of the parent.
  1244. //
  1245. if ( ( tviParent.iImage < nImageIn )
  1246. || ( ( tviParent.iImage == tsDONE )
  1247. && ( nImageIn == tsPENDING )
  1248. )
  1249. )
  1250. {
  1251. //
  1252. // Special Case: For the parent to be set to tsDONE, all
  1253. // the children must be set to tsDONE as well.
  1254. //
  1255. if ( ( nImageIn == tsDONE )
  1256. && ! fOnlyUpdateProgressIn
  1257. )
  1258. {
  1259. //
  1260. // Enum the children to see if they all have tsDONE as their images.
  1261. //
  1262. htiChild = TreeView_GetChild( m_hwndTV, tviParent.hItem );
  1263. while ( htiChild != NULL )
  1264. {
  1265. tviChild.mask = TVIF_IMAGE;
  1266. tviChild.hItem = htiChild;
  1267. fReturn = TreeView_GetItem( m_hwndTV, &tviChild );
  1268. if ( ! fReturn )
  1269. {
  1270. sc = TW32( ERROR_NOT_FOUND );
  1271. goto Win32Error;
  1272. }
  1273. if ( tviChild.iImage != tsDONE )
  1274. {
  1275. //
  1276. // Not all tsDONE! Skip setting parent's image!
  1277. // This can occur if the child is displaying a warning
  1278. // or error state image.
  1279. //
  1280. goto Cleanup;
  1281. }
  1282. // Get next child
  1283. htiChild = TreeView_GetNextSibling( m_hwndTV, htiChild );
  1284. } // while: more children
  1285. } // if: special case (see above)
  1286. //
  1287. // Set the parent's icon.
  1288. //
  1289. tviParent.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE;
  1290. tviParent.iImage = nImageIn;
  1291. tviParent.iSelectedImage = nImageIn;
  1292. TreeView_SetItem( m_hwndTV, &tviParent );
  1293. } // if: need to update parent's image
  1294. //
  1295. // Traverse up the tree.
  1296. //
  1297. hr = STHR( HrPropagateChildStateToParents( htiParent, nImageIn, fOnlyUpdateProgressIn ) );
  1298. if ( hr == S_FALSE )
  1299. {
  1300. // S_FALSE means that there wasn't a parent.
  1301. hr = S_OK;
  1302. }
  1303. goto Cleanup;
  1304. Win32Error:
  1305. hr = HRESULT_FROM_WIN32( sc );
  1306. goto Cleanup;
  1307. Cleanup:
  1308. HRETURN( hr );
  1309. } //*** CTaskTreeView::HrPropagateChildStateToParents()
  1310. //////////////////////////////////////////////////////////////////////////////
  1311. //++
  1312. //
  1313. // CTaskTreeView::HrDisplayDetails
  1314. //
  1315. // Description:
  1316. // Display the Details dialog box.
  1317. //
  1318. // Arguments:
  1319. // None.
  1320. //
  1321. // Return Values:
  1322. // S_OK
  1323. //
  1324. //--
  1325. //////////////////////////////////////////////////////////////////////////////
  1326. HRESULT
  1327. CTaskTreeView::HrDisplayDetails( void )
  1328. {
  1329. TraceFunc( "" );
  1330. HRESULT hr = S_OK;
  1331. HTREEITEM hti;
  1332. HWND hwndPropertyPage;
  1333. //
  1334. // If no item is selected, select the first item.
  1335. //
  1336. if ( m_htiSelected == NULL )
  1337. {
  1338. hti = TreeView_GetRoot( m_hwndTV );
  1339. Assert( hti != NULL );
  1340. hr = THR( HrSelectItem( hti ) );
  1341. if ( FAILED( hr ) )
  1342. {
  1343. // TODO: Display message box
  1344. goto Cleanup;
  1345. }
  1346. } // if: no items are selected
  1347. //
  1348. // Display the dialog box.
  1349. //
  1350. hwndPropertyPage = GetParent( m_hwndTV );
  1351. Assert( hwndPropertyPage != NULL );
  1352. hr = THR( CDetailsDlg::S_HrDisplayModalDialog( hwndPropertyPage, this, m_htiSelected ) );
  1353. SetFocus( m_hwndTV );
  1354. Cleanup:
  1355. HRETURN( hr );
  1356. } //*** CTaskTreeView::HrDisplayDetails()
  1357. //////////////////////////////////////////////////////////////////////////////
  1358. //++
  1359. //
  1360. // CTaskTreeView::FGetItem
  1361. //
  1362. // Description:
  1363. // Get the data for an item.
  1364. //
  1365. // Arguments:
  1366. // htiIn - Handle for the item to get.
  1367. // pptipdOut - Pointer in which to return the data structure.
  1368. //
  1369. // Return Values:
  1370. // TRUE - Item returned successfully.
  1371. // FALSE - Item not returned.
  1372. //
  1373. //--
  1374. //////////////////////////////////////////////////////////////////////////////
  1375. BOOL
  1376. CTaskTreeView::FGetItem(
  1377. HTREEITEM htiIn
  1378. , STreeItemLParamData ** pptipd
  1379. )
  1380. {
  1381. TraceFunc( "" );
  1382. Assert( htiIn != NULL );
  1383. Assert( pptipd != NULL );
  1384. BOOL fRet;
  1385. TVITEMEX tvi;
  1386. ZeroMemory( &tvi, sizeof( tvi ) );
  1387. tvi.mask = TVIF_PARAM;
  1388. tvi.hItem = htiIn;
  1389. fRet = TreeView_GetItem( m_hwndTV, &tvi );
  1390. if ( fRet == FALSE )
  1391. {
  1392. goto Cleanup;
  1393. }
  1394. Assert( tvi.lParam != NULL );
  1395. *pptipd = reinterpret_cast< STreeItemLParamData * >( tvi.lParam );
  1396. Cleanup:
  1397. RETURN( fRet );
  1398. } //*** CTaskTreeView::FGetItem()
  1399. //////////////////////////////////////////////////////////////////////////////
  1400. //++
  1401. //
  1402. // CTaskTreeView::HrFindPrevItem
  1403. //
  1404. // Description:
  1405. // Find the previous item. The previous item could be at a deeper
  1406. // level than this item.
  1407. //
  1408. // Arguments:
  1409. // phtiOut - Handle to previous item (optional).
  1410. //
  1411. // Return Values:
  1412. // S_OK - Previous item found successfully.
  1413. // S_FALSE - No previous item found.
  1414. // Other HRESULTs.
  1415. //
  1416. //--
  1417. //////////////////////////////////////////////////////////////////////////////
  1418. HRESULT
  1419. CTaskTreeView::HrFindPrevItem(
  1420. HTREEITEM * phtiOut
  1421. )
  1422. {
  1423. TraceFunc( "" );
  1424. HRESULT hr = S_FALSE;
  1425. HTREEITEM htiCur;
  1426. HTREEITEM htiPrev;
  1427. htiCur = m_htiSelected;
  1428. if ( phtiOut != NULL )
  1429. {
  1430. *phtiOut = NULL;
  1431. }
  1432. //
  1433. // Find the previous sibling item.
  1434. //
  1435. htiPrev = TreeView_GetPrevSibling( m_hwndTV, htiCur );
  1436. if ( htiPrev == NULL )
  1437. {
  1438. //
  1439. // NO PREVIOUS SIBLING ITEM FOUND.
  1440. //
  1441. // Find the parent item.
  1442. // If there isn't a parent, then there isn't a previous item.
  1443. //
  1444. htiPrev = TreeView_GetParent( m_hwndTV, htiCur );
  1445. if ( htiPrev == NULL )
  1446. {
  1447. goto Cleanup;
  1448. } // if: no parent item
  1449. //
  1450. // The parent is the previous item.
  1451. //
  1452. } // if: no previous sibling
  1453. else
  1454. {
  1455. //
  1456. // PREVIOUS SIBLING ITEM FOUND.
  1457. //
  1458. // Find the deepest child of the last child item.
  1459. //
  1460. for ( ;; )
  1461. {
  1462. //
  1463. // Find the first child item.
  1464. //
  1465. htiCur = TreeView_GetChild( m_hwndTV, htiPrev );
  1466. if ( htiCur == NULL )
  1467. {
  1468. //
  1469. // NO CHILD ITEM FOUND.
  1470. //
  1471. // This is the previous item.
  1472. //
  1473. break;
  1474. } // if: no children
  1475. //
  1476. // CHILD ITEM FOUND.
  1477. //
  1478. // Find the last sibling of this child item.
  1479. //
  1480. for ( ;; )
  1481. {
  1482. //
  1483. // Find the next sibling item.
  1484. //
  1485. htiPrev = TreeView_GetNextSibling( m_hwndTV, htiCur );
  1486. if ( htiPrev == NULL )
  1487. {
  1488. //
  1489. // No next sibling item found.
  1490. // Exit this loop and continue the outer loop
  1491. // to find this item's children.
  1492. //
  1493. htiPrev = htiCur;
  1494. break;
  1495. } // if: no next sibling item found
  1496. //
  1497. // Found a next sibling item.
  1498. //
  1499. htiCur = htiPrev;
  1500. } // forever: find the last child item
  1501. } // forever: find the deepest child item
  1502. } // else: previous sibling item found
  1503. //
  1504. // Return the item we found.
  1505. //
  1506. Assert( htiPrev != NULL );
  1507. if ( phtiOut != NULL )
  1508. {
  1509. *phtiOut = htiPrev;
  1510. }
  1511. hr = S_OK;
  1512. Cleanup:
  1513. HRETURN( hr );
  1514. } //*** CTaskTreeView::HrFindPrevItem()
  1515. //////////////////////////////////////////////////////////////////////////////
  1516. //++
  1517. //
  1518. // CTaskTreeView::HrFindNextItem
  1519. //
  1520. // Description:
  1521. // Find the next item. The next item could be at a different level than
  1522. // this item.
  1523. //
  1524. // Arguments:
  1525. // phtiOut - Handle to next item (optional).
  1526. //
  1527. // Return Values:
  1528. // S_OK - Next item found successfully.
  1529. // S_FALSE - No next item found.
  1530. // Other HRESULTs.
  1531. //
  1532. //--
  1533. //////////////////////////////////////////////////////////////////////////////
  1534. HRESULT
  1535. CTaskTreeView::HrFindNextItem(
  1536. HTREEITEM * phtiOut
  1537. )
  1538. {
  1539. TraceFunc( "" );
  1540. HRESULT hr = S_FALSE;
  1541. HTREEITEM htiCur;
  1542. HTREEITEM htiNext;
  1543. htiCur = m_htiSelected;
  1544. if ( phtiOut != NULL )
  1545. {
  1546. *phtiOut = NULL;
  1547. }
  1548. //
  1549. // Find the first child item.
  1550. //
  1551. htiNext = TreeView_GetChild( m_hwndTV, htiCur );
  1552. if ( htiNext == NULL )
  1553. {
  1554. //
  1555. // NO CHILD ITEM FOUND.
  1556. //
  1557. for ( ;; )
  1558. {
  1559. //
  1560. // Get the next sibling item.
  1561. //
  1562. htiNext = TreeView_GetNextSibling( m_hwndTV, htiCur );
  1563. if ( htiNext == NULL )
  1564. {
  1565. //
  1566. // NO SIBLING ITEM FOUND.
  1567. //
  1568. // Find the parent item so we can find its next sibling.
  1569. //
  1570. htiNext = TreeView_GetParent( m_hwndTV, htiCur );
  1571. if ( htiNext == NULL )
  1572. {
  1573. //
  1574. // NO PARENT ITEM FOUND.
  1575. //
  1576. // At the end of the tree.
  1577. //
  1578. goto Cleanup;
  1579. } // if: no parent found
  1580. //
  1581. // PARENT ITEM FOUND.
  1582. //
  1583. // Find the parent item's next sibling.
  1584. //
  1585. htiCur = htiNext;
  1586. continue;
  1587. } // if: no next sibling item
  1588. //
  1589. // SIBLING ITEM FOUND.
  1590. //
  1591. // Found the next item.
  1592. //
  1593. break;
  1594. } // forever: find the next sibling or parent's sibling
  1595. } // if: no child item found
  1596. else
  1597. {
  1598. //
  1599. // CHILD ITEM FOUND.
  1600. //
  1601. // Found the next item.
  1602. //
  1603. } // else: child item found
  1604. //
  1605. // Return the item we found.
  1606. //
  1607. Assert( htiNext != NULL );
  1608. if ( phtiOut != NULL )
  1609. {
  1610. *phtiOut = htiNext;
  1611. }
  1612. hr = S_OK;
  1613. Cleanup:
  1614. HRETURN( hr );
  1615. } //*** CTaskTreeView::HrFindNextItem()
  1616. //////////////////////////////////////////////////////////////////////////////
  1617. //++
  1618. //
  1619. // CTaskTreeView::HrSelectItem
  1620. //
  1621. // Description:
  1622. // Select the specified item.
  1623. //
  1624. // Arguments:
  1625. // htiIn - Handle to item to select.
  1626. //
  1627. // Return Values:
  1628. // S_OK - Item selected successfully.
  1629. // Other HRESULTs.
  1630. //
  1631. //--
  1632. //////////////////////////////////////////////////////////////////////////////
  1633. HRESULT
  1634. CTaskTreeView::HrSelectItem(
  1635. HTREEITEM htiIn
  1636. )
  1637. {
  1638. TraceFunc( "" );
  1639. Assert( htiIn != NULL );
  1640. HRESULT hr = S_OK;
  1641. TreeView_SelectItem( m_hwndTV, htiIn );
  1642. HRETURN( hr );
  1643. } //*** CTaskTreeView::HrSelectItem()
  1644. //****************************************************************************
  1645. //
  1646. // Static Functions
  1647. //
  1648. //****************************************************************************
  1649. //////////////////////////////////////////////////////////////////////////////
  1650. //++
  1651. //
  1652. // HrCreateTreeItem
  1653. //
  1654. // Description:
  1655. // Create a tree item.
  1656. //
  1657. // Arguments:
  1658. // ptvisOut - Tree view insert structure to fill in.
  1659. // ptipdIn - Input tree item LParam data to create this item from.
  1660. // htiParentIn - Parent tree view item.
  1661. // nImageIn - Image index.
  1662. // bstrTextIn - Text to display.
  1663. //
  1664. // Return Values:
  1665. // S_OK - Operation was successful.
  1666. // E_OUTOFMEMORY - Error allocating memory.
  1667. //
  1668. //--
  1669. //////////////////////////////////////////////////////////////////////////////
  1670. HRESULT
  1671. HrCreateTreeItem(
  1672. TVINSERTSTRUCT * ptvisOut
  1673. , STreeItemLParamData * ptipdIn
  1674. , HTREEITEM htiParentIn
  1675. , int nImageIn
  1676. , BSTR bstrTextIn
  1677. )
  1678. {
  1679. TraceFunc( "" );
  1680. Assert( ptvisOut != NULL );
  1681. Assert( ptipdIn != NULL );
  1682. Assert( htiParentIn != NULL );
  1683. Assert( bstrTextIn != NULL );
  1684. // LOCAL VARIABLES
  1685. HRESULT hr = S_OK;
  1686. STreeItemLParamData * ptipdNew = NULL;
  1687. //
  1688. // Allocate the tree view LParam data and initialize it.
  1689. //
  1690. ptipdNew = new STreeItemLParamData;
  1691. if ( ptipdNew == NULL )
  1692. {
  1693. hr = THR( E_OUTOFMEMORY );
  1694. goto Cleanup;
  1695. }
  1696. CopyMemory( &ptipdNew->clsidMajorTaskId, &ptipdIn->clsidMajorTaskId, sizeof( ptipdNew->clsidMajorTaskId ) );
  1697. CopyMemory( &ptipdNew->clsidMinorTaskId, &ptipdIn->clsidMinorTaskId, sizeof( ptipdNew->clsidMinorTaskId ) );
  1698. CopyMemory( &ptipdNew->ftTime, &ptipdIn->ftTime, sizeof( ptipdNew->ftTime ) );
  1699. ptipdNew->ulMin = ptipdIn->ulMin;
  1700. ptipdNew->ulMax = ptipdIn->ulMax;
  1701. ptipdNew->ulCurrent = ptipdIn->ulCurrent;
  1702. ptipdNew->hr = ptipdIn->hr;
  1703. if ( ptipdIn->bstrNodeName != NULL )
  1704. {
  1705. ptipdNew->bstrNodeName = TraceSysAllocString( ptipdIn->bstrNodeName );
  1706. if ( ptipdNew->bstrNodeName == NULL )
  1707. {
  1708. hr = THR( E_OUTOFMEMORY );
  1709. goto Cleanup;
  1710. }
  1711. }
  1712. if ( ptipdIn->bstrDescription != NULL )
  1713. {
  1714. ptipdNew->bstrDescription = TraceSysAllocString( ptipdIn->bstrDescription );
  1715. if ( ptipdNew->bstrDescription == NULL )
  1716. {
  1717. hr = THR( E_OUTOFMEMORY );
  1718. goto Cleanup;
  1719. }
  1720. }
  1721. if ( ptipdIn->bstrReference != NULL )
  1722. {
  1723. ptipdNew->bstrReference = TraceSysAllocString( ptipdIn->bstrReference );
  1724. if ( ptipdNew->bstrReference == NULL )
  1725. {
  1726. hr = THR( E_OUTOFMEMORY );
  1727. goto Cleanup;
  1728. }
  1729. }
  1730. //
  1731. // Initialize the tree view insert structure.
  1732. //
  1733. ptvisOut->hParent = htiParentIn;
  1734. ptvisOut->hInsertAfter = TVI_LAST;
  1735. ptvisOut->itemex.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM;
  1736. ptvisOut->itemex.cchTextMax = SysStringLen( bstrTextIn );
  1737. ptvisOut->itemex.pszText = bstrTextIn;
  1738. ptvisOut->itemex.iImage = nImageIn;
  1739. ptvisOut->itemex.iSelectedImage = nImageIn;
  1740. ptvisOut->itemex.lParam = reinterpret_cast< LPARAM >( ptipdNew );
  1741. Assert( ptvisOut->itemex.cchTextMax > 0 );
  1742. // Release ownership to the tree view insert structure.
  1743. ptipdNew = NULL;
  1744. goto Cleanup;
  1745. Cleanup:
  1746. if ( ptipdNew != NULL )
  1747. {
  1748. TraceSysFreeString( ptipdNew->bstrNodeName );
  1749. TraceSysFreeString( ptipdNew->bstrDescription );
  1750. TraceSysFreeString( ptipdNew->bstrReference );
  1751. delete ptipdNew;
  1752. }
  1753. HRETURN( hr );
  1754. } //*** HrCreateTreeItem()