~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/kernel32/process.c

Version: ~ [ wine-1.0-rc1 ] ~ [ wine-0.9.61 ] ~ [ wine-0.9.60 ] ~ [ wine-0.9.59 ] ~ [ wine-0.9.58 ] ~ [ wine-0.9.57 ] ~ [ wine-0.9.56 ] ~ [ wine-0.9.55 ] ~ [ wine-0.9.54 ] ~ [ wine-0.9.53 ] ~ [ wine-0.9.52 ] ~ [ wine-0.9.51 ] ~ [ wine-0.9.50 ] ~ [ wine-0.9.49 ] ~ [ wine-0.9.48 ] ~ [ wine-0.9.47 ] ~ [ wine-0.9.46 ] ~ [ wine-0.9.45 ] ~ [ wine-0.9.44 ] ~ [ wine-0.9.43 ] ~ [ wine-0.9.42 ] ~ [ wine-0.9.41 ] ~ [ wine-0.9.40 ] ~ [ wine-0.9.39 ] ~ [ wine-0.9.38 ] ~ [ wine-0.9.37 ] ~ [ wine-0.9.36 ] ~ [ wine-0.9.35 ] ~ [ wine-0.9.34 ] ~ [ wine-0.9.33 ] ~ [ wine-0.9.32 ] ~ [ wine-0.9.31 ] ~ [ wine-0.9.30 ] ~ [ wine-0.9.29 ] ~ [ wine-0.9.28 ] ~ [ wine-0.9.27 ] ~ [ wine-0.9.26 ] ~ [ wine-0.9.25 ] ~ [ wine-0.9.24 ] ~ [ wine-0.9.23 ] ~ [ wine-0.9.22 ] ~ [ wine-0.9.21 ] ~ [ wine-0.9.20 ] ~ [ wine-0.9.19 ] ~ [ wine-0.9.18 ] ~ [ wine-0.9.17 ] ~ [ wine-0.9.16 ] ~ [ wine-0.9.15 ] ~ [ wine-0.9.14 ] ~ [ wine-0.9.13 ] ~ [ wine-0.9.12 ] ~ [ wine-0.9.11 ] ~ [ wine-0.9.10 ] ~ [ wine-0.9.9 ] ~ [ wine-0.9.8 ] ~ [ wine-0.9.7 ] ~ [ wine-0.9.6 ] ~ [ wine-0.9.5 ] ~ [ wine-0.9.4 ] ~ [ wine-0.9.3 ] ~ [ wine-0.9.2 ] ~ [ wine-0.9.1 ] ~ [ wine-0.9 ] ~ [ wine20050930 ] ~ [ wine20050830 ] ~ [ wine20050725 ] ~ [ wine20050628 ] ~ [ wine20050524 ] ~ [ wine20050419 ] ~ [ wine20050310 ] ~ [ wine20050211 ] ~ [ wine20050111 ] ~ [ wine20041201 ] ~ [ wine20041019 ] ~ [ wine20040914 ] ~ [ wine20040813 ] ~ [ wine20040716 ] ~ [ wine20040615 ] ~ [ wine20040505 ] ~ [ wine20040408 ] ~ [ wine20040309 ] ~ [ wine20040213 ] ~ [ wine20040121 ] ~ [ wine20031212 ] ~ [ wine20031118 ] ~ [ wine20031016 ] ~ [ wine20030911 ] ~ [ wine20030813 ] ~ [ wine20030709 ] ~ [ wine20030618 ] ~ [ wine20030508 ] ~ [ wine20030408 ] ~ [ wine20030318 ] ~ [ wine20030219 ] ~ [ wine20030115 ] ~ [ wine20021219 ] ~ [ wine20021125 ] ~ [ wine20021031 ] ~ [ wine20021007 ] ~ [ wine20020904 ] ~ [ wine20020804 ] ~ [ wine20020710 ] ~ [ wine20020605 ] ~ [ wine20020509 ] ~ [ wine20020411 ] ~ [ wine20020310 ] ~ [ wine20020228 ] ~ [ wine20011226 ] ~ [ wine20011108 ] ~ [ wine20011004 ] ~ [ wine20010824 ] ~ [ wine20010731 ] ~ [ wine20010629 ] ~ [ wine20010510 ] ~ [ wine20010418 ] ~ [ wine20010326 ] ~ [ wine20010305 ] ~ [ wine20010216 ] ~ [ wine20010112 ] ~ [ wine20001222 ] ~ [ wine20001202 ] ~ [ wine20001026 ] ~ [ wine20001002 ] ~ [ wine20000909 ] ~ [ wine20000821 ] ~ [ wine20000801 ] ~ [ wine20000716 ] ~ [ wine20000326 ] ~ [ wine20000227 ] ~ [ wine20000130 ] ~ [ wine20000109 ] ~

  1 /*
  2  * Win32 processes
  3  *
  4  * Copyright 1996, 1998 Alexandre Julliard
  5  *
  6  * This library is free software; you can redistribute it and/or
  7  * modify it under the terms of the GNU Lesser General Public
  8  * License as published by the Free Software Foundation; either
  9  * version 2.1 of the License, or (at your option) any later version.
 10  *
 11  * This library is distributed in the hope that it will be useful,
 12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 14  * Lesser General Public License for more details.
 15  *
 16  * You should have received a copy of the GNU Lesser General Public
 17  * License along with this library; if not, write to the Free Software
 18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 19  */
 20 
 21 #include "config.h"
 22 #include "wine/port.h"
 23 
 24 #include <assert.h>
 25 #include <ctype.h>
 26 #include <errno.h>
 27 #include <signal.h>
 28 #include <stdio.h>
 29 #include <time.h>
 30 #ifdef HAVE_SYS_TIME_H
 31 # include <sys/time.h>
 32 #endif
 33 #ifdef HAVE_SYS_IOCTL_H
 34 #include <sys/ioctl.h>
 35 #endif
 36 #ifdef HAVE_SYS_SOCKET_H
 37 #include <sys/socket.h>
 38 #endif
 39 #ifdef HAVE_SYS_PRCTL_H
 40 # include <sys/prctl.h>
 41 #endif
 42 #include <sys/types.h>
 43 
 44 #include "ntstatus.h"
 45 #define WIN32_NO_STATUS
 46 #include "wine/winbase16.h"
 47 #include "wine/winuser16.h"
 48 #include "winternl.h"
 49 #include "kernel_private.h"
 50 #include "wine/exception.h"
 51 #include "wine/server.h"
 52 #include "wine/unicode.h"
 53 #include "wine/debug.h"
 54 
 55 WINE_DEFAULT_DEBUG_CHANNEL(process);
 56 WINE_DECLARE_DEBUG_CHANNEL(file);
 57 WINE_DECLARE_DEBUG_CHANNEL(relay);
 58 
 59 typedef struct
 60 {
 61     LPSTR lpEnvAddress;
 62     LPSTR lpCmdLine;
 63     LPSTR lpCmdShow;
 64     DWORD dwReserved;
 65 } LOADPARMS32;
 66 
 67 static UINT process_error_mode;
 68 
 69 static DWORD shutdown_flags = 0;
 70 static DWORD shutdown_priority = 0x280;
 71 static DWORD process_dword;
 72 
 73 HMODULE kernel32_handle = 0;
 74 
 75 const WCHAR *DIR_Windows = NULL;
 76 const WCHAR *DIR_System = NULL;
 77 
 78 /* Process flags */
 79 #define PDB32_DEBUGGED      0x0001  /* Process is being debugged */
 80 #define PDB32_WIN16_PROC    0x0008  /* Win16 process */
 81 #define PDB32_DOS_PROC      0x0010  /* Dos process */
 82 #define PDB32_CONSOLE_PROC  0x0020  /* Console process */
 83 #define PDB32_FILE_APIS_OEM 0x0040  /* File APIs are OEM */
 84 #define PDB32_WIN32S_PROC   0x8000  /* Win32s process */
 85 
 86 static const WCHAR comW[] = {'.','c','o','m',0};
 87 static const WCHAR batW[] = {'.','b','a','t',0};
 88 static const WCHAR cmdW[] = {'.','c','m','d',0};
 89 static const WCHAR pifW[] = {'.','p','i','f',0};
 90 static const WCHAR winevdmW[] = {'w','i','n','e','v','d','m','.','e','x','e',0};
 91 
 92 static void exec_process( LPCWSTR name );
 93 
 94 extern void SHELL_LoadRegistry(void);
 95 
 96 
 97 /***********************************************************************
 98  *           contains_path
 99  */
100 static inline int contains_path( LPCWSTR name )
101 {
102     return ((*name && (name[1] == ':')) || strchrW(name, '/') || strchrW(name, '\\'));
103 }
104 
105 
106 /***********************************************************************
107  *           is_special_env_var
108  *
109  * Check if an environment variable needs to be handled specially when
110  * passed through the Unix environment (i.e. prefixed with "WINE").
111  */
112 static inline int is_special_env_var( const char *var )
113 {
114     return (!strncmp( var, "PATH=", sizeof("PATH=")-1 ) ||
115             !strncmp( var, "HOME=", sizeof("HOME=")-1 ) ||
116             !strncmp( var, "TEMP=", sizeof("TEMP=")-1 ) ||
117             !strncmp( var, "TMP=", sizeof("TMP=")-1 ));
118 }
119 
120 
121 /***************************************************************************
122  *      get_builtin_path
123  *
124  * Get the path of a builtin module when the native file does not exist.
125  */
126 static BOOL get_builtin_path( const WCHAR *libname, const WCHAR *ext, WCHAR *filename, UINT size )
127 {
128     WCHAR *file_part;
129     UINT len = strlenW( DIR_System );
130 
131     if (contains_path( libname ))
132     {
133         if (RtlGetFullPathName_U( libname, size * sizeof(WCHAR),
134                                   filename, &file_part ) > size * sizeof(WCHAR))
135             return FALSE;  /* too long */
136 
137         if (strncmpiW( filename, DIR_System, len ) || filename[len] != '\\')
138             return FALSE;
139         while (filename[len] == '\\') len++;
140         if (filename + len != file_part) return FALSE;
141     }
142     else
143     {
144         if (strlenW(libname) + len + 2 >= size) return FALSE;  /* too long */
145         memcpy( filename, DIR_System, len * sizeof(WCHAR) );
146         file_part = filename + len;
147         if (file_part > filename && file_part[-1] != '\\') *file_part++ = '\\';
148         strcpyW( file_part, libname );
149     }
150     if (ext && !strchrW( file_part, '.' ))
151     {
152         if (file_part + strlenW(file_part) + strlenW(ext) + 1 > filename + size)
153             return FALSE;  /* too long */
154         strcatW( file_part, ext );
155     }
156     return TRUE;
157 }
158 
159 
160 /***********************************************************************
161  *           open_builtin_exe_file
162  *
163  * Open an exe file for a builtin exe.
164  */
165 static void *open_builtin_exe_file( const WCHAR *name, char *error, int error_size,
166                                     int test_only, int *file_exists )
167 {
168     char exename[MAX_PATH];
169     WCHAR *p;
170     UINT i, len;
171 
172     *file_exists = 0;
173     if ((p = strrchrW( name, '/' ))) name = p + 1;
174     if ((p = strrchrW( name, '\\' ))) name = p + 1;
175 
176     /* we don't want to depend on the current codepage here */
177     len = strlenW( name ) + 1;
178     if (len >= sizeof(exename)) return NULL;
179     for (i = 0; i < len; i++)
180     {
181         if (name[i] > 127) return NULL;
182         exename[i] = (char)name[i];
183         if (exename[i] >= 'A' && exename[i] <= 'Z') exename[i] += 'a' - 'A';
184     }
185     return wine_dll_load_main_exe( exename, error, error_size, test_only, file_exists );
186 }
187 
188 
189 /***********************************************************************
190  *           open_exe_file
191  *
192  * Open a specific exe file, taking load order into account.
193  * Returns the file handle or 0 for a builtin exe.
194  */
195 static HANDLE open_exe_file( const WCHAR *name )
196 {
197     HANDLE handle;
198 
199     TRACE("looking for %s\n", debugstr_w(name) );
200 
201     if ((handle = CreateFileW( name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_DELETE,
202                                NULL, OPEN_EXISTING, 0, 0 )) == INVALID_HANDLE_VALUE)
203     {
204         WCHAR buffer[MAX_PATH];
205         /* file doesn't exist, check for builtin */
206         if (!contains_path( name )) goto error;
207         if (!get_builtin_path( name, NULL, buffer, sizeof(buffer) )) goto error;
208         handle = 0;
209     }
210     return handle;
211 
212  error:
213     SetLastError( ERROR_FILE_NOT_FOUND );
214     return INVALID_HANDLE_VALUE;
215 }
216 
217 
218 /***********************************************************************
219  *           find_exe_file
220  *
221  * Open an exe file, and return the full name and file handle.
222  * Returns FALSE if file could not be found.
223  * If file exists but cannot be opened, returns TRUE and set handle to INVALID_HANDLE_VALUE.
224  * If file is a builtin exe, returns TRUE and sets handle to 0.
225  */
226 static BOOL find_exe_file( const WCHAR *name, WCHAR *buffer, int buflen, HANDLE *handle )
227 {
228     static const WCHAR exeW[] = {'.','e','x','e',0};
229     int file_exists;
230 
231     TRACE("looking for %s\n", debugstr_w(name) );
232 
233     if (!SearchPathW( NULL, name, exeW, buflen, buffer, NULL ) &&
234         !get_builtin_path( name, exeW, buffer, buflen ))
235     {
236         /* no builtin found, try native without extension in case it is a Unix app */
237 
238         if (SearchPathW( NULL, name, NULL, buflen, buffer, NULL ))
239         {
240             TRACE( "Trying native/Unix binary %s\n", debugstr_w(buffer) );
241             if ((*handle = CreateFileW( buffer, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_DELETE,
242                                         NULL, OPEN_EXISTING, 0, 0 )) != INVALID_HANDLE_VALUE)
243                 return TRUE;
244         }
245         return FALSE;
246     }
247 
248     TRACE( "Trying native exe %s\n", debugstr_w(buffer) );
249     if ((*handle = CreateFileW( buffer, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_DELETE,
250                                 NULL, OPEN_EXISTING, 0, 0 )) != INVALID_HANDLE_VALUE)
251         return TRUE;
252 
253     TRACE( "Trying built-in exe %s\n", debugstr_w(buffer) );
254     open_builtin_exe_file( buffer, NULL, 0, 1, &file_exists );
255     if (file_exists)
256     {
257         *handle = 0;
258         return TRUE;
259     }
260 
261     return FALSE;
262 }
263 
264 
265 /***********************************************************************
266  *           build_initial_environment
267  *
268  * Build the Win32 environment from the Unix environment
269  */
270 static BOOL build_initial_environment( char **environ )
271 {
272     SIZE_T size = 1;
273     char **e;
274     WCHAR *p, *endptr;
275     void *ptr;
276 
277     /* Compute the total size of the Unix environment */
278     for (e = environ; *e; e++)
279     {
280         if (is_special_env_var( *e )) continue;
281         size += MultiByteToWideChar( CP_UNIXCP, 0, *e, -1, NULL, 0 );
282     }
283     size *= sizeof(WCHAR);
284 
285     /* Now allocate the environment */
286     ptr = NULL;
287     if (NtAllocateVirtualMemory(NtCurrentProcess(), &ptr, 0, &size,
288                                 MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE) != STATUS_SUCCESS)
289         return FALSE;
290 
291     NtCurrentTeb()->Peb->ProcessParameters->Environment = p = ptr;
292     endptr = p + size / sizeof(WCHAR);
293 
294     /* And fill it with the Unix environment */
295     for (e = environ; *e; e++)
296     {
297         char *str = *e;
298 
299         /* skip Unix special variables and use the Wine variants instead */
300         if (!strncmp( str, "WINE", 4 ))
301         {
302             if (is_special_env_var( str + 4 )) str += 4;
303             else if (!strncmp( str, "WINEPRELOADRESERVE=", 19 )) continue;  /* skip it */
304         }
305         else if (is_special_env_var( str )) continue;  /* skip it */
306 
307         MultiByteToWideChar( CP_UNIXCP, 0, str, -1, p, endptr - p );
308         p += strlenW(p) + 1;
309     }
310     *p = 0;
311     return TRUE;
312 }
313 
314 
315 /***********************************************************************
316  *           set_registry_variables
317  *
318  * Set environment variables by enumerating the values of a key;
319  * helper for set_registry_environment().
320  * Note that Windows happily truncates the value if it's too big.
321  */
322 static void set_registry_variables( HANDLE hkey, ULONG type )
323 {
324     UNICODE_STRING env_name, env_value;
325     NTSTATUS status;
326     DWORD size;
327     int index;
328     char buffer[1024*sizeof(WCHAR) + sizeof(KEY_VALUE_FULL_INFORMATION)];
329     KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
330 
331     for (index = 0; ; index++)
332     {
333         status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
334                                       buffer, sizeof(buffer), &size );
335         if (status != STATUS_SUCCESS && status != STATUS_BUFFER_OVERFLOW)
336             break;
337         if (info->Type != type)
338             continue;
339         env_name.Buffer = info->Name;
340         env_name.Length = env_name.MaximumLength = info->NameLength;
341         env_value.Buffer = (WCHAR *)(buffer + info->DataOffset);
342         env_value.Length = env_value.MaximumLength = info->DataLength;
343         if (env_value.Length && !env_value.Buffer[env_value.Length/sizeof(WCHAR)-1])
344             env_value.Length -= sizeof(WCHAR);  /* don't count terminating null if any */
345         if (info->Type == REG_EXPAND_SZ)
346         {
347             WCHAR buf_expanded[1024];
348             UNICODE_STRING env_expanded;
349             env_expanded.Length = env_expanded.MaximumLength = sizeof(buf_expanded);
350             env_expanded.Buffer=buf_expanded;
351             status = RtlExpandEnvironmentStrings_U(NULL, &env_value, &env_expanded, NULL);
352             if (status == STATUS_SUCCESS || status == STATUS_BUFFER_OVERFLOW)
353                 RtlSetEnvironmentVariable( NULL, &env_name, &env_expanded );
354         }
355         else
356         {
357             RtlSetEnvironmentVariable( NULL, &env_name, &env_value );
358         }
359     }
360 }
361 
362 
363 /***********************************************************************
364  *           set_registry_environment
365  *
366  * Set the environment variables specified in the registry.
367  *
368  * Note: Windows handles REG_SZ and REG_EXPAND_SZ in one pass with the
369  * consequence that REG_EXPAND_SZ cannot be used reliably as it depends
370  * on the order in which the variables are processed. But on Windows it
371  * does not really matter since they only use %SystemDrive% and
372  * %SystemRoot% which are predefined. But Wine defines these in the
373  * registry, so we need two passes.
374  */
375 static BOOL set_registry_environment(void)
376 {
377     static const WCHAR env_keyW[] = {'M','a','c','h','i','n','e','\\',
378                                      'S','y','s','t','e','m','\\',
379                                      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
380                                      'C','o','n','t','r','o','l','\\',
381                                      'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
382                                      'E','n','v','i','r','o','n','m','e','n','t',0};
383     static const WCHAR envW[] = {'E','n','v','i','r','o','n','m','e','n','t',0};
384 
385     OBJECT_ATTRIBUTES attr;
386     UNICODE_STRING nameW;
387     HANDLE hkey;
388     BOOL ret = FALSE;
389 
390     attr.Length = sizeof(attr);
391     attr.RootDirectory = 0;
392     attr.ObjectName = &nameW;
393     attr.Attributes = 0;
394     attr.SecurityDescriptor = NULL;
395     attr.SecurityQualityOfService = NULL;
396 
397     /* first the system environment variables */
398     RtlInitUnicodeString( &nameW, env_keyW );
399     if (NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr ) == STATUS_SUCCESS)
400     {
401         set_registry_variables( hkey, REG_SZ );
402         set_registry_variables( hkey, REG_EXPAND_SZ );
403         NtClose( hkey );
404         ret = TRUE;
405     }
406 
407     /* then the ones for the current user */
408     if (RtlOpenCurrentUser( KEY_ALL_ACCESS, &attr.RootDirectory ) != STATUS_SUCCESS) return ret;
409     RtlInitUnicodeString( &nameW, envW );
410     if (NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr ) == STATUS_SUCCESS)
411     {
412         set_registry_variables( hkey, REG_SZ );
413         set_registry_variables( hkey, REG_EXPAND_SZ );
414         NtClose( hkey );
415     }
416     NtClose( attr.RootDirectory );
417     return ret;
418 }
419 
420 
421 /***********************************************************************
422  *           get_reg_value
423  */
424 static WCHAR *get_reg_value( HKEY hkey, const WCHAR *name )
425 {
426     char buffer[1024 * sizeof(WCHAR) + sizeof(KEY_VALUE_PARTIAL_INFORMATION)];
427     KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
428     DWORD len, size = sizeof(buffer);
429     WCHAR *ret = NULL;
430     UNICODE_STRING nameW;
431 
432     RtlInitUnicodeString( &nameW, name );
433     if (NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, buffer, size, &size ))
434         return NULL;
435 
436     if (size <= FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data )) return NULL;
437     len = (size - FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data )) / sizeof(WCHAR);
438 
439     if (info->Type == REG_EXPAND_SZ)
440     {
441         UNICODE_STRING value, expanded;
442 
443         value.MaximumLength = len * sizeof(WCHAR);
444         value.Buffer = (WCHAR *)info->Data;
445         if (!value.Buffer[len - 1]) len--;  /* don't count terminating null if any */
446         value.Length = len * sizeof(WCHAR);
447         expanded.Length = expanded.MaximumLength = 1024 * sizeof(WCHAR);
448         if (!(expanded.Buffer = HeapAlloc( GetProcessHeap(), 0, expanded.MaximumLength ))) return NULL;
449         if (!RtlExpandEnvironmentStrings_U( NULL, &value, &expanded, NULL )) ret = expanded.Buffer;
450         else RtlFreeUnicodeString( &expanded );
451     }
452     else if (info->Type == REG_SZ)
453     {
454         if ((ret = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) )))
455         {
456             memcpy( ret, info->Data, len * sizeof(WCHAR) );
457             ret[len] = 0;
458         }
459     }
460     return ret;
461 }
462 
463 
464 /***********************************************************************
465  *           set_additional_environment
466  *
467  * Set some additional environment variables not specified in the registry.
468  */
469 static void set_additional_environment(void)
470 {
471     static const WCHAR profile_keyW[] = {'M','a','c','h','i','n','e','\\',
472                                          'S','o','f','t','w','a','r','e','\\',
473                                          'M','i','c','r','o','s','o','f','t','\\',
474                                          'W','i','n','d','o','w','s',' ','N','T','\\',
475                                          'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
476                                          'P','r','o','f','i','l','e','L','i','s','t',0};
477     static const WCHAR profiles_valueW[] = {'P','r','o','f','i','l','e','s','D','i','r','e','c','t','o','r','y',0};
478     static const WCHAR all_users_valueW[] = {'A','l','l','U','s','e','r','s','P','r','o','f','i','l','e','\0'};
479     static const WCHAR usernameW[] = {'U','S','E','R','N','A','M','E',0};
480     static const WCHAR userprofileW[] = {'U','S','E','R','P','R','O','F','I','L','E',0};
481     static const WCHAR allusersW[] = {'A','L','L','U','S','E','R','S','P','R','O','F','I','L','E',0};
482     OBJECT_ATTRIBUTES attr;
483     UNICODE_STRING nameW;
484     WCHAR *user_name = NULL, *profile_dir = NULL, *all_users_dir = NULL;
485     HANDLE hkey;
486     const char *name = wine_get_user_name();
487     DWORD len;
488 
489     /* set the USERNAME variable */
490 
491     len = MultiByteToWideChar( CP_UNIXCP, 0, name, -1, NULL, 0 );
492     if (len)
493     {
494         user_name = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
495         MultiByteToWideChar( CP_UNIXCP, 0, name, -1, user_name, len );
496         SetEnvironmentVariableW( usernameW, user_name );
497     }
498 
499     /* set the USERPROFILE and ALLUSERSPROFILE variables */
500 
501     attr.Length = sizeof(attr);
502     attr.RootDirectory = 0;
503     attr.ObjectName = &nameW;
504     attr.Attributes = 0;
505     attr.SecurityDescriptor = NULL;
506     attr.SecurityQualityOfService = NULL;
507     RtlInitUnicodeString( &nameW, profile_keyW );
508     if (!NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr ))
509     {
510         profile_dir = get_reg_value( hkey, profiles_valueW );
511         all_users_dir = get_reg_value( hkey, all_users_valueW );
512         NtClose( hkey );
513     }
514 
515     if (profile_dir)
516     {
517         WCHAR *value, *p;
518 
519         if (all_users_dir) len = max( len, strlenW(all_users_dir) + 1 );
520         len += strlenW(profile_dir) + 1;
521         value = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
522         strcpyW( value, profile_dir );
523         p = value + strlenW(value);
524         if (p > value && p[-1] != '\\') *p++ = '\\';
525         strcpyW( p, user_name );
526         SetEnvironmentVariableW( userprofileW, value );
527         if (all_users_dir)
528         {
529             strcpyW( p, all_users_dir );
530             SetEnvironmentVariableW( allusersW, value );
531         }
532         HeapFree( GetProcessHeap(), 0, value );
533     }
534 
535     HeapFree( GetProcessHeap(), 0, all_users_dir );
536     HeapFree( GetProcessHeap(), 0, profile_dir );
537     HeapFree( GetProcessHeap(), 0, user_name );
538 }
539 
540 /***********************************************************************
541  *              set_library_wargv
542  *
543  * Set the Wine library Unicode argv global variables.
544  */
545 static void set_library_wargv( char **argv )
546 {
547     int argc;
548     char *q;
549     WCHAR *p;
550     WCHAR **wargv;
551     DWORD total = 0;
552 
553     for (argc = 0; argv[argc]; argc++)
554         total += MultiByteToWideChar( CP_UNIXCP, 0, argv[argc], -1, NULL, 0 );
555 
556     wargv = RtlAllocateHeap( GetProcessHeap(), 0,
557                              total * sizeof(WCHAR) + (argc + 1) * sizeof(*wargv) );
558     p = (WCHAR *)(wargv + argc + 1);
559     for (argc = 0; argv[argc]; argc++)
560     {
561         DWORD reslen = MultiByteToWideChar( CP_UNIXCP, 0, argv[argc], -1, p, total );
562         wargv[argc] = p;
563         p += reslen;
564         total -= reslen;
565     }
566     wargv[argc] = NULL;
567 
568     /* convert argv back from Unicode since it has to be in the Ansi codepage not the Unix one */
569 
570     for (argc = 0; wargv[argc]; argc++)
571         total += WideCharToMultiByte( CP_ACP, 0, wargv[argc], -1, NULL, 0, NULL, NULL );
572 
573     argv = RtlAllocateHeap( GetProcessHeap(), 0, total + (argc + 1) * sizeof(*argv) );
574     q = (char *)(argv + argc + 1);
575     for (argc = 0; wargv[argc]; argc++)
576     {
577         DWORD reslen = WideCharToMultiByte( CP_ACP, 0, wargv[argc], -1, q, total, NULL, NULL );
578         argv[argc] = q;
579         q += reslen;
580         total -= reslen;
581     }
582     argv[argc] = NULL;
583 
584     __wine_main_argc = argc;
585     __wine_main_argv = argv;
586     __wine_main_wargv = wargv;
587 }
588 
589 
590 /***********************************************************************
591  *           build_command_line
592  *
593  * Build the command line of a process from the argv array.
594  *
595  * Note that it does NOT necessarily include the file name.
596  * Sometimes we don't even have any command line options at all.
597  *
598  * We must quote and escape characters so that the argv array can be rebuilt
599  * from the command line:
600  * - spaces and tabs must be quoted
601  *   'a b'   -> '"a b"'
602  * - quotes must be escaped
603  *   '"'     -> '\"'
604  * - if '\'s are followed by a '"', they must be doubled and followed by '\"',
605  *   resulting in an odd number of '\' followed by a '"'
606  *   '\"'    -> '\\\"'
607  *   '\\"'   -> '\\\\\"'
608  * - '\'s that are not followed by a '"' can be left as is
609  *   'a\b'   == 'a\b'
610  *   'a\\b'  == 'a\\b'
611  */
612 static BOOL build_command_line( WCHAR **argv )
613 {
614     int len;
615     WCHAR **arg;
616     LPWSTR p;
617     RTL_USER_PROCESS_PARAMETERS* rupp = NtCurrentTeb()->Peb->ProcessParameters;
618 
619     if (rupp->CommandLine.Buffer) return TRUE; /* already got it from the server */
620 
621     len = 0;
622     for (arg = argv; *arg; arg++)
623     {
624         int has_space,bcount;
625         WCHAR* a;
626 
627         has_space=0;
628         bcount=0;
629         a=*arg;
630         if( !*a ) has_space=1;
631         while (*a!='\0') {
632             if (*a=='\\') {
633                 bcount++;
634             } else {
635                 if (*a==' ' || *a=='\t') {
636                     has_space=1;
637                 } else if (*a=='"') {
638                     /* doubling of '\' preceding a '"',
639                      * plus escaping of said '"'
640                      */
641                     len+=2*bcount+1;
642                 }
643                 bcount=0;
644             }
645             a++;
646         }
647         len+=(a-*arg)+1 /* for the separating space */;
648         if (has_space)
649             len+=2; /* for the quotes */
650     }
651 
652     if (!(rupp->CommandLine.Buffer = RtlAllocateHeap( GetProcessHeap(), 0, len * sizeof(WCHAR))))
653         return FALSE;
654 
655     p = rupp->CommandLine.Buffer;
656     rupp->CommandLine.Length = (len - 1) * sizeof(WCHAR);
657     rupp->CommandLine.MaximumLength = len * sizeof(WCHAR);
658     for (arg = argv; *arg; arg++)
659     {
660         int has_space,has_quote;
661         WCHAR* a;
662 
663         /* Check for quotes and spaces in this argument */
664         has_space=has_quote=0;
665         a=*arg;
666         if( !*a ) has_space=1;
667         while (*a!='\0') {
668             if (*a==' ' || *a=='\t') {
669                 has_space=1;
670                 if (has_quote)
671                     break;
672             } else if (*a=='"') {
673                 has_quote=1;
674                 if (has_space)
675                     break;
676             }
677             a++;
678         }
679 
680         /* Now transfer it to the command line */
681         if (has_space)
682             *p++='"';
683         if (has_quote) {
684             int bcount;
685             WCHAR* a;
686 
687             bcount=0;
688             a=*arg;
689             while (*a!='\0') {
690                 if (*a=='\\') {
691                     *p++=*a;
692                     bcount++;
693                 } else {
694                     if (*a=='"') {
695                         int i;
696 
697                         /* Double all the '\\' preceding this '"', plus one */
698                         for (i=0;i<=bcount;i++)
699                             *p++='\\';
700                         *p++='"';
701                     } else {
702                         *p++=*a;
703                     }
704                     bcount=0;
705                 }
706                 a++;
707             }
708         } else {
709             WCHAR* x = *arg;
710             while ((*p=*x++)) p++;
711         }
712         if (has_space)
713             *p++='"';
714         *p++=' ';
715     }
716     if (p > rupp->CommandLine.Buffer)
717         p--;  /* remove last space */
718     *p = '\0';
719 
720     return TRUE;
721 }
722 
723 
724 /***********************************************************************
725  *           init_current_directory
726  *
727  * Initialize the current directory from the Unix cwd or the parent info.
728  */
729 static void init_current_directory( CURDIR *cur_dir )
730 {
731     UNICODE_STRING dir_str;
732     char *cwd;
733     int size;
734 
735     /* if we received a cur dir from the parent, try this first */
736 
737     if (cur_dir->DosPath.Length)
738     {
739         if (RtlSetCurrentDirectory_U( &cur_dir->DosPath ) == STATUS_SUCCESS) goto done;
740     }
741 
742     /* now try to get it from the Unix cwd */
743 
744     for (size = 256; ; size *= 2)
745     {
746         if (!(cwd = HeapAlloc( GetProcessHeap(), 0, size ))) break;
747         if (getcwd( cwd, size )) break;
748         HeapFree( GetProcessHeap(), 0, cwd );
749         if (errno == ERANGE) continue;
750         cwd = NULL;
751         break;
752     }
753 
754     if (cwd)
755     {
756         WCHAR *dirW;
757         int lenW = MultiByteToWideChar( CP_UNIXCP, 0, cwd, -1, NULL, 0 );
758         if ((dirW = HeapAlloc( GetProcessHeap(), 0, lenW * sizeof(WCHAR) )))
759         {
760             MultiByteToWideChar( CP_UNIXCP, 0, cwd, -1, dirW, lenW );
761             RtlInitUnicodeString( &dir_str, dirW );
762             RtlSetCurrentDirectory_U( &dir_str );
763             RtlFreeUnicodeString( &dir_str );
764         }
765     }
766 
767     if (!cur_dir->DosPath.Length)  /* still not initialized */
768     {
769         MESSAGE("Warning: could not find DOS drive for current working directory '%s', "
770                 "starting in the Windows directory.\n", cwd ? cwd : "" );
771         RtlInitUnicodeString( &dir_str, DIR_Windows );
772         RtlSetCurrentDirectory_U( &dir_str );
773     }
774     HeapFree( GetProcessHeap(), 0, cwd );
775 
776 done:
777     if (!cur_dir->Handle) chdir("/"); /* change to root directory so as not to lock cdroms */
778     TRACE( "starting in %s %p\n", debugstr_w( cur_dir->DosPath.Buffer ), cur_dir->Handle );
779 }
780 
781 
782 /***********************************************************************
783  *           init_windows_dirs
784  *
785  * Initialize the windows and system directories from the environment.
786  */
787 static void init_windows_dirs(void)
788 {
789     extern void __wine_init_windows_dir( const WCHAR *windir, const WCHAR *sysdir );
790 
791     static const WCHAR windirW[] = {'w','i','n','d','i','r',0};
792     static const WCHAR winsysdirW[] = {'w','i','n','s','y','s','d','i','r',0};
793     static const WCHAR default_windirW[] = {'C',':','\\','w','i','n','d','o','w','s',0};
794     static const WCHAR default_sysdirW[] = {'\\','s','y','s','t','e','m','3','2',0};
795 
796     DWORD len;
797     WCHAR *buffer;
798 
799     if ((len = GetEnvironmentVariableW( windirW, NULL, 0 )))
800     {
801         buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
802         GetEnvironmentVariableW( windirW, buffer, len );
803         DIR_Windows = buffer;
804     }
805     else DIR_Windows = default_windirW;
806 
807     if ((len = GetEnvironmentVariableW( winsysdirW, NULL, 0 )))
808     {
809         buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
810         GetEnvironmentVariableW( winsysdirW, buffer, len );
811         DIR_System = buffer;
812     }
813     else
814     {
815         len = strlenW( DIR_Windows );
816         buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) + sizeof(default_sysdirW) );
817         memcpy( buffer, DIR_Windows, len * sizeof(WCHAR) );
818         memcpy( buffer + len, default_sysdirW, sizeof(default_sysdirW) );
819         DIR_System = buffer;
820     }
821 
822     if (!CreateDirectoryW( DIR_Windows, NULL ) && GetLastError() != ERROR_ALREADY_EXISTS)
823         ERR( "directory %s could not be created, error %u\n",
824              debugstr_w(DIR_Windows), GetLastError() );
825     if (!CreateDirectoryW( DIR_System, NULL ) && GetLastError() != ERROR_ALREADY_EXISTS)
826         ERR( "directory %s could not be created, error %u\n",
827              debugstr_w(DIR_System), GetLastError() );
828 
829     TRACE_(file)( "WindowsDir = %s\n", debugstr_w(DIR_Windows) );
830     TRACE_(file)( "SystemDir  = %s\n", debugstr_w(DIR_System) );
831 
832     /* set the directories in ntdll too */
833     __wine_init_windows_dir( DIR_Windows, DIR_System );
834 }
835 
836 
837 /***********************************************************************
838  *           start_wineboot
839  *
840  * Start the wineboot process if necessary. Return the event to wait on.
841  */
842 static HANDLE start_wineboot(void)
843 {
844     static const WCHAR wineboot_eventW[] = {'_','_','w','i','n','e','b','o','o','t','_','e','v','e','n','t',0};
845     HANDLE event;
846 
847     if (!(event = CreateEventW( NULL, TRUE, FALSE, wineboot_eventW )))
848     {
849         ERR( "failed to create wineboot event, expect trouble\n" );
850         return 0;
851     }
852     if (GetLastError() != ERROR_ALREADY_EXISTS)  /* we created it */
853     {
854         static const WCHAR command_line[] = {'\\','w','i','n','e','b','o','o','t','.','e','x','e',' ','-','-','i','n','i','t',0};
855         STARTUPINFOW si;
856         PROCESS_INFORMATION pi;
857         WCHAR cmdline[MAX_PATH + sizeof(command_line)/sizeof(WCHAR)];
858 
859         memset( &si, 0, sizeof(si) );
860         si.cb = sizeof(si);
861         si.dwFlags = STARTF_USESTDHANDLES;
862         si.hStdInput  = 0;
863         si.hStdOutput = 0;
864         si.hStdError  = GetStdHandle( STD_ERROR_HANDLE );
865 
866         GetSystemDirectoryW( cmdline, MAX_PATH );
867         lstrcatW( cmdline, command_line );
868         if (CreateProcessW( NULL, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &si, &pi ))
869         {
870             TRACE( "started wineboot pid %04x tid %04x\n", pi.dwProcessId, pi.dwThreadId );
871             CloseHandle( pi.hThread );
872             CloseHandle( pi.hProcess );
873 
874         }
875         else ERR( "failed to start wineboot, err %u\n", GetLastError() );
876     }
877     return event;
878 }
879 
880 
881 /***********************************************************************
882  *           start_process
883  *
884  * Startup routine of a new process. Runs on the new process stack.
885  */
886 static void start_process( void *arg )
887 {
888     __TRY
889     {
890         PEB *peb = NtCurrentTeb()->Peb;
891         IMAGE_NT_HEADERS *nt;
892         LPTHREAD_START_ROUTINE entry;
893