server: Simplify process creation.

Pass the socket for the new process from the parent through the
environment.
Perform initialisations during the new_process request.
diff --git a/dlls/kernel/process.c b/dlls/kernel/process.c
index 911cf51..ec92bb1 100644
--- a/dlls/kernel/process.c
+++ b/dlls/kernel/process.c
@@ -31,6 +31,12 @@
 #ifdef HAVE_SYS_TIME_H
 # include <sys/time.h>
 #endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
 #ifdef HAVE_SYS_PRCTL_H
 # include <sys/prctl.h>
 #endif
@@ -1104,6 +1110,7 @@
         {
             if (*p == '=') continue;  /* skip drive curdirs, this crashes some unix apps */
             if (!strncmp( p, "WINEPRELOADRESERVE=", sizeof("WINEPRELOADRESERVE=")-1 )) continue;
+            if (!strncmp( p, "WINESERVERSOCKET=", sizeof("WINESERVERSOCKET=")-1 )) continue;
             if (is_special_env_var( p ))  /* prefix it with "WINE" */
                 *envptr++ = alloc_env_string( "WINE", p );
             else
@@ -1210,9 +1217,18 @@
     if (flags & CREATE_NEW_PROCESS_GROUP) params->ConsoleFlags = 1;
     if (flags & CREATE_NEW_CONSOLE) params->ConsoleHandle = (HANDLE)1;  /* FIXME: cf. kernel_main.c */
 
-    params->hStdInput       = startup->hStdInput;
-    params->hStdOutput      = startup->hStdOutput;
-    params->hStdError       = startup->hStdError;
+    if (startup->dwFlags & STARTF_USESTDHANDLES)
+    {
+        params->hStdInput  = startup->hStdInput;
+        params->hStdOutput = startup->hStdOutput;
+        params->hStdError  = startup->hStdError;
+    }
+    else
+    {
+        params->hStdInput  = GetStdHandle( STD_INPUT_HANDLE );
+        params->hStdOutput = GetStdHandle( STD_OUTPUT_HANDLE );
+        params->hStdError  = GetStdHandle( STD_ERROR_HANDLE );
+    }
     params->dwX             = startup->dwX;
     params->dwY             = startup->dwY;
     params->dwXSize         = startup->dwXSize;
@@ -1243,12 +1259,9 @@
     WCHAR *env_end;
     char *winedebug = NULL;
     RTL_USER_PROCESS_PARAMETERS *params;
-    int startfd[2];
-    int execfd[2];
+    int socketfd[2];
     pid_t pid;
     int err;
-    char dummy = 0;
-    char preloader_reserve[64];
 
     if (!env) RtlAcquirePebLock();
 
@@ -1271,96 +1284,34 @@
     }
     env_end++;
 
-    sprintf( preloader_reserve, "WINEPRELOADRESERVE=%lx-%lx%c",
-             (unsigned long)res_start, (unsigned long)res_end, 0 );
+    /* create the socket for the new process */
 
-    /* create the synchronization pipes */
-
-    if (pipe( startfd ) == -1)
+    if (socketpair( PF_UNIX, SOCK_STREAM, 0, socketfd ) == -1)
     {
         if (!env) RtlReleasePebLock();
         HeapFree( GetProcessHeap(), 0, winedebug );
+        RtlDestroyProcessParameters( params );
         SetLastError( ERROR_TOO_MANY_OPEN_FILES );
-        RtlDestroyProcessParameters( params );
         return FALSE;
     }
-    if (pipe( execfd ) == -1)
-    {
-        if (!env) RtlReleasePebLock();
-        HeapFree( GetProcessHeap(), 0, winedebug );
-        SetLastError( ERROR_TOO_MANY_OPEN_FILES );
-        close( startfd[0] );
-        close( startfd[1] );
-        RtlDestroyProcessParameters( params );
-        return FALSE;
-    }
-    fcntl( execfd[1], F_SETFD, 1 );  /* set close on exec */
-
-    /* create the child process */
-
-    if (!(pid = fork()))  /* child */
-    {
-        char **argv = build_argv( cmd_line, 1 );
-
-        close( startfd[1] );
-        close( execfd[0] );
-
-        /* wait for parent to tell us to start */
-        if (read( startfd[0], &dummy, 1 ) != 1) _exit(1);
-
-        close( startfd[0] );
-        if (flags & (CREATE_NEW_PROCESS_GROUP | CREATE_NEW_CONSOLE | DETACHED_PROCESS)) setsid();
-
-        /* Reset signals that we previously set to SIG_IGN */
-        signal( SIGPIPE, SIG_DFL );
-        signal( SIGCHLD, SIG_DFL );
-
-        putenv( preloader_reserve );
-        if (winedebug) putenv( winedebug );
-        if (unixdir) chdir(unixdir);
-
-        if (argv) wine_exec_wine_binary( NULL, argv, getenv("WINELOADER") );
-
-        err = errno;
-        write( execfd[1], &err, sizeof(err) );
-        _exit(1);
-    }
-
-    /* this is the parent */
-
-    close( startfd[0] );
-    close( execfd[1] );
-    HeapFree( GetProcessHeap(), 0, winedebug );
-    if (pid == -1)
-    {
-        if (!env) RtlReleasePebLock();
-        close( startfd[1] );
-        close( execfd[0] );
-        FILE_SetDosError();
-        RtlDestroyProcessParameters( params );
-        return FALSE;
-    }
+    wine_server_send_fd( socketfd[1] );
+    close( socketfd[1] );
 
     /* create the process on the server side */
 
     SERVER_START_REQ( new_process )
     {
-        req->inherit_all  = inherit;
-        req->create_flags = flags;
-        req->unix_pid     = pid;
-        req->exe_file     = hFile;
-        if (startup->dwFlags & STARTF_USESTDHANDLES)
-        {
-            req->hstdin  = startup->hStdInput;
-            req->hstdout = startup->hStdOutput;
-            req->hstderr = startup->hStdError;
-        }
-        else
-        {
-            req->hstdin  = GetStdHandle( STD_INPUT_HANDLE );
-            req->hstdout = GetStdHandle( STD_OUTPUT_HANDLE );
-            req->hstderr = GetStdHandle( STD_ERROR_HANDLE );
-        }
+        req->inherit_all    = inherit;
+        req->create_flags   = flags;
+        req->socket_fd      = socketfd[1];
+        req->exe_file       = hFile;
+        req->process_access = PROCESS_ALL_ACCESS;
+        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         = params->hStdInput;
+        req->hstdout        = params->hStdOutput;
+        req->hstderr        = params->hStdError;
 
         if ((flags & (CREATE_NEW_CONSOLE | DETACHED_PROCESS)) != 0)
         {
@@ -1378,7 +1329,13 @@
 
         wine_server_add_data( req, params, params->Size );
         wine_server_add_data( req, params->Environment, (env_end-params->Environment)*sizeof(WCHAR) );
-        ret = !wine_server_call_err( req );
+        if ((ret = !wine_server_call_err( req )))
+        {
+            info->dwProcessId = (DWORD)reply->pid;
+            info->dwThreadId  = (DWORD)reply->tid;
+            info->hProcess    = reply->phandle;
+            info->hThread     = reply->thandle;
+        }
         process_info = reply->info;
     }
     SERVER_END_REQ;
@@ -1387,57 +1344,74 @@
     RtlDestroyProcessParameters( params );
     if (!ret)
     {
-        close( startfd[1] );
-        close( execfd[0] );
+        close( socketfd[0] );
+        HeapFree( GetProcessHeap(), 0, winedebug );
         return FALSE;
     }
 
-    /* tell child to start and wait for it to exec */
+    /* create the child process */
 
-    write( startfd[1], &dummy, 1 );
-    close( startfd[1] );
-
-    if (read( execfd[0], &err, sizeof(err) ) > 0) /* exec failed */
+    if (!(pid = fork()))  /* child */
     {
-        errno = err;
-        FILE_SetDosError();
-        close( execfd[0] );
-        CloseHandle( process_info );
-        return FALSE;
+        char preloader_reserve[64], socket_env[64];
+        char **argv = build_argv( cmd_line, 1 );
+
+        if (flags & (CREATE_NEW_PROCESS_GROUP | CREATE_NEW_CONSOLE | DETACHED_PROCESS)) setsid();
+
+        /* Reset signals that we previously set to SIG_IGN */
+        signal( SIGPIPE, SIG_DFL );
+        signal( SIGCHLD, SIG_DFL );
+
+        sprintf( socket_env, "WINESERVERSOCKET=%u", socketfd[0] );
+        sprintf( preloader_reserve, "WINEPRELOADRESERVE=%lx-%lx",
+                 (unsigned long)res_start, (unsigned long)res_end );
+
+        putenv( preloader_reserve );
+        putenv( socket_env );
+        if (winedebug) putenv( winedebug );
+        if (unixdir) chdir(unixdir);
+
+        if (argv) wine_exec_wine_binary( NULL, argv, getenv("WINELOADER") );
+        _exit(1);
     }
-    close( execfd[0] );
+
+    /* this is the parent */
+
+    close( socketfd[0] );
+    HeapFree( GetProcessHeap(), 0, winedebug );
+    if (pid == -1)
+    {
+        FILE_SetDosError();
+        goto error;
+    }
 
     /* wait for the new process info to be ready */
 
     WaitForSingleObject( process_info, INFINITE );
     SERVER_START_REQ( get_new_process_info )
     {
-        req->info           = process_info;
-        req->process_access = PROCESS_ALL_ACCESS;
-        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;
-        if ((ret = !wine_server_call_err( req )))
-        {
-            info->dwProcessId = (DWORD)reply->pid;
-            info->dwThreadId  = (DWORD)reply->tid;
-            info->hProcess    = reply->phandle;
-            info->hThread     = reply->thandle;
-            success           = reply->success;
-        }
+        req->info = process_info;
+        wine_server_call( req );
+        success = reply->success;
+        err = reply->exit_code;
     }
     SERVER_END_REQ;
 
-    if (ret && !success)  /* new process failed to start */
+    if (!success)
     {
-        DWORD exitcode;
-        if (GetExitCodeProcess( info->hProcess, &exitcode )) SetLastError( exitcode );
-        CloseHandle( info->hThread );
-        CloseHandle( info->hProcess );
-        ret = FALSE;
+        SetLastError( err ? err : ERROR_INTERNAL_ERROR );
+        goto error;
     }
     CloseHandle( process_info );
-    return ret;
+    return success;
+
+error:
+    CloseHandle( process_info );
+    CloseHandle( info->hProcess );
+    CloseHandle( info->hThread );
+    info->hProcess = info->hThread = 0;
+    info->dwProcessId = info->dwThreadId = 0;
+    return FALSE;
 }
 
 
diff --git a/dlls/ntdll/server.c b/dlls/ntdll/server.c
index b10a391..a64bdb6 100644
--- a/dlls/ntdll/server.c
+++ b/dlls/ntdll/server.c
@@ -843,16 +843,27 @@
 void server_init_process(void)
 {
     obj_handle_t dummy_handle;
-    const char *server_dir = wine_get_server_dir();
+    const char *env_socket = getenv( "WINESERVERSOCKET" );
 
-    if (!server_dir)  /* this means the config dir doesn't exist */
+    if (env_socket)
     {
-        create_config_dir();
-        server_dir = wine_get_server_dir();
+        fd_socket = atoi( env_socket );
+        if (fcntl( fd_socket, F_SETFD, 1 ) == -1)
+            fatal_perror( "Bad server socket %d", fd_socket );
     }
+    else
+    {
+        const char *server_dir = wine_get_server_dir();
 
-    /* connect to the server */
-    fd_socket = server_connect( server_dir );
+        if (!server_dir)  /* this means the config dir doesn't exist */
+        {
+            create_config_dir();
+            server_dir = wine_get_server_dir();
+        }
+
+        /* connect to the server */
+        fd_socket = server_connect( server_dir );
+    }
 
     /* setup the signal mask */
     sigemptyset( &block_set );
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index 3c8f487..2755827 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -193,11 +193,15 @@
     struct request_header __header;
     int          inherit_all;
     unsigned int create_flags;
-    int          unix_pid;
+    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); */
     /* VARARG(env,unicode_str); */
 };
@@ -205,6 +209,10 @@
 {
     struct reply_header __header;
     obj_handle_t info;
+    process_id_t pid;
+    obj_handle_t phandle;
+    thread_id_t  tid;
+    obj_handle_t thandle;
 };
 
 
@@ -213,19 +221,12 @@
 {
     struct request_header __header;
     obj_handle_t info;
-    unsigned int process_access;
-    unsigned int process_attr;
-    unsigned int thread_access;
-    unsigned int thread_attr;
 };
 struct get_new_process_info_reply
 {
     struct reply_header __header;
-    process_id_t pid;
-    obj_handle_t phandle;
-    thread_id_t  tid;
-    obj_handle_t thandle;
     int          success;
+    int          exit_code;
 };
 
 
@@ -4382,6 +4383,6 @@
     struct query_symlink_reply query_symlink_reply;
 };
 
-#define SERVER_PROTOCOL_VERSION 237
+#define SERVER_PROTOCOL_VERSION 238
 
 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
diff --git a/server/process.c b/server/process.c
index 0c71540..231eb2f 100644
--- a/server/process.c
+++ b/server/process.c
@@ -94,17 +94,11 @@
 struct startup_info
 {
     struct object       obj;          /* object header */
-    struct list         entry;        /* entry in list of startup infos */
-    int                 inherit_all;  /* inherit all handles from parent */
-    unsigned int        create_flags; /* creation flags */
-    int                 unix_pid;     /* Unix pid of new process */
     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 thread      *owner;        /* owner thread (the one that created the new process) */
     struct process     *process;      /* created process */
-    struct thread      *thread;       /* created thread */
     size_t              data_size;    /* size of startup data */
     void               *data;         /* data for startup info */
 };
@@ -130,8 +124,6 @@
 };
 
 
-static struct list startup_info_list = LIST_INIT(startup_info_list);
-
 struct ptid_entry
 {
     void        *ptr;   /* entry ptr */
@@ -226,13 +218,18 @@
 }
 
 /* create a new process and its main thread */
-struct thread *create_process( int fd )
+/* if the function fails the fd is closed */
+struct thread *create_process( int fd, struct thread *parent_thread, int inherit_all )
 {
     struct process *process;
     struct thread *thread = NULL;
     int request_pipe[2];
 
-    if (!(process = alloc_object( &process_ops ))) goto error;
+    if (!(process = alloc_object( &process_ops )))
+    {
+        close( fd );
+        goto error;
+    }
     process->parent          = NULL;
     process->debugger        = NULL;
     process->handles         = NULL;
@@ -261,9 +258,24 @@
     gettimeofday( &process->start_time, NULL );
     list_add_head( &process_list, &process->entry );
 
-    if (!(process->id = process->group_id = alloc_ptid( process ))) goto error;
+    if (!(process->id = process->group_id = alloc_ptid( process )))
+    {
+        close( fd );
+        goto error;
+    }
     if (!(process->msg_fd = create_anonymous_fd( &process_fd_ops, fd, &process->obj ))) goto error;
 
+    /* create the handle table */
+    if (!parent_thread) process->handles = alloc_handle_table( process, 0 );
+    else
+    {
+        struct process *parent = parent_thread->process;
+        process->parent = (struct process *)grab_object( parent );
+        process->handles = inherit_all ? copy_handle_table( process, parent )
+                                       : alloc_handle_table( process, 0 );
+    }
+    if (!process->handles) goto error;
+
     /* create the main thread */
     if (pipe( request_pipe ) == -1)
     {
@@ -290,82 +302,13 @@
     return NULL;
 }
 
-/* find the startup info for a given Unix process */
-inline static struct startup_info *find_startup_info( int unix_pid )
-{
-    struct list *ptr;
-
-    LIST_FOR_EACH( ptr, &startup_info_list )
-    {
-        struct startup_info *info = LIST_ENTRY( ptr, struct startup_info, entry );
-        if (info->unix_pid == unix_pid) return info;
-    }
-    return NULL;
-}
-
 /* initialize the current process and fill in the request */
 size_t init_process( struct thread *thread )
 {
     struct process *process = thread->process;
-    struct thread *parent_thread = NULL;
-    struct process *parent = NULL;
-    struct startup_info *info;
-
-    if (process->startup_info) return process->startup_info->data_size;  /* already initialized */
-
-    if ((info = find_startup_info( thread->unix_pid )))
-    {
-        if (info->thread) return info->data_size;  /* already initialized */
-
-        info->thread  = (struct thread *)grab_object( thread );
-        info->process = (struct process *)grab_object( process );
-        process->startup_info = (struct startup_info *)grab_object( info );
-
-        parent_thread = info->owner;
-        parent = parent_thread->process;
-        process->parent = (struct process *)grab_object( parent );
-
-        /* set the process flags */
-        process->create_flags = info->create_flags;
-
-        if (info->inherit_all) process->handles = copy_handle_table( process, parent );
-    }
-
-    /* create the handle table */
-    if (!process->handles) process->handles = alloc_handle_table( process, 0 );
-    if (!process->handles)
-    {
-        set_error( STATUS_NO_MEMORY );
-        return 0;
-    }
-
-    /* connect to the window station */
-    connect_process_winstation( process, parent_thread );
+    struct startup_info *info = process->startup_info;
 
     if (!info) return 0;
-
-    /* thread will be actually suspended in init_done */
-    if (info->create_flags & CREATE_SUSPENDED) thread->suspend++;
-
-    /* set the process console */
-    if (!(info->create_flags & (DETACHED_PROCESS | CREATE_NEW_CONSOLE)))
-    {
-        /* FIXME: some better error checking should be done...
-         * like if hConOut and hConIn are console handles, then they should be on the same
-         * physical console
-         */
-        inherit_console( parent_thread, process, info->inherit_all ? info->hstdin : 0 );
-    }
-
-    /* attach to the debugger if requested */
-    if (process->create_flags & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS))
-        set_process_debugger( process, parent_thread );
-    else if (parent->debugger && !(parent->create_flags & DEBUG_ONLY_THIS_PROCESS))
-        set_process_debugger( process, parent->debugger );
-
-    if (!(process->create_flags & CREATE_NEW_PROCESS_GROUP))
-        process->group_id = parent->group_id;
-
     return info->data_size;
 }
 
@@ -426,12 +369,9 @@
 {
     struct startup_info *info = (struct startup_info *)obj;
     assert( obj->ops == &startup_info_ops );
-    list_remove( &info->entry );
     if (info->data) free( info->data );
     if (info->exe_file) release_object( info->exe_file );
     if (info->process) release_object( info->process );
-    if (info->thread) release_object( info->thread );
-    if (info->owner) release_object( info->owner );
 }
 
 static void startup_info_dump( struct object *obj, int verbose )
@@ -439,8 +379,8 @@
     struct startup_info *info = (struct startup_info *)obj;
     assert( obj->ops == &startup_info_ops );
 
-    fprintf( stderr, "Startup info flags=%x in=%p out=%p err=%p\n",
-             info->create_flags, info->hstdin, info->hstdout, info->hstderr );
+    fprintf( stderr, "Startup info in=%p out=%p err=%p\n",
+             info->hstdin, info->hstdout, info->hstderr );
 }
 
 static int startup_info_signaled( struct object *obj, struct thread *thread )
@@ -792,20 +732,30 @@
 DECL_HANDLER(new_process)
 {
     struct startup_info *info;
+    struct thread *thread;
+    struct process *process;
+    struct process *parent = current->process;
+    int socket_fd = thread_get_inflight_fd( current, req->socket_fd );
+
+    if (socket_fd == -1)
+    {
+        set_error( STATUS_INVALID_PARAMETER );
+        return;
+    }
+    if (fcntl( socket_fd, F_SETFL, O_NONBLOCK ) == -1)
+    {
+        set_error( STATUS_INVALID_HANDLE );
+        close( socket_fd );
+        return;
+    }
 
     /* build the startup info for a new process */
     if (!(info = alloc_object( &startup_info_ops ))) return;
-    list_add_head( &startup_info_list, &info->entry );
-    info->inherit_all  = req->inherit_all;
-    info->create_flags = req->create_flags;
-    info->unix_pid     = req->unix_pid;
     info->hstdin       = req->hstdin;
     info->hstdout      = req->hstdout;
     info->hstderr      = req->hstderr;
     info->exe_file     = NULL;
-    info->owner        = (struct thread *)grab_object( current );
     info->process      = NULL;
-    info->thread       = NULL;
     info->data_size    = get_req_data_size();
     info->data         = NULL;
 
@@ -814,7 +764,56 @@
         goto done;
 
     if (!(info->data = memdup( get_req_data(), info->data_size ))) goto done;
+
+    if (!(thread = create_process( socket_fd, current, req->inherit_all ))) goto done;
+    process = thread->process;
+    process->create_flags = req->create_flags;
+    process->startup_info = (struct startup_info *)grab_object( info );
+
+    /* connect to the window station */
+    connect_process_winstation( process, current );
+
+    /* thread will be actually suspended in init_done */
+    if (req->create_flags & CREATE_SUSPENDED) thread->suspend++;
+
+    /* set the process console */
+    if (!(req->create_flags & (DETACHED_PROCESS | CREATE_NEW_CONSOLE)))
+    {
+        /* FIXME: some better error checking should be done...
+         * 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 );
+    }
+
+    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 );
+        /* 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();
+    }
+
+    /* attach to the debugger if requested */
+    if (req->create_flags & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS))
+        set_process_debugger( process, current );
+    else if (parent->debugger && !(parent->create_flags & DEBUG_ONLY_THIS_PROCESS))
+        set_process_debugger( process, parent->debugger );
+
+    if (!(req->create_flags & CREATE_NEW_PROCESS_GROUP))
+        process->group_id = parent->group_id;
+
+    info->process = (struct process *)grab_object( process );
     reply->info = alloc_handle( current->process, info, SYNCHRONIZE, 0 );
+    reply->pid = get_process_id( process );
+    reply->tid = get_thread_id( thread );
+    reply->phandle = alloc_handle( parent, process, req->process_access, req->process_attr );
+    reply->thandle = alloc_handle( parent, thread, req->thread_access, req->thread_attr );
 
  done:
     release_object( info );
@@ -828,23 +827,10 @@
     if ((info = (struct startup_info *)get_handle_obj( current->process, req->info,
                                                        0, &startup_info_ops )))
     {
-        reply->pid = get_process_id( info->process );
-        reply->tid = get_thread_id( info->thread );
-        reply->phandle = alloc_handle( current->process, info->process,
-                                       req->process_access, req->process_attr );
-        reply->thandle = alloc_handle( current->process, info->thread,
-                                       req->thread_access, req->thread_attr );
         reply->success = is_process_init_done( info->process );
+        reply->exit_code = info->process->exit_code;
         release_object( info );
     }
-    else
-    {
-        reply->pid     = 0;
-        reply->tid     = 0;
-        reply->phandle = 0;
-        reply->thandle = 0;
-        reply->success = 0;
-    }
 }
 
 /* Retrieve the new process startup info */
@@ -859,25 +845,9 @@
     if (info->exe_file &&
         !(reply->exe_file = alloc_handle( process, info->exe_file, GENERIC_READ, 0 ))) return;
 
-    if (!info->inherit_all && !(info->create_flags & CREATE_NEW_CONSOLE))
-    {
-        struct process *parent_process = info->owner->process;
-        reply->hstdin  = duplicate_handle( parent_process, info->hstdin, process,
-                                           0, OBJ_INHERIT, DUPLICATE_SAME_ACCESS );
-        reply->hstdout = duplicate_handle( parent_process, info->hstdout, process,
-                                           0, OBJ_INHERIT, DUPLICATE_SAME_ACCESS );
-        reply->hstderr = duplicate_handle( parent_process, info->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();
-    }
-    else
-    {
-        reply->hstdin  = info->hstdin;
-        reply->hstdout = info->hstdout;
-        reply->hstderr = info->hstderr;
-    }
+    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 */
     size = info->data_size;
diff --git a/server/process.h b/server/process.h
index baf2632..e5289da 100644
--- a/server/process.h
+++ b/server/process.h
@@ -102,7 +102,7 @@
 extern unsigned int alloc_ptid( void *ptr );
 extern void free_ptid( unsigned int id );
 extern void *get_ptid_entry( unsigned int id );
-extern struct thread *create_process( int fd );
+extern struct thread *create_process( int fd, struct thread *parent_thread, int inherit_all );
 extern size_t init_process( struct thread *thread );
 extern struct thread *get_process_first_thread( struct process *process );
 extern struct process *get_process_from_id( process_id_t id );
diff --git a/server/protocol.def b/server/protocol.def
index 663f910..eab3115 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -205,33 +205,34 @@
 
 /* Create a new process from the context of the parent */
 @REQ(new_process)
-    int          inherit_all;  /* inherit all handles from parent */
-    unsigned int create_flags; /* creation flags */
-    int          unix_pid;     /* Unix pid of new process */
-    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 */
-    VARARG(env,unicode_str);   /* environment for new process */
+    int          inherit_all;    /* inherit all handles from parent */
+    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 */
+    VARARG(env,unicode_str);     /* environment for new process */
 @REPLY
-    obj_handle_t info;         /* new process info handle */
+    obj_handle_t info;           /* new process info handle */
+    process_id_t pid;            /* process id */
+    obj_handle_t phandle;        /* process handle (in the current process) */
+    thread_id_t  tid;            /* thread id */
+    obj_handle_t thandle;        /* thread handle (in the current process) */
 @END
 
 
 /* Retrieve information about a newly started process */
 @REQ(get_new_process_info)
     obj_handle_t info;           /* info handle returned from new_process_request */
-    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 */
 @REPLY
-    process_id_t pid;          /* process id */
-    obj_handle_t phandle;      /* process handle (in the current process) */
-    thread_id_t  tid;          /* thread id */
-    obj_handle_t thandle;      /* thread handle (in the current process) */
     int          success;      /* did the process start successfully? */
+    int          exit_code;    /* process exit code if failed */
 @END
 
 
diff --git a/server/request.c b/server/request.c
index a78916e..260fc62 100644
--- a/server/request.c
+++ b/server/request.c
@@ -508,7 +508,7 @@
             sock->timeout = NULL;
         }
         fcntl( client, F_SETFL, O_NONBLOCK );
-        create_process( client );
+        create_process( client, NULL, 0 );
     }
 }
 
diff --git a/server/trace.c b/server/trace.c
index 24e0c6e..b5e40b8 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -606,11 +606,15 @@
 {
     fprintf( stderr, " inherit_all=%d,", req->inherit_all );
     fprintf( stderr, " create_flags=%08x,", req->create_flags );
-    fprintf( stderr, " unix_pid=%d,", req->unix_pid );
+    fprintf( stderr, " socket_fd=%d,", req->socket_fd );
     fprintf( stderr, " exe_file=%p,", req->exe_file );
     fprintf( stderr, " hstdin=%p,", req->hstdin );
     fprintf( stderr, " hstdout=%p,", req->hstdout );
     fprintf( stderr, " hstderr=%p,", 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 );
     fprintf( stderr, " info=" );
     dump_varargs_startup_info( cur_size );
     fputc( ',', stderr );
@@ -620,25 +624,22 @@
 
 static void dump_new_process_reply( const struct new_process_reply *req )
 {
-    fprintf( stderr, " info=%p", req->info );
+    fprintf( stderr, " info=%p,", req->info );
+    fprintf( stderr, " pid=%04x,", req->pid );
+    fprintf( stderr, " phandle=%p,", req->phandle );
+    fprintf( stderr, " tid=%04x,", req->tid );
+    fprintf( stderr, " thandle=%p", req->thandle );
 }
 
 static void dump_get_new_process_info_request( const struct get_new_process_info_request *req )
 {
-    fprintf( stderr, " info=%p,", req->info );
-    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 );
+    fprintf( stderr, " info=%p", req->info );
 }
 
 static void dump_get_new_process_info_reply( const struct get_new_process_info_reply *req )
 {
-    fprintf( stderr, " pid=%04x,", req->pid );
-    fprintf( stderr, " phandle=%p,", req->phandle );
-    fprintf( stderr, " tid=%04x,", req->tid );
-    fprintf( stderr, " thandle=%p,", req->thandle );
-    fprintf( stderr, " success=%d", req->success );
+    fprintf( stderr, " success=%d,", req->success );
+    fprintf( stderr, " exit_code=%d", req->exit_code );
 }
 
 static void dump_new_thread_request( const struct new_thread_request *req )