Refactor the component system
This commit is contained in:
parent
13be8f3894
commit
ef39098e28
@ -757,9 +757,9 @@ namespace arxan
|
||||
//restore_debug_functions();
|
||||
}
|
||||
|
||||
int priority() override
|
||||
component_priority priority() const override
|
||||
{
|
||||
return 9999;
|
||||
return component_priority::arxan;
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -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");
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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) \
|
||||
|
@ -183,7 +183,7 @@ namespace
|
||||
{
|
||||
remove_crash_file();
|
||||
|
||||
if (!component_loader::pre_load())
|
||||
if (!component_loader::activate())
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user