CommonLibVR
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 #ifndef SKYRIMVR
89  _filename = L"SkyrimSE.exe"sv;
90 #else
91  _filename = L"SkyrimVR.exe"sv;
92 #endif
93  }
94 
95  load();
96  }
97 
98  Module(const Module&) = delete;
99  Module(Module&&) = delete;
100 
101  ~Module() noexcept = default;
102 
103  Module& operator=(const Module&) = delete;
104  Module& operator=(Module&&) = delete;
105 
106  void load()
107  {
108  auto handle = REX::W32::GetModuleHandleW(_filename.c_str());
109  if (handle == nullptr) {
111  std::format(
112  "Failed to obtain module handle for: \"{0}\".\n"
113  "You have likely renamed the executable to something unexpected. "
114  "Renaming the executable back to \"{0}\" may resolve the issue."sv,
115  stl::utf16_to_utf8(_filename).value_or("<unicode conversion error>"s)));
116  }
117  _base = reinterpret_cast<std::uintptr_t>(handle);
118 
119  load_version();
120  load_segments();
121  }
122 
123  void load_segments();
124 
125  void load_version()
126  {
127  const auto version = GetFileVersion(_filename);
128  if (version) {
129  _version = *version;
130  } else {
132  std::format(
133  "Failed to obtain file version info for: {}\n"
134  "Please contact the author of this script extender plugin for further assistance."sv,
135  stl::utf16_to_utf8(_filename).value_or("<unicode conversion error>"s)));
136  }
137  }
138 
139  static constexpr std::array SEGMENTS{
141  std::make_pair(".idata"sv, 0u),
142  std::make_pair(".rdata"sv, 0u),
143  std::make_pair(".data"sv, 0u),
144  std::make_pair(".pdata"sv, 0u),
145  std::make_pair(".tls"sv, 0u),
147  std::make_pair(".gfids"sv, 0u)
148  };
149 
150  static constexpr auto ENVIRONMENT = L"SKSE_RUNTIME"sv;
151 
152  std::wstring _filename;
153  std::array<Segment, Segment::total> _segments;
154  Version _version;
155  std::uintptr_t _base{ 0 };
156  };
157 }
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:9
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:179
void report_and_fail(std::string_view a_msg, std::source_location a_loc=std::source_location::current())
Definition: PCH.h:588
auto utf16_to_utf8(std::wstring_view a_in) noexcept -> std::optional< std::string >
Definition: PCH.h:560
basic_zstring< wchar_t > zwstring
Definition: PCH.h:80
Definition: EffectArchetypes.h:65