mirror of
https://github.com/momo5502/emulator.git
synced 2026-01-10 16:16:16 +00:00
Add support for user_object/user_handle_table
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
#include "unicode.hpp"
|
||||
#include "status.hpp"
|
||||
#include "process.hpp"
|
||||
#include "user.hpp"
|
||||
#include "kernel_mapped.hpp"
|
||||
#include "memory.hpp"
|
||||
#include "file_management.hpp"
|
||||
|
||||
@@ -50,6 +50,14 @@ typedef union _LARGE_INTEGER
|
||||
|
||||
using BYTE = std::uint8_t;
|
||||
#define CHAR BYTE
|
||||
|
||||
typedef struct _RECT
|
||||
{
|
||||
LONG left;
|
||||
LONG top;
|
||||
LONG right;
|
||||
LONG bottom;
|
||||
} RECT;
|
||||
#endif
|
||||
|
||||
using WORD = std::uint16_t;
|
||||
|
||||
102
src/common/platform/user.hpp
Normal file
102
src/common/platform/user.hpp
Normal file
@@ -0,0 +1,102 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
// NOLINTBEGIN(modernize-use-using,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
|
||||
|
||||
struct USER_SERVERINFO
|
||||
{
|
||||
DWORD dwSRVIFlags;
|
||||
uint64_t cHandleEntries;
|
||||
uint8_t unknown[0x1000];
|
||||
};
|
||||
|
||||
struct USER_DISPINFO
|
||||
{
|
||||
DWORD dwMonitorCount;
|
||||
EMULATOR_CAST(uint64_t, USER_MONITOR*) pPrimaryMonitor;
|
||||
uint8_t unknown[0xFF];
|
||||
};
|
||||
|
||||
struct USER_HANDLEENTRY
|
||||
{
|
||||
uint64_t pHead;
|
||||
uint64_t pOwner;
|
||||
uint64_t unknown;
|
||||
uint8_t bType;
|
||||
uint8_t bFlags;
|
||||
uint16_t wUniq;
|
||||
};
|
||||
static_assert(sizeof(USER_HANDLEENTRY) == 0x20);
|
||||
|
||||
struct USER_SHAREDINFO
|
||||
{
|
||||
uint64_t psi;
|
||||
uint64_t aheList;
|
||||
uint32_t HeEntrySize;
|
||||
uint64_t pDispInfo;
|
||||
uint8_t unknown[0xFF];
|
||||
};
|
||||
|
||||
struct USER_THROBJHEAD
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint64_t h;
|
||||
uint32_t cLockObj;
|
||||
} h;
|
||||
uint64_t pti;
|
||||
};
|
||||
|
||||
struct USER_THRDESKHEAD
|
||||
{
|
||||
USER_THROBJHEAD h;
|
||||
uint64_t rpdesk;
|
||||
uint64_t pSelf;
|
||||
};
|
||||
|
||||
enum USER_HANDLETYPE : uint8_t
|
||||
{
|
||||
TYPE_FREE = 0,
|
||||
TYPE_WINDOW = 1,
|
||||
TYPE_MENU = 2,
|
||||
TYPE_CURSOR = 3,
|
||||
TYPE_SETWINDOWPOS = 4,
|
||||
TYPE_HOOK = 5,
|
||||
TYPE_CLIPDATA = 6,
|
||||
TYPE_CALLPROC = 7,
|
||||
TYPE_ACCELTABLE = 8,
|
||||
TYPE_DDEACCESS = 9,
|
||||
TYPE_DDECONV = 10,
|
||||
TYPE_DDEXACT = 11,
|
||||
TYPE_MONITOR = 12,
|
||||
TYPE_KBDLAYOUT = 13,
|
||||
TYPE_KBDFILE = 14,
|
||||
TYPE_WINEVENTHOOK = 15,
|
||||
TYPE_TIMER = 16,
|
||||
TYPE_INPUTCONTEXT = 17,
|
||||
TYPE_HIDDATA = 18,
|
||||
TYPE_DEVICEINFO = 19,
|
||||
TYPE_TOUCHINPUTINFO = 20,
|
||||
TYPE_GESTUREINFOOBJ = 21,
|
||||
TYPE_CTYPES = 22,
|
||||
TYPE_GENERIC = 255
|
||||
};
|
||||
|
||||
struct USER_MONITOR
|
||||
{
|
||||
EMULATOR_CAST(uint64_t, HMONITOR) hmon;
|
||||
uint8_t unknown1[0x14];
|
||||
RECT monitorRect;
|
||||
RECT workRect;
|
||||
uint16_t monitorDpi;
|
||||
uint16_t nativeDpi;
|
||||
uint8_t unknown2[0xFF];
|
||||
};
|
||||
|
||||
struct USER_WINDOW
|
||||
{
|
||||
uint8_t unknown[0xFF];
|
||||
};
|
||||
|
||||
// NOLINTEND(modernize-use-using,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
|
||||
@@ -509,6 +509,41 @@ namespace
|
||||
return true;
|
||||
}
|
||||
|
||||
bool test_monitor_info()
|
||||
{
|
||||
const POINT pt = {0, 0};
|
||||
const auto hMonitor = MonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY);
|
||||
if (!hMonitor)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
MONITORINFOEXA mi;
|
||||
mi.cbSize = sizeof(mi);
|
||||
|
||||
if (!GetMonitorInfoA(hMonitor, &mi))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (std::string_view(mi.szDevice) != R"(\\.\DISPLAY1)")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mi.rcMonitor.left != 0 || mi.rcMonitor.top != 0 || mi.rcMonitor.right != 1920 || mi.rcMonitor.bottom != 1080)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(mi.dwFlags & MONITORINFOF_PRIMARY))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool test_time_zone()
|
||||
{
|
||||
DYNAMIC_TIME_ZONE_INFORMATION current_dtzi = {};
|
||||
@@ -908,6 +943,7 @@ int main(const int argc, const char* argv[])
|
||||
RUN_TEST(test_working_directory, "Working Directory")
|
||||
RUN_TEST(test_registry, "Registry")
|
||||
RUN_TEST(test_system_info, "System Info")
|
||||
RUN_TEST(test_monitor_info, "Monitor Info")
|
||||
RUN_TEST(test_time_zone, "Time Zone")
|
||||
RUN_TEST(test_threads, "Threads")
|
||||
RUN_TEST(test_threads_winapi, "Threads WinAPI")
|
||||
|
||||
@@ -21,6 +21,7 @@ struct handle_types
|
||||
token,
|
||||
window,
|
||||
timer,
|
||||
monitor,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -9,7 +9,13 @@ namespace
|
||||
{
|
||||
NTSTATUS handle_request(windows_emulator& win_emu, const lpc_request_context& c) override
|
||||
{
|
||||
// TODO: Fix this. This is broken and wrong.
|
||||
uint32_t server_dll_index{};
|
||||
win_emu.memory.read_memory(c.recv_buffer + 0x18, &server_dll_index, sizeof(server_dll_index));
|
||||
|
||||
if (server_dll_index != 3)
|
||||
{
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
@@ -17,8 +23,13 @@ namespace
|
||||
const auto dest = data.read();
|
||||
const auto base = dest.Base;
|
||||
|
||||
const auto value = base + 0x10;
|
||||
win_emu.emu().write_memory(base + 8, &value, sizeof(value));
|
||||
const emulator_object<USER_SHAREDINFO> shared_obj{win_emu.emu(), base + 8};
|
||||
shared_obj.access([&](USER_SHAREDINFO& shared) {
|
||||
shared.psi = win_emu.process.user_handles.get_server_info().value();
|
||||
shared.aheList = win_emu.process.user_handles.get_handle_table().value();
|
||||
shared.HeEntrySize = sizeof(USER_HANDLEENTRY);
|
||||
shared.pDispInfo = win_emu.process.user_handles.get_display_info().value();
|
||||
});
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
|
||||
@@ -391,6 +391,24 @@ void process_context::setup(x86_64_emulator& emu, memory_manager& memory, regist
|
||||
this->instrumentation_callback = 0;
|
||||
|
||||
this->default_register_set = emu.save_registers();
|
||||
|
||||
this->user_handles.setup(memory);
|
||||
|
||||
auto [h, monitor_obj] = this->user_handles.allocate_object<USER_MONITOR>(handle_types::monitor);
|
||||
this->default_monitor_handle = h;
|
||||
monitor_obj.access([&](USER_MONITOR& monitor) {
|
||||
monitor.hmon = h.bits;
|
||||
monitor.monitorRect = {.left = 0, .top = 0, .right = 1920, .bottom = 1080};
|
||||
monitor.workRect = monitor.monitorRect;
|
||||
monitor.monitorDpi = 96;
|
||||
monitor.nativeDpi = monitor.monitorDpi;
|
||||
});
|
||||
|
||||
const auto user_display_info = this->user_handles.get_display_info();
|
||||
user_display_info.access([&](USER_DISPINFO& display_info) {
|
||||
display_info.dwMonitorCount = 1;
|
||||
display_info.pPrimaryMonitor = monitor_obj.value();
|
||||
});
|
||||
}
|
||||
|
||||
void process_context::serialize(utils::buffer_serializer& buffer) const
|
||||
@@ -416,6 +434,8 @@ void process_context::serialize(utils::buffer_serializer& buffer) const
|
||||
buffer.write(this->ki_user_exception_dispatcher);
|
||||
buffer.write(this->instrumentation_callback);
|
||||
|
||||
buffer.write(this->user_handles);
|
||||
buffer.write(this->default_monitor_handle);
|
||||
buffer.write(this->events);
|
||||
buffer.write(this->files);
|
||||
buffer.write(this->sections);
|
||||
@@ -462,6 +482,8 @@ void process_context::deserialize(utils::buffer_deserializer& buffer)
|
||||
buffer.read(this->ki_user_exception_dispatcher);
|
||||
buffer.read(this->instrumentation_callback);
|
||||
|
||||
buffer.read(this->user_handles);
|
||||
buffer.read(this->default_monitor_handle);
|
||||
buffer.read(this->events);
|
||||
buffer.read(this->files);
|
||||
buffer.read(this->sections);
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "windows_objects.hpp"
|
||||
#include "emulator_thread.hpp"
|
||||
#include "port.hpp"
|
||||
#include "user_handle_table.hpp"
|
||||
|
||||
#include "apiset/apiset.hpp"
|
||||
|
||||
@@ -118,6 +119,8 @@ struct process_context
|
||||
std::optional<emulator_object<RTL_USER_PROCESS_PARAMETERS32>> process_params32;
|
||||
std::optional<uint64_t> rtl_user_thread_start32{};
|
||||
|
||||
user_handle_table user_handles{};
|
||||
handle default_monitor_handle{};
|
||||
handle_store<handle_types::event, event> events{};
|
||||
handle_store<handle_types::file, file> files{};
|
||||
handle_store<handle_types::section, section> sections{};
|
||||
@@ -125,7 +128,7 @@ struct process_context
|
||||
handle_store<handle_types::semaphore, semaphore> semaphores{};
|
||||
handle_store<handle_types::port, port_container> ports{};
|
||||
handle_store<handle_types::mutant, mutant> mutants{};
|
||||
handle_store<handle_types::window, window> windows{};
|
||||
user_handle_store<handle_types::window, window> windows{user_handles};
|
||||
handle_store<handle_types::timer, timer> timers{};
|
||||
handle_store<handle_types::registry, registry_key, 2> registry_keys{};
|
||||
std::map<uint16_t, atom_entry> atoms{};
|
||||
|
||||
@@ -463,7 +463,7 @@ namespace syscalls
|
||||
return STATUS_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
if (auto* e = c.win_emu.process.events.get(event))
|
||||
if (auto* e = c.proc.events.get(event))
|
||||
{
|
||||
e->signaled = false;
|
||||
}
|
||||
@@ -831,7 +831,7 @@ namespace syscalls
|
||||
const hwnd /*parent*/, const hmenu /*menu*/, const hinstance /*instance*/, const pointer /*l_param*/,
|
||||
const DWORD /*flags*/, const pointer /*acbi_buffer*/)
|
||||
{
|
||||
window win{};
|
||||
auto [handle, win] = c.proc.windows.create(c.win_emu.memory);
|
||||
win.x = x;
|
||||
win.y = y;
|
||||
win.width = width;
|
||||
@@ -840,7 +840,7 @@ namespace syscalls
|
||||
win.class_name = read_large_string(class_name);
|
||||
win.name = read_large_string(window_name);
|
||||
|
||||
return c.proc.windows.store(std::move(win)).bits;
|
||||
return handle.bits;
|
||||
}
|
||||
|
||||
BOOL handle_NtUserDestroyWindow(const syscall_context& c, const hwnd window)
|
||||
@@ -1027,6 +1027,19 @@ namespace syscalls
|
||||
{
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
BOOL handle_NtUserGetHDevName(const syscall_context& c, handle hdev, emulator_pointer device_name)
|
||||
{
|
||||
if (hdev != c.proc.default_monitor_handle)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
const std::u16string name = u"\\\\.\\DISPLAY1";
|
||||
c.emu.write_memory(device_name, name.c_str(), (name.size() + 1) * sizeof(char16_t));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
void syscall_dispatcher::add_handlers(std::map<std::string, syscall_handler>& handler_mapping)
|
||||
@@ -1239,6 +1252,7 @@ void syscall_dispatcher::add_handlers(std::map<std::string, syscall_handler>& ha
|
||||
add_handler(NtSetInformationDebugObject);
|
||||
add_handler(NtRemoveProcessDebug);
|
||||
add_handler(NtNotifyChangeDirectoryFileEx);
|
||||
add_handler(NtUserGetHDevName);
|
||||
|
||||
#undef add_handler
|
||||
}
|
||||
|
||||
389
src/windows-emulator/user_handle_table.hpp
Normal file
389
src/windows-emulator/user_handle_table.hpp
Normal file
@@ -0,0 +1,389 @@
|
||||
#pragma once
|
||||
#include "emulator_utils.hpp"
|
||||
#include "handles.hpp"
|
||||
|
||||
class user_handle_table
|
||||
{
|
||||
public:
|
||||
static constexpr uint32_t MAX_HANDLES = 0xFFFF;
|
||||
|
||||
void setup(memory_manager& memory)
|
||||
{
|
||||
memory_ = &memory;
|
||||
|
||||
const auto server_info_size = static_cast<size_t>(page_align_up(sizeof(USER_SERVERINFO)));
|
||||
server_info_addr_ = memory.allocate_memory(server_info_size, memory_permission::read);
|
||||
|
||||
const auto display_info_size = static_cast<size_t>(page_align_up(sizeof(USER_DISPINFO)));
|
||||
display_info_addr_ = memory.allocate_memory(display_info_size, memory_permission::read);
|
||||
|
||||
const emulator_object<USER_SERVERINFO> srv_obj(memory, server_info_addr_);
|
||||
srv_obj.access([&](USER_SERVERINFO& srv) {
|
||||
srv.cHandleEntries = MAX_HANDLES - 1; //
|
||||
});
|
||||
|
||||
const auto handle_table_size = static_cast<size_t>(page_align_up(sizeof(USER_HANDLEENTRY) * MAX_HANDLES));
|
||||
handle_table_addr_ = memory.allocate_memory(handle_table_size, memory_permission::read);
|
||||
}
|
||||
|
||||
emulator_object<USER_SHAREDINFO> get_server_info() const
|
||||
{
|
||||
return {*memory_, server_info_addr_};
|
||||
}
|
||||
|
||||
emulator_object<USER_HANDLEENTRY> get_handle_table() const
|
||||
{
|
||||
return {*memory_, handle_table_addr_};
|
||||
}
|
||||
|
||||
emulator_object<USER_DISPINFO> get_display_info() const
|
||||
{
|
||||
return {*memory_, display_info_addr_};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::pair<handle, emulator_object<T>> allocate_object(handle_types::type type)
|
||||
{
|
||||
const auto index = find_free_index();
|
||||
|
||||
const auto alloc_size = static_cast<size_t>(page_align_up(sizeof(T)));
|
||||
const auto alloc_ptr = memory_->allocate_memory(alloc_size, memory_permission::read);
|
||||
const emulator_object<T> alloc_obj(*memory_, alloc_ptr);
|
||||
|
||||
const emulator_object<USER_HANDLEENTRY> handle_table_obj(*memory_, handle_table_addr_);
|
||||
handle_table_obj.access(
|
||||
[&](USER_HANDLEENTRY& entry) {
|
||||
entry.pHead = alloc_ptr;
|
||||
entry.bType = get_native_type(type);
|
||||
entry.wUniq = static_cast<uint16_t>(type << 7);
|
||||
},
|
||||
index);
|
||||
|
||||
used_indices_[index] = true;
|
||||
|
||||
return {make_handle(index, type, false), alloc_obj};
|
||||
}
|
||||
|
||||
void free_index(uint32_t index)
|
||||
{
|
||||
if (index >= used_indices_.size() || !used_indices_[index])
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
used_indices_[index] = false;
|
||||
|
||||
const emulator_object<USER_HANDLEENTRY> handle_table_obj(*memory_, handle_table_addr_);
|
||||
handle_table_obj.access(
|
||||
[&](USER_HANDLEENTRY& entry) {
|
||||
memory_->release_memory(entry.pHead, 0);
|
||||
entry = {};
|
||||
},
|
||||
index);
|
||||
}
|
||||
|
||||
void serialize(utils::buffer_serializer& buffer) const
|
||||
{
|
||||
buffer.write(server_info_addr_);
|
||||
buffer.write(handle_table_addr_);
|
||||
buffer.write(display_info_addr_);
|
||||
buffer.write(used_indices_);
|
||||
}
|
||||
|
||||
void deserialize(utils::buffer_deserializer& buffer)
|
||||
{
|
||||
buffer.read(server_info_addr_);
|
||||
buffer.read(handle_table_addr_);
|
||||
buffer.read(display_info_addr_);
|
||||
buffer.read(used_indices_);
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t find_free_index() const
|
||||
{
|
||||
for (uint32_t i = 1; i < used_indices_.size(); ++i)
|
||||
{
|
||||
if (!used_indices_[i])
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
throw std::runtime_error("No more user handles available");
|
||||
}
|
||||
|
||||
static uint8_t get_native_type(handle_types::type type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case handle_types::type::window:
|
||||
return TYPE_WINDOW;
|
||||
case handle_types::type::monitor:
|
||||
return TYPE_MONITOR;
|
||||
default:
|
||||
throw std::runtime_error("Unhandled handle type!");
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t server_info_addr_{};
|
||||
uint64_t handle_table_addr_{};
|
||||
uint64_t display_info_addr_{};
|
||||
std::array<bool, MAX_HANDLES> used_indices_{};
|
||||
memory_manager* memory_{};
|
||||
};
|
||||
|
||||
template <handle_types::type Type, typename T>
|
||||
requires(utils::Serializable<T> && std::is_base_of_v<ref_counted_object, T>)
|
||||
class user_handle_store : public generic_handle_store
|
||||
{
|
||||
public:
|
||||
using index_type = uint32_t;
|
||||
using value_map = std::map<index_type, T>;
|
||||
|
||||
explicit user_handle_store(user_handle_table& table)
|
||||
: table_(&table)
|
||||
{
|
||||
}
|
||||
|
||||
std::pair<handle, T&> create(memory_interface& memory)
|
||||
{
|
||||
if (this->block_mutation_)
|
||||
{
|
||||
throw std::runtime_error("Mutation of user object store is blocked!");
|
||||
}
|
||||
|
||||
auto [h, guest_obj] = table_->allocate_object<typename T::guest_type>(Type);
|
||||
|
||||
T new_obj(memory);
|
||||
new_obj.guest = std::move(guest_obj);
|
||||
|
||||
const auto index = static_cast<uint32_t>(h.value.id);
|
||||
const auto it = this->store_.emplace(index, std::move(new_obj)).first;
|
||||
return {h, it->second};
|
||||
}
|
||||
|
||||
bool block_mutation(bool blocked)
|
||||
{
|
||||
std::swap(this->block_mutation_, blocked);
|
||||
return blocked;
|
||||
}
|
||||
|
||||
handle make_handle(const index_type index) const
|
||||
{
|
||||
handle h{};
|
||||
h.bits = 0;
|
||||
h.value.is_pseudo = false;
|
||||
h.value.type = Type;
|
||||
h.value.id = index;
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
T* get_by_index(const uint32_t index)
|
||||
{
|
||||
const auto it = this->store_.find(index);
|
||||
if (it == this->store_.end())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return &it->second;
|
||||
}
|
||||
|
||||
T* get(const handle_value h)
|
||||
{
|
||||
if (h.type != Type || h.is_pseudo)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return this->get_by_index(static_cast<uint32_t>(h.id));
|
||||
}
|
||||
|
||||
T* get(const handle h)
|
||||
{
|
||||
return this->get(h.value);
|
||||
}
|
||||
|
||||
T* get(const uint64_t h)
|
||||
{
|
||||
handle hh{};
|
||||
hh.bits = h;
|
||||
return this->get(hh);
|
||||
}
|
||||
|
||||
size_t size() const
|
||||
{
|
||||
return this->store_.size();
|
||||
}
|
||||
|
||||
std::optional<handle> duplicate(const handle h) override
|
||||
{
|
||||
auto* entry = this->get(h);
|
||||
if (!entry)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
++entry->ref_count;
|
||||
return h;
|
||||
}
|
||||
|
||||
std::pair<typename value_map::iterator, bool> erase(const typename value_map::iterator& entry)
|
||||
{
|
||||
if (this->block_mutation_)
|
||||
{
|
||||
throw std::runtime_error("Mutation of handle store is blocked!");
|
||||
}
|
||||
|
||||
if (entry == this->store_.end())
|
||||
{
|
||||
return {entry, false};
|
||||
}
|
||||
|
||||
if constexpr (handle_detail::has_deleter_function<T>())
|
||||
{
|
||||
if (!T::deleter(entry->second))
|
||||
{
|
||||
return {entry, true};
|
||||
}
|
||||
}
|
||||
|
||||
auto new_iter = this->store_.erase(entry);
|
||||
return {new_iter, true};
|
||||
}
|
||||
|
||||
bool erase(const handle_value h)
|
||||
{
|
||||
if (this->block_mutation_)
|
||||
{
|
||||
throw std::runtime_error("Mutation of user object store is blocked!");
|
||||
}
|
||||
|
||||
if (h.type != Type || h.is_pseudo)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto index = static_cast<uint32_t>(h.id);
|
||||
const auto entry = this->store_.find(index);
|
||||
|
||||
if (entry == this->store_.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if constexpr (handle_detail::has_deleter_function<T>())
|
||||
{
|
||||
if (!T::deleter(entry->second))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
table_->free_index(index);
|
||||
this->store_.erase(entry);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool erase(const handle h) override
|
||||
{
|
||||
return this->erase(h.value);
|
||||
}
|
||||
|
||||
bool erase(const uint64_t h)
|
||||
{
|
||||
handle hh{};
|
||||
hh.bits = h;
|
||||
return this->erase(hh);
|
||||
}
|
||||
|
||||
bool erase(const T& value)
|
||||
{
|
||||
const auto entry = this->find(value);
|
||||
if (entry == this->store_.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return this->erase(make_handle(entry->first));
|
||||
}
|
||||
|
||||
typename value_map::iterator find(const T& value)
|
||||
{
|
||||
auto i = this->store_.begin();
|
||||
for (; i != this->store_.end(); ++i)
|
||||
{
|
||||
if (&i->second == &value)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
typename value_map::const_iterator find(const T& value) const
|
||||
{
|
||||
auto i = this->store_.begin();
|
||||
for (; i != this->store_.end(); ++i)
|
||||
{
|
||||
if (&i->second == &value)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
handle find_handle(const T& value) const
|
||||
{
|
||||
const auto entry = this->find(value);
|
||||
if (entry == this->end())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
return this->make_handle(entry->first);
|
||||
}
|
||||
|
||||
handle find_handle(const T* value) const
|
||||
{
|
||||
if (!value)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
return this->find_handle(*value);
|
||||
}
|
||||
|
||||
typename value_map::iterator begin()
|
||||
{
|
||||
return this->store_.begin();
|
||||
}
|
||||
typename value_map::const_iterator begin() const
|
||||
{
|
||||
return this->store_.begin();
|
||||
}
|
||||
typename value_map::iterator end()
|
||||
{
|
||||
return this->store_.end();
|
||||
}
|
||||
typename value_map::const_iterator end() const
|
||||
{
|
||||
return this->store_.end();
|
||||
}
|
||||
|
||||
void serialize(utils::buffer_serializer& buffer) const
|
||||
{
|
||||
buffer.write(this->block_mutation_);
|
||||
buffer.write_map(this->store_);
|
||||
}
|
||||
|
||||
void deserialize(utils::buffer_deserializer& buffer)
|
||||
{
|
||||
buffer.read(this->block_mutation_);
|
||||
buffer.read_map(this->store_);
|
||||
}
|
||||
|
||||
private:
|
||||
user_handle_table* table_;
|
||||
bool block_mutation_{false};
|
||||
value_map store_{};
|
||||
};
|
||||
@@ -54,19 +54,47 @@ struct event : ref_counted_object
|
||||
}
|
||||
};
|
||||
|
||||
struct window : ref_counted_object
|
||||
template <typename GuestType>
|
||||
struct user_object : ref_counted_object
|
||||
{
|
||||
using guest_type = GuestType;
|
||||
emulator_object<GuestType> guest;
|
||||
|
||||
user_object(memory_interface& memory)
|
||||
: guest(memory)
|
||||
{
|
||||
}
|
||||
|
||||
void serialize_object(utils::buffer_serializer& buffer) const override
|
||||
{
|
||||
buffer.write(this->guest);
|
||||
}
|
||||
|
||||
void deserialize_object(utils::buffer_deserializer& buffer) override
|
||||
{
|
||||
buffer.read(this->guest);
|
||||
}
|
||||
};
|
||||
|
||||
struct window : user_object<USER_WINDOW>
|
||||
{
|
||||
uint32_t thread_id{};
|
||||
std::u16string name{};
|
||||
std::u16string class_name{};
|
||||
int32_t width;
|
||||
int32_t height;
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
int32_t width{};
|
||||
int32_t height{};
|
||||
int32_t x{};
|
||||
int32_t y{};
|
||||
std::unordered_map<std::u16string, uint64_t> props;
|
||||
|
||||
window(memory_interface& memory)
|
||||
: user_object(memory)
|
||||
{
|
||||
}
|
||||
|
||||
void serialize_object(utils::buffer_serializer& buffer) const override
|
||||
{
|
||||
user_object::serialize_object(buffer);
|
||||
buffer.write(this->thread_id);
|
||||
buffer.write(this->name);
|
||||
buffer.write(this->class_name);
|
||||
@@ -79,6 +107,7 @@ struct window : ref_counted_object
|
||||
|
||||
void deserialize_object(utils::buffer_deserializer& buffer) override
|
||||
{
|
||||
user_object::deserialize_object(buffer);
|
||||
buffer.read(this->thread_id);
|
||||
buffer.read(this->name);
|
||||
buffer.read(this->class_name);
|
||||
@@ -186,7 +215,6 @@ struct file : ref_counted_object
|
||||
utils::file_handle handle{};
|
||||
std::u16string name{};
|
||||
std::optional<file_enumeration_state> enumeration_state{};
|
||||
std::optional<std::u16string> deferred_rename;
|
||||
|
||||
bool is_file() const
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user