// StatsDlg.cpp : Implementation of CStatusDlg
#include "stdafx.h"

#include "WizChain.h"
#include "StatsDlg.h"

// This is the thread that displays the status dialog
DWORD WINAPI DialogThreadProc( LPVOID lpv )
{
    HRESULT hr;

    CStatusDlg * pSD = (CStatusDlg *)lpv;

    // Increment the ref count so that the object does not disappear when the user releases it
    hr = pSD->AddRef();
    if( SUCCEEDED(hr) && pSD )
    {
        pSD->DoModal(NULL); 
    }

    // Decrement the ref count
    pSD->Release();    
    return 0;
}

STDMETHODIMP CStatusDlg::AddComponent( BSTR bstrComponent, long * plIndex )
{
    HRESULT hr = S_OK;

    // If the dialog is already displayed
    // we are not accepting new components

    if( m_hThread )
        return E_UNEXPECTED; 

    // Validate the arguments

    if( NULL == bstrComponent || NULL == plIndex )
        return E_INVALIDARG;

    // Get a new index
    long lNewIndex = m_mapComponents.size();
    if( m_mapComponents.find(lNewIndex) == m_mapComponents.end() )
    {
        // Add the new component 
        BSTR bstrNewComponent = SysAllocString(bstrComponent);        
        if( bstrNewComponent )
        {
            m_mapComponents.insert(COMPONENTMAP::value_type(lNewIndex, bstrNewComponent));
        }
        else
        {
            hr = E_OUTOFMEMORY;
        }
    }
    else
    {
        hr = E_UNEXPECTED;  // This cannot happen!
    }

    if( SUCCEEDED(hr) )
    {
        *plIndex = lNewIndex;
    }
    
    return hr;
}


STDMETHODIMP CStatusDlg::Initialize( BSTR bstrWindowTitle, BSTR bstrWindowText, VARIANT varFlags )
{
    HRESULT hr = S_OK;

    // If the dialog is already displayed
    // do not allow to reinitialize 
    
    if( m_hThread ) return E_UNEXPECTED;
    if( !bstrWindowTitle || !bstrWindowText ) return E_INVALIDARG;
    if( VT_I2 != V_VT(&varFlags) && VT_I4 != V_VT(&varFlags) ) return E_INVALIDARG;
    
    if( VT_I2 == V_VT(&varFlags) ) 
    {
        m_lFlags = (long) varFlags.iVal;
    }
    else 
    {
        m_lFlags = varFlags.lVal;
    }
     
    if( SUCCEEDED(hr) )
    {
        // Initialize the common control library
        INITCOMMONCONTROLSEX initCommonControlsEx;
        initCommonControlsEx.dwSize = sizeof(initCommonControlsEx);
        initCommonControlsEx.dwICC = ICC_PROGRESS_CLASS | ICC_LISTVIEW_CLASSES;

        if( !::InitCommonControlsEx(&initCommonControlsEx) )
        {
            hr = HRESULT_FROM_WIN32(GetLastError());
        }
    }

    if( SUCCEEDED(hr) )
    {
        if( bstrWindowTitle )
        {
            m_strWindowTitle = bstrWindowTitle; // Status Dialog Title
        }

        if( bstrWindowText )
        {
            m_strWindowText = bstrWindowText;   // Status Dialog Text 
        }
    }

    return hr;
}

STDMETHODIMP CStatusDlg::SetStatus(long lIndex, SD_STATUS lStatus)
{
    HRESULT hr = S_OK;
    BOOL    bToggleActive = FALSE;
    COMPONENTMAP::iterator compIterator;
    
    // Validate the arguments
    if( (SD_STATUS_NONE > lStatus) || (SD_STATUS_RUNNING < lStatus) ) 
    {
        return E_INVALIDARG;
    }

    compIterator = m_mapComponents.find(lIndex);

    if( compIterator == m_mapComponents.end() )
    {
        return E_INVALIDARG;    // Cannot find the component
    }
        
    if( IsWindow() )
    {
        if( m_pProgressList )
        {
            CProgressItem * pPI;            
            compIterator = m_mapComponents.begin();

            // Make sure that no component has status "running"
            while( compIterator != m_mapComponents.end() )
            {
                pPI = m_pProgressList->GetProgressItem(compIterator->first);

                if( pPI && pPI->m_bActive )
                {
                    m_pProgressList->ToggleActive(compIterator->first);
                }

                compIterator++;
            }

            if( SD_STATUS_RUNNING == lStatus )
            {
                m_pProgressList->ToggleActive(lIndex); // New status is "running"
            }
            else
            {                
                // Update the state of the component on the Listview
                m_pProgressList->SetItemState(lIndex, (ItemState) lStatus);

                // If the component's done, update the total progress
                if( (lStatus == SD_STATUS_SUCCEEDED) || (lStatus == SD_STATUS_FAILED) )
                {
                    // TO DO: No need to do this, just send a message to the dialog to do that                        
                    PBRANGE range;
                    SendDlgItemMessage(IDC_PROGRESS1, PBM_GETRANGE, FALSE, (LPARAM) &range);
                    SendDlgItemMessage(IDC_PROGRESS1, PBM_SETPOS, range.iHigh, 0);
                    InterlockedExchangeAdd(&m_lTotalProgress, range.iHigh);
                }
            }
        }
        else
        {
            hr = E_UNEXPECTED;
        }

        if( SUCCEEDED(hr) )
        {
            SetupButtons( );
        }
        
    }
    else
    {
        hr = E_UNEXPECTED;
    }

    return hr;
}

void CStatusDlg::SetupButtons( )
{
    HWND hWnd = NULL;
    HWND hWndOK = NULL;
    HWND hWndCancel = NULL;

    CString csText;

    BOOL bFailed = FALSE;

    BSTR bstrText = NULL;

    USES_CONVERSION;

    hWndOK = GetDlgItem(IDOK);
    hWndCancel = GetDlgItem(IDCANCEL);

    if( IsWindow() && hWndOK && hWndCancel )
    {
        if( AreAllComponentsDone(bFailed) )
        {
            // Enable OK button
            ::EnableWindow(hWndOK, TRUE);
                
            // Disable Cancel button
            ::EnableWindow(hWndCancel, FALSE);

            // Default button is the Close button
            ::SendMessage(m_hWnd, WM_NEXTDLGCTL, (WPARAM) hWndOK, 1);

            //
            // When all components are done we will hide the progress bars to give the user 
            // a visual clue to realize that the wizard is done. I know, that sounds stupid.
            //

            hWnd = GetDlgItem(IDC_STATIC2); // Component progress text

            if (NULL != hWnd)
            {
                ::ShowWindow(hWnd, SW_HIDE);
            }

            hWnd = GetDlgItem(IDC_PROGRESS1); // Component progress text

            if (NULL != hWnd)
            {
                ::ShowWindow(hWnd, SW_HIDE);
            }

            hWnd = GetDlgItem(IDC_STATIC3); // Overall progress text

            if (NULL != hWnd)
            {
                ::ShowWindow(hWnd, SW_HIDE);
            }

            hWnd = GetDlgItem(IDC_PROGRESS2); // Overall progress

            if (NULL != hWnd)
            {
                ::ShowWindow(hWnd, SW_HIDE);
            }

            if (FALSE == bFailed)
            {
                if (csText.LoadString(IDS_STATUS_SUCCESS))
                {
                    bstrText = T2BSTR(csText);

                    if (NULL != bstrText)
                    {
                        SetStatusText(bstrText);
                    }
               
                }
            }
            else
            {
                if (csText.LoadString(IDS_STATUS_FAIL))
                {
                    bstrText = T2BSTR(csText);

                    if (NULL != bstrText)
                    {
                        SetStatusText(bstrText);
                    }
                }
            }

            if (NULL != bstrText)
            {
                ::SysFreeString(bstrText);
            }
        }
        else
        {
            // Disable OK button
            ::EnableWindow( hWndOK, FALSE );

            if( m_lFlags & SD_BUTTON_CANCEL )
            {
                ::EnableWindow( hWndCancel, TRUE );
            }
        }
    }
}

STDMETHODIMP CStatusDlg::Display( BOOL bShow )
{
    HRESULT hr = S_OK;

    if( bShow )
    {
        if( m_hThread != NULL )
        {
            if( !IsWindowVisible() )  // We are already on
            {
                ShowWindow(SW_SHOW); 
            }
        }
        else
        {
            // Create a new thread which will DoModal the status dialog
            m_hThread = CreateThread( NULL, 0, DialogThreadProc, (void *) this, 0, NULL );
            
            if( NULL == m_hThread )
            {
                hr = HRESULT_FROM_WIN32(GetLastError());
            }
            else if( m_hDisplayedEvent ) // Wait till the dialog is displayed
            {
                if( WAIT_OBJECT_0 != WaitForSingleObject(m_hDisplayedEvent, INFINITE) ) 
                {
                    hr = E_UNEXPECTED;
                }
            }
        }
    }    
    else
    {
        // Will close the dialog
        if( m_hThread != NULL )
        {
            EndDialog(IDCANCEL);

            WaitForSingleObject(m_hThread, INFINITE);
        }            
    }

    return hr;
}


// The wizard writer should call this function to wait on user response
// If the user has already responded: clicked OK or Cancel 
// then this method will return immediately
STDMETHODIMP CStatusDlg::WaitForUser( )
{
    if( m_hThread )
    {
        WaitForSingleObject(m_hThread, INFINITE);
    }

    return S_OK;
}

STDMETHODIMP CStatusDlg::get_Cancelled( BOOL *pVal )
{
    if( NULL == pVal )
    {
        return E_INVALIDARG;
    }

    if( m_lFlags & SD_BUTTON_CANCEL )
    {
        if( m_iCancelled == 0 )
        {
            *pVal = FALSE;
        }
        else
        {
            *pVal = TRUE;
        }
    }
    else
    {
        *pVal = FALSE;
    }

    return S_OK;
}

STDMETHODIMP CStatusDlg::get_ComponentProgress( IStatusProgress** pVal )
{
    HRESULT hr = S_OK;

    if( NULL == pVal )
    {
        return E_INVALIDARG;
    }
    
    if( m_lFlags & SD_PROGRESS_COMPONENT )
    {
        // Create component progress object
        if( m_pComponentProgress == NULL )
        {
            hr = CComObject<CStatusProgress>::CreateInstance(&m_pComponentProgress);

            if( SUCCEEDED(hr) )
            {
                hr = m_pComponentProgress->AddRef();
            }        

            if( SUCCEEDED(hr) && IsWindow() )
            {    
                // Initialize the component progress with the progress bar handle
                hr = m_pComponentProgress->Initialize(this, GetDlgItem(IDC_PROGRESS1), FALSE);
            }
        }
            
        if( SUCCEEDED(hr) )
        {
            hr = (m_pComponentProgress->QueryInterface(IID_IStatusProgress, (void **) pVal));
        }                
    } 
    
    return hr;
}

LRESULT CStatusDlg::OnInitDialog( UINT uint, WPARAM wparam, LPARAM lparam, BOOL& bbool ) 
{
    HWND    hWndText            = GetDlgItem(IDC_STATIC1);
    HWND    hWndLV              = GetDlgItem(IDC_LIST2);
    HWND    hWndCompText        = GetDlgItem(IDC_STATIC2);
    HWND    hWndCompProgress    = GetDlgItem(IDC_PROGRESS1);
    HWND    hWndOverallText     = GetDlgItem(IDC_STATIC3);
    HWND    hWndOverallProgress = GetDlgItem(IDC_PROGRESS2);
    HWND    hWndOK              = GetDlgItem(IDOK);
    HWND    hWndCancel          = GetDlgItem(IDCANCEL);    

    LOGFONT     logFont;
    HIMAGELIST  hILSmall;
    HBITMAP     hBitmap;
    HDC         hDC;
    TEXTMETRIC  tm;
    RECT        rect;
    CWindow     wnd;

    int iResizeLV   = 0;
    int iResize     = 0;

    // Attach to the Listview
    wnd.Attach(hWndLV);
    wnd.GetWindowRect(&rect);
    hDC = GetDC();
    GetTextMetrics(hDC, &tm);
    ReleaseDC(hDC);

    // Check if size of the list view is OK enough to hold all the components
    iResizeLV = rect.bottom - rect.top - ((tm.tmHeight + 2) * (m_mapComponents.size() + 1));

    // Depending on the options selected, decide whether the stus dialog will shrink or expand
    if( (m_lFlags & SD_PROGRESS_COMPONENT) && !(m_lFlags & SD_PROGRESS_OVERALL) )
    {
       iResize = GetWindowLength(hWndOverallText, hWndOverallProgress);
    }
    else if( !(m_lFlags & SD_PROGRESS_COMPONENT) && (m_lFlags & SD_PROGRESS_OVERALL) )
    {
        iResize = GetWindowLength(hWndCompText, hWndCompProgress);
    }
    else if( !(m_lFlags & SD_PROGRESS_COMPONENT) && !(m_lFlags & SD_PROGRESS_OVERALL) )
    {
        iResize = GetWindowLength(hWndCompText, hWndOverallProgress);
    }

    // Hide component progress if necessary
    if( !(m_lFlags & SD_PROGRESS_COMPONENT) )
    {
       ::ShowWindow(hWndCompText, SW_HIDE);
       ::ShowWindow(hWndCompProgress, SW_HIDE);
    }

    // Hide overall progress if necessary
    if( !(m_lFlags & SD_PROGRESS_OVERALL) )
    {
       ::ShowWindow(hWndOverallText, SW_HIDE);
       ::ShowWindow(hWndOverallProgress, SW_HIDE);
    }

    if ((!(m_lFlags & SD_PROGRESS_OVERALL)) || (!(m_lFlags & SD_PROGRESS_COMPONENT)))
    {        
        // We need to get rid of the space between the progress bars        
        iResize -= GetWindowLength(hWndCompText, hWndOverallProgress) - GetWindowLength(hWndOverallText, hWndOverallProgress) - GetWindowLength(hWndCompText, hWndOverallProgress) + 4;
    }

    // Well, we may need to make LV bigger, but the dialog length could stay the same
    // if the user does not want component and/or overall progress
    if( iResizeLV < 0 )  // Will need to make the LV bigger
    {
        iResize += iResizeLV;
    }
    else
    {
        iResizeLV = 0;  // We will not touch the LV
    }

    
    if( iResizeLV != 0 || iResize != 0 ) // We will need to do some moving and resizing
    {
        VerticalResizeWindow(m_hWnd, iResize);
        VerticalMoveWindow(hWndOK, iResize);
        VerticalMoveWindow(hWndCancel, iResize);

        // Location of progress bars completely depend on the resizing of the LV
        VerticalMoveWindow(hWndOverallText, iResizeLV);  
        VerticalMoveWindow(hWndOverallProgress, iResizeLV);
        VerticalMoveWindow(hWndCompText, iResizeLV);
        VerticalMoveWindow(hWndCompProgress, iResizeLV);

        // Last, but not the least, resize the LV
        VerticalResizeWindow(hWndLV, iResizeLV);
    }
    
    if( !(m_lFlags & SD_BUTTON_CANCEL) ) // We will only have an OK button
    {
        LONG_PTR dwStyle = ::GetWindowLongPtr( m_hWnd, GWL_STYLE );
        if( 0 != dwStyle )
        {
            // Get rid of the System Menu (Close X) as well
            dwStyle &= ~WS_SYSMENU; 
            ::SetWindowLongPtr( m_hWnd, GWL_STYLE, dwStyle );
        }

        ReplaceWindow(hWndCancel, hWndOK);
    }

    // if we only have overall progress, we need to move it up
    // so that it replaces the component progress
    if( (m_lFlags & SD_PROGRESS_OVERALL) && !(m_lFlags & SD_PROGRESS_COMPONENT) )
    {
        ReplaceWindow(hWndCompText, hWndOverallText);
        ReplaceWindow(hWndCompProgress, hWndOverallProgress);
    }

    // Set some style for the LV
    ::SendMessage(hWndLV, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_SUBITEMIMAGES);
    ::SendMessage(hWndLV, LVM_SETBKCOLOR, 0, (LPARAM) CLR_NONE);
    ::SendMessage(hWndLV, LVM_SETTEXTBKCOLOR, 0, (LPARAM) CLR_NONE); 
        
    LVCOLUMN col;
    ZeroMemory (&col, sizeof(col));
    col.mask    = LVCF_WIDTH;
    col.cx      = 500;

    SendMessage( hWndLV, LVM_INSERTCOLUMN, 0, (LPARAM)&col );

    // Thanks to Jeffzi
    m_pProgressList->Attach( hWndLV );
    COMPONENTMAP::iterator compIterator;
    
    compIterator = m_mapComponents.begin();          
    while( compIterator != m_mapComponents.end() )
    {
        // Add each component to the LV
        m_pProgressList->AddItem(compIterator->second);
        m_pProgressList->SetItemState(compIterator->first, IS_NONE, FALSE );
        compIterator++;
    }

    if( m_pComponentProgress )
    {
        // Initialize the component progress with the progress bar handle
        m_pComponentProgress->Initialize( this, hWndCompProgress, FALSE );
    }

    if (m_pOverallProgress)
    {
        // Initialize the overall progress with the progress bar handle
        m_pOverallProgress->Initialize( this, hWndOverallProgress, TRUE );
    }

    // Here comes the dialog title and text
    SetWindowText(m_strWindowTitle.c_str());
    ::SetWindowText(hWndText, m_strWindowText.c_str());
    SetupButtons();
    
    // Center the window, no Jeff this works just right if you have 2 monitors
    CenterWindow();
   
    if( m_hDisplayedEvent )
    {
        SetEvent(m_hDisplayedEvent);
    }

    return TRUE;
}

BOOL CStatusDlg::VerticalMoveWindow( HWND hWnd, int iResize )
{
    BOOL bRet;
    CWindow wnd;
    RECT rect;

    wnd.Attach( hWnd );   // Returns void

    if(wnd.GetWindowRect(&rect) )
    {
        rect.top -= iResize;
        rect.bottom -= iResize;

        // GetWindowRect fills in RECT relative to the desktop
        // We need to make it relative to the dialog
        // as MoveWindow works that way
        if( ScreenToClient(&rect) )
        {
            bRet = wnd.MoveWindow(&rect);
        }
        else
        {
            bRet = FALSE;
        }
    }
    else
    {
        bRet = FALSE;
    }
    
    return bRet;
}

BOOL CStatusDlg::ReplaceWindow( HWND hWndOld, HWND hWndNew )
{
    BOOL bRet;
    CWindow wnd;
    RECT rect;

    wnd.Attach(hWndOld);
    
    // Get the coordinates of the old Window
    if( wnd.GetWindowRect(&rect) )
    {
        // Hide it, we are trying to replace it
        wnd.ShowWindow(SW_HIDE);

        // Attach to the new one
        wnd.Attach(hWndNew);
    
        // Map the coordinates and move the window on top of the old one
        if( ScreenToClient(&rect) )
        {
            bRet = wnd.MoveWindow(&rect);
        }
        else
        {
            bRet = FALSE;
        }
    }
    else
    {
        bRet = FALSE;
    }

    return bRet;
}

BOOL CStatusDlg::VerticalResizeWindow( HWND hWnd, int iResize )
{
    CWindow wnd;
    RECT rect;
    BOOL bRet = FALSE;
    
    if( iResize )
    {
        // Attach to the window        
        wnd.Attach(hWnd);
        
        // Get the coordinates
        if( wnd.GetWindowRect(&rect) )
        {
            rect.bottom -= iResize; // Increase the bottom

            if( ScreenToClient(&rect) )
            {
                bRet = wnd.MoveWindow(&rect);  // Resize
            }
            else
            {
                bRet= FALSE;
            }
        }
        else
        {
            bRet = FALSE;
        }
    }

    return bRet;
}

int CStatusDlg::GetWindowLength( HWND hWndTop, HWND hWndBottom )
{
    CWindow wnd;
    RECT rect;
    int iTop;

    wnd.Attach(hWndTop);

    if( wnd.GetWindowRect(&rect) )
    {
        iTop = rect.top;
        wnd.Attach(hWndBottom);

        if( wnd.GetWindowRect(&rect) )
        {
            return rect.bottom - iTop;
        }
    }

    return 0;
}

STDMETHODIMP CStatusDlg::get_OverallProgress( IStatusProgress** pVal )
{
    HRESULT hr = S_OK;

	if( NULL == pVal )
    {
        return E_INVALIDARG;
    }

    if( m_lFlags & SD_PROGRESS_OVERALL )
    {
        // Create component progress object
        if( m_pOverallProgress == NULL )
        {
            hr = CComObject<CStatusProgress>::CreateInstance(&m_pOverallProgress);

            if( SUCCEEDED(hr) )
            {
                hr = m_pOverallProgress->AddRef();
            }
            
            if( SUCCEEDED(hr) && IsWindow() )
            {
                // Initialize the overall progress with the progress bar handle
                hr = m_pOverallProgress->Initialize(this, GetDlgItem(IDC_PROGRESS2), TRUE);
            }
        }
        
        hr = m_pOverallProgress->QueryInterface(IID_IStatusProgress, (void **) pVal);                
    } 
    
    return hr;
}

BOOL CStatusDlg::AreAllComponentsDone( BOOL& bFailedComponent )
{
    BOOL bComponentToRun = FALSE;

    COMPONENTMAP::iterator compIterator = m_mapComponents.begin();

    if( m_pProgressList )
    {
        // Look for a component that's not done
        while( m_pProgressList && !bComponentToRun && compIterator != m_mapComponents.end() )
        {
            CProgressItem * pPI = m_pProgressList->GetProgressItem(compIterator->first);

            if( NULL != pPI )
            {
                // Is the component done?
                if( IS_NONE == pPI->m_eState )
                {
                    bComponentToRun = TRUE;
                }            
                else if( IS_FAILED == pPI->m_eState )
                {
                    bFailedComponent = TRUE;
                }
            }
            else
            {
                _ASSERT( pPI );
            }

            compIterator++;
        }
    }

    return !bComponentToRun;
}

LRESULT CStatusDlg::OnCloseCmd( WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/ )
{
    EndDialog(wID); 

	return 0;
} 

LRESULT CStatusDlg::OnCancelCmd( WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/ )
{
    HWND hWnd = NULL;

    if( 0 == m_iCancelled )
    {
        InterlockedIncrement((LONG *) &m_iCancelled);  
    }

    // Disable the Cancel button    
    hWnd = GetDlgItem(IDCANCEL);
    if( hWnd && ::IsWindow(hWnd) )
    {
        ::EnableWindow( hWnd, FALSE );
    }

    //  EndDialog(wID);
    //  Leaving it to the component to close the dialog  
    return 0;
}

LRESULT CStatusDlg::OnDrawItem( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
{
	if( wParam == IDC_LIST2 )
	{
        if( m_pProgressList )
        {
		    m_pProgressList->OnDrawItem( lParam );
        }
	}
	return 0;
}

LRESULT CStatusDlg::OnMeasureItem( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
{
	if( wParam == IDC_LIST2)
	{
        if( m_pProgressList )
        {
            m_pProgressList->OnMeasureItem( lParam );
        }
	}
	return 0;
}


LRESULT CStatusDlg::OnClose( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
{
    if( m_lFlags & SD_BUTTON_CANCEL )    // Cancel button?
    {
        if( ::IsWindowEnabled( GetDlgItem(IDCANCEL) ) ) // Is it enabled?
        {
            if( 0 == m_iCancelled )
            {
                InterlockedIncrement( (LONG*)&m_iCancelled );
            }

            EndDialog(0);
        }
        else if( ::IsWindowEnabled( GetDlgItem(IDOK) ) )
        {
            // it could be OK button sending WM_CLOSE or the user
            // As long as OK button is enabled we need to close the dialog
            EndDialog(1);
        }
    }
    else if( ::IsWindowEnabled( GetDlgItem(IDOK) ) )
    {
        EndDialog( 1 );
    }
	return 0;
}

LRESULT CStatusDlg::OnTimerProgress( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
{
    HRESULT hr;
    long lPosition;

    if( wParam && (m_lTimer == wParam) )   // Make sure that this is for our timer
    {
        lPosition = SendDlgItemMessage(IDC_PROGRESS1, PBM_GETPOS, 0, 0);

        if( lPosition < m_lMaxSteps )    // Do we still have room for progress?
        {
            SendDlgItemMessage(IDC_PROGRESS1, PBM_STEPIT, 0, 0);    // Step 1
            SendMessage(WM_UPDATEOVERALLPROGRESS, 0, 0);            // Update the overall progress
        }
        else
        {
            // There's no room to progress, we've reached the max
            // Let's kill the timer
            SendMessage(WM_KILLTIMER, 0);
        }        
    }

    return 0;
}

LRESULT CStatusDlg::OnUpdateOverallProgress( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
{
    long lPosition = 0;

    if( m_lFlags & SD_PROGRESS_COMPONENT )   // Make sure that there's a component progress
    {
        lPosition = SendDlgItemMessage(IDC_PROGRESS1, PBM_GETPOS, 0, 0);

        // Update the overall progress        
        SendDlgItemMessage(IDC_PROGRESS2, PBM_SETPOS, m_lTotalProgress + lPosition, 0);
    }

    return 0;
}

LRESULT CStatusDlg::OnStartTimer( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
{
    if( !m_lTimer ) // There might be a timer already
    {
        m_lTimer = SetTimer(SD_TIMER_ID, wParam * 500); // Create a timer
        m_lMaxSteps = (long) lParam;    // Max. not to exceed for the progress bar
    }

    return 0;
}

LRESULT CStatusDlg::OnKillTimer( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
{
    if( m_lTimer )   // Is there a timer?
    {
        KillTimer( m_lTimer );    // Kill it
        m_lTimer = 0;           
        m_lMaxSteps = 0;
    }

    return 0;
}

STDMETHODIMP CStatusDlg::SetStatusText(BSTR bstrText)
{
    if( !bstrText ) return E_POINTER;

    HRESULT hr = S_OK;
    HWND    hWnd = GetDlgItem(IDC_STATIC1);

    if( hWnd && ::IsWindow(hWnd) )
    {
        if( 0 == ::SetWindowText(hWnd, OLE2T(bstrText)) )
        {
            hr = HRESULT_FROM_WIN32(GetLastError());
        }
    }
    else
    {
        hr = E_FAIL;
    }

    return hr;
}


STDMETHODIMP CStatusDlg::DisplayError(BSTR bstrError, BSTR bstrTitle, DWORD dwFlags, long * pRet)
{
    if( !bstrError || !bstrTitle || !pRet ) return E_POINTER;

    HRESULT hr = S_OK;    

    *pRet = MessageBox( bstrError, bstrTitle, dwFlags );

    if( 0 == *pRet )
    {
	    hr = HRESULT_FROM_WIN32(GetLastError());
    }

    return hr;
}