Refactor the component system

This commit is contained in:
momo5502 2022-11-11 17:00:34 +01:00
parent 13be8f3894
commit ef39098e28
10 changed files with 286 additions and 302 deletions

View File

@ -757,9 +757,9 @@ namespace arxan
//restore_debug_functions();
}
int priority() override
component_priority priority() const override
{
return 9999;
return component_priority::arxan;
}
private:

View File

@ -444,7 +444,7 @@ namespace demonware
class component final : public component_interface
{
public:
void pre_load() override
component()
{
udp_servers.create<stun_server>("stun.us.demonware.net");
udp_servers.create<stun_server>("stun.eu.demonware.net");

View File

@ -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);

View File

@ -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();
}
}
void show()
{
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<HBRUSH>(6);
wnd_class.lpszClassName = "Black Ops III Splash Screen";
if (RegisterClassA(&wnd_class))
{
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<LPARAM>(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);
}
}
class component final : public component_interface
{
public:
void pre_load() override
{
this->image_ = load_splash_image();
enable_dpi_awareness();
window_thread = std::thread([this]
{
this->draw();
});
}
void pre_destroy() override
{
destroy_window();
if (window_thread.joinable())
{
window_thread.detach();
}
}
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<HBRUSH>(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);
std::this_thread::sleep_for(1ms);
}
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<LPARAM>(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);
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();
}
};

View File

@ -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;
}
};

View File

@ -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:

View File

@ -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;
}
};

View File

@ -3,166 +3,165 @@
#include <utils/nt.hpp>
void component_loader::register_component(std::unique_ptr<component_interface>&& component_)
namespace component_loader
{
auto& components = get_components();
components.push_back(std::move(component_));
std::ranges::stable_sort(components, [](const std::unique_ptr<component_interface>& a,
const std::unique_ptr<component_interface>& b)
namespace
{
return a->priority() > b->priority();
});
}
bool component_loader::pre_load()
{
static auto res = []
std::vector<std::unique_ptr<component_interface>>& get_components()
{
clean();
try
{
for (const auto& component_ : get_components())
{
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;
}
}
}
void component_loader::trigger_premature_shutdown()
{
throw premature_shutdown_trigger();
}
std::vector<std::unique_ptr<component_interface>>& component_loader::get_components()
{
using component_vector = std::vector<std::unique_ptr<component_interface>>;
using component_vector_container = std::unique_ptr<component_vector, std::function<void(component_vector*)>>;
using component_vector_container = std::unique_ptr<component_vector, std::function<void(component_vector*)>>
;
static component_vector_container components(new component_vector, [](const component_vector* component_vector)
static component_vector_container components(new component_vector,
[](const component_vector* component_vector)
{
pre_destroy();
delete component_vector;
});
return *components;
}
std::vector<registration_functor>& get_registration_functors()
{
static std::vector<registration_functor> functors;
return functors;
}
void activate_component(std::unique_ptr<component_interface> component)
{
auto& components = get_components();
components.push_back(std::move(component));
std::ranges::stable_sort(components, [](const std::unique_ptr<component_interface>& a,
const std::unique_ptr<component_interface>& b)
{
return a->priority() > b->priority();
});
}
}
void register_component(registration_functor functor)
{
if (!get_components().empty())
{
throw std::runtime_error("Registration is too late");
}
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");
}

View File

@ -1,9 +1,19 @@
#pragma once
#include "component_interface.hpp"
class component_loader final
namespace component_loader
{
public:
using registration_functor = std::function<std::unique_ptr<component_interface>()>;
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<T>());
register_component([]
{
return std::make_unique<T>();
});
}
};
template <typename T>
static T* get()
{
for (const auto& component_ : get_components())
{
if (typeid(*component_.get()) == typeid(T))
{
return reinterpret_cast<T*>(component_.get());
}
}
return nullptr;
}
static void register_component(std::unique_ptr<component_interface>&& 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<std::unique_ptr<component_interface>>& get_components();
};
#define REGISTER_COMPONENT(name) \

View File

@ -183,7 +183,7 @@ namespace
{
remove_crash_file();
if (!component_loader::pre_load())
if (!component_loader::activate())
{
return 1;
}