[ui] Why, it's the check for application update (part 6)

* Use TortoiseGit inspired notification and download dialog
This commit is contained in:
Pete Batard 2012-12-05 01:53:10 +00:00
parent 4251e78fcd
commit 25e999ded9
8 changed files with 130 additions and 56 deletions

View File

@ -81,6 +81,10 @@ const char* additional_copyrights =
"http://winscp.net\\line\n"
"GNU General Public License (GPL) v3 or later\\line\n"
"\\line\n"
"Check for Update dialog inspired by TortoiseSVN & TortoiseGit\\line\n"
"http://tortoisesvn.net/, http://code.google.com/p/tortoisegit/\\line\n"
"GNU General Public License (GPL) v2 or later\\line\n"
"\\line\n"
"\\line\n"
"All other references can be found in the source.\\line\n}";

View File

@ -233,7 +233,7 @@ const char* WinInetErrorString(void)
* Download a file from an URL
* Mostly taken from http://support.microsoft.com/kb/234913
*/
BOOL DownloadFile(const char* url, const char* file)
BOOL DownloadFile(const char* url, const char* file, HWND hProgressDialog, HWND hProgressBar)
{
BOOL r = FALSE;
DWORD dwFlags, dwSize, dwDownloaded, dwTotalSize, dwStatus;
@ -247,12 +247,15 @@ BOOL DownloadFile(const char* url, const char* file)
int i;
// We reuse the ISO progress dialog for download progress
SetWindowTextU(hISOProgressDlg, "Downloading file...");
SetWindowTextU(hISOFileName, url);
progress_style = GetWindowLong(hISOProgressBar, GWL_STYLE);
SetWindowLong(hISOProgressBar, GWL_STYLE, progress_style & (~PBS_MARQUEE));
SendMessage(hISOProgressBar, PBM_SETPOS, 0, 0);
SendMessage(hISOProgressDlg, UM_ISO_INIT, 0, 0);
if (hProgressDialog != NULL)
SetWindowTextU(hProgressDialog, "Downloading file...");
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);
@ -329,7 +332,7 @@ BOOL DownloadFile(const char* url, const char* file)
if (!InternetReadFile(hRequest, buf, sizeof(buf), &dwDownloaded) || (dwDownloaded == 0))
break;
dwSize += dwDownloaded;
SendMessage(hISOProgressBar, PBM_SETPOS, (WPARAM)(MAX_PROGRESS*((1.0f*dwSize)/(1.0f*dwTotalSize))), 0);
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));
if (fwrite(buf, 1, dwDownloaded, fd) != dwDownloaded) {
uprintf("Error writing file %s: %s\n", file, WinInetErrorString());
@ -347,7 +350,8 @@ BOOL DownloadFile(const char* url, const char* file)
}
out:
SendMessage(hISOProgressDlg, UM_ISO_EXIT, 0, 0);
if (hProgressDialog != NULL)
SendMessage(hProgressDialog, UM_ISO_EXIT, 0, 0);
if (fd != NULL) fclose(fd);
if (!r) {
_unlink(file);

View File

@ -34,17 +34,6 @@
#include "rufus.h"
#include "msapi_utf8.h"
typedef struct {
uint8_t version[4];
char* type; // "release", "beta", "notice"
char* platform; // target platform ("windows", "linux", etc.)
char* platform_arch; // "x86", "x64", "arm"
char* platform_min; // minimum platform version required
char* download_url;
char* release_notes;
} rufus_update;
// Parse a line of UTF-16 text and return the data if it matches the 'token'
// The parsed line is of the form: [ ]token[ ]=[ ]["]data["][ ] and the line
// is modified by the parser
@ -214,14 +203,12 @@ static __inline char* get_sanitized_token_data_buffer(const char* token, unsigne
// NB: since this is remote data, and we're running elevated, it *IS* considered
// potentially malicious, even if it comes from a supposedly trusted server.
// len should be the size of the buffer, including the zero terminator
extern INT_PTR NewVersionDialog(const char* notes, const char* url);
void parse_update(char* buf, size_t len)
{
size_t i;
char *data = NULL, *token;
char allowed_rtf_chars[] = "abcdefghijklmnopqrstuvwxyz|~-_:*'";
char allowed_std_chars[] = "\r\n ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!\"$%^&+=<>(){}[].,;#@/?";
rufus_update update;
// strchr includes the NUL terminator in the search, so take care of backslash before NUL
if ((buf == NULL) || (len < 2) || (len > 65536) || (buf[len-1] != 0) || (buf[len-2] == '\\'))
@ -264,8 +251,7 @@ void parse_update(char* buf, size_t len)
while (iso_op_in_progress || format_op_in_progress) {
Sleep(3000);
}
NewVersionDialog(update.release_notes, update.download_url);
DownloadNewVersion();
// TODO: free all these strings!
}

View File

@ -89,6 +89,11 @@
#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
#define IDC_DOWNLOAD_URL 1070
// Next default values for new objects
//
@ -97,7 +102,7 @@
#define _APS_NO_MFC 1
#define _APS_NEXT_RESOURCE_VALUE 113
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1066
#define _APS_NEXT_CONTROL_VALUE 1071
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

View File

@ -106,6 +106,7 @@ HWND hISOProgressDlg = NULL, hLogDlg = NULL, hISOProgressBar, hISOFileName, hDis
BOOL use_own_vesamenu = FALSE, detect_fakes = TRUE, mbr_selected_by_user = FALSE;
BOOL iso_op_in_progress = FALSE, format_op_in_progress = FALSE;
int rufus_version[4];
RUFUS_UPDATE update;
extern char szStatusMessage[256];
static HANDLE format_thid = NULL;
@ -1282,7 +1283,8 @@ 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) {
if (DownloadFile(VESAMENU_URL, vesamenu_filename))
SetWindowTextU(hISOFileName, VESAMENU_URL);
if (DownloadFile(VESAMENU_URL, vesamenu_filename, hISOProgressDlg, hISOProgressBar))
use_own_vesamenu = TRUE;
}
}
@ -1371,7 +1373,6 @@ void InitDialog(HWND hDlg)
HINSTANCE hDllInst;
HDC hDC;
int i, i16, s16, s32;
HICON hSmallIcon, hBigIcon;
char tmp[128], *token;
#ifdef RUFUS_TEST
@ -1418,10 +1419,7 @@ void InitDialog(HWND hDlg)
s32 = 24;
// Create the title bar icon
hSmallIcon = (HICON)LoadImage(hMainInstance, MAKEINTRESOURCE(IDI_ICON), IMAGE_ICON, s16, s16, 0);
SendMessage (hDlg, WM_SETICON, ICON_SMALL, (LPARAM)hSmallIcon);
hBigIcon = (HICON)LoadImage(hMainInstance, MAKEINTRESOURCE(IDI_ICON), IMAGE_ICON, s32, s32, 0);
SendMessage (hDlg, WM_SETICON, ICON_BIG, (LPARAM)hBigIcon);
SetTitleBarIcon(hDlg);
GetWindowTextA(hDlg, tmp, sizeof(tmp));
// Count of Microsoft for making it more attractive to read a
// version using strtok() than using GetFileVersionInfo()

View File

@ -175,6 +175,16 @@ typedef struct {
BOOL uses_minint;
} RUFUS_ISO_REPORT;
typedef struct {
uint8_t version[4];
char* type; // "release", "beta", "notice"
char* platform; // target platform ("windows", "linux", etc.)
char* platform_arch; // "x86", "x64", "arm"
char* platform_min; // minimum platform version required
char* download_url;
char* release_notes;
} RUFUS_UPDATE;
/* Duplication of the TBPFLAG enum for Windows 7 taskbar progress */
typedef enum TASKBAR_PROGRESS_FLAGS
{
@ -215,6 +225,7 @@ extern RUFUS_ISO_REPORT iso_report;
extern int64_t iso_blocking_status;
extern int rufus_version[4];
extern enum WindowsVersion nWindowsVersion;
extern RUFUS_UPDATE update;
/*
* Shared prototypes
@ -227,6 +238,7 @@ extern void UpdateProgress(int op, float percent);
extern const char* StrError(DWORD error_code);
extern void CenterDialog(HWND hDlg);
extern void CreateStatusBar(void);
extern void SetTitleBarIcon(HWND hDlg);
extern BOOL CreateTaskbarList(void);
extern BOOL SetTaskbarProgressState(TASKBAR_PROGRESS_FLAGS tbpFlags);
extern BOOL SetTaskbarProgressValue(ULONGLONG ullCompleted, ULONGLONG ullTotal);
@ -250,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);
extern BOOL DownloadFile(const char* url, const char* file, HWND hProgressDialog, HWND hProgressBar);
extern INT_PTR CALLBACK UpdateCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
extern BOOL SetUpdateCheck(void);
extern BOOL CheckForUpdates(void);
extern void DownloadNewVersion(void);
extern BOOL IsShown(HWND hDlg);
extern char* get_token_data_file(const char* token, const char* filename);
extern char* get_token_data_buffer(const char* token, unsigned int n, const char* buffer, size_t buffer_size);

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.202"
CAPTION "Rufus v1.2.1.203"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "Start",IDC_START,94,278,50,14
@ -138,14 +138,23 @@ BEGIN
GROUPBOX "Settings",IDC_STATIC,46,145,173,45
END
IDD_NEW_VERSION DIALOGEX 0, 0, 287, 198
IDD_NEW_VERSION DIALOGEX 0, 0, 384, 268
STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "New version available"
CAPTION "Check For Updates - Rufus"
FONT 8, "Microsoft Sans Serif", 400, 0, 0x0
BEGIN
PUSHBUTTON "Close",IDCANCEL,229,177,50,14,WS_GROUP
CONTROL "",IDC_RELEASE_NOTES,"RichEdit20W",ES_MULTILINE | ES_READONLY | WS_VSCROLL,4,4,279,167,WS_EX_STATICEDGE
DEFPUSHBUTTON "Download",IDC_DOWNLOAD,173,177,50,14,WS_GROUP
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
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
LTEXT "[...]",IDC_LATEST_VERSION,10,19,129,8
CONTROL "<a href=""http://rufus.akeo.ie"">Click here to go to the website</a>",IDC_WEBSITE,
"SysLink",WS_TABSTOP,143,49,96,9
GROUPBOX "Download",IDC_STATIC,8,177,367,58
EDITTEXT IDC_DOWNLOAD_URL,15,191,351,13,ES_AUTOHSCROLL | ES_READONLY
END
@ -263,8 +272,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,2,1,202
PRODUCTVERSION 1,2,1,202
FILEVERSION 1,2,1,203
PRODUCTVERSION 1,2,1,203
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -281,13 +290,13 @@ BEGIN
BEGIN
VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)"
VALUE "FileDescription", "Rufus"
VALUE "FileVersion", "1.2.1.202"
VALUE "FileVersion", "1.2.1.203"
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.202"
VALUE "ProductVersion", "1.2.1.203"
END
END
BLOCK "VarFileInfo"

View File

@ -662,6 +662,7 @@ INT_PTR CALLBACK AboutCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM lP
switch (message) {
case WM_INITDIALOG:
SetTitleBarIcon(hDlg);
CenterDialog(hDlg);
if (reg_commcheck)
ShowWindow(GetDlgItem(hDlg, IDC_ABOUT_UPDATES), SW_SHOW);
@ -733,6 +734,7 @@ INT_PTR CALLBACK NotificationCallback(HWND hDlg, UINT message, WPARAM wParam, LP
case WM_INITDIALOG:
white_brush = CreateSolidBrush(WHITE);
separator_brush = CreateSolidBrush(SEPARATOR_GREY);
SetTitleBarIcon(hDlg);
CenterDialog(hDlg);
// Change the default icon
if (Static_SetIcon(GetDlgItem(hDlg, IDC_NOTIFICATION_ICON), hMessageIcon) == 0) {
@ -1118,6 +1120,7 @@ INT_PTR CALLBACK UpdateCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM l
switch (message) {
case WM_INITDIALOG:
SetTitleBarIcon(hDlg);
CenterDialog(hDlg);
hFrequency = GetDlgItem(hDlg, IDC_UPDATE_FREQUENCY);
IGNORE_RETVAL(ComboBox_SetItemData(hFrequency, ComboBox_AddStringU(hFrequency, "Disabled"), -1));
@ -1194,8 +1197,6 @@ BOOL SetUpdateCheck(void)
/*
* New version notification dialog
*/
static const char* release_notes;
static const char* download_url;
INT_PTR CALLBACK NewVersionCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
int i;
@ -1203,19 +1204,36 @@ INT_PTR CALLBACK NewVersionCallback(HWND hDlg, UINT message, WPARAM wParam, LPAR
TEXTRANGEW tr;
ENLINK* enl;
wchar_t wUrl[256];
char tmp[128];
char* filepath;
static BOOL was_downloaded = FALSE;
switch (message) {
case WM_INITDIALOG:
SetTitleBarIcon(hDlg);
CenterDialog(hDlg);
hNotes = GetDlgItem(hDlg, IDC_RELEASE_NOTES);
SendMessage(hNotes, EM_AUTOURLDETECT, 1, 0);
SendMessageA(hNotes, EM_SETTEXTEX, (WPARAM)&friggin_microsoft_unicode_amateurs, (LPARAM)release_notes);
SendMessageA(hNotes, EM_SETTEXTEX, (WPARAM)&friggin_microsoft_unicode_amateurs, (LPARAM)update.release_notes);
SendMessage(hNotes, EM_SETSEL, -1, -1);
SendMessage(hNotes, EM_SETEVENTMASK, 0, ENM_LINK);
safe_sprintf(tmp, sizeof(tmp), "Your version: %d.%d.%d (Build %d)",
rufus_version[0], rufus_version[1], rufus_version[2], rufus_version[3]);
SetWindowTextA(GetDlgItem(hDlg, IDC_YOUR_VERSION), tmp);
safe_sprintf(tmp, sizeof(tmp), "Latest version: %d.%d.%d (Build %d)",
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);
break;
case WM_NOTIFY:
switch (((LPNMHDR)lParam)->code) {
case NM_CLICK:
case NM_RETURN:
if (LOWORD(wParam) == IDC_WEBSITE) {
ShellExecuteA(hDlg, "open", RUFUS_URL, NULL, NULL, SW_SHOWNORMAL);
}
break;
case EN_LINK:
enl = (ENLINK*) lParam;
if (enl->msg == WM_LBUTTONUP) {
@ -1235,15 +1253,16 @@ INT_PTR CALLBACK NewVersionCallback(HWND hDlg, UINT message, WPARAM wParam, LPAR
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
case IDC_DOWNLOAD:
if (download_url == NULL)
if (update.download_url == NULL)
return (INT_PTR)TRUE;
for (i=(int)safe_strlen(download_url); (i>0)&&(download_url[i]!='/'); i--);
filepath = FileDialog(TRUE, app_dir, (char*)&download_url[i+1], "exe", "Application");
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) {
// TODO: Do we want to close the release notes once download starts?
// EndDialog(hDlg, 0);
// SetFocus(hMainDialog);
DownloadFile(download_url, filepath);
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);
}
return (INT_PTR)TRUE;
@ -1253,9 +1272,45 @@ INT_PTR CALLBACK NewVersionCallback(HWND hDlg, UINT message, WPARAM wParam, LPAR
return (INT_PTR)FALSE;
}
INT_PTR NewVersionDialog(const char* notes, const char* url)
void DownloadNewVersion(void)
{
release_notes = notes;
download_url = url;
return DialogBoxA(hMainInstance, MAKEINTRESOURCEA(IDD_NEW_VERSION), hMainDialog, NewVersionCallback);
DialogBoxA(hMainInstance, MAKEINTRESOURCEA(IDD_NEW_VERSION), hMainDialog, NewVersionCallback);
}
void SetTitleBarIcon(HWND hDlg)
{
HDC hDC;
int i16, s16, s32;
HICON hSmallIcon, hBigIcon;
// High DPI scaling
i16 = GetSystemMetrics(SM_CXSMICON);
hDC = GetDC(hDlg);
fScale = GetDeviceCaps(hDC, LOGPIXELSX) / 96.0f;
ReleaseDC(hDlg, hDC);
// Adjust icon size lookup
s16 = i16;
s32 = (int)(32.0f*fScale);
if (s16 >= 54)
s16 = 64;
else if (s16 >= 40)
s16 = 48;
else if (s16 >= 28)
s16 = 32;
else if (s16 >= 20)
s16 = 24;
if (s32 >= 54)
s32 = 64;
else if (s32 >= 40)
s32 = 48;
else if (s32 >= 28)
s32 = 32;
else if (s32 >= 20)
s32 = 24;
// Create the title bar icon
hSmallIcon = (HICON)LoadImage(hMainInstance, MAKEINTRESOURCE(IDI_ICON), IMAGE_ICON, s16, s16, 0);
SendMessage (hDlg, WM_SETICON, ICON_SMALL, (LPARAM)hSmallIcon);
hBigIcon = (HICON)LoadImage(hMainInstance, MAKEINTRESOURCE(IDI_ICON), IMAGE_ICON, s32, s32, 0);
SendMessage (hDlg, WM_SETICON, ICON_BIG, (LPARAM)hBigIcon);
}