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.

2585 lines
80 KiB

  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 2000-2002 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 PROGRESSBAR_CONTROL_TICK_COUNT 1000
  22. #define PROGRESSBAR_INITIAL_POSITION 10
  23. #define PROGRESSBAR_RESIZE_PERCENT 5
  24. //****************************************************************************
  25. //
  26. // Static Function Prototypes
  27. //
  28. //****************************************************************************
  29. static
  30. HRESULT
  31. HrCreateTreeItem(
  32. TVINSERTSTRUCT * ptvisOut
  33. , STreeItemLParamData * ptipdIn
  34. , HTREEITEM htiParentIn
  35. , int nImageIn
  36. , BSTR bstrTextIn
  37. );
  38. //////////////////////////////////////////////////////////////////////////////
  39. //++
  40. //
  41. // CTaskTreeView::CTaskTreeView
  42. //
  43. //--
  44. //////////////////////////////////////////////////////////////////////////////
  45. CTaskTreeView::CTaskTreeView(
  46. HWND hwndParentIn
  47. , UINT uIDTVIn
  48. , UINT uIDProgressIn
  49. , UINT uIDStatusIn
  50. , size_t nInitialTickCount
  51. )
  52. {
  53. TraceFunc( "" );
  54. m_hwndParent = hwndParentIn;
  55. m_hwndTV = GetDlgItem( hwndParentIn, uIDTVIn );
  56. Assert( m_hwndTV != NULL );
  57. m_hwndProg = GetDlgItem( hwndParentIn, uIDProgressIn );
  58. Assert( m_hwndProg != NULL );
  59. m_hwndStatus = GetDlgItem( hwndParentIn, uIDStatusIn );
  60. Assert( m_hwndStatus != NULL );
  61. m_hImgList = NULL;
  62. Assert( m_htiSelected == NULL );
  63. Assert( m_bstrClientMachineName == NULL );
  64. Assert( m_fDisplayErrorsAsWarnings == FALSE );
  65. //
  66. // Most of these get set in HrOnNotifySetActive, so just init them to zero.
  67. //
  68. m_nInitialTickCount = (ULONG) nInitialTickCount;
  69. m_nCurrentPos = 0;
  70. m_nRealPos = 0;
  71. m_fThresholdBroken = FALSE;
  72. m_cPASize = 0;
  73. m_cPACount = 0;
  74. m_ptipdProgressArray = NULL;
  75. TraceFuncExit();
  76. } //*** CTaskTreeView::CTaskTreeView()
  77. //////////////////////////////////////////////////////////////////////////////
  78. //++
  79. //
  80. // CTaskTreeView::~CTaskTreeView( void )
  81. //
  82. //--
  83. //////////////////////////////////////////////////////////////////////////////
  84. CTaskTreeView::~CTaskTreeView( void )
  85. {
  86. TraceFunc( "" );
  87. size_t idx;
  88. STreeItemLParamData * ptipdTemp;
  89. TreeView_DeleteAllItems( m_hwndTV );
  90. if ( m_hImgList != NULL )
  91. {
  92. ImageList_Destroy( m_hImgList );
  93. } // if:
  94. TraceSysFreeString( m_bstrClientMachineName );
  95. // Cleanup the progress array and delete any allocated entries.
  96. for ( idx = 0; idx < m_cPASize; idx++ )
  97. {
  98. if ( m_ptipdProgressArray[ idx ] != NULL )
  99. {
  100. ptipdTemp = m_ptipdProgressArray[ idx ];
  101. TraceSysFreeString( ptipdTemp->bstrNodeName );
  102. delete ptipdTemp;
  103. } // if: element is not NULL
  104. } // for: each element of the array
  105. delete [] m_ptipdProgressArray;
  106. TraceFuncExit();
  107. } //*** CTaskTreeView::~CTaskTreeView
  108. //////////////////////////////////////////////////////////////////////////////
  109. //++
  110. //
  111. // CTaskTreeView::HrOnInitDialog
  112. //
  113. // Description:
  114. // Handle the WM_INITDIALOG message.
  115. //
  116. // Arguments:
  117. // None.
  118. //
  119. // Return Values:
  120. // S_OK - Success.
  121. // Other HRESULTS.
  122. //
  123. //--
  124. //////////////////////////////////////////////////////////////////////////////
  125. HRESULT
  126. CTaskTreeView::HrOnInitDialog( void )
  127. {
  128. TraceFunc( "" );
  129. HRESULT hr = S_OK;
  130. HICON hIcon;
  131. int idx;
  132. Assert( m_bstrClientMachineName == NULL );
  133. hr = THR( HrGetComputerName(
  134. ComputerNameDnsHostname
  135. , &m_bstrClientMachineName
  136. , TRUE // fBestFit
  137. ) );
  138. if ( FAILED( hr ) )
  139. {
  140. goto Cleanup;
  141. } // if:
  142. //
  143. // Build image list for icons in tree view.
  144. //
  145. m_hImgList = ImageList_Create( 16, 16, ILC_MASK, tsMAX, 0);
  146. if ( m_hImgList == NULL )
  147. {
  148. hr = HRESULT_FROM_WIN32( TW32( GetLastError() ) );
  149. goto Cleanup;
  150. } // if:
  151. //
  152. // Unknown Icon - Task Unknown.
  153. //
  154. hIcon = (HICON) LoadImage( g_hInstance,
  155. MAKEINTRESOURCE( IDI_SEL ),
  156. IMAGE_ICON,
  157. 16,
  158. 16,
  159. LR_SHARED
  160. );
  161. if ( hIcon == NULL )
  162. {
  163. hr = HRESULT_FROM_WIN32( TW32( GetLastError() ) );
  164. goto Cleanup;
  165. } // if:
  166. idx = ImageList_AddIcon( m_hImgList, hIcon );
  167. Assert( idx == tsUNKNOWN );
  168. //
  169. // Pending Icon - Task Pending.
  170. //
  171. hIcon = (HICON) LoadImage( g_hInstance,
  172. MAKEINTRESOURCE( IDI_PENDING ),
  173. IMAGE_ICON,
  174. 16,
  175. 16,
  176. LR_SHARED
  177. );
  178. if ( hIcon == NULL )
  179. {
  180. hr = HRESULT_FROM_WIN32( TW32( GetLastError() ) );
  181. goto Cleanup;
  182. } // if:
  183. idx = ImageList_AddIcon( m_hImgList, hIcon );
  184. Assert( idx == tsPENDING );
  185. //
  186. // Checkmark Icon - Task Done.
  187. //
  188. hIcon = (HICON) LoadImage( g_hInstance,
  189. MAKEINTRESOURCE( IDI_CHECK ),
  190. IMAGE_ICON,
  191. 16,
  192. 16,
  193. LR_SHARED
  194. );
  195. if ( hIcon == NULL )
  196. {
  197. hr = HRESULT_FROM_WIN32( TW32( GetLastError() ) );
  198. goto Cleanup;
  199. } // if:
  200. idx = ImageList_AddIcon( m_hImgList, hIcon );
  201. Assert( idx == tsDONE );
  202. //
  203. // Warning Icon - Task Warning.
  204. //
  205. hIcon = (HICON) LoadImage( g_hInstance,
  206. MAKEINTRESOURCE( IDI_WARN ),
  207. IMAGE_ICON,
  208. 16,
  209. 16,
  210. LR_SHARED
  211. );
  212. if ( hIcon == NULL )
  213. {
  214. hr = HRESULT_FROM_WIN32( TW32( GetLastError() ) );
  215. goto Cleanup;
  216. } // if:
  217. idx = ImageList_AddIcon( m_hImgList, hIcon );
  218. Assert( idx == tsWARNING );
  219. //
  220. // Fail Icon - Task Failed.
  221. //
  222. hIcon = (HICON) LoadImage( g_hInstance,
  223. MAKEINTRESOURCE( IDI_FAIL ),
  224. IMAGE_ICON,
  225. 16,
  226. 16,
  227. LR_SHARED
  228. );
  229. if ( hIcon == NULL )
  230. {
  231. hr = HRESULT_FROM_WIN32( TW32( GetLastError() ) );
  232. goto Cleanup;
  233. } // if:
  234. idx = ImageList_AddIcon( m_hImgList, hIcon );
  235. Assert( idx == tsFAILED );
  236. Assert( ImageList_GetImageCount( m_hImgList ) == tsMAX );
  237. //
  238. // Set the image list and background color.
  239. //
  240. TreeView_SetImageList( m_hwndTV, m_hImgList, TVSIL_NORMAL );
  241. TreeView_SetBkColor( m_hwndTV, GetSysColor( COLOR_3DFACE ) );
  242. Cleanup:
  243. HRETURN( hr );
  244. } //*** CTaskTreeView::HrOnInitDialog
  245. //////////////////////////////////////////////////////////////////////////////
  246. //++
  247. //
  248. // CTaskTreeView::HrAddTreeViewItem
  249. //
  250. // Description:
  251. // Add a tree view item. This method will return the item handle and
  252. // allows the caller to specify the parent item.
  253. //
  254. // Arguments:
  255. // phtiOut
  256. // Handle to the item being added (optional).
  257. //
  258. // idsIn
  259. // String resource ID for description of the new item.
  260. //
  261. // rclsidMinorTaskIDIn
  262. // Minor task ID for the item.
  263. //
  264. // rclsidMajorTaskIDIn
  265. // Major task ID for the item. Defaults to IID_NULL.
  266. //
  267. // htiParentIn
  268. // Parent item. Defaults to the root.
  269. //
  270. // fParentToAllNodeTasksIn
  271. // TRUE = allow item to be parent to tasks from all nodes.
  272. // FALSE = only allow item to be parent to tasks from the local node.
  273. // Defaults to FALSE.
  274. //
  275. // Return Values:
  276. // S_OK - Success.
  277. // Other HRESULTs.
  278. //
  279. //--
  280. //////////////////////////////////////////////////////////////////////////////
  281. HRESULT
  282. CTaskTreeView::HrAddTreeViewItem(
  283. HTREEITEM * phtiOut
  284. , UINT idsIn
  285. , REFCLSID rclsidMinorTaskIDIn
  286. , REFCLSID rclsidMajorTaskIDIn // = IID_NULL
  287. , HTREEITEM htiParentIn // = TVI_ROOT
  288. , BOOL fParentToAllNodeTasksIn // = FALSE
  289. )
  290. {
  291. TraceFunc( "" );
  292. HRESULT hr = S_OK;
  293. STreeItemLParamData * ptipd;
  294. SYSTEMTIME systemtime;
  295. TVINSERTSTRUCT tvis;
  296. HTREEITEM hti = NULL;
  297. //
  298. // Allocate an item data structure.
  299. //
  300. ptipd = new STreeItemLParamData;
  301. if ( ptipd == NULL )
  302. {
  303. hr = THR( E_OUTOFMEMORY );
  304. goto Cleanup;
  305. } // if:
  306. //
  307. // Set the node name to the local computer name.
  308. //
  309. hr = THR( HrGetComputerName(
  310. ComputerNamePhysicalDnsFullyQualified
  311. , &ptipd->bstrNodeName
  312. , TRUE // fBestFitIn
  313. ) );
  314. if ( FAILED( hr ) )
  315. {
  316. goto Cleanup;
  317. } // if:
  318. hr = THR( HrGetFQNDisplayName( ptipd->bstrNodeName, &ptipd->bstrNodeNameWithoutDomain ) );
  319. if ( FAILED( hr ) )
  320. {
  321. goto Cleanup;
  322. } // if:
  323. //
  324. // Set the desription from the string resource ID.
  325. //
  326. hr = THR( HrLoadStringIntoBSTR( g_hInstance, idsIn, &ptipd->bstrDescription ) );
  327. if ( FAILED( hr ) )
  328. {
  329. goto Cleanup;
  330. } // if:
  331. //
  332. // Set the date/time to the current date/time.
  333. //
  334. GetSystemTime( &systemtime );
  335. if ( ! SystemTimeToFileTime( &systemtime, &ptipd->ftTime ) )
  336. {
  337. DWORD sc = TW32( GetLastError() );
  338. hr = HRESULT_FROM_WIN32( sc );
  339. goto Cleanup;
  340. } // if:
  341. //
  342. // Set the task IDs.
  343. //
  344. CopyMemory( &ptipd->clsidMajorTaskId, &rclsidMajorTaskIDIn, sizeof( ptipd->clsidMajorTaskId ) );
  345. CopyMemory( &ptipd->clsidMinorTaskId, &rclsidMinorTaskIDIn, sizeof( ptipd->clsidMinorTaskId ) );
  346. //
  347. // Set the flag describing which items this item can be a parent to.
  348. //
  349. ptipd->fParentToAllNodeTasks = fParentToAllNodeTasksIn;
  350. //
  351. // Initialize the insert structure and insert the item into the tree.
  352. //
  353. tvis.hParent = htiParentIn;
  354. tvis.hInsertAfter = TVI_LAST;
  355. tvis.itemex.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM;
  356. tvis.itemex.cchTextMax = SysStringLen( ptipd->bstrDescription );
  357. tvis.itemex.pszText = ptipd->bstrDescription;
  358. tvis.itemex.iImage = tsUNKNOWN;
  359. tvis.itemex.iSelectedImage = tsUNKNOWN;
  360. tvis.itemex.lParam = reinterpret_cast< LPARAM >( ptipd );
  361. hti = TreeView_InsertItem( m_hwndTV, &tvis );
  362. Assert( hti != NULL );
  363. ptipd = NULL;
  364. if ( phtiOut != NULL )
  365. {
  366. *phtiOut = hti;
  367. } // if:
  368. goto Cleanup;
  369. Cleanup:
  370. if ( ptipd != NULL )
  371. {
  372. TraceSysFreeString( ptipd->bstrNodeName );
  373. TraceSysFreeString( ptipd->bstrNodeNameWithoutDomain );
  374. TraceSysFreeString( ptipd->bstrDescription );
  375. delete ptipd;
  376. } // if: ptipd != NULL
  377. HRETURN( hr );
  378. } //*** CTaskTreeView::HrAddTreeViewItem
  379. //////////////////////////////////////////////////////////////////////////////
  380. //++
  381. //
  382. // CTaskTreeView::OnNotify
  383. //
  384. // Description:
  385. // Handler for the WM_NOTIFY message.
  386. //
  387. // Arguments:
  388. // pnmhdrIn - Notification structure.
  389. //
  390. // Return Values:
  391. // Notification-specific return code.
  392. //
  393. //--
  394. //////////////////////////////////////////////////////////////////////////////
  395. LRESULT
  396. CTaskTreeView::OnNotify(
  397. LPNMHDR pnmhdrIn
  398. )
  399. {
  400. TraceFunc( "" );
  401. LRESULT lr = TRUE;
  402. switch( pnmhdrIn->code )
  403. {
  404. case TVN_DELETEITEM:
  405. OnNotifyDeleteItem( pnmhdrIn );
  406. break;
  407. case TVN_SELCHANGED:
  408. OnNotifySelChanged( pnmhdrIn );
  409. break;
  410. } // switch: notify code
  411. RETURN( lr );
  412. } //*** CTaskTreeView::OnNotify
  413. //////////////////////////////////////////////////////////////////////////////
  414. //++
  415. //
  416. // CTaskTreeView::OnNotifyDeleteItem
  417. //
  418. // Description:
  419. // Handler for the TVN_DELETEITEM notification message.
  420. //
  421. // Arguments:
  422. // pnmhdrIn - Notification structure for the item being deleted.
  423. //
  424. // Return Values:
  425. // None.
  426. //
  427. //--
  428. //////////////////////////////////////////////////////////////////////////////
  429. void
  430. CTaskTreeView::OnNotifyDeleteItem(
  431. LPNMHDR pnmhdrIn
  432. )
  433. {
  434. TraceFunc( "" );
  435. LPNMTREEVIEW pnmtv = reinterpret_cast< LPNMTREEVIEW >( pnmhdrIn );
  436. if ( pnmtv->itemOld.lParam != NULL )
  437. {
  438. STreeItemLParamData * ptipd = reinterpret_cast< STreeItemLParamData * >( pnmtv->itemOld.lParam );
  439. TraceSysFreeString( ptipd->bstrNodeName );
  440. TraceSysFreeString( ptipd->bstrNodeNameWithoutDomain );
  441. TraceSysFreeString( ptipd->bstrDescription );
  442. TraceSysFreeString( ptipd->bstrReference );
  443. delete ptipd;
  444. } // if: lParam != NULL
  445. TraceFuncExit();
  446. } //*** CTaskTreeView::OnNotifyDeleteItem
  447. //////////////////////////////////////////////////////////////////////////////
  448. //++
  449. //
  450. // CTaskTreeView::OnNotifySelChanged
  451. //
  452. // Description:
  453. // Handler for the TVN_SELCHANGED notification message.
  454. //
  455. // Arguments:
  456. // pnmhdrIn - Notification structure for the item being deleted.
  457. //
  458. // Return Values:
  459. // None.
  460. //
  461. //--
  462. //////////////////////////////////////////////////////////////////////////////
  463. void
  464. CTaskTreeView::OnNotifySelChanged(
  465. LPNMHDR pnmhdrIn
  466. )
  467. {
  468. TraceFunc( "" );
  469. LPNMTREEVIEW pnmtv = reinterpret_cast< LPNMTREEVIEW >( pnmhdrIn );
  470. Assert( pnmtv->itemNew.mask & TVIF_HANDLE );
  471. m_htiSelected = pnmtv->itemNew.hItem;
  472. TraceFuncExit();
  473. } //*** CTaskTreeView::OnNotifySelChanged
  474. //////////////////////////////////////////////////////////////////////////////
  475. //++
  476. //
  477. // HRESULT
  478. // CTaskTreeView::HrShowStatusAsDone( void )
  479. //
  480. //--
  481. //////////////////////////////////////////////////////////////////////////////
  482. HRESULT
  483. CTaskTreeView::HrShowStatusAsDone( void )
  484. {
  485. TraceFunc( "" );
  486. HRESULT hr = S_OK;
  487. BSTR bstrDescription = NULL;
  488. PBRANGE pbrange;
  489. SendMessage( m_hwndProg, PBM_GETRANGE, FALSE, (LPARAM) &pbrange );
  490. SendMessage( m_hwndProg, PBM_SETPOS, pbrange.iHigh, 0 );
  491. hr = THR( HrLoadStringIntoBSTR( g_hInstance, IDS_TASKS_COMPLETED, &bstrDescription ) );
  492. if ( FAILED( hr ) )
  493. {
  494. SetWindowText( m_hwndStatus, L"" );
  495. goto Cleanup;
  496. } // if:
  497. SetWindowText( m_hwndStatus, bstrDescription );
  498. Cleanup:
  499. TraceSysFreeString( bstrDescription );
  500. HRETURN( hr );
  501. } //*** CTaskTreeView::HrShowStatusAsDone
  502. //////////////////////////////////////////////////////////////////////////////
  503. //++
  504. //
  505. // HRESULT
  506. // CTaskTreeView::HrOnNotifySetActive( void )
  507. //
  508. //--
  509. //////////////////////////////////////////////////////////////////////////////
  510. HRESULT
  511. CTaskTreeView::HrOnNotifySetActive( void )
  512. {
  513. TraceFunc( "" );
  514. STreeItemLParamData * ptipdTemp;
  515. HRESULT hr = S_OK;
  516. size_t idx;
  517. TreeView_DeleteAllItems( m_hwndTV );
  518. SetWindowText( m_hwndStatus, L"" );
  519. // Cleanup the progress array and delete any allocated entries.
  520. for ( idx = 0; idx < m_cPASize; idx++ )
  521. {
  522. if ( m_ptipdProgressArray[ idx ] != NULL )
  523. {
  524. ptipdTemp = m_ptipdProgressArray[ idx ];
  525. TraceSysFreeString( ptipdTemp->bstrNodeName );
  526. delete ptipdTemp;
  527. } // if: element != NULL
  528. } // for: each element in the array
  529. m_cPASize = 0;
  530. m_cPACount = 0;
  531. delete [] m_ptipdProgressArray;
  532. m_ptipdProgressArray = NULL;
  533. m_nRangeHigh = 1; // We don't have any reported tasks yet. Choose 1 to avoid any div/0 errors.
  534. m_nCurrentPos = PROGRESSBAR_INITIAL_POSITION;
  535. m_nRealPos = PROGRESSBAR_INITIAL_POSITION;
  536. m_fThresholdBroken = FALSE;
  537. SendMessage( m_hwndProg, PBM_SETRANGE, 0, MAKELPARAM( 0, PROGRESSBAR_CONTROL_TICK_COUNT ) );
  538. SendMessage( m_hwndProg, PBM_SETPOS, m_nCurrentPos, 0 );
  539. HRETURN( hr );
  540. } //*** CTaskTreeView::HrOnNotifySetActive
  541. //////////////////////////////////////////////////////////////////////////////
  542. //++
  543. //
  544. // CTaskTreeView::HrOnSendStatusReport
  545. //
  546. // Description:
  547. // Handle a status report call.
  548. //
  549. // Arguments:
  550. // pcszNodeNameIn -
  551. // clsidTaskMajorIn -
  552. // clsidTaskMinorIn -
  553. // nMinIn -
  554. // nMaxIn -
  555. // nCurrentIn -
  556. // hrStatusIn -
  557. // pcszDescriptionIn -
  558. // pftTimeIn -
  559. // pcszReferenceIn -
  560. //
  561. // Return Values:
  562. // S_OK - Operation completed successfully.
  563. //
  564. //--
  565. //////////////////////////////////////////////////////////////////////////////
  566. HRESULT
  567. CTaskTreeView::HrOnSendStatusReport(
  568. LPCWSTR pcszNodeNameIn
  569. , CLSID clsidTaskMajorIn
  570. , CLSID clsidTaskMinorIn
  571. , ULONG nMinIn
  572. , ULONG nMaxIn
  573. , ULONG nCurrentIn
  574. , HRESULT hrStatusIn
  575. , LPCWSTR pcszDescriptionIn
  576. , FILETIME * pftTimeIn
  577. , LPCWSTR pcszReferenceIn
  578. )
  579. {
  580. TraceFunc( "" );
  581. Assert( pcszNodeNameIn != NULL );
  582. HRESULT hr = S_OK;
  583. int nImageChild;
  584. STreeItemLParamData tipd;
  585. HTREEITEM htiRoot;
  586. BSTR bstrStatus = NULL;
  587. BSTR bstrDisplayName = NULL;
  588. LPCWSTR pcszNameToUse = pcszNodeNameIn;
  589. ZeroMemory( &tipd, sizeof( tipd ) );
  590. //
  591. // If no node name was supplied then provide this machine's name so
  592. // we have something to use as the node name key part when placing
  593. // this tree item in the tree.
  594. //
  595. if ( pcszNodeNameIn == NULL )
  596. {
  597. pcszNodeNameIn = m_bstrClientMachineName;
  598. } // if:
  599. //
  600. // If the node name is fully-qualified, use just the prefix.
  601. //
  602. hr = STHR( HrGetFQNDisplayName( pcszNodeNameIn, &bstrDisplayName ) );
  603. if ( SUCCEEDED( hr ) )
  604. {
  605. pcszNameToUse = bstrDisplayName;
  606. } // if:
  607. //////////////////////////////////////////////////////////////////////////
  608. //
  609. // Update status text.
  610. // Don't do this if it is a log-only message.
  611. //
  612. //////////////////////////////////////////////////////////////////////////
  613. if ( ( pcszDescriptionIn != NULL )
  614. && ! IsEqualIID( clsidTaskMajorIn, TASKID_Major_Client_Log )
  615. && ! IsEqualIID( clsidTaskMajorIn, TASKID_Major_Server_Log )
  616. && ! IsEqualIID( clsidTaskMajorIn, TASKID_Major_Client_And_Server_Log )
  617. )
  618. {
  619. BOOL fReturn;
  620. if ( pcszNodeNameIn != NULL )
  621. {
  622. hr = THR( HrFormatMessageIntoBSTR(
  623. g_hInstance
  624. , IDS_FORMAT_STATUS
  625. , &bstrStatus
  626. , pcszNameToUse
  627. , pcszDescriptionIn
  628. ) );
  629. //
  630. // Handle the formatting error if there was one.
  631. //
  632. if ( FAILED( hr ) )
  633. {
  634. // TODO: Display default description instead of exiting this function
  635. goto Error;
  636. } // if:
  637. } // if: node name was specified
  638. else
  639. {
  640. bstrStatus = TraceSysAllocString( pcszDescriptionIn );
  641. if ( bstrStatus == NULL )
  642. {
  643. hr = THR( E_OUTOFMEMORY );
  644. goto Error;
  645. } // if:
  646. } // else: node name wasn't specified
  647. Assert( bstrStatus!= NULL );
  648. Assert( *bstrStatus!= L'\0' );
  649. fReturn = SetWindowText( m_hwndStatus, bstrStatus );
  650. Assert( fReturn );
  651. } // if: description specified, not log-only
  652. //////////////////////////////////////////////////////////////////////////
  653. //
  654. // Select the right icon.
  655. //
  656. //////////////////////////////////////////////////////////////////////////
  657. switch ( hrStatusIn )
  658. {
  659. case S_OK:
  660. if ( nCurrentIn == nMaxIn )
  661. {
  662. nImageChild = tsDONE;
  663. } // if:
  664. else
  665. {
  666. nImageChild = tsPENDING;
  667. } // else:
  668. break;
  669. case S_FALSE:
  670. nImageChild = tsWARNING;
  671. break;
  672. case E_PENDING:
  673. nImageChild = tsPENDING;
  674. break;
  675. default:
  676. if ( FAILED( hrStatusIn ) && ( m_fDisplayErrorsAsWarnings == FALSE ) )
  677. {
  678. nImageChild = tsFAILED;
  679. } // if:
  680. else
  681. {
  682. nImageChild = tsWARNING;
  683. } // else:
  684. break;
  685. } // switch: hrStatusIn
  686. //////////////////////////////////////////////////////////////////////////
  687. //
  688. // Loop through each item at the top of the tree looking for an item
  689. // whose minor ID matches this report's major ID.
  690. //
  691. //////////////////////////////////////////////////////////////////////////
  692. //
  693. // Fill in the param data structure.
  694. //
  695. tipd.hr = hrStatusIn;
  696. tipd.nMin = nMinIn;
  697. tipd.nMax = nMaxIn;
  698. tipd.nCurrent = nCurrentIn;
  699. CopyMemory( &tipd.clsidMajorTaskId, &clsidTaskMajorIn, sizeof( tipd.clsidMajorTaskId ) );
  700. CopyMemory( &tipd.clsidMinorTaskId, &clsidTaskMinorIn, sizeof( tipd.clsidMinorTaskId ) );
  701. CopyMemory( &tipd.ftTime, pftTimeIn, sizeof( tipd.ftTime ) );
  702. // tipd.bstrDescription is set above.
  703. tipd.bstrNodeName = TraceSysAllocString( pcszNodeNameIn );
  704. if ( tipd.bstrNodeName == NULL )
  705. {
  706. hr = THR( E_OUTOFMEMORY );
  707. goto Error;
  708. } // if:
  709. tipd.bstrNodeNameWithoutDomain = bstrDisplayName;
  710. bstrDisplayName = NULL; // tipd now owns this string.
  711. if ( pcszDescriptionIn == NULL )
  712. {
  713. tipd.bstrDescription = NULL;
  714. } // if:
  715. else
  716. {
  717. tipd.bstrDescription = TraceSysAllocString( pcszDescriptionIn );
  718. if ( tipd.bstrDescription == NULL )
  719. {
  720. hr = THR( E_OUTOFMEMORY );
  721. goto Error;
  722. } // if:
  723. } // else: pcszDescritionIn != NULL
  724. if ( pcszReferenceIn == NULL )
  725. {
  726. tipd.bstrReference = NULL;
  727. } // if:
  728. else
  729. {
  730. tipd.bstrReference = TraceSysAllocString( pcszReferenceIn );
  731. if ( tipd.bstrReference == NULL )
  732. {
  733. hr = THR( E_OUTOFMEMORY );
  734. goto Error;
  735. } // if:
  736. } // else: pcszReferenceIn != NULL
  737. if ( IsEqualIID( tipd.clsidMajorTaskId, TASKID_Major_Update_Progress ) )
  738. {
  739. // It's an update_progress task so just call HrProcessUpdateProgressTask.
  740. hr = STHR( HrProcessUpdateProgressTask( &tipd ) );
  741. if ( FAILED( hr ) )
  742. {
  743. goto Error;
  744. } // if:
  745. } // if: major == update_progress
  746. else
  747. {
  748. // Start with the first item in the tree view.
  749. htiRoot = TreeView_GetRoot( m_hwndTV );
  750. if ( htiRoot == NULL )
  751. {
  752. TW32( ERROR_NOT_FOUND );
  753. // Don't return an error result since doing so will prevent the report
  754. // from being propagated to other subscribers.
  755. hr = S_OK;
  756. goto Cleanup;
  757. } // if: htiRoot is NULL
  758. // Insert the status report into the tree view.
  759. hr = STHR( HrInsertTaskIntoTree( htiRoot, &tipd, nImageChild, bstrStatus ) );
  760. if ( FAILED( hr ) )
  761. {
  762. LogMsg( "[WIZ] Error inserting status report into the tree control. hr=%.08x, %ws", tipd.hr, pcszDescriptionIn );
  763. goto Error;
  764. } // if:
  765. } // else: not an update_progress task
  766. if ( hr == S_FALSE )
  767. {
  768. // Don't return S_FALSE to the caller since it won't mean anything there.
  769. hr = S_OK;
  770. // TODO: Should this be written to the log?
  771. #if defined( DEBUG )
  772. //
  773. // Check to make sure that if the major task ID wasn't recognized
  774. // that it is one of the known exceptions.
  775. //
  776. if ( ! IsEqualIID( clsidTaskMajorIn, TASKID_Major_Client_Log )
  777. && ! IsEqualIID( clsidTaskMajorIn, TASKID_Major_Server_Log )
  778. && ! IsEqualIID( clsidTaskMajorIn, TASKID_Major_Client_And_Server_Log ) )
  779. {
  780. BSTR bstrMsg = NULL;
  781. THR( HrFormatStringIntoBSTR(
  782. g_hInstance
  783. , IDS_UNKNOWN_TASK
  784. , &bstrMsg
  785. , clsidTaskMajorIn.Data1 // 1
  786. , clsidTaskMajorIn.Data2 // 2
  787. , clsidTaskMajorIn.Data3 // 3
  788. , clsidTaskMajorIn.Data4[ 0 ] // 4
  789. , clsidTaskMajorIn.Data4[ 1 ] // 5
  790. , clsidTaskMajorIn.Data4[ 2 ] // 6
  791. , clsidTaskMajorIn.Data4[ 3 ] // 7
  792. , clsidTaskMajorIn.Data4[ 4 ] // 8
  793. , clsidTaskMajorIn.Data4[ 5 ] // 9
  794. , clsidTaskMajorIn.Data4[ 6 ] // 10
  795. , clsidTaskMajorIn.Data4[ 7 ] // 11
  796. ) );
  797. AssertString( 0, bstrMsg );
  798. TraceSysFreeString( bstrMsg );
  799. } // if: log only
  800. #endif // DEBUG
  801. } // if: S_FALSE returned from HrInsertTaskIntoTree
  802. goto Cleanup;
  803. Error:
  804. // Don't return an error result since doing so will prevent the report
  805. // from being propagated to other subscribers.
  806. hr = S_OK;
  807. goto Cleanup;
  808. Cleanup:
  809. TraceSysFreeString( bstrDisplayName );
  810. TraceSysFreeString( bstrStatus );
  811. TraceSysFreeString( tipd.bstrNodeName );
  812. TraceSysFreeString( tipd.bstrNodeNameWithoutDomain );
  813. TraceSysFreeString( tipd.bstrDescription );
  814. TraceSysFreeString( tipd.bstrReference );
  815. HRETURN( hr );
  816. } //*** CTaskTreeView::HrOnSendStatusReport
  817. //////////////////////////////////////////////////////////////////////////////
  818. //++
  819. //
  820. // CTaskTreeView::HrInsertTaskIntoTree
  821. //
  822. // Description:
  823. // Insert the specified task into the tree based on the node, major
  824. // task, and minor task.
  825. //
  826. // Arguments:
  827. // htiFirstIn - First tree item to examine.
  828. // ptipdIn - Tree item parameter data for the task to be inserted.
  829. // nImageIn - Image identifier for the child item.
  830. // bstrDescriptionIn - Description string to display.
  831. //
  832. // Return Values:
  833. // S_OK - Task inserted successfully.
  834. // S_FALSE - Task not inserted.
  835. // hr - The operation failed.
  836. //
  837. //--
  838. //////////////////////////////////////////////////////////////////////////////
  839. HRESULT
  840. CTaskTreeView::HrInsertTaskIntoTree(
  841. HTREEITEM htiFirstIn
  842. , STreeItemLParamData * ptipdIn
  843. , int nImageIn
  844. , BSTR bstrDescriptionIn
  845. )
  846. {
  847. TraceFunc( "" );
  848. Assert( htiFirstIn != NULL );
  849. Assert( ptipdIn != NULL );
  850. //
  851. // LOCAL VARIABLES
  852. //
  853. HRESULT hr;
  854. HTREEITEM htiParent;
  855. HTREEITEM htiChild = NULL;
  856. TVITEMEX tviParent;
  857. TVITEMEX tviChild;
  858. BOOL fReturn;
  859. BOOL fSameNode;
  860. STreeItemLParamData * ptipdParent = NULL;
  861. STreeItemLParamData * ptipdChild = NULL;
  862. //
  863. // Loop through each item to determine if the task should be added below
  864. // that item. If not, attempt to traverse its children.
  865. //
  866. for ( htiParent = htiFirstIn, hr = S_FALSE
  867. ; ( htiParent != NULL ) && ( hr == S_FALSE )
  868. ; )
  869. {
  870. //
  871. // Get the information about this item in the tree.
  872. //
  873. tviParent.mask = TVIF_PARAM | TVIF_IMAGE;
  874. tviParent.hItem = htiParent;
  875. fReturn = TreeView_GetItem( m_hwndTV, &tviParent );
  876. if ( fReturn == FALSE )
  877. {
  878. hr = HRESULT_FROM_WIN32( TW32( ERROR_NOT_FOUND ) );
  879. goto Cleanup;
  880. } // if:
  881. ptipdParent = reinterpret_cast< STreeItemLParamData * >( tviParent.lParam );
  882. Assert( ptipdParent != NULL );
  883. //
  884. // Determine if either the parent can be a parent to tasks from any
  885. // node or, if not, the parent and input tasks are from the same node.
  886. //
  887. if ( ptipdParent->fParentToAllNodeTasks == TRUE )
  888. {
  889. fSameNode = TRUE;
  890. } // if: parent task can host tasks from any node
  891. else
  892. {
  893. fSameNode = ( NBSTRCompareNoCase( ptipdIn->bstrNodeNameWithoutDomain, ptipdParent->bstrNodeNameWithoutDomain ) == 0 );
  894. } // else: parent task's node must match input task's node
  895. //
  896. // Reset hr to S_FALSE because it is the return value when a tree item is
  897. // to be added to the tree because it was not found.
  898. //
  899. hr = S_FALSE;
  900. //
  901. // See if this item could be the parent.
  902. // If not, recurse through child items.
  903. //
  904. if ( IsEqualIID( ptipdIn->clsidMajorTaskId, ptipdParent->clsidMinorTaskId )
  905. && ( fSameNode == TRUE )
  906. )
  907. {
  908. //
  909. // FOUND THE PARENT ITEM
  910. //
  911. BOOL fMinorTaskIdMatches;
  912. BOOL fBothNodeNamesPresent;
  913. BOOL fBothNodeNamesEmpty;
  914. BOOL fNodeNamesEqual;
  915. //////////////////////////////////////////////////////////////
  916. //
  917. // Loop through the child items looking for an item with
  918. // the same minor ID.
  919. //
  920. //////////////////////////////////////////////////////////////
  921. htiChild = TreeView_GetChild( m_hwndTV, htiParent );
  922. while ( htiChild != NULL )
  923. {
  924. //
  925. // Get the child item details.
  926. //
  927. tviChild.mask = TVIF_PARAM | TVIF_IMAGE;
  928. tviChild.hItem = htiChild;
  929. fReturn = TreeView_GetItem( m_hwndTV, &tviChild );
  930. if ( fReturn == FALSE )
  931. {
  932. hr = HRESULT_FROM_WIN32( TW32( ERROR_NOT_FOUND ) );
  933. goto Cleanup;
  934. } // if:
  935. ptipdChild = reinterpret_cast< STreeItemLParamData * >( tviChild.lParam );
  936. Assert( ptipdChild != NULL );
  937. //
  938. // Does this child item match the minor ID and node name?
  939. //
  940. fMinorTaskIdMatches = IsEqualIID( ptipdIn->clsidMinorTaskId, ptipdChild->clsidMinorTaskId );
  941. fBothNodeNamesPresent = ( ptipdIn->bstrNodeNameWithoutDomain != NULL ) && ( ptipdChild->bstrNodeNameWithoutDomain != NULL );
  942. fBothNodeNamesEmpty = ( ptipdIn->bstrNodeNameWithoutDomain == NULL ) && ( ptipdChild->bstrNodeNameWithoutDomain == NULL );
  943. if ( fBothNodeNamesPresent == TRUE )
  944. {
  945. fNodeNamesEqual = ( NBSTRCompareNoCase( ptipdIn->bstrNodeNameWithoutDomain, ptipdChild->bstrNodeNameWithoutDomain ) == 0 );
  946. } // if:
  947. else if ( fBothNodeNamesEmpty == TRUE )
  948. {
  949. fNodeNamesEqual = TRUE;
  950. } // else if:
  951. else
  952. {
  953. fNodeNamesEqual = FALSE;
  954. } // else:
  955. if ( ( fMinorTaskIdMatches == TRUE ) && ( fNodeNamesEqual == TRUE ) )
  956. {
  957. //
  958. // CHILD ITEM MATCHES.
  959. // Update the child item.
  960. //
  961. //
  962. // Update the progress bar.
  963. //
  964. STHR( HrUpdateProgressBar( ptipdIn, ptipdChild ) );
  965. // ignore failure.
  966. //
  967. // Copy data from the report.
  968. // This must be done after the call to
  969. // HrUpdateProgressBar so that the previous values
  970. // can be compared to the new values.
  971. //
  972. ptipdChild->nMin = ptipdIn->nMin;
  973. ptipdChild->nMax = ptipdIn->nMax;
  974. ptipdChild->nCurrent = ptipdIn->nCurrent;
  975. CopyMemory( &ptipdChild->ftTime, &ptipdIn->ftTime, sizeof( ptipdChild->ftTime ) );
  976. // Update the error code if needed.
  977. if ( ptipdChild->hr == S_OK )
  978. {
  979. ptipdChild->hr = ptipdIn->hr;
  980. } // if:
  981. //
  982. // If the new state is worse than the last state,
  983. // update the state of the item.
  984. //
  985. if ( tviChild.iImage < nImageIn )
  986. {
  987. tviChild.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE;
  988. tviChild.iImage = nImageIn;
  989. tviChild.iSelectedImage = nImageIn;
  990. TreeView_SetItem( m_hwndTV, &tviChild );
  991. } // if: new state is worse than the last state
  992. //
  993. // Update the text of the child item if needed.
  994. //
  995. if ( ( ptipdIn->bstrDescription != NULL )
  996. && ( ( ptipdChild->bstrDescription == NULL )
  997. || ( NBSTRCompareCase( ptipdIn->bstrDescription, ptipdChild->bstrDescription ) != 0 )
  998. )
  999. )
  1000. {
  1001. fReturn = TraceSysReAllocString( &ptipdChild->bstrDescription, ptipdIn->bstrDescription );
  1002. if ( fReturn == FALSE )
  1003. {
  1004. hr = THR( E_OUTOFMEMORY );
  1005. goto Cleanup;
  1006. } // if:
  1007. tviChild.mask = TVIF_TEXT;
  1008. tviChild.pszText = bstrDescriptionIn;
  1009. tviChild.cchTextMax = (int) wcslen( tviChild.pszText );
  1010. TreeView_SetItem( m_hwndTV, &tviChild );
  1011. } // if: description was specified and is different
  1012. //
  1013. // Copy the reference if it is different.
  1014. //
  1015. if ( ( ptipdIn->bstrReference != NULL )
  1016. && ( ( ptipdChild->bstrReference == NULL )
  1017. || ( NBSTRCompareCase( ptipdChild->bstrReference, ptipdIn->bstrReference ) != 0 )
  1018. )
  1019. )
  1020. {
  1021. fReturn = TraceSysReAllocString( &ptipdChild->bstrReference, ptipdIn->bstrReference );
  1022. if ( fReturn == FALSE )
  1023. {
  1024. hr = THR( E_OUTOFMEMORY );
  1025. goto Cleanup;
  1026. } // if:
  1027. } // if: reference is different
  1028. break; // exit loop
  1029. } // if: found a matching child item
  1030. //
  1031. // Get the next item.
  1032. //
  1033. htiChild = TreeView_GetNextSibling( m_hwndTV, htiChild );
  1034. } // while: more child items
  1035. //////////////////////////////////////////////////////////////
  1036. //
  1037. // If the tree item was not found and the description was
  1038. // specified, then we need to create the child item.
  1039. //
  1040. //////////////////////////////////////////////////////////////
  1041. if ( ( htiChild == NULL )
  1042. && ( ptipdIn->bstrDescription != NULL )
  1043. )
  1044. {
  1045. //
  1046. // ITEM NOT FOUND AND DESCRIPTION WAS SPECIFIED
  1047. //
  1048. // Insert a new item in the tree under the major's task.
  1049. //
  1050. TVINSERTSTRUCT tvis;
  1051. // Create the item.
  1052. hr = THR( HrCreateTreeItem(
  1053. &tvis
  1054. , ptipdIn
  1055. , htiParent
  1056. , nImageIn
  1057. , bstrDescriptionIn
  1058. ) );
  1059. if ( FAILED( hr ) )
  1060. {
  1061. goto Cleanup;
  1062. } // if:
  1063. // Insert the item in the tree.
  1064. htiChild = TreeView_InsertItem( m_hwndTV, &tvis );
  1065. Assert( htiChild != NULL );
  1066. //
  1067. // Update the progress bar.
  1068. //
  1069. ptipdChild = reinterpret_cast< STreeItemLParamData * >( tvis.itemex.lParam );
  1070. Assert( ptipdChild != NULL );
  1071. STHR( HrUpdateProgressBar( ptipdIn, ptipdChild ) );
  1072. // ignore failure.
  1073. } // if: need to add new child
  1074. //////////////////////////////////////////////////////////////
  1075. //
  1076. // If the child item was created and the child has an error
  1077. // condition, then create a child of the child item
  1078. // indicating the error code and system string.
  1079. //
  1080. //////////////////////////////////////////////////////////////
  1081. if ( ( ptipdChild != NULL )
  1082. && ( FAILED( ptipdIn->hr )
  1083. || ( ( ptipdIn->hr != S_OK )
  1084. && ( ptipdIn->hr != S_FALSE )
  1085. )
  1086. )
  1087. )
  1088. {
  1089. //
  1090. // CHILD ITEM FOUND OR CREATED FOR ERROR REPORT
  1091. // CREATE ERROR ITEM IN THE TREE
  1092. //
  1093. BSTR bstrError = NULL;
  1094. BSTR bstrErrorDescription = NULL;
  1095. HRESULT hrFormat;
  1096. TVINSERTSTRUCT tvis;
  1097. HTREEITEM htiChildStatus;
  1098. DWORD dwSeverity;
  1099. HRESULT hrNewStatus = S_OK;
  1100. dwSeverity = SCODE_SEVERITY( ptipdIn->hr );
  1101. THR( HrFormatErrorIntoBSTR( ptipdIn->hr, &bstrError, &hrNewStatus ) );
  1102. //
  1103. // If we got an updated status code then we need to choose
  1104. // a new format string that shows both the old and the new
  1105. // status codes.
  1106. //
  1107. if ( hrNewStatus != ptipdIn->hr )
  1108. {
  1109. Assert( bstrError != NULL );
  1110. hrFormat = THR( HrFormatMessageIntoBSTR(
  1111. g_hInstance
  1112. , dwSeverity == 0 ? IDS_TASK_RETURNED_NEW_STATUS : IDS_TASK_RETURNED_NEW_ERROR
  1113. , &bstrErrorDescription
  1114. , ptipdIn->hr
  1115. , hrNewStatus
  1116. , bstrError
  1117. ) );
  1118. } // if:
  1119. else
  1120. {
  1121. hrFormat = THR( HrFormatMessageIntoBSTR(
  1122. g_hInstance
  1123. , dwSeverity == 0 ? IDS_TASK_RETURNED_STATUS : IDS_TASK_RETURNED_ERROR
  1124. , &bstrErrorDescription
  1125. , ptipdIn->hr
  1126. , ( bstrError == NULL ? L"" : bstrError )
  1127. ) );
  1128. } // else:
  1129. if ( SUCCEEDED( hrFormat ) )
  1130. {
  1131. //
  1132. // Insert a new item in the tree under the minor's
  1133. // task explaining the ptipdIn->hr.
  1134. //
  1135. // Create the item.
  1136. hr = THR( HrCreateTreeItem(
  1137. &tvis
  1138. , ptipdIn
  1139. , htiChild
  1140. , nImageIn
  1141. , bstrErrorDescription
  1142. ) );
  1143. if ( SUCCEEDED( hr ) )
  1144. {
  1145. //
  1146. // Failures are handled below to make sure we free
  1147. // all the strings allocated by this section of
  1148. // the code.
  1149. //
  1150. // Insert the item.
  1151. htiChildStatus = TreeView_InsertItem( m_hwndTV, &tvis );
  1152. Assert( htiChildStatus != NULL );
  1153. } // if: tree item created successfully
  1154. TraceSysFreeString( bstrErrorDescription );
  1155. } // if: message formatted successfully
  1156. TraceSysFreeString( bstrError );
  1157. //
  1158. // This error handling is for the return value from
  1159. // HrCreateTreeItem above. It is here so that all the strings
  1160. // can be cleaned up without having to resort to hokey
  1161. // boolean variables or move the bstrs to a more global scope.
  1162. //
  1163. if ( FAILED( hr ) )
  1164. {
  1165. goto Cleanup;
  1166. } // if:
  1167. } // if: child and error
  1168. //////////////////////////////////////////////////////////////
  1169. //
  1170. // If a child was found or created, propagate its state to
  1171. // the parent items.
  1172. //
  1173. //////////////////////////////////////////////////////////////
  1174. if ( htiChild != NULL )
  1175. {
  1176. hr = STHR( HrPropagateChildStateToParents(
  1177. htiChild
  1178. , nImageIn
  1179. , FALSE // fOnlyUpdateProgressIn
  1180. ) );
  1181. if ( FAILED( hr ) )
  1182. {
  1183. goto Cleanup;
  1184. } // if:
  1185. } // if: found or created a child
  1186. //
  1187. // Return success since we found the parent for this report.
  1188. //
  1189. hr = S_OK;
  1190. break;
  1191. } // if: found an item to be the parent
  1192. else
  1193. {
  1194. //
  1195. // PARENT ITEM NOT FOUND
  1196. //
  1197. // Recurse through all the child items.
  1198. //
  1199. htiChild = TreeView_GetChild( m_hwndTV, htiParent );
  1200. while ( htiChild != NULL )
  1201. {
  1202. hr = STHR( HrInsertTaskIntoTree( htiChild, ptipdIn, nImageIn, bstrDescriptionIn ) );
  1203. if ( hr == S_OK )
  1204. {
  1205. // Found a match, so exit the loop.
  1206. break;
  1207. } // if:
  1208. htiChild = TreeView_GetNextSibling( m_hwndTV, htiChild );
  1209. } // while: more child items
  1210. } // else: item not the parent
  1211. //
  1212. // Get the next sibling of the parent.
  1213. //
  1214. htiParent = TreeView_GetNextSibling( m_hwndTV, htiParent );
  1215. } // for: each item at this level in the tree
  1216. Cleanup:
  1217. RETURN( hr );
  1218. } //*** CTaskTreeView::HrInsertTaskIntoTree
  1219. //////////////////////////////////////////////////////////////////////////////
  1220. //++
  1221. //
  1222. // CTaskTreeView::HrProcessUpdateProgressTask
  1223. //
  1224. // Description:
  1225. // Update the progress bar based on new tree item data.
  1226. //
  1227. // Arguments:
  1228. // ptipdNewIn - New values of the tree item data.
  1229. //
  1230. // Return Values:
  1231. // S_OK - Operation completed successfully.
  1232. // E_OUTOFMEMORY - Failure allocating memory
  1233. // Other HRESULTs
  1234. //
  1235. //--
  1236. //////////////////////////////////////////////////////////////////////////////
  1237. HRESULT
  1238. CTaskTreeView::HrProcessUpdateProgressTask(
  1239. const STreeItemLParamData * ptipdIn
  1240. )
  1241. {
  1242. TraceFunc( "" );
  1243. HRESULT hr = S_OK;
  1244. STreeItemLParamData * ptipdPrev = NULL;
  1245. size_t idx;
  1246. size_t cPassed;
  1247. size_t idxPrev = 0;
  1248. BOOL fNewTask = FALSE; // Are ptipdPrev && ptipdIn the same task?
  1249. Assert( ptipdIn != NULL );
  1250. Assert( IsEqualIID( ptipdIn->clsidMajorTaskId, TASKID_Major_Update_Progress ) );
  1251. //
  1252. // Is this a one-off event? min == max == current
  1253. //
  1254. if ( ( ptipdIn->nMin == ptipdIn->nMax ) && ( ptipdIn->nMax == ptipdIn->nCurrent ) )
  1255. {
  1256. // Yes - don't bother mucking with the array.
  1257. STHR( HrUpdateProgressBar( ptipdIn, ptipdIn ) );
  1258. hr = S_OK;
  1259. goto Cleanup;
  1260. } // if: one-off event
  1261. //
  1262. // Check to see if this task is in the array.
  1263. //
  1264. for ( idx = 0, cPassed = 0;
  1265. ( idx < m_cPASize ) && ( cPassed < m_cPACount );
  1266. idx++ )
  1267. {
  1268. if ( m_ptipdProgressArray[ idx ] != NULL )
  1269. {
  1270. // Check the minors and make sure this is the same node.
  1271. if ( IsEqualIID( m_ptipdProgressArray[ idx ]->clsidMinorTaskId, ptipdIn->clsidMinorTaskId )
  1272. && ( NBSTRCompareNoCase( m_ptipdProgressArray[ idx ]->bstrNodeName, ptipdIn->bstrNodeName ) == 0 ) )
  1273. {
  1274. ptipdPrev = m_ptipdProgressArray[ idx ];
  1275. idxPrev = idx;
  1276. break;
  1277. } // if:
  1278. // If the array is X elements long and we have Y elements, stop after looking at Y elements.
  1279. cPassed++;
  1280. } // if: current slot is null
  1281. } // for: each item in the array until we find a match
  1282. if ( ptipdPrev == NULL )
  1283. {
  1284. //
  1285. // We didn't find it in the list - we'll have to insert it.
  1286. //
  1287. if ( m_ptipdProgressArray == NULL )
  1288. {
  1289. Assert( m_cPACount == 0 );
  1290. //
  1291. // We have to allocate the array.
  1292. //
  1293. m_cPASize = 10; // Pick a reasonable initial array size.
  1294. m_ptipdProgressArray = new PSTreeItemLParamData[ m_cPASize ];
  1295. if ( m_ptipdProgressArray == NULL )
  1296. {
  1297. hr = THR( E_OUTOFMEMORY );
  1298. goto Cleanup;
  1299. } // if:
  1300. ZeroMemory( m_ptipdProgressArray, m_cPASize * sizeof( m_ptipdProgressArray[ 0 ] ) );
  1301. // We just allocated the array so we know the first slot is open.
  1302. idx = 0;
  1303. } // if: we need to allocate the array
  1304. else if ( m_cPACount == m_cPASize )
  1305. {
  1306. STreeItemLParamData ** ptipdTempArray = NULL;
  1307. Assert( m_cPASize != 0 );
  1308. //
  1309. // We need to increase the size of the array.
  1310. //
  1311. ptipdTempArray = new STreeItemLParamData* [ m_cPASize * 2 ];
  1312. if ( ptipdTempArray == NULL )
  1313. {
  1314. hr = THR( E_OUTOFMEMORY );
  1315. goto Cleanup;
  1316. } // if:
  1317. // Copy the old array over the first half of the new array.
  1318. CopyMemory( ptipdTempArray, m_ptipdProgressArray, m_cPASize * sizeof( m_ptipdProgressArray[ 0 ] ) );
  1319. // Zero out the second half of the new array.
  1320. ZeroMemory( &ptipdTempArray[ m_cPASize ], m_cPASize * sizeof( ptipdTempArray[ 0 ] ) );
  1321. //
  1322. // Update member variables to reflect the changes.
  1323. //
  1324. m_cPASize *= 2; // We doubled the array length.
  1325. delete [] m_ptipdProgressArray;
  1326. m_ptipdProgressArray = ptipdTempArray;
  1327. ptipdTempArray = NULL;
  1328. // We know the first open slot is at index m_cPACount.
  1329. idx = m_cPACount;
  1330. } // else: we've used all available slots
  1331. else
  1332. {
  1333. // Else we have a spot open somewhere in the existing array. Start searching from 0.
  1334. idx = 0;
  1335. } // else: there's an available slot
  1336. //
  1337. // Find an empty slot and allocate a new task to put in it.
  1338. //
  1339. for ( ; idx < m_cPASize; idx++ )
  1340. {
  1341. if ( m_ptipdProgressArray[ idx ] == NULL )
  1342. {
  1343. //
  1344. // Found an empty slot - allocate the new task.
  1345. //
  1346. ptipdPrev = new STreeItemLParamData;
  1347. if ( ptipdPrev == NULL )
  1348. {
  1349. hr = THR( E_OUTOFMEMORY );
  1350. goto Cleanup;
  1351. } // if:
  1352. ptipdPrev->bstrNodeName = TraceSysAllocString( ptipdIn->bstrNodeName );
  1353. if ( ( ptipdIn->bstrNodeName != NULL ) && ( ptipdPrev->bstrNodeName == NULL ) )
  1354. {
  1355. hr = THR( E_OUTOFMEMORY );
  1356. delete ptipdPrev;
  1357. ptipdPrev = NULL;
  1358. goto Cleanup;
  1359. } // if:
  1360. CopyMemory( &ptipdPrev->clsidMajorTaskId, &ptipdIn->clsidMajorTaskId, sizeof( ptipdIn->clsidMajorTaskId ) );
  1361. CopyMemory( &ptipdPrev->clsidMinorTaskId, &ptipdIn->clsidMinorTaskId, sizeof( ptipdIn->clsidMinorTaskId ) );
  1362. ptipdPrev->nMin = ptipdIn->nMin;
  1363. ptipdPrev->nMax = ptipdIn->nMax;
  1364. ptipdPrev->nCurrent = ptipdIn->nCurrent;
  1365. ptipdPrev->fParentToAllNodeTasks = ptipdIn->fParentToAllNodeTasks;
  1366. m_ptipdProgressArray[ idx ] = ptipdPrev;
  1367. m_cPACount++;
  1368. fNewTask = TRUE;
  1369. idxPrev = idx;
  1370. break;
  1371. } // if:
  1372. } // for: find an emtpy slot
  1373. } // if: couldn't find a matching task in the array
  1374. Assert( ptipdPrev != NULL );
  1375. Assert( ptipdIn->bstrReference == NULL );
  1376. Assert( ptipdIn->nMin < ptipdIn->nMax );
  1377. Assert( ptipdIn->nMin <= ptipdIn->nCurrent );
  1378. Assert( ptipdIn->nCurrent <= ptipdIn->nMax );
  1379. //
  1380. // Update the progress bar.
  1381. //
  1382. STHR( HrUpdateProgressBar( ptipdIn, ptipdPrev ) ); // Ignore failure.
  1383. //
  1384. // If the task has completed, remove it from the array.
  1385. //
  1386. if ( ptipdIn->nMax == ptipdIn->nCurrent )
  1387. {
  1388. TraceSysFreeString( ptipdPrev->bstrNodeName );
  1389. delete ptipdPrev;
  1390. m_ptipdProgressArray[ idxPrev ] = NULL;
  1391. m_cPACount--;
  1392. } // if: task complete
  1393. else if ( fNewTask == FALSE )
  1394. {
  1395. //
  1396. // Else, update ptipdPrev only if we didn't just copy the array.
  1397. //
  1398. // This could have been a range-changing event, so copy the min, max, current.
  1399. ptipdPrev->nMin = ptipdIn->nMin;
  1400. ptipdPrev->nMax = ptipdIn->nMax;
  1401. ptipdPrev->nCurrent = ptipdIn->nCurrent;
  1402. } // else if: not a new task
  1403. Cleanup:
  1404. RETURN( hr );
  1405. } //*** CTaskTreeView::HrProcessUpdateProgressTask
  1406. //////////////////////////////////////////////////////////////////////////////
  1407. //++
  1408. //
  1409. // CTaskTreeView::HrUpdateProgressBar
  1410. //
  1411. // Description:
  1412. // Update the progress bar based on new tree item data.
  1413. //
  1414. // Arguments:
  1415. // ptipdNewIn - New values of the tree item data.
  1416. // ptipdPrevIn - Previous values of the tree item data.
  1417. //
  1418. // Return Values:
  1419. // S_OK - Operation completed successfully.
  1420. //
  1421. //--
  1422. //////////////////////////////////////////////////////////////////////////////
  1423. HRESULT
  1424. CTaskTreeView::HrUpdateProgressBar(
  1425. const STreeItemLParamData * ptipdNewIn
  1426. , const STreeItemLParamData * ptipdPrevIn
  1427. )
  1428. {
  1429. TraceFunc( "" );
  1430. HRESULT hr = S_OK;
  1431. ULONG nRealPos = 0;
  1432. ULONG nShrink = 0;
  1433. ULONG nExpand = 0;
  1434. ULONG nProgress = 0;
  1435. //
  1436. // Verify parameters.
  1437. //
  1438. Assert( m_hwndProg != NULL );
  1439. Assert( ptipdNewIn != NULL );
  1440. Assert( ptipdPrevIn != NULL );
  1441. Assert( (ptipdPrevIn->nCurrent <= ptipdPrevIn->nMax) && (ptipdNewIn->nCurrent <= ptipdNewIn->nMax) );
  1442. Assert( (ptipdPrevIn->nCurrent >= ptipdPrevIn->nMin) && (ptipdNewIn->nCurrent >= ptipdNewIn->nMin) );
  1443. //
  1444. // Make sure we're only passed a task update that we can analyze.
  1445. //
  1446. Assert( IsEqualIID( ptipdPrevIn->clsidMajorTaskId, IID_NULL ) == FALSE );
  1447. Assert( IsEqualIID( ptipdPrevIn->clsidMajorTaskId, ptipdNewIn->clsidMajorTaskId ) == TRUE ) // Majors match
  1448. Assert( IsEqualIID( ptipdPrevIn->clsidMinorTaskId, ptipdNewIn->clsidMinorTaskId ) == TRUE ) // && Minors match
  1449. if ( IsEqualIID( ptipdPrevIn->clsidMajorTaskId, ptipdNewIn->clsidMajorTaskId ) == FALSE // Majors don't match
  1450. || IsEqualIID( ptipdPrevIn->clsidMinorTaskId, ptipdNewIn->clsidMinorTaskId ) == FALSE ) // or Minors don't match
  1451. {
  1452. // This update is meaningless because we don't know how to compare the two IN params.
  1453. WCHAR szNewMajor[ 64 ];
  1454. WCHAR szNewMinor[ 64 ];
  1455. WCHAR szPrevMajor[ 64 ];
  1456. WCHAR szPrevMinor[ 64 ];
  1457. int cch;
  1458. cch = StringFromGUID2( ptipdNewIn->clsidMajorTaskId, szNewMajor, RTL_NUMBER_OF( szNewMajor ) );
  1459. Assert( cch > 0 ); // 64 chars should always hold a guid!
  1460. cch = StringFromGUID2( ptipdNewIn->clsidMinorTaskId, szNewMinor, RTL_NUMBER_OF( szNewMinor ) );
  1461. Assert( cch > 0 ); // 64 chars should always hold a guid!
  1462. cch = StringFromGUID2( ptipdPrevIn->clsidMajorTaskId, szPrevMajor, RTL_NUMBER_OF( szPrevMajor ) );
  1463. Assert( cch > 0 ); // 64 chars should always hold a guid!
  1464. cch = StringFromGUID2( ptipdPrevIn->clsidMinorTaskId, szPrevMinor, RTL_NUMBER_OF( szPrevMinor ) );
  1465. Assert( cch > 0 ); // 64 chars should always hold a guid!
  1466. LogMsg(
  1467. L"[WIZ] Ignoring invalid progress -- major and minor task IDs do not match. new major = %ws, new minor = %ws, prev major = %ws, prev minor = %ws"
  1468. , szNewMajor
  1469. , szNewMinor
  1470. , szPrevMajor
  1471. , szPrevMinor
  1472. );
  1473. hr = THR( S_FALSE );
  1474. goto Cleanup;
  1475. } // if: the two tipd's don't match
  1476. if ( ( ptipdNewIn->nMin == ptipdNewIn->nMax ) && ( ptipdNewIn->nCurrent == ptipdNewIn->nMax ) )
  1477. {
  1478. // This is a one-off: min == max && current == max.
  1479. nExpand = ptipdNewIn->nCurrent;
  1480. nProgress = ptipdNewIn->nCurrent;
  1481. } // else: this is a one-off
  1482. else if ( ( ptipdNewIn->nMax != ptipdPrevIn->nMax ) || ( ptipdNewIn->nMin != ptipdPrevIn->nMin ) )
  1483. {
  1484. //
  1485. // The min's and/or maxes changed. Verify that it follows the rules.
  1486. //
  1487. // Rules:
  1488. // Max: If the max changes then min and current need to stay the same.
  1489. // Resizing max can not cause the current to exceed max.
  1490. //
  1491. // Min: If the min changes then max can't change and the difference
  1492. // between current and min has to remain the same.
  1493. //
  1494. // In no case should a resizing cause min == max == current - this
  1495. // will be treated as a one-off event and may orphan a task in the
  1496. // update progress array.
  1497. //
  1498. if ( ptipdNewIn->nMax != ptipdPrevIn->nMax ) // Maxes changed
  1499. {
  1500. if ( ( ptipdNewIn->nCurrent != ptipdPrevIn->nCurrent ) // Currents changed
  1501. || ( ptipdNewIn->nMin != ptipdPrevIn->nMin ) // or Mins changed
  1502. || ( ptipdNewIn->nCurrent > ptipdNewIn->nMax ) ) // or current exceeded the max
  1503. {
  1504. LogMsg(
  1505. L"[WIZ] Ignoring invalid progress -- mins and/or maxes are invalid. new min = %d, prev min = %d, new max = %d, prev max = %d, new current = %d, prev current = %d"
  1506. , ptipdNewIn->nMin
  1507. , ptipdPrevIn->nMin
  1508. , ptipdNewIn->nMax
  1509. , ptipdPrevIn->nMax
  1510. , ptipdNewIn->nCurrent
  1511. , ptipdPrevIn->nCurrent
  1512. );
  1513. hr = THR( S_FALSE );
  1514. goto Cleanup;
  1515. } // if:
  1516. //
  1517. // The max changed, meaning we'll need to modify the range by that much.
  1518. //
  1519. if ( ptipdNewIn->nMax > ptipdPrevIn->nMax )
  1520. {
  1521. nExpand = ptipdNewIn->nMax - ptipdPrevIn->nMax;
  1522. } // if:
  1523. else
  1524. {
  1525. nShrink = ptipdPrevIn->nMax - ptipdNewIn->nMax;
  1526. } // else:
  1527. } // if: maxes differ
  1528. else // Mins changed
  1529. {
  1530. // If the difference between min & current varies between the two, or if the new current > new max then fail.
  1531. if ( ( ptipdNewIn->nCurrent - ptipdNewIn->nMin ) != ( ptipdPrevIn->nCurrent - ptipdPrevIn->nMin )
  1532. || ( ptipdNewIn->nCurrent > ptipdNewIn->nMax ) )
  1533. {
  1534. LogMsg(
  1535. L"[WIZ] Ignoring invalid progress -- the range between current and max is incorrect. new current - new min = %d, prev current - prev min = %d, new current %d > new max %d"
  1536. , ( ptipdNewIn->nCurrent - ptipdNewIn->nMin )
  1537. , ( ptipdPrevIn->nCurrent - ptipdPrevIn->nMin )
  1538. , ptipdNewIn->nCurrent
  1539. , ptipdNewIn->nMax
  1540. );
  1541. hr = THR( S_FALSE );
  1542. goto Cleanup;
  1543. } // if:
  1544. //
  1545. // The min changed, meaning we need to modify the range by the difference.
  1546. //
  1547. if ( ptipdNewIn->nMin > ptipdPrevIn->nMin )
  1548. {
  1549. nShrink = ptipdNewIn->nMin - ptipdPrevIn->nMin;
  1550. } // if:
  1551. else
  1552. {
  1553. nExpand = ptipdPrevIn->nMin - ptipdNewIn->nMin;
  1554. } // else:
  1555. } // else: mins changed
  1556. } // else if: min or max changed
  1557. else if ( ( ptipdNewIn->nMax == ptipdPrevIn->nMax ) // max didn't change
  1558. && ( ptipdNewIn->nMin == ptipdPrevIn->nMin ) // and min didn't change
  1559. && ( ptipdNewIn->nCurrent == ptipdPrevIn->nCurrent ) // and current didn't change
  1560. && ( ptipdNewIn->nCurrent == ptipdNewIn->nMin ) ) // and current equals min
  1561. {
  1562. nExpand = ptipdNewIn->nMax - ptipdNewIn->nMin; // We have a new task.
  1563. } // else if: we're adding a new task
  1564. else if ( ( ptipdNewIn->nMax == ptipdPrevIn->nMax ) // max didn't change
  1565. && ( ptipdNewIn->nMin == ptipdPrevIn->nMin ) // and min didn't change
  1566. && ( ptipdNewIn->nCurrent > ptipdPrevIn->nCurrent ) // and current increased
  1567. && ( ptipdNewIn->nCurrent <= ptipdNewIn->nMax ) ) // and current didn't exceed max
  1568. {
  1569. nProgress = ptipdNewIn->nCurrent - ptipdPrevIn->nCurrent; // We have an update.
  1570. } // else if: we're updating a known task
  1571. else
  1572. {
  1573. // This event broke the rules - toss it out.
  1574. LogMsg(
  1575. L"[WIZ] Ignoring invalid progress -- min, max or current are invalid. new min = %d, prev min = %d, new max = %d, prev max = %d, new current = %d, prev current = %d"
  1576. , ptipdNewIn->nMin
  1577. , ptipdPrevIn->nMin
  1578. , ptipdNewIn->nMax
  1579. , ptipdPrevIn->nMax
  1580. , ptipdNewIn->nCurrent
  1581. , ptipdPrevIn->nCurrent
  1582. );
  1583. hr = THR( S_FALSE );
  1584. goto Cleanup;
  1585. } // else if: the two tipd's don't conform to the rules of a progress bar update
  1586. m_nRangeHigh += nExpand;
  1587. Assert( m_nRangeHigh >= nShrink )
  1588. m_nRangeHigh -= nShrink;
  1589. if ( m_nRangeHigh > m_nInitialTickCount )
  1590. {
  1591. m_fThresholdBroken = TRUE;
  1592. } // if: exceeded the initial tick count
  1593. m_nCurrentPos += nProgress;
  1594. if ( m_nCurrentPos >= m_nRangeHigh )
  1595. {
  1596. //
  1597. // Something went wrong - our position is now somehow greater than
  1598. // the range (multi-threading issue?). Simple fix - set our new range
  1599. // to be PROGRESSBAR_RESIZE_PERCENT percent greater than our new position
  1600. //
  1601. m_nRangeHigh = ( m_nCurrentPos * (100 + PROGRESSBAR_RESIZE_PERCENT) ) / 100;
  1602. } // if: current pos caught up to the upper range
  1603. // Adjust to the progress bar's scale (PROGRESSBAR_CONTROL_TICK_COUNT).
  1604. nRealPos = m_nCurrentPos * PROGRESSBAR_CONTROL_TICK_COUNT;
  1605. if ( m_fThresholdBroken )
  1606. {
  1607. nRealPos /= m_nRangeHigh;
  1608. } // if: use threshold
  1609. else
  1610. {
  1611. nRealPos /= m_nInitialTickCount;
  1612. } // else: use initial tick count
  1613. //
  1614. // If our progress bar position actually moved forward - update the control.
  1615. // This isn't always the case because we may have a new task come in and
  1616. // report a large number of steps, thereby moving our real position
  1617. // backwards, but we don't want to show reverse progress - just a steady
  1618. // advancement towards being done.
  1619. //
  1620. if ( nRealPos > m_nRealPos )
  1621. {
  1622. m_nRealPos = nRealPos;
  1623. SendMessage( m_hwndProg, PBM_SETPOS, m_nRealPos, 0 );
  1624. } // if: forward progress
  1625. Cleanup:
  1626. HRETURN( hr );
  1627. } //*** CTaskTreeView::HrUpdateProgressBar
  1628. //////////////////////////////////////////////////////////////////////////////
  1629. //++
  1630. //
  1631. // CTaskTreeView::HrPropagateChildStateToParents
  1632. //
  1633. // Description:
  1634. // Extend the state of a child item to its parent items.
  1635. // If the state of the child is worse (higher priority) than the
  1636. // parent's, update the state of the parent.
  1637. //
  1638. // Arguments:
  1639. // htiChildIn - Child item whose state is to be extended.
  1640. // nImageIn - Image of the child item.
  1641. // fOnlyUpdateProgressIn - TRUE = only updating progress.
  1642. //
  1643. // Return Values:
  1644. // S_OK - Operation completed successfully.
  1645. // S_FALSE - No parent item.
  1646. //
  1647. //--
  1648. //////////////////////////////////////////////////////////////////////////////
  1649. HRESULT
  1650. CTaskTreeView::HrPropagateChildStateToParents(
  1651. HTREEITEM htiChildIn
  1652. , int nImageIn
  1653. , BOOL fOnlyUpdateProgressIn
  1654. )
  1655. {
  1656. TraceFunc( "" );
  1657. Assert( htiChildIn != NULL );
  1658. HRESULT hr = S_OK;
  1659. BOOL fReturn;
  1660. TVITEMEX tviParent;
  1661. TVITEMEX tviChild;
  1662. HTREEITEM htiParent;
  1663. HTREEITEM htiChild;
  1664. //
  1665. // Get the parent item.
  1666. //
  1667. htiParent = TreeView_GetParent( m_hwndTV, htiChildIn );
  1668. if ( htiParent == NULL )
  1669. {
  1670. hr = S_FALSE;
  1671. goto Cleanup;
  1672. } // if:
  1673. tviParent.mask = TVIF_PARAM | TVIF_IMAGE;
  1674. tviParent.hItem = htiParent;
  1675. fReturn = TreeView_GetItem( m_hwndTV, &tviParent );
  1676. if ( ! fReturn )
  1677. {
  1678. hr = HRESULT_FROM_WIN32( TW32( ERROR_NOT_FOUND ) );
  1679. goto Cleanup;
  1680. } // if:
  1681. //
  1682. // If the state of the child is worse (higher priority) than the
  1683. // parent's, update the state of the parent.
  1684. //
  1685. if ( ( tviParent.iImage < nImageIn )
  1686. || ( ( tviParent.iImage == tsDONE )
  1687. && ( nImageIn == tsPENDING )
  1688. )
  1689. )
  1690. {
  1691. //
  1692. // Special Case: For the parent to be set to tsDONE, all
  1693. // the children must be set to tsDONE as well.
  1694. //
  1695. if ( ( nImageIn == tsDONE )
  1696. && ! fOnlyUpdateProgressIn
  1697. )
  1698. {
  1699. //
  1700. // Enum the children to see if they all have tsDONE as their images.
  1701. //
  1702. htiChild = TreeView_GetChild( m_hwndTV, tviParent.hItem );
  1703. while ( htiChild != NULL )
  1704. {
  1705. tviChild.mask = TVIF_IMAGE;
  1706. tviChild.hItem = htiChild;
  1707. fReturn = TreeView_GetItem( m_hwndTV, &tviChild );
  1708. if ( ! fReturn )
  1709. {
  1710. hr = HRESULT_FROM_WIN32( TW32( ERROR_NOT_FOUND ) );
  1711. goto Cleanup;
  1712. } // if:
  1713. if ( tviChild.iImage != tsDONE )
  1714. {
  1715. //
  1716. // Not all tsDONE! Skip setting parent's image!
  1717. // This can occur if the child is displaying a warning
  1718. // or error state image.
  1719. //
  1720. goto Cleanup;
  1721. } // if:
  1722. // Get next child
  1723. htiChild = TreeView_GetNextSibling( m_hwndTV, htiChild );
  1724. } // while: more children
  1725. } // if: special case (see above)
  1726. //
  1727. // Set the parent's icon.
  1728. //
  1729. tviParent.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE;
  1730. tviParent.iImage = nImageIn;
  1731. tviParent.iSelectedImage = nImageIn;
  1732. TreeView_SetItem( m_hwndTV, &tviParent );
  1733. } // if: need to update parent's image
  1734. //
  1735. // Traverse up the tree.
  1736. //
  1737. hr = STHR( HrPropagateChildStateToParents( htiParent, nImageIn, fOnlyUpdateProgressIn ) );
  1738. if ( hr == S_FALSE )
  1739. {
  1740. // S_FALSE means that there wasn't a parent.
  1741. hr = S_OK;
  1742. } // if:
  1743. goto Cleanup;
  1744. Cleanup:
  1745. HRETURN( hr );
  1746. } //*** CTaskTreeView::HrPropagateChildStateToParents
  1747. //////////////////////////////////////////////////////////////////////////////
  1748. //++
  1749. //
  1750. // CTaskTreeView::HrDisplayDetails
  1751. //
  1752. // Description:
  1753. // Display the Details dialog box.
  1754. //
  1755. // Arguments:
  1756. // None.
  1757. //
  1758. // Return Values:
  1759. // S_OK
  1760. //
  1761. //--
  1762. //////////////////////////////////////////////////////////////////////////////
  1763. HRESULT
  1764. CTaskTreeView::HrDisplayDetails( void )
  1765. {
  1766. TraceFunc( "" );
  1767. HRESULT hr = S_OK;
  1768. HTREEITEM hti;
  1769. HWND hwndPropertyPage;
  1770. //
  1771. // If no item is selected, select the first item.
  1772. //
  1773. if ( m_htiSelected == NULL )
  1774. {
  1775. hti = TreeView_GetRoot( m_hwndTV );
  1776. Assert( hti != NULL );
  1777. hr = THR( HrSelectItem( hti ) );
  1778. if ( FAILED( hr ) )
  1779. {
  1780. // TODO: Display message box
  1781. goto Cleanup;
  1782. } // if:
  1783. } // if: no items are selected
  1784. //
  1785. // Display the dialog box.
  1786. //
  1787. hwndPropertyPage = GetParent( m_hwndTV );
  1788. Assert( hwndPropertyPage != NULL );
  1789. hr = THR( CDetailsDlg::S_HrDisplayModalDialog( hwndPropertyPage, this, m_htiSelected ) );
  1790. SetFocus( m_hwndTV );
  1791. Cleanup:
  1792. HRETURN( hr );
  1793. } //*** CTaskTreeView::HrDisplayDetails
  1794. //////////////////////////////////////////////////////////////////////////////
  1795. //++
  1796. //
  1797. // CTaskTreeView::FGetItem
  1798. //
  1799. // Description:
  1800. // Get the data for an item.
  1801. //
  1802. // Arguments:
  1803. // htiIn - Handle for the item to get.
  1804. // pptipdOut - Pointer in which to return the data structure.
  1805. //
  1806. // Return Values:
  1807. // TRUE - Item returned successfully.
  1808. // FALSE - Item not returned.
  1809. //
  1810. //--
  1811. //////////////////////////////////////////////////////////////////////////////
  1812. BOOL
  1813. CTaskTreeView::FGetItem(
  1814. HTREEITEM htiIn
  1815. , STreeItemLParamData ** pptipd
  1816. )
  1817. {
  1818. TraceFunc( "" );
  1819. Assert( htiIn != NULL );
  1820. Assert( pptipd != NULL );
  1821. BOOL fRet;
  1822. TVITEMEX tvi;
  1823. ZeroMemory( &tvi, sizeof( tvi ) );
  1824. tvi.mask = TVIF_PARAM;
  1825. tvi.hItem = htiIn;
  1826. fRet = TreeView_GetItem( m_hwndTV, &tvi );
  1827. if ( fRet == FALSE )
  1828. {
  1829. goto Cleanup;
  1830. } // if:
  1831. Assert( tvi.lParam != NULL );
  1832. *pptipd = reinterpret_cast< STreeItemLParamData * >( tvi.lParam );
  1833. Cleanup:
  1834. RETURN( fRet );
  1835. } //*** CTaskTreeView::FGetItem
  1836. //////////////////////////////////////////////////////////////////////////////
  1837. //++
  1838. //
  1839. // CTaskTreeView::HrFindPrevItem
  1840. //
  1841. // Description:
  1842. // Find the previous item. The previous item could be at a deeper
  1843. // level than this item.
  1844. //
  1845. // Arguments:
  1846. // phtiOut - Handle to previous item (optional).
  1847. //
  1848. // Return Values:
  1849. // S_OK - Previous item found successfully.
  1850. // S_FALSE - No previous item found.
  1851. // Other HRESULTs.
  1852. //
  1853. //--
  1854. //////////////////////////////////////////////////////////////////////////////
  1855. HRESULT
  1856. CTaskTreeView::HrFindPrevItem(
  1857. HTREEITEM * phtiOut
  1858. )
  1859. {
  1860. TraceFunc( "" );
  1861. HRESULT hr = S_FALSE;
  1862. HTREEITEM htiCur;
  1863. HTREEITEM htiPrev;
  1864. htiCur = m_htiSelected;
  1865. if ( phtiOut != NULL )
  1866. {
  1867. *phtiOut = NULL;
  1868. } // if:
  1869. //
  1870. // Find the previous sibling item.
  1871. //
  1872. htiPrev = TreeView_GetPrevSibling( m_hwndTV, htiCur );
  1873. if ( htiPrev == NULL )
  1874. {
  1875. //
  1876. // NO PREVIOUS SIBLING ITEM FOUND.
  1877. //
  1878. // Find the parent item.
  1879. // If there isn't a parent, then there isn't a previous item.
  1880. //
  1881. htiPrev = TreeView_GetParent( m_hwndTV, htiCur );
  1882. if ( htiPrev == NULL )
  1883. {
  1884. goto Cleanup;
  1885. } // if: no parent item
  1886. //
  1887. // The parent is the previous item.
  1888. //
  1889. } // if: no previous sibling
  1890. else
  1891. {
  1892. //
  1893. // PREVIOUS SIBLING ITEM FOUND.
  1894. //
  1895. // Find the deepest child of the last child item.
  1896. //
  1897. for ( ;; )
  1898. {
  1899. //
  1900. // Find the first child item.
  1901. //
  1902. htiCur = TreeView_GetChild( m_hwndTV, htiPrev );
  1903. if ( htiCur == NULL )
  1904. {
  1905. //
  1906. // NO CHILD ITEM FOUND.
  1907. //
  1908. // This is the previous item.
  1909. //
  1910. break;
  1911. } // if: no children
  1912. //
  1913. // CHILD ITEM FOUND.
  1914. //
  1915. // Find the last sibling of this child item.
  1916. //
  1917. for ( ;; )
  1918. {
  1919. //
  1920. // Find the next sibling item.
  1921. //
  1922. htiPrev = TreeView_GetNextSibling( m_hwndTV, htiCur );
  1923. if ( htiPrev == NULL )
  1924. {
  1925. //
  1926. // No next sibling item found.
  1927. // Exit this loop and continue the outer loop
  1928. // to find this item's children.
  1929. //
  1930. htiPrev = htiCur;
  1931. break;
  1932. } // if: no next sibling item found
  1933. //
  1934. // Found a next sibling item.
  1935. //
  1936. htiCur = htiPrev;
  1937. } // forever: find the last child item
  1938. } // forever: find the deepest child item
  1939. } // else: previous sibling item found
  1940. //
  1941. // Return the item we found.
  1942. //
  1943. Assert( htiPrev != NULL );
  1944. if ( phtiOut != NULL )
  1945. {
  1946. *phtiOut = htiPrev;
  1947. } // if:
  1948. hr = S_OK;
  1949. Cleanup:
  1950. HRETURN( hr );
  1951. } //*** CTaskTreeView::HrFindPrevItem
  1952. //////////////////////////////////////////////////////////////////////////////
  1953. //++
  1954. //
  1955. // CTaskTreeView::HrFindNextItem
  1956. //
  1957. // Description:
  1958. // Find the next item. The next item could be at a different level than
  1959. // this item.
  1960. //
  1961. // Arguments:
  1962. // phtiOut - Handle to next item (optional).
  1963. //
  1964. // Return Values:
  1965. // S_OK - Next item found successfully.
  1966. // S_FALSE - No next item found.
  1967. // Other HRESULTs.
  1968. //
  1969. //--
  1970. //////////////////////////////////////////////////////////////////////////////
  1971. HRESULT
  1972. CTaskTreeView::HrFindNextItem(
  1973. HTREEITEM * phtiOut
  1974. )
  1975. {
  1976. TraceFunc( "" );
  1977. HRESULT hr = S_FALSE;
  1978. HTREEITEM htiCur;
  1979. HTREEITEM htiNext;
  1980. htiCur = m_htiSelected;
  1981. if ( phtiOut != NULL )
  1982. {
  1983. *phtiOut = NULL;
  1984. } // if:
  1985. //
  1986. // Find the first child item.
  1987. //
  1988. htiNext = TreeView_GetChild( m_hwndTV, htiCur );
  1989. if ( htiNext == NULL )
  1990. {
  1991. //
  1992. // NO CHILD ITEM FOUND.
  1993. //
  1994. for ( ;; )
  1995. {
  1996. //
  1997. // Get the next sibling item.
  1998. //
  1999. htiNext = TreeView_GetNextSibling( m_hwndTV, htiCur );
  2000. if ( htiNext == NULL )
  2001. {
  2002. //
  2003. // NO SIBLING ITEM FOUND.
  2004. //
  2005. // Find the parent item so we can find its next sibling.
  2006. //
  2007. htiNext = TreeView_GetParent( m_hwndTV, htiCur );
  2008. if ( htiNext == NULL )
  2009. {
  2010. //
  2011. // NO PARENT ITEM FOUND.
  2012. //
  2013. // At the end of the tree.
  2014. //
  2015. goto Cleanup;
  2016. } // if: no parent found
  2017. //
  2018. // PARENT ITEM FOUND.
  2019. //
  2020. // Find the parent item's next sibling.
  2021. //
  2022. htiCur = htiNext;
  2023. continue;
  2024. } // if: no next sibling item
  2025. //
  2026. // SIBLING ITEM FOUND.
  2027. //
  2028. // Found the next item.
  2029. //
  2030. break;
  2031. } // forever: find the next sibling or parent's sibling
  2032. } // if: no child item found
  2033. else
  2034. {
  2035. //
  2036. // CHILD ITEM FOUND.
  2037. //
  2038. // Found the next item.
  2039. //
  2040. } // else: child item found
  2041. //
  2042. // Return the item we found.
  2043. //
  2044. Assert( htiNext != NULL );
  2045. if ( phtiOut != NULL )
  2046. {
  2047. *phtiOut = htiNext;
  2048. } // if:
  2049. hr = S_OK;
  2050. Cleanup:
  2051. HRETURN( hr );
  2052. } //*** CTaskTreeView::HrFindNextItem
  2053. //////////////////////////////////////////////////////////////////////////////
  2054. //++
  2055. //
  2056. // CTaskTreeView::HrSelectItem
  2057. //
  2058. // Description:
  2059. // Select the specified item.
  2060. //
  2061. // Arguments:
  2062. // htiIn - Handle to item to select.
  2063. //
  2064. // Return Values:
  2065. // S_OK - Item selected successfully.
  2066. // Other HRESULTs.
  2067. //
  2068. //--
  2069. //////////////////////////////////////////////////////////////////////////////
  2070. HRESULT
  2071. CTaskTreeView::HrSelectItem(
  2072. HTREEITEM htiIn
  2073. )
  2074. {
  2075. TraceFunc( "" );
  2076. Assert( htiIn != NULL );
  2077. HRESULT hr = S_OK;
  2078. TreeView_SelectItem( m_hwndTV, htiIn );
  2079. HRETURN( hr );
  2080. } //*** CTaskTreeView::HrSelectItem
  2081. //****************************************************************************
  2082. //
  2083. // Static Functions
  2084. //
  2085. //****************************************************************************
  2086. //////////////////////////////////////////////////////////////////////////////
  2087. //++
  2088. //
  2089. // HrCreateTreeItem
  2090. //
  2091. // Description:
  2092. // Create a tree item.
  2093. //
  2094. // Arguments:
  2095. // ptvisOut - Tree view insert structure to fill in.
  2096. // ptipdIn - Input tree item LParam data to create this item from.
  2097. // htiParentIn - Parent tree view item.
  2098. // nImageIn - Image index.
  2099. // bstrTextIn - Text to display.
  2100. //
  2101. // Return Values:
  2102. // S_OK - Operation was successful.
  2103. // E_OUTOFMEMORY - Error allocating memory.
  2104. //
  2105. //--
  2106. //////////////////////////////////////////////////////////////////////////////
  2107. HRESULT
  2108. HrCreateTreeItem(
  2109. TVINSERTSTRUCT * ptvisOut
  2110. , STreeItemLParamData * ptipdIn
  2111. , HTREEITEM htiParentIn
  2112. , int nImageIn
  2113. , BSTR bstrTextIn
  2114. )
  2115. {
  2116. TraceFunc( "" );
  2117. Assert( ptvisOut != NULL );
  2118. Assert( ptipdIn != NULL );
  2119. Assert( htiParentIn != NULL );
  2120. Assert( bstrTextIn != NULL );
  2121. // LOCAL VARIABLES
  2122. HRESULT hr = S_OK;
  2123. STreeItemLParamData * ptipdNew = NULL;
  2124. //
  2125. // Allocate the tree view LParam data and initialize it.
  2126. //
  2127. ptipdNew = new STreeItemLParamData;
  2128. if ( ptipdNew == NULL )
  2129. {
  2130. hr = THR( E_OUTOFMEMORY );
  2131. goto Cleanup;
  2132. } // if:
  2133. CopyMemory( &ptipdNew->clsidMajorTaskId, &ptipdIn->clsidMajorTaskId, sizeof( ptipdNew->clsidMajorTaskId ) );
  2134. CopyMemory( &ptipdNew->clsidMinorTaskId, &ptipdIn->clsidMinorTaskId, sizeof( ptipdNew->clsidMinorTaskId ) );
  2135. CopyMemory( &ptipdNew->ftTime, &ptipdIn->ftTime, sizeof( ptipdNew->ftTime ) );
  2136. ptipdNew->nMin = ptipdIn->nMin;
  2137. ptipdNew->nMax = ptipdIn->nMax;
  2138. ptipdNew->nCurrent = ptipdIn->nCurrent;
  2139. ptipdNew->hr = ptipdIn->hr;
  2140. if ( ptipdIn->bstrNodeName != NULL )
  2141. {
  2142. ptipdNew->bstrNodeName = TraceSysAllocString( ptipdIn->bstrNodeName );
  2143. if ( ptipdNew->bstrNodeName == NULL )
  2144. {
  2145. hr = THR( E_OUTOFMEMORY );
  2146. goto Cleanup;
  2147. } // if:
  2148. Assert( ptipdIn->bstrNodeNameWithoutDomain != NULL );
  2149. ptipdNew->bstrNodeNameWithoutDomain = TraceSysAllocString( ptipdIn->bstrNodeNameWithoutDomain );
  2150. if ( ptipdNew->bstrNodeNameWithoutDomain == NULL )
  2151. {
  2152. hr = THR( E_OUTOFMEMORY );
  2153. goto Cleanup;
  2154. } // if:
  2155. } // if: node name specified
  2156. if ( ptipdIn->bstrDescription != NULL )
  2157. {
  2158. ptipdNew->bstrDescription = TraceSysAllocString( ptipdIn->bstrDescription );
  2159. if ( ptipdNew->bstrDescription == NULL )
  2160. {
  2161. hr = THR( E_OUTOFMEMORY );
  2162. goto Cleanup;
  2163. } // if:
  2164. } // if: description specified
  2165. if ( ptipdIn->bstrReference != NULL )
  2166. {
  2167. ptipdNew->bstrReference = TraceSysAllocString( ptipdIn->bstrReference );
  2168. if ( ptipdNew->bstrReference == NULL )
  2169. {
  2170. hr = THR( E_OUTOFMEMORY );
  2171. goto Cleanup;
  2172. } // if:
  2173. } // if: reference specified
  2174. //
  2175. // Initialize the tree view insert structure.
  2176. //
  2177. ptvisOut->hParent = htiParentIn;
  2178. ptvisOut->hInsertAfter = TVI_LAST;
  2179. ptvisOut->itemex.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM;
  2180. ptvisOut->itemex.cchTextMax = SysStringLen( bstrTextIn );
  2181. ptvisOut->itemex.pszText = bstrTextIn;
  2182. ptvisOut->itemex.iImage = nImageIn;
  2183. ptvisOut->itemex.iSelectedImage = nImageIn;
  2184. ptvisOut->itemex.lParam = reinterpret_cast< LPARAM >( ptipdNew );
  2185. Assert( ptvisOut->itemex.cchTextMax > 0 );
  2186. // Release ownership to the tree view insert structure.
  2187. ptipdNew = NULL;
  2188. goto Cleanup;
  2189. Cleanup:
  2190. if ( ptipdNew != NULL )
  2191. {
  2192. TraceSysFreeString( ptipdNew->bstrNodeName );
  2193. TraceSysFreeString( ptipdNew->bstrNodeNameWithoutDomain );
  2194. TraceSysFreeString( ptipdNew->bstrDescription );
  2195. TraceSysFreeString( ptipdNew->bstrReference );
  2196. delete ptipdNew;
  2197. } // if:
  2198. HRETURN( hr );
  2199. } //*** HrCreateTreeItem