Hello
This is a basic framework. Not finished, not really tested -- just stable point. It does no harm for applications I'm using. I would be glad to get some comments and suggestions.
This patch does not contain files generated by tools/make_requests
Index: dlls/kernel/kernel_private.h =================================================================== RCS file: /home/wine/wine/dlls/kernel/kernel_private.h,v retrieving revision 1.20 diff -u -r1.20 kernel_private.h --- dlls/kernel/kernel_private.h 14 May 2004 21:43:18 -0000 1.20 +++ dlls/kernel/kernel_private.h 23 Aug 2004 09:28:39 -0000 @@ -91,4 +91,6 @@ } INSTANCEDATA; #include "poppack.h"
+extern void CALLBACK THREAD_Start( void *ptr ); + #endif Index: dlls/kernel/process.c =================================================================== RCS file: /home/wine/wine/dlls/kernel/process.c,v retrieving revision 1.71 diff -u -r1.71 process.c --- dlls/kernel/process.c 18 Aug 2004 21:03:32 -0000 1.71 +++ dlls/kernel/process.c 23 Aug 2004 09:29:03 -0000 @@ -894,6 +894,7 @@ { req->peb = peb; req->ldt_copy = &wine_ldt_copy; + req->kernel_thread_start = THREAD_Start; if ((ret = !wine_server_call_err( req ))) { main_exe_file = reply->exe_file; Index: dlls/kernel/thread.c =================================================================== RCS file: /home/wine/wine/dlls/kernel/thread.c,v retrieving revision 1.19 diff -u -r1.19 thread.c --- dlls/kernel/thread.c 7 Jul 2004 00:49:34 -0000 1.19 +++ dlls/kernel/thread.c 23 Aug 2004 09:29:08 -0000 @@ -90,13 +90,13 @@ * * Start execution of a newly created thread. Does not return. */ -static void CALLBACK THREAD_Start( void *ptr ) +void CALLBACK THREAD_Start( void *ptr ) { struct new_thread_info *info = ptr; LPTHREAD_START_ROUTINE func = info->func; void *arg = info->arg;
- RtlFreeHeap( GetProcessHeap(), 0, info ); + VirtualFree( info, 0, MEM_RELEASE );
if (TRACE_ON(relay)) DPRINTF("%04lx:Starting thread (entryproc=%p)\n", GetCurrentThreadId(), func ); @@ -121,39 +121,8 @@ LPTHREAD_START_ROUTINE start, LPVOID param, DWORD flags, LPDWORD id ) { - HANDLE handle; - CLIENT_ID client_id; - NTSTATUS status; - SIZE_T stack_reserve = 0, stack_commit = 0; - struct new_thread_info *info; - - if (!(info = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*info) ))) - { - SetLastError( ERROR_NOT_ENOUGH_MEMORY ); - return 0; - } - info->func = start; - info->arg = param; - - if (flags & STACK_SIZE_PARAM_IS_A_RESERVATION) stack_reserve = stack; - else stack_commit = stack; - - status = RtlCreateUserThread( GetCurrentProcess(), NULL, (flags & CREATE_SUSPENDED) != 0, - NULL, stack_reserve, stack_commit, - THREAD_Start, info, &handle, &client_id ); - if (status == STATUS_SUCCESS) - { - if (id) *id = (DWORD)client_id.UniqueThread; - if (sa && (sa->nLength >= sizeof(*sa)) && sa->bInheritHandle) - SetHandleInformation( handle, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT ); - } - else - { - RtlFreeHeap( GetProcessHeap(), 0, info ); - SetLastError( RtlNtStatusToDosError(status) ); - handle = 0; - } - return handle; + return CreateRemoteThread( GetCurrentProcess(), + sa, stack, start, param, flags, id ); }
@@ -168,16 +137,68 @@ * Success: Handle to the new thread. * Failure: NULL. Use GetLastError() to find the error cause. * - * BUGS - * Unimplemented */ HANDLE WINAPI CreateRemoteThread( HANDLE hProcess, SECURITY_ATTRIBUTES *sa, SIZE_T stack, LPTHREAD_START_ROUTINE start, LPVOID param, DWORD flags, LPDWORD id ) { - FIXME("(): stub, Write Me.\n"); + extern BOOL __wine_is_current_process( HANDLE hProcess ); + + HANDLE handle; + CLIENT_ID client_id; + NTSTATUS status; + SIZE_T stack_reserve = 0, stack_commit = 0; + struct new_thread_info *info; + PRTL_THREAD_START_ROUTINE start_addr; + + if (!(info = VirtualAllocEx( hProcess, NULL, sizeof(*info), + MEM_COMMIT, PAGE_READWRITE ))) + return 0; + + if( __wine_is_current_process( hProcess ) ) + { + info->func = start; + info->arg = param; + start_addr = (void*) THREAD_Start; + } + else + { + struct new_thread_info local_info; + DWORD written; + + local_info.func = start; + local_info.arg = param; + if( ! WriteProcessMemory( hProcess, &info, &local_info, + sizeof(struct new_thread_info), &written ) ) + return NULL; + SERVER_START_REQ( get_kernel_thread_start ) + { + req->handle = hProcess; + if (!(status = wine_server_call( req ))) + start_addr = (PRTL_THREAD_START_ROUTINE) reply->address; + } + SERVER_END_REQ; + if (status) + goto error; + } + + if (flags & STACK_SIZE_PARAM_IS_A_RESERVATION) stack_reserve = stack; + else stack_commit = stack; + + status = RtlCreateUserThread( hProcess, NULL, (flags & CREATE_SUSPENDED) != 0, + NULL, stack_reserve, stack_commit, + start_addr, info, &handle, &client_id ); + if (status) + goto error; + + if (id) *id = (DWORD)client_id.UniqueThread; + if (sa && (sa->nLength >= sizeof(*sa)) && sa->bInheritHandle) + SetHandleInformation( handle, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT ); + return handle;
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED); +error: + VirtualFreeEx( hProcess, info, 0, MEM_RELEASE ); + SetLastError( RtlNtStatusToDosError(status) ); return NULL; }
Index: dlls/ntdll/ntdll.spec =================================================================== RCS file: /home/wine/wine/dlls/ntdll/ntdll.spec,v retrieving revision 1.162 diff -u -r1.162 ntdll.spec --- dlls/ntdll/ntdll.spec 18 Aug 2004 00:04:58 -0000 1.162 +++ dlls/ntdll/ntdll.spec 23 Aug 2004 09:29:22 -0000 @@ -1135,6 +1135,9 @@ @ cdecl wine_nt_to_unix_file_name(ptr ptr long long) @ cdecl __wine_init_windows_dir(wstr wstr)
+# remote operations +@ cdecl __wine_is_current_process(long) + ################################################################ # Wine dll separation hacks, these will go away, don't use them # Index: dlls/ntdll/ntdll_misc.h =================================================================== RCS file: /home/wine/wine/dlls/ntdll/ntdll_misc.h,v retrieving revision 1.48 diff -u -r1.48 ntdll_misc.h --- dlls/ntdll/ntdll_misc.h 15 Jul 2004 22:07:21 -0000 1.48 +++ dlls/ntdll/ntdll_misc.h 23 Aug 2004 09:29:22 -0000 @@ -98,4 +98,9 @@ extern int ntdll_wcstoumbs(DWORD flags, const WCHAR* src, int srclen, char* dst, int dstlen, const char* defchar, int *used );
+/* remote operations */ +extern BOOL __wine_is_current_process( HANDLE handle ); +extern NTSTATUS remote_op( HANDLE process, int type, + void* params, int params_size, void* result, int* result_size ); + #endif Index: dlls/ntdll/thread.c =================================================================== RCS file: /home/wine/wine/dlls/ntdll/thread.c,v retrieving revision 1.20 diff -u -r1.20 thread.c --- dlls/ntdll/thread.c 13 Aug 2004 23:20:27 -0000 1.20 +++ dlls/ntdll/thread.c 23 Aug 2004 09:29:26 -0000 @@ -215,6 +215,29 @@ ULONG size; int request_pipe[2]; NTSTATUS status; + + if( ! __wine_is_current_process( process ) ) + { + struct remote_op_params_new_thread op_params; + struct remote_op_result_new_thread op_result; + int result_size = sizeof(struct remote_op_result_new_thread); + + op_params.suspend = suspended; + op_params.stack_addr = stack_addr; + op_params.stack_reserve = stack_reserve; + op_params.stack_commit = stack_commit; + op_params.start = start; + op_params.param = param; + status = remote_op( process, REMOTE_OP_NEW_THREAD, + &op_params, sizeof(op_params), + &op_result, &result_size ); + if (status) + return status; + + handle = op_result.handle; + tid = op_result.tid; + goto success; + }
if (pipe( request_pipe ) == -1) return STATUS_TOO_MANY_OPENED_FILES; fcntl( request_pipe[1], F_SETFD, 1 ); /* set close on exec flag */ @@ -284,6 +307,7 @@ goto error; }
+success: if (id) id->UniqueThread = (HANDLE)tid; if (handle_ptr) *handle_ptr = handle; else NtClose( handle ); Index: dlls/ntdll/virtual.c =================================================================== RCS file: /home/wine/wine/dlls/ntdll/virtual.c,v retrieving revision 1.38 diff -u -r1.38 virtual.c --- dlls/ntdll/virtual.c 18 Aug 2004 00:04:58 -0000 1.38 +++ dlls/ntdll/virtual.c 23 Aug 2004 09:29:36 -0000 @@ -1024,11 +1024,11 @@
/*********************************************************************** - * is_current_process + * __wine_is_current_process * * Check whether a process handle is for the current process. */ -static BOOL is_current_process( HANDLE handle ) +BOOL __wine_is_current_process( HANDLE handle ) { BOOL ret = FALSE;
@@ -1045,6 +1045,53 @@
/*********************************************************************** + * remote_op + * + */ +NTSTATUS remote_op( HANDLE process, int type, + void* params, int params_size, void* result, int* result_size ) +{ + HANDLE event; + NTSTATUS status, remote_status; + + /* send params */ + SERVER_START_REQ( remote_operation ) + { + req->handle = process; + req->type = type; + if (params) wine_server_add_data( req, params, params_size ); + if (!(status = wine_server_call( req ))) + event = reply->event; + } + SERVER_END_REQ; + if (status) + return status; + + /* wait for completion */ + status = NtWaitForMultipleObjects( 1, &event, FALSE, FALSE, NULL ); + NtClose( event ); + if (HIWORD(status)) + return status; + + /* get result */ + remote_status = 0; /* make compiler happy */ + SERVER_START_REQ( remote_operation_result ) + { + wine_server_set_reply( req, result, *result_size ); + if (!(status = wine_server_call( req ))) + { + remote_status = reply->status; + if (result) + *result_size = wine_server_reply_size( reply ); + } + } + SERVER_END_REQ; + + return status? status : remote_status; +} + + +/*********************************************************************** * virtual_init */ void virtual_init(void) @@ -1158,19 +1205,38 @@ { void *base; BYTE vprot; - DWORD size = *size_ptr; + DWORD size; NTSTATUS status = STATUS_SUCCESS; struct file_view *view;
- if (!is_current_process( process )) - { - ERR("Unsupported on other process\n"); - return STATUS_ACCESS_DENIED; - } + TRACE("%p %p %p %p %lx %08lx\n", process, ret, addr, size_ptr, type, protect ); + + /* sanity check */ + if (NULL == ret || NULL == size_ptr) return STATUS_INVALID_PARAMETER; + + TRACE("size=%08lx\n", *size_ptr ); + if (!(size = *size_ptr)) return STATUS_INVALID_PARAMETER;
- TRACE("%p %08lx %lx %08lx\n", addr, size, type, protect ); + if (!__wine_is_current_process( process )) + { + struct remote_op_params_vm_alloc alloc_params; + struct remote_op_result_vm_alloc alloc_result; + int result_size = sizeof(struct remote_op_result_vm_alloc);
- if (!size) return STATUS_INVALID_PARAMETER; + alloc_params.addr = addr; + alloc_params.size = size; + alloc_params.type = type; + alloc_params.protect = protect; + status = remote_op( process, REMOTE_OP_VM_ALLOC, + &alloc_params, sizeof(alloc_params), + &alloc_result, &result_size ); + if (!status) + { + *ret = alloc_result.base; + *size_ptr = alloc_result.size; + } + return status; + }
/* Round parameters to a page boundary */
@@ -1265,16 +1331,37 @@ FILE_VIEW *view; char *base; NTSTATUS status = STATUS_SUCCESS; - LPVOID addr = *addr_ptr; - DWORD size = *size_ptr; + LPVOID addr; + DWORD size;
- if (!is_current_process( process )) + TRACE("%p %p %p %lx\n", process, addr_ptr, size_ptr, type ); + + /* sanity check */ + if (NULL == addr_ptr || NULL == size_ptr) return ERROR_INVALID_PARAMETER; + + addr = *addr_ptr; + size = *size_ptr; + TRACE("addr=%p size=%08lx\n", addr, size ); + + if (!__wine_is_current_process( process )) { - ERR("Unsupported on other process\n"); - return STATUS_ACCESS_DENIED; - } + struct remote_op_params_vm_free free_params; + struct remote_op_result_vm_free free_result; + int result_size = sizeof(struct remote_op_result_vm_free);
- TRACE("%p %08lx %lx\n", addr, size, type ); + free_params.addr = addr; + free_params.size = size; + free_params.type = type; + status = remote_op( process, REMOTE_OP_VM_FREE, + &free_params, sizeof(free_params), + &free_result, &result_size ); + if (!status) + { + *addr_ptr = free_result.base; + *size_ptr = free_result.size; + } + return status; + }
/* Fix the parameters */
@@ -1341,16 +1428,38 @@ char *base; UINT i; BYTE vprot, *p; - DWORD prot, size = *size_ptr; - LPVOID addr = *addr_ptr; + DWORD prot, size; + LPVOID addr;
- if (!is_current_process( process )) + TRACE("%p %p %p %08lx %p\n", process, addr_ptr, size_ptr, new_prot, old_prot ); + + /* sanity check */ + if (NULL == addr_ptr || NULL == size_ptr) return ERROR_INVALID_PARAMETER; + + addr = *addr_ptr; + size = *size_ptr; + TRACE("addr=%p size=%08lx\n", addr, size ); + + if (!__wine_is_current_process( process )) { - ERR("Unsupported on other process\n"); - return STATUS_ACCESS_DENIED; - } + struct remote_op_params_vm_protect protect_params; + struct remote_op_result_vm_protect protect_result; + int result_size = sizeof(struct remote_op_result_vm_protect);
- TRACE("%p %08lx %08lx\n", addr, size, new_prot ); + protect_params.addr = addr; + protect_params.size = size; + protect_params.new_prot = new_prot; + status = remote_op( process, REMOTE_OP_VM_PROTECT, + &protect_params, sizeof(protect_params), + &protect_result, &result_size ); + if (!status) + { + *addr_ptr = protect_result.base; + *size_ptr = protect_result.size; + if (old_prot) *old_prot = protect_result.old_prot; + } + return status; + }
/* Fix the parameters */
@@ -1409,15 +1518,40 @@ UINT size = 0; MEMORY_BASIC_INFORMATION *info = buffer;
+ TRACE("%p %p %d %p %lu %p\n", process, addr, info_class, buffer, len, res_len ); + + /* sanity check */ + if (NULL == buffer) return ERROR_INVALID_PARAMETER; + + if (!__wine_is_current_process( process )) + { + struct remote_op_params_vm_query *query_params; + int result_size = len; + NTSTATUS status; + + query_params = (struct remote_op_params_vm_query*) + RtlAllocateHeap( GetProcessHeap(), 0, sizeof(struct remote_op_params_vm_query) + len ); + if (!query_params) + return STATUS_NO_MEMORY; + + query_params->addr = (void*) addr; + query_params->info_class = info_class; + if (len) memcpy( query_params + 1, buffer, len ); + status = remote_op( process, REMOTE_OP_VM_QUERY, + query_params, sizeof(struct remote_op_params_vm_query) + len, + buffer, &result_size ); + RtlFreeHeap( GetProcessHeap(), 0, query_params ); + if (!status) + if (res_len) *res_len = result_size; + return status; + } + if (info_class != MemoryBasicInformation) return STATUS_INVALID_INFO_CLASS; if (ADDRESS_SPACE_LIMIT && addr >= ADDRESS_SPACE_LIMIT) return STATUS_WORKING_SET_LIMIT_RANGE;
- if (!is_current_process( process )) - { - ERR("Unsupported on other process\n"); - return STATUS_ACCESS_DENIED; - } + /* sanity check */ + if (len < sizeof(MEMORY_BASIC_INFORMATION)) return ERROR_INVALID_PARAMETER;
base = ROUND_ADDR( addr, page_mask );
@@ -1497,10 +1631,10 @@ */ NTSTATUS WINAPI NtLockVirtualMemory( HANDLE process, PVOID *addr, ULONG *size, ULONG unknown ) { - if (!is_current_process( process )) + /* FIXME */ + if (!__wine_is_current_process( process )) { - ERR("Unsupported on other process\n"); - return STATUS_ACCESS_DENIED; + return STATUS_SUCCESS; } return STATUS_SUCCESS; } @@ -1512,10 +1646,10 @@ */ NTSTATUS WINAPI NtUnlockVirtualMemory( HANDLE process, PVOID *addr, ULONG *size, ULONG unknown ) { - if (!is_current_process( process )) + /* FIXME */ + if (!__wine_is_current_process( process )) { - ERR("Unsupported on other process\n"); - return STATUS_ACCESS_DENIED; + return STATUS_SUCCESS; } return STATUS_SUCCESS; } @@ -1608,14 +1742,39 @@ HANDLE shared_file; BOOL removable = FALSE;
- if (!is_current_process( process )) - { - ERR("Unsupported on other process\n"); - return STATUS_ACCESS_DENIED; - } + TRACE("%p %p %p %lu %lu %p %p %d %lu %lx\n", handle, process, addr_ptr, zero_bits, + commit_size, offset, size_ptr, inherit, alloc_type, protect );
- TRACE("handle=%p addr=%p off=%lx%08lx size=%x access=%lx\n", - handle, *addr_ptr, offset->u.HighPart, offset->u.LowPart, size, protect ); + /* sanity check */ + if (NULL == addr_ptr || NULL == size_ptr || NULL == offset) return ERROR_INVALID_PARAMETER; + + TRACE("addr=%p off=%lx%08lx\n", *addr_ptr, offset->u.HighPart, offset->u.LowPart ); + + if (!__wine_is_current_process( process )) + { + struct remote_op_params_vm_map map_params; + struct remote_op_result_vm_map map_result; + int result_size = sizeof(struct remote_op_result_vm_map); + + map_params.addr = *addr_ptr; + map_params.zero_bits = zero_bits; + map_params.commit_size = commit_size; + map_params.offset_low = offset->u.LowPart; + map_params.offset_high = offset->u.HighPart; + map_params.size = *size_ptr; + map_params.inherit = inherit; + map_params.alloc_type = alloc_type; + map_params.protect = protect; + res = remote_op( process, REMOTE_OP_VM_MAP, + &map_params, sizeof(map_params), + &map_result, &result_size ); + if (!res) + { + *addr_ptr = map_result.base; + *size_ptr = map_result.size; + } + return res; + }
/* Check parameters */
@@ -1764,11 +1923,14 @@ NTSTATUS status = STATUS_INVALID_PARAMETER; void *base = ROUND_ADDR( addr, page_mask );
- if (!is_current_process( process )) + TRACE("%p %p base=%p\n", process, addr, base ); + + if (!__wine_is_current_process( process )) { - ERR("Unsupported on other process\n"); - return STATUS_ACCESS_DENIED; + return remote_op( process, REMOTE_OP_VM_UNMAP, + &addr, sizeof(addr), NULL, NULL ); } + RtlEnterCriticalSection( &csVirtual ); if ((view = VIRTUAL_FindView( base )) && (base == view->base)) { @@ -1789,13 +1951,38 @@ { FILE_VIEW *view; NTSTATUS status = STATUS_SUCCESS; - void *addr = ROUND_ADDR( *addr_ptr, page_mask ); + void *addr; + ULONG size;
- if (!is_current_process( process )) + TRACE("%p %p %p %lx\n", process, addr_ptr, size_ptr, unknown ); + + /* sanity check */ + if (NULL == addr_ptr || NULL == size_ptr) return ERROR_INVALID_PARAMETER; + + size = *size_ptr; + TRACE("addr=%p size=%08lx\n", *addr_ptr, size ); + + if (!__wine_is_current_process( process )) { - ERR("Unsupported on other process\n"); - return STATUS_ACCESS_DENIED; + struct remote_op_params_vm_flush flush_params; + struct remote_op_result_vm_flush flush_result; + int result_size = sizeof(struct remote_op_result_vm_flush); + + flush_params.addr = (void*) *addr_ptr; + flush_params.size = size; + flush_params.unknown = unknown; + status = remote_op( process, REMOTE_OP_VM_FLUSH, + &flush_params, sizeof(flush_params), + &flush_result, &result_size ); + if (!status) + { + *addr_ptr = flush_result.base; + if (!*size_ptr) *size_ptr = flush_result.size; + } + return status; } + + addr = ROUND_ADDR( *addr_ptr, page_mask ); RtlEnterCriticalSection( &csVirtual ); if (!(view = VIRTUAL_FindView( addr ))) status = STATUS_INVALID_PARAMETER; else Index: server/process.c =================================================================== RCS file: /home/wine/wine/server/process.c,v retrieving revision 1.117 diff -u -r1.117 process.c --- server/process.c 14 Jun 2004 17:02:00 -0000 1.117 +++ server/process.c 23 Aug 2004 09:30:22 -0000 @@ -45,6 +45,7 @@ #include "request.h" #include "console.h" #include "user.h" +#include "object.h"
/* process structure */
@@ -972,6 +973,7 @@ reply->info_size = 0; current->process->peb = req->peb; current->process->ldt_copy = req->ldt_copy; + current->process->kernel_thread_start = req->kernel_thread_start; current->process->startup_info = init_process( reply ); }
@@ -1188,5 +1190,136 @@ reply->event = alloc_handle( current->process, process->idle_event, EVENT_ALL_ACCESS, 0 ); release_object( process ); + } +} + +/* return address of internal thread start function in kernel32 */ +DECL_HANDLER(get_kernel_thread_start) +{ + struct process *process; + + /* because this is used for CreateRemoteThread, + required access rights must be the same + */ + if ((process = get_process_from_handle( req->handle, + PROCESS_CREATE_THREAD + | PROCESS_QUERY_INFORMATION + | PROCESS_VM_OPERATION + | PROCESS_VM_READ | PROCESS_VM_WRITE ))) + { + reply->address = process->kernel_thread_start; + release_object( process ); + } +} + +/* Accept parameters for remote operation and start it */ +DECL_HANDLER(remote_operation) +{ + int access; + struct process *process; + struct event *event; + + /* define required access rights */ + switch( req->type ) + { + case REMOTE_OP_NEW_THREAD: + access = PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION + | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE; + break; + case REMOTE_OP_VM_ALLOC: access = PROCESS_VM_OPERATION; break; + case REMOTE_OP_VM_FREE: access = PROCESS_VM_OPERATION; break; + case REMOTE_OP_VM_PROTECT: access = PROCESS_VM_OPERATION; break; + case REMOTE_OP_VM_QUERY: access = PROCESS_QUERY_INFORMATION; break; + case REMOTE_OP_VM_MAP: access = PROCESS_VM_OPERATION; break; + case REMOTE_OP_VM_UNMAP: access = PROCESS_VM_OPERATION; break; + case REMOTE_OP_VM_FLUSH: access = PROCESS_VM_OPERATION; break; /* FIXME: is access right? */ + default: + set_error( STATUS_INVALID_PARAMETER ); + return; + } + + /* get process object */ + if (!(process = get_process_from_handle( req->handle, access ))) return; + + /* dispose result data buffer if allocated */ + if (current->result_data) + { + free( current->result_data ); + current->result_data = NULL; + } + + /* create event object */ + reply->event = NULL; + if (current->result_event) + { + release_object( current->result_event ); + current->result_event = NULL; + } + if (!(event = create_event( NULL, 0, 1, 0 ))) + goto error; + + if (!(reply->event = alloc_handle( current->process, event, EVENT_ALL_ACCESS, FALSE ))) + goto error; + + /* FIXME: pass somehow operation type, params and originator thread id + for some thread in the process and force execution of operation */ + set_error( STATUS_NOT_IMPLEMENTED ); + + /* save event object in thread structure for future set operation; + we do not release it here */ + current->result_event = event; + release_object( process ); + return; + +error: + if (reply->event) close_handle( current->process, reply->event, NULL ); + if (event) release_object( event ); + release_object( process ); +} + +/* save result of remote operation and wakeup originator */ +DECL_HANDLER(remote_operation_complete) +{ + struct thread *thread = get_thread_from_id( req->originator ); + + if (!thread) return; + + /* save status */ + thread->remote_status = req->status; + + /* allocate buffer for result data, if required */ + if (thread->result_data) + { + free( thread->result_data ); + thread->result_data = NULL; + } + if ((thread->result_size = get_req_data_size())) + { + if ((thread->result_data = mem_alloc( thread->result_size ))) + memcpy( thread->result_data, get_req_data(), thread->result_size ); + else + thread->remote_status = get_error(); + } + + /* set event */ + if (thread->result_event) + { + set_event( thread->result_event ); + release_object( thread->result_event ); + thread->result_event = NULL; + } + release_object( thread ); +} + +/* return status and result data from remote opertaion */ +DECL_HANDLER(remote_operation_result) +{ + reply->status = current->remote_status; + + if (current->result_data) + { + void *result = current->result_data; + current->result_data = NULL; + set_reply_data_ptr( result, current->result_size ); } } Index: server/process.h =================================================================== RCS file: /home/wine/wine/server/process.h,v retrieving revision 1.42 diff -u -r1.42 process.h --- server/process.h 10 Dec 2003 04:08:06 -0000 1.42 +++ server/process.h 23 Aug 2004 09:30:24 -0000 @@ -79,6 +79,8 @@ struct process_dll exe; /* main exe file */ void *peb; /* PEB address in client address space */ void *ldt_copy; /* pointer to LDT copy in client addr space */ + void *kernel_thread_start; /* addr of internal kernel32 thread routine */ + /* (in client address space) */ };
struct process_snapshot Index: server/protocol.def =================================================================== RCS file: /home/wine/wine/server/protocol.def,v retrieving revision 1.110 diff -u -r1.110 protocol.def --- server/protocol.def 18 Aug 2004 00:04:58 -0000 1.110 +++ server/protocol.def 23 Aug 2004 09:30:45 -0000 @@ -232,6 +232,7 @@ @REQ(init_process) void* peb; /* addr of PEB */ void* ldt_copy; /* addr of LDT copy */ + void* kernel_thread_start; /* addr of internal kernel32 thread routine */ @REPLY int create_flags; /* creation flags */ unsigned int server_start; /* server start time (GetTickCount) */ @@ -2166,3 +2167,133 @@ #define SET_GLOBAL_SHELL_WINDOWS 0x01 /* set both main shell and listview windows */ #define SET_GLOBAL_PROGMAN_WINDOW 0x02 #define SET_GLOBAL_TASKMAN_WINDOW 0x04 + +/* Get address of kernel32 internal THREAD_Start function */ +@REQ(get_kernel_thread_start) + obj_handle_t handle; /* process handle */ +@REPLY + void* address; +@END + +/* Accept parameters for remote operation and start it */ +@REQ(remote_operation) + obj_handle_t handle; /* process handle */ + int type; /* operation type (see below) */ + VARARG(data,bytes); /* operation parameters (see below) */ +@REPLY + obj_handle_t event; /* originator waits for it */ +@END +enum remote_op_type +{ + REMOTE_OP_NEW_THREAD, + REMOTE_OP_VM_ALLOC, + REMOTE_OP_VM_FREE, + REMOTE_OP_VM_PROTECT, + REMOTE_OP_VM_QUERY, + REMOTE_OP_VM_MAP, + REMOTE_OP_VM_UNMAP, + REMOTE_OP_VM_FLUSH +}; + +/* Notify that remote operation has been complete */ +@REQ(remote_operation_complete) + thread_id_t originator; /* originator thread id */ + unsigned int status; /* operation status */ + VARARG(data,bytes); /* operation result data (see below) */ +@END + +/* Get result of remote opertaion */ +@REQ(remote_operation_result) +@REPLY + unsigned int status; /* operation status */ + VARARG(data,bytes); /* operation result data (see below) */ +@END + +struct remote_op_params_new_thread +{ + int suspend; + void *stack_addr; + unsigned int stack_reserve; + unsigned int stack_commit; + void *start; + void *param; +}; +struct remote_op_result_new_thread +{ + obj_handle_t handle; + thread_id_t tid; +}; + +struct remote_op_params_vm_alloc +{ + void *addr; + unsigned long size; + unsigned long type; + unsigned long protect; +}; +struct remote_op_result_vm_alloc +{ + void *base; + unsigned long size; +}; + +struct remote_op_params_vm_free +{ + void *addr; + unsigned long size; + unsigned long type; +}; +struct remote_op_result_vm_free +{ + void *base; + unsigned long size; +}; + +struct remote_op_params_vm_protect +{ + void *addr; + unsigned long size; + unsigned long new_prot; +}; +struct remote_op_result_vm_protect +{ + void *base; + unsigned long size; + unsigned long old_prot; +}; + +struct remote_op_params_vm_query +{ + void *addr; + int info_class; +}; + +struct remote_op_params_vm_map +{ + void *addr; + unsigned long zero_bits; + unsigned long commit_size; + unsigned long offset_low; + long offset_high; + unsigned long size; + int inherit; + unsigned long alloc_type; + unsigned long protect; +}; +struct remote_op_result_vm_map +{ + void *base; + unsigned long size; +}; + +struct remote_op_params_vm_flush +{ + void *addr; + unsigned long size; + unsigned long unknown; +}; +struct remote_op_result_vm_flush +{ + void *base; + unsigned long size; +}; Index: server/thread.c =================================================================== RCS file: /home/wine/wine/server/thread.c,v retrieving revision 1.103 diff -u -r1.103 thread.c --- server/thread.c 27 Oct 2003 22:10:22 -0000 1.103 +++ server/thread.c 23 Aug 2004 09:30:54 -0000 @@ -142,6 +142,8 @@ thread->suspend = 0; thread->creation_time = time(NULL); thread->exit_time = 0; + thread->result_data = NULL; + thread->result_event = NULL;
for (i = 0; i < MAX_INFLIGHT_FDS; i++) thread->inflight[i].server = thread->inflight[i].client = -1; @@ -210,6 +212,8 @@ if (thread->request_fd) release_object( thread->request_fd ); if (thread->reply_fd) release_object( thread->reply_fd ); if (thread->wait_fd) release_object( thread->wait_fd ); + if (thread->result_data) free( thread->result_data ); + if (thread->result_event) release_object( thread->result_event ); free_msg_queue( thread ); cleanup_clipboard_thread(thread); destroy_thread_windows( thread ); @@ -226,6 +230,8 @@ thread->request_fd = NULL; thread->reply_fd = NULL; thread->wait_fd = NULL; + thread->result_data = NULL; + thread->result_event = NULL;
if (thread == booting_thread) /* killing booting thread */ { Index: server/thread.h =================================================================== RCS file: /home/wine/wine/server/thread.h,v retrieving revision 1.56 diff -u -r1.56 thread.h --- server/thread.h 10 Dec 2003 01:12:18 -0000 1.56 +++ server/thread.h 23 Aug 2004 09:30:56 -0000 @@ -94,6 +94,10 @@ time_t creation_time; /* Thread creation time */ time_t exit_time; /* Thread exit time */ struct token *token; /* security token associated with this thread */ + unsigned int remote_status; /* error code from remote operation */ + void *result_data; /* result data from remote operation */ + int result_size; /* size of result data */ + struct event *result_event; /* originator of remote operation waits for it */ };
struct thread_snapshot