From da8acbc47d6e14ca6a1336dfdb9847356c71cc32 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Thu, 20 Aug 2009 20:05:21 +0200 Subject: [PATCH] server: Define an architecture-independent structure for process startup info. --- dlls/kernel32/process.c | 222 +++++++++++++++++++-------------- dlls/ntdll/thread.c | 129 +++++++++++-------- include/wine/server_protocol.h | 50 ++++++-- server/process.c | 72 +++++++---- server/protocol.def | 48 +++++-- server/request.h | 18 ++- server/trace.c | 89 +++++-------- 7 files changed, 371 insertions(+), 257 deletions(-) diff --git a/dlls/kernel32/process.c b/dlls/kernel32/process.c index 92eb01a022c..ddc93f28fc6 100644 --- a/dlls/kernel32/process.c +++ b/dlls/kernel32/process.c @@ -1430,85 +1430,127 @@ static int fork_and_exec( const char *filename, const WCHAR *cmdline, const WCHA } -/*********************************************************************** - * create_user_params - */ -static RTL_USER_PROCESS_PARAMETERS *create_user_params( LPCWSTR filename, LPCWSTR cmdline, - LPCWSTR cur_dir, LPWSTR env, DWORD flags, - const STARTUPINFOW *startup ) +static inline DWORD append_string( void **ptr, const WCHAR *str ) { - RTL_USER_PROCESS_PARAMETERS *params; - UNICODE_STRING image_str, cmdline_str, curdir_str, desktop, title, runtime, newdir; - NTSTATUS status; - WCHAR buffer[MAX_PATH]; + DWORD len = strlenW( str ); + memcpy( *ptr, str, len * sizeof(WCHAR) ); + *ptr = (WCHAR *)*ptr + len; + return len * sizeof(WCHAR); +} - if(!GetLongPathNameW( filename, buffer, MAX_PATH )) - lstrcpynW( buffer, filename, MAX_PATH ); - if(!GetFullPathNameW( buffer, MAX_PATH, buffer, NULL )) - lstrcpynW( buffer, filename, MAX_PATH ); - RtlInitUnicodeString( &image_str, buffer ); +/*********************************************************************** + * create_startup_info + */ +static startup_info_t *create_startup_info( LPCWSTR filename, LPCWSTR cmdline, + LPCWSTR cur_dir, LPWSTR env, DWORD flags, + const STARTUPINFOW *startup, DWORD *info_size ) +{ + const RTL_USER_PROCESS_PARAMETERS *cur_params; + startup_info_t *info; + DWORD size; + void *ptr; + UNICODE_STRING newdir; + WCHAR imagepath[MAX_PATH]; + HANDLE hstdin, hstdout, hstderr; + + if(!GetLongPathNameW( filename, imagepath, MAX_PATH )) + lstrcpynW( imagepath, filename, MAX_PATH ); + if(!GetFullPathNameW( imagepath, MAX_PATH, imagepath, NULL )) + lstrcpynW( imagepath, filename, MAX_PATH ); + + cur_params = NtCurrentTeb()->Peb->ProcessParameters; - RtlInitUnicodeString( &cmdline_str, cmdline ); newdir.Buffer = NULL; if (cur_dir) { if (RtlDosPathNameToNtPathName_U( cur_dir, &newdir, NULL, NULL )) - { - /* skip \??\ prefix */ - curdir_str.Buffer = newdir.Buffer + 4; - curdir_str.Length = newdir.Length - 4 * sizeof(WCHAR); - curdir_str.MaximumLength = newdir.MaximumLength - 4 * sizeof(WCHAR); - } - else cur_dir = NULL; + cur_dir = newdir.Buffer + 4; /* skip \??\ prefix */ + else + cur_dir = NULL; } - if (startup->lpDesktop) RtlInitUnicodeString( &desktop, startup->lpDesktop ); - if (startup->lpTitle) RtlInitUnicodeString( &title, startup->lpTitle ); - if (startup->lpReserved2 && startup->cbReserved2) + if (!cur_dir) { - runtime.Length = 0; - runtime.MaximumLength = startup->cbReserved2; - runtime.Buffer = (WCHAR*)startup->lpReserved2; + if (NtCurrentTeb()->Tib.SubSystemTib) /* FIXME: hack */ + cur_dir = ((WIN16_SUBSYSTEM_TIB *)NtCurrentTeb()->Tib.SubSystemTib)->curdir.DosPath.Buffer; + else + cur_dir = cur_params->CurrentDirectory.DosPath.Buffer; } - status = RtlCreateProcessParameters( ¶ms, &image_str, NULL, - cur_dir ? &curdir_str : NULL, - &cmdline_str, env, - startup->lpTitle ? &title : NULL, - startup->lpDesktop ? &desktop : NULL, - NULL, - (startup->lpReserved2 && startup->cbReserved2) ? &runtime : NULL ); - RtlFreeUnicodeString( &newdir ); - if (status != STATUS_SUCCESS) - { - SetLastError( RtlNtStatusToDosError(status) ); - return NULL; - } + size = sizeof(*info); + size += strlenW( cur_dir ) * sizeof(WCHAR); + size += cur_params->DllPath.Length; + size += strlenW( imagepath ) * sizeof(WCHAR); + size += strlenW( cmdline ) * sizeof(WCHAR); + if (startup->lpTitle) size += strlenW( startup->lpTitle ) * sizeof(WCHAR); + if (startup->lpDesktop) size += strlenW( startup->lpDesktop ) * sizeof(WCHAR); + /* FIXME: shellinfo */ + if (startup->lpReserved2 && startup->cbReserved2) size += startup->cbReserved2; + size = (size + 1) & ~1; + *info_size = size; - if (flags & CREATE_NEW_PROCESS_GROUP) params->ConsoleFlags = 1; - if (flags & CREATE_NEW_CONSOLE) params->ConsoleHandle = (HANDLE)1; /* FIXME: cf. kernel_main.c */ + if (!(info = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size ))) goto done; + + info->console_flags = cur_params->ConsoleFlags; + if (flags & CREATE_NEW_PROCESS_GROUP) info->console_flags = 1; + if (flags & CREATE_NEW_CONSOLE) info->console = (obj_handle_t)1; /* FIXME: cf. kernel_main.c */ if (startup->dwFlags & STARTF_USESTDHANDLES) { - params->hStdInput = startup->hStdInput; - params->hStdOutput = startup->hStdOutput; - params->hStdError = startup->hStdError; + hstdin = startup->hStdInput; + hstdout = startup->hStdOutput; + hstderr = startup->hStdError; } else { - params->hStdInput = GetStdHandle( STD_INPUT_HANDLE ); - params->hStdOutput = GetStdHandle( STD_OUTPUT_HANDLE ); - params->hStdError = GetStdHandle( STD_ERROR_HANDLE ); + hstdin = GetStdHandle( STD_INPUT_HANDLE ); + hstdout = GetStdHandle( STD_OUTPUT_HANDLE ); + hstderr = GetStdHandle( STD_ERROR_HANDLE ); } - params->dwX = startup->dwX; - params->dwY = startup->dwY; - params->dwXSize = startup->dwXSize; - params->dwYSize = startup->dwYSize; - params->dwXCountChars = startup->dwXCountChars; - params->dwYCountChars = startup->dwYCountChars; - params->dwFillAttribute = startup->dwFillAttribute; - params->dwFlags = startup->dwFlags; - params->wShowWindow = startup->wShowWindow; - return params; + info->hstdin = wine_server_obj_handle( hstdin ); + info->hstdout = wine_server_obj_handle( hstdout ); + info->hstderr = wine_server_obj_handle( hstderr ); + if ((flags & (CREATE_NEW_CONSOLE | DETACHED_PROCESS)) != 0) + { + /* this is temporary (for console handles). We have no way to control that the handle is invalid in child process otherwise */ + if (is_console_handle(hstdin)) info->hstdin = wine_server_obj_handle( INVALID_HANDLE_VALUE ); + if (is_console_handle(hstdout)) info->hstdout = wine_server_obj_handle( INVALID_HANDLE_VALUE ); + if (is_console_handle(hstderr)) info->hstderr = wine_server_obj_handle( INVALID_HANDLE_VALUE ); + } + else + { + if (is_console_handle(hstdin)) info->hstdin = console_handle_unmap(hstdin); + if (is_console_handle(hstdout)) info->hstdout = console_handle_unmap(hstdout); + if (is_console_handle(hstderr)) info->hstderr = console_handle_unmap(hstderr); + } + + info->x = startup->dwX; + info->y = startup->dwY; + info->xsize = startup->dwXSize; + info->ysize = startup->dwYSize; + info->xchars = startup->dwXCountChars; + info->ychars = startup->dwYCountChars; + info->attribute = startup->dwFillAttribute; + info->flags = startup->dwFlags; + info->show = startup->wShowWindow; + + ptr = info + 1; + info->curdir_len = append_string( &ptr, cur_dir ); + info->dllpath_len = cur_params->DllPath.Length; + memcpy( ptr, cur_params->DllPath.Buffer, cur_params->DllPath.Length ); + ptr = (char *)ptr + cur_params->DllPath.Length; + info->imagepath_len = append_string( &ptr, imagepath ); + info->cmdline_len = append_string( &ptr, cmdline ); + if (startup->lpTitle) info->title_len = append_string( &ptr, startup->lpTitle ); + if (startup->lpDesktop) info->desktop_len = append_string( &ptr, startup->lpDesktop ); + if (startup->lpReserved2 && startup->cbReserved2) + { + info->runtime_len = startup->cbReserved2; + memcpy( ptr, startup->lpReserved2, startup->cbReserved2 ); + } + +done: + RtlFreeUnicodeString( &newdir ); + return info; } @@ -1525,11 +1567,12 @@ static BOOL create_process( HANDLE hFile, LPCWSTR filename, LPWSTR cmd_line, LPW void *res_start, void *res_end, DWORD binary_type, int exec_only ) { BOOL ret, success = FALSE; - HANDLE process_info, hstdin, hstdout; + HANDLE process_info; WCHAR *env_end; char *winedebug = NULL; char **argv; - RTL_USER_PROCESS_PARAMETERS *params; + startup_info_t *startup_info; + DWORD startup_info_size; int socketfd[2], stdin_fd = -1, stdout_fd = -1; pid_t pid; int err; @@ -1541,14 +1584,16 @@ static BOOL create_process( HANDLE hFile, LPCWSTR filename, LPWSTR cmd_line, LPW return FALSE; } - if (!env) RtlAcquirePebLock(); + RtlAcquirePebLock(); - if (!(params = create_user_params( filename, cmd_line, cur_dir, env, flags, startup ))) + if (!(startup_info = create_startup_info( filename, cmd_line, cur_dir, env, flags, startup, + &startup_info_size ))) { - if (!env) RtlReleasePebLock(); + RtlReleasePebLock(); return FALSE; } - env_end = params->Environment; + if (!env) env = NtCurrentTeb()->Peb->ProcessParameters->Environment; + env_end = env; while (*env_end) { static const WCHAR WINEDEBUG[] = {'W','I','N','E','D','E','B','U','G','=',0}; @@ -1566,9 +1611,9 @@ static BOOL create_process( HANDLE hFile, LPCWSTR filename, LPWSTR cmd_line, LPW if (socketpair( PF_UNIX, SOCK_STREAM, 0, socketfd ) == -1) { - if (!env) RtlReleasePebLock(); + RtlReleasePebLock(); HeapFree( GetProcessHeap(), 0, winedebug ); - RtlDestroyProcessParameters( params ); + HeapFree( GetProcessHeap(), 0, startup_info ); SetLastError( ERROR_TOO_MANY_OPEN_FILES ); return FALSE; } @@ -1587,29 +1632,10 @@ static BOOL create_process( HANDLE hFile, LPCWSTR filename, LPWSTR cmd_line, LPW req->process_attr = (psa && (psa->nLength >= sizeof(*psa)) && psa->bInheritHandle) ? OBJ_INHERIT : 0; req->thread_access = THREAD_ALL_ACCESS; req->thread_attr = (tsa && (tsa->nLength >= sizeof(*tsa)) && tsa->bInheritHandle) ? OBJ_INHERIT : 0; - req->hstdin = wine_server_obj_handle( params->hStdInput ); - req->hstdout = wine_server_obj_handle( params->hStdOutput ); - req->hstderr = wine_server_obj_handle( params->hStdError ); + req->info_size = startup_info_size; - if ((flags & (CREATE_NEW_CONSOLE | DETACHED_PROCESS)) != 0) - { - /* this is temporary (for console handles). We have no way to control that the handle is invalid in child process otherwise */ - if (is_console_handle(params->hStdInput)) req->hstdin = wine_server_obj_handle( INVALID_HANDLE_VALUE ); - if (is_console_handle(params->hStdOutput)) req->hstdout = wine_server_obj_handle( INVALID_HANDLE_VALUE ); - if (is_console_handle(params->hStdError)) req->hstderr = wine_server_obj_handle( INVALID_HANDLE_VALUE ); - hstdin = hstdout = 0; - } - else - { - if (is_console_handle(params->hStdInput)) req->hstdin = console_handle_unmap(params->hStdInput); - if (is_console_handle(params->hStdOutput)) req->hstdout = console_handle_unmap(params->hStdOutput); - if (is_console_handle(params->hStdError)) req->hstderr = console_handle_unmap(params->hStdError); - hstdin = wine_server_ptr_handle( req->hstdin ); - hstdout = wine_server_ptr_handle( req->hstdout ); - } - - wine_server_add_data( req, params, params->Size ); - wine_server_add_data( req, params->Environment, (env_end-params->Environment)*sizeof(WCHAR) ); + wine_server_add_data( req, startup_info, startup_info_size ); + wine_server_add_data( req, env, (env_end - env) * sizeof(WCHAR) ); if ((ret = !wine_server_call_err( req ))) { info->dwProcessId = (DWORD)reply->pid; @@ -1621,17 +1647,25 @@ static BOOL create_process( HANDLE hFile, LPCWSTR filename, LPWSTR cmd_line, LPW } SERVER_END_REQ; - if (!env) RtlReleasePebLock(); - RtlDestroyProcessParameters( params ); + RtlReleasePebLock(); if (!ret) { close( socketfd[0] ); + HeapFree( GetProcessHeap(), 0, startup_info ); HeapFree( GetProcessHeap(), 0, winedebug ); return FALSE; } - if (hstdin) wine_server_handle_to_fd( hstdin, FILE_READ_DATA, &stdin_fd, NULL ); - if (hstdout) wine_server_handle_to_fd( hstdout, FILE_WRITE_DATA, &stdout_fd, NULL ); + if (!(flags & (CREATE_NEW_CONSOLE | DETACHED_PROCESS))) + { + if (startup_info->hstdin) + wine_server_handle_to_fd( wine_server_ptr_handle(startup_info->hstdin), + FILE_READ_DATA, &stdin_fd, NULL ); + if (startup_info->hstdout) + wine_server_handle_to_fd( wine_server_ptr_handle(startup_info->hstdout), + FILE_WRITE_DATA, &stdout_fd, NULL ); + } + HeapFree( GetProcessHeap(), 0, startup_info ); /* create the child process */ argv = build_argv( cmd_line, 1 ); diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c index c2d839c0813..f44bd6083ff 100644 --- a/dlls/ntdll/thread.c +++ b/dlls/ntdll/thread.c @@ -126,89 +126,118 @@ static inline NTSTATUS init_teb( TEB *teb ) /*********************************************************************** - * fix_unicode_string + * get_unicode_string * - * Make sure the unicode string doesn't point beyond the end pointer + * Copy a unicode string from the startup info. */ -static inline void fix_unicode_string( UNICODE_STRING *str, const char *end_ptr ) +static inline void get_unicode_string( UNICODE_STRING *str, WCHAR **src, WCHAR **dst, UINT len ) { - if ((char *)str->Buffer >= end_ptr) - { - str->Length = str->MaximumLength = 0; - str->Buffer = NULL; - return; - } - if ((char *)str->Buffer + str->MaximumLength > end_ptr) - { - str->MaximumLength = (end_ptr - (char *)str->Buffer) & ~(sizeof(WCHAR) - 1); - } - if (str->Length >= str->MaximumLength) - { - if (str->MaximumLength >= sizeof(WCHAR)) - str->Length = str->MaximumLength - sizeof(WCHAR); - else - str->Length = str->MaximumLength = 0; - } + str->Buffer = *dst; + str->Length = len; + str->MaximumLength = len + sizeof(WCHAR); + memcpy( str->Buffer, *src, len ); + str->Buffer[len / sizeof(WCHAR)] = 0; + *src += len / sizeof(WCHAR); + *dst += len / sizeof(WCHAR) + 1; } - /*********************************************************************** * init_user_process_params * * Fill the RTL_USER_PROCESS_PARAMETERS structure from the server. */ -static NTSTATUS init_user_process_params( SIZE_T info_size, HANDLE *exe_file ) +static NTSTATUS init_user_process_params( SIZE_T data_size, HANDLE *exe_file ) { void *ptr; - SIZE_T env_size; + WCHAR *src, *dst; + SIZE_T info_size, env_size, size, alloc_size; NTSTATUS status; + startup_info_t *info; RTL_USER_PROCESS_PARAMETERS *params = NULL; - status = NtAllocateVirtualMemory( NtCurrentProcess(), (void **)¶ms, 0, &info_size, - MEM_COMMIT, PAGE_READWRITE ); - if (status != STATUS_SUCCESS) return status; - - params->AllocationSize = info_size; - NtCurrentTeb()->Peb->ProcessParameters = params; + if (!(info = RtlAllocateHeap( GetProcessHeap(), 0, data_size ))) + return STATUS_NO_MEMORY; SERVER_START_REQ( get_startup_info ) { - wine_server_set_reply( req, params, info_size ); + wine_server_set_reply( req, info, data_size ); if (!(status = wine_server_call( req ))) { - info_size = wine_server_reply_size( reply ); + data_size = wine_server_reply_size( reply ); + info_size = reply->info_size; + env_size = data_size - info_size; *exe_file = wine_server_ptr_handle( reply->exe_file ); - params->hStdInput = wine_server_ptr_handle( reply->hstdin ); - params->hStdOutput = wine_server_ptr_handle( reply->hstdout ); - params->hStdError = wine_server_ptr_handle( reply->hstderr ); } } SERVER_END_REQ; if (status != STATUS_SUCCESS) return status; - if (params->Size > info_size) params->Size = info_size; + size = sizeof(*params); + size += MAX_NT_PATH_LENGTH * sizeof(WCHAR); + size += info->dllpath_len + sizeof(WCHAR); + size += info->imagepath_len + sizeof(WCHAR); + size += info->cmdline_len + sizeof(WCHAR); + size += info->title_len + sizeof(WCHAR); + size += info->desktop_len + sizeof(WCHAR); + size += info->shellinfo_len + sizeof(WCHAR); + size += info->runtime_len + sizeof(WCHAR); - /* make sure the strings are valid */ - fix_unicode_string( ¶ms->CurrentDirectory.DosPath, (char *)info_size ); - fix_unicode_string( ¶ms->DllPath, (char *)info_size ); - fix_unicode_string( ¶ms->ImagePathName, (char *)info_size ); - fix_unicode_string( ¶ms->CommandLine, (char *)info_size ); - fix_unicode_string( ¶ms->WindowTitle, (char *)info_size ); - fix_unicode_string( ¶ms->Desktop, (char *)info_size ); - fix_unicode_string( ¶ms->ShellInfo, (char *)info_size ); - fix_unicode_string( ¶ms->RuntimeInfo, (char *)info_size ); + alloc_size = size; + status = NtAllocateVirtualMemory( NtCurrentProcess(), (void **)¶ms, 0, &alloc_size, + MEM_COMMIT, PAGE_READWRITE ); + if (status != STATUS_SUCCESS) goto done; + + NtCurrentTeb()->Peb->ProcessParameters = params; + params->AllocationSize = alloc_size; + params->Size = size; + params->Flags = PROCESS_PARAMS_FLAG_NORMALIZED; + params->DebugFlags = info->debug_flags; + params->ConsoleHandle = wine_server_ptr_handle( info->console ); + params->ConsoleFlags = info->console_flags; + params->hStdInput = wine_server_ptr_handle( info->hstdin ); + params->hStdOutput = wine_server_ptr_handle( info->hstdout ); + params->hStdError = wine_server_ptr_handle( info->hstderr ); + params->dwX = info->x; + params->dwY = info->y; + params->dwXSize = info->xsize; + params->dwYSize = info->ysize; + params->dwXCountChars = info->xchars; + params->dwYCountChars = info->ychars; + params->dwFillAttribute = info->attribute; + params->dwFlags = info->flags; + params->wShowWindow = info->show; + + src = (WCHAR *)(info + 1); + dst = (WCHAR *)(params + 1); + + /* current directory needs more space */ + get_unicode_string( ¶ms->CurrentDirectory.DosPath, &src, &dst, info->curdir_len ); + params->CurrentDirectory.DosPath.MaximumLength = MAX_NT_PATH_LENGTH * sizeof(WCHAR); + dst = (WCHAR *)(params + 1) + MAX_NT_PATH_LENGTH; + + get_unicode_string( ¶ms->DllPath, &src, &dst, info->dllpath_len ); + get_unicode_string( ¶ms->ImagePathName, &src, &dst, info->imagepath_len ); + get_unicode_string( ¶ms->CommandLine, &src, &dst, info->cmdline_len ); + get_unicode_string( ¶ms->WindowTitle, &src, &dst, info->title_len ); + get_unicode_string( ¶ms->Desktop, &src, &dst, info->desktop_len ); + get_unicode_string( ¶ms->ShellInfo, &src, &dst, info->shellinfo_len ); + + /* runtime info isn't a real string */ + params->RuntimeInfo.Buffer = dst; + params->RuntimeInfo.Length = params->RuntimeInfo.MaximumLength = info->runtime_len; + memcpy( dst, src, info->runtime_len ); /* environment needs to be a separate memory block */ - env_size = info_size - params->Size; - if (!env_size) env_size = 1; ptr = NULL; - status = NtAllocateVirtualMemory( NtCurrentProcess(), &ptr, 0, &env_size, + alloc_size = max( 1, env_size ); + status = NtAllocateVirtualMemory( NtCurrentProcess(), &ptr, 0, &alloc_size, MEM_COMMIT, PAGE_READWRITE ); - if (status != STATUS_SUCCESS) return status; - memcpy( ptr, (char *)params + params->Size, info_size - params->Size ); + if (status != STATUS_SUCCESS) goto done; + memcpy( ptr, (char *)info + info_size, env_size ); params->Environment = ptr; - RtlNormalizeProcessParams( params ); +done: + RtlFreeHeap( GetProcessHeap(), 0, info ); return status; } diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index c926f6d8744..6ab1df24bd0 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -211,6 +211,42 @@ typedef __int64 timeout_t; #define TIMEOUT_INFINITE (((timeout_t)0x7fffffff) << 32 | 0xffffffff) +typedef struct +{ + unsigned int debug_flags; + unsigned int console_flags; + obj_handle_t console; + obj_handle_t hstdin; + obj_handle_t hstdout; + obj_handle_t hstderr; + unsigned int x; + unsigned int y; + unsigned int xsize; + unsigned int ysize; + unsigned int xchars; + unsigned int ychars; + unsigned int attribute; + unsigned int flags; + unsigned int show; + data_size_t curdir_len; + data_size_t dllpath_len; + data_size_t imagepath_len; + data_size_t cmdline_len; + data_size_t title_len; + data_size_t desktop_len; + data_size_t shellinfo_len; + data_size_t runtime_len; + + + + + + + + +} startup_info_t; + + typedef struct { atom_t atom; @@ -535,14 +571,12 @@ struct new_process_request unsigned int create_flags; int socket_fd; obj_handle_t exe_file; - obj_handle_t hstdin; - obj_handle_t hstdout; - obj_handle_t hstderr; unsigned int process_access; unsigned int process_attr; unsigned int thread_access; unsigned int thread_attr; - /* VARARG(info,startup_info); */ + data_size_t info_size; + /* VARARG(info,startup_info,info_size); */ /* VARARG(env,unicode_str); */ }; struct new_process_reply @@ -597,10 +631,8 @@ struct get_startup_info_reply { struct reply_header __header; obj_handle_t exe_file; - obj_handle_t hstdin; - obj_handle_t hstdout; - obj_handle_t hstderr; - /* VARARG(info,startup_info); */ + data_size_t info_size; + /* VARARG(info,startup_info,info_size); */ /* VARARG(env,unicode_str); */ }; @@ -5315,6 +5347,6 @@ union generic_reply struct set_window_layered_info_reply set_window_layered_info_reply; }; -#define SERVER_PROTOCOL_VERSION 388 +#define SERVER_PROTOCOL_VERSION 389 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/process.c b/server/process.c index 2b8d8f6cc64..8df9f394221 100644 --- a/server/process.c +++ b/server/process.c @@ -102,13 +102,11 @@ static const struct fd_ops process_fd_ops = struct startup_info { struct object obj; /* object header */ - obj_handle_t hstdin; /* handle for stdin */ - obj_handle_t hstdout; /* handle for stdout */ - obj_handle_t hstderr; /* handle for stderr */ struct file *exe_file; /* file handle for main exe */ struct process *process; /* created process */ - data_size_t data_size; /* size of startup data */ - void *data; /* data for startup info */ + data_size_t info_size; /* size of startup info */ + data_size_t data_size; /* size of whole startup data */ + startup_info_t *data; /* data for startup info */ }; static void startup_info_dump( struct object *obj, int verbose ); @@ -478,7 +476,7 @@ static void startup_info_dump( struct object *obj, int verbose ) assert( obj->ops == &startup_info_ops ); fprintf( stderr, "Startup info in=%04x out=%04x err=%04x\n", - info->hstdin, info->hstdout, info->hstderr ); + info->data->hstdin, info->data->hstdout, info->data->hstderr ); } static int startup_info_signaled( struct object *obj, struct thread *thread ) @@ -891,19 +889,46 @@ DECL_HANDLER(new_process) /* build the startup info for a new process */ if (!(info = alloc_object( &startup_info_ops ))) return; - info->hstdin = req->hstdin; - info->hstdout = req->hstdout; - info->hstderr = req->hstderr; - info->exe_file = NULL; - info->process = NULL; - info->data_size = get_req_data_size(); - info->data = NULL; + info->exe_file = NULL; + info->process = NULL; + info->data = NULL; if (req->exe_file && !(info->exe_file = get_file_obj( current->process, req->exe_file, FILE_READ_DATA ))) goto done; - if (!(info->data = memdup( get_req_data(), info->data_size ))) goto done; + info->data_size = get_req_data_size(); + info->info_size = min( req->info_size, info->data_size ); + + if (req->info_size < sizeof(*info->data)) + { + /* make sure we have a full startup_info_t structure */ + data_size_t env_size = info->data_size - info->info_size; + data_size_t info_size = min( req->info_size, FIELD_OFFSET( startup_info_t, curdir_len )); + + if (!(info->data = mem_alloc( sizeof(*info->data) + env_size ))) goto done; + memcpy( info->data, get_req_data(), info_size ); + memset( (char *)info->data + info_size, 0, sizeof(*info->data) - info_size ); + memcpy( info->data + 1, (const char *)get_req_data() + req->info_size, env_size ); + info->info_size = sizeof(startup_info_t); + info->data_size = info->info_size + env_size; + } + else + { + data_size_t pos = sizeof(*info->data); + + if (!(info->data = memdup( get_req_data(), info->data_size ))) goto done; +#define FIXUP_LEN(len) do { (len) = min( (len), info->info_size - pos ); pos += (len); } while(0) + FIXUP_LEN( info->data->curdir_len ); + FIXUP_LEN( info->data->dllpath_len ); + FIXUP_LEN( info->data->imagepath_len ); + FIXUP_LEN( info->data->cmdline_len ); + FIXUP_LEN( info->data->title_len ); + FIXUP_LEN( info->data->desktop_len ); + FIXUP_LEN( info->data->shellinfo_len ); + FIXUP_LEN( info->data->runtime_len ); +#undef FIXUP_LEN + } if (!(thread = create_process( socket_fd, current, req->inherit_all ))) goto done; process = thread->process; @@ -923,17 +948,17 @@ DECL_HANDLER(new_process) * like if hConOut and hConIn are console handles, then they should be on the same * physical console */ - inherit_console( current, process, req->inherit_all ? req->hstdin : 0 ); + inherit_console( current, process, req->inherit_all ? info->data->hstdin : 0 ); } if (!req->inherit_all && !(req->create_flags & CREATE_NEW_CONSOLE)) { - info->hstdin = duplicate_handle( parent, req->hstdin, process, - 0, OBJ_INHERIT, DUPLICATE_SAME_ACCESS ); - info->hstdout = duplicate_handle( parent, req->hstdout, process, - 0, OBJ_INHERIT, DUPLICATE_SAME_ACCESS ); - info->hstderr = duplicate_handle( parent, req->hstderr, process, - 0, OBJ_INHERIT, DUPLICATE_SAME_ACCESS ); + info->data->hstdin = duplicate_handle( parent, info->data->hstdin, process, + 0, OBJ_INHERIT, DUPLICATE_SAME_ACCESS ); + info->data->hstdout = duplicate_handle( parent, info->data->hstdout, process, + 0, OBJ_INHERIT, DUPLICATE_SAME_ACCESS ); + info->data->hstderr = duplicate_handle( parent, info->data->hstderr, process, + 0, OBJ_INHERIT, DUPLICATE_SAME_ACCESS ); /* some handles above may have been invalid; this is not an error */ if (get_error() == STATUS_INVALID_HANDLE || get_error() == STATUS_OBJECT_TYPE_MISMATCH) clear_error(); @@ -985,11 +1010,8 @@ DECL_HANDLER(get_startup_info) if (info->exe_file && !(reply->exe_file = alloc_handle( process, info->exe_file, GENERIC_READ, 0 ))) return; - reply->hstdin = info->hstdin; - reply->hstdout = info->hstdout; - reply->hstderr = info->hstderr; - /* we return the data directly without making a copy so this can only be called once */ + reply->info_size = info->info_size; size = info->data_size; if (size > get_reply_max_size()) size = get_reply_max_size(); set_reply_data_ptr( info->data, size ); diff --git a/server/protocol.def b/server/protocol.def index 1dcc04248d0..d6b282a19d8 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -226,6 +226,42 @@ struct wake_up_reply typedef __int64 timeout_t; #define TIMEOUT_INFINITE (((timeout_t)0x7fffffff) << 32 | 0xffffffff) +/* structure for process startup info */ +typedef struct +{ + unsigned int debug_flags; + unsigned int console_flags; + obj_handle_t console; + obj_handle_t hstdin; + obj_handle_t hstdout; + obj_handle_t hstderr; + unsigned int x; + unsigned int y; + unsigned int xsize; + unsigned int ysize; + unsigned int xchars; + unsigned int ychars; + unsigned int attribute; + unsigned int flags; + unsigned int show; + data_size_t curdir_len; + data_size_t dllpath_len; + data_size_t imagepath_len; + data_size_t cmdline_len; + data_size_t title_len; + data_size_t desktop_len; + data_size_t shellinfo_len; + data_size_t runtime_len; + /* VARARG(curdir,unicode_str,curdir_len); */ + /* VARARG(dllpath,unicode_str,dllpath_len); */ + /* VARARG(imagepath,unicode_str,imagepath_len); */ + /* VARARG(cmdline,unicode_str,cmdline_len); */ + /* VARARG(title,unicode_str,title_len); */ + /* VARARG(desktop,unicode_str,desktop_len); */ + /* VARARG(shellinfo,unicode_str,shellinfo_len); */ + /* VARARG(runtime,unicode_str,runtime_len); */ +} startup_info_t; + /* structure returned in the list of window properties */ typedef struct { @@ -549,14 +585,12 @@ typedef union unsigned int create_flags; /* creation flags */ int socket_fd; /* file descriptor for process socket */ obj_handle_t exe_file; /* file handle for main exe */ - obj_handle_t hstdin; /* handle for stdin */ - obj_handle_t hstdout; /* handle for stdout */ - obj_handle_t hstderr; /* handle for stderr */ unsigned int process_access; /* access rights for process object */ unsigned int process_attr; /* attributes for process object */ unsigned int thread_access; /* access rights for thread object */ unsigned int thread_attr; /* attributes for thread object */ - VARARG(info,startup_info); /* startup information */ + data_size_t info_size; /* size of startup info */ + VARARG(info,startup_info,info_size); /* startup information */ VARARG(env,unicode_str); /* environment for new process */ @REPLY obj_handle_t info; /* new process info handle */ @@ -592,10 +626,8 @@ typedef union @REQ(get_startup_info) @REPLY obj_handle_t exe_file; /* file handle for main exe */ - obj_handle_t hstdin; /* handle for stdin */ - obj_handle_t hstdout; /* handle for stdout */ - obj_handle_t hstderr; /* handle for stderr */ - VARARG(info,startup_info); /* startup information */ + data_size_t info_size; /* size of startup info */ + VARARG(info,startup_info,info_size); /* startup information */ VARARG(env,unicode_str); /* environment */ @END diff --git a/server/request.h b/server/request.h index a0efd2d0b0e..c726130443a 100644 --- a/server/request.h +++ b/server/request.h @@ -627,13 +627,11 @@ C_ASSERT( FIELD_OFFSET(struct new_process_request, inherit_all) == 12 ); C_ASSERT( FIELD_OFFSET(struct new_process_request, create_flags) == 16 ); C_ASSERT( FIELD_OFFSET(struct new_process_request, socket_fd) == 20 ); C_ASSERT( FIELD_OFFSET(struct new_process_request, exe_file) == 24 ); -C_ASSERT( FIELD_OFFSET(struct new_process_request, hstdin) == 28 ); -C_ASSERT( FIELD_OFFSET(struct new_process_request, hstdout) == 32 ); -C_ASSERT( FIELD_OFFSET(struct new_process_request, hstderr) == 36 ); -C_ASSERT( FIELD_OFFSET(struct new_process_request, process_access) == 40 ); -C_ASSERT( FIELD_OFFSET(struct new_process_request, process_attr) == 44 ); -C_ASSERT( FIELD_OFFSET(struct new_process_request, thread_access) == 48 ); -C_ASSERT( FIELD_OFFSET(struct new_process_request, thread_attr) == 52 ); +C_ASSERT( FIELD_OFFSET(struct new_process_request, process_access) == 28 ); +C_ASSERT( FIELD_OFFSET(struct new_process_request, process_attr) == 32 ); +C_ASSERT( FIELD_OFFSET(struct new_process_request, thread_access) == 36 ); +C_ASSERT( FIELD_OFFSET(struct new_process_request, thread_attr) == 40 ); +C_ASSERT( FIELD_OFFSET(struct new_process_request, info_size) == 44 ); C_ASSERT( FIELD_OFFSET(struct new_process_reply, info) == 8 ); C_ASSERT( FIELD_OFFSET(struct new_process_reply, pid) == 12 ); C_ASSERT( FIELD_OFFSET(struct new_process_reply, phandle) == 16 ); @@ -652,10 +650,8 @@ C_ASSERT( FIELD_OFFSET(struct new_thread_reply, tid) == 8 ); C_ASSERT( FIELD_OFFSET(struct new_thread_reply, handle) == 12 ); C_ASSERT( sizeof(struct new_thread_reply) == 16 ); C_ASSERT( FIELD_OFFSET(struct get_startup_info_reply, exe_file) == 8 ); -C_ASSERT( FIELD_OFFSET(struct get_startup_info_reply, hstdin) == 12 ); -C_ASSERT( FIELD_OFFSET(struct get_startup_info_reply, hstdout) == 16 ); -C_ASSERT( FIELD_OFFSET(struct get_startup_info_reply, hstderr) == 20 ); -C_ASSERT( sizeof(struct get_startup_info_reply) == 24 ); +C_ASSERT( FIELD_OFFSET(struct get_startup_info_reply, info_size) == 12 ); +C_ASSERT( sizeof(struct get_startup_info_reply) == 16 ); C_ASSERT( FIELD_OFFSET(struct init_process_done_request, gui) == 12 ); C_ASSERT( FIELD_OFFSET(struct init_process_done_request, module) == 16 ); C_ASSERT( FIELD_OFFSET(struct init_process_done_request, ldt_copy) == 24 ); diff --git a/server/trace.c b/server/trace.c index be3f1c68f23..38a20b764b8 100644 --- a/server/trace.c +++ b/server/trace.c @@ -675,65 +675,38 @@ static void dump_varargs_debug_event( const char *prefix, data_size_t size ) } /* dump a unicode string contained in a buffer; helper for dump_varargs_startup_info */ -static void dump_inline_unicode_string( const UNICODE_STRING *str, const void *data, data_size_t size ) +static data_size_t dump_inline_unicode_string( const char *prefix, data_size_t pos, data_size_t len, data_size_t total_size ) { - size_t length = str->Length; - size_t offset = (size_t)str->Buffer; - - if (offset >= size) return; - if (offset + length > size) length = size - offset; - dump_strW( (const WCHAR *)data + offset/sizeof(WCHAR), length/sizeof(WCHAR), stderr, "\"\"" ); + fputs( prefix, stderr ); + if (pos >= total_size) return pos; + if (len > total_size - pos) len = total_size - pos; + len /= sizeof(WCHAR); + dump_strW( (const WCHAR *)cur_data + pos/sizeof(WCHAR), len, stderr, "\"\"" ); + return pos + len * sizeof(WCHAR); } static void dump_varargs_startup_info( const char *prefix, data_size_t size ) { - const RTL_USER_PROCESS_PARAMETERS *ptr = cur_data; - RTL_USER_PROCESS_PARAMETERS params; + startup_info_t info; + data_size_t pos = sizeof(info); - if (size < sizeof(params.Size)) - { - fprintf( stderr, "%s{}", prefix ); - return; - } - if (size > ptr->Size) size = ptr->Size; - memset( ¶ms, 0, sizeof(params) ); - memcpy( ¶ms, ptr, min( size, sizeof(params) )); + memset( &info, 0, sizeof(info) ); + memcpy( &info, cur_data, min( size, sizeof(info) )); - fprintf( stderr, "%s{AllocationSize=%x,", prefix, params.AllocationSize ); - fprintf( stderr, "Size=%x,", params.Size ); - fprintf( stderr, "Flags=%x,", params.Flags ); - fprintf( stderr, "DebugFlags=%x,", params.DebugFlags ); - fprintf( stderr, "ConsoleHandle=%p,", params.ConsoleHandle ); - fprintf( stderr, "ConsoleFlags=%x,", params.ConsoleFlags ); - fprintf( stderr, "hStdInput=%p,", params.hStdInput ); - fprintf( stderr, "hStdOutput=%p,", params.hStdOutput ); - fprintf( stderr, "hStdError=%p,", params.hStdError ); - fprintf( stderr, "CurrentDirectory.Handle=%p,", params.CurrentDirectory.Handle ); - fprintf( stderr, "dwX=%d,", params.dwX ); - fprintf( stderr, "dwY=%d,", params.dwY ); - fprintf( stderr, "dwXSize=%d,", params.dwXSize ); - fprintf( stderr, "dwYSize=%d,", params.dwYSize ); - fprintf( stderr, "dwXCountChars=%d,", params.dwXCountChars ); - fprintf( stderr, "dwYCountChars=%d,", params.dwYCountChars ); - fprintf( stderr, "dwFillAttribute=%x,", params.dwFillAttribute ); - fprintf( stderr, "dwFlags=%x,", params.dwFlags ); - fprintf( stderr, "wShowWindow=%x,", params.wShowWindow ); - fprintf( stderr, "CurrentDirectory.DosPath=L\"" ); - dump_inline_unicode_string( ¶ms.CurrentDirectory.DosPath, cur_data, size ); - fprintf( stderr, "\",DllPath=L\"" ); - dump_inline_unicode_string( ¶ms.DllPath, cur_data, size ); - fprintf( stderr, "\",ImagePathName=L\"" ); - dump_inline_unicode_string( ¶ms.ImagePathName, cur_data, size ); - fprintf( stderr, "\",CommandLine=L\"" ); - dump_inline_unicode_string( ¶ms.CommandLine, cur_data, size ); - fprintf( stderr, "\",WindowTitle=L\"" ); - dump_inline_unicode_string( ¶ms.WindowTitle, cur_data, size ); - fprintf( stderr, "\",Desktop=L\"" ); - dump_inline_unicode_string( ¶ms.Desktop, cur_data, size ); - fprintf( stderr, "\",ShellInfo=L\"" ); - dump_inline_unicode_string( ¶ms.ShellInfo, cur_data, size ); - fprintf( stderr, "\",RuntimeInfo=L\"" ); - dump_inline_unicode_string( ¶ms.RuntimeInfo, cur_data, size ); + fprintf( stderr, + "%s{debug_flags=%x,console_flags=%x,console=%04x,hstdin=%04x,hstdout=%04x,hstderr=%04x," + "x=%u,y=%u,xsize=%u,ysize=%u,xchars=%u,ychars=%u,attribute=%02x,flags=%x,show=%u", + prefix, info.debug_flags, info.console_flags, info.console, + info.hstdin, info.hstdout, info.hstderr, info.x, info.y, info.xsize, info.ysize, + info.xchars, info.ychars, info.attribute, info.flags, info.show ); + pos = dump_inline_unicode_string( ",curdir=L\"", pos, info.curdir_len, size ); + pos = dump_inline_unicode_string( "\",dllpath=L\"", pos, info.dllpath_len, size ); + pos = dump_inline_unicode_string( "\",imagepath=L\"", pos, info.imagepath_len, size ); + pos = dump_inline_unicode_string( "\",cmdline=L\"", pos, info.cmdline_len, size ); + pos = dump_inline_unicode_string( "\",title=L\"", pos, info.title_len, size ); + pos = dump_inline_unicode_string( "\",desktop=L\"", pos, info.desktop_len, size ); + pos = dump_inline_unicode_string( "\",shellinfo=L\"", pos, info.shellinfo_len, size ); + pos = dump_inline_unicode_string( "\",runtime=L\"", pos, info.runtime_len, size ); fprintf( stderr, "\"}" ); remove_data( size ); } @@ -1025,14 +998,12 @@ static void dump_new_process_request( const struct new_process_request *req ) fprintf( stderr, ", create_flags=%08x", req->create_flags ); fprintf( stderr, ", socket_fd=%d", req->socket_fd ); fprintf( stderr, ", exe_file=%04x", req->exe_file ); - fprintf( stderr, ", hstdin=%04x", req->hstdin ); - fprintf( stderr, ", hstdout=%04x", req->hstdout ); - fprintf( stderr, ", hstderr=%04x", req->hstderr ); fprintf( stderr, ", process_access=%08x", req->process_access ); fprintf( stderr, ", process_attr=%08x", req->process_attr ); fprintf( stderr, ", thread_access=%08x", req->thread_access ); fprintf( stderr, ", thread_attr=%08x", req->thread_attr ); - dump_varargs_startup_info( ", info=", cur_size ); + fprintf( stderr, ", info_size=%u", req->info_size ); + dump_varargs_startup_info( ", info=", min(cur_size,req->info_size) ); dump_varargs_unicode_str( ", env=", cur_size ); } @@ -1077,10 +1048,8 @@ static void dump_get_startup_info_request( const struct get_startup_info_request static void dump_get_startup_info_reply( const struct get_startup_info_reply *req ) { fprintf( stderr, " exe_file=%04x", req->exe_file ); - fprintf( stderr, ", hstdin=%04x", req->hstdin ); - fprintf( stderr, ", hstdout=%04x", req->hstdout ); - fprintf( stderr, ", hstderr=%04x", req->hstderr ); - dump_varargs_startup_info( ", info=", cur_size ); + fprintf( stderr, ", info_size=%u", req->info_size ); + dump_varargs_startup_info( ", info=", min(cur_size,req->info_size) ); dump_varargs_unicode_str( ", env=", cur_size ); }