Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/kernel32/kernel32.spec | 2 +- dlls/kernel32/thread.c | 116 ++++++++++++++++++++++++++++++++++++++++++++ include/winbase.h | 1 + 3 files changed, 118 insertions(+), 1 deletion(-)
diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec index 1cb0b54..de6f007 100644 --- a/dlls/kernel32/kernel32.spec +++ b/dlls/kernel32/kernel32.spec @@ -1603,7 +1603,7 @@ @ stdcall Wow64GetThreadContext(long ptr) # @ stub Wow64GetThreadSelectorEntry @ stdcall Wow64RevertWow64FsRedirection(ptr) -# @ stub Wow64SetThreadContext +@ stdcall Wow64SetThreadContext(long ptr) # @ stub Wow64SuspendThread @ stdcall WriteConsoleA(long ptr long ptr ptr) @ stdcall WriteConsoleInputA(long ptr long ptr) diff --git a/dlls/kernel32/thread.c b/dlls/kernel32/thread.c index caeec63..838cf0f 100644 --- a/dlls/kernel32/thread.c +++ b/dlls/kernel32/thread.c @@ -235,6 +235,122 @@ BOOL WINAPI SetThreadContext( HANDLE handle, /* [in] Handle to thread }
+static NTSTATUS wow64_context_to_server( context_t *to, const WOW64_CONTEXT *from ) +{ + DWORD flags = from->ContextFlags & ~WOW64_CONTEXT_i386; /* get rid of CPU id */ + + memset( to, 0, sizeof(*to) ); + to->cpu = CPU_x86; + + if (flags & WOW64_CONTEXT_CONTROL) + { + to->flags |= SERVER_CTX_CONTROL; + to->ctl.i386_regs.ebp = from->Ebp; + to->ctl.i386_regs.esp = from->Esp; + to->ctl.i386_regs.eip = from->Eip; + to->ctl.i386_regs.cs = from->SegCs; + to->ctl.i386_regs.ss = from->SegSs; + to->ctl.i386_regs.eflags = from->EFlags; + } + if (flags & WOW64_CONTEXT_INTEGER) + { + to->flags |= SERVER_CTX_INTEGER; + to->integer.i386_regs.eax = from->Eax; + to->integer.i386_regs.ebx = from->Ebx; + to->integer.i386_regs.ecx = from->Ecx; + to->integer.i386_regs.edx = from->Edx; + to->integer.i386_regs.esi = from->Esi; + to->integer.i386_regs.edi = from->Edi; + } + if (flags & WOW64_CONTEXT_SEGMENTS) + { + to->flags |= SERVER_CTX_SEGMENTS; + to->seg.i386_regs.ds = from->SegDs; + to->seg.i386_regs.es = from->SegEs; + to->seg.i386_regs.fs = from->SegFs; + to->seg.i386_regs.gs = from->SegGs; + } + if (flags & WOW64_CONTEXT_FLOATING_POINT) + { + to->flags |= SERVER_CTX_FLOATING_POINT; + to->fp.i386_regs.ctrl = from->FloatSave.ControlWord; + to->fp.i386_regs.status = from->FloatSave.StatusWord; + to->fp.i386_regs.tag = from->FloatSave.TagWord; + to->fp.i386_regs.err_off = from->FloatSave.ErrorOffset; + to->fp.i386_regs.err_sel = from->FloatSave.ErrorSelector; + to->fp.i386_regs.data_off = from->FloatSave.DataOffset; + to->fp.i386_regs.data_sel = from->FloatSave.DataSelector; + to->fp.i386_regs.cr0npx = from->FloatSave.Cr0NpxState; + memcpy( to->fp.i386_regs.regs, from->FloatSave.RegisterArea, sizeof(to->fp.i386_regs.regs) ); + } + if (flags & WOW64_CONTEXT_DEBUG_REGISTERS) + { + to->flags |= SERVER_CTX_DEBUG_REGISTERS; + to->debug.i386_regs.dr0 = from->Dr0; + to->debug.i386_regs.dr1 = from->Dr1; + to->debug.i386_regs.dr2 = from->Dr2; + to->debug.i386_regs.dr3 = from->Dr3; + to->debug.i386_regs.dr6 = from->Dr6; + to->debug.i386_regs.dr7 = from->Dr7; + } + if (flags & WOW64_CONTEXT_EXTENDED_REGISTERS) + { + to->flags |= SERVER_CTX_EXTENDED_REGISTERS; + memcpy( to->ext.i386_regs, from->ExtendedRegisters, sizeof(to->ext.i386_regs) ); + } + return STATUS_SUCCESS; +} + + +/*********************************************************************** + * Wow64GetThreadContext [KERNEL32.@] + */ +BOOL WINAPI Wow64SetThreadContext( HANDLE handle, const WOW64_CONTEXT *context) +{ + NTSTATUS ret; + DWORD dummy, i; + context_t server_context; + + wow64_context_to_server( &server_context, context ); + + SERVER_START_REQ( set_thread_context ) + { + req->handle = wine_server_obj_handle( handle ); + req->suspend = 1; + wine_server_add_data( req, &server_context, sizeof(server_context) ); + ret = wine_server_call( req ); + } + SERVER_END_REQ; + + if (ret == STATUS_PENDING) + { + for (i = 0; i < 100; i++) + { + SERVER_START_REQ( set_thread_context ) + { + req->handle = wine_server_obj_handle( handle ); + req->suspend = 0; + wine_server_add_data( req, &server_context, sizeof(server_context) ); + ret = wine_server_call( req ); + } + SERVER_END_REQ; + if (ret == STATUS_PENDING) + { + LARGE_INTEGER timeout; + timeout.QuadPart = -10000; + NtDelayExecution( FALSE, &timeout ); + } + else break; + } + NtResumeThread( handle, &dummy ); + if (ret == STATUS_PENDING) ret = STATUS_ACCESS_DENIED; + } + + if (ret) SetLastError( RtlNtStatusToDosError( ret ) ); + return !ret; +} + + /*********************************************************************** * GetThreadContext [KERNEL32.@] Retrieves context of thread. * diff --git a/include/winbase.h b/include/winbase.h index f7239b8..667df96 100644 --- a/include/winbase.h +++ b/include/winbase.h @@ -2708,6 +2708,7 @@ WINBASEAPI BOOL WINAPI Wow64DisableWow64FsRedirection(PVOID*); WINBASEAPI BOOLEAN WINAPI Wow64EnableWow64FsRedirection(BOOLEAN); WINBASEAPI BOOL WINAPI Wow64GetThreadContext(HANDLE, WOW64_CONTEXT *); WINBASEAPI BOOL WINAPI Wow64RevertWow64FsRedirection(PVOID); +WINBASEAPI BOOL WINAPI Wow64SetThreadContext(HANDLE, const WOW64_CONTEXT *); WINADVAPI DWORD WINAPI WriteEncryptedFileRaw(PFE_IMPORT_FUNC,PVOID,PVOID); WINBASEAPI BOOL WINAPI WriteFile(HANDLE,LPCVOID,DWORD,LPDWORD,LPOVERLAPPED); WINBASEAPI BOOL WINAPI WriteFileEx(HANDLE,LPCVOID,DWORD,LPOVERLAPPED,LPOVERLAPPED_COMPLETION_ROUTINE);