Merge pull request #8217 from CookiePLMonster/windows-updater-improvements

Updates to auto-updater on Windows
This commit is contained in:
Connor McLaughlin 2019-07-23 10:39:04 +10:00 committed by GitHub
commit 8f6b237e11
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 75 additions and 49 deletions

View File

@ -95,6 +95,11 @@ void Updater::OnUpdateAvailable(const NewVersionInformation& info)
AutoUpdateChecker::RestartMode::RESTART_AFTER_UPDATE);
if (!later)
m_parent->close();
{
RunOnObject(m_parent, [this] {
m_parent->close();
return 0;
});
}
}
}

View File

@ -234,12 +234,16 @@ void AutoUpdateChecker::TriggerUpdate(const AutoUpdateChecker::NewVersionInforma
INFO_LOG(COMMON, "Updater command line: %s", command_line.c_str());
#ifdef _WIN32
STARTUPINFO sinfo = {sizeof(info)};
STARTUPINFO sinfo = {sizeof(sinfo)};
sinfo.dwFlags = STARTF_FORCEOFFFEEDBACK; // No hourglass cursor after starting the process.
PROCESS_INFORMATION pinfo;
if (!CreateProcessW(UTF8ToUTF16(reloc_updater_path).c_str(),
const_cast<wchar_t*>(UTF8ToUTF16(command_line).c_str()), nullptr, nullptr,
FALSE, 0, nullptr, nullptr, &sinfo, &pinfo))
if (CreateProcessW(UTF8ToUTF16(reloc_updater_path).c_str(), UTF8ToUTF16(command_line).data(),
nullptr, nullptr, FALSE, 0, nullptr, nullptr, &sinfo, &pinfo))
{
CloseHandle(pinfo.hThread);
CloseHandle(pinfo.hProcess);
}
else
{
ERROR_LOG(COMMON, "Could not start updater process: error=%d", GetLastError());
}

View File

@ -16,6 +16,7 @@
#include "Common/CommonPaths.h"
#include "Common/FileUtil.h"
#include "Common/HttpRequest.h"
#include "Common/ScopeGuard.h"
#include "Common/StringUtil.h"
#include "UpdaterCommon/UI.h"
@ -498,7 +499,6 @@ void FatalError(const std::string& message)
UI::SetVisible(true);
UI::Error(message);
UI::Stop();
}
std::optional<Manifest> ParseManifest(const std::string& manifest)
@ -686,6 +686,7 @@ bool RunUpdater(std::vector<std::string> args)
UI::Init();
UI::SetVisible(false);
Common::ScopeGuard ui_guard{[] { UI::Stop(); }};
Options opts = std::move(*maybe_opts);
if (opts.log_file)
@ -777,7 +778,5 @@ bool RunUpdater(std::vector<std::string> args)
UI::LaunchApplication(opts.binary_to_restart.value());
}
UI::Stop();
return true;
}

View File

@ -6,6 +6,7 @@
#include <ShlObj.h>
#include <shellapi.h>
#include <optional>
#include <string>
#include <vector>
@ -32,6 +33,28 @@ std::vector<std::string> CommandLineToUtf8Argv(PCWSTR command_line)
LocalFree(tokenized);
return argv;
}
std::optional<std::wstring> GetModuleName(HINSTANCE hInstance)
{
std::wstring name;
DWORD max_size = 50; // Start with space for 50 characters and grow if needed
name.resize(max_size);
DWORD size;
while ((size = GetModuleFileNameW(hInstance, name.data(), max_size)) == max_size &&
GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
max_size *= 2;
name.resize(max_size);
}
if (size == 0)
{
return {};
}
name.resize(size);
return name;
}
}; // namespace
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
@ -64,15 +87,15 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine
return 1;
}
wchar_t path[MAX_PATH];
if (GetModuleFileName(hInstance, path, sizeof(path)) == 0)
auto path = GetModuleName(hInstance);
if (!path)
{
MessageBox(nullptr, L"Failed to get updater filename.", L"Error", MB_ICONERROR);
return 1;
}
// Relaunch the updater as administrator
ShellExecuteW(nullptr, L"runas", path, pCmdLine, NULL, SW_SHOW);
ShellExecuteW(nullptr, L"runas", path->c_str(), pCmdLine, NULL, SW_SHOW);
return 0;
}

View File

@ -12,7 +12,6 @@
#include <ShObjIdl.h>
#include <shellapi.h>
#include "Common/Flag.h"
#include "Common/StringUtil.h"
namespace
@ -23,8 +22,7 @@ HWND total_progressbar_handle = nullptr;
HWND current_progressbar_handle = nullptr;
ITaskbarList3* taskbar_list = nullptr;
Common::Flag running;
Common::Flag request_stop;
std::thread ui_thread;
int GetWindowHeight(HWND hwnd)
{
@ -33,6 +31,17 @@ int GetWindowHeight(HWND hwnd)
return rect.bottom - rect.top;
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}; // namespace
constexpr int PROGRESSBAR_FLAGS = WS_VISIBLE | WS_CHILD | PBS_SMOOTH | PBS_SMOOTHREVERSE;
@ -46,7 +55,7 @@ bool InitWindow()
InitCommonControls();
WNDCLASS wndcl = {};
wndcl.lpfnWndProc = DefWindowProcW;
wndcl.lpfnWndProc = WindowProc;
wndcl.hbrBackground = GetSysColorBrush(COLOR_MENU);
wndcl.lpszClassName = L"UPDATER";
@ -124,14 +133,6 @@ bool InitWindow()
return true;
}
void Destroy()
{
DestroyWindow(window_handle);
DestroyWindow(label_handle);
DestroyWindow(total_progressbar_handle);
DestroyWindow(current_progressbar_handle);
}
void SetTotalMarquee(bool marquee)
{
SetWindowLong(total_progressbar_handle, GWL_STYLE,
@ -199,49 +200,40 @@ void SetDescription(const std::string& text)
void MessageLoop()
{
request_stop.Clear();
running.Set();
if (!InitWindow())
{
running.Clear();
MessageBox(nullptr, L"Window init failed!", L"", MB_ICONERROR);
// Destroying the parent (if exists) destroys all children windows
if (window_handle)
{
DestroyWindow(window_handle);
window_handle = nullptr;
}
return;
}
SetTotalMarquee(true);
SetCurrentMarquee(true);
while (!request_stop.IsSet())
MSG msg;
while (GetMessage(&msg, nullptr, 0, 0))
{
MSG msg;
while (PeekMessage(&msg, window_handle, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
running.Clear();
Destroy();
}
void Init()
{
std::thread thread(MessageLoop);
thread.detach();
ui_thread = std::thread(MessageLoop);
}
void Stop()
{
if (!running.IsSet())
return;
if (window_handle)
PostMessage(window_handle, WM_CLOSE, 0, 0);
request_stop.Set();
while (running.IsSet())
{
}
ui_thread.join();
}
void LaunchApplication(std::string path)
@ -259,8 +251,11 @@ void Sleep(int sleep)
void WaitForPID(u32 pid)
{
HANDLE parent_handle = OpenProcess(SYNCHRONIZE, FALSE, static_cast<DWORD>(pid));
WaitForSingleObject(parent_handle, INFINITE);
CloseHandle(parent_handle);
if (parent_handle)
{
WaitForSingleObject(parent_handle, INFINITE);
CloseHandle(parent_handle);
}
}
void SetVisible(bool visible)