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
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); AutoUpdateChecker::RestartMode::RESTART_AFTER_UPDATE);
if (!later) if (!later)
{
RunOnObject(m_parent, [this] {
m_parent->close(); 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()); INFO_LOG(COMMON, "Updater command line: %s", command_line.c_str());
#ifdef _WIN32 #ifdef _WIN32
STARTUPINFO sinfo = {sizeof(info)}; STARTUPINFO sinfo = {sizeof(sinfo)};
sinfo.dwFlags = STARTF_FORCEOFFFEEDBACK; // No hourglass cursor after starting the process. sinfo.dwFlags = STARTF_FORCEOFFFEEDBACK; // No hourglass cursor after starting the process.
PROCESS_INFORMATION pinfo; PROCESS_INFORMATION pinfo;
if (!CreateProcessW(UTF8ToUTF16(reloc_updater_path).c_str(), if (CreateProcessW(UTF8ToUTF16(reloc_updater_path).c_str(), UTF8ToUTF16(command_line).data(),
const_cast<wchar_t*>(UTF8ToUTF16(command_line).c_str()), nullptr, nullptr, nullptr, nullptr, FALSE, 0, nullptr, nullptr, &sinfo, &pinfo))
FALSE, 0, nullptr, nullptr, &sinfo, &pinfo)) {
CloseHandle(pinfo.hThread);
CloseHandle(pinfo.hProcess);
}
else
{ {
ERROR_LOG(COMMON, "Could not start updater process: error=%d", GetLastError()); ERROR_LOG(COMMON, "Could not start updater process: error=%d", GetLastError());
} }

View File

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

View File

@ -6,6 +6,7 @@
#include <ShlObj.h> #include <ShlObj.h>
#include <shellapi.h> #include <shellapi.h>
#include <optional>
#include <string> #include <string>
#include <vector> #include <vector>
@ -32,6 +33,28 @@ std::vector<std::string> CommandLineToUtf8Argv(PCWSTR command_line)
LocalFree(tokenized); LocalFree(tokenized);
return argv; 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 }; // namespace
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) 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; return 1;
} }
wchar_t path[MAX_PATH]; auto path = GetModuleName(hInstance);
if (GetModuleFileName(hInstance, path, sizeof(path)) == 0) if (!path)
{ {
MessageBox(nullptr, L"Failed to get updater filename.", L"Error", MB_ICONERROR); MessageBox(nullptr, L"Failed to get updater filename.", L"Error", MB_ICONERROR);
return 1; return 1;
} }
// Relaunch the updater as administrator // 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; return 0;
} }

View File

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