CreateRemoteThread and related stuff (patch)

Roger Olson u60 at comcast.net
Thu Aug 26 23:05:10 CDT 2004


Hi All,

I have been using spare time ro study a means to implement this api for
several
months in order to get my app (United Devices) to work but have been on
the usual steep learning curve for Win32/Posix C and how Wine interacts.  In
looking at the wonderful work Alexander has submitted with this patch, I can
see this was at least a mile over my head but am gratified to know I was at
least exploring in the appropriate areas.

I have a question however, and by no means is this intended to be a critique
but
rather a newbie inquirey  (I am too new to know what I don't know yet) and
am
very happy a developer was willing to take this on. :)

I am wondering why delete the CreateThread()  code and refer all such
requests
to CreateRemoteThread()?  It would appear to me that retaining the
CreateThread()
code in addition to and compliant with the patch changes would be more
expeditious
for apps that do not need a call for Remote Operations.

I ask this as I performed a cheap hack by copying the CreateThread() code to
CreateRemoteThread(), sprinkled a bunch of Fixme's thru out the appropriate
functions to see what info my app provided and what it may be looking for.
The app
actually worked quite well with the exception of spurious blocked threads
upon closing,
what a surprise :).  Any help greatly appreciated and since I'm on the Left
Coast, I
can say "I'll be Back" to hopefully offer some production input.

Thanks, Roger

----- Original Message ----- 
From: "Alexander Yaworsky" <yaworsky at migusoft.ru>
To: "Roger Olson" <u60 at comcast.net>
Cc: <wine-devel at winehq.org>
Sent: Monday, August 23, 2004 4:15 AM
Subject: CreateRemoteThread and related stuff (patch)


> 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_pt
r, 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