Skip to content

Commit

Permalink
Updater: Implement UI
Browse files Browse the repository at this point in the history
  • Loading branch information
spycrab committed Mar 27, 2018
1 parent 075b48a commit e2aeda9
Show file tree
Hide file tree
Showing 5 changed files with 220 additions and 3 deletions.
43 changes: 41 additions & 2 deletions Source/Core/Updater/Main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <mbedtls/sha256.h>
#include <optional>
#include <shellapi.h>
#include <thread>
#include <vector>
#include <zlib.h>

Expand All @@ -23,6 +24,8 @@
#include "Common/HttpRequest.h"
#include "Common/StringUtil.h"

#include "Updater/UI.h"

namespace
{
// Public key used to verify update manifests.
Expand Down Expand Up @@ -286,6 +289,7 @@ std::optional<Manifest> ParseManifest(const std::string& manifest)
return parsed;
}

// Not showing a progress bar here because this part is just to quick
std::optional<Manifest> FetchAndParseManifest(const std::string& url)
{
Common::HttpRequest http;
Expand Down Expand Up @@ -469,13 +473,22 @@ Manifest::Hash ComputeHash(const std::string& contents)
return out;
}

int ProgressCallback(void*, double total, double now, double, double)
{
UI::SetProgress(static_cast<int>(now), static_cast<int>(total));
return 0;
}

bool DownloadContent(const std::vector<Manifest::Hash>& to_download,
const std::string& content_base_url, const std::string& temp_path)
{
Common::HttpRequest req(std::chrono::seconds(30));
Common::HttpRequest req(std::chrono::seconds(30), ProgressCallback);

for (const auto& h : to_download)
{
std::string hash_filename = HexEncode(h.data(), h.size());
UI::SetDescription("Downloading " + hash_filename + "...");
UI::SetMarquee(false);

// Add slashes where needed.
std::string content_store_path = hash_filename;
Expand All @@ -484,10 +497,14 @@ bool DownloadContent(const std::vector<Manifest::Hash>& to_download,

std::string url = content_base_url + content_store_path;
fprintf(log_fp, "Downloading %s ...\n", url.c_str());

auto resp = req.Get(url);
if (!resp)
return false;

UI::SetMarquee(true);
UI::SetDescription("Verifying " + url + "...");

std::string contents(reinterpret_cast<char*>(resp->data()), resp->size());
std::optional<std::string> maybe_decompressed = GzipInflate(contents);
if (!maybe_decompressed)
Expand Down Expand Up @@ -631,9 +648,11 @@ void FatalError(const std::string& message)
MessageBox(nullptr,
(L"A fatal error occured and the updater cannot continue:\n " + wide_message).c_str(),
L"Error", MB_ICONERROR);

fprintf(log_fp, "%s\n", message.c_str());
}

UI::Stop();
}
} // namespace

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
Expand Down Expand Up @@ -671,6 +690,11 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine
fprintf(log_fp, "Completed! Proceeding with update.\n");
}

std::thread thread(UI::Loop);
thread.detach();

UI::SetDescription("Fetching and parsing manifests...");

Manifest this_manifest, next_manifest;
{
std::optional<Manifest> maybe_manifest = FetchAndParseManifest(opts.this_manifest_url);
Expand All @@ -690,6 +714,8 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine
next_manifest = std::move(*maybe_manifest);
}

UI::SetDescription("Computing what to do...");

TodoList todo = ComputeActionsToDo(this_manifest, next_manifest);
todo.Log();

Expand All @@ -698,16 +724,29 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine
return 1;
std::string temp_dir = std::move(*maybe_temp_dir);

UI::SetDescription("Performing Update...");

bool ok = PerformUpdate(todo, opts.install_base_path, opts.content_store_url, temp_dir);
if (!ok)
FatalError("Failed to apply the update.");

CleanUpTempDir(temp_dir, todo);

UI::ResetProgress();
UI::SetMarquee(false);
UI::SetProgress(100, 100);
UI::SetDescription("Done!");

// Let the user process that we are done.
Sleep(100);

if (opts.binary_to_restart)
{
ShellExecuteW(nullptr, L"open", UTF8ToUTF16(*opts.binary_to_restart).c_str(), L"", nullptr,
SW_SHOW);
}

UI::Stop();

return !ok;
}
151 changes: 151 additions & 0 deletions Source/Core/Updater/UI.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
// Copyright 2018 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.

#include "Updater/UI.h"

// Enable visual styles
#pragma comment(linker, "\"/manifestdependency:type='win32' \
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")

#include <CommCtrl.h>

#include <string>

#include "Common/Flag.h"
#include "Common/StringUtil.h"

namespace
{
HWND window_handle = nullptr;
HWND label_handle = nullptr;
HWND progressbar_handle = nullptr;

Common::Flag running;
Common::Flag request_stop;
}; // namespace

constexpr int PROGRESSBAR_FLAGS = WS_VISIBLE | WS_CHILD | PBS_SMOOTH | PBS_SMOOTHREVERSE;

namespace UI
{
bool Init()
{
InitCommonControls();

WNDCLASS wndcl = {};
wndcl.lpfnWndProc = DefWindowProcW;
wndcl.hbrBackground = GetSysColorBrush(COLOR_MENU);
wndcl.lpszClassName = L"UPDATER";

if (!RegisterClass(&wndcl))
return false;

window_handle =
CreateWindow(L"UPDATER", L"Dolphin Updater", WS_VISIBLE | WS_CLIPCHILDREN, CW_USEDEFAULT,
CW_USEDEFAULT, 500, 100, nullptr, nullptr, GetModuleHandle(nullptr), 0);

if (!window_handle)
return false;

label_handle = CreateWindow(L"STATIC", NULL, WS_VISIBLE | WS_CHILD, 5, 5, 500, 25, window_handle,
nullptr, nullptr, 0);

if (!label_handle)
return false;

// Get the default system font
NONCLIENTMETRICS metrics = {};
metrics.cbSize = sizeof(NONCLIENTMETRICS);

if (!SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(metrics), &metrics, 0))
return false;

SendMessage(label_handle, WM_SETFONT,
reinterpret_cast<WPARAM>(CreateFontIndirect(&metrics.lfMessageFont)), 0);

progressbar_handle = CreateWindow(PROGRESS_CLASS, NULL, PROGRESSBAR_FLAGS, 5, 25, 470, 25,
window_handle, nullptr, nullptr, 0);

if (!progressbar_handle)
return false;

return true;
}

void Destroy()
{
DestroyWindow(window_handle);
DestroyWindow(label_handle);
DestroyWindow(progressbar_handle);
}

void SetMarquee(bool marquee)
{
SetWindowLong(progressbar_handle, GWL_STYLE, PROGRESSBAR_FLAGS | (marquee ? PBS_MARQUEE : 0));
SendMessage(progressbar_handle, PBM_SETMARQUEE, marquee, 0);
}

void ResetProgress()
{
SendMessage(progressbar_handle, PBM_SETPOS, 0, 0);
SetMarquee(true);
}

void SetProgress(int current, int total)
{
SendMessage(progressbar_handle, PBM_SETRANGE32, 0, total);
SendMessage(progressbar_handle, PBM_SETPOS, current, 0);
}

void IncrementProgress(int amount)
{
SendMessage(progressbar_handle, PBM_DELTAPOS, amount, 0);
}

void SetDescription(const std::string& text)
{
SetWindowText(label_handle, UTF8ToUTF16(text).c_str());
}

void Loop()
{
request_stop.Clear();
running.Set();

if (!Init())
{
running.Clear();
MessageBox(nullptr, L"Window init failed!", L"", MB_ICONERROR);
}

SetMarquee(true);

while (!request_stop.IsSet())
{
MSG msg;
while (PeekMessage(&msg, window_handle, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}

running.Clear();

Destroy();
}

void Stop()
{
if (!running.IsSet())
return;

request_stop.Set();

while (running.IsSet())
{
}
}
}; // namespace UI
19 changes: 19 additions & 0 deletions Source/Core/Updater/UI.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright 2018 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.

#pragma once

#include <Windows.h>

namespace UI
{
void Loop();
void Stop();

void SetDescription(const std::string& text);
void SetMarquee(bool marquee);
void ResetProgress();
void SetProgress(int current, int total);
void IncrementProgress(int amount);
} // namespace UI
6 changes: 5 additions & 1 deletion Source/Core/Updater/Updater.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
<PropertyGroup />
<ItemDefinitionGroup>
<Link>
<AdditionalDependencies>iphlpapi.lib;winmm.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>iphlpapi.lib;winmm.lib;ws2_32.lib;comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
Expand All @@ -63,6 +63,7 @@
</ItemGroup>
<ItemGroup>
<ClCompile Include="Main.cpp" />
<ClCompile Include="UI.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
Expand All @@ -71,6 +72,9 @@
<ItemGroup>
<SourceFiles Include="$(TargetPath)" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="UI.h" />
</ItemGroup>
<Target Name="AfterBuild" Inputs="@(SourceFiles)" Outputs="@(SourceFiles -> '$(BinaryOutputDir)%(Filename)%(Extension)')">
<Message Text="Copy: @(SourceFiles) -&gt; $(BinaryOutputDir)" Importance="High" />
<Copy SourceFiles="@(SourceFiles)" DestinationFolder="$(BinaryOutputDir)" />
Expand Down
4 changes: 4 additions & 0 deletions Source/Core/Updater/Updater.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,9 @@
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="Main.cpp" />
<ClCompile Include="UI.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="UI.h" />
</ItemGroup>
</Project>

0 comments on commit e2aeda9

Please sign in to comment.