Framework for remote operations

Alexander Yaworsky yaworsky at migusoft.ru
Wed Aug 25 02:15:27 CDT 2004


Hello

ChangeLog:

Basic framework for thread creation and memory
management functions in context of arbitrarily process.

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 25 Aug 2004 06:38:24 -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.72
diff -u -r1.72 process.c
--- dlls/kernel/process.c 24 Aug 2004 18:46:05 -0000 1.72
+++ dlls/kernel/process.c 25 Aug 2004 06:38:37 -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 25 Aug 2004 06:38:40 -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,66 @@
  *   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");
+    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( GetProcessId( hProcess ) == GetCurrentProcessId() )
+    {
+        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_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 25 Aug 2004 06:38:43 -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 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.21
diff -u -r1.21 thread.c
--- dlls/ntdll/thread.c 23 Aug 2004 18:52:54 -0000 1.21
+++ dlls/ntdll/thread.c 25 Aug 2004 06:38:46 -0000
@@ -215,6 +215,29 @@
     ULONG size;
     int request_pipe[2];
     NTSTATUS status;
+    
+    if( ! 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 25 Aug 2004 06:38:55 -0000
@@ -1028,7 +1028,7 @@
  *
  * Check whether a process handle is for the current process.
  */
-static BOOL is_current_process( HANDLE handle )
+BOOL 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,20 +1205,39 @@
 {
     void *base;
     BYTE vprot;
-    DWORD size = *size_ptr;
+    DWORD size;
     NTSTATUS status = STATUS_SUCCESS;
     struct file_view *view;
 
+    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;
+
     if (!is_current_process( process ))
     {
-        ERR("Unsupported on other process\n");
-        return STATUS_ACCESS_DENIED;
+        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);
+
+        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;
     }
 
-    TRACE("%p %08lx %lx %08lx\n", addr, size, type, protect );
-
-    if (!size) return STATUS_INVALID_PARAMETER;
-
     /* Round parameters to a page boundary */
 
     if (size > 0x7fc00000) return STATUS_WORKING_SET_LIMIT_RANGE; /* 2Gb - 4Mb */
@@ -1265,17 +1331,38 @@
     FILE_VIEW *view;
     char *base;
     NTSTATUS status = STATUS_SUCCESS;
-    LPVOID addr = *addr_ptr;
-    DWORD size = *size_ptr;
+    LPVOID addr;
+    DWORD size;
+
+    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 (!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);
+
+        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;
     }
 
-    TRACE("%p %08lx %lx\n", addr, size, type );
-
     /* Fix the parameters */
 
     size = ROUND_SIZE( addr, size );
@@ -1341,17 +1428,39 @@
     char *base;
     UINT i;
     BYTE vprot, *p;
-    DWORD prot, size = *size_ptr;
-    LPVOID addr = *addr_ptr;
+    DWORD prot, size;
+    LPVOID addr;
+
+    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 (!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);
+
+        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;
     }
 
-    TRACE("%p %08lx %08lx\n", addr, size, new_prot );
-
     /* Fix the parameters */
 
     size = ROUND_SIZE( addr, size );
@@ -1409,16 +1518,41 @@
     UINT size = 0;
     MEMORY_BASIC_INFORMATION *info = buffer;
 
-    if (info_class != MemoryBasicInformation) return STATUS_INVALID_INFO_CLASS;
-    if (ADDRESS_SPACE_LIMIT && addr >= ADDRESS_SPACE_LIMIT)
-        return STATUS_WORKING_SET_LIMIT_RANGE;
+    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 (!is_current_process( process ))
     {
-        ERR("Unsupported on other process\n");
-        return STATUS_ACCESS_DENIED;
+        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;
+
+    /* sanity check */
+    if (len < sizeof(MEMORY_BASIC_INFORMATION)) return ERROR_INVALID_PARAMETER;
+
     base = ROUND_ADDR( addr, page_mask );
 
     /* Find the view containing the address */
@@ -1497,10 +1631,10 @@
  */
 NTSTATUS WINAPI NtLockVirtualMemory( HANDLE process, PVOID *addr, ULONG *size, ULONG unknown )
 {
+    /* FIXME */
     if (!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 )
 {
+    /* FIXME */
     if (!is_current_process( process ))
     {
-        ERR("Unsupported on other process\n");
-        return STATUS_ACCESS_DENIED;
+        return STATUS_SUCCESS;
     }
     return STATUS_SUCCESS;
 }
@@ -1608,15 +1742,40 @@
     HANDLE shared_file;
     BOOL removable = FALSE;
 
+    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 );
+
+    /* 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 (!is_current_process( process ))
     {
-        ERR("Unsupported on other process\n");
-        return STATUS_ACCESS_DENIED;
+        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;
     }
 
-    TRACE("handle=%p addr=%p off=%lx%08lx size=%x access=%lx\n",
-          handle, *addr_ptr, offset->u.HighPart, offset->u.LowPart, size, protect );
-
     /* Check parameters */
 
     if ((offset->u.LowPart & granularity_mask) ||
@@ -1764,11 +1923,14 @@
     NTSTATUS status = STATUS_INVALID_PARAMETER;
     void *base = ROUND_ADDR( addr, page_mask );
 
+    TRACE("%p %p base=%p\n", process, addr, base );
+
     if (!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;
+
+    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 (!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: include/wine/server_protocol.h
===================================================================
RCS file: /home/wine/wine/include/wine/server_protocol.h,v
retrieving revision 1.111
diff -u -r1.111 server_protocol.h
--- include/wine/server_protocol.h 18 Aug 2004 00:04:58 -0000 1.111
+++ include/wine/server_protocol.h 25 Aug 2004 06:39:12 -0000
@@ -239,6 +239,7 @@
     struct request_header __header;
     void*        peb;
     void*        ldt_copy;
+    void*        kernel_thread_start;
 };
 struct init_process_reply
 {
@@ -3095,6 +3096,157 @@
 #define SET_GLOBAL_TASKMAN_WINDOW  0x04
 
 
+struct get_kernel_thread_start_request
+{
+    struct request_header __header;
+    obj_handle_t handle;
+};
+struct get_kernel_thread_start_reply
+{
+    struct reply_header __header;
+    void*        address;
+};
+
+
+struct remote_operation_request
+{
+    struct request_header __header;
+    obj_handle_t handle;
+    int          type;
+    /* VARARG(data,bytes); */
+};
+struct remote_operation_reply
+{
+    struct reply_header __header;
+    obj_handle_t event;
+};
+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
+};
+
+
+struct remote_operation_complete_request
+{
+    struct request_header __header;
+    thread_id_t  originator;
+    unsigned int status;
+    /* VARARG(data,bytes); */
+};
+struct remote_operation_complete_reply
+{
+    struct reply_header __header;
+};
+
+
+struct remote_operation_result_request
+{
+    struct request_header __header;
+};
+struct remote_operation_result_reply
+{
+    struct reply_header __header;
+    unsigned int status;
+    /* VARARG(data,bytes); */
+};
+
+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;
+};
+
+
 enum request
 {
     REQ_new_process,
@@ -3274,6 +3426,10 @@
     REQ_set_clipboard_info,
     REQ_open_token,
     REQ_set_global_windows,
+    REQ_get_kernel_thread_start,
+    REQ_remote_operation,
+    REQ_remote_operation_complete,
+    REQ_remote_operation_result,
     REQ_NB_REQUESTS
 };
 
@@ -3458,6 +3614,10 @@
     struct set_clipboard_info_request set_clipboard_info_request;
     struct open_token_request open_token_request;
     struct set_global_windows_request set_global_windows_request;
+    struct get_kernel_thread_start_request get_kernel_thread_start_request;
+    struct remote_operation_request remote_operation_request;
+    struct remote_operation_complete_request remote_operation_complete_request;
+    struct remote_operation_result_request remote_operation_result_request;
 };
 union generic_reply
 {
@@ -3640,6 +3800,10 @@
     struct set_clipboard_info_reply set_clipboard_info_reply;
     struct open_token_reply open_token_reply;
     struct set_global_windows_reply set_global_windows_reply;
+    struct get_kernel_thread_start_reply get_kernel_thread_start_reply;
+    struct remote_operation_reply remote_operation_reply;
+    struct remote_operation_complete_reply remote_operation_complete_reply;
+    struct remote_operation_result_reply remote_operation_result_reply;
 };
 
 #define SERVER_PROTOCOL_VERSION 149
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 25 Aug 2004 06:39:20 -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 25 Aug 2004 06:39:21 -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 25 Aug 2004 06:39:30 -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/request.h
===================================================================
RCS file: /home/wine/wine/server/request.h,v
retrieving revision 1.102
diff -u -r1.102 request.h
--- server/request.h 20 Jul 2004 22:17:39 -0000 1.102
+++ server/request.h 25 Aug 2004 06:39:32 -0000
@@ -280,6 +280,10 @@
 DECL_HANDLER(set_clipboard_info);
 DECL_HANDLER(open_token);
 DECL_HANDLER(set_global_windows);
+DECL_HANDLER(get_kernel_thread_start);
+DECL_HANDLER(remote_operation);
+DECL_HANDLER(remote_operation_complete);
+DECL_HANDLER(remote_operation_result);
 
 #ifdef WANT_REQUEST_HANDLERS
 
@@ -463,6 +467,10 @@
     (req_handler)req_set_clipboard_info,
     (req_handler)req_open_token,
     (req_handler)req_set_global_windows,
+    (req_handler)req_get_kernel_thread_start,
+    (req_handler)req_remote_operation,
+    (req_handler)req_remote_operation_complete,
+    (req_handler)req_remote_operation_result,
 };
 #endif  /* WANT_REQUEST_HANDLERS */
 
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 25 Aug 2004 06:39:36 -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 25 Aug 2004 06:39:37 -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
Index: server/trace.c
===================================================================
RCS file: /home/wine/wine/server/trace.c,v
retrieving revision 1.212
diff -u -r1.212 trace.c
--- server/trace.c 18 Aug 2004 00:04:58 -0000 1.212
+++ server/trace.c 25 Aug 2004 06:39:49 -0000
@@ -471,6 +471,7 @@
 {
     fprintf( stderr, " peb=%p,", req->peb );
     fprintf( stderr, " ldt_copy=%p", req->ldt_copy );
+    fprintf( stderr, " kernel_thread_start=%p", req->kernel_thread_start );
 }
 
 static void dump_init_process_reply( const struct init_process_reply *req )
@@ -2548,6 +2549,48 @@
     fprintf( stderr, " old_taskman_window=%p", req->old_taskman_window );
 }
 
+static void dump_get_kernel_thread_start_request( const struct get_kernel_thread_start_request *req )
+{
+    fprintf( stderr, " handle=%p", req->handle );
+}
+
+static void dump_get_kernel_thread_start_reply( const struct get_kernel_thread_start_reply *req )
+{
+    fprintf( stderr, " address=%p", req->address );
+}
+
+static void dump_remote_operation_request( const struct remote_operation_request *req )
+{
+    fprintf( stderr, " handle=%p,", req->handle );
+    fprintf( stderr, " type=%d,", req->type );
+    fprintf( stderr, " data=" );
+    dump_varargs_bytes( cur_size );
+}
+
+static void dump_remote_operation_reply( const struct remote_operation_reply *req )
+{
+    fprintf( stderr, " event=%p", req->event );
+}
+
+static void dump_remote_operation_complete_request( const struct remote_operation_complete_request *req )
+{
+    fprintf( stderr, " originator=%04x,", req->originator );
+    fprintf( stderr, " status=%08x,", req->status );
+    fprintf( stderr, " data=" );
+    dump_varargs_bytes( cur_size );
+}
+
+static void dump_remote_operation_result_request( const struct remote_operation_result_request *req )
+{
+}
+
+static void dump_remote_operation_result_reply( const struct remote_operation_result_reply *req )
+{
+    fprintf( stderr, " status=%08x,", req->status );
+    fprintf( stderr, " data=" );
+    dump_varargs_bytes( cur_size );
+}
+
 static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
     (dump_func)dump_new_process_request,
     (dump_func)dump_get_new_process_info_request,
@@ -2726,6 +2769,10 @@
     (dump_func)dump_set_clipboard_info_request,
     (dump_func)dump_open_token_request,
     (dump_func)dump_set_global_windows_request,
+    (dump_func)dump_get_kernel_thread_start_request,
+    (dump_func)dump_remote_operation_request,
+    (dump_func)dump_remote_operation_complete_request,
+    (dump_func)dump_remote_operation_result_request,
 };
 
 static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
@@ -2906,6 +2953,10 @@
     (dump_func)dump_set_clipboard_info_reply,
     (dump_func)dump_open_token_reply,
     (dump_func)dump_set_global_windows_reply,
+    (dump_func)dump_get_kernel_thread_start_reply,
+    (dump_func)dump_remote_operation_reply,
+    (dump_func)0,
+    (dump_func)dump_remote_operation_result_reply,
 };
 
 static const char * const req_names[REQ_NB_REQUESTS] = {
@@ -3086,6 +3137,10 @@
     "set_clipboard_info",
     "open_token",
     "set_global_windows",
+    "get_kernel_thread_start",
+    "remote_operation",
+    "remote_operation_complete",
+    "remote_operation_result",
 };
 
 /* ### make_requests end ### */




More information about the wine-patches mailing list