diff --git a/dlls/kernel/process.c b/dlls/kernel/process.c
index 8df05af72dd57f309d073d23837d1f85f6f87a20..07851b040e3c55e0325936e2e73969dffdabf510 100644
--- a/dlls/kernel/process.c
+++ b/dlls/kernel/process.c
@@ -64,7 +64,6 @@ typedef struct
 
 static UINT process_error_mode;
 
-static HANDLE main_exe_file;
 static DWORD shutdown_flags = 0;
 static DWORD shutdown_priority = 0x280;
 static DWORD process_dword;
@@ -637,28 +636,6 @@ static BOOL build_command_line( WCHAR **argv )
 }
 
 
-/* make sure the unicode string doesn't point beyond the end pointer */
-static inline void fix_unicode_string( UNICODE_STRING *str, char *end_ptr )
-{
-    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;
-    }
-}
-
 static void version(void)
 {
     MESSAGE( "%s\n", PACKAGE_STRING );
@@ -675,87 +652,6 @@ static void usage(void)
 }
 
 
-/***********************************************************************
- *           init_user_process_params
- *
- * Fill the RTL_USER_PROCESS_PARAMETERS structure from the server.
- */
-static BOOL init_user_process_params( RTL_USER_PROCESS_PARAMETERS *params )
-{
-    BOOL ret;
-    void *ptr;
-    SIZE_T size, env_size, info_size;
-    HANDLE hstdin, hstdout, hstderr;
-
-    size = info_size = params->AllocationSize;
-    if (!size) return TRUE;  /* no parameters received from parent */
-
-    SERVER_START_REQ( get_startup_info )
-    {
-        wine_server_set_reply( req, params, size );
-        if ((ret = !wine_server_call( req )))
-        {
-            info_size = wine_server_reply_size( reply );
-            main_exe_file     = reply->exe_file;
-            hstdin            = reply->hstdin;
-            hstdout           = reply->hstdout;
-            hstderr           = reply->hstderr;
-        }
-    }
-    SERVER_END_REQ;
-    if (!ret) return ret;
-
-    params->AllocationSize = size;
-    if (params->Size > info_size) params->Size = info_size;
-
-    /* make sure the strings are valid */
-    fix_unicode_string( &params->CurrentDirectory.DosPath, (char *)info_size );
-    fix_unicode_string( &params->DllPath, (char *)info_size );
-    fix_unicode_string( &params->ImagePathName, (char *)info_size );
-    fix_unicode_string( &params->CommandLine, (char *)info_size );
-    fix_unicode_string( &params->WindowTitle, (char *)info_size );
-    fix_unicode_string( &params->Desktop, (char *)info_size );
-    fix_unicode_string( &params->ShellInfo, (char *)info_size );
-    fix_unicode_string( &params->RuntimeInfo, (char *)info_size );
-
-    /* environment needs to be a separate memory block */
-    env_size = info_size - params->Size;
-    if (!env_size) env_size = 1;
-    ptr = NULL;
-    if (NtAllocateVirtualMemory( NtCurrentProcess(), &ptr, 0, &env_size,
-                                 MEM_COMMIT, PAGE_READWRITE ) != STATUS_SUCCESS)
-        return FALSE;
-    memcpy( ptr, (char *)params + params->Size, info_size - params->Size );
-    params->Environment = ptr;
-
-    /* convert value from server:
-     * + 0 => INVALID_HANDLE_VALUE
-     * + console handle needs to be mapped
-     */
-    if (!hstdin)
-        hstdin = INVALID_HANDLE_VALUE;
-    else if (VerifyConsoleIoHandle(console_handle_map(hstdin)))
-        hstdin = console_handle_map(hstdin);
-
-    if (!hstdout)
-        hstdout = INVALID_HANDLE_VALUE;
-    else if (VerifyConsoleIoHandle(console_handle_map(hstdout)))
-        hstdout = console_handle_map(hstdout);
-
-    if (!hstderr)
-        hstderr = INVALID_HANDLE_VALUE;
-    else if (VerifyConsoleIoHandle(console_handle_map(hstderr)))
-        hstderr = console_handle_map(hstderr);
-
-    params->hStdInput  = hstdin;
-    params->hStdOutput = hstdout;
-    params->hStdError  = hstderr;
-
-    RtlNormalizeProcessParams( params );
-    return TRUE;
-}
-
-
 /***********************************************************************
  *           init_current_directory
  *
@@ -878,6 +774,7 @@ static BOOL process_init(void)
 {
     static const WCHAR kernel32W[] = {'k','e','r','n','e','l','3','2',0};
     PEB *peb = NtCurrentTeb()->Peb;
+    RTL_USER_PROCESS_PARAMETERS *params = peb->ProcessParameters;
 
     PTHREAD_Init();
 
@@ -885,13 +782,11 @@ static BOOL process_init(void)
     setbuf(stderr,NULL);
     setlocale(LC_CTYPE,"");
 
-    if (!init_user_process_params( peb->ProcessParameters )) return FALSE;
-
     kernel32_handle = GetModuleHandleW(kernel32W);
 
     LOCALE_Init();
 
-    if (!peb->ProcessParameters->Environment)
+    if (!params->Environment)
     {
         /* Copy the parent environment */
         if (!build_initial_environment( __wine_main_environ )) return FALSE;
@@ -903,7 +798,26 @@ static BOOL process_init(void)
     }
 
     init_windows_dirs();
-    init_current_directory( &peb->ProcessParameters->CurrentDirectory );
+    init_current_directory( &params->CurrentDirectory );
+
+    /* convert value from server:
+     * + 0 => INVALID_HANDLE_VALUE
+     * + console handle needs to be mapped
+     */
+    if (!params->hStdInput)
+        params->hStdInput = INVALID_HANDLE_VALUE;
+    else if (VerifyConsoleIoHandle(console_handle_map(params->hStdInput)))
+        params->hStdInput = console_handle_map(params->hStdInput);
+
+    if (!params->hStdOutput)
+        params->hStdOutput = INVALID_HANDLE_VALUE;
+    else if (VerifyConsoleIoHandle(console_handle_map(params->hStdOutput)))
+        params->hStdOutput = console_handle_map(params->hStdOutput);
+
+    if (!params->hStdError)
+        params->hStdError = INVALID_HANDLE_VALUE;
+    else if (VerifyConsoleIoHandle(console_handle_map(params->hStdError)))
+        params->hStdError = console_handle_map(params->hStdError);
 
     return TRUE;
 }
@@ -1023,7 +937,7 @@ void __wine_kernel_init(void)
             !get_builtin_path( exe_nameW, exeW, main_exe_name, MAX_PATH ))
         {
             MESSAGE( "wine: cannot find '%s'\n", __wine_main_argv[0] );
-            ExitProcess(1);
+            ExitProcess( GetLastError() );
         }
     }
 
@@ -1031,8 +945,8 @@ void __wine_kernel_init(void)
     p = strrchrW( main_exe_name, '.' );
     if (!p || strchrW( p, '/' ) || strchrW( p, '\\' )) strcatW( main_exe_name, dotW );
 
-    TRACE( "starting process name=%s file=%p argv[0]=%s\n",
-           debugstr_w(main_exe_name), main_exe_file, debugstr_a(__wine_main_argv[0]) );
+    TRACE( "starting process name=%s argv[0]=%s\n",
+           debugstr_w(main_exe_name), debugstr_a(__wine_main_argv[0]) );
 
     RtlInitUnicodeString( &NtCurrentTeb()->Peb->ProcessParameters->DllPath,
                           MODULE_get_dll_load_path(NULL) );
@@ -1054,14 +968,12 @@ void __wine_kernel_init(void)
         }
     }
 
-    if (main_exe_file) CloseHandle( main_exe_file );
-
     if (!module)
     {
         char msg[1024];
         FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, msg, sizeof(msg), NULL );
         MESSAGE( "wine: could not load %s: %s", debugstr_w(main_exe_name), msg );
-        ExitProcess(1);
+        ExitProcess( error );
     }
 
     peb->ImageBaseAddress = module;
diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c
index aa23017b3637f63c88cbcd8d051d704e00e26b9d..4143bf28cf4814426768e27110ea985f4ca56090 100644
--- a/dlls/ntdll/loader.c
+++ b/dlls/ntdll/loader.c
@@ -85,6 +85,7 @@ struct builtin_load_info
 static struct builtin_load_info default_load_info;
 static struct builtin_load_info *builtin_load_info = &default_load_info;
 
+static HANDLE main_exe_file;
 static UINT tls_module_count;      /* number of modules with TLS directory */
 static UINT tls_total_size;        /* total size of TLS storage */
 static const IMAGE_TLS_DIRECTORY **tls_dirs;  /* array of TLS directories */
@@ -2037,6 +2038,8 @@ void WINAPI LdrInitializeThunk( ULONG unknown1, ULONG unknown2, ULONG unknown3,
     PEB *peb = NtCurrentTeb()->Peb;
     IMAGE_NT_HEADERS *nt = RtlImageNtHeader( peb->ImageBaseAddress );
 
+    if (main_exe_file) NtClose( main_exe_file );  /* at this point the main module is created */
+
     /* allocate the modref for the main exe (if not already done) */
     wm = get_modref( peb->ImageBaseAddress );
     assert( wm );
@@ -2243,7 +2246,7 @@ void __wine_process_init( int argc, char *argv[] )
     void (* DECLSPEC_NORETURN init_func)(void);
     extern mode_t FILE_umask;
 
-    thread_init();
+    main_exe_file = thread_init();
 
     /* retrieve current umask */
     FILE_umask = umask(0777);
diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h
index d50e1bdfb3ba0ced87964dae4174b7ef60fa6a58..20bd5c850c6276a6428d9ce36cad21cf437d0ab5 100644
--- a/dlls/ntdll/ntdll_misc.h
+++ b/dlls/ntdll/ntdll_misc.h
@@ -48,7 +48,7 @@ extern BOOL SIGNAL_Init(void);
 extern size_t get_signal_stack_total_size(void);
 extern void version_init( const WCHAR *appname );
 extern void debug_init(void);
-extern void thread_init(void);
+extern HANDLE thread_init(void);
 
 /* server support */
 extern time_t server_start_time;
diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c
index 760f8490afafc7c14250bb4f9e2eb7f924b444f2..5bfdceef4708084a30f6e0a8194f35894152c802 100644
--- a/dlls/ntdll/thread.c
+++ b/dlls/ntdll/thread.c
@@ -101,6 +101,94 @@ static inline void free_teb( TEB *teb )
 }
 
 
+/***********************************************************************
+ *           fix_unicode_string
+ *
+ * Make sure the unicode string doesn't point beyond the end pointer
+ */
+static inline void fix_unicode_string( UNICODE_STRING *str, char *end_ptr )
+{
+    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;
+    }
+}
+
+
+/***********************************************************************
+ *           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 )
+{
+    void *ptr;
+    SIZE_T env_size;
+    NTSTATUS status;
+    RTL_USER_PROCESS_PARAMETERS *params = NULL;
+
+    status = NtAllocateVirtualMemory( NtCurrentProcess(), (void **)&params, 0, &info_size,
+                                      MEM_COMMIT, PAGE_READWRITE );
+    if (status != STATUS_SUCCESS) return status;
+
+    params->AllocationSize = info_size;
+    peb.ProcessParameters = params;
+
+    SERVER_START_REQ( get_startup_info )
+    {
+        wine_server_set_reply( req, params, info_size );
+        if (!(status = wine_server_call( req )))
+        {
+            info_size = wine_server_reply_size( reply );
+            *exe_file = reply->exe_file;
+            params->hStdInput  = reply->hstdin;
+            params->hStdOutput = reply->hstdout;
+            params->hStdError  = reply->hstderr;
+        }
+    }
+    SERVER_END_REQ;
+    if (status != STATUS_SUCCESS) return status;
+
+    if (params->Size > info_size) params->Size = info_size;
+
+    /* make sure the strings are valid */
+    fix_unicode_string( &params->CurrentDirectory.DosPath, (char *)info_size );
+    fix_unicode_string( &params->DllPath, (char *)info_size );
+    fix_unicode_string( &params->ImagePathName, (char *)info_size );
+    fix_unicode_string( &params->CommandLine, (char *)info_size );
+    fix_unicode_string( &params->WindowTitle, (char *)info_size );
+    fix_unicode_string( &params->Desktop, (char *)info_size );
+    fix_unicode_string( &params->ShellInfo, (char *)info_size );
+    fix_unicode_string( &params->RuntimeInfo, (char *)info_size );
+
+    /* 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,
+                                      MEM_COMMIT, PAGE_READWRITE );
+    if (status != STATUS_SUCCESS) return status;
+    memcpy( ptr, (char *)params + params->Size, info_size - params->Size );
+    params->Environment = ptr;
+
+    RtlNormalizeProcessParams( params );
+    return status;
+}
+
+
 /***********************************************************************
  *           thread_init
  *
@@ -108,11 +196,12 @@ static inline void free_teb( TEB *teb )
  *
  * NOTES: The first allocated TEB on NT is at 0x7ffde000.
  */
-void thread_init(void)
+HANDLE thread_init(void)
 {
     TEB *teb;
     void *addr;
     SIZE_T info_size;
+    HANDLE exe_file = 0;
     struct ntdll_thread_data *thread_data;
     struct ntdll_thread_regs *thread_regs;
     struct wine_pthread_thread_info thread_info;
@@ -170,14 +259,7 @@ void thread_init(void)
     /* allocate user parameters */
     if (info_size)
     {
-        RTL_USER_PROCESS_PARAMETERS *params = NULL;
-
-        if (NtAllocateVirtualMemory( NtCurrentProcess(), (void **)&params, 0, &info_size,
-                                     MEM_COMMIT, PAGE_READWRITE ) == STATUS_SUCCESS)
-        {
-            params->AllocationSize = info_size;
-            NtCurrentTeb()->Peb->ProcessParameters = params;
-        }
+        init_user_process_params( info_size, &exe_file );
     }
     else
     {
@@ -188,6 +270,7 @@ void thread_init(void)
         wine_server_fd_to_handle( 1, GENERIC_WRITE|SYNCHRONIZE, OBJ_INHERIT, &params.hStdOutput );
         wine_server_fd_to_handle( 2, GENERIC_WRITE|SYNCHRONIZE, OBJ_INHERIT, &params.hStdError );
     }
+    return exe_file;
 }