From d08bcbae9c96fbafd43f80c56f9bd0340e72532f Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sun, 18 May 2025 09:13:26 +0200 Subject: [PATCH 1/6] Add window object --- src/windows-emulator/handles.hpp | 13 +++++----- src/windows-emulator/process_context.hpp | 1 + src/windows-emulator/syscalls/thread.cpp | 13 ++++++++++ src/windows-emulator/windows_objects.hpp | 33 ++++++++++++++++++++++++ 4 files changed, 54 insertions(+), 6 deletions(-) diff --git a/src/windows-emulator/handles.hpp b/src/windows-emulator/handles.hpp index 963bfcae..1efcce77 100644 --- a/src/windows-emulator/handles.hpp +++ b/src/windows-emulator/handles.hpp @@ -19,6 +19,7 @@ struct handle_types registry, mutant, token, + window, }; }; @@ -238,7 +239,7 @@ class handle_store : public generic_handle_store return h; } - bool erase(const typename value_map::iterator& entry) + std::pair erase(const typename value_map::iterator& entry) { if (this->block_mutation_) { @@ -247,25 +248,25 @@ class handle_store : public generic_handle_store if (entry == this->store_.end()) { - return false; + return {entry, false}; } if constexpr (handle_detail::has_deleter_function()) { if (!T::deleter(entry->second)) { - return true; + return {entry, true}; } } - this->store_.erase(entry); - return true; + auto new_iter = this->store_.erase(entry); + return {new_iter, true}; } bool erase(const handle_value h) { const auto entry = this->get_iterator(h); - return this->erase(entry); + return this->erase(entry).second; } bool erase(const handle h) override diff --git a/src/windows-emulator/process_context.hpp b/src/windows-emulator/process_context.hpp index 2cacaf58..5c41be57 100644 --- a/src/windows-emulator/process_context.hpp +++ b/src/windows-emulator/process_context.hpp @@ -109,6 +109,7 @@ struct process_context handle_store semaphores{}; handle_store ports{}; handle_store mutants{}; + handle_store windows{}; handle_store registry_keys{}; std::map atoms{}; diff --git a/src/windows-emulator/syscalls/thread.cpp b/src/windows-emulator/syscalls/thread.cpp index a0f4af92..b34aa3d3 100644 --- a/src/windows-emulator/syscalls/thread.cpp +++ b/src/windows-emulator/syscalls/thread.cpp @@ -279,6 +279,19 @@ namespace syscalls thread->exit_status = exit_status; c.win_emu.callbacks.on_thread_terminated(thread_handle, *thread); + + for (auto i = c.proc.windows.begin(); i != c.proc.windows.end();) + { + if (i->second.thread_id != thread->id) + { + ++i; + continue; + } + + i->second.ref_count = 1; + i = c.proc.windows.erase(i).first; + } + if (thread == c.proc.active_thread) { c.win_emu.yield_thread(); diff --git a/src/windows-emulator/windows_objects.hpp b/src/windows-emulator/windows_objects.hpp index e51143b1..0795e6e0 100644 --- a/src/windows-emulator/windows_objects.hpp +++ b/src/windows-emulator/windows_objects.hpp @@ -39,6 +39,39 @@ struct event : ref_counted_object } }; +struct window : ref_counted_object +{ + uint32_t thread_id{}; + std::u16string name{}; + std::u16string class_name{}; + uint32_t width; + uint32_t height; + uint32_t x; + uint32_t y; + + void serialize_object(utils::buffer_serializer& buffer) const override + { + buffer.write(this->thread_id); + buffer.write(this->name); + buffer.write(this->class_name); + buffer.write(this->width); + buffer.write(this->height); + buffer.write(this->x); + buffer.write(this->y); + } + + void deserialize_object(utils::buffer_deserializer& buffer) override + { + buffer.read(this->thread_id); + buffer.read(this->name); + buffer.read(this->class_name); + buffer.read(this->width); + buffer.read(this->height); + buffer.read(this->x); + buffer.read(this->y); + } +}; + struct mutant : ref_counted_object { uint32_t locked_count{0}; From 0fbd563e8c12aa63312e9300d421f17e1e3ea059 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sun, 18 May 2025 09:51:28 +0200 Subject: [PATCH 2/6] Support window creation --- src/windows-emulator/emulator_utils.hpp | 15 ++++++- src/windows-emulator/process_context.cpp | 2 + src/windows-emulator/syscalls.cpp | 57 ++++++++++++++---------- src/windows-emulator/windows_objects.hpp | 8 ++-- 4 files changed, 52 insertions(+), 30 deletions(-) diff --git a/src/windows-emulator/emulator_utils.hpp b/src/windows-emulator/emulator_utils.hpp index e339d50e..3e4e15c1 100644 --- a/src/windows-emulator/emulator_utils.hpp +++ b/src/windows-emulator/emulator_utils.hpp @@ -161,6 +161,11 @@ class emulator_object return emulator_object(*this->memory_, this->address_ + offset); } + memory_interface* get_memory_interface() const + { + return this->memory_; + } + private: memory_interface* memory_{}; uint64_t address_{}; @@ -310,16 +315,22 @@ class emulator_allocator }; template -std::basic_string read_string(memory_manager& mem, const uint64_t address) +std::basic_string read_string(memory_interface& mem, const uint64_t address, + const std::optional size = {}) { std::basic_string result{}; for (size_t i = 0;; ++i) { + if (size && i >= *size) + { + break; + } + Element element{}; mem.read_memory(address + (i * sizeof(element)), &element, sizeof(element)); - if (!element) + if (!size && !element) { break; } diff --git a/src/windows-emulator/process_context.cpp b/src/windows-emulator/process_context.cpp index 5b565990..affd76a9 100644 --- a/src/windows-emulator/process_context.cpp +++ b/src/windows-emulator/process_context.cpp @@ -271,6 +271,7 @@ void process_context::serialize(utils::buffer_serializer& buffer) const buffer.write(this->semaphores); buffer.write(this->ports); buffer.write(this->mutants); + buffer.write(this->windows); buffer.write(this->registry_keys); buffer.write_map(this->atoms); @@ -309,6 +310,7 @@ void process_context::deserialize(utils::buffer_deserializer& buffer) buffer.read(this->semaphores); buffer.read(this->ports); buffer.read(this->mutants); + buffer.read(this->windows); buffer.read(this->registry_keys); buffer.read_map(this->atoms); diff --git a/src/windows-emulator/syscalls.cpp b/src/windows-emulator/syscalls.cpp index 095b2fe7..923ddc74 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -733,32 +733,41 @@ namespace syscalls return 0; } - hwnd handle_NtUserCreateWindowEx(const syscall_context& c, const DWORD ex_style, - const emulator_object class_name, - const emulator_object cls_version, - const emulator_object window_name, const DWORD style, const int x, - const int y, const int width, const int height, const hwnd parent, - const hmenu menu, const hinstance instance, const pointer l_param, - const DWORD flags, const pointer acbi_buffer) + std::u16string read_large_string(const emulator_object str_obj) { - (void)c; - (void)ex_style; - (void)class_name; - (void)cls_version; - (void)window_name; - (void)style; - (void)x; - (void)y; - (void)width; - (void)height; - (void)parent; - (void)menu; - (void)instance; - (void)l_param; - (void)flags; - (void)acbi_buffer; + if (!str_obj) + { + return {}; + } - return 1; + const auto str = str_obj.read(); + if (!str.bAnsi) + { + return read_string(*str_obj.get_memory_interface(), str.Buffer, str.Length / 2); + } + + const auto ansi_string = read_string(*str_obj.get_memory_interface(), str.Buffer, str.Length); + return u8_to_u16(ansi_string); + } + + hwnd handle_NtUserCreateWindowEx(const syscall_context& c, const DWORD /*ex_style*/, + const emulator_object class_name, + const emulator_object /*cls_version*/, + const emulator_object window_name, const DWORD /*style*/, + const int x, const int y, const int width, const int height, const hwnd /*parent*/, + const hmenu /*menu*/, const hinstance /*instance*/, const pointer /*l_param*/, + const DWORD /*flags*/, const pointer /*acbi_buffer*/) + { + window win{}; + win.x = x; + win.y = y; + win.width = width; + win.height = height; + win.thread_id = c.win_emu.current_thread().id; + win.class_name = read_large_string(class_name); + win.name = read_large_string(window_name); + + return c.proc.windows.store(std::move(win)).bits; } ULONG handle_NtUserGetRawInputDeviceList() diff --git a/src/windows-emulator/windows_objects.hpp b/src/windows-emulator/windows_objects.hpp index 0795e6e0..2c0bebaf 100644 --- a/src/windows-emulator/windows_objects.hpp +++ b/src/windows-emulator/windows_objects.hpp @@ -44,10 +44,10 @@ struct window : ref_counted_object uint32_t thread_id{}; std::u16string name{}; std::u16string class_name{}; - uint32_t width; - uint32_t height; - uint32_t x; - uint32_t y; + int32_t width; + int32_t height; + int32_t x; + int32_t y; void serialize_object(utils::buffer_serializer& buffer) const override { From 6241c10f02884879ea9e213b6204e1b14b183f71 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sun, 18 May 2025 09:51:46 +0200 Subject: [PATCH 3/6] Support window props --- src/windows-emulator/process_context.hpp | 2 +- src/windows-emulator/syscalls.cpp | 32 ++++++++++++++++++++++++ src/windows-emulator/windows_objects.hpp | 3 +++ 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/windows-emulator/process_context.hpp b/src/windows-emulator/process_context.hpp index 5c41be57..8d4c8855 100644 --- a/src/windows-emulator/process_context.hpp +++ b/src/windows-emulator/process_context.hpp @@ -42,7 +42,7 @@ struct process_context std::u16string name; uint32_t ref_count = 0; - atom_entry(std::u16string n, uint32_t count) + atom_entry(std::u16string n, const uint32_t count) : name(std::move(n)), ref_count(count) { diff --git a/src/windows-emulator/syscalls.cpp b/src/windows-emulator/syscalls.cpp index 923ddc74..2cc1867b 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -770,6 +770,36 @@ namespace syscalls return c.proc.windows.store(std::move(win)).bits; } + BOOL handle_NtUserSetProp(const syscall_context& c, const hwnd window, const uint16_t atom, const uint64_t data) + { + auto* win = c.proc.windows.get(window); + auto* prop = c.proc.get_atom_name(atom); + + if (!win || !prop) + { + return FALSE; + } + + win->props[*prop] = data; + + return TRUE; + } + + BOOL handle_NtUserSetProp2(const syscall_context& c, const hwnd window, + const emulator_object>> str, const uint64_t data) + { + auto* win = c.proc.windows.get(window); + if (!win || !str) + { + return FALSE; + } + + auto prop = read_unicode_string(c.emu, str); + win->props[std::move(prop)] = data; + + return TRUE; + } + ULONG handle_NtUserGetRawInputDeviceList() { return 0; @@ -1012,6 +1042,8 @@ void syscall_dispatcher::add_handlers(std::map& ha add_handler(NtUserGetRawInputDeviceList); add_handler(NtUserGetKeyboardType); add_handler(NtUserEnumDisplayDevices); + add_handler(NtUserSetProp); + add_handler(NtUserSetProp2); #undef add_handler } diff --git a/src/windows-emulator/windows_objects.hpp b/src/windows-emulator/windows_objects.hpp index 2c0bebaf..4db28449 100644 --- a/src/windows-emulator/windows_objects.hpp +++ b/src/windows-emulator/windows_objects.hpp @@ -48,6 +48,7 @@ struct window : ref_counted_object int32_t height; int32_t x; int32_t y; + std::unordered_map props; void serialize_object(utils::buffer_serializer& buffer) const override { @@ -58,6 +59,7 @@ struct window : ref_counted_object buffer.write(this->height); buffer.write(this->x); buffer.write(this->y); + buffer.write_map(this->props); } void deserialize_object(utils::buffer_deserializer& buffer) override @@ -69,6 +71,7 @@ struct window : ref_counted_object buffer.read(this->height); buffer.read(this->x); buffer.read(this->y); + buffer.read_map(this->props); } }; From 836262f3d7ef4a55423a6cd33690b298efa0be8c Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sun, 18 May 2025 10:03:56 +0200 Subject: [PATCH 4/6] Stub NtUserChangeWindowMessageFilterEx --- src/windows-emulator/syscalls.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/windows-emulator/syscalls.cpp b/src/windows-emulator/syscalls.cpp index 2cc1867b..5872a974 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -810,6 +810,11 @@ namespace syscalls return 0; } + uint64_t handle_NtUserChangeWindowMessageFilterEx() + { + return 0; + } + BOOL handle_NtUserShowWindow(const syscall_context& c, const hwnd hwnd, const LONG cmd_show) { (void)c; @@ -1044,6 +1049,7 @@ void syscall_dispatcher::add_handlers(std::map& ha add_handler(NtUserEnumDisplayDevices); add_handler(NtUserSetProp); add_handler(NtUserSetProp2); + add_handler(NtUserChangeWindowMessageFilterEx); #undef add_handler } From 67031b40eac0bf287778fa89b29519a1692d4323 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sun, 18 May 2025 10:35:22 +0200 Subject: [PATCH 5/6] More UI syscalls --- src/common/platform/window.hpp | 1 + src/windows-emulator/process_context.cpp | 14 ++++++++++ src/windows-emulator/process_context.hpp | 1 + src/windows-emulator/syscalls.cpp | 34 +++++++++++++++++++++--- 4 files changed, 46 insertions(+), 4 deletions(-) diff --git a/src/common/platform/window.hpp b/src/common/platform/window.hpp index 9e02d09b..b5bbee90 100644 --- a/src/common/platform/window.hpp +++ b/src/common/platform/window.hpp @@ -24,6 +24,7 @@ typedef struct _LARGE_STRING pointer Buffer; } LARGE_STRING; +using hdc = pointer; using hwnd = pointer; using hmenu = pointer; using hinstance = pointer; diff --git a/src/windows-emulator/process_context.cpp b/src/windows-emulator/process_context.cpp index affd76a9..d8aaf239 100644 --- a/src/windows-emulator/process_context.cpp +++ b/src/windows-emulator/process_context.cpp @@ -363,6 +363,20 @@ handle process_context::create_thread(memory_manager& memory, const uint64_t sta return h; } +std::optional process_context::find_atom(const std::u16string_view name) +{ + for (auto& entry : this->atoms) + { + if (entry.second.name == name) + { + ++entry.second.ref_count; + return entry.first; + } + } + + return {}; +} + uint16_t process_context::add_or_find_atom(std::u16string name) { uint16_t index = 1; diff --git a/src/windows-emulator/process_context.hpp b/src/windows-emulator/process_context.hpp index 8d4c8855..155a1d7e 100644 --- a/src/windows-emulator/process_context.hpp +++ b/src/windows-emulator/process_context.hpp @@ -67,6 +67,7 @@ struct process_context handle create_thread(memory_manager& memory, uint64_t start_address, uint64_t argument, uint64_t stack_size, bool suspended); + std::optional find_atom(std::u16string_view name); uint16_t add_or_find_atom(std::u16string name); bool delete_atom(const std::u16string& name); bool delete_atom(uint16_t atom_id); diff --git a/src/windows-emulator/syscalls.cpp b/src/windows-emulator/syscalls.cpp index 5872a974..5ba2bbcf 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -574,6 +574,24 @@ namespace syscalls return STATUS_SUCCESS; } + NTSTATUS handle_NtFindAtom(const syscall_context& c, const uint64_t atom_name, const ULONG length, + const emulator_object atom) + { + const auto name = read_string(c.emu, atom_name, length / 2); + const auto index = c.proc.find_atom(name); + if (!index) + { + return STATUS_OBJECT_NAME_NOT_FOUND; + } + + if (atom) + { + atom.write(*index); + } + + return STATUS_SUCCESS; + } + NTSTATUS handle_NtUserGetAtomName(const syscall_context& c, const RTL_ATOM atom, const emulator_object>> atom_name) { @@ -611,14 +629,15 @@ namespace syscalls return 96; } - NTSTATUS handle_NtUserGetDCEx() + hdc handle_NtUserGetDCEx(const syscall_context& /*c*/, const hwnd window, const uint64_t /*clip_region*/, + const ULONG /*flags*/) { - return 1; + return window; } - NTSTATUS handle_NtUserGetDC() + hdc handle_NtUserGetDC(const syscall_context& c, const hwnd window) { - return handle_NtUserGetDCEx(); + return handle_NtUserGetDCEx(c, window, 0, 0); } NTSTATUS handle_NtUserGetWindowDC() @@ -770,6 +789,11 @@ namespace syscalls return c.proc.windows.store(std::move(win)).bits; } + BOOL handle_NtUserDestroyWindow(const syscall_context& c, const hwnd window) + { + return c.proc.windows.erase(window); + } + BOOL handle_NtUserSetProp(const syscall_context& c, const hwnd window, const uint16_t atom, const uint64_t data) { auto* win = c.proc.windows.get(window); @@ -942,6 +966,7 @@ void syscall_dispatcher::add_handlers(std::map& ha add_handler(NtDxgkIsFeatureEnabled); add_handler(NtAddAtomEx); add_handler(NtAddAtom); + add_handler(NtFindAtom); add_handler(NtDeleteAtom); add_handler(NtUserGetAtomName); add_handler(NtInitializeNlsFiles); @@ -1050,6 +1075,7 @@ void syscall_dispatcher::add_handlers(std::map& ha add_handler(NtUserSetProp); add_handler(NtUserSetProp2); add_handler(NtUserChangeWindowMessageFilterEx); + add_handler(NtUserDestroyWindow); #undef add_handler } From beea923a153f835174640fd800c5b69913d20541 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sun, 18 May 2025 10:52:52 +0200 Subject: [PATCH 6/6] Fix warning --- src/windows-emulator/syscalls.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/windows-emulator/syscalls.cpp b/src/windows-emulator/syscalls.cpp index 5ba2bbcf..364dcab0 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -797,7 +797,7 @@ namespace syscalls BOOL handle_NtUserSetProp(const syscall_context& c, const hwnd window, const uint16_t atom, const uint64_t data) { auto* win = c.proc.windows.get(window); - auto* prop = c.proc.get_atom_name(atom); + const auto* prop = c.proc.get_atom_name(atom); if (!win || !prop) {