From ef39098e280fd5266790392454912d2a13585957 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Fri, 11 Nov 2022 17:00:34 +0100 Subject: [PATCH] Refactor the component system --- src/client/component/arxan.cpp | 4 +- src/client/component/demonware.cpp | 2 +- src/client/component/exception.cpp | 2 +- src/client/component/splash.cpp | 196 +++++++------- src/client/component/steam_proxy.cpp | 4 +- src/client/component/updater.cpp | 6 +- src/client/loader/component_interface.hpp | 23 +- src/client/loader/component_loader.cpp | 303 +++++++++++----------- src/client/loader/component_loader.hpp | 46 ++-- src/client/main.cpp | 2 +- 10 files changed, 286 insertions(+), 302 deletions(-) diff --git a/src/client/component/arxan.cpp b/src/client/component/arxan.cpp index 5f55171e..8d0eaf90 100644 --- a/src/client/component/arxan.cpp +++ b/src/client/component/arxan.cpp @@ -757,9 +757,9 @@ namespace arxan //restore_debug_functions(); } - int priority() override + component_priority priority() const override { - return 9999; + return component_priority::arxan; } private: diff --git a/src/client/component/demonware.cpp b/src/client/component/demonware.cpp index efb5a570..3e31c656 100644 --- a/src/client/component/demonware.cpp +++ b/src/client/component/demonware.cpp @@ -444,7 +444,7 @@ namespace demonware class component final : public component_interface { public: - void pre_load() override + component() { udp_servers.create("stun.us.demonware.net"); udp_servers.create("stun.eu.demonware.net"); diff --git a/src/client/component/exception.cpp b/src/client/component/exception.cpp index a61244b6..eea66cde 100644 --- a/src/client/component/exception.cpp +++ b/src/client/component/exception.cpp @@ -196,7 +196,7 @@ namespace exception class component final : public component_interface { public: - void pre_load() override + component() { main_thread_id = GetCurrentThreadId(); SetUnhandledExceptionFilter(exception_filter); diff --git a/src/client/component/splash.cpp b/src/client/component/splash.cpp index 952b4e53..dd8aaa6b 100644 --- a/src/client/component/splash.cpp +++ b/src/client/component/splash.cpp @@ -10,7 +10,9 @@ namespace splash namespace { HWND window{}; + HANDLE image{}; std::thread window_thread{}; + std::atomic_bool join_safe{false}; HANDLE load_splash_image() { @@ -51,53 +53,73 @@ namespace splash window_thread.detach(); } } - } - class component final : public component_interface - { - public: - void pre_load() override + void show() { - this->image_ = load_splash_image(); + WNDCLASSA wnd_class; - enable_dpi_awareness(); - window_thread = std::thread([this] - { - this->draw(); - }); - } + const auto self = utils::nt::library::get_by_address(load_splash_image); - void pre_destroy() override - { - destroy_window(); - if (window_thread.joinable()) + wnd_class.style = CS_DROPSHADOW; + wnd_class.cbClsExtra = 0; + wnd_class.cbWndExtra = 0; + wnd_class.lpszMenuName = nullptr; + wnd_class.lpfnWndProc = DefWindowProcA; + wnd_class.hInstance = self; + wnd_class.hIcon = LoadIconA(self, MAKEINTRESOURCEA(ID_ICON)); + wnd_class.hCursor = LoadCursorA(nullptr, IDC_APPSTARTING); + wnd_class.hbrBackground = reinterpret_cast(6); + wnd_class.lpszClassName = "Black Ops III Splash Screen"; + + if (RegisterClassA(&wnd_class)) { - window_thread.detach(); + const auto x_pixels = GetSystemMetrics(SM_CXFULLSCREEN); + const auto y_pixels = GetSystemMetrics(SM_CYFULLSCREEN); + + if (image) + { + window = CreateWindowExA(WS_EX_APPWINDOW, "Black Ops III Splash Screen", "BOIII", + WS_POPUP | WS_SYSMENU, + (x_pixels - 320) / 2, (y_pixels - 100) / 2, 320, 100, nullptr, + nullptr, + self, nullptr); + + if (window) + { + auto* const image_window = CreateWindowExA(0, "Static", nullptr, WS_CHILD | WS_VISIBLE | 0xEu, + 0, 0, + 320, 100, window, nullptr, self, nullptr); + if (image_window) + { + RECT rect; + SendMessageA(image_window, 0x172u, 0, reinterpret_cast(image)); + GetWindowRect(image_window, &rect); + + const int width = rect.right - rect.left; + rect.left = (x_pixels - width) / 2; + + const int height = rect.bottom - rect.top; + rect.top = (y_pixels - height) / 2; + + rect.right = rect.left + width; + rect.bottom = rect.top + height; + AdjustWindowRect(&rect, WS_CHILD | WS_VISIBLE | 0xEu, 0); + SetWindowPos(window, nullptr, rect.left, rect.top, rect.right - rect.left, + rect.bottom - rect.top, SWP_NOZORDER); + + SetWindowRgn(window, + CreateRoundRectRgn(0, 0, rect.right - rect.left, rect.bottom - rect.top, 15, + 15), TRUE); + + ShowWindow(window, SW_SHOW); + UpdateWindow(window); + } + } + } } } - void post_unpack() override - { - destroy_window(); - } - - private: - std::atomic_bool join_safe_{false}; - HANDLE image_{}; - - void draw() - { - this->show(); - while (this->draw_frame()) - { - std::this_thread::sleep_for(1ms); - } - - window = nullptr; - UnregisterClassA("Black Ops III Splash Screen", utils::nt::library{}); - } - - bool draw_frame() const + bool draw_frame() { if (!window) { @@ -125,69 +147,45 @@ namespace splash return success; } - void show() + void draw() { - WNDCLASSA wnd_class; - - const auto self = utils::nt::library::get_by_address(load_splash_image); - - wnd_class.style = CS_DROPSHADOW; - wnd_class.cbClsExtra = 0; - wnd_class.cbWndExtra = 0; - wnd_class.lpszMenuName = nullptr; - wnd_class.lpfnWndProc = DefWindowProcA; - wnd_class.hInstance = self; - wnd_class.hIcon = LoadIconA(self, MAKEINTRESOURCEA(ID_ICON)); - wnd_class.hCursor = LoadCursorA(nullptr, IDC_APPSTARTING); - wnd_class.hbrBackground = reinterpret_cast(6); - wnd_class.lpszClassName = "Black Ops III Splash Screen"; - - if (RegisterClassA(&wnd_class)) + show(); + while (draw_frame()) { - const auto x_pixels = GetSystemMetrics(SM_CXFULLSCREEN); - const auto y_pixels = GetSystemMetrics(SM_CYFULLSCREEN); - - if (image_) - { - window = CreateWindowExA(WS_EX_APPWINDOW, "Black Ops III Splash Screen", "BOIII", - WS_POPUP | WS_SYSMENU, - (x_pixels - 320) / 2, (y_pixels - 100) / 2, 320, 100, nullptr, - nullptr, - self, nullptr); - - if (window) - { - auto* const image_window = CreateWindowExA(0, "Static", nullptr, WS_CHILD | WS_VISIBLE | 0xEu, - 0, 0, - 320, 100, window, nullptr, self, nullptr); - if (image_window) - { - RECT rect; - SendMessageA(image_window, 0x172u, 0, reinterpret_cast(image_)); - GetWindowRect(image_window, &rect); - - const int width = rect.right - rect.left; - rect.left = (x_pixels - width) / 2; - - const int height = rect.bottom - rect.top; - rect.top = (y_pixels - height) / 2; - - rect.right = rect.left + width; - rect.bottom = rect.top + height; - AdjustWindowRect(&rect, WS_CHILD | WS_VISIBLE | 0xEu, 0); - SetWindowPos(window, nullptr, rect.left, rect.top, rect.right - rect.left, - rect.bottom - rect.top, SWP_NOZORDER); - - SetWindowRgn(window, - CreateRoundRectRgn(0, 0, rect.right - rect.left, rect.bottom - rect.top, 15, - 15), TRUE); - - ShowWindow(window, SW_SHOW); - UpdateWindow(window); - } - } - } + std::this_thread::sleep_for(1ms); } + + window = nullptr; + UnregisterClassA("Black Ops III Splash Screen", utils::nt::library{}); + } + } + + class component final : public component_interface + { + public: + component() + { + enable_dpi_awareness(); + + image = load_splash_image(); + window_thread = std::thread([this] + { + draw(); + }); + } + + void pre_destroy() override + { + destroy_window(); + if (window_thread.joinable()) + { + window_thread.detach(); + } + } + + void post_unpack() override + { + destroy_window(); } }; diff --git a/src/client/component/steam_proxy.cpp b/src/client/component/steam_proxy.cpp index d060af45..02e767c0 100644 --- a/src/client/component/steam_proxy.cpp +++ b/src/client/component/steam_proxy.cpp @@ -235,9 +235,9 @@ namespace steam_proxy } } - int priority() override + component_priority priority() const override { - return 998; // Run after the updater + return component_priority::steam_proxy; } }; diff --git a/src/client/component/updater.cpp b/src/client/component/updater.cpp index f381d211..dc54ae01 100644 --- a/src/client/component/updater.cpp +++ b/src/client/component/updater.cpp @@ -130,7 +130,7 @@ namespace updater class component final : public component_interface { public: - void pre_load() override + component() { cleanup_update(); @@ -150,9 +150,9 @@ namespace updater join(); } - int priority() override + component_priority priority() const override { - return 999; + return component_priority::updater; } private: diff --git a/src/client/loader/component_interface.hpp b/src/client/loader/component_interface.hpp index 03b78993..73674add 100644 --- a/src/client/loader/component_interface.hpp +++ b/src/client/loader/component_interface.hpp @@ -1,14 +1,20 @@ #pragma once +enum class component_priority +{ + min = 0, + // must run after the updater + steam_proxy, + updater, + // must have the highest priority + arxan, +}; + class component_interface { public: virtual ~component_interface() = default; - virtual void pre_load() - { - } - virtual void post_load() { } @@ -21,13 +27,8 @@ public: { } - virtual bool is_supported() + virtual component_priority priority() const { - return true; - } - - virtual int priority() - { - return 0; + return component_priority::min; } }; diff --git a/src/client/loader/component_loader.cpp b/src/client/loader/component_loader.cpp index b0d1f281..614c9fd9 100644 --- a/src/client/loader/component_loader.cpp +++ b/src/client/loader/component_loader.cpp @@ -3,166 +3,165 @@ #include -void component_loader::register_component(std::unique_ptr&& component_) +namespace component_loader { - auto& components = get_components(); - components.push_back(std::move(component_)); - - std::ranges::stable_sort(components, [](const std::unique_ptr& a, - const std::unique_ptr& b) + namespace { - return a->priority() > b->priority(); - }); -} - -bool component_loader::pre_load() -{ - static auto res = [] - { - clean(); - - try + std::vector>& get_components() { - for (const auto& component_ : get_components()) + using component_vector = std::vector>; + using component_vector_container = std::unique_ptr> + ; + + static component_vector_container components(new component_vector, + [](const component_vector* component_vector) + { + pre_destroy(); + delete component_vector; + }); + + return *components; + } + + std::vector& get_registration_functors() + { + static std::vector functors; + return functors; + } + + void activate_component(std::unique_ptr component) + { + auto& components = get_components(); + components.push_back(std::move(component)); + + std::ranges::stable_sort(components, [](const std::unique_ptr& a, + const std::unique_ptr& b) { - component_->pre_load(); - } - } - catch (premature_shutdown_trigger&) - { - return false; - } - catch (const std::exception& e) - { - MessageBoxA(nullptr, e.what(), "Error", MB_ICONERROR); - return false; - } - - return true; - }(); - - return res; -} - -bool component_loader::post_load() -{ - static auto res = [] - { - clean(); - - try - { - for (const auto& component_ : get_components()) - { - component_->post_load(); - } - } - catch (premature_shutdown_trigger&) - { - return false; - } - catch (const std::exception& e) - { - MessageBoxA(nullptr, e.what(), "Error", MB_ICONERROR); - return false; - } - - return true; - }(); - - return res; -} - -void component_loader::post_unpack() -{ - static auto res = [] - { - clean(); - - try - { - for (const auto& component_ : get_components()) - { - component_->post_unpack(); - } - } - catch (const std::exception& e) - { - MessageBoxA(nullptr, e.what(), "Error", MB_ICONERROR); - return false; - } - - return true; - }(); - - if (!res) - { - TerminateProcess(GetCurrentProcess(), 1); - } -} - -void component_loader::pre_destroy() -{ - static auto res = [] - { - clean(); - - try - { - for (const auto& component_ : get_components()) - { - component_->pre_destroy(); - } - } - catch (const std::exception& e) - { - MessageBoxA(nullptr, e.what(), "Error", MB_ICONERROR); - return false; - } - - return true; - }(); - - if (!res) - { - TerminateProcess(GetCurrentProcess(), 1); - } -} - -void component_loader::clean() -{ - auto& components = get_components(); - for (auto i = components.begin(); i != components.end();) - { - if (!(*i)->is_supported()) - { - (*i)->pre_destroy(); - i = components.erase(i); - } - else - { - ++i; + return a->priority() > b->priority(); + }); } } -} -void component_loader::trigger_premature_shutdown() -{ - throw premature_shutdown_trigger(); -} - -std::vector>& component_loader::get_components() -{ - using component_vector = std::vector>; - using component_vector_container = std::unique_ptr>; - - static component_vector_container components(new component_vector, [](const component_vector* component_vector) + void register_component(registration_functor functor) { - pre_destroy(); - delete component_vector; - }); + if (!get_components().empty()) + { + throw std::runtime_error("Registration is too late"); + } - return *components; + get_registration_functors().push_back(std::move(functor)); + } + + bool activate() + { + static auto res = [] + { + try + { + for (auto& functor : get_registration_functors()) + { + activate_component(functor()); + } + } + catch (premature_shutdown_trigger&) + { + return false; + } + catch (const std::exception& e) + { + MessageBoxA(nullptr, e.what(), "Error", MB_ICONERROR | MB_SETFOREGROUND | MB_TOPMOST); + return false; + } + + return true; + }(); + + return res; + } + + bool post_load() + { + static auto res = [] + { + try + { + for (const auto& component : get_components()) + { + component->post_load(); + } + } + catch (premature_shutdown_trigger&) + { + return false; + } + catch (const std::exception& e) + { + MessageBoxA(nullptr, e.what(), "Error", MB_ICONERROR | MB_SETFOREGROUND | MB_TOPMOST); + return false; + } + + return true; + }(); + + return res; + } + + void post_unpack() + { + static auto res = [] + { + try + { + for (const auto& component : get_components()) + { + component->post_unpack(); + } + } + catch (const std::exception& e) + { + MessageBoxA(nullptr, e.what(), "Error", MB_ICONERROR | MB_SETFOREGROUND | MB_TOPMOST); + return false; + } + + return true; + }(); + + if (!res) + { + TerminateProcess(GetCurrentProcess(), 1); + } + } + + void pre_destroy() + { + static auto res = [] + { + try + { + for (const auto& component : get_components()) + { + component->pre_destroy(); + } + } + catch (const std::exception& e) + { + MessageBoxA(nullptr, e.what(), "Error", MB_ICONERROR | MB_SETFOREGROUND | MB_TOPMOST); + return false; + } + + return true; + }(); + + if (!res) + { + TerminateProcess(GetCurrentProcess(), 1); + } + } + + void trigger_premature_shutdown() + { + throw premature_shutdown_trigger(); + } } size_t get_base() @@ -170,7 +169,7 @@ size_t get_base() static auto base = [] { const utils::nt::library host{}; - if(!host || host == utils::nt::library::get_by_address(get_base)) + if (!host || host == utils::nt::library::get_by_address(get_base)) { throw std::runtime_error("Invalid host application"); } diff --git a/src/client/loader/component_loader.hpp b/src/client/loader/component_loader.hpp index 471cd5bc..b743bd0e 100644 --- a/src/client/loader/component_loader.hpp +++ b/src/client/loader/component_loader.hpp @@ -1,9 +1,19 @@ #pragma once #include "component_interface.hpp" -class component_loader final +namespace component_loader { -public: + using registration_functor = std::function()>; + + void register_component(registration_functor functor); + + bool activate(); + bool post_load(); + void post_unpack(); + void pre_destroy(); + + [[noreturn]] void trigger_premature_shutdown(); + class premature_shutdown_trigger final : public std::exception { [[nodiscard]] const char* what() const noexcept override @@ -20,36 +30,12 @@ public: public: installer() { - register_component(std::make_unique()); + register_component([] + { + return std::make_unique(); + }); } }; - - template - static T* get() - { - for (const auto& component_ : get_components()) - { - if (typeid(*component_.get()) == typeid(T)) - { - return reinterpret_cast(component_.get()); - } - } - - return nullptr; - } - - static void register_component(std::unique_ptr&& component); - - static bool pre_load(); - static bool post_load(); - static void post_unpack(); - static void pre_destroy(); - static void clean(); - - static void trigger_premature_shutdown(); - -private: - static std::vector>& get_components(); }; #define REGISTER_COMPONENT(name) \ diff --git a/src/client/main.cpp b/src/client/main.cpp index 4b1122f6..531a50cc 100644 --- a/src/client/main.cpp +++ b/src/client/main.cpp @@ -183,7 +183,7 @@ namespace { remove_crash_file(); - if (!component_loader::pre_load()) + if (!component_loader::activate()) { return 1; }