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
2585 lines
80 KiB
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (c) 2000-2002 Microsoft Corporation
|
|
//
|
|
// Module Name:
|
|
// TaskTreeView.cpp
|
|
//
|
|
// Maintained By:
|
|
// Galen Barbee (GalenB) 22-MAY-2000
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "Pch.h"
|
|
#include "TaskTreeView.h"
|
|
#include "DetailsDlg.h"
|
|
|
|
DEFINE_THISCLASS( "CTaskTreeView" )
|
|
|
|
|
|
//****************************************************************************
|
|
//
|
|
// Constants
|
|
//
|
|
//****************************************************************************
|
|
|
|
#define PROGRESSBAR_CONTROL_TICK_COUNT 1000
|
|
#define PROGRESSBAR_INITIAL_POSITION 10
|
|
#define PROGRESSBAR_RESIZE_PERCENT 5
|
|
|
|
//****************************************************************************
|
|
//
|
|
// Static Function Prototypes
|
|
//
|
|
//****************************************************************************
|
|
static
|
|
HRESULT
|
|
HrCreateTreeItem(
|
|
TVINSERTSTRUCT * ptvisOut
|
|
, STreeItemLParamData * ptipdIn
|
|
, HTREEITEM htiParentIn
|
|
, int nImageIn
|
|
, BSTR bstrTextIn
|
|
);
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CTaskTreeView::CTaskTreeView
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
CTaskTreeView::CTaskTreeView(
|
|
HWND hwndParentIn
|
|
, UINT uIDTVIn
|
|
, UINT uIDProgressIn
|
|
, UINT uIDStatusIn
|
|
, size_t nInitialTickCount
|
|
)
|
|
{
|
|
TraceFunc( "" );
|
|
|
|
m_hwndParent = hwndParentIn;
|
|
m_hwndTV = GetDlgItem( hwndParentIn, uIDTVIn );
|
|
Assert( m_hwndTV != NULL );
|
|
|
|
m_hwndProg = GetDlgItem( hwndParentIn, uIDProgressIn );
|
|
Assert( m_hwndProg != NULL );
|
|
|
|
m_hwndStatus = GetDlgItem( hwndParentIn, uIDStatusIn );
|
|
Assert( m_hwndStatus != NULL );
|
|
|
|
m_hImgList = NULL;
|
|
|
|
Assert( m_htiSelected == NULL );
|
|
Assert( m_bstrClientMachineName == NULL );
|
|
Assert( m_fDisplayErrorsAsWarnings == FALSE );
|
|
|
|
//
|
|
// Most of these get set in HrOnNotifySetActive, so just init them to zero.
|
|
//
|
|
m_nInitialTickCount = (ULONG) nInitialTickCount;
|
|
m_nCurrentPos = 0;
|
|
m_nRealPos = 0;
|
|
m_fThresholdBroken = FALSE;
|
|
|
|
m_cPASize = 0;
|
|
m_cPACount = 0;
|
|
m_ptipdProgressArray = NULL;
|
|
|
|
TraceFuncExit();
|
|
|
|
} //*** CTaskTreeView::CTaskTreeView()
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CTaskTreeView::~CTaskTreeView( void )
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
CTaskTreeView::~CTaskTreeView( void )
|
|
{
|
|
TraceFunc( "" );
|
|
|
|
size_t idx;
|
|
STreeItemLParamData * ptipdTemp;
|
|
|
|
TreeView_DeleteAllItems( m_hwndTV );
|
|
|
|
if ( m_hImgList != NULL )
|
|
{
|
|
ImageList_Destroy( m_hImgList );
|
|
} // if:
|
|
|
|
TraceSysFreeString( m_bstrClientMachineName );
|
|
|
|
// Cleanup the progress array and delete any allocated entries.
|
|
for ( idx = 0; idx < m_cPASize; idx++ )
|
|
{
|
|
if ( m_ptipdProgressArray[ idx ] != NULL )
|
|
{
|
|
ptipdTemp = m_ptipdProgressArray[ idx ];
|
|
TraceSysFreeString( ptipdTemp->bstrNodeName );
|
|
delete ptipdTemp;
|
|
} // if: element is not NULL
|
|
} // for: each element of the array
|
|
|
|
delete [] m_ptipdProgressArray;
|
|
|
|
TraceFuncExit();
|
|
|
|
} //*** CTaskTreeView::~CTaskTreeView
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CTaskTreeView::HrOnInitDialog
|
|
//
|
|
// Description:
|
|
// Handle the WM_INITDIALOG message.
|
|
//
|
|
// Arguments:
|
|
// None.
|
|
//
|
|
// Return Values:
|
|
// S_OK - Success.
|
|
// Other HRESULTS.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
CTaskTreeView::HrOnInitDialog( void )
|
|
{
|
|
TraceFunc( "" );
|
|
|
|
HRESULT hr = S_OK;
|
|
HICON hIcon;
|
|
int idx;
|
|
|
|
Assert( m_bstrClientMachineName == NULL );
|
|
hr = THR( HrGetComputerName(
|
|
ComputerNameDnsHostname
|
|
, &m_bstrClientMachineName
|
|
, TRUE // fBestFit
|
|
) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
//
|
|
// Build image list for icons in tree view.
|
|
//
|
|
|
|
m_hImgList = ImageList_Create( 16, 16, ILC_MASK, tsMAX, 0);
|
|
if ( m_hImgList == NULL )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( TW32( GetLastError() ) );
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
//
|
|
// Unknown Icon - Task Unknown.
|
|
//
|
|
|
|
hIcon = (HICON) LoadImage( g_hInstance,
|
|
MAKEINTRESOURCE( IDI_SEL ),
|
|
IMAGE_ICON,
|
|
16,
|
|
16,
|
|
LR_SHARED
|
|
);
|
|
if ( hIcon == NULL )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( TW32( GetLastError() ) );
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
idx = ImageList_AddIcon( m_hImgList, hIcon );
|
|
Assert( idx == tsUNKNOWN );
|
|
|
|
//
|
|
// Pending Icon - Task Pending.
|
|
//
|
|
|
|
hIcon = (HICON) LoadImage( g_hInstance,
|
|
MAKEINTRESOURCE( IDI_PENDING ),
|
|
IMAGE_ICON,
|
|
16,
|
|
16,
|
|
LR_SHARED
|
|
);
|
|
if ( hIcon == NULL )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( TW32( GetLastError() ) );
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
idx = ImageList_AddIcon( m_hImgList, hIcon );
|
|
Assert( idx == tsPENDING );
|
|
|
|
//
|
|
// Checkmark Icon - Task Done.
|
|
//
|
|
|
|
hIcon = (HICON) LoadImage( g_hInstance,
|
|
MAKEINTRESOURCE( IDI_CHECK ),
|
|
IMAGE_ICON,
|
|
16,
|
|
16,
|
|
LR_SHARED
|
|
);
|
|
if ( hIcon == NULL )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( TW32( GetLastError() ) );
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
idx = ImageList_AddIcon( m_hImgList, hIcon );
|
|
Assert( idx == tsDONE );
|
|
|
|
//
|
|
// Warning Icon - Task Warning.
|
|
//
|
|
|
|
hIcon = (HICON) LoadImage( g_hInstance,
|
|
MAKEINTRESOURCE( IDI_WARN ),
|
|
IMAGE_ICON,
|
|
16,
|
|
16,
|
|
LR_SHARED
|
|
);
|
|
if ( hIcon == NULL )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( TW32( GetLastError() ) );
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
idx = ImageList_AddIcon( m_hImgList, hIcon );
|
|
Assert( idx == tsWARNING );
|
|
|
|
//
|
|
// Fail Icon - Task Failed.
|
|
//
|
|
|
|
hIcon = (HICON) LoadImage( g_hInstance,
|
|
MAKEINTRESOURCE( IDI_FAIL ),
|
|
IMAGE_ICON,
|
|
16,
|
|
16,
|
|
LR_SHARED
|
|
);
|
|
if ( hIcon == NULL )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( TW32( GetLastError() ) );
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
idx = ImageList_AddIcon( m_hImgList, hIcon );
|
|
Assert( idx == tsFAILED );
|
|
|
|
Assert( ImageList_GetImageCount( m_hImgList ) == tsMAX );
|
|
|
|
//
|
|
// Set the image list and background color.
|
|
//
|
|
|
|
TreeView_SetImageList( m_hwndTV, m_hImgList, TVSIL_NORMAL );
|
|
TreeView_SetBkColor( m_hwndTV, GetSysColor( COLOR_3DFACE ) );
|
|
|
|
Cleanup:
|
|
|
|
HRETURN( hr );
|
|
|
|
} //*** CTaskTreeView::HrOnInitDialog
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CTaskTreeView::HrAddTreeViewItem
|
|
//
|
|
// Description:
|
|
// Add a tree view item. This method will return the item handle and
|
|
// allows the caller to specify the parent item.
|
|
//
|
|
// Arguments:
|
|
// phtiOut
|
|
// Handle to the item being added (optional).
|
|
//
|
|
// idsIn
|
|
// String resource ID for description of the new item.
|
|
//
|
|
// rclsidMinorTaskIDIn
|
|
// Minor task ID for the item.
|
|
//
|
|
// rclsidMajorTaskIDIn
|
|
// Major task ID for the item. Defaults to IID_NULL.
|
|
//
|
|
// htiParentIn
|
|
// Parent item. Defaults to the root.
|
|
//
|
|
// fParentToAllNodeTasksIn
|
|
// TRUE = allow item to be parent to tasks from all nodes.
|
|
// FALSE = only allow item to be parent to tasks from the local node.
|
|
// Defaults to FALSE.
|
|
//
|
|
// Return Values:
|
|
// S_OK - Success.
|
|
// Other HRESULTs.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
CTaskTreeView::HrAddTreeViewItem(
|
|
HTREEITEM * phtiOut
|
|
, UINT idsIn
|
|
, REFCLSID rclsidMinorTaskIDIn
|
|
, REFCLSID rclsidMajorTaskIDIn // = IID_NULL
|
|
, HTREEITEM htiParentIn // = TVI_ROOT
|
|
, BOOL fParentToAllNodeTasksIn // = FALSE
|
|
)
|
|
{
|
|
TraceFunc( "" );
|
|
|
|
HRESULT hr = S_OK;
|
|
STreeItemLParamData * ptipd;
|
|
SYSTEMTIME systemtime;
|
|
TVINSERTSTRUCT tvis;
|
|
HTREEITEM hti = NULL;
|
|
|
|
//
|
|
// Allocate an item data structure.
|
|
//
|
|
|
|
ptipd = new STreeItemLParamData;
|
|
if ( ptipd == NULL )
|
|
{
|
|
hr = THR( E_OUTOFMEMORY );
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
//
|
|
// Set the node name to the local computer name.
|
|
//
|
|
|
|
hr = THR( HrGetComputerName(
|
|
ComputerNamePhysicalDnsFullyQualified
|
|
, &ptipd->bstrNodeName
|
|
, TRUE // fBestFitIn
|
|
) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
hr = THR( HrGetFQNDisplayName( ptipd->bstrNodeName, &ptipd->bstrNodeNameWithoutDomain ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
//
|
|
// Set the desription from the string resource ID.
|
|
//
|
|
|
|
hr = THR( HrLoadStringIntoBSTR( g_hInstance, idsIn, &ptipd->bstrDescription ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
//
|
|
// Set the date/time to the current date/time.
|
|
//
|
|
|
|
GetSystemTime( &systemtime );
|
|
if ( ! SystemTimeToFileTime( &systemtime, &ptipd->ftTime ) )
|
|
{
|
|
DWORD sc = TW32( GetLastError() );
|
|
hr = HRESULT_FROM_WIN32( sc );
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
//
|
|
// Set the task IDs.
|
|
//
|
|
|
|
CopyMemory( &ptipd->clsidMajorTaskId, &rclsidMajorTaskIDIn, sizeof( ptipd->clsidMajorTaskId ) );
|
|
CopyMemory( &ptipd->clsidMinorTaskId, &rclsidMinorTaskIDIn, sizeof( ptipd->clsidMinorTaskId ) );
|
|
|
|
//
|
|
// Set the flag describing which items this item can be a parent to.
|
|
//
|
|
|
|
ptipd->fParentToAllNodeTasks = fParentToAllNodeTasksIn;
|
|
|
|
//
|
|
// Initialize the insert structure and insert the item into the tree.
|
|
//
|
|
|
|
tvis.hParent = htiParentIn;
|
|
tvis.hInsertAfter = TVI_LAST;
|
|
tvis.itemex.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM;
|
|
tvis.itemex.cchTextMax = SysStringLen( ptipd->bstrDescription );
|
|
tvis.itemex.pszText = ptipd->bstrDescription;
|
|
tvis.itemex.iImage = tsUNKNOWN;
|
|
tvis.itemex.iSelectedImage = tsUNKNOWN;
|
|
tvis.itemex.lParam = reinterpret_cast< LPARAM >( ptipd );
|
|
|
|
hti = TreeView_InsertItem( m_hwndTV, &tvis );
|
|
Assert( hti != NULL );
|
|
|
|
ptipd = NULL;
|
|
|
|
if ( phtiOut != NULL )
|
|
{
|
|
*phtiOut = hti;
|
|
} // if:
|
|
|
|
goto Cleanup;
|
|
|
|
Cleanup:
|
|
|
|
if ( ptipd != NULL )
|
|
{
|
|
TraceSysFreeString( ptipd->bstrNodeName );
|
|
TraceSysFreeString( ptipd->bstrNodeNameWithoutDomain );
|
|
TraceSysFreeString( ptipd->bstrDescription );
|
|
delete ptipd;
|
|
} // if: ptipd != NULL
|
|
|
|
HRETURN( hr );
|
|
|
|
} //*** CTaskTreeView::HrAddTreeViewItem
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CTaskTreeView::OnNotify
|
|
//
|
|
// Description:
|
|
// Handler for the WM_NOTIFY message.
|
|
//
|
|
// Arguments:
|
|
// pnmhdrIn - Notification structure.
|
|
//
|
|
// Return Values:
|
|
// Notification-specific return code.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
LRESULT
|
|
CTaskTreeView::OnNotify(
|
|
LPNMHDR pnmhdrIn
|
|
)
|
|
{
|
|
TraceFunc( "" );
|
|
|
|
LRESULT lr = TRUE;
|
|
|
|
switch( pnmhdrIn->code )
|
|
{
|
|
case TVN_DELETEITEM:
|
|
OnNotifyDeleteItem( pnmhdrIn );
|
|
break;
|
|
|
|
case TVN_SELCHANGED:
|
|
OnNotifySelChanged( pnmhdrIn );
|
|
break;
|
|
|
|
} // switch: notify code
|
|
|
|
RETURN( lr );
|
|
|
|
} //*** CTaskTreeView::OnNotify
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CTaskTreeView::OnNotifyDeleteItem
|
|
//
|
|
// Description:
|
|
// Handler for the TVN_DELETEITEM notification message.
|
|
//
|
|
// Arguments:
|
|
// pnmhdrIn - Notification structure for the item being deleted.
|
|
//
|
|
// Return Values:
|
|
// None.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
void
|
|
CTaskTreeView::OnNotifyDeleteItem(
|
|
LPNMHDR pnmhdrIn
|
|
)
|
|
{
|
|
TraceFunc( "" );
|
|
|
|
LPNMTREEVIEW pnmtv = reinterpret_cast< LPNMTREEVIEW >( pnmhdrIn );
|
|
|
|
if ( pnmtv->itemOld.lParam != NULL )
|
|
{
|
|
STreeItemLParamData * ptipd = reinterpret_cast< STreeItemLParamData * >( pnmtv->itemOld.lParam );
|
|
TraceSysFreeString( ptipd->bstrNodeName );
|
|
TraceSysFreeString( ptipd->bstrNodeNameWithoutDomain );
|
|
TraceSysFreeString( ptipd->bstrDescription );
|
|
TraceSysFreeString( ptipd->bstrReference );
|
|
delete ptipd;
|
|
} // if: lParam != NULL
|
|
|
|
TraceFuncExit();
|
|
|
|
} //*** CTaskTreeView::OnNotifyDeleteItem
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CTaskTreeView::OnNotifySelChanged
|
|
//
|
|
// Description:
|
|
// Handler for the TVN_SELCHANGED notification message.
|
|
//
|
|
// Arguments:
|
|
// pnmhdrIn - Notification structure for the item being deleted.
|
|
//
|
|
// Return Values:
|
|
// None.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
void
|
|
CTaskTreeView::OnNotifySelChanged(
|
|
LPNMHDR pnmhdrIn
|
|
)
|
|
{
|
|
TraceFunc( "" );
|
|
|
|
LPNMTREEVIEW pnmtv = reinterpret_cast< LPNMTREEVIEW >( pnmhdrIn );
|
|
|
|
Assert( pnmtv->itemNew.mask & TVIF_HANDLE );
|
|
|
|
m_htiSelected = pnmtv->itemNew.hItem;
|
|
|
|
TraceFuncExit();
|
|
|
|
} //*** CTaskTreeView::OnNotifySelChanged
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// HRESULT
|
|
// CTaskTreeView::HrShowStatusAsDone( void )
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
CTaskTreeView::HrShowStatusAsDone( void )
|
|
{
|
|
TraceFunc( "" );
|
|
|
|
HRESULT hr = S_OK;
|
|
BSTR bstrDescription = NULL;
|
|
PBRANGE pbrange;
|
|
|
|
SendMessage( m_hwndProg, PBM_GETRANGE, FALSE, (LPARAM) &pbrange );
|
|
SendMessage( m_hwndProg, PBM_SETPOS, pbrange.iHigh, 0 );
|
|
|
|
hr = THR( HrLoadStringIntoBSTR( g_hInstance, IDS_TASKS_COMPLETED, &bstrDescription ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
SetWindowText( m_hwndStatus, L"" );
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
SetWindowText( m_hwndStatus, bstrDescription );
|
|
|
|
Cleanup:
|
|
|
|
TraceSysFreeString( bstrDescription );
|
|
|
|
HRETURN( hr );
|
|
|
|
} //*** CTaskTreeView::HrShowStatusAsDone
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// HRESULT
|
|
// CTaskTreeView::HrOnNotifySetActive( void )
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
CTaskTreeView::HrOnNotifySetActive( void )
|
|
{
|
|
TraceFunc( "" );
|
|
|
|
STreeItemLParamData * ptipdTemp;
|
|
HRESULT hr = S_OK;
|
|
size_t idx;
|
|
|
|
TreeView_DeleteAllItems( m_hwndTV );
|
|
SetWindowText( m_hwndStatus, L"" );
|
|
|
|
// Cleanup the progress array and delete any allocated entries.
|
|
for ( idx = 0; idx < m_cPASize; idx++ )
|
|
{
|
|
if ( m_ptipdProgressArray[ idx ] != NULL )
|
|
{
|
|
ptipdTemp = m_ptipdProgressArray[ idx ];
|
|
TraceSysFreeString( ptipdTemp->bstrNodeName );
|
|
delete ptipdTemp;
|
|
} // if: element != NULL
|
|
} // for: each element in the array
|
|
|
|
m_cPASize = 0;
|
|
m_cPACount = 0;
|
|
delete [] m_ptipdProgressArray;
|
|
m_ptipdProgressArray = NULL;
|
|
|
|
m_nRangeHigh = 1; // We don't have any reported tasks yet. Choose 1 to avoid any div/0 errors.
|
|
m_nCurrentPos = PROGRESSBAR_INITIAL_POSITION;
|
|
m_nRealPos = PROGRESSBAR_INITIAL_POSITION;
|
|
m_fThresholdBroken = FALSE;
|
|
|
|
SendMessage( m_hwndProg, PBM_SETRANGE, 0, MAKELPARAM( 0, PROGRESSBAR_CONTROL_TICK_COUNT ) );
|
|
SendMessage( m_hwndProg, PBM_SETPOS, m_nCurrentPos, 0 );
|
|
|
|
HRETURN( hr );
|
|
|
|
} //*** CTaskTreeView::HrOnNotifySetActive
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CTaskTreeView::HrOnSendStatusReport
|
|
//
|
|
// Description:
|
|
// Handle a status report call.
|
|
//
|
|
// Arguments:
|
|
// pcszNodeNameIn -
|
|
// clsidTaskMajorIn -
|
|
// clsidTaskMinorIn -
|
|
// nMinIn -
|
|
// nMaxIn -
|
|
// nCurrentIn -
|
|
// hrStatusIn -
|
|
// pcszDescriptionIn -
|
|
// pftTimeIn -
|
|
// pcszReferenceIn -
|
|
//
|
|
// Return Values:
|
|
// S_OK - Operation completed successfully.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
CTaskTreeView::HrOnSendStatusReport(
|
|
LPCWSTR pcszNodeNameIn
|
|
, CLSID clsidTaskMajorIn
|
|
, CLSID clsidTaskMinorIn
|
|
, ULONG nMinIn
|
|
, ULONG nMaxIn
|
|
, ULONG nCurrentIn
|
|
, HRESULT hrStatusIn
|
|
, LPCWSTR pcszDescriptionIn
|
|
, FILETIME * pftTimeIn
|
|
, LPCWSTR pcszReferenceIn
|
|
)
|
|
{
|
|
TraceFunc( "" );
|
|
Assert( pcszNodeNameIn != NULL );
|
|
|
|
HRESULT hr = S_OK;
|
|
int nImageChild;
|
|
STreeItemLParamData tipd;
|
|
HTREEITEM htiRoot;
|
|
BSTR bstrStatus = NULL;
|
|
BSTR bstrDisplayName = NULL;
|
|
LPCWSTR pcszNameToUse = pcszNodeNameIn;
|
|
|
|
ZeroMemory( &tipd, sizeof( tipd ) );
|
|
|
|
//
|
|
// If no node name was supplied then provide this machine's name so
|
|
// we have something to use as the node name key part when placing
|
|
// this tree item in the tree.
|
|
//
|
|
|
|
if ( pcszNodeNameIn == NULL )
|
|
{
|
|
pcszNodeNameIn = m_bstrClientMachineName;
|
|
} // if:
|
|
|
|
//
|
|
// If the node name is fully-qualified, use just the prefix.
|
|
//
|
|
hr = STHR( HrGetFQNDisplayName( pcszNodeNameIn, &bstrDisplayName ) );
|
|
if ( SUCCEEDED( hr ) )
|
|
{
|
|
pcszNameToUse = bstrDisplayName;
|
|
} // if:
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Update status text.
|
|
// Don't do this if it is a log-only message.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
if ( ( pcszDescriptionIn != NULL )
|
|
&& ! IsEqualIID( clsidTaskMajorIn, TASKID_Major_Client_Log )
|
|
&& ! IsEqualIID( clsidTaskMajorIn, TASKID_Major_Server_Log )
|
|
&& ! IsEqualIID( clsidTaskMajorIn, TASKID_Major_Client_And_Server_Log )
|
|
)
|
|
{
|
|
BOOL fReturn;
|
|
|
|
if ( pcszNodeNameIn != NULL )
|
|
{
|
|
hr = THR( HrFormatMessageIntoBSTR(
|
|
g_hInstance
|
|
, IDS_FORMAT_STATUS
|
|
, &bstrStatus
|
|
, pcszNameToUse
|
|
, pcszDescriptionIn
|
|
) );
|
|
//
|
|
// Handle the formatting error if there was one.
|
|
//
|
|
|
|
if ( FAILED( hr ) )
|
|
{
|
|
// TODO: Display default description instead of exiting this function
|
|
goto Error;
|
|
} // if:
|
|
} // if: node name was specified
|
|
else
|
|
{
|
|
bstrStatus = TraceSysAllocString( pcszDescriptionIn );
|
|
if ( bstrStatus == NULL )
|
|
{
|
|
hr = THR( E_OUTOFMEMORY );
|
|
goto Error;
|
|
} // if:
|
|
} // else: node name wasn't specified
|
|
|
|
Assert( bstrStatus!= NULL );
|
|
Assert( *bstrStatus!= L'\0' );
|
|
fReturn = SetWindowText( m_hwndStatus, bstrStatus );
|
|
Assert( fReturn );
|
|
} // if: description specified, not log-only
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Select the right icon.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
switch ( hrStatusIn )
|
|
{
|
|
case S_OK:
|
|
if ( nCurrentIn == nMaxIn )
|
|
{
|
|
nImageChild = tsDONE;
|
|
} // if:
|
|
else
|
|
{
|
|
nImageChild = tsPENDING;
|
|
} // else:
|
|
break;
|
|
|
|
case S_FALSE:
|
|
nImageChild = tsWARNING;
|
|
break;
|
|
|
|
case E_PENDING:
|
|
nImageChild = tsPENDING;
|
|
break;
|
|
|
|
default:
|
|
if ( FAILED( hrStatusIn ) && ( m_fDisplayErrorsAsWarnings == FALSE ) )
|
|
{
|
|
nImageChild = tsFAILED;
|
|
} // if:
|
|
else
|
|
{
|
|
nImageChild = tsWARNING;
|
|
} // else:
|
|
break;
|
|
} // switch: hrStatusIn
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Loop through each item at the top of the tree looking for an item
|
|
// whose minor ID matches this report's major ID.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
// Fill in the param data structure.
|
|
//
|
|
|
|
tipd.hr = hrStatusIn;
|
|
tipd.nMin = nMinIn;
|
|
tipd.nMax = nMaxIn;
|
|
tipd.nCurrent = nCurrentIn;
|
|
|
|
CopyMemory( &tipd.clsidMajorTaskId, &clsidTaskMajorIn, sizeof( tipd.clsidMajorTaskId ) );
|
|
CopyMemory( &tipd.clsidMinorTaskId, &clsidTaskMinorIn, sizeof( tipd.clsidMinorTaskId ) );
|
|
CopyMemory( &tipd.ftTime, pftTimeIn, sizeof( tipd.ftTime ) );
|
|
|
|
// tipd.bstrDescription is set above.
|
|
tipd.bstrNodeName = TraceSysAllocString( pcszNodeNameIn );
|
|
if ( tipd.bstrNodeName == NULL )
|
|
{
|
|
hr = THR( E_OUTOFMEMORY );
|
|
goto Error;
|
|
} // if:
|
|
tipd.bstrNodeNameWithoutDomain = bstrDisplayName;
|
|
bstrDisplayName = NULL; // tipd now owns this string.
|
|
|
|
if ( pcszDescriptionIn == NULL )
|
|
{
|
|
tipd.bstrDescription = NULL;
|
|
} // if:
|
|
else
|
|
{
|
|
tipd.bstrDescription = TraceSysAllocString( pcszDescriptionIn );
|
|
if ( tipd.bstrDescription == NULL )
|
|
{
|
|
hr = THR( E_OUTOFMEMORY );
|
|
goto Error;
|
|
} // if:
|
|
} // else: pcszDescritionIn != NULL
|
|
if ( pcszReferenceIn == NULL )
|
|
{
|
|
tipd.bstrReference = NULL;
|
|
} // if:
|
|
else
|
|
{
|
|
tipd.bstrReference = TraceSysAllocString( pcszReferenceIn );
|
|
if ( tipd.bstrReference == NULL )
|
|
{
|
|
hr = THR( E_OUTOFMEMORY );
|
|
goto Error;
|
|
} // if:
|
|
} // else: pcszReferenceIn != NULL
|
|
|
|
if ( IsEqualIID( tipd.clsidMajorTaskId, TASKID_Major_Update_Progress ) )
|
|
{
|
|
// It's an update_progress task so just call HrProcessUpdateProgressTask.
|
|
hr = STHR( HrProcessUpdateProgressTask( &tipd ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Error;
|
|
} // if:
|
|
} // if: major == update_progress
|
|
else
|
|
{
|
|
// Start with the first item in the tree view.
|
|
htiRoot = TreeView_GetRoot( m_hwndTV );
|
|
if ( htiRoot == NULL )
|
|
{
|
|
TW32( ERROR_NOT_FOUND );
|
|
// Don't return an error result since doing so will prevent the report
|
|
// from being propagated to other subscribers.
|
|
hr = S_OK;
|
|
goto Cleanup;
|
|
} // if: htiRoot is NULL
|
|
|
|
// Insert the status report into the tree view.
|
|
hr = STHR( HrInsertTaskIntoTree( htiRoot, &tipd, nImageChild, bstrStatus ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
LogMsg( "[WIZ] Error inserting status report into the tree control. hr=%.08x, %ws", tipd.hr, pcszDescriptionIn );
|
|
goto Error;
|
|
} // if:
|
|
} // else: not an update_progress task
|
|
|
|
if ( hr == S_FALSE )
|
|
{
|
|
// Don't return S_FALSE to the caller since it won't mean anything there.
|
|
hr = S_OK;
|
|
// TODO: Should this be written to the log?
|
|
|
|
#if defined( DEBUG )
|
|
//
|
|
// Check to make sure that if the major task ID wasn't recognized
|
|
// that it is one of the known exceptions.
|
|
//
|
|
|
|
if ( ! IsEqualIID( clsidTaskMajorIn, TASKID_Major_Client_Log )
|
|
&& ! IsEqualIID( clsidTaskMajorIn, TASKID_Major_Server_Log )
|
|
&& ! IsEqualIID( clsidTaskMajorIn, TASKID_Major_Client_And_Server_Log ) )
|
|
{
|
|
BSTR bstrMsg = NULL;
|
|
|
|
THR( HrFormatStringIntoBSTR(
|
|
g_hInstance
|
|
, IDS_UNKNOWN_TASK
|
|
, &bstrMsg
|
|
, clsidTaskMajorIn.Data1 // 1
|
|
, clsidTaskMajorIn.Data2 // 2
|
|
, clsidTaskMajorIn.Data3 // 3
|
|
, clsidTaskMajorIn.Data4[ 0 ] // 4
|
|
, clsidTaskMajorIn.Data4[ 1 ] // 5
|
|
, clsidTaskMajorIn.Data4[ 2 ] // 6
|
|
, clsidTaskMajorIn.Data4[ 3 ] // 7
|
|
, clsidTaskMajorIn.Data4[ 4 ] // 8
|
|
, clsidTaskMajorIn.Data4[ 5 ] // 9
|
|
, clsidTaskMajorIn.Data4[ 6 ] // 10
|
|
, clsidTaskMajorIn.Data4[ 7 ] // 11
|
|
) );
|
|
AssertString( 0, bstrMsg );
|
|
|
|
TraceSysFreeString( bstrMsg );
|
|
} // if: log only
|
|
#endif // DEBUG
|
|
} // if: S_FALSE returned from HrInsertTaskIntoTree
|
|
|
|
goto Cleanup;
|
|
|
|
Error:
|
|
// Don't return an error result since doing so will prevent the report
|
|
// from being propagated to other subscribers.
|
|
hr = S_OK;
|
|
goto Cleanup;
|
|
|
|
Cleanup:
|
|
|
|
TraceSysFreeString( bstrDisplayName );
|
|
TraceSysFreeString( bstrStatus );
|
|
TraceSysFreeString( tipd.bstrNodeName );
|
|
TraceSysFreeString( tipd.bstrNodeNameWithoutDomain );
|
|
TraceSysFreeString( tipd.bstrDescription );
|
|
TraceSysFreeString( tipd.bstrReference );
|
|
|
|
HRETURN( hr );
|
|
|
|
} //*** CTaskTreeView::HrOnSendStatusReport
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CTaskTreeView::HrInsertTaskIntoTree
|
|
//
|
|
// Description:
|
|
// Insert the specified task into the tree based on the node, major
|
|
// task, and minor task.
|
|
//
|
|
// Arguments:
|
|
// htiFirstIn - First tree item to examine.
|
|
// ptipdIn - Tree item parameter data for the task to be inserted.
|
|
// nImageIn - Image identifier for the child item.
|
|
// bstrDescriptionIn - Description string to display.
|
|
//
|
|
// Return Values:
|
|
// S_OK - Task inserted successfully.
|
|
// S_FALSE - Task not inserted.
|
|
// hr - The operation failed.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
CTaskTreeView::HrInsertTaskIntoTree(
|
|
HTREEITEM htiFirstIn
|
|
, STreeItemLParamData * ptipdIn
|
|
, int nImageIn
|
|
, BSTR bstrDescriptionIn
|
|
)
|
|
{
|
|
TraceFunc( "" );
|
|
|
|
Assert( htiFirstIn != NULL );
|
|
Assert( ptipdIn != NULL );
|
|
|
|
//
|
|
// LOCAL VARIABLES
|
|
//
|
|
|
|
HRESULT hr;
|
|
HTREEITEM htiParent;
|
|
HTREEITEM htiChild = NULL;
|
|
TVITEMEX tviParent;
|
|
TVITEMEX tviChild;
|
|
BOOL fReturn;
|
|
BOOL fSameNode;
|
|
STreeItemLParamData * ptipdParent = NULL;
|
|
STreeItemLParamData * ptipdChild = NULL;
|
|
|
|
//
|
|
// Loop through each item to determine if the task should be added below
|
|
// that item. If not, attempt to traverse its children.
|
|
//
|
|
|
|
for ( htiParent = htiFirstIn, hr = S_FALSE
|
|
; ( htiParent != NULL ) && ( hr == S_FALSE )
|
|
; )
|
|
{
|
|
//
|
|
// Get the information about this item in the tree.
|
|
//
|
|
|
|
tviParent.mask = TVIF_PARAM | TVIF_IMAGE;
|
|
tviParent.hItem = htiParent;
|
|
|
|
fReturn = TreeView_GetItem( m_hwndTV, &tviParent );
|
|
if ( fReturn == FALSE )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( TW32( ERROR_NOT_FOUND ) );
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
ptipdParent = reinterpret_cast< STreeItemLParamData * >( tviParent.lParam );
|
|
Assert( ptipdParent != NULL );
|
|
|
|
//
|
|
// Determine if either the parent can be a parent to tasks from any
|
|
// node or, if not, the parent and input tasks are from the same node.
|
|
//
|
|
|
|
if ( ptipdParent->fParentToAllNodeTasks == TRUE )
|
|
{
|
|
fSameNode = TRUE;
|
|
} // if: parent task can host tasks from any node
|
|
else
|
|
{
|
|
fSameNode = ( NBSTRCompareNoCase( ptipdIn->bstrNodeNameWithoutDomain, ptipdParent->bstrNodeNameWithoutDomain ) == 0 );
|
|
} // else: parent task's node must match input task's node
|
|
|
|
//
|
|
// Reset hr to S_FALSE because it is the return value when a tree item is
|
|
// to be added to the tree because it was not found.
|
|
//
|
|
|
|
hr = S_FALSE;
|
|
|
|
//
|
|
// See if this item could be the parent.
|
|
// If not, recurse through child items.
|
|
//
|
|
|
|
if ( IsEqualIID( ptipdIn->clsidMajorTaskId, ptipdParent->clsidMinorTaskId )
|
|
&& ( fSameNode == TRUE )
|
|
)
|
|
{
|
|
//
|
|
// FOUND THE PARENT ITEM
|
|
//
|
|
|
|
BOOL fMinorTaskIdMatches;
|
|
BOOL fBothNodeNamesPresent;
|
|
BOOL fBothNodeNamesEmpty;
|
|
BOOL fNodeNamesEqual;
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
//
|
|
// Loop through the child items looking for an item with
|
|
// the same minor ID.
|
|
//
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
htiChild = TreeView_GetChild( m_hwndTV, htiParent );
|
|
while ( htiChild != NULL )
|
|
{
|
|
//
|
|
// Get the child item details.
|
|
//
|
|
|
|
tviChild.mask = TVIF_PARAM | TVIF_IMAGE;
|
|
tviChild.hItem = htiChild;
|
|
|
|
fReturn = TreeView_GetItem( m_hwndTV, &tviChild );
|
|
if ( fReturn == FALSE )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( TW32( ERROR_NOT_FOUND ) );
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
ptipdChild = reinterpret_cast< STreeItemLParamData * >( tviChild.lParam );
|
|
Assert( ptipdChild != NULL );
|
|
|
|
//
|
|
// Does this child item match the minor ID and node name?
|
|
//
|
|
|
|
fMinorTaskIdMatches = IsEqualIID( ptipdIn->clsidMinorTaskId, ptipdChild->clsidMinorTaskId );
|
|
fBothNodeNamesPresent = ( ptipdIn->bstrNodeNameWithoutDomain != NULL ) && ( ptipdChild->bstrNodeNameWithoutDomain != NULL );
|
|
fBothNodeNamesEmpty = ( ptipdIn->bstrNodeNameWithoutDomain == NULL ) && ( ptipdChild->bstrNodeNameWithoutDomain == NULL );
|
|
|
|
if ( fBothNodeNamesPresent == TRUE )
|
|
{
|
|
fNodeNamesEqual = ( NBSTRCompareNoCase( ptipdIn->bstrNodeNameWithoutDomain, ptipdChild->bstrNodeNameWithoutDomain ) == 0 );
|
|
} // if:
|
|
else if ( fBothNodeNamesEmpty == TRUE )
|
|
{
|
|
fNodeNamesEqual = TRUE;
|
|
} // else if:
|
|
else
|
|
{
|
|
fNodeNamesEqual = FALSE;
|
|
} // else:
|
|
|
|
if ( ( fMinorTaskIdMatches == TRUE ) && ( fNodeNamesEqual == TRUE ) )
|
|
{
|
|
//
|
|
// CHILD ITEM MATCHES.
|
|
// Update the child item.
|
|
//
|
|
|
|
//
|
|
// Update the progress bar.
|
|
//
|
|
|
|
STHR( HrUpdateProgressBar( ptipdIn, ptipdChild ) );
|
|
// ignore failure.
|
|
|
|
//
|
|
// Copy data from the report.
|
|
// This must be done after the call to
|
|
// HrUpdateProgressBar so that the previous values
|
|
// can be compared to the new values.
|
|
//
|
|
|
|
ptipdChild->nMin = ptipdIn->nMin;
|
|
ptipdChild->nMax = ptipdIn->nMax;
|
|
ptipdChild->nCurrent = ptipdIn->nCurrent;
|
|
CopyMemory( &ptipdChild->ftTime, &ptipdIn->ftTime, sizeof( ptipdChild->ftTime ) );
|
|
|
|
// Update the error code if needed.
|
|
if ( ptipdChild->hr == S_OK )
|
|
{
|
|
ptipdChild->hr = ptipdIn->hr;
|
|
} // if:
|
|
|
|
//
|
|
// If the new state is worse than the last state,
|
|
// update the state of the item.
|
|
//
|
|
|
|
if ( tviChild.iImage < nImageIn )
|
|
{
|
|
tviChild.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE;
|
|
tviChild.iImage = nImageIn;
|
|
tviChild.iSelectedImage = nImageIn;
|
|
TreeView_SetItem( m_hwndTV, &tviChild );
|
|
} // if: new state is worse than the last state
|
|
|
|
//
|
|
// Update the text of the child item if needed.
|
|
//
|
|
|
|
if ( ( ptipdIn->bstrDescription != NULL )
|
|
&& ( ( ptipdChild->bstrDescription == NULL )
|
|
|| ( NBSTRCompareCase( ptipdIn->bstrDescription, ptipdChild->bstrDescription ) != 0 )
|
|
)
|
|
)
|
|
{
|
|
fReturn = TraceSysReAllocString( &ptipdChild->bstrDescription, ptipdIn->bstrDescription );
|
|
if ( fReturn == FALSE )
|
|
{
|
|
hr = THR( E_OUTOFMEMORY );
|
|
goto Cleanup;
|
|
} // if:
|
|
tviChild.mask = TVIF_TEXT;
|
|
tviChild.pszText = bstrDescriptionIn;
|
|
tviChild.cchTextMax = (int) wcslen( tviChild.pszText );
|
|
TreeView_SetItem( m_hwndTV, &tviChild );
|
|
} // if: description was specified and is different
|
|
|
|
//
|
|
// Copy the reference if it is different.
|
|
//
|
|
|
|
if ( ( ptipdIn->bstrReference != NULL )
|
|
&& ( ( ptipdChild->bstrReference == NULL )
|
|
|| ( NBSTRCompareCase( ptipdChild->bstrReference, ptipdIn->bstrReference ) != 0 )
|
|
)
|
|
)
|
|
{
|
|
fReturn = TraceSysReAllocString( &ptipdChild->bstrReference, ptipdIn->bstrReference );
|
|
if ( fReturn == FALSE )
|
|
{
|
|
hr = THR( E_OUTOFMEMORY );
|
|
goto Cleanup;
|
|
} // if:
|
|
} // if: reference is different
|
|
|
|
break; // exit loop
|
|
|
|
} // if: found a matching child item
|
|
|
|
//
|
|
// Get the next item.
|
|
//
|
|
|
|
htiChild = TreeView_GetNextSibling( m_hwndTV, htiChild );
|
|
|
|
} // while: more child items
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
//
|
|
// If the tree item was not found and the description was
|
|
// specified, then we need to create the child item.
|
|
//
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
if ( ( htiChild == NULL )
|
|
&& ( ptipdIn->bstrDescription != NULL )
|
|
)
|
|
{
|
|
//
|
|
// ITEM NOT FOUND AND DESCRIPTION WAS SPECIFIED
|
|
//
|
|
// Insert a new item in the tree under the major's task.
|
|
//
|
|
|
|
TVINSERTSTRUCT tvis;
|
|
|
|
// Create the item.
|
|
hr = THR( HrCreateTreeItem(
|
|
&tvis
|
|
, ptipdIn
|
|
, htiParent
|
|
, nImageIn
|
|
, bstrDescriptionIn
|
|
) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
// Insert the item in the tree.
|
|
htiChild = TreeView_InsertItem( m_hwndTV, &tvis );
|
|
Assert( htiChild != NULL );
|
|
|
|
//
|
|
// Update the progress bar.
|
|
//
|
|
|
|
ptipdChild = reinterpret_cast< STreeItemLParamData * >( tvis.itemex.lParam );
|
|
Assert( ptipdChild != NULL );
|
|
STHR( HrUpdateProgressBar( ptipdIn, ptipdChild ) );
|
|
// ignore failure.
|
|
|
|
} // if: need to add new child
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
//
|
|
// If the child item was created and the child has an error
|
|
// condition, then create a child of the child item
|
|
// indicating the error code and system string.
|
|
//
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
if ( ( ptipdChild != NULL )
|
|
&& ( FAILED( ptipdIn->hr )
|
|
|| ( ( ptipdIn->hr != S_OK )
|
|
&& ( ptipdIn->hr != S_FALSE )
|
|
)
|
|
)
|
|
)
|
|
{
|
|
//
|
|
// CHILD ITEM FOUND OR CREATED FOR ERROR REPORT
|
|
// CREATE ERROR ITEM IN THE TREE
|
|
//
|
|
|
|
BSTR bstrError = NULL;
|
|
BSTR bstrErrorDescription = NULL;
|
|
HRESULT hrFormat;
|
|
TVINSERTSTRUCT tvis;
|
|
HTREEITEM htiChildStatus;
|
|
DWORD dwSeverity;
|
|
HRESULT hrNewStatus = S_OK;
|
|
|
|
dwSeverity = SCODE_SEVERITY( ptipdIn->hr );
|
|
|
|
THR( HrFormatErrorIntoBSTR( ptipdIn->hr, &bstrError, &hrNewStatus ) );
|
|
|
|
//
|
|
// If we got an updated status code then we need to choose
|
|
// a new format string that shows both the old and the new
|
|
// status codes.
|
|
//
|
|
|
|
if ( hrNewStatus != ptipdIn->hr )
|
|
{
|
|
Assert( bstrError != NULL );
|
|
|
|
hrFormat = THR( HrFormatMessageIntoBSTR(
|
|
g_hInstance
|
|
, dwSeverity == 0 ? IDS_TASK_RETURNED_NEW_STATUS : IDS_TASK_RETURNED_NEW_ERROR
|
|
, &bstrErrorDescription
|
|
, ptipdIn->hr
|
|
, hrNewStatus
|
|
, bstrError
|
|
) );
|
|
} // if:
|
|
else
|
|
{
|
|
hrFormat = THR( HrFormatMessageIntoBSTR(
|
|
g_hInstance
|
|
, dwSeverity == 0 ? IDS_TASK_RETURNED_STATUS : IDS_TASK_RETURNED_ERROR
|
|
, &bstrErrorDescription
|
|
, ptipdIn->hr
|
|
, ( bstrError == NULL ? L"" : bstrError )
|
|
) );
|
|
} // else:
|
|
|
|
if ( SUCCEEDED( hrFormat ) )
|
|
{
|
|
//
|
|
// Insert a new item in the tree under the minor's
|
|
// task explaining the ptipdIn->hr.
|
|
//
|
|
|
|
// Create the item.
|
|
hr = THR( HrCreateTreeItem(
|
|
&tvis
|
|
, ptipdIn
|
|
, htiChild
|
|
, nImageIn
|
|
, bstrErrorDescription
|
|
) );
|
|
if ( SUCCEEDED( hr ) )
|
|
{
|
|
//
|
|
// Failures are handled below to make sure we free
|
|
// all the strings allocated by this section of
|
|
// the code.
|
|
//
|
|
|
|
// Insert the item.
|
|
htiChildStatus = TreeView_InsertItem( m_hwndTV, &tvis );
|
|
Assert( htiChildStatus != NULL );
|
|
} // if: tree item created successfully
|
|
|
|
TraceSysFreeString( bstrErrorDescription );
|
|
|
|
} // if: message formatted successfully
|
|
|
|
TraceSysFreeString( bstrError );
|
|
|
|
//
|
|
// This error handling is for the return value from
|
|
// HrCreateTreeItem above. It is here so that all the strings
|
|
// can be cleaned up without having to resort to hokey
|
|
// boolean variables or move the bstrs to a more global scope.
|
|
//
|
|
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
} // if: child and error
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
//
|
|
// If a child was found or created, propagate its state to
|
|
// the parent items.
|
|
//
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
if ( htiChild != NULL )
|
|
{
|
|
hr = STHR( HrPropagateChildStateToParents(
|
|
htiChild
|
|
, nImageIn
|
|
, FALSE // fOnlyUpdateProgressIn
|
|
) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
goto Cleanup;
|
|
} // if:
|
|
} // if: found or created a child
|
|
|
|
//
|
|
// Return success since we found the parent for this report.
|
|
//
|
|
|
|
hr = S_OK;
|
|
break;
|
|
|
|
} // if: found an item to be the parent
|
|
else
|
|
{
|
|
//
|
|
// PARENT ITEM NOT FOUND
|
|
//
|
|
// Recurse through all the child items.
|
|
//
|
|
|
|
htiChild = TreeView_GetChild( m_hwndTV, htiParent );
|
|
while ( htiChild != NULL )
|
|
{
|
|
hr = STHR( HrInsertTaskIntoTree( htiChild, ptipdIn, nImageIn, bstrDescriptionIn ) );
|
|
if ( hr == S_OK )
|
|
{
|
|
// Found a match, so exit the loop.
|
|
break;
|
|
} // if:
|
|
|
|
htiChild = TreeView_GetNextSibling( m_hwndTV, htiChild );
|
|
} // while: more child items
|
|
} // else: item not the parent
|
|
|
|
//
|
|
// Get the next sibling of the parent.
|
|
//
|
|
|
|
htiParent = TreeView_GetNextSibling( m_hwndTV, htiParent );
|
|
|
|
} // for: each item at this level in the tree
|
|
|
|
Cleanup:
|
|
|
|
RETURN( hr );
|
|
|
|
} //*** CTaskTreeView::HrInsertTaskIntoTree
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CTaskTreeView::HrProcessUpdateProgressTask
|
|
//
|
|
// Description:
|
|
// Update the progress bar based on new tree item data.
|
|
//
|
|
// Arguments:
|
|
// ptipdNewIn - New values of the tree item data.
|
|
//
|
|
// Return Values:
|
|
// S_OK - Operation completed successfully.
|
|
// E_OUTOFMEMORY - Failure allocating memory
|
|
// Other HRESULTs
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
CTaskTreeView::HrProcessUpdateProgressTask(
|
|
const STreeItemLParamData * ptipdIn
|
|
)
|
|
{
|
|
TraceFunc( "" );
|
|
|
|
HRESULT hr = S_OK;
|
|
STreeItemLParamData * ptipdPrev = NULL;
|
|
size_t idx;
|
|
size_t cPassed;
|
|
size_t idxPrev = 0;
|
|
BOOL fNewTask = FALSE; // Are ptipdPrev && ptipdIn the same task?
|
|
|
|
Assert( ptipdIn != NULL );
|
|
Assert( IsEqualIID( ptipdIn->clsidMajorTaskId, TASKID_Major_Update_Progress ) );
|
|
|
|
//
|
|
// Is this a one-off event? min == max == current
|
|
//
|
|
if ( ( ptipdIn->nMin == ptipdIn->nMax ) && ( ptipdIn->nMax == ptipdIn->nCurrent ) )
|
|
{
|
|
// Yes - don't bother mucking with the array.
|
|
STHR( HrUpdateProgressBar( ptipdIn, ptipdIn ) );
|
|
hr = S_OK;
|
|
goto Cleanup;
|
|
} // if: one-off event
|
|
|
|
//
|
|
// Check to see if this task is in the array.
|
|
//
|
|
for ( idx = 0, cPassed = 0;
|
|
( idx < m_cPASize ) && ( cPassed < m_cPACount );
|
|
idx++ )
|
|
{
|
|
if ( m_ptipdProgressArray[ idx ] != NULL )
|
|
{
|
|
// Check the minors and make sure this is the same node.
|
|
if ( IsEqualIID( m_ptipdProgressArray[ idx ]->clsidMinorTaskId, ptipdIn->clsidMinorTaskId )
|
|
&& ( NBSTRCompareNoCase( m_ptipdProgressArray[ idx ]->bstrNodeName, ptipdIn->bstrNodeName ) == 0 ) )
|
|
{
|
|
ptipdPrev = m_ptipdProgressArray[ idx ];
|
|
idxPrev = idx;
|
|
break;
|
|
} // if:
|
|
|
|
// If the array is X elements long and we have Y elements, stop after looking at Y elements.
|
|
cPassed++;
|
|
} // if: current slot is null
|
|
} // for: each item in the array until we find a match
|
|
|
|
if ( ptipdPrev == NULL )
|
|
{
|
|
//
|
|
// We didn't find it in the list - we'll have to insert it.
|
|
//
|
|
if ( m_ptipdProgressArray == NULL )
|
|
{
|
|
Assert( m_cPACount == 0 );
|
|
//
|
|
// We have to allocate the array.
|
|
//
|
|
m_cPASize = 10; // Pick a reasonable initial array size.
|
|
m_ptipdProgressArray = new PSTreeItemLParamData[ m_cPASize ];
|
|
if ( m_ptipdProgressArray == NULL )
|
|
{
|
|
hr = THR( E_OUTOFMEMORY );
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
ZeroMemory( m_ptipdProgressArray, m_cPASize * sizeof( m_ptipdProgressArray[ 0 ] ) );
|
|
|
|
// We just allocated the array so we know the first slot is open.
|
|
idx = 0;
|
|
} // if: we need to allocate the array
|
|
else if ( m_cPACount == m_cPASize )
|
|
{
|
|
STreeItemLParamData ** ptipdTempArray = NULL;
|
|
|
|
Assert( m_cPASize != 0 );
|
|
|
|
//
|
|
// We need to increase the size of the array.
|
|
//
|
|
ptipdTempArray = new STreeItemLParamData* [ m_cPASize * 2 ];
|
|
if ( ptipdTempArray == NULL )
|
|
{
|
|
hr = THR( E_OUTOFMEMORY );
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
// Copy the old array over the first half of the new array.
|
|
CopyMemory( ptipdTempArray, m_ptipdProgressArray, m_cPASize * sizeof( m_ptipdProgressArray[ 0 ] ) );
|
|
|
|
// Zero out the second half of the new array.
|
|
ZeroMemory( &ptipdTempArray[ m_cPASize ], m_cPASize * sizeof( ptipdTempArray[ 0 ] ) );
|
|
|
|
//
|
|
// Update member variables to reflect the changes.
|
|
//
|
|
|
|
m_cPASize *= 2; // We doubled the array length.
|
|
|
|
delete [] m_ptipdProgressArray;
|
|
m_ptipdProgressArray = ptipdTempArray;
|
|
ptipdTempArray = NULL;
|
|
|
|
// We know the first open slot is at index m_cPACount.
|
|
idx = m_cPACount;
|
|
} // else: we've used all available slots
|
|
else
|
|
{
|
|
// Else we have a spot open somewhere in the existing array. Start searching from 0.
|
|
idx = 0;
|
|
} // else: there's an available slot
|
|
|
|
//
|
|
// Find an empty slot and allocate a new task to put in it.
|
|
//
|
|
for ( ; idx < m_cPASize; idx++ )
|
|
{
|
|
if ( m_ptipdProgressArray[ idx ] == NULL )
|
|
{
|
|
//
|
|
// Found an empty slot - allocate the new task.
|
|
//
|
|
ptipdPrev = new STreeItemLParamData;
|
|
if ( ptipdPrev == NULL )
|
|
{
|
|
hr = THR( E_OUTOFMEMORY );
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
ptipdPrev->bstrNodeName = TraceSysAllocString( ptipdIn->bstrNodeName );
|
|
if ( ( ptipdIn->bstrNodeName != NULL ) && ( ptipdPrev->bstrNodeName == NULL ) )
|
|
{
|
|
hr = THR( E_OUTOFMEMORY );
|
|
delete ptipdPrev;
|
|
ptipdPrev = NULL;
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
CopyMemory( &ptipdPrev->clsidMajorTaskId, &ptipdIn->clsidMajorTaskId, sizeof( ptipdIn->clsidMajorTaskId ) );
|
|
CopyMemory( &ptipdPrev->clsidMinorTaskId, &ptipdIn->clsidMinorTaskId, sizeof( ptipdIn->clsidMinorTaskId ) );
|
|
ptipdPrev->nMin = ptipdIn->nMin;
|
|
ptipdPrev->nMax = ptipdIn->nMax;
|
|
ptipdPrev->nCurrent = ptipdIn->nCurrent;
|
|
ptipdPrev->fParentToAllNodeTasks = ptipdIn->fParentToAllNodeTasks;
|
|
|
|
m_ptipdProgressArray[ idx ] = ptipdPrev;
|
|
m_cPACount++;
|
|
fNewTask = TRUE;
|
|
idxPrev = idx;
|
|
break;
|
|
} // if:
|
|
} // for: find an emtpy slot
|
|
} // if: couldn't find a matching task in the array
|
|
|
|
Assert( ptipdPrev != NULL );
|
|
Assert( ptipdIn->bstrReference == NULL );
|
|
Assert( ptipdIn->nMin < ptipdIn->nMax );
|
|
Assert( ptipdIn->nMin <= ptipdIn->nCurrent );
|
|
Assert( ptipdIn->nCurrent <= ptipdIn->nMax );
|
|
|
|
//
|
|
// Update the progress bar.
|
|
//
|
|
STHR( HrUpdateProgressBar( ptipdIn, ptipdPrev ) ); // Ignore failure.
|
|
|
|
//
|
|
// If the task has completed, remove it from the array.
|
|
//
|
|
if ( ptipdIn->nMax == ptipdIn->nCurrent )
|
|
{
|
|
TraceSysFreeString( ptipdPrev->bstrNodeName );
|
|
delete ptipdPrev;
|
|
m_ptipdProgressArray[ idxPrev ] = NULL;
|
|
m_cPACount--;
|
|
} // if: task complete
|
|
else if ( fNewTask == FALSE )
|
|
{
|
|
//
|
|
// Else, update ptipdPrev only if we didn't just copy the array.
|
|
//
|
|
|
|
// This could have been a range-changing event, so copy the min, max, current.
|
|
ptipdPrev->nMin = ptipdIn->nMin;
|
|
ptipdPrev->nMax = ptipdIn->nMax;
|
|
ptipdPrev->nCurrent = ptipdIn->nCurrent;
|
|
} // else if: not a new task
|
|
|
|
Cleanup:
|
|
|
|
RETURN( hr );
|
|
|
|
} //*** CTaskTreeView::HrProcessUpdateProgressTask
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CTaskTreeView::HrUpdateProgressBar
|
|
//
|
|
// Description:
|
|
// Update the progress bar based on new tree item data.
|
|
//
|
|
// Arguments:
|
|
// ptipdNewIn - New values of the tree item data.
|
|
// ptipdPrevIn - Previous values of the tree item data.
|
|
//
|
|
// Return Values:
|
|
// S_OK - Operation completed successfully.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
CTaskTreeView::HrUpdateProgressBar(
|
|
const STreeItemLParamData * ptipdNewIn
|
|
, const STreeItemLParamData * ptipdPrevIn
|
|
)
|
|
{
|
|
TraceFunc( "" );
|
|
|
|
HRESULT hr = S_OK;
|
|
ULONG nRealPos = 0;
|
|
ULONG nShrink = 0;
|
|
ULONG nExpand = 0;
|
|
ULONG nProgress = 0;
|
|
|
|
//
|
|
// Verify parameters.
|
|
//
|
|
Assert( m_hwndProg != NULL );
|
|
Assert( ptipdNewIn != NULL );
|
|
Assert( ptipdPrevIn != NULL );
|
|
Assert( (ptipdPrevIn->nCurrent <= ptipdPrevIn->nMax) && (ptipdNewIn->nCurrent <= ptipdNewIn->nMax) );
|
|
Assert( (ptipdPrevIn->nCurrent >= ptipdPrevIn->nMin) && (ptipdNewIn->nCurrent >= ptipdNewIn->nMin) );
|
|
|
|
//
|
|
// Make sure we're only passed a task update that we can analyze.
|
|
//
|
|
Assert( IsEqualIID( ptipdPrevIn->clsidMajorTaskId, IID_NULL ) == FALSE );
|
|
Assert( IsEqualIID( ptipdPrevIn->clsidMajorTaskId, ptipdNewIn->clsidMajorTaskId ) == TRUE ) // Majors match
|
|
Assert( IsEqualIID( ptipdPrevIn->clsidMinorTaskId, ptipdNewIn->clsidMinorTaskId ) == TRUE ) // && Minors match
|
|
|
|
if ( IsEqualIID( ptipdPrevIn->clsidMajorTaskId, ptipdNewIn->clsidMajorTaskId ) == FALSE // Majors don't match
|
|
|| IsEqualIID( ptipdPrevIn->clsidMinorTaskId, ptipdNewIn->clsidMinorTaskId ) == FALSE ) // or Minors don't match
|
|
{
|
|
// This update is meaningless because we don't know how to compare the two IN params.
|
|
WCHAR szNewMajor[ 64 ];
|
|
WCHAR szNewMinor[ 64 ];
|
|
WCHAR szPrevMajor[ 64 ];
|
|
WCHAR szPrevMinor[ 64 ];
|
|
int cch;
|
|
|
|
cch = StringFromGUID2( ptipdNewIn->clsidMajorTaskId, szNewMajor, RTL_NUMBER_OF( szNewMajor ) );
|
|
Assert( cch > 0 ); // 64 chars should always hold a guid!
|
|
|
|
cch = StringFromGUID2( ptipdNewIn->clsidMinorTaskId, szNewMinor, RTL_NUMBER_OF( szNewMinor ) );
|
|
Assert( cch > 0 ); // 64 chars should always hold a guid!
|
|
|
|
cch = StringFromGUID2( ptipdPrevIn->clsidMajorTaskId, szPrevMajor, RTL_NUMBER_OF( szPrevMajor ) );
|
|
Assert( cch > 0 ); // 64 chars should always hold a guid!
|
|
|
|
cch = StringFromGUID2( ptipdPrevIn->clsidMinorTaskId, szPrevMinor, RTL_NUMBER_OF( szPrevMinor ) );
|
|
Assert( cch > 0 ); // 64 chars should always hold a guid!
|
|
|
|
LogMsg(
|
|
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"
|
|
, szNewMajor
|
|
, szNewMinor
|
|
, szPrevMajor
|
|
, szPrevMinor
|
|
);
|
|
hr = THR( S_FALSE );
|
|
goto Cleanup;
|
|
} // if: the two tipd's don't match
|
|
|
|
if ( ( ptipdNewIn->nMin == ptipdNewIn->nMax ) && ( ptipdNewIn->nCurrent == ptipdNewIn->nMax ) )
|
|
{
|
|
// This is a one-off: min == max && current == max.
|
|
nExpand = ptipdNewIn->nCurrent;
|
|
nProgress = ptipdNewIn->nCurrent;
|
|
} // else: this is a one-off
|
|
else if ( ( ptipdNewIn->nMax != ptipdPrevIn->nMax ) || ( ptipdNewIn->nMin != ptipdPrevIn->nMin ) )
|
|
{
|
|
//
|
|
// The min's and/or maxes changed. Verify that it follows the rules.
|
|
//
|
|
// Rules:
|
|
// Max: If the max changes then min and current need to stay the same.
|
|
// Resizing max can not cause the current to exceed max.
|
|
//
|
|
// Min: If the min changes then max can't change and the difference
|
|
// between current and min has to remain the same.
|
|
//
|
|
// In no case should a resizing cause min == max == current - this
|
|
// will be treated as a one-off event and may orphan a task in the
|
|
// update progress array.
|
|
//
|
|
if ( ptipdNewIn->nMax != ptipdPrevIn->nMax ) // Maxes changed
|
|
{
|
|
if ( ( ptipdNewIn->nCurrent != ptipdPrevIn->nCurrent ) // Currents changed
|
|
|| ( ptipdNewIn->nMin != ptipdPrevIn->nMin ) // or Mins changed
|
|
|| ( ptipdNewIn->nCurrent > ptipdNewIn->nMax ) ) // or current exceeded the max
|
|
{
|
|
LogMsg(
|
|
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"
|
|
, ptipdNewIn->nMin
|
|
, ptipdPrevIn->nMin
|
|
, ptipdNewIn->nMax
|
|
, ptipdPrevIn->nMax
|
|
, ptipdNewIn->nCurrent
|
|
, ptipdPrevIn->nCurrent
|
|
);
|
|
hr = THR( S_FALSE );
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
//
|
|
// The max changed, meaning we'll need to modify the range by that much.
|
|
//
|
|
if ( ptipdNewIn->nMax > ptipdPrevIn->nMax )
|
|
{
|
|
nExpand = ptipdNewIn->nMax - ptipdPrevIn->nMax;
|
|
} // if:
|
|
else
|
|
{
|
|
nShrink = ptipdPrevIn->nMax - ptipdNewIn->nMax;
|
|
} // else:
|
|
} // if: maxes differ
|
|
else // Mins changed
|
|
{
|
|
// If the difference between min & current varies between the two, or if the new current > new max then fail.
|
|
if ( ( ptipdNewIn->nCurrent - ptipdNewIn->nMin ) != ( ptipdPrevIn->nCurrent - ptipdPrevIn->nMin )
|
|
|| ( ptipdNewIn->nCurrent > ptipdNewIn->nMax ) )
|
|
{
|
|
LogMsg(
|
|
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"
|
|
, ( ptipdNewIn->nCurrent - ptipdNewIn->nMin )
|
|
, ( ptipdPrevIn->nCurrent - ptipdPrevIn->nMin )
|
|
, ptipdNewIn->nCurrent
|
|
, ptipdNewIn->nMax
|
|
);
|
|
hr = THR( S_FALSE );
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
//
|
|
// The min changed, meaning we need to modify the range by the difference.
|
|
//
|
|
if ( ptipdNewIn->nMin > ptipdPrevIn->nMin )
|
|
{
|
|
nShrink = ptipdNewIn->nMin - ptipdPrevIn->nMin;
|
|
} // if:
|
|
else
|
|
{
|
|
nExpand = ptipdPrevIn->nMin - ptipdNewIn->nMin;
|
|
} // else:
|
|
} // else: mins changed
|
|
} // else if: min or max changed
|
|
else if ( ( ptipdNewIn->nMax == ptipdPrevIn->nMax ) // max didn't change
|
|
&& ( ptipdNewIn->nMin == ptipdPrevIn->nMin ) // and min didn't change
|
|
&& ( ptipdNewIn->nCurrent == ptipdPrevIn->nCurrent ) // and current didn't change
|
|
&& ( ptipdNewIn->nCurrent == ptipdNewIn->nMin ) ) // and current equals min
|
|
{
|
|
nExpand = ptipdNewIn->nMax - ptipdNewIn->nMin; // We have a new task.
|
|
} // else if: we're adding a new task
|
|
else if ( ( ptipdNewIn->nMax == ptipdPrevIn->nMax ) // max didn't change
|
|
&& ( ptipdNewIn->nMin == ptipdPrevIn->nMin ) // and min didn't change
|
|
&& ( ptipdNewIn->nCurrent > ptipdPrevIn->nCurrent ) // and current increased
|
|
&& ( ptipdNewIn->nCurrent <= ptipdNewIn->nMax ) ) // and current didn't exceed max
|
|
{
|
|
nProgress = ptipdNewIn->nCurrent - ptipdPrevIn->nCurrent; // We have an update.
|
|
} // else if: we're updating a known task
|
|
else
|
|
{
|
|
// This event broke the rules - toss it out.
|
|
LogMsg(
|
|
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"
|
|
, ptipdNewIn->nMin
|
|
, ptipdPrevIn->nMin
|
|
, ptipdNewIn->nMax
|
|
, ptipdPrevIn->nMax
|
|
, ptipdNewIn->nCurrent
|
|
, ptipdPrevIn->nCurrent
|
|
);
|
|
hr = THR( S_FALSE );
|
|
goto Cleanup;
|
|
} // else if: the two tipd's don't conform to the rules of a progress bar update
|
|
|
|
m_nRangeHigh += nExpand;
|
|
Assert( m_nRangeHigh >= nShrink )
|
|
m_nRangeHigh -= nShrink;
|
|
if ( m_nRangeHigh > m_nInitialTickCount )
|
|
{
|
|
m_fThresholdBroken = TRUE;
|
|
} // if: exceeded the initial tick count
|
|
|
|
m_nCurrentPos += nProgress;
|
|
|
|
if ( m_nCurrentPos >= m_nRangeHigh )
|
|
{
|
|
//
|
|
// Something went wrong - our position is now somehow greater than
|
|
// the range (multi-threading issue?). Simple fix - set our new range
|
|
// to be PROGRESSBAR_RESIZE_PERCENT percent greater than our new position
|
|
//
|
|
m_nRangeHigh = ( m_nCurrentPos * (100 + PROGRESSBAR_RESIZE_PERCENT) ) / 100;
|
|
} // if: current pos caught up to the upper range
|
|
|
|
// Adjust to the progress bar's scale (PROGRESSBAR_CONTROL_TICK_COUNT).
|
|
nRealPos = m_nCurrentPos * PROGRESSBAR_CONTROL_TICK_COUNT;
|
|
if ( m_fThresholdBroken )
|
|
{
|
|
nRealPos /= m_nRangeHigh;
|
|
} // if: use threshold
|
|
else
|
|
{
|
|
nRealPos /= m_nInitialTickCount;
|
|
} // else: use initial tick count
|
|
|
|
//
|
|
// If our progress bar position actually moved forward - update the control.
|
|
// This isn't always the case because we may have a new task come in and
|
|
// report a large number of steps, thereby moving our real position
|
|
// backwards, but we don't want to show reverse progress - just a steady
|
|
// advancement towards being done.
|
|
//
|
|
if ( nRealPos > m_nRealPos )
|
|
{
|
|
m_nRealPos = nRealPos;
|
|
SendMessage( m_hwndProg, PBM_SETPOS, m_nRealPos, 0 );
|
|
} // if: forward progress
|
|
|
|
Cleanup:
|
|
|
|
HRETURN( hr );
|
|
|
|
} //*** CTaskTreeView::HrUpdateProgressBar
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CTaskTreeView::HrPropagateChildStateToParents
|
|
//
|
|
// Description:
|
|
// Extend the state of a child item to its parent items.
|
|
// If the state of the child is worse (higher priority) than the
|
|
// parent's, update the state of the parent.
|
|
//
|
|
// Arguments:
|
|
// htiChildIn - Child item whose state is to be extended.
|
|
// nImageIn - Image of the child item.
|
|
// fOnlyUpdateProgressIn - TRUE = only updating progress.
|
|
//
|
|
// Return Values:
|
|
// S_OK - Operation completed successfully.
|
|
// S_FALSE - No parent item.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
CTaskTreeView::HrPropagateChildStateToParents(
|
|
HTREEITEM htiChildIn
|
|
, int nImageIn
|
|
, BOOL fOnlyUpdateProgressIn
|
|
)
|
|
{
|
|
TraceFunc( "" );
|
|
|
|
Assert( htiChildIn != NULL );
|
|
|
|
HRESULT hr = S_OK;
|
|
BOOL fReturn;
|
|
TVITEMEX tviParent;
|
|
TVITEMEX tviChild;
|
|
HTREEITEM htiParent;
|
|
HTREEITEM htiChild;
|
|
|
|
//
|
|
// Get the parent item.
|
|
//
|
|
|
|
htiParent = TreeView_GetParent( m_hwndTV, htiChildIn );
|
|
if ( htiParent == NULL )
|
|
{
|
|
hr = S_FALSE;
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
tviParent.mask = TVIF_PARAM | TVIF_IMAGE;
|
|
tviParent.hItem = htiParent;
|
|
|
|
fReturn = TreeView_GetItem( m_hwndTV, &tviParent );
|
|
if ( ! fReturn )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( TW32( ERROR_NOT_FOUND ) );
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
//
|
|
// If the state of the child is worse (higher priority) than the
|
|
// parent's, update the state of the parent.
|
|
//
|
|
|
|
if ( ( tviParent.iImage < nImageIn )
|
|
|| ( ( tviParent.iImage == tsDONE )
|
|
&& ( nImageIn == tsPENDING )
|
|
)
|
|
)
|
|
{
|
|
//
|
|
// Special Case: For the parent to be set to tsDONE, all
|
|
// the children must be set to tsDONE as well.
|
|
//
|
|
if ( ( nImageIn == tsDONE )
|
|
&& ! fOnlyUpdateProgressIn
|
|
)
|
|
{
|
|
//
|
|
// Enum the children to see if they all have tsDONE as their images.
|
|
//
|
|
|
|
htiChild = TreeView_GetChild( m_hwndTV, tviParent.hItem );
|
|
while ( htiChild != NULL )
|
|
{
|
|
tviChild.mask = TVIF_IMAGE;
|
|
tviChild.hItem = htiChild;
|
|
|
|
fReturn = TreeView_GetItem( m_hwndTV, &tviChild );
|
|
if ( ! fReturn )
|
|
{
|
|
hr = HRESULT_FROM_WIN32( TW32( ERROR_NOT_FOUND ) );
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
if ( tviChild.iImage != tsDONE )
|
|
{
|
|
//
|
|
// Not all tsDONE! Skip setting parent's image!
|
|
// This can occur if the child is displaying a warning
|
|
// or error state image.
|
|
//
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
// Get next child
|
|
htiChild = TreeView_GetNextSibling( m_hwndTV, htiChild );
|
|
} // while: more children
|
|
} // if: special case (see above)
|
|
|
|
//
|
|
// Set the parent's icon.
|
|
//
|
|
|
|
tviParent.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE;
|
|
tviParent.iImage = nImageIn;
|
|
tviParent.iSelectedImage = nImageIn;
|
|
TreeView_SetItem( m_hwndTV, &tviParent );
|
|
} // if: need to update parent's image
|
|
|
|
//
|
|
// Traverse up the tree.
|
|
//
|
|
|
|
hr = STHR( HrPropagateChildStateToParents( htiParent, nImageIn, fOnlyUpdateProgressIn ) );
|
|
if ( hr == S_FALSE )
|
|
{
|
|
// S_FALSE means that there wasn't a parent.
|
|
hr = S_OK;
|
|
} // if:
|
|
|
|
goto Cleanup;
|
|
|
|
Cleanup:
|
|
HRETURN( hr );
|
|
|
|
} //*** CTaskTreeView::HrPropagateChildStateToParents
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CTaskTreeView::HrDisplayDetails
|
|
//
|
|
// Description:
|
|
// Display the Details dialog box.
|
|
//
|
|
// Arguments:
|
|
// None.
|
|
//
|
|
// Return Values:
|
|
// S_OK
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
CTaskTreeView::HrDisplayDetails( void )
|
|
{
|
|
TraceFunc( "" );
|
|
|
|
HRESULT hr = S_OK;
|
|
HTREEITEM hti;
|
|
HWND hwndPropertyPage;
|
|
|
|
//
|
|
// If no item is selected, select the first item.
|
|
//
|
|
|
|
if ( m_htiSelected == NULL )
|
|
{
|
|
hti = TreeView_GetRoot( m_hwndTV );
|
|
Assert( hti != NULL );
|
|
hr = THR( HrSelectItem( hti ) );
|
|
if ( FAILED( hr ) )
|
|
{
|
|
// TODO: Display message box
|
|
goto Cleanup;
|
|
} // if:
|
|
} // if: no items are selected
|
|
|
|
//
|
|
// Display the dialog box.
|
|
//
|
|
|
|
hwndPropertyPage = GetParent( m_hwndTV );
|
|
Assert( hwndPropertyPage != NULL );
|
|
hr = THR( CDetailsDlg::S_HrDisplayModalDialog( hwndPropertyPage, this, m_htiSelected ) );
|
|
|
|
SetFocus( m_hwndTV );
|
|
|
|
Cleanup:
|
|
HRETURN( hr );
|
|
|
|
} //*** CTaskTreeView::HrDisplayDetails
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CTaskTreeView::FGetItem
|
|
//
|
|
// Description:
|
|
// Get the data for an item.
|
|
//
|
|
// Arguments:
|
|
// htiIn - Handle for the item to get.
|
|
// pptipdOut - Pointer in which to return the data structure.
|
|
//
|
|
// Return Values:
|
|
// TRUE - Item returned successfully.
|
|
// FALSE - Item not returned.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
BOOL
|
|
CTaskTreeView::FGetItem(
|
|
HTREEITEM htiIn
|
|
, STreeItemLParamData ** pptipd
|
|
)
|
|
{
|
|
TraceFunc( "" );
|
|
|
|
Assert( htiIn != NULL );
|
|
Assert( pptipd != NULL );
|
|
|
|
BOOL fRet;
|
|
TVITEMEX tvi;
|
|
|
|
ZeroMemory( &tvi, sizeof( tvi ) );
|
|
|
|
tvi.mask = TVIF_PARAM;
|
|
tvi.hItem = htiIn;
|
|
|
|
fRet = TreeView_GetItem( m_hwndTV, &tvi );
|
|
if ( fRet == FALSE )
|
|
{
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
Assert( tvi.lParam != NULL );
|
|
*pptipd = reinterpret_cast< STreeItemLParamData * >( tvi.lParam );
|
|
|
|
Cleanup:
|
|
RETURN( fRet );
|
|
|
|
} //*** CTaskTreeView::FGetItem
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CTaskTreeView::HrFindPrevItem
|
|
//
|
|
// Description:
|
|
// Find the previous item. The previous item could be at a deeper
|
|
// level than this item.
|
|
//
|
|
// Arguments:
|
|
// phtiOut - Handle to previous item (optional).
|
|
//
|
|
// Return Values:
|
|
// S_OK - Previous item found successfully.
|
|
// S_FALSE - No previous item found.
|
|
// Other HRESULTs.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
CTaskTreeView::HrFindPrevItem(
|
|
HTREEITEM * phtiOut
|
|
)
|
|
{
|
|
TraceFunc( "" );
|
|
|
|
HRESULT hr = S_FALSE;
|
|
HTREEITEM htiCur;
|
|
HTREEITEM htiPrev;
|
|
|
|
htiCur = m_htiSelected;
|
|
|
|
if ( phtiOut != NULL )
|
|
{
|
|
*phtiOut = NULL;
|
|
} // if:
|
|
|
|
//
|
|
// Find the previous sibling item.
|
|
//
|
|
|
|
htiPrev = TreeView_GetPrevSibling( m_hwndTV, htiCur );
|
|
if ( htiPrev == NULL )
|
|
{
|
|
//
|
|
// NO PREVIOUS SIBLING ITEM FOUND.
|
|
//
|
|
// Find the parent item.
|
|
// If there isn't a parent, then there isn't a previous item.
|
|
//
|
|
|
|
htiPrev = TreeView_GetParent( m_hwndTV, htiCur );
|
|
if ( htiPrev == NULL )
|
|
{
|
|
goto Cleanup;
|
|
} // if: no parent item
|
|
|
|
//
|
|
// The parent is the previous item.
|
|
//
|
|
|
|
} // if: no previous sibling
|
|
else
|
|
{
|
|
//
|
|
// PREVIOUS SIBLING ITEM FOUND.
|
|
//
|
|
// Find the deepest child of the last child item.
|
|
//
|
|
|
|
for ( ;; )
|
|
{
|
|
//
|
|
// Find the first child item.
|
|
//
|
|
|
|
htiCur = TreeView_GetChild( m_hwndTV, htiPrev );
|
|
if ( htiCur == NULL )
|
|
{
|
|
//
|
|
// NO CHILD ITEM FOUND.
|
|
//
|
|
// This is the previous item.
|
|
//
|
|
|
|
break;
|
|
|
|
} // if: no children
|
|
|
|
//
|
|
// CHILD ITEM FOUND.
|
|
//
|
|
// Find the last sibling of this child item.
|
|
//
|
|
|
|
for ( ;; )
|
|
{
|
|
//
|
|
// Find the next sibling item.
|
|
//
|
|
|
|
htiPrev = TreeView_GetNextSibling( m_hwndTV, htiCur );
|
|
if ( htiPrev == NULL )
|
|
{
|
|
//
|
|
// No next sibling item found.
|
|
// Exit this loop and continue the outer loop
|
|
// to find this item's children.
|
|
//
|
|
|
|
htiPrev = htiCur;
|
|
break;
|
|
} // if: no next sibling item found
|
|
|
|
//
|
|
// Found a next sibling item.
|
|
//
|
|
|
|
htiCur = htiPrev;
|
|
} // forever: find the last child item
|
|
} // forever: find the deepest child item
|
|
} // else: previous sibling item found
|
|
|
|
//
|
|
// Return the item we found.
|
|
//
|
|
|
|
Assert( htiPrev != NULL );
|
|
|
|
if ( phtiOut != NULL )
|
|
{
|
|
*phtiOut = htiPrev;
|
|
} // if:
|
|
|
|
hr = S_OK;
|
|
|
|
Cleanup:
|
|
HRETURN( hr );
|
|
|
|
} //*** CTaskTreeView::HrFindPrevItem
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CTaskTreeView::HrFindNextItem
|
|
//
|
|
// Description:
|
|
// Find the next item. The next item could be at a different level than
|
|
// this item.
|
|
//
|
|
// Arguments:
|
|
// phtiOut - Handle to next item (optional).
|
|
//
|
|
// Return Values:
|
|
// S_OK - Next item found successfully.
|
|
// S_FALSE - No next item found.
|
|
// Other HRESULTs.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
CTaskTreeView::HrFindNextItem(
|
|
HTREEITEM * phtiOut
|
|
)
|
|
{
|
|
TraceFunc( "" );
|
|
|
|
HRESULT hr = S_FALSE;
|
|
HTREEITEM htiCur;
|
|
HTREEITEM htiNext;
|
|
|
|
htiCur = m_htiSelected;
|
|
|
|
if ( phtiOut != NULL )
|
|
{
|
|
*phtiOut = NULL;
|
|
} // if:
|
|
|
|
//
|
|
// Find the first child item.
|
|
//
|
|
|
|
htiNext = TreeView_GetChild( m_hwndTV, htiCur );
|
|
if ( htiNext == NULL )
|
|
{
|
|
//
|
|
// NO CHILD ITEM FOUND.
|
|
//
|
|
|
|
for ( ;; )
|
|
{
|
|
//
|
|
// Get the next sibling item.
|
|
//
|
|
|
|
htiNext = TreeView_GetNextSibling( m_hwndTV, htiCur );
|
|
if ( htiNext == NULL )
|
|
{
|
|
//
|
|
// NO SIBLING ITEM FOUND.
|
|
//
|
|
// Find the parent item so we can find its next sibling.
|
|
//
|
|
|
|
htiNext = TreeView_GetParent( m_hwndTV, htiCur );
|
|
if ( htiNext == NULL )
|
|
{
|
|
//
|
|
// NO PARENT ITEM FOUND.
|
|
//
|
|
// At the end of the tree.
|
|
//
|
|
|
|
goto Cleanup;
|
|
} // if: no parent found
|
|
|
|
//
|
|
// PARENT ITEM FOUND.
|
|
//
|
|
// Find the parent item's next sibling.
|
|
//
|
|
|
|
htiCur = htiNext;
|
|
continue;
|
|
} // if: no next sibling item
|
|
|
|
//
|
|
// SIBLING ITEM FOUND.
|
|
//
|
|
// Found the next item.
|
|
//
|
|
|
|
break;
|
|
} // forever: find the next sibling or parent's sibling
|
|
} // if: no child item found
|
|
else
|
|
{
|
|
//
|
|
// CHILD ITEM FOUND.
|
|
//
|
|
// Found the next item.
|
|
//
|
|
} // else: child item found
|
|
|
|
//
|
|
// Return the item we found.
|
|
//
|
|
|
|
Assert( htiNext != NULL );
|
|
|
|
if ( phtiOut != NULL )
|
|
{
|
|
*phtiOut = htiNext;
|
|
} // if:
|
|
|
|
hr = S_OK;
|
|
|
|
Cleanup:
|
|
HRETURN( hr );
|
|
|
|
} //*** CTaskTreeView::HrFindNextItem
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CTaskTreeView::HrSelectItem
|
|
//
|
|
// Description:
|
|
// Select the specified item.
|
|
//
|
|
// Arguments:
|
|
// htiIn - Handle to item to select.
|
|
//
|
|
// Return Values:
|
|
// S_OK - Item selected successfully.
|
|
// Other HRESULTs.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
CTaskTreeView::HrSelectItem(
|
|
HTREEITEM htiIn
|
|
)
|
|
{
|
|
TraceFunc( "" );
|
|
|
|
Assert( htiIn != NULL );
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
TreeView_SelectItem( m_hwndTV, htiIn );
|
|
|
|
HRETURN( hr );
|
|
|
|
} //*** CTaskTreeView::HrSelectItem
|
|
|
|
//****************************************************************************
|
|
//
|
|
// Static Functions
|
|
//
|
|
//****************************************************************************
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// HrCreateTreeItem
|
|
//
|
|
// Description:
|
|
// Create a tree item.
|
|
//
|
|
// Arguments:
|
|
// ptvisOut - Tree view insert structure to fill in.
|
|
// ptipdIn - Input tree item LParam data to create this item from.
|
|
// htiParentIn - Parent tree view item.
|
|
// nImageIn - Image index.
|
|
// bstrTextIn - Text to display.
|
|
//
|
|
// Return Values:
|
|
// S_OK - Operation was successful.
|
|
// E_OUTOFMEMORY - Error allocating memory.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
HrCreateTreeItem(
|
|
TVINSERTSTRUCT * ptvisOut
|
|
, STreeItemLParamData * ptipdIn
|
|
, HTREEITEM htiParentIn
|
|
, int nImageIn
|
|
, BSTR bstrTextIn
|
|
)
|
|
{
|
|
TraceFunc( "" );
|
|
|
|
Assert( ptvisOut != NULL );
|
|
Assert( ptipdIn != NULL );
|
|
Assert( htiParentIn != NULL );
|
|
Assert( bstrTextIn != NULL );
|
|
|
|
// LOCAL VARIABLES
|
|
HRESULT hr = S_OK;
|
|
STreeItemLParamData * ptipdNew = NULL;
|
|
|
|
//
|
|
// Allocate the tree view LParam data and initialize it.
|
|
//
|
|
|
|
ptipdNew = new STreeItemLParamData;
|
|
if ( ptipdNew == NULL )
|
|
{
|
|
hr = THR( E_OUTOFMEMORY );
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
CopyMemory( &ptipdNew->clsidMajorTaskId, &ptipdIn->clsidMajorTaskId, sizeof( ptipdNew->clsidMajorTaskId ) );
|
|
CopyMemory( &ptipdNew->clsidMinorTaskId, &ptipdIn->clsidMinorTaskId, sizeof( ptipdNew->clsidMinorTaskId ) );
|
|
CopyMemory( &ptipdNew->ftTime, &ptipdIn->ftTime, sizeof( ptipdNew->ftTime ) );
|
|
ptipdNew->nMin = ptipdIn->nMin;
|
|
ptipdNew->nMax = ptipdIn->nMax;
|
|
ptipdNew->nCurrent = ptipdIn->nCurrent;
|
|
ptipdNew->hr = ptipdIn->hr;
|
|
|
|
if ( ptipdIn->bstrNodeName != NULL )
|
|
{
|
|
ptipdNew->bstrNodeName = TraceSysAllocString( ptipdIn->bstrNodeName );
|
|
if ( ptipdNew->bstrNodeName == NULL )
|
|
{
|
|
hr = THR( E_OUTOFMEMORY );
|
|
goto Cleanup;
|
|
} // if:
|
|
|
|
Assert( ptipdIn->bstrNodeNameWithoutDomain != NULL );
|
|
ptipdNew->bstrNodeNameWithoutDomain = TraceSysAllocString( ptipdIn->bstrNodeNameWithoutDomain );
|
|
if ( ptipdNew->bstrNodeNameWithoutDomain == NULL )
|
|
{
|
|
hr = THR( E_OUTOFMEMORY );
|
|
goto Cleanup;
|
|
} // if:
|
|
} // if: node name specified
|
|
|
|
if ( ptipdIn->bstrDescription != NULL )
|
|
{
|
|
ptipdNew->bstrDescription = TraceSysAllocString( ptipdIn->bstrDescription );
|
|
if ( ptipdNew->bstrDescription == NULL )
|
|
{
|
|
hr = THR( E_OUTOFMEMORY );
|
|
goto Cleanup;
|
|
} // if:
|
|
} // if: description specified
|
|
|
|
if ( ptipdIn->bstrReference != NULL )
|
|
{
|
|
ptipdNew->bstrReference = TraceSysAllocString( ptipdIn->bstrReference );
|
|
if ( ptipdNew->bstrReference == NULL )
|
|
{
|
|
hr = THR( E_OUTOFMEMORY );
|
|
goto Cleanup;
|
|
} // if:
|
|
} // if: reference specified
|
|
|
|
//
|
|
// Initialize the tree view insert structure.
|
|
//
|
|
|
|
ptvisOut->hParent = htiParentIn;
|
|
ptvisOut->hInsertAfter = TVI_LAST;
|
|
ptvisOut->itemex.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM;
|
|
ptvisOut->itemex.cchTextMax = SysStringLen( bstrTextIn );
|
|
ptvisOut->itemex.pszText = bstrTextIn;
|
|
ptvisOut->itemex.iImage = nImageIn;
|
|
ptvisOut->itemex.iSelectedImage = nImageIn;
|
|
ptvisOut->itemex.lParam = reinterpret_cast< LPARAM >( ptipdNew );
|
|
|
|
Assert( ptvisOut->itemex.cchTextMax > 0 );
|
|
|
|
// Release ownership to the tree view insert structure.
|
|
ptipdNew = NULL;
|
|
|
|
goto Cleanup;
|
|
|
|
Cleanup:
|
|
|
|
if ( ptipdNew != NULL )
|
|
{
|
|
TraceSysFreeString( ptipdNew->bstrNodeName );
|
|
TraceSysFreeString( ptipdNew->bstrNodeNameWithoutDomain );
|
|
TraceSysFreeString( ptipdNew->bstrDescription );
|
|
TraceSysFreeString( ptipdNew->bstrReference );
|
|
delete ptipdNew;
|
|
} // if:
|
|
HRETURN( hr );
|
|
|
|
} //*** HrCreateTreeItem
|
|
|