VoltMod
C++23 framework for CS2 server plugins
Loading...
Searching...
No Matches
SharedLibrary.cpp
Go to the documentation of this file.
2
3#include <format>
4#include <string>
5#include <utility>
6
7#if defined(_WIN32)
8#include <windows.h>
9
10#include <system_error>
11#else
12#include <dlfcn.h>
13#endif
14
15namespace VoltMod
16{
17
18#if defined(_WIN32)
19
20static std::string LastError()
21{
22 const DWORD code = GetLastError();
23 return std::format("{} (error {})", std::system_category().message(static_cast<int>(code)), code);
24}
25
26static void* OpenLibrary(const std::filesystem::path& path)
27{
28 return LoadLibraryW(path.c_str());
29}
30
31static void* FindExport(void* handle, const char* name)
32{
33 return reinterpret_cast<void*>(GetProcAddress(static_cast<HMODULE>(handle), name));
34}
35
36static void CloseLibrary(void* handle)
37{
38 FreeLibrary(static_cast<HMODULE>(handle));
39}
40
41#else
42
43static std::string LastError()
44{
45 const char* message = dlerror();
46 return message != nullptr ? std::string(message) : std::string("no message");
47}
48
49static void* OpenLibrary(const std::filesystem::path& path)
50{
51 // RTLD_LOCAL keeps each plugin's static SDK private; RTLD_NOW reports missing symbols here.
52 return dlopen(path.c_str(), RTLD_NOW | RTLD_LOCAL);
53}
54
55static void* FindExport(void* handle, const char* name)
56{
57 return dlsym(handle, name);
58}
59
60static void CloseLibrary(void* handle)
61{
63}
64
65#endif
66
68{
69 Close();
70}
71
72SharedLibrary::SharedLibrary(SharedLibrary&& other) noexcept : _handle(std::exchange(other._handle, nullptr)) {}
73
75{
76 if (this != &other)
77 {
78 Close();
79 _handle = std::exchange(other._handle, nullptr);
80 }
81 return *this;
82}
83
84Result<SharedLibrary> SharedLibrary::Open(const std::filesystem::path& path)
85{
86 void* handle = OpenLibrary(path);
87 if (handle == nullptr)
88 {
89 return std::unexpected(Error::Failed(std::format("cannot load {}: {}", path.string(), LastError())));
90 }
91
92 return SharedLibrary(handle);
93}
94
95Result<void*> SharedLibrary::Symbol(const char* name) const
96{
97 if (_handle == nullptr)
98 {
99 return std::unexpected(Error::NotReady(std::format("cannot look up {}: nothing is loaded", name)));
100 }
101
102 void* address = FindExport(_handle, name);
103 if (address == nullptr)
104 {
105 return std::unexpected(Error::NotFound(std::format("does not export {}: {}", name, LastError())));
106 }
107
108 return address;
109}
110
111void SharedLibrary::Close()
112{
113 if (_handle == nullptr)
114 {
115 return;
116 }
117
118 CloseLibrary(std::exchange(_handle, nullptr));
119}
120
121} // namespace VoltMod
static Result< SharedLibrary > Open(const std::filesystem::path &path)
Result< void * > Symbol(const char *name) const
SharedLibrary & operator=(SharedLibrary &&other) noexcept
static std::string LastError()
static void * OpenLibrary(const std::filesystem::path &path)
static std::string ReadFile(const std::filesystem::path &path)
Definition Loader.cpp:56
std::expected< T, Error > Result
Definition Result.hpp:64
static void * FindExport(void *handle, const char *name)
static void CloseLibrary(void *handle)
static Error Failed(std::string detail)
Definition Result.hpp:59
static Error NotFound(std::string detail)
Definition Result.hpp:49
static Error NotReady(std::string detail)
Definition Result.hpp:50