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/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/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.cpp b/src/windows-emulator/process_context.cpp index 5b565990..d8aaf239 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); @@ -361,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 2cacaf58..155a1d7e 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) { @@ -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); @@ -109,6 +110,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.cpp b/src/windows-emulator/syscalls.cpp index 095b2fe7..364dcab0 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() @@ -733,32 +752,76 @@ 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; + } + + 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); + const 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() @@ -771,6 +834,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; @@ -898,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); @@ -1003,6 +1072,10 @@ void syscall_dispatcher::add_handlers(std::map& ha add_handler(NtUserGetRawInputDeviceList); add_handler(NtUserGetKeyboardType); add_handler(NtUserEnumDisplayDevices); + add_handler(NtUserSetProp); + add_handler(NtUserSetProp2); + add_handler(NtUserChangeWindowMessageFilterEx); + add_handler(NtUserDestroyWindow); #undef add_handler } 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..4db28449 100644 --- a/src/windows-emulator/windows_objects.hpp +++ b/src/windows-emulator/windows_objects.hpp @@ -39,6 +39,42 @@ struct event : ref_counted_object } }; +struct window : ref_counted_object +{ + uint32_t thread_id{}; + std::u16string name{}; + std::u16string class_name{}; + int32_t width; + int32_t height; + int32_t x; + int32_t y; + std::unordered_map props; + + 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); + buffer.write_map(this->props); + } + + 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); + buffer.read_map(this->props); + } +}; + struct mutant : ref_counted_object { uint32_t locked_count{0};