// Thin RAII wrapper over a Win32 file-mapping section used as the host<->hook // IPC transport. Header-only so both modules share one implementation. #pragma once #include #include #include #include "coop/protocol.hpp" namespace coop { class SharedMemory { public: SharedMemory() = default; SharedMemory(const SharedMemory&) = delete; SharedMemory& operator=(const SharedMemory&) = delete; SharedMemory(SharedMemory&& other) noexcept { *this = std::move(other); } SharedMemory& operator=(SharedMemory&& other) noexcept { if (this != &other) { reset(); mapping_ = std::exchange(other.mapping_, nullptr); view_ = std::exchange(other.view_, nullptr); size_ = std::exchange(other.size_, 0); } return *this; } ~SharedMemory() { reset(); } // Host side: create (or open if it already exists) the named section. bool create(const std::wstring& name, std::size_t size) { reset(); mapping_ = CreateFileMappingW(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0, static_cast(size), name.c_str()); if (mapping_ == nullptr) { return false; } return map(size); } // Hook side: open an existing section created by the host. bool open(const std::wstring& name, std::size_t size) { reset(); mapping_ = OpenFileMappingW(FILE_MAP_ALL_ACCESS, FALSE, name.c_str()); if (mapping_ == nullptr) { return false; } return map(size); } void reset() { if (view_ != nullptr) { UnmapViewOfFile(view_); view_ = nullptr; } if (mapping_ != nullptr) { CloseHandle(mapping_); mapping_ = nullptr; } size_ = 0; } [[nodiscard]] bool valid() const { return view_ != nullptr; } template [[nodiscard]] T* as() const { return static_cast(view_); } [[nodiscard]] void* data() const { return view_; } [[nodiscard]] std::size_t size() const { return size_; } private: bool map(std::size_t size) { view_ = MapViewOfFile(mapping_, FILE_MAP_ALL_ACCESS, 0, 0, size); if (view_ == nullptr) { CloseHandle(mapping_); mapping_ = nullptr; return false; } size_ = size; return true; } HANDLE mapping_ = nullptr; void* view_ = nullptr; std::size_t size_ = 0; }; // Build the per-pid section name both sides agree on. inline std::wstring shared_memory_name(unsigned long target_pid) { return std::wstring(kSharedMemoryPrefix) + std::to_wstring(target_pid); } } // namespace coop