/* * New version notification dialog */ INT_PTR CALLBACK new_version_callback(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { int i; HWND hNotes; char tmp[128], cmdline[] = APPLICATION_NAME " /W"; static char* filepath = NULL; static int download_status = 0; STARTUPINFOA si; PROCESS_INFORMATION pi; HFONT hyperlink_font = NULL; EXT_DECL(exe_ext, NULL, __VA_GROUP__("*.exe"), __VA_GROUP__("Application")); switch (message) { case WM_INITDIALOG: download_status = 0; set_title_bar_icon(hDlg); center_dialog(hDlg); // Subclass the callback so that we can change the cursor original_wndproc = (WNDPROC)SetWindowLongPtr(hDlg, GWLP_WNDPROC, (LONG_PTR)subclass_callback); hNotes = GetDlgItem(hDlg, IDC_RELEASE_NOTES); SendMessage(hNotes, EM_AUTOURLDETECT, 1, 0); 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 (Build %d)", application_version[0], application_version[1], application_version[2]); SetWindowTextU(GetDlgItem(hDlg, IDC_YOUR_VERSION), tmp); safe_sprintf(tmp, sizeof(tmp), "Latest version: %d.%d (Build %d)", update.version[0], update.version[1], update.version[2]); SetWindowTextU(GetDlgItem(hDlg, IDC_LATEST_VERSION), tmp); SetWindowTextU(GetDlgItem(hDlg, IDC_DOWNLOAD_URL), update.download_url); SendMessage(GetDlgItem(hDlg, IDC_PROGRESS), PBM_SETRANGE, 0, (MAX_PROGRESS<<16) & 0xFFFF0000); if (update.download_url == NULL) EnableWindow(GetDlgItem(hDlg, IDC_DOWNLOAD), FALSE); break; case WM_CTLCOLORSTATIC: if ((HWND)lParam != GetDlgItem(hDlg, IDC_WEBSITE)) return FALSE; // Change the font for the hyperlink SetBkMode((HDC)wParam, TRANSPARENT); CreateStaticFont((HDC)wParam, &hyperlink_font); SelectObject((HDC)wParam, hyperlink_font); SetTextColor((HDC)wParam, RGB(0,0,125)); // DARK_BLUE return (INT_PTR)CreateSolidBrush(GetSysColor(COLOR_BTNFACE)); case WM_COMMAND: switch (LOWORD(wParam)) { case IDCLOSE: case IDCANCEL: if (download_status != 1) { safe_free(filepath); EndDialog(hDlg, LOWORD(wParam)); } return (INT_PTR)TRUE; case IDC_WEBSITE: ShellExecuteA(hDlg, "open", APPLICATION_URL, NULL, NULL, SW_SHOWNORMAL); break; case IDC_DOWNLOAD: // Also doubles as abort and launch function switch(download_status) { case 1: // Abort download_status = 0; error_code = ERROR_SEVERITY_ERROR|ERROR_CANCELLED; break; case 2: // Launch newer version and close this one Sleep(1000); // Add a delay on account of antivirus scanners memset(&si, 0, sizeof(si)); memset(&pi, 0, sizeof(pi)); si.cb = sizeof(si); if (!CreateProcessU(filepath, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) { print_status(0, TRUE, "Failed to launch new application"); dprintf("Failed to launch new application: %s\n", WindowsErrorString()); } else { print_status(0, FALSE, "Launching new application..."); PostMessage(hDlg, WM_COMMAND, (WPARAM)IDCLOSE, 0); PostMessage(hMainDialog, WM_CLOSE, 0, 0); } break; default: // Download if (update.download_url == NULL) { print_status(0, TRUE, "Could not get download URL\n"); break; } for (i=(int)strlen(update.download_url); (i>0)&&(update.download_url[i]!='/'); i--); exe_ext.filename = PathFindFileNameU(update.download_url); filepath = FileDialog(TRUE, app_dir, &exe_ext, OFN_NOCHANGEDIR); if (filepath == NULL) { print_status(0, TRUE, "Could not get save path\n"); break; } DownloadFileThreaded(update.download_url, filepath, hDlg); break; } return (INT_PTR)TRUE; } break; case UM_DOWNLOAD_INIT: error_code = 0; download_status = 1; SetWindowTextU(GetDlgItem(hDlg, IDC_DOWNLOAD), "Abort"); return (INT_PTR)TRUE; case UM_DOWNLOAD_EXIT: if (wParam) { SetWindowTextU(GetDlgItem(hDlg, IDC_DOWNLOAD), "Launch"); download_status = 2; } else { SetWindowTextU(GetDlgItem(hDlg, IDC_DOWNLOAD), "Download"); download_status = 0; } return (INT_PTR)TRUE; } return (INT_PTR)FALSE; }
// Run a console command, with optional redirection of stdout and stderr to our log DWORD RunCommand(const char* cmd, const char* dir, BOOL log) { DWORD ret, dwRead, dwAvail, dwPipeSize = 4096; STARTUPINFOA si = {0}; PROCESS_INFORMATION pi = {0}; HANDLE hOutputRead = INVALID_HANDLE_VALUE, hOutputWrite = INVALID_HANDLE_VALUE; HANDLE hDupOutputWrite = INVALID_HANDLE_VALUE; static char* output; si.cb = sizeof(si); if (log) { // NB: The size of a pipe is a suggestion, NOT an absolute guarantee // This means that you may get a pipe of 4K even if you requested 1K if (!CreatePipe(&hOutputRead, &hOutputWrite, NULL, dwPipeSize)) { ret = GetLastError(); uprintf("Could not set commandline pipe: %s", WindowsErrorString()); goto out; } // We need an inheritable pipe endpoint handle DuplicateHandle(GetCurrentProcess(), hOutputWrite, GetCurrentProcess(), &hDupOutputWrite, 0L, TRUE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS); si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; si.wShowWindow = SW_HIDE; si.hStdOutput = hDupOutputWrite; si.hStdError = hDupOutputWrite; } if (!CreateProcessU(NULL, cmd, NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW, NULL, dir, &si, &pi)) { ret = GetLastError(); uprintf("Unable to launch command '%s': %s", cmd, WindowsErrorString()); goto out; } if (log) { while (1) { // coverity[string_null] if (PeekNamedPipe(hOutputRead, NULL, dwPipeSize, NULL, &dwAvail, NULL)) { if (dwAvail != 0) { output = malloc(dwAvail + 1); if ((output != NULL) && (ReadFile(hOutputRead, output, dwAvail, &dwRead, NULL)) && (dwRead != 0)) { output[dwAvail] = 0; // coverity[tainted_string] uprintf(output); } free(output); } } if (WaitForSingleObject(pi.hProcess, 0) == WAIT_OBJECT_0) break; Sleep(100); }; } else { WaitForSingleObject(pi.hProcess, INFINITE); } if (!GetExitCodeProcess(pi.hProcess, &ret)) ret = GetLastError(); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); out: safe_closehandle(hDupOutputWrite); safe_closehandle(hOutputRead); return ret; }