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.
1397 lines
37 KiB
1397 lines
37 KiB
|
|
#ifndef UNICODE
|
|
#define UNICODE
|
|
#endif
|
|
|
|
#ifndef _UNICODE
|
|
#define _UNICODE
|
|
#endif
|
|
|
|
#undef _WIN32_IE
|
|
#define _WIN32_IE 0x0500
|
|
|
|
#pragma warning( disable : 4786 )
|
|
|
|
#include <windows.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <malloc.h>
|
|
#include <math.h>
|
|
#include <float.h>
|
|
#include <commctrl.h>
|
|
#include <commdlg.h>
|
|
#include <shellapi.h>
|
|
#include <shlwapi.h>
|
|
#include <wininet.h>
|
|
#include <shlobj.h>
|
|
#include <bits.h>
|
|
#include <comdef.h>
|
|
#include <fusenetincludes.h>
|
|
#include "resource.h"
|
|
#include "dialog.h"
|
|
|
|
#include <assemblydownload.h>
|
|
|
|
extern HINSTANCE g_hInst;
|
|
|
|
|
|
// Maxstring size, bump up on problems
|
|
#define MAX_STRING 0x800 // 2K
|
|
|
|
// BUGBUG - these two also have to be made per-instance
|
|
// adriaanc
|
|
GUID g_JobId;
|
|
WCHAR g_szDefaultTitle[] = { L"ClickOnce Application" };
|
|
|
|
// Received on update request while timer is active
|
|
LONG g_RefreshOnTimer = 0;
|
|
|
|
bool g_IsMinimized = FALSE;
|
|
|
|
#define TRAY_UID 0
|
|
|
|
// note: ensure no conflict with other messages
|
|
#define MYWM_NOTIFYICON WM_USER+9
|
|
|
|
HRESULT CreateDialogObject(CDownloadDlg **ppDlg)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
MAKE_ERROR_MACROS_STATIC(hr);
|
|
CDownloadDlg *pDlg = NULL;
|
|
|
|
IF_ALLOC_FAILED_EXIT(pDlg = new CDownloadDlg);
|
|
|
|
*ppDlg = pDlg;
|
|
hr = (pDlg)->CreateUI(SW_SHOW);
|
|
|
|
exit:
|
|
return hr;
|
|
}
|
|
|
|
VOID CDownloadDlg::SetJobObject(IBackgroundCopyJob *pJob)
|
|
{
|
|
if(_pJob)
|
|
{
|
|
// update job data details .....
|
|
BG_JOB_PROGRESS progress;
|
|
if(SUCCEEDED(_pJob->GetProgress( &progress )))
|
|
{
|
|
if ( progress.BytesTotal != BG_SIZE_UNKNOWN )
|
|
{
|
|
// BUGBUG: try to do an atomic add
|
|
_ui64BytesFromPrevJobs += progress.BytesTransferred;
|
|
}
|
|
}
|
|
_dwJobCount++;
|
|
}
|
|
|
|
SAFERELEASE(_pJob);
|
|
_pJob = pJob;
|
|
_pJob->AddRef();
|
|
}
|
|
|
|
CDownloadDlg::CDownloadDlg()
|
|
{
|
|
_pJob = NULL;
|
|
_hwndDlg = NULL;
|
|
_ui64StartTime = GetSystemTimeAsUINT64();
|
|
_ui64BytesFromPrevJobs = 0;
|
|
_dwJobCount = 0;
|
|
_eState = DOWNLOADDLG_STATE_INIT;
|
|
}
|
|
|
|
CDownloadDlg::~CDownloadDlg()
|
|
{
|
|
SAFERELEASE(_pJob);
|
|
}
|
|
|
|
const WCHAR * CDownloadDlg::GetString( UINT id )
|
|
{
|
|
|
|
//
|
|
// Retrieves the localized string for the resource id
|
|
// caching the string when loaded.
|
|
static const WCHAR* pStringArray[ IDS_MAX ];
|
|
static WCHAR TempStringBuffer[ MAX_STRING ];
|
|
const WCHAR * & pStringPointer = pStringArray[ id - 1 ];
|
|
|
|
// Cache resource strings
|
|
if ( pStringPointer )
|
|
return pStringPointer;
|
|
|
|
// Load string from resource
|
|
|
|
int CharsLoaded =
|
|
LoadStringW(
|
|
g_hInst,
|
|
id,
|
|
TempStringBuffer,
|
|
MAX_STRING );
|
|
|
|
if ( !CharsLoaded )
|
|
return L"";
|
|
|
|
WCHAR *pNewString = new WCHAR[ CharsLoaded + 1];
|
|
if ( !pNewString )
|
|
return L"";
|
|
|
|
wcscpy( pNewString, TempStringBuffer );
|
|
return ( pStringPointer = pNewString );
|
|
|
|
}
|
|
|
|
void CDownloadDlg::SetWindowTime(
|
|
HWND hwnd,
|
|
FILETIME filetime
|
|
)
|
|
{
|
|
// Set the window text to be the text representation
|
|
// of the file time.
|
|
// If an error occurs, set the window text to be error
|
|
|
|
FILETIME localtime;
|
|
FileTimeToLocalFileTime( &filetime, &localtime );
|
|
|
|
SYSTEMTIME systemtime;
|
|
FileTimeToSystemTime( &localtime, &systemtime );
|
|
|
|
int RequiredDateSize =
|
|
GetDateFormatW(
|
|
LOCALE_USER_DEFAULT,
|
|
0,
|
|
&systemtime,
|
|
NULL,
|
|
NULL,
|
|
0 );
|
|
|
|
if ( !RequiredDateSize )
|
|
{
|
|
SetWindowText( hwnd, GetString( IDS_ERROR ) );
|
|
return;
|
|
}
|
|
|
|
WCHAR *pszDateBuffer = (WCHAR*)alloca( sizeof(WCHAR) * (RequiredDateSize + 1) );
|
|
|
|
int DateSize =
|
|
GetDateFormatW(
|
|
LOCALE_USER_DEFAULT,
|
|
0,
|
|
&systemtime,
|
|
NULL,
|
|
pszDateBuffer,
|
|
RequiredDateSize );
|
|
|
|
if (!DateSize)
|
|
{
|
|
SetWindowText( hwnd, GetString( IDS_ERROR ) );
|
|
return;
|
|
}
|
|
|
|
int RequiredTimeSize =
|
|
GetTimeFormatW(
|
|
LOCALE_USER_DEFAULT,
|
|
0,
|
|
&systemtime,
|
|
NULL,
|
|
NULL,
|
|
0 );
|
|
|
|
if (!RequiredTimeSize)
|
|
{
|
|
SetWindowText( hwnd, GetString( IDS_ERROR ) );
|
|
return;
|
|
}
|
|
|
|
WCHAR *pszTimeBuffer = (WCHAR*)alloca( sizeof( WCHAR ) * ( RequiredTimeSize + 1 ) );
|
|
|
|
int TimeSize =
|
|
GetTimeFormatW(
|
|
LOCALE_USER_DEFAULT,
|
|
0,
|
|
&systemtime,
|
|
NULL,
|
|
pszTimeBuffer,
|
|
RequiredTimeSize );
|
|
|
|
if (!TimeSize)
|
|
{
|
|
SetWindowText( hwnd, GetString( IDS_ERROR ) );
|
|
return;
|
|
}
|
|
|
|
// Add 2 for extra measure
|
|
WCHAR *FullTime =
|
|
(WCHAR*)alloca( sizeof( WCHAR ) *
|
|
( RequiredTimeSize + RequiredDateSize + 2 ) );
|
|
wsprintf( FullTime, L"%s %s", pszDateBuffer, pszTimeBuffer );
|
|
|
|
SetWindowText( hwnd, FullTime );
|
|
|
|
}
|
|
|
|
UINT64 CDownloadDlg::GetSystemTimeAsUINT64()
|
|
{
|
|
|
|
//
|
|
// Returns the system time as an UINT instead of a FILETIME.
|
|
//
|
|
|
|
FILETIME filetime;
|
|
GetSystemTimeAsFileTime( &filetime );
|
|
|
|
ULARGE_INTEGER large;
|
|
memcpy( &large, &filetime, sizeof(FILETIME) );
|
|
|
|
return large.QuadPart;
|
|
}
|
|
|
|
void CDownloadDlg::SignalAlert(
|
|
HWND hwndDlg,
|
|
UINT Type
|
|
)
|
|
{
|
|
|
|
//
|
|
// Alert the user that an important event has occurred
|
|
//
|
|
|
|
FLASHWINFO FlashInfo;
|
|
FlashInfo.cbSize = sizeof(FlashInfo);
|
|
FlashInfo.hwnd = hwndDlg;
|
|
FlashInfo.dwFlags = FLASHW_ALL | FLASHW_TIMERNOFG;
|
|
FlashInfo.uCount = 0;
|
|
FlashInfo.dwTimeout = 0;
|
|
|
|
FlashWindowEx( &FlashInfo );
|
|
MessageBeep( Type );
|
|
|
|
}
|
|
|
|
const WCHAR *
|
|
CDownloadDlg::MapStateToString(
|
|
BG_JOB_STATE state
|
|
)
|
|
{
|
|
|
|
//
|
|
// Maps a BITS job state to a human readable string
|
|
//
|
|
|
|
switch( state )
|
|
{
|
|
|
|
case BG_JOB_STATE_QUEUED:
|
|
return GetString( IDS_QUEUED );
|
|
|
|
case BG_JOB_STATE_CONNECTING:
|
|
return GetString( IDS_CONNECTING );
|
|
|
|
case BG_JOB_STATE_TRANSFERRING:
|
|
return GetString( IDS_TRANSFERRING );
|
|
|
|
case BG_JOB_STATE_SUSPENDED:
|
|
return GetString( IDS_SUSPENDED );
|
|
|
|
case BG_JOB_STATE_ERROR:
|
|
return GetString( IDS_FATALERROR );
|
|
|
|
case BG_JOB_STATE_TRANSIENT_ERROR:
|
|
return GetString( IDS_TRANSIENTERROR );
|
|
|
|
case BG_JOB_STATE_TRANSFERRED:
|
|
return GetString( IDS_TRANSFERRED );
|
|
|
|
case BG_JOB_STATE_ACKNOWLEDGED:
|
|
return GetString( IDS_ACKNOWLEDGED );
|
|
|
|
case BG_JOB_STATE_CANCELLED:
|
|
return GetString( IDS_CANCELLED );
|
|
|
|
default:
|
|
|
|
// NOTE: Always provide a default case
|
|
// since new states may be added in future versions.
|
|
return GetString( IDS_UNKNOWN );
|
|
|
|
}
|
|
}
|
|
|
|
UINT64
|
|
CDownloadDlg::ScaleDownloadRate(
|
|
double Rate, // rate in seconds
|
|
const WCHAR **pFormat )
|
|
{
|
|
|
|
//
|
|
// Scales a download rate and selects the correct
|
|
// format to pass to wprintf for printing.
|
|
//
|
|
|
|
double RateBounds[] =
|
|
{
|
|
1073741824.0, // Gigabyte
|
|
1048576.0, // Megabyte
|
|
1024.0, // Kilobyte
|
|
0 // Byte
|
|
};
|
|
|
|
UINT RateFormat[] =
|
|
{
|
|
IDS_GIGAFORMAT,
|
|
IDS_MEGAFORMAT,
|
|
IDS_KILOFORMAT,
|
|
IDS_BYTEFORMAT
|
|
};
|
|
|
|
for( unsigned int c = 0;; c++ )
|
|
{
|
|
if ( Rate >= RateBounds[c] )
|
|
{
|
|
*pFormat = GetString( RateFormat[c] );
|
|
double scale = (RateBounds[c] >= 1.0) ? RateBounds[c] : 1.0;
|
|
return (UINT64)floor( ( Rate / scale ) + 0.5);
|
|
}
|
|
}
|
|
}
|
|
|
|
UINT64
|
|
CDownloadDlg::ScaleDownloadEstimate(
|
|
double Time, // time in seconds
|
|
const WCHAR **pFormat )
|
|
{
|
|
|
|
//
|
|
// Scales a download time estimate and selects the correct
|
|
// format to pass to wprintf for printing.
|
|
//
|
|
|
|
|
|
double TimeBounds[] =
|
|
{
|
|
60.0 * 60.0 * 24.0, // Days
|
|
60.0 * 60.0, // Hours
|
|
60.0, // Minutes
|
|
0.0 // Seconds
|
|
};
|
|
|
|
UINT TimeFormat[] =
|
|
{
|
|
IDS_DAYSFORMAT,
|
|
IDS_HOURSFORMAT,
|
|
IDS_MINUTESFORMAT,
|
|
IDS_SECONDSFORMAT
|
|
};
|
|
|
|
for( unsigned int c = 0;; c++ )
|
|
{
|
|
if ( Time >= TimeBounds[c] )
|
|
{
|
|
*pFormat = GetString( TimeFormat[c] );
|
|
double scale = (TimeBounds[c] >= 1.0) ? TimeBounds[c] : 1.0;
|
|
return (UINT64)floor( ( Time / scale ) + 0.5);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// DemoHack
|
|
void
|
|
CDownloadDlg::UpdateDialog(
|
|
HWND hwndDlg, LPWSTR wzErrorMsg)
|
|
{
|
|
SetWindowText( GetDlgItem( hwndDlg, IDC_ERRORMSG ), wzErrorMsg );
|
|
ShowWindow( GetDlgItem( hwndDlg, IDC_ERRORMSG ), SW_SHOW );
|
|
}
|
|
|
|
HRESULT CDownloadDlg::UpdateProgress( HWND hwndDlg )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
MAKE_ERROR_MACROS_STATIC(hr);
|
|
|
|
|
|
BG_JOB_PROGRESS progress;
|
|
IBackgroundCopyError *pError = NULL;
|
|
|
|
WCHAR szProgress[MAX_STRING];
|
|
WCHAR szTitle[MAX_STRING];
|
|
WPARAM newpos = 0;
|
|
|
|
UINT64 ui64BytesTotal = _ui64BytesFromPrevJobs;
|
|
UINT64 ui64BytesTransferred = _ui64BytesFromPrevJobs;
|
|
|
|
double AvgRate = 0;
|
|
|
|
static BG_JOB_STATE prevstate = BG_JOB_STATE_SUSPENDED;
|
|
BG_JOB_STATE state;
|
|
|
|
IF_FAILED_EXIT(_pJob->GetState( &state ));
|
|
|
|
IF_FAILED_EXIT(_pJob->GetProgress( &progress ));
|
|
|
|
// update the title, progress bar, and progress description
|
|
|
|
if ( progress.BytesTotal != BG_SIZE_UNKNOWN )
|
|
{
|
|
ui64BytesTotal += progress.BytesTotal;
|
|
ui64BytesTransferred += progress.BytesTransferred;
|
|
}
|
|
|
|
if ( ui64BytesTotal )
|
|
{
|
|
swprintf( szProgress, GetString( IDS_LONGPROGRESS ),ui64BytesTransferred,
|
|
ui64BytesTotal );
|
|
|
|
double Percent = (double)ui64BytesTransferred *100 /
|
|
(double)ui64BytesTotal;
|
|
|
|
swprintf( szTitle, L"%u%% of %s Downloaded", (unsigned int)Percent, (_sTitle._cc != 0) ? _sTitle._pwz : g_szDefaultTitle );
|
|
newpos = (WPARAM)Percent;
|
|
}
|
|
else
|
|
{
|
|
swprintf( szProgress, GetString( IDS_SHORTPROGRESS ), ui64BytesTransferred );
|
|
wcscpy( szTitle, (_sTitle.CharCount() > 1) ? _sTitle._pwz : g_szDefaultTitle );
|
|
newpos = 0;
|
|
}
|
|
|
|
SendDlgItemMessage( hwndDlg, IDC_PROGRESSBAR, PBM_SETPOS, newpos, 0 );
|
|
|
|
SetWindowText( GetDlgItem( hwndDlg, IDC_PROGRESSINFO ), szProgress );
|
|
ShowWindow( GetDlgItem( hwndDlg, IDC_PROGRESSINFO ), SW_SHOW );
|
|
EnableWindow( GetDlgItem( hwndDlg, IDC_PROGRESSINFOTXT ), TRUE );
|
|
SetWindowText( hwndDlg, szTitle );
|
|
|
|
|
|
// Only enable the finish button if the job is finished.
|
|
// ADRIAANC EnableWindow( GetDlgItem( hwndDlg, IDC_FINISH ), ( state == BG_JOB_STATE_TRANSFERRED ) );
|
|
EnableWindow( GetDlgItem( hwndDlg, IDC_FINISH ), ( state == BG_JOB_STATE_ACKNOWLEDGED ) );
|
|
|
|
// felixybc BUGBUG: CANCEL is not allowed when the job is done
|
|
// - should hold off ACK-ing that job until user clicks FINISH so that it can still be canceled at 100%?
|
|
EnableWindow( GetDlgItem( hwndDlg, IDC_CANCEL ), ( state != BG_JOB_STATE_ACKNOWLEDGED && state != BG_JOB_STATE_CANCELLED ) );
|
|
|
|
// Only enable the suspend button if the job is not finished or transferred
|
|
BOOL EnableSuspend =
|
|
( state != BG_JOB_STATE_SUSPENDED ) && ( state != BG_JOB_STATE_TRANSFERRED ) && (state != BG_JOB_STATE_ACKNOWLEDGED);
|
|
EnableWindow( GetDlgItem( hwndDlg, IDC_SUSPEND ), EnableSuspend );
|
|
|
|
// Only enable the resume button if the job is suspended
|
|
BOOL EnableResume = ( BG_JOB_STATE_SUSPENDED == state );
|
|
EnableWindow( GetDlgItem( hwndDlg, IDC_RESUME ), EnableResume );
|
|
|
|
// Alert the user when something important happens
|
|
// such as the job completes or a unrecoverable error occurs
|
|
if ( (BG_JOB_STATE_ERROR == state) && (BG_JOB_STATE_ERROR != prevstate) )
|
|
SignalAlert( hwndDlg, MB_ICONEXCLAMATION );
|
|
|
|
|
|
// update the error message
|
|
if ( FAILED(_pJob->GetError( &pError )) )
|
|
{
|
|
ShowWindow( GetDlgItem( hwndDlg, IDC_ERRORMSG ), SW_HIDE );
|
|
EnableWindow( GetDlgItem( hwndDlg, IDC_ERRORMSGTXT ), FALSE );
|
|
}
|
|
else
|
|
{
|
|
CString sErrMsg;
|
|
|
|
IF_FAILED_EXIT(CAssemblyDownload::GetBITSErrorMsg(pError, sErrMsg));
|
|
|
|
HWND hwndErrorText = GetDlgItem( hwndDlg, IDC_ERRORMSG );
|
|
SetWindowText( hwndErrorText, sErrMsg._pwz );
|
|
ShowWindow( hwndErrorText, SW_SHOW );
|
|
EnableWindow( GetDlgItem( hwndDlg, IDC_ERRORMSGTXT ), TRUE );
|
|
}
|
|
|
|
//
|
|
// This large block of text computes the average transfer rate
|
|
// and estimated completion time. This code has much
|
|
// room for improvement.
|
|
//
|
|
|
|
BOOL HasRates = TRUE;
|
|
BOOL EnableRate = FALSE;
|
|
|
|
WCHAR szRateText[MAX_STRING];
|
|
|
|
if ( !( BG_JOB_STATE_QUEUED == state ) &&
|
|
!( BG_JOB_STATE_CONNECTING == state ) &&
|
|
!( BG_JOB_STATE_TRANSFERRING == state ) )
|
|
{
|
|
// If the job isn't running, then rate values won't
|
|
// make any sense. Don't display them.
|
|
HasRates = FALSE;
|
|
}
|
|
|
|
if ( HasRates )
|
|
{
|
|
|
|
UINT64 ui64CurrentTime = GetSystemTimeAsUINT64();
|
|
|
|
UINT64 ui64TimeDiff = ui64CurrentTime - _ui64StartTime;
|
|
|
|
AvgRate = (double)(__int64)ui64BytesTransferred /
|
|
(double)(__int64) ui64TimeDiff;
|
|
|
|
// convert from FILETIME units to seconds
|
|
double NewDisplayRate = AvgRate * 10000000;
|
|
|
|
const WCHAR *pRateFormat = NULL;
|
|
UINT64 Rate = ScaleDownloadRate( NewDisplayRate, &pRateFormat );
|
|
wsprintf( szRateText, pRateFormat, Rate );
|
|
|
|
EnableRate = TRUE;
|
|
}
|
|
|
|
|
|
if (!EnableRate)
|
|
{
|
|
ShowWindow( GetDlgItem( hwndDlg, IDC_TRANSFERRATE ), SW_HIDE );
|
|
EnableWindow( GetDlgItem( hwndDlg, IDC_TRANSFERRATETXT ), FALSE );
|
|
}
|
|
else
|
|
{
|
|
SetWindowText( GetDlgItem( hwndDlg, IDC_TRANSFERRATE ), szRateText );
|
|
ShowWindow( GetDlgItem( hwndDlg, IDC_TRANSFERRATE ), SW_SHOW );
|
|
EnableWindow( GetDlgItem( hwndDlg, IDC_TRANSFERRATETXT ), TRUE );
|
|
}
|
|
|
|
BOOL EnableEstimate = FALSE;
|
|
WCHAR szEstimateText[MAX_STRING];
|
|
|
|
if ( EnableRate && ui64BytesTotal && AvgRate)
|
|
{
|
|
double TimeRemaining = ( ui64BytesTotal - ui64BytesTransferred ) / AvgRate;
|
|
|
|
// convert from FILETIME units to seconds
|
|
TimeRemaining = TimeRemaining / 10000000.0;
|
|
|
|
static const double SecsPer30Days = 60.0 * 60.0 * 24.0 * 30.0;
|
|
|
|
// Don't estimate if estimate is larger then 30 days.
|
|
if ( TimeRemaining < SecsPer30Days )
|
|
{
|
|
const WCHAR *pFormat = NULL;
|
|
UINT64 Time = ScaleDownloadEstimate( TimeRemaining, &pFormat );
|
|
wsprintf( szEstimateText, pFormat, Time );
|
|
EnableEstimate = TRUE;
|
|
}
|
|
}
|
|
|
|
if (!EnableEstimate)
|
|
{
|
|
ShowWindow( GetDlgItem( hwndDlg, IDC_ESTIMATEDTIME ), SW_HIDE );
|
|
EnableWindow( GetDlgItem( hwndDlg, IDC_ESTIMATEDTIMETXT ), FALSE );
|
|
}
|
|
else
|
|
{
|
|
SetWindowText( GetDlgItem( hwndDlg, IDC_ESTIMATEDTIME ), szEstimateText );
|
|
ShowWindow( GetDlgItem( hwndDlg, IDC_ESTIMATEDTIME ), SW_SHOW );
|
|
EnableWindow( GetDlgItem( hwndDlg, IDC_ESTIMATEDTIMETXT ), TRUE );
|
|
}
|
|
|
|
prevstate = state;
|
|
|
|
exit :
|
|
|
|
SAFERELEASE(pError);
|
|
|
|
return hr;
|
|
}
|
|
|
|
void
|
|
CDownloadDlg::UpdateDialog(
|
|
HWND hwndDlg
|
|
)
|
|
{
|
|
|
|
UpdateProgress(hwndDlg);
|
|
return;
|
|
//
|
|
// Main update routine for the dialog box.
|
|
// Retries the job state/properties from
|
|
// BITS and updates the dialog box.
|
|
//
|
|
|
|
// update the display name
|
|
|
|
|
|
static BG_JOB_STATE prevstate = BG_JOB_STATE_SUSPENDED;
|
|
BG_JOB_STATE state;
|
|
|
|
if (FAILED(_pJob->GetState( &state )))
|
|
return; // stop updating on an error
|
|
|
|
if ( BG_JOB_STATE_ACKNOWLEDGED == state ||
|
|
BG_JOB_STATE_CANCELLED == state )
|
|
{
|
|
// someone else cancelled or completed the job on us,
|
|
// just exist the exit.
|
|
// May happen if job is canceled with bitsadmin
|
|
|
|
// DeleteStartupLink( g_JobId );
|
|
// ExitProcess( 0 );
|
|
|
|
// BUGBUG: Should post a CANCEL message to assemblydownload
|
|
|
|
}
|
|
|
|
BG_JOB_PROGRESS progress;
|
|
if (FAILED(_pJob->GetProgress( &progress )))
|
|
return; // stop updating on an error
|
|
|
|
{
|
|
// update the title, progress bar, and progress description
|
|
WCHAR szProgress[MAX_STRING];
|
|
WCHAR szTitle[MAX_STRING];
|
|
WPARAM newpos = 0;
|
|
|
|
if ( progress.BytesTotal &&
|
|
( progress.BytesTotal != BG_SIZE_UNKNOWN ) )
|
|
{
|
|
swprintf( szProgress, GetString( IDS_LONGPROGRESS ), progress.BytesTransferred,
|
|
progress.BytesTotal );
|
|
|
|
double Percent = (double)(__int64)progress.BytesTransferred /
|
|
(double)(__int64)progress.BytesTotal;
|
|
Percent *= 100.0;
|
|
swprintf( szTitle, L"%u%% of %s Downloaded", (unsigned int)Percent, (_sTitle._cc != 0) ? _sTitle._pwz : g_szDefaultTitle );
|
|
newpos = (WPARAM)Percent;
|
|
|
|
}
|
|
else
|
|
{
|
|
swprintf( szProgress, GetString( IDS_SHORTPROGRESS ), progress.BytesTransferred );
|
|
wcscpy( szTitle, (_sTitle._cc != 0) ? _sTitle._pwz : g_szDefaultTitle );
|
|
newpos = 0;
|
|
}
|
|
|
|
SendDlgItemMessage( hwndDlg, IDC_PROGRESSBAR, PBM_SETPOS, newpos, 0 );
|
|
|
|
SetWindowText( GetDlgItem( hwndDlg, IDC_PROGRESSINFO ), szProgress );
|
|
ShowWindow( GetDlgItem( hwndDlg, IDC_PROGRESSINFO ), SW_SHOW );
|
|
EnableWindow( GetDlgItem( hwndDlg, IDC_PROGRESSINFOTXT ), TRUE );
|
|
SetWindowText( hwndDlg, szTitle );
|
|
|
|
}
|
|
|
|
{
|
|
|
|
// Only enable the finish button if the job is finished.
|
|
// ADRIAANC EnableWindow( GetDlgItem( hwndDlg, IDC_FINISH ), ( state == BG_JOB_STATE_TRANSFERRED ) );
|
|
EnableWindow( GetDlgItem( hwndDlg, IDC_FINISH ), ( state == BG_JOB_STATE_ACKNOWLEDGED ) );
|
|
|
|
// felixybc BUGBUG: CANCEL is not allowed when the job is done
|
|
// - should hold off ACK-ing that job until user clicks FINISH so that it can still be canceled at 100%?
|
|
EnableWindow( GetDlgItem( hwndDlg, IDC_CANCEL ), ( state != BG_JOB_STATE_ACKNOWLEDGED && state != BG_JOB_STATE_CANCELLED ) );
|
|
|
|
// Only enable the suspend button if the job is not finished or transferred
|
|
BOOL EnableSuspend =
|
|
( state != BG_JOB_STATE_SUSPENDED ) && ( state != BG_JOB_STATE_TRANSFERRED ) && (state != BG_JOB_STATE_ACKNOWLEDGED);
|
|
EnableWindow( GetDlgItem( hwndDlg, IDC_SUSPEND ), EnableSuspend );
|
|
|
|
// Only enable the resume button if the job is suspended
|
|
BOOL EnableResume = ( BG_JOB_STATE_SUSPENDED == state );
|
|
EnableWindow( GetDlgItem( hwndDlg, IDC_RESUME ), EnableResume );
|
|
|
|
// Alert the user when something important happens
|
|
// such as the job completes or a unrecoverable error occurs
|
|
if ( BG_JOB_STATE_ERROR == state &&
|
|
BG_JOB_STATE_ERROR != prevstate )
|
|
SignalAlert( hwndDlg, MB_ICONEXCLAMATION );
|
|
|
|
}
|
|
|
|
|
|
{
|
|
// update the error message
|
|
// BUGBUG - release the error interface.
|
|
IBackgroundCopyError *pError;
|
|
HRESULT Hr = _pJob->GetError( &pError );
|
|
|
|
if ( FAILED(Hr) )
|
|
{
|
|
ShowWindow( GetDlgItem( hwndDlg, IDC_ERRORMSG ), SW_HIDE );
|
|
EnableWindow( GetDlgItem( hwndDlg, IDC_ERRORMSGTXT ), FALSE );
|
|
}
|
|
else
|
|
{
|
|
|
|
WCHAR* pszDescription = NULL;
|
|
WCHAR* pszContext = NULL;
|
|
SIZE_T SizeRequired = 0;
|
|
|
|
// If these APIs fail, we should get back
|
|
// a NULL string. So everything should be harmless.
|
|
|
|
pError->GetErrorDescription(
|
|
LANGIDFROMLCID( GetThreadLocale() ),
|
|
&pszDescription );
|
|
pError->GetErrorContextDescription(
|
|
LANGIDFROMLCID( GetThreadLocale() ),
|
|
&pszContext );
|
|
SAFERELEASE(pError);
|
|
|
|
if ( pszDescription )
|
|
SizeRequired += wcslen( pszDescription );
|
|
if ( pszContext )
|
|
SizeRequired += wcslen( pszContext );
|
|
|
|
WCHAR* pszFullText = (WCHAR*)_alloca((SizeRequired + 1) * sizeof(WCHAR));
|
|
*pszFullText = L'\0';
|
|
|
|
if ( pszDescription )
|
|
wcscpy( pszFullText, pszDescription );
|
|
if ( pszContext )
|
|
wcscat( pszFullText, pszContext );
|
|
CoTaskMemFree( pszDescription );
|
|
CoTaskMemFree( pszContext );
|
|
|
|
HWND hwndErrorText = GetDlgItem( hwndDlg, IDC_ERRORMSG );
|
|
SetWindowText( hwndErrorText, pszFullText );
|
|
ShowWindow( hwndErrorText, SW_SHOW );
|
|
EnableWindow( GetDlgItem( hwndDlg, IDC_ERRORMSGTXT ), TRUE );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
{
|
|
|
|
//
|
|
// This large block of text computes the average transfer rate
|
|
// and estimated completion time. This code has much
|
|
// room for improvement.
|
|
//
|
|
|
|
static BOOL HasRates = FALSE;
|
|
static UINT64 LastMeasurementTime;
|
|
static UINT64 LastMeasurementBytes;
|
|
static double LastMeasurementRate;
|
|
|
|
WCHAR szRateText[MAX_STRING];
|
|
BOOL EnableRate = FALSE;
|
|
|
|
if ( !( BG_JOB_STATE_QUEUED == state ) &&
|
|
!( BG_JOB_STATE_CONNECTING == state ) &&
|
|
!( BG_JOB_STATE_TRANSFERRING == state ) )
|
|
{
|
|
// If the job isn't running, then rate values won't
|
|
// make any sense. Don't display them.
|
|
HasRates = FALSE;
|
|
}
|
|
else
|
|
{
|
|
|
|
if ( !HasRates )
|
|
{
|
|
LastMeasurementTime = GetSystemTimeAsUINT64();
|
|
LastMeasurementBytes = progress.BytesTransferred;
|
|
LastMeasurementRate = 0;
|
|
HasRates = TRUE;
|
|
}
|
|
else
|
|
{
|
|
|
|
UINT64 CurrentTime = GetSystemTimeAsUINT64();
|
|
UINT64 NewTotalBytes = progress.BytesTransferred;
|
|
|
|
UINT64 NewTimeDiff = CurrentTime - LastMeasurementTime;
|
|
UINT64 NewBytesDiff = NewTotalBytes - LastMeasurementBytes;
|
|
double NewInstantRate = (double)(__int64)NewBytesDiff /
|
|
(double)(__int64)NewTimeDiff;
|
|
double NewAvgRate = (0.3 * LastMeasurementRate) +
|
|
(0.7 * NewInstantRate );
|
|
|
|
if ( !_finite(NewInstantRate) || !_finite(NewAvgRate) )
|
|
{
|
|
NewInstantRate = 0;
|
|
NewAvgRate = LastMeasurementRate;
|
|
}
|
|
|
|
LastMeasurementTime = CurrentTime;
|
|
LastMeasurementBytes = NewTotalBytes;
|
|
LastMeasurementRate = NewAvgRate;
|
|
|
|
// convert from FILETIME units to seconds
|
|
double NewDisplayRate = NewAvgRate * 10000000;
|
|
|
|
const WCHAR *pRateFormat = NULL;
|
|
UINT64 Rate = ScaleDownloadRate( NewDisplayRate, &pRateFormat );
|
|
wsprintf( szRateText, pRateFormat, Rate );
|
|
|
|
EnableRate = TRUE;
|
|
}
|
|
|
|
}
|
|
|
|
if (!EnableRate)
|
|
{
|
|
ShowWindow( GetDlgItem( hwndDlg, IDC_TRANSFERRATE ), SW_HIDE );
|
|
EnableWindow( GetDlgItem( hwndDlg, IDC_TRANSFERRATETXT ), FALSE );
|
|
}
|
|
else
|
|
{
|
|
SetWindowText( GetDlgItem( hwndDlg, IDC_TRANSFERRATE ), szRateText );
|
|
ShowWindow( GetDlgItem( hwndDlg, IDC_TRANSFERRATE ), SW_SHOW );
|
|
EnableWindow( GetDlgItem( hwndDlg, IDC_TRANSFERRATETXT ), TRUE );
|
|
}
|
|
|
|
BOOL EnableEstimate = FALSE;
|
|
WCHAR szEstimateText[MAX_STRING];
|
|
|
|
if ( EnableRate )
|
|
{
|
|
|
|
if ( progress.BytesTotal != 0 &&
|
|
progress.BytesTotal != BG_SIZE_UNKNOWN )
|
|
{
|
|
|
|
double TimeRemaining =
|
|
( (__int64)progress.BytesTotal - (__int64)LastMeasurementBytes ) / LastMeasurementRate;
|
|
|
|
// convert from FILETIME units to seconds
|
|
TimeRemaining = TimeRemaining / 10000000.0;
|
|
|
|
static const double SecsPer30Days = 60.0 * 60.0 * 24.0 * 30.0;
|
|
|
|
// Don't estimate if estimate is larger then 30 days.
|
|
if ( TimeRemaining < SecsPer30Days )
|
|
{
|
|
|
|
const WCHAR *pFormat = NULL;
|
|
UINT64 Time = ScaleDownloadEstimate( TimeRemaining, &pFormat );
|
|
wsprintf( szEstimateText, pFormat, Time );
|
|
EnableEstimate = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!EnableEstimate)
|
|
{
|
|
ShowWindow( GetDlgItem( hwndDlg, IDC_ESTIMATEDTIME ), SW_HIDE );
|
|
EnableWindow( GetDlgItem( hwndDlg, IDC_ESTIMATEDTIMETXT ), FALSE );
|
|
}
|
|
else
|
|
{
|
|
SetWindowText( GetDlgItem( hwndDlg, IDC_ESTIMATEDTIME ), szEstimateText );
|
|
ShowWindow( GetDlgItem( hwndDlg, IDC_ESTIMATEDTIME ), SW_SHOW );
|
|
EnableWindow( GetDlgItem( hwndDlg, IDC_ESTIMATEDTIMETXT ), TRUE );
|
|
}
|
|
|
|
}
|
|
|
|
prevstate = state;
|
|
}
|
|
|
|
void
|
|
CDownloadDlg::InitDialog(
|
|
HWND hwndDlg
|
|
)
|
|
{
|
|
|
|
//
|
|
// Populate the priority list with priority descriptions
|
|
//
|
|
|
|
_hwndDlg = hwndDlg;
|
|
|
|
|
|
SendDlgItemMessage( hwndDlg, IDC_PROGRESSBAR, PBM_SETRANGE, 0, MAKELPARAM(0, 100) );
|
|
|
|
}
|
|
|
|
void CDownloadDlg::CheckHR( HWND hwnd, HRESULT Hr, bool bThrow )
|
|
{
|
|
//
|
|
// Provides automatic error code checking and dialog
|
|
// for generic system errors
|
|
//
|
|
|
|
if (SUCCEEDED(Hr))
|
|
return;
|
|
|
|
WCHAR * pszError = NULL;
|
|
|
|
if(FormatMessage(
|
|
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
|
|
NULL,
|
|
(DWORD)Hr,
|
|
LANGIDFROMLCID( GetThreadLocale() ),
|
|
(WCHAR*)&pszError,
|
|
0,
|
|
NULL ))
|
|
{
|
|
MessageBox( hwnd, pszError, GetString( IDS_ERRORBOXTITLE ),
|
|
MB_OK | MB_ICONSTOP | MB_APPLMODAL );
|
|
LocalFree( pszError );
|
|
}
|
|
if ( bThrow )
|
|
throw _com_error( Hr );
|
|
|
|
}
|
|
|
|
void CDownloadDlg::BITSCheckHR( HWND hwnd, HRESULT Hr, bool bThrow )
|
|
{
|
|
|
|
//
|
|
// Provides automatic error code checking and dialog
|
|
// for BITS specific errors
|
|
//
|
|
|
|
|
|
if (SUCCEEDED(Hr))
|
|
return;
|
|
|
|
WCHAR * pszError = NULL;
|
|
g_pBITSManager->GetErrorDescription(
|
|
Hr,
|
|
LANGIDFROMLCID( GetThreadLocale() ),
|
|
&pszError );
|
|
|
|
MessageBox( hwnd, pszError, GetString( IDS_ERRORBOXTITLE ),
|
|
MB_OK | MB_ICONSTOP | MB_APPLMODAL );
|
|
CoTaskMemFree( pszError );
|
|
|
|
if ( bThrow )
|
|
throw _com_error( Hr );
|
|
}
|
|
|
|
void
|
|
CDownloadDlg::DoCancel(
|
|
HWND hwndDlg,
|
|
bool PromptUser
|
|
)
|
|
{
|
|
|
|
//
|
|
// Handle all the operations required to cancel the job.
|
|
// This includes asking the user for confirmation.
|
|
//
|
|
|
|
/*
|
|
if ( PromptUser )
|
|
{
|
|
|
|
int Result =
|
|
MessageBox(
|
|
hwndDlg,
|
|
GetString( IDS_CANCELTEXT ),
|
|
GetString( IDS_CANCELCAPTION ),
|
|
MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2 | MB_APPLMODAL |
|
|
MB_SETFOREGROUND | MB_TOPMOST );
|
|
|
|
|
|
if ( IDYES != Result )
|
|
return;
|
|
|
|
}
|
|
*/
|
|
// try
|
|
{
|
|
// BITSCheckHR( hwndDlg, _pJob->Cancel(), false );//felixybc true );
|
|
}
|
|
// catch( _com_error Error )
|
|
{
|
|
// If we can't cancel for some unknown reason,
|
|
// don't exit
|
|
// return;
|
|
}
|
|
|
|
// DeleteStartupLink( g_JobId );
|
|
//felixybc ExitProcess( 0 );
|
|
//KillTimer(hwndDlg, 0);
|
|
PostMessage(hwndDlg, WM_CANCEL_DOWNLOAD, 0, 0);
|
|
}
|
|
|
|
void
|
|
CDownloadDlg::DoFinish(
|
|
HWND hwndDlg
|
|
)
|
|
{
|
|
|
|
//
|
|
// Handles all the necessary work to complete
|
|
// the download.
|
|
//
|
|
|
|
// try
|
|
{
|
|
// ADRIAANC
|
|
// BITSCheckHR( hwndDlg, _pJob->Complete(), true );
|
|
}
|
|
// catch( _com_error Error )
|
|
{
|
|
// If we can't finish/complete for some unknown reason,
|
|
// don't exit
|
|
// return;
|
|
}
|
|
|
|
// DeleteStartupLink( g_JobId );
|
|
// ExitProcess( 0 );
|
|
|
|
// Commit the bits and notify done.
|
|
//_pDownload->_pRootEmit->Commit(0);
|
|
//KillTimer(hwndDlg, 0);
|
|
PostMessage(hwndDlg, WM_FINISH_DOWNLOAD, 0, 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
void
|
|
CDownloadDlg::DoClose(
|
|
HWND hwndDlg
|
|
)
|
|
{
|
|
//
|
|
// Handles an attempt by the user to close the sample.
|
|
//
|
|
|
|
// Check to see if the download has finished,
|
|
// if so don't let the user exit.
|
|
|
|
BG_JOB_STATE state;
|
|
HRESULT hResult = _pJob->GetState( &state );
|
|
|
|
if (FAILED( hResult ))
|
|
{
|
|
BITSCheckHR( hwndDlg, hResult, false );
|
|
return;
|
|
}
|
|
|
|
// BUGBUG: should also check for BG_JOB_STATE_ACKNOWLEDGED and don't call DoCancel then
|
|
// _pJob->Cancel();
|
|
DoCancel( hwndDlg, false );
|
|
return;
|
|
|
|
/*
|
|
if ( BG_JOB_STATE_ERROR == state ||
|
|
BG_JOB_STATE_TRANSFERRED == state )
|
|
{
|
|
|
|
MessageBox(
|
|
hwndDlg,
|
|
GetString( IDS_ALREADYFINISHED ),
|
|
GetString( IDS_ALREADYFINISHEDCAPTION ),
|
|
MB_OK | MB_ICONERROR | MB_DEFBUTTON1 | MB_APPLMODAL |
|
|
MB_SETFOREGROUND | MB_TOPMOST );
|
|
|
|
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Inform the user that he selected close and ask
|
|
// confirm the intention to exit. Explain that the job
|
|
// will be canceled.
|
|
|
|
int Result =
|
|
MessageBox(
|
|
hwndDlg,
|
|
GetString( IDS_CLOSETEXT ),
|
|
GetString( IDS_CLOSECAPTION ),
|
|
MB_OKCANCEL | MB_ICONWARNING | MB_DEFBUTTON2 | MB_APPLMODAL |
|
|
MB_SETFOREGROUND | MB_TOPMOST );
|
|
|
|
if ( IDOK == Result )
|
|
{
|
|
|
|
// User confirmed the cancel, just do it.
|
|
|
|
DoCancel( hwndDlg, false );
|
|
return;
|
|
}
|
|
|
|
// The user didn't really want to exit, so ignore him
|
|
else
|
|
return;
|
|
*/
|
|
|
|
}
|
|
|
|
void
|
|
CDownloadDlg::HandleTimerTick( HWND hwndDlg )
|
|
{
|
|
// The timer fired. Update dialog.
|
|
UpdateDialog( hwndDlg );
|
|
|
|
if (_eState == DOWNLOADDLG_STATE_ALL_DONE)
|
|
{
|
|
static bool bHasTip = FALSE;
|
|
if (!g_IsMinimized)
|
|
{
|
|
// not minimized, continue to run app
|
|
DoFinish(hwndDlg);
|
|
}
|
|
else
|
|
{
|
|
if (!bHasTip)
|
|
{
|
|
// minimized, pop up buttom tip
|
|
NOTIFYICONDATA tnid = {0};
|
|
|
|
// ignore all error
|
|
|
|
tnid.cbSize = sizeof(NOTIFYICONDATA);
|
|
tnid.hWnd = hwndDlg;
|
|
tnid.uID = TRAY_UID;
|
|
tnid.uFlags = NIF_INFO;
|
|
|
|
tnid.uTimeout = 20000; // in milliseconds
|
|
tnid.dwInfoFlags = NIIF_INFO;
|
|
lstrcpyn(tnid.szInfoTitle, L"ClickOnce application ready!", (sizeof(tnid.szInfoTitle)/sizeof(tnid.szInfoTitle[0])));
|
|
lstrcpyn(tnid.szInfo, L"Click this notification icon to start. You can also find this new application on your Start Menu, Programs listing.", (sizeof(tnid.szInfo)/sizeof(tnid.szInfo[0])));
|
|
|
|
Shell_NotifyIcon(NIM_MODIFY, &tnid);
|
|
bHasTip = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
HRESULT
|
|
CDownloadDlg::HandleUpdate()
|
|
{
|
|
|
|
// Handle a update request, batching the update if needed
|
|
DWORD dwRefresh = 0;
|
|
dwRefresh = InterlockedIncrement(&g_RefreshOnTimer);
|
|
if (dwRefresh == 1)
|
|
{
|
|
// First time in; fire off timer and update the dialog.
|
|
UpdateDialog(_hwndDlg);
|
|
SendMessage(_hwndDlg, WM_SETCALLBACKTIMER, 0, 0);
|
|
}
|
|
else
|
|
{
|
|
// We've already received the first callback.
|
|
// Let the timer do any further work.
|
|
InterlockedDecrement(&g_RefreshOnTimer);
|
|
}
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
INT_PTR CALLBACK DialogProc(
|
|
HWND hwndDlg, // handle to dialog box
|
|
UINT uMsg, // message
|
|
WPARAM wParam, // first message parameter
|
|
LPARAM lParam // second message parameter
|
|
)
|
|
{
|
|
//
|
|
// Dialog proc for main dialog window
|
|
//
|
|
static CDownloadDlg *pDlg = NULL;
|
|
|
|
switch( uMsg )
|
|
{
|
|
|
|
case WM_DESTROY:
|
|
{
|
|
Animate_Stop(GetDlgItem(hwndDlg, IDC_ANIMATE_DOWNLOAD));
|
|
Animate_Close(GetDlgItem(hwndDlg, IDC_ANIMATE_DOWNLOAD));
|
|
return FALSE;
|
|
}
|
|
case WM_INITDIALOG:
|
|
pDlg = (CDownloadDlg*) lParam;
|
|
pDlg->InitDialog(hwndDlg);
|
|
ShowWindow(GetDlgItem(hwndDlg, IDC_ANIMATE_DOWNLOAD), SW_SHOW);
|
|
Animate_Open(GetDlgItem(hwndDlg, IDC_ANIMATE_DOWNLOAD), MAKEINTRESOURCE(IDA_DOWNLOADING));
|
|
Animate_Play(GetDlgItem(hwndDlg, IDC_ANIMATE_DOWNLOAD), 0, -1, -1);
|
|
return TRUE;
|
|
|
|
case WM_SETCALLBACKTIMER:
|
|
SetTimer(hwndDlg, 1, 500, NULL );
|
|
return TRUE;
|
|
|
|
case WM_TIMER:
|
|
pDlg->HandleTimerTick( hwndDlg );
|
|
return TRUE;
|
|
|
|
|
|
case WM_CLOSE:
|
|
pDlg->DoClose( hwndDlg );
|
|
return TRUE;
|
|
|
|
case WM_COMMAND:
|
|
|
|
switch( LOWORD( wParam ) )
|
|
{
|
|
|
|
case IDC_RESUME:
|
|
pDlg->BITSCheckHR( hwndDlg, pDlg->_pJob->Resume(), false );
|
|
return TRUE;
|
|
|
|
case IDC_SUSPEND:
|
|
pDlg->BITSCheckHR( hwndDlg, pDlg->_pJob->Suspend(), false );
|
|
return TRUE;
|
|
|
|
case IDC_CANCEL:
|
|
pDlg->DoCancel( hwndDlg, true );
|
|
return TRUE;
|
|
|
|
case IDC_FINISH:
|
|
pDlg->DoFinish( hwndDlg );
|
|
return TRUE;
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
case WM_SIZE:
|
|
|
|
if (wParam == SIZE_MINIMIZED)
|
|
{
|
|
HICON hIcon = LoadIcon(g_hInst, MAKEINTRESOURCE(IDI_ICON));
|
|
|
|
if (hIcon != NULL)
|
|
{
|
|
NOTIFYICONDATA tnid = {0};
|
|
|
|
// ignore all error (user will not be able to restore dialog in some cases)
|
|
|
|
tnid.cbSize = sizeof(NOTIFYICONDATA);
|
|
tnid.hWnd = hwndDlg;
|
|
tnid.uID = TRAY_UID;
|
|
tnid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
|
|
tnid.uCallbackMessage = MYWM_NOTIFYICON;
|
|
tnid.hIcon = hIcon;
|
|
lstrcpyn(tnid.szTip, L"Downloading ClickOnce application.", (sizeof(tnid.szTip)/sizeof(tnid.szTip[0]))); // set tip to file name
|
|
Shell_NotifyIcon(NIM_ADD, &tnid);
|
|
|
|
DestroyIcon(hIcon);
|
|
|
|
// set shell32 v5 behavior
|
|
tnid.uVersion = NOTIFYICON_VERSION;
|
|
tnid.uFlags = 0;
|
|
Shell_NotifyIcon(NIM_SETVERSION, &tnid);
|
|
|
|
// hide window
|
|
ShowWindow( hwndDlg, SW_HIDE );
|
|
g_IsMinimized = TRUE;
|
|
return TRUE;
|
|
}
|
|
// else error loading icon - ignore
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
case MYWM_NOTIFYICON:
|
|
if (g_IsMinimized && (lParam == WM_CONTEXTMENU || lParam == NIN_KEYSELECT || lParam == NIN_SELECT ))
|
|
{
|
|
// if the notification icon is clicked on
|
|
|
|
NOTIFYICONDATA tnid = {0};
|
|
|
|
// show window
|
|
ShowWindow( hwndDlg, SW_RESTORE );
|
|
g_IsMinimized = FALSE;
|
|
|
|
// remove icon from tray
|
|
tnid.cbSize = sizeof(NOTIFYICONDATA);
|
|
tnid.hWnd = hwndDlg;
|
|
tnid.uID = TRAY_UID;
|
|
tnid.uFlags = 0;
|
|
Shell_NotifyIcon(NIM_DELETE, &tnid);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CDownloadDlg::CreateUI( int nShowCmd )
|
|
{
|
|
DWORD dwError = 0;
|
|
//
|
|
// Creates the dialog box for the sample.
|
|
//
|
|
InitCommonControls();
|
|
_hwndDlg =
|
|
CreateDialogParam(
|
|
g_hInst,
|
|
MAKEINTRESOURCE(IDD_DIALOG),
|
|
NULL,
|
|
DialogProc,
|
|
(LPARAM) (this));
|
|
|
|
if (!_hwndDlg)
|
|
{
|
|
dwError = GetLastError();
|
|
return HRESULT_FROM_WIN32(dwError);
|
|
}
|
|
|
|
ShowWindow(_hwndDlg, nShowCmd);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
void CDownloadDlg::ResumeJob(
|
|
WCHAR* szJobGUID,
|
|
WCHAR* szJobFileName
|
|
)
|
|
{
|
|
|
|
//
|
|
// Resume the display on an existing job
|
|
//
|
|
|
|
// try
|
|
{
|
|
CheckHR( NULL, IIDFromString( szJobGUID, &g_JobId ), true );
|
|
|
|
CheckHR( NULL,
|
|
CoCreateInstance( CLSID_BackgroundCopyManager,
|
|
NULL,
|
|
CLSCTX_LOCAL_SERVER,
|
|
IID_IBackgroundCopyManager,
|
|
(void**)&g_pBITSManager ), true );
|
|
|
|
BITSCheckHR( NULL, g_pBITSManager->GetJob( g_JobId, &_pJob ), true );
|
|
|
|
// BUGBUG - bits dialog class doesn't know about callbacks - adriaanc
|
|
|
|
// BITSCheckHR( NULL,
|
|
// _pJob->SetNotifyInterface( (IBackgroundCopyCallback*)&g_Callback ),
|
|
// true );
|
|
|
|
BITSCheckHR( NULL, _pJob->SetNotifyFlags( BG_NOTIFY_JOB_MODIFICATION ), true );
|
|
|
|
ShowWindow(_hwndDlg, SW_MINIMIZE );
|
|
HandleUpdate();
|
|
}
|
|
/*
|
|
catch(_com_error error )
|
|
{
|
|
ExitProcess( error.Error() );
|
|
}
|
|
*/
|
|
}
|
|
|
|
void CDownloadDlg::SetJob(IBackgroundCopyJob *pJob)
|
|
{
|
|
SAFERELEASE(_pJob);
|
|
_pJob = pJob;
|
|
_pJob->AddRef();
|
|
}
|
|
void CDownloadDlg::SetDlgState(DOWNLOADDLG_STATE eState)
|
|
{
|
|
_eState = eState;
|
|
}
|
|
|
|
|
|
HRESULT CDownloadDlg::SetDlgTitle(LPCWSTR pwzTitle)
|
|
{
|
|
return _sTitle.Assign((LPWSTR)pwzTitle);
|
|
}
|
|
|