CommonLibSSE (powerof3)
Module.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include "REL/Version.h"
4 
5 #include "REX/W32/KERNEL32.h"
6 
7 namespace REL
8 {
9  class Segment
10  {
11  public:
12  enum Name : std::size_t
13  {
19  tls,
22  total
23  };
24 
25  Segment() noexcept = default;
26 
27  Segment(std::uintptr_t a_proxyBase, std::uintptr_t a_address, std::uintptr_t a_size) noexcept :
28  _proxyBase(a_proxyBase),
29  _address(a_address),
30  _size(a_size)
31  {}
32 
33  [[nodiscard]] std::uintptr_t address() const noexcept { return _address; }
34  [[nodiscard]] std::size_t offset() const noexcept { return address() - _proxyBase; }
35  [[nodiscard]] std::size_t size() const noexcept { return _size; }
36 
37  [[nodiscard]] void* pointer() const noexcept { return reinterpret_cast<void*>(address()); }
38 
39  template <class T>
40  [[nodiscard]] T* pointer() const noexcept
41  {
42  return static_cast<T*>(pointer());
43  }
44 
45  private:
46  std::uintptr_t _proxyBase{ 0 };
47  std::uintptr_t _address{ 0 };
48  std::size_t _size{ 0 };
49  };
50 
51  class Module
52  {
53  public:
54  [[nodiscard]] static Module& get()
55  {
56  static Module singleton;
57  return singleton;
58  }
59 
60  [[nodiscard]] std::uintptr_t base() const noexcept { return _base; }
61  [[nodiscard]] stl::zwstring filename() const noexcept { return _filename; }
62  [[nodiscard]] Version version() const noexcept { return _version; }
63 
64  [[nodiscard]] Segment segment(Segment::Name a_segment) const noexcept { return _segments[a_segment]; }
65 
66  [[nodiscard]] REX::W32::HMODULE pointer() const noexcept { return reinterpret_cast<REX::W32::HMODULE>(base()); }
67 
68  template <class T>
69  [[nodiscard]] T* pointer() const noexcept
70  {
71  return static_cast<T*>(pointer());
72  }
73 
74  private:
75  Module()
76  {
77  const auto getFilename = [&]() {
79  ENVIRONMENT.data(),
80  _filename.data(),
81  static_cast<std::uint32_t>(_filename.size()));
82  };
83 
84  _filename.resize(getFilename());
85  if (const auto result = getFilename();
86  result != _filename.size() - 1 ||
87  result == 0) {
88  _filename = L"SkyrimSE.exe"sv;
89  }
90 
91  load();
92  }
93 
94  Module(const Module&) = delete;
95  Module(Module&&) = delete;
96 
97  ~Module() noexcept = default;
98 
99  Module& operator=(const Module&) = delete;
100  Module& operator=(Module&&) = delete;
101 
102  void load()
103  {
104  auto handle = REX::W32::GetModuleHandleW(_filename.c_str());
105  if (handle == nullptr) {
107  std::format(
108  "Failed to obtain module handle for: \"{0}\".\n"
109  "You have likely renamed the executable to something unexpected. "
110  "Renaming the executable back to \"{0}\" may resolve the issue."sv,
111  stl::utf16_to_utf8(_filename).value_or("<unicode conversion error>"s)));
112  }
113  _base = reinterpret_cast<std::uintptr_t>(handle);
114 
115  load_version();
116  load_segments();
117  }
118 
119  void load_segments();
120 
121  void load_version()
122  {
123  const auto version = GetFileVersion(_filename);
124  if (version) {
125  _version = *version;
126  } else {
128  std::format(
129  "Failed to obtain file version info for: {}\n"
130  "Please contact the author of this script extender plugin for further assistance."sv,
131  stl::utf16_to_utf8(_filename).value_or("<unicode conversion error>"s)));
132  }
133  }
134 
135  static constexpr std::array SEGMENTS{
137  std::make_pair(".idata"sv, 0u),
138  std::make_pair(".rdata"sv, 0u),
139  std::make_pair(".data"sv, 0u),
140  std::make_pair(".pdata"sv, 0u),
141  std::make_pair(".tls"sv, 0u),
143  std::make_pair(".gfids"sv, 0u)
144  };
145 
146  static constexpr auto ENVIRONMENT = L"SKSE_RUNTIME"sv;
147 
148  std::wstring _filename;
149  std::array<Segment, Segment::total> _segments;
150  Version _version;
151  std::uintptr_t _base{ 0 };
152  };
153 }
Definition: Module.h:52
static Module & get()
Definition: Module.h:54
Version version() const noexcept
Definition: Module.h:62
std::uintptr_t base() const noexcept
Definition: Module.h:60
stl::zwstring filename() const noexcept
Definition: Module.h:61
REX::W32::HMODULE pointer() const noexcept
Definition: Module.h:66
T * pointer() const noexcept
Definition: Module.h:69
Segment segment(Segment::Name a_segment) const noexcept
Definition: Module.h:64
Definition: Module.h:10
std::size_t size() const noexcept
Definition: Module.h:35
void * pointer() const noexcept
Definition: Module.h:37
Name
Definition: Module.h:13
@ data
Definition: Module.h:17
@ tls
Definition: Module.h:19
@ textw
Definition: Module.h:20
@ gfids
Definition: Module.h:21
@ total
Definition: Module.h:22
@ idata
Definition: Module.h:15
@ textx
Definition: Module.h:14
@ pdata
Definition: Module.h:18
@ rdata
Definition: Module.h:16
T * pointer() const noexcept
Definition: Module.h:40
std::uintptr_t address() const noexcept
Definition: Module.h:33
Segment() noexcept=default
std::size_t offset() const noexcept
Definition: Module.h:34
Definition: Version.h:6
Definition: ID.h:6
std::optional< Version > GetFileVersion(stl::zwstring a_filename)
constexpr auto IMAGE_SCN_MEM_EXECUTE
Definition: KERNEL32.h:96
constexpr auto IMAGE_SCN_MEM_WRITE
Definition: KERNEL32.h:98
HINSTANCE HMODULE
Definition: BASE.h:24
HMODULE GetModuleHandleW(const wchar_t *a_name) noexcept
std::uint32_t GetEnvironmentVariableW(const wchar_t *a_name, wchar_t *a_buf, std::uint32_t a_bufLen) noexcept
auto make_pair(T1 &&a_first, T2 &&a_second)
Definition: BSTTuple.h:177
void report_and_fail(std::string_view a_msg, std::source_location a_loc=std::source_location::current())
Definition: PCH.h:396
auto utf16_to_utf8(std::wstring_view a_in) noexcept -> std::optional< std::string >
Definition: PCH.h:368
basic_zstring< wchar_t > zwstring
Definition: PCH.h:82
Definition: EffectArchetypes.h:65