1
1
Fork 0
mirror of https://github.com/pbatard/rufus.git synced 2024-08-14 23:57:05 +00:00

[ui] Almost there: Check for application update (part 7)

* Add an abort during download
* Add automated launching of the new version
* Make DownloadFile() more generic with regards to progress indicators
This commit is contained in:
Pete Batard 2012-12-06 01:40:44 +00:00
parent 25e999ded9
commit b315805fa4
6 changed files with 182 additions and 83 deletions

View file

@ -42,7 +42,8 @@
/* Globals */
DWORD error_code;
static DWORD error_code;
static BOOL update_check_in_progress = FALSE;
/* MinGW is missing some of those */
#if !defined(ERROR_INTERNET_DISCONNECTED)
@ -232,9 +233,13 @@ const char* WinInetErrorString(void)
/*
* Download a file from an URL
* Mostly taken from http://support.microsoft.com/kb/234913
* If hProgressDialog is not NULL, this function will send INIT and EXIT messages
* to the dialog in question, with WPARAM being set to nonzero for EXIT on success
* and also attempt to indicate progress using an IDC_PROGRESS control
*/
BOOL DownloadFile(const char* url, const char* file, HWND hProgressDialog, HWND hProgressBar)
BOOL DownloadFile(const char* url, const char* file, HWND hProgressDialog)
{
HWND hProgressBar = NULL;
BOOL r = FALSE;
DWORD dwFlags, dwSize, dwDownloaded, dwTotalSize, dwStatus;
FILE* fd = NULL;
@ -246,16 +251,16 @@ BOOL DownloadFile(const char* url, const char* file, HWND hProgressDialog, HWND
hostname, sizeof(hostname), 0, NULL, 1, urlpath, sizeof(urlpath), NULL, 1};
int i;
// We reuse the ISO progress dialog for download progress
if (hProgressDialog != NULL)
SetWindowTextU(hProgressDialog, "Downloading file...");
if (hProgressDialog != NULL) {
// Use the progress control provided, if any
hProgressBar = GetDlgItem(hProgressDialog, IDC_PROGRESS);
if (hProgressBar != NULL) {
progress_style = GetWindowLong(hProgressBar, GWL_STYLE);
SetWindowLong(hProgressBar, GWL_STYLE, progress_style & (~PBS_MARQUEE));
SendMessage(hProgressBar, PBM_SETPOS, 0, 0);
}
if (hProgressDialog != NULL)
SendMessage(hProgressDialog, UM_ISO_INIT, 0, 0);
}
PrintStatus(0, FALSE, "Downloading %s: Connecting...\n", file);
uprintf("Downloading %s from %s\n", file, url);
@ -333,7 +338,7 @@ BOOL DownloadFile(const char* url, const char* file, HWND hProgressDialog, HWND
break;
dwSize += dwDownloaded;
SendMessage(hProgressBar, PBM_SETPOS, (WPARAM)(MAX_PROGRESS*((1.0f*dwSize)/(1.0f*dwTotalSize))), 0);
PrintStatus(0, FALSE, "Downloading %s: %0.1f%%\n", file, (100.0f*dwSize)/(1.0f*dwTotalSize));
PrintStatus(0, FALSE, "Downloading: %0.1f%%\n", (100.0f*dwSize)/(1.0f*dwTotalSize));
if (fwrite(buf, 1, dwDownloaded, fd) != dwDownloaded) {
uprintf("Error writing file %s: %s\n", file, WinInetErrorString());
goto out;
@ -351,7 +356,7 @@ BOOL DownloadFile(const char* url, const char* file, HWND hProgressDialog, HWND
out:
if (hProgressDialog != NULL)
SendMessage(hProgressDialog, UM_ISO_EXIT, 0, 0);
SendMessage(hProgressDialog, UM_ISO_EXIT, (WPARAM)r, 0);
if (fd != NULL) fclose(fd);
if (!r) {
_unlink(file);
@ -367,9 +372,29 @@ out:
return r;
}
// TODO: check that no format operation is occurring
DWORD WINAPI CheckForUpdatesThread(LPVOID param)
/* Threaded download */
static const char *_url, *_file;
static HWND _hProgressDialog;
static DWORD WINAPI _DownloadFileThread(LPVOID param)
{
ExitThread(DownloadFile(_url, _file, _hProgressDialog));
}
HANDLE DownloadFileThreaded(const char* url, const char* file, HWND hProgressDialog)
{
_url = url;
_file = file;
_hProgressDialog = hProgressDialog;
return CreateThread(NULL, 0, _DownloadFileThread, NULL, 0, NULL);
}
/*
* Background thread to check for updates
*/
static DWORD WINAPI CheckForUpdatesThread(LPVOID param)
{
BOOL force = (BOOL)param;
const char* server_url = RUFUS_URL "/";
int i, j, verbose = 2, verpos[4];
static char* archname[] = {"win_x86", "win_x64"};
@ -382,9 +407,11 @@ DWORD WINAPI CheckForUpdatesThread(LPVOID param)
hostname, sizeof(hostname), 0, NULL, 1, urlpath, sizeof(urlpath), NULL, 1};
SYSTEMTIME ServerTime, LocalTime;
FILETIME FileTime;
int64_t local_time, reg_time, server_time, update_interval;
int64_t local_time = 0, reg_time, server_time, update_interval;
BOOL is_x64 = FALSE, (__stdcall *pIsWow64Process)(HANDLE, PBOOL) = NULL;
update_check_in_progress = TRUE;
if (!force) {
// Wait a while before checking for updates
// TODO: Also check on inactivity
do {
@ -412,6 +439,7 @@ DWORD WINAPI CheckForUpdatesThread(LPVOID param)
vuprintf("Next update check in %" PRId64 " seconds.\n", reg_time + update_interval - local_time);
goto out;
}
}
PrintStatus(3000, FALSE, "Checking for " APPLICATION_NAME " updates...\n");
@ -505,12 +533,14 @@ DWORD WINAPI CheckForUpdatesThread(LPVOID param)
// Always store the server response time - the only clock we trust!
WriteRegistryKey64(REGKEY_LAST_UPDATE, server_time);
// Might as well let the user know
if (!force) {
if (local_time > server_time + 600) {
uprintf("Your local clock appears more than 10 minutes early - You ought to fix that...\n");
}
if (local_time < server_time - 600) {
uprintf("Your local clock appears more than 10 minutes late - you ought to fix that...\n");
}
}
dwSize = sizeof(dwTotalSize);
if (!HttpQueryInfoA(hRequest, HTTP_QUERY_CONTENT_LENGTH|HTTP_QUERY_FLAG_NUMBER, (LPVOID)&dwTotalSize, &dwSize, NULL))
@ -532,13 +562,18 @@ out:
if (hRequest) InternetCloseHandle(hRequest);
if (hConnection) InternetCloseHandle(hConnection);
if (hSession) InternetCloseHandle(hSession);
update_check_in_progress = FALSE;
ExitThread(0);
}
BOOL CheckForUpdates(void)
/*
* Initiate a check for updates. If force is true, ignore the wait period
*/
BOOL CheckForUpdates(BOOL force)
{
if (CreateThread(NULL, 0, CheckForUpdatesThread, NULL, 0, 0) == NULL) {
if (update_check_in_progress)
return FALSE;
if (CreateThread(NULL, 0, CheckForUpdatesThread, (LPVOID)force, 0, NULL) == NULL) {
uprintf("Unable to start check for updates thread");
return FALSE;
}

View file

@ -63,7 +63,6 @@
#define IDC_SELECT_ISO 1016
#define IDC_SET_ICON 1017
#define IDC_RUFUS_MBR 1018
#define IDC_ISO_PROGRESS 1019
#define IDC_ISO_FILENAME 1020
#define IDC_ISO_ABORT 1021
#define IDC_DISK_ID 1022
@ -89,7 +88,6 @@
#define IDC_INCLUDE_BETAS 1063
#define IDC_RELEASE_NOTES 1064
#define IDC_DOWNLOAD 1065
#define IDC_UPDATE_PROGRESS 1066
#define IDC_WEBSITE 1067
#define IDC_YOUR_VERSION 1068
#define IDC_LATEST_VERSION 1069

View file

@ -1199,7 +1199,7 @@ BOOL CALLBACK ISOProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) {
case WM_INITDIALOG:
hISOProgressBar = GetDlgItem(hDlg, IDC_ISO_PROGRESS);
hISOProgressBar = GetDlgItem(hDlg, IDC_PROGRESS);
hISOFileName = GetDlgItem(hDlg, IDC_ISO_FILENAME);
// Use maximum granularity for the progress bar
SendMessage(hISOProgressBar, PBM_SETRANGE, 0, MAX_PROGRESS<<16);
@ -1283,8 +1283,9 @@ DWORD WINAPI ISOScanThread(LPVOID param)
"Note: the file will be downloaded in the current directory. Once a\n"
"vesamenu.c32 exists there, it will always be used as replacement.\n", "Replace vesamenu.c32?",
MB_YESNO|MB_ICONWARNING) == IDYES) {
SetWindowTextU(hISOProgressDlg, "Downloading file...");
SetWindowTextU(hISOFileName, VESAMENU_URL);
if (DownloadFile(VESAMENU_URL, vesamenu_filename, hISOProgressDlg, hISOProgressBar))
if (DownloadFile(VESAMENU_URL, vesamenu_filename, hISOProgressDlg))
use_own_vesamenu = TRUE;
}
}
@ -1550,7 +1551,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
hLogDlg = CreateDialogA(hMainInstance, MAKEINTRESOURCEA(IDD_LOG), hDlg, (DLGPROC)LogProc);
InitDialog(hDlg);
GetUSBDevices(0);
CheckForUpdates();
CheckForUpdates(FALSE);
PostMessage(hMainDialog, UM_ISO_CREATE, 0, 0);
return (INT_PTR)TRUE;
@ -1774,7 +1775,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
selection_default = DT_ISO;
CreateTooltip(hSelectISO, iso_path, -1);
FormatStatus = 0;
if (CreateThread(NULL, 0, ISOScanThread, NULL, 0, 0) == NULL) {
if (CreateThread(NULL, 0, ISOScanThread, NULL, 0, NULL) == NULL) {
uprintf("Unable to start ISO scanning thread");
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_START_THREAD);
}
@ -1915,18 +1916,43 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
/*
* Application Entrypoint
*/
// If we ever need to process more than one commandline arguments, uncomment the following parts
// typedef int (CDECL *__wgetmainargs_t)(int*, wchar_t***, wchar_t***, int, int*);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
// int i, argc = 0, si = 0;
// char** argv = NULL;
// wchar_t **wenv, **wargv;
// PF_DECL(__wgetmainargs);
HANDLE mutex = NULL;
HWND hDlg = NULL;
MSG msg;
int wait_for_mutex = 0;
uprintf("*** RUFUS INIT ***\n");
// Prevent 2 applications from running at the same time
// PF_INIT(__wgetmainargs, msvcrt);
// if (pf__wgetmainargs != NULL) {
// pf__wgetmainargs(&argc, &wargv, &wenv, 1, &si);
// argv = (char**)calloc(argc, sizeof(char*));
// for (i=0; i<argc; i++) {
// argv[i] = wchar_to_utf8(wargv[i]);
// }
// } else {
// uprintf("unable to access UTF-16 args");
// }
// Prevent 2 applications from running at the same time, unless "/W" is passed as an option
// in which case we wait for the mutex to be relinquished
if ((safe_strlen(lpCmdLine)==2) && (lpCmdLine[0] == '/') && (lpCmdLine[1] == 'W'))
wait_for_mutex = 150; // Try to acquire the mutex for 15 seconds
mutex = CreateMutexA(NULL, TRUE, "Global/RUFUS");
if ((mutex == NULL) || (GetLastError() == ERROR_ALREADY_EXISTS))
{
for (;(wait_for_mutex>0) && (mutex != NULL) && (GetLastError() == ERROR_ALREADY_EXISTS); wait_for_mutex--) {
CloseHandle(mutex);
Sleep(100);
mutex = CreateMutexA(NULL, TRUE, "Global/RUFUS");
}
if ((mutex == NULL) || (GetLastError() == ERROR_ALREADY_EXISTS)) {
MessageBoxA(NULL, "Another Rufus application is running.\n"
"Please close the first application before running another one.",
"Other instance detected", MB_ICONSTOP);
@ -2009,6 +2035,11 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
DeleteRegistryKey(COMPANY_NAME);
continue;
}
// Alt-U => Force an update check
if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'U')) {
CheckForUpdates(TRUE);
continue;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}

View file

@ -262,10 +262,11 @@ extern BOOL SetAutorun(const char* path);
extern char* FileDialog(BOOL save, char* path, char* filename, char* ext, char* ext_desc);
extern BOOL FileIO(BOOL save, char* path, char** buffer, DWORD* size);
extern LONG GetEntryWidth(HWND hDropDown, const char* entry);
extern BOOL DownloadFile(const char* url, const char* file, HWND hProgressDialog, HWND hProgressBar);
extern BOOL DownloadFile(const char* url, const char* file, HWND hProgressDialog);
extern HANDLE DownloadFileThreaded(const char* url, const char* file, HWND hProgressDialog);
extern INT_PTR CALLBACK UpdateCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
extern BOOL SetUpdateCheck(void);
extern BOOL CheckForUpdates(void);
extern BOOL CheckForUpdates(BOOL force);
extern void DownloadNewVersion(void);
extern BOOL IsShown(HWND hDlg);
extern char* get_token_data_file(const char* token, const char* filename);

View file

@ -30,7 +30,7 @@ LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL
IDD_DIALOG DIALOGEX 12, 12, 206, 316
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_APPWINDOW
CAPTION "Rufus v1.2.1.203"
CAPTION "Rufus v1.2.1.204"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "Start",IDC_START,94,278,50,14
@ -85,7 +85,7 @@ CAPTION "Copying ISO files..."
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
LTEXT "Opening ISO image - please wait...",IDC_ISO_FILENAME,8,10,246,13,SS_PATHELLIPSIS
CONTROL "",IDC_ISO_PROGRESS,"msctls_progress32",WS_BORDER,7,26,247,8
CONTROL "",IDC_PROGRESS,"msctls_progress32",WS_BORDER,7,26,247,8
PUSHBUTTON "Cancel",IDC_ISO_ABORT,111,43,50,14
END
@ -146,7 +146,7 @@ BEGIN
PUSHBUTTON "Close",IDCANCEL,167,244,50,14,WS_GROUP
CONTROL "",IDC_RELEASE_NOTES,"RichEdit20W",ES_MULTILINE | ES_READONLY | WS_VSCROLL,15,77,352,88,WS_EX_STATICEDGE
DEFPUSHBUTTON "Download",IDC_DOWNLOAD,293,211,74,14,WS_GROUP
CONTROL "",IDC_UPDATE_PROGRESS,"msctls_progress32",WS_BORDER,15,212,270,11
CONTROL "",IDC_PROGRESS,"msctls_progress32",WS_BORDER,15,212,270,11
GROUPBOX "Release Notes",IDC_STATIC,8,63,367,111
LTEXT "A newer version is available. Please download the latest version!",IDC_STATIC,10,32,229,8
LTEXT "[...]",IDC_YOUR_VERSION,10,8,124,8
@ -272,8 +272,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,2,1,203
PRODUCTVERSION 1,2,1,203
FILEVERSION 1,2,1,204
PRODUCTVERSION 1,2,1,204
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -290,13 +290,13 @@ BEGIN
BEGIN
VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)"
VALUE "FileDescription", "Rufus"
VALUE "FileVersion", "1.2.1.203"
VALUE "FileVersion", "1.2.1.204"
VALUE "InternalName", "Rufus"
VALUE "LegalCopyright", "(c) 2011-2012 Pete Batard (GPL v3)"
VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html"
VALUE "OriginalFilename", "rufus.exe"
VALUE "ProductName", "Rufus"
VALUE "ProductVersion", "1.2.1.203"
VALUE "ProductVersion", "1.2.1.204"
END
END
BLOCK "VarFileInfo"

View file

@ -1189,8 +1189,6 @@ BOOL SetUpdateCheck(void)
((ReadRegistryKey32(REGKEY_UPDATE_INTERVAL) == -1) && enable_updates) )
WriteRegistryKey32(REGKEY_UPDATE_INTERVAL, 86400);
}
// TODO: check for lastcheck + interval & launch the background thread here?
// TODO: make sure we check for updates if user just accepted
return TRUE;
}
@ -1205,11 +1203,14 @@ INT_PTR CALLBACK NewVersionCallback(HWND hDlg, UINT message, WPARAM wParam, LPAR
ENLINK* enl;
wchar_t wUrl[256];
char tmp[128];
char* filepath;
static BOOL was_downloaded = FALSE;
static char* filepath = NULL;
static int download_status = 0;
STARTUPINFOA si;
PROCESS_INFORMATION pi;
switch (message) {
case WM_INITDIALOG:
download_status = 0;
SetTitleBarIcon(hDlg);
CenterDialog(hDlg);
hNotes = GetDlgItem(hDlg, IDC_RELEASE_NOTES);
@ -1224,7 +1225,9 @@ INT_PTR CALLBACK NewVersionCallback(HWND hDlg, UINT message, WPARAM wParam, LPAR
update.version[0], update.version[1], update.version[2], update.version[3]);
SetWindowTextA(GetDlgItem(hDlg, IDC_LATEST_VERSION), tmp);
SetWindowTextA(GetDlgItem(hDlg, IDC_DOWNLOAD_URL), update.download_url);
SendMessage(GetDlgItem(hDlg, IDC_UPDATE_PROGRESS), PBM_SETRANGE, 0, MAX_PROGRESS<<16);
SendMessage(GetDlgItem(hDlg, IDC_PROGRESS), PBM_SETRANGE, 0, MAX_PROGRESS<<16);
if (update.download_url == NULL)
EnableWindow(GetDlgItem(hDlg, IDC_DOWNLOAD), FALSE);
break;
case WM_NOTIFY:
switch (((LPNMHDR)lParam)->code) {
@ -1250,24 +1253,55 @@ INT_PTR CALLBACK NewVersionCallback(HWND hDlg, UINT message, WPARAM wParam, LPAR
switch (LOWORD(wParam)) {
case IDCLOSE:
case IDCANCEL:
safe_free(filepath);
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
case IDC_DOWNLOAD:
if (update.download_url == NULL)
return (INT_PTR)TRUE;
case IDC_DOWNLOAD: // Also doubles as abort and laucnh function
switch(download_status) {
case 1: // Abort
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_CANCELLED;
break;
case 2: // Launch newer version and close this one
for (i=(int)safe_strlen(filepath); (i>0)&&(filepath[i]!='\\'); i--);
safe_strcpy(tmp, sizeof(tmp), &filepath[i+1]);
safe_strcat(tmp, sizeof(tmp), " /W");
filepath[i] = 0;
memset(&si, 0, sizeof(si));
memset(&pi, 0, sizeof(pi));
si.cb = sizeof(si);
if (!CreateProcessU(NULL, tmp, NULL, NULL, FALSE, 0, NULL, filepath, &si, &pi)) {
PrintStatus(0, FALSE, "Failed to launch new application");
uprintf("Failed to launch new application: %s\n", WindowsErrorString());
} else {
PrintStatus(0, FALSE, "Launching new application...");
PostMessage(hDlg, WM_COMMAND, (WPARAM)IDCLOSE, 0);
PostMessage(hMainDialog, WM_CLOSE, 0, 0);
}
break;
default: // Download
for (i=(int)safe_strlen(update.download_url); (i>0)&&(update.download_url[i]!='/'); i--);
filepath = FileDialog(TRUE, app_dir, (char*)&update.download_url[i+1], "exe", "Application");
if (filepath != NULL) {
if (DownloadFile(update.download_url, filepath, NULL, GetDlgItem(hDlg, IDC_UPDATE_PROGRESS))) {
// TODO: create a thread and allow aborts + invoke a launcher when successful
SetWindowTextA(GetDlgItem(hDlg, IDC_DOWNLOAD), "Done");
EnableWindow(GetDlgItem(hDlg, IDC_DOWNLOAD), FALSE);
}
safe_free(filepath);
if (filepath != NULL)
DownloadFileThreaded(update.download_url, filepath, hDlg);
break;
}
return (INT_PTR)TRUE;
}
break;
case UM_ISO_INIT:
FormatStatus = 0;
download_status = 1;
SetWindowTextA(GetDlgItem(hDlg, IDC_DOWNLOAD), "Abort");
return (INT_PTR)TRUE;
case UM_ISO_EXIT:
if (wParam) {
SetWindowTextA(GetDlgItem(hDlg, IDC_DOWNLOAD), "Launch");
download_status = 2;
} else {
SetWindowTextA(GetDlgItem(hDlg, IDC_DOWNLOAD), "Download");
download_status = 0;
}
return (INT_PTR)TRUE;
}
return (INT_PTR)FALSE;
}