CreateRemoteThread and related stuff (patch)
Alexander Yaworsky
yaworsky at migusoft.ru
Mon Aug 23 06:15:02 CDT 2004
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 */
+ at REQ(get_kernel_thread_start)
+ obj_handle_t handle; /* process handle */
+ at REPLY
+ void* address;
+ at END
+
+/* Accept parameters for remote operation and start it */
+ at REQ(remote_operation)
+ obj_handle_t handle; /* process handle */
+ int type; /* operation type (see below) */
+ VARARG(data,bytes); /* operation parameters (see below) */
+ at REPLY
+ obj_handle_t event; /* originator waits for it */
+ at 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 */
+ at REQ(remote_operation_complete)
+ thread_id_t originator; /* originator thread id */
+ unsigned int status; /* operation status */
+ VARARG(data,bytes); /* operation result data (see below) */
+ at END
+
+/* Get result of remote opertaion */
+ at REQ(remote_operation_result)
+ at REPLY
+ unsigned int status; /* operation status */
+ VARARG(data,bytes); /* operation result data (see below) */
+ at 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
More information about the wine-devel
mailing list