@@ -19,6 +19,7 @@
#include <Windows.h>
#include <Knownfolders.h>
#include <Memoryapi.h>
#include <Objbase.h>
#include <Shlobj.h>
#include <shellscalingapi.h>
@@ -60,4 +61,39 @@ unsigned active_window_scale_factor() {
return static_cast<unsigned>(std::lround(static_cast<float>(scale_factor) / 100.f));
}
// VirtualFree has a weird 2nd argument:
// [in] dwSize - The size of the region of memory to be freed, in bytes.
// If the dwFreeType parameter is MEM_RELEASE, this parameter must be 0 (zero).
// https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualfree
ExecutableMemory::~ExecutableMemory() {
if (memory_ != nullptr && !VirtualFree(memory_, 0, MEM_RELEASE)) {
std::abort();
}
}
std::optional<ExecutableMemory> ExecutableMemory::allocate_containing(std::span<std::uint8_t const> data) {
if (data.empty()) {
return std::nullopt;
}
auto *memory = VirtualAlloc(nullptr, data.size(), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (memory == nullptr) {
return std::nullopt;
}
std::memcpy(memory, data.data(), data.size());
DWORD old_protect{};
if (!VirtualProtect(memory, data.size(), PAGE_EXECUTE, &old_protect)
|| !FlushInstructionCache(GetCurrentProcess(), memory, data.size())) {
if (!VirtualFree(memory, 0, MEM_RELEASE)) {
std::abort();
}
return std::nullopt;
}
return ExecutableMemory{memory, data.size()};
}
} // namespace os