kernel32: Rewrote toolhelp implementation only on top of ntdll functions.
[wine] / dlls / kernel / process.c
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 <locale.h>
28 #include <signal.h>
29 #include <stdio.h>
30 #include <time.h>
31 #ifdef HAVE_SYS_TIME_H
32 # include <sys/time.h>
33 #endif
34 #ifdef HAVE_SYS_PRCTL_H
35 # include <sys/prctl.h>
36 #endif
37 #include <sys/types.h>
38
39 #include "ntstatus.h"
40 #define WIN32_NO_STATUS
41 #include "wine/winbase16.h"
42 #include "wine/winuser16.h"
43 #include "winioctl.h"
44 #include "winternl.h"
45 #include "kernel_private.h"
46 #include "wine/exception.h"
47 #include "wine/server.h"
48 #include "wine/unicode.h"
49 #include "wine/debug.h"
50
51 #ifdef HAVE_VALGRIND_MEMCHECK_H
52 #include <valgrind/memcheck.h>
53 #endif
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 pifW[] = {'.','p','i','f',0};
89 static const WCHAR winevdmW[] = {'w','i','n','e','v','d','m','.','e','x','e',0};
90
91 extern void SHELL_LoadRegistry(void);
92
93
94 /***********************************************************************
95  *           contains_path
96  */
97 inline static int contains_path( LPCWSTR name )
98 {
99     return ((*name && (name[1] == ':')) || strchrW(name, '/') || strchrW(name, '\\'));
100 }
101
102
103 /***********************************************************************
104  *           is_special_env_var
105  *
106  * Check if an environment variable needs to be handled specially when
107  * passed through the Unix environment (i.e. prefixed with "WINE").
108  */
109 inline static int is_special_env_var( const char *var )
110 {
111     return (!strncmp( var, "PATH=", sizeof("PATH=")-1 ) ||
112             !strncmp( var, "HOME=", sizeof("HOME=")-1 ) ||
113             !strncmp( var, "TEMP=", sizeof("TEMP=")-1 ) ||
114             !strncmp( var, "TMP=", sizeof("TMP=")-1 ));
115 }
116
117
118 /***************************************************************************
119  *      get_builtin_path
120  *
121  * Get the path of a builtin module when the native file does not exist.
122  */
123 static BOOL get_builtin_path( const WCHAR *libname, const WCHAR *ext, WCHAR *filename, UINT size )
124 {
125     WCHAR *file_part;
126     UINT len = strlenW( DIR_System );
127
128     if (contains_path( libname ))
129     {
130         if (RtlGetFullPathName_U( libname, size * sizeof(WCHAR),
131                                   filename, &file_part ) > size * sizeof(WCHAR))
132             return FALSE;  /* too long */
133
134         if (strncmpiW( filename, DIR_System, len ) || filename[len] != '\\')
135             return FALSE;
136         while (filename[len] == '\\') len++;
137         if (filename + len != file_part) return FALSE;
138     }
139     else
140     {
141         if (strlenW(libname) + len + 2 >= size) return FALSE;  /* too long */
142         memcpy( filename, DIR_System, len * sizeof(WCHAR) );
143         file_part = filename + len;
144         if (file_part > filename && file_part[-1] != '\\') *file_part++ = '\\';
145         strcpyW( file_part, libname );
146     }
147     if (ext && !strchrW( file_part, '.' ))
148     {
149         if (file_part + strlenW(file_part) + strlenW(ext) + 1 > filename + size)
150             return FALSE;  /* too long */
151         strcatW( file_part, ext );
152     }
153     return TRUE;
154 }
155
156
157 /***********************************************************************
158  *           open_builtin_exe_file
159  *
160  * Open an exe file for a builtin exe.
161  */
162 static void *open_builtin_exe_file( const WCHAR *name, char *error, int error_size,
163                                     int test_only, int *file_exists )
164 {
165     char exename[MAX_PATH];
166     WCHAR *p;
167     UINT i, len;
168
169     *file_exists = 0;
170     if ((p = strrchrW( name, '/' ))) name = p + 1;
171     if ((p = strrchrW( name, '\\' ))) name = p + 1;
172
173     /* we don't want to depend on the current codepage here */
174     len = strlenW( name ) + 1;
175     if (len >= sizeof(exename)) return NULL;
176     for (i = 0; i < len; i++)
177     {
178         if (name[i] > 127) return NULL;
179         exename[i] = (char)name[i];
180         if (exename[i] >= 'A' && exename[i] <= 'Z') exename[i] += 'a' - 'A';
181     }
182     return wine_dll_load_main_exe( exename, error, error_size, test_only, file_exists );
183 }
184
185
186 /***********************************************************************
187  *           open_exe_file
188  *
189  * Open a specific exe file, taking load order into account.
190  * Returns the file handle or 0 for a builtin exe.
191  */
192 static HANDLE open_exe_file( const WCHAR *name )
193 {
194     HANDLE handle;
195
196     TRACE("looking for %s\n", debugstr_w(name) );
197
198     if ((handle = CreateFileW( name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_DELETE,
199                                NULL, OPEN_EXISTING, 0, 0 )) == INVALID_HANDLE_VALUE)
200     {
201         WCHAR buffer[MAX_PATH];
202         /* file doesn't exist, check for builtin */
203         if (!contains_path( name )) goto error;
204         if (!get_builtin_path( name, NULL, buffer, sizeof(buffer) )) goto error;
205         handle = 0;
206     }
207     return handle;
208
209  error:
210     SetLastError( ERROR_FILE_NOT_FOUND );
211     return INVALID_HANDLE_VALUE;
212 }
213
214
215 /***********************************************************************
216  *           find_exe_file
217  *
218  * Open an exe file, and return the full name and file handle.
219  * Returns FALSE if file could not be found.
220  * If file exists but cannot be opened, returns TRUE and set handle to INVALID_HANDLE_VALUE.
221  * If file is a builtin exe, returns TRUE and sets handle to 0.
222  */
223 static BOOL find_exe_file( const WCHAR *name, WCHAR *buffer, int buflen, HANDLE *handle )
224 {
225     static const WCHAR exeW[] = {'.','e','x','e',0};
226     int file_exists;
227
228     TRACE("looking for %s\n", debugstr_w(name) );
229
230     if (!SearchPathW( NULL, name, exeW, buflen, buffer, NULL ) &&
231         !get_builtin_path( name, exeW, buffer, buflen ))
232     {
233         /* no builtin found, try native without extension in case it is a Unix app */
234
235         if (SearchPathW( NULL, name, NULL, buflen, buffer, NULL ))
236         {
237             TRACE( "Trying native/Unix binary %s\n", debugstr_w(buffer) );
238             if ((*handle = CreateFileW( buffer, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_DELETE,
239                                         NULL, OPEN_EXISTING, 0, 0 )) != INVALID_HANDLE_VALUE)
240                 return TRUE;
241         }
242         return FALSE;
243     }
244
245     TRACE( "Trying native exe %s\n", debugstr_w(buffer) );
246     if ((*handle = CreateFileW( buffer, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_DELETE,
247                                 NULL, OPEN_EXISTING, 0, 0 )) != INVALID_HANDLE_VALUE)
248         return TRUE;
249
250     TRACE( "Trying built-in exe %s\n", debugstr_w(buffer) );
251     open_builtin_exe_file( buffer, NULL, 0, 1, &file_exists );
252     if (file_exists)
253     {
254         *handle = 0;
255         return TRUE;
256     }
257
258     return FALSE;
259 }
260
261
262 /***********************************************************************
263  *           build_initial_environment
264  *
265  * Build the Win32 environment from the Unix environment
266  */
267 static BOOL build_initial_environment( char **environ )
268 {
269     SIZE_T size = 1;
270     char **e;
271     WCHAR *p, *endptr;
272     void *ptr;
273
274     /* Compute the total size of the Unix environment */
275     for (e = environ; *e; e++)
276     {
277         if (is_special_env_var( *e )) continue;
278         size += MultiByteToWideChar( CP_UNIXCP, 0, *e, -1, NULL, 0 );
279     }
280     size *= sizeof(WCHAR);
281
282     /* Now allocate the environment */
283     ptr = NULL;
284     if (NtAllocateVirtualMemory(NtCurrentProcess(), &ptr, 0, &size,
285                                 MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE) != STATUS_SUCCESS)
286         return FALSE;
287
288     NtCurrentTeb()->Peb->ProcessParameters->Environment = p = ptr;
289     endptr = p + size / sizeof(WCHAR);
290
291     /* And fill it with the Unix environment */
292     for (e = environ; *e; e++)
293     {
294         char *str = *e;
295
296         /* skip Unix special variables and use the Wine variants instead */
297         if (!strncmp( str, "WINE", 4 ))
298         {
299             if (is_special_env_var( str + 4 )) str += 4;
300             else if (!strncmp( str, "WINEPRELOADRESERVE=", 19 )) continue;  /* skip it */
301         }
302         else if (is_special_env_var( str )) continue;  /* skip it */
303
304         MultiByteToWideChar( CP_UNIXCP, 0, str, -1, p, endptr - p );
305         p += strlenW(p) + 1;
306     }
307     *p = 0;
308     return TRUE;
309 }
310
311
312 /***********************************************************************
313  *           set_registry_variables
314  *
315  * Set environment variables by enumerating the values of a key;
316  * helper for set_registry_environment().
317  * Note that Windows happily truncates the value if it's too big.
318  */
319 static void set_registry_variables( HANDLE hkey, ULONG type )
320 {
321     UNICODE_STRING env_name, env_value;
322     NTSTATUS status;
323     DWORD size;
324     int index;
325     char buffer[1024*sizeof(WCHAR) + sizeof(KEY_VALUE_FULL_INFORMATION)];
326     KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
327
328     for (index = 0; ; index++)
329     {
330         status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
331                                       buffer, sizeof(buffer), &size );
332         if (status != STATUS_SUCCESS && status != STATUS_BUFFER_OVERFLOW)
333             break;
334         if (info->Type != type)
335             continue;
336         env_name.Buffer = info->Name;
337         env_name.Length = env_name.MaximumLength = info->NameLength;
338         env_value.Buffer = (WCHAR *)(buffer + info->DataOffset);
339         env_value.Length = env_value.MaximumLength = info->DataLength;
340         if (env_value.Length && !env_value.Buffer[env_value.Length/sizeof(WCHAR)-1])
341             env_value.Length--;  /* don't count terminating null if any */
342         if (info->Type == REG_EXPAND_SZ)
343         {
344             WCHAR buf_expanded[1024];
345             UNICODE_STRING env_expanded;
346             env_expanded.Length = env_expanded.MaximumLength = sizeof(buf_expanded);
347             env_expanded.Buffer=buf_expanded;
348             status = RtlExpandEnvironmentStrings_U(NULL, &env_value, &env_expanded, NULL);
349             if (status == STATUS_SUCCESS || status == STATUS_BUFFER_OVERFLOW)
350                 RtlSetEnvironmentVariable( NULL, &env_name, &env_expanded );
351         }
352         else
353         {
354             RtlSetEnvironmentVariable( NULL, &env_name, &env_value );
355         }
356     }
357 }
358
359
360 /***********************************************************************
361  *           set_registry_environment
362  *
363  * Set the environment variables specified in the registry.
364  *
365  * Note: Windows handles REG_SZ and REG_EXPAND_SZ in one pass with the
366  * consequence that REG_EXPAND_SZ cannot be used reliably as it depends
367  * on the order in which the variables are processed. But on Windows it
368  * does not really matter since they only use %SystemDrive% and
369  * %SystemRoot% which are predefined. But Wine defines these in the
370  * registry, so we need two passes.
371  */
372 static void set_registry_environment(void)
373 {
374     static const WCHAR env_keyW[] = {'M','a','c','h','i','n','e','\\',
375                                      'S','y','s','t','e','m','\\',
376                                      'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
377                                      'C','o','n','t','r','o','l','\\',
378                                      'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
379                                      'E','n','v','i','r','o','n','m','e','n','t',0};
380     static const WCHAR envW[] = {'E','n','v','i','r','o','n','m','e','n','t',0};
381
382     OBJECT_ATTRIBUTES attr;
383     UNICODE_STRING nameW;
384     HANDLE hkey;
385
386     attr.Length = sizeof(attr);
387     attr.RootDirectory = 0;
388     attr.ObjectName = &nameW;
389     attr.Attributes = 0;
390     attr.SecurityDescriptor = NULL;
391     attr.SecurityQualityOfService = NULL;
392
393     /* first the system environment variables */
394     RtlInitUnicodeString( &nameW, env_keyW );
395     if (NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr ) == STATUS_SUCCESS)
396     {
397         set_registry_variables( hkey, REG_SZ );
398         set_registry_variables( hkey, REG_EXPAND_SZ );
399         NtClose( hkey );
400     }
401
402     /* then the ones for the current user */
403     if (RtlOpenCurrentUser( KEY_ALL_ACCESS, &attr.RootDirectory ) != STATUS_SUCCESS) return;
404     RtlInitUnicodeString( &nameW, envW );
405     if (NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr ) == STATUS_SUCCESS)
406     {
407         set_registry_variables( hkey, REG_SZ );
408         set_registry_variables( hkey, REG_EXPAND_SZ );
409         NtClose( hkey );
410     }
411     NtClose( attr.RootDirectory );
412 }
413
414
415 /***********************************************************************
416  *              set_library_wargv
417  *
418  * Set the Wine library Unicode argv global variables.
419  */
420 static void set_library_wargv( char **argv )
421 {
422     int argc;
423     char *q;
424     WCHAR *p;
425     WCHAR **wargv;
426     DWORD total = 0;
427
428     for (argc = 0; argv[argc]; argc++)
429         total += MultiByteToWideChar( CP_UNIXCP, 0, argv[argc], -1, NULL, 0 );
430
431     wargv = RtlAllocateHeap( GetProcessHeap(), 0,
432                              total * sizeof(WCHAR) + (argc + 1) * sizeof(*wargv) );
433     p = (WCHAR *)(wargv + argc + 1);
434     for (argc = 0; argv[argc]; argc++)
435     {
436         DWORD reslen = MultiByteToWideChar( CP_UNIXCP, 0, argv[argc], -1, p, total );
437         wargv[argc] = p;
438         p += reslen;
439         total -= reslen;
440     }
441     wargv[argc] = NULL;
442
443     /* convert argv back from Unicode since it has to be in the Ansi codepage not the Unix one */
444
445     for (argc = 0; wargv[argc]; argc++)
446         total += WideCharToMultiByte( CP_ACP, 0, wargv[argc], -1, NULL, 0, NULL, NULL );
447
448     argv = RtlAllocateHeap( GetProcessHeap(), 0, total + (argc + 1) * sizeof(*argv) );
449     q = (char *)(argv + argc + 1);
450     for (argc = 0; wargv[argc]; argc++)
451     {
452         DWORD reslen = WideCharToMultiByte( CP_ACP, 0, wargv[argc], -1, q, total, NULL, NULL );
453         argv[argc] = q;
454         q += reslen;
455         total -= reslen;
456     }
457     argv[argc] = NULL;
458
459     __wine_main_argv = argv;
460     __wine_main_wargv = wargv;
461 }
462
463
464 /***********************************************************************
465  *           build_command_line
466  *
467  * Build the command line of a process from the argv array.
468  *
469  * Note that it does NOT necessarily include the file name.
470  * Sometimes we don't even have any command line options at all.
471  *
472  * We must quote and escape characters so that the argv array can be rebuilt
473  * from the command line:
474  * - spaces and tabs must be quoted
475  *   'a b'   -> '"a b"'
476  * - quotes must be escaped
477  *   '"'     -> '\"'
478  * - if '\'s are followed by a '"', they must be doubled and followed by '\"',
479  *   resulting in an odd number of '\' followed by a '"'
480  *   '\"'    -> '\\\"'
481  *   '\\"'   -> '\\\\\"'
482  * - '\'s that are not followed by a '"' can be left as is
483  *   'a\b'   == 'a\b'
484  *   'a\\b'  == 'a\\b'
485  */
486 static BOOL build_command_line( WCHAR **argv )
487 {
488     int len;
489     WCHAR **arg;
490     LPWSTR p;
491     RTL_USER_PROCESS_PARAMETERS* rupp = NtCurrentTeb()->Peb->ProcessParameters;
492
493     if (rupp->CommandLine.Buffer) return TRUE; /* already got it from the server */
494
495     len = 0;
496     for (arg = argv; *arg; arg++)
497     {
498         int has_space,bcount;
499         WCHAR* a;
500
501         has_space=0;
502         bcount=0;
503         a=*arg;
504         if( !*a ) has_space=1;
505         while (*a!='\0') {
506             if (*a=='\\') {
507                 bcount++;
508             } else {
509                 if (*a==' ' || *a=='\t') {
510                     has_space=1;
511                 } else if (*a=='"') {
512                     /* doubling of '\' preceding a '"',
513                      * plus escaping of said '"'
514                      */
515                     len+=2*bcount+1;
516                 }
517                 bcount=0;
518             }
519             a++;
520         }
521         len+=(a-*arg)+1 /* for the separating space */;
522         if (has_space)
523             len+=2; /* for the quotes */
524     }
525
526     if (!(rupp->CommandLine.Buffer = RtlAllocateHeap( GetProcessHeap(), 0, len * sizeof(WCHAR))))
527         return FALSE;
528
529     p = rupp->CommandLine.Buffer;
530     rupp->CommandLine.Length = (len - 1) * sizeof(WCHAR);
531     rupp->CommandLine.MaximumLength = len * sizeof(WCHAR);
532     for (arg = argv; *arg; arg++)
533     {
534         int has_space,has_quote;
535         WCHAR* a;
536
537         /* Check for quotes and spaces in this argument */
538         has_space=has_quote=0;
539         a=*arg;
540         if( !*a ) has_space=1;
541         while (*a!='\0') {
542             if (*a==' ' || *a=='\t') {
543                 has_space=1;
544                 if (has_quote)
545                     break;
546             } else if (*a=='"') {
547                 has_quote=1;
548                 if (has_space)
549                     break;
550             }
551             a++;
552         }
553
554         /* Now transfer it to the command line */
555         if (has_space)
556             *p++='"';
557         if (has_quote) {
558             int bcount;
559             WCHAR* a;
560
561             bcount=0;
562             a=*arg;
563             while (*a!='\0') {
564                 if (*a=='\\') {
565                     *p++=*a;
566                     bcount++;
567                 } else {
568                     if (*a=='"') {
569                         int i;
570
571                         /* Double all the '\\' preceding this '"', plus one */
572                         for (i=0;i<=bcount;i++)
573                             *p++='\\';
574                         *p++='"';
575                     } else {
576                         *p++=*a;
577                     }
578                     bcount=0;
579                 }
580                 a++;
581             }
582         } else {
583             WCHAR* x = *arg;
584             while ((*p=*x++)) p++;
585         }
586         if (has_space)
587             *p++='"';
588         *p++=' ';
589     }
590     if (p > rupp->CommandLine.Buffer)
591         p--;  /* remove last space */
592     *p = '\0';
593
594     return TRUE;
595 }
596
597
598 /***********************************************************************
599  *           init_current_directory
600  *
601  * Initialize the current directory from the Unix cwd or the parent info.
602  */
603 static void init_current_directory( CURDIR *cur_dir )
604 {
605     UNICODE_STRING dir_str;
606     char *cwd;
607     int size;
608
609     /* if we received a cur dir from the parent, try this first */
610
611     if (cur_dir->DosPath.Length)
612     {
613         if (RtlSetCurrentDirectory_U( &cur_dir->DosPath ) == STATUS_SUCCESS) goto done;
614     }
615
616     /* now try to get it from the Unix cwd */
617
618     for (size = 256; ; size *= 2)
619     {
620         if (!(cwd = HeapAlloc( GetProcessHeap(), 0, size ))) break;
621         if (getcwd( cwd, size )) break;
622         HeapFree( GetProcessHeap(), 0, cwd );
623         if (errno == ERANGE) continue;
624         cwd = NULL;
625         break;
626     }
627
628     if (cwd)
629     {
630         WCHAR *dirW;
631         int lenW = MultiByteToWideChar( CP_UNIXCP, 0, cwd, -1, NULL, 0 );
632         if ((dirW = HeapAlloc( GetProcessHeap(), 0, lenW * sizeof(WCHAR) )))
633         {
634             MultiByteToWideChar( CP_UNIXCP, 0, cwd, -1, dirW, lenW );
635             RtlInitUnicodeString( &dir_str, dirW );
636             RtlSetCurrentDirectory_U( &dir_str );
637             RtlFreeUnicodeString( &dir_str );
638         }
639     }
640
641     if (!cur_dir->DosPath.Length)  /* still not initialized */
642     {
643         MESSAGE("Warning: could not find DOS drive for current working directory '%s', "
644                 "starting in the Windows directory.\n", cwd ? cwd : "" );
645         RtlInitUnicodeString( &dir_str, DIR_Windows );
646         RtlSetCurrentDirectory_U( &dir_str );
647     }
648     HeapFree( GetProcessHeap(), 0, cwd );
649
650 done:
651     if (!cur_dir->Handle) chdir("/"); /* change to root directory so as not to lock cdroms */
652     TRACE( "starting in %s %p\n", debugstr_w( cur_dir->DosPath.Buffer ), cur_dir->Handle );
653 }
654
655
656 /***********************************************************************
657  *           init_windows_dirs
658  *
659  * Initialize the windows and system directories from the environment.
660  */
661 static void init_windows_dirs(void)
662 {
663     extern void __wine_init_windows_dir( const WCHAR *windir, const WCHAR *sysdir );
664
665     static const WCHAR windirW[] = {'w','i','n','d','i','r',0};
666     static const WCHAR winsysdirW[] = {'w','i','n','s','y','s','d','i','r',0};
667     static const WCHAR default_windirW[] = {'c',':','\\','w','i','n','d','o','w','s',0};
668     static const WCHAR default_sysdirW[] = {'\\','s','y','s','t','e','m','3','2',0};
669
670     DWORD len;
671     WCHAR *buffer;
672
673     if ((len = GetEnvironmentVariableW( windirW, NULL, 0 )))
674     {
675         buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
676         GetEnvironmentVariableW( windirW, buffer, len );
677         DIR_Windows = buffer;
678     }
679     else DIR_Windows = default_windirW;
680
681     if ((len = GetEnvironmentVariableW( winsysdirW, NULL, 0 )))
682     {
683         buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
684         GetEnvironmentVariableW( winsysdirW, buffer, len );
685         DIR_System = buffer;
686     }
687     else
688     {
689         len = strlenW( DIR_Windows );
690         buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) + sizeof(default_sysdirW) );
691         memcpy( buffer, DIR_Windows, len * sizeof(WCHAR) );
692         memcpy( buffer + len, default_sysdirW, sizeof(default_sysdirW) );
693         DIR_System = buffer;
694     }
695
696     if (GetFileAttributesW( DIR_Windows ) == INVALID_FILE_ATTRIBUTES)
697         MESSAGE( "Warning: the specified Windows directory %s is not accessible.\n",
698                  debugstr_w(DIR_Windows) );
699     if (GetFileAttributesW( DIR_System ) == INVALID_FILE_ATTRIBUTES)
700         MESSAGE( "Warning: the specified System directory %s is not accessible.\n",
701                  debugstr_w(DIR_System) );
702
703     TRACE_(file)( "WindowsDir = %s\n", debugstr_w(DIR_Windows) );
704     TRACE_(file)( "SystemDir  = %s\n", debugstr_w(DIR_System) );
705
706     /* set the directories in ntdll too */
707     __wine_init_windows_dir( DIR_Windows, DIR_System );
708 }
709
710
711 /***********************************************************************
712  *           process_init
713  *
714  * Main process initialisation code
715  */
716 static BOOL process_init(void)
717 {
718     static const WCHAR kernel32W[] = {'k','e','r','n','e','l','3','2',0};
719     PEB *peb = NtCurrentTeb()->Peb;
720     RTL_USER_PROCESS_PARAMETERS *params = peb->ProcessParameters;
721
722     PTHREAD_Init();
723
724     setbuf(stdout,NULL);
725     setbuf(stderr,NULL);
726     setlocale(LC_CTYPE,"");
727
728     kernel32_handle = GetModuleHandleW(kernel32W);
729
730     LOCALE_Init();
731
732     if (!params->Environment)
733     {
734         /* Copy the parent environment */
735         if (!build_initial_environment( __wine_main_environ )) return FALSE;
736
737         /* convert old configuration to new format */
738         convert_old_config();
739
740         set_registry_environment();
741     }
742
743     init_windows_dirs();
744     init_current_directory( &params->CurrentDirectory );
745
746     /* convert value from server:
747      * + 0 => INVALID_HANDLE_VALUE
748      * + console handle needs to be mapped
749      */
750     if (!params->hStdInput)
751         params->hStdInput = INVALID_HANDLE_VALUE;
752     else if (VerifyConsoleIoHandle(console_handle_map(params->hStdInput)))
753         params->hStdInput = console_handle_map(params->hStdInput);
754
755     if (!params->hStdOutput)
756         params->hStdOutput = INVALID_HANDLE_VALUE;
757     else if (VerifyConsoleIoHandle(console_handle_map(params->hStdOutput)))
758         params->hStdOutput = console_handle_map(params->hStdOutput);
759
760     if (!params->hStdError)
761         params->hStdError = INVALID_HANDLE_VALUE;
762     else if (VerifyConsoleIoHandle(console_handle_map(params->hStdError)))
763         params->hStdError = console_handle_map(params->hStdError);
764
765     return TRUE;
766 }
767
768
769 /***********************************************************************
770  *           init_stack
771  *
772  * Allocate the stack of new process.
773  */
774 static void *init_stack(void)
775 {
776     void *base;
777     SIZE_T stack_size, page_size = getpagesize();
778     IMAGE_NT_HEADERS *nt = RtlImageNtHeader( NtCurrentTeb()->Peb->ImageBaseAddress );
779
780     stack_size = max( nt->OptionalHeader.SizeOfStackReserve, nt->OptionalHeader.SizeOfStackCommit );
781     stack_size += page_size;  /* for the guard page */
782     stack_size = (stack_size + 0xffff) & ~0xffff;  /* round to 64K boundary */
783     if (stack_size < 1024 * 1024) stack_size = 1024 * 1024;  /* Xlib needs a large stack */
784
785     if (!(base = VirtualAlloc( NULL, stack_size, MEM_COMMIT, PAGE_READWRITE )))
786     {
787         ERR( "failed to allocate main process stack\n" );
788         ExitProcess( 1 );
789     }
790
791     /* note: limit is lower than base since the stack grows down */
792     NtCurrentTeb()->DeallocationStack = base;
793     NtCurrentTeb()->Tib.StackBase     = (char *)base + stack_size;
794     NtCurrentTeb()->Tib.StackLimit    = (char *)base + page_size;
795
796 #ifdef VALGRIND_STACK_REGISTER
797     /* no need to de-register the stack as it's the one of the main thread */
798     VALGRIND_STACK_REGISTER(NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase);
799 #endif
800
801     /* setup guard page */
802     VirtualProtect( base, page_size, PAGE_NOACCESS, NULL );
803     return NtCurrentTeb()->Tib.StackBase;
804 }
805
806
807 /***********************************************************************
808  *           start_process
809  *
810  * Startup routine of a new process. Runs on the new process stack.
811  */
812 static void start_process( void *arg )
813 {
814     __TRY
815     {
816         PEB *peb = NtCurrentTeb()->Peb;
817         IMAGE_NT_HEADERS *nt;
818         LPTHREAD_START_ROUTINE entry;
819
820         LdrInitializeThunk( 0, 0, 0, 0 );
821
822         nt = RtlImageNtHeader( peb->ImageBaseAddress );
823         entry = (LPTHREAD_START_ROUTINE)((char *)peb->ImageBaseAddress +
824                                          nt->OptionalHeader.AddressOfEntryPoint);
825
826         if (TRACE_ON(relay))
827             DPRINTF( "%04lx:Starting process %s (entryproc=%p)\n", GetCurrentThreadId(),
828                      debugstr_w(peb->ProcessParameters->ImagePathName.Buffer), entry );
829
830         SetLastError( 0 );  /* clear error code */
831         if (peb->BeingDebugged) DbgBreakPoint();
832         ExitProcess( entry( peb ) );
833     }
834     __EXCEPT(UnhandledExceptionFilter)
835     {
836         TerminateThread( GetCurrentThread(), GetExceptionCode() );
837     }
838     __ENDTRY
839 }
840
841
842 /***********************************************************************
843  *           set_process_name
844  *
845  * Change the process name in the ps output.
846  */
847 static void set_process_name( int *argc, char *argv[], char *name )
848 {
849 #ifdef HAVE_PRCTL
850     int i, offset;
851     char *prctl_name = NULL;
852     char *end = argv[*argc-1] + strlen(argv[*argc-1]) + 1;
853
854 #ifndef PR_SET_NAME
855 # define PR_SET_NAME 15
856 #endif
857
858     if (!name)
859     {
860         char *p;
861         prctl_name = argv[1];
862         if ((p = strrchr( prctl_name, '\\' ))) prctl_name = p + 1;
863         if ((p = strrchr( prctl_name, '/' ))) prctl_name = p + 1;
864     }
865     else
866     {
867         if (strlen(name) <= strlen(argv[0])) prctl_name = name;
868     }
869
870     if (prctl_name && prctl( PR_SET_NAME, prctl_name ) != -1)
871     {
872         if (name)
873         {
874             strcpy( argv[0], name );
875             offset = argv[1] - (argv[0] + strlen(name) + 1);
876             memmove( argv[1] - offset, argv[1], end - argv[1] );
877             memset( end - offset, 0, offset );
878             for (i = 1; i < *argc; i++) argv[i] -= offset;
879         }
880         else
881         {
882             offset = argv[1] - argv[0];
883             memmove( argv[1] - offset, argv[1], end - argv[1] );
884             memset( end - offset, 0, offset );
885             for (i = 1; i < *argc; i++) argv[i-1] = argv[i] - offset;
886             argv[i-1] = NULL;
887             (*argc)--;
888         }
889     }
890     else
891 #endif  /* HAVE_PRCTL */
892     {
893         if (name) argv[0] = name;
894         else
895         {
896             /* remove argv[0] */
897             memmove( argv, argv + 1, *argc * sizeof(argv[0]) );
898             (*argc)--;
899         }
900     }
901 }
902
903
904 /***********************************************************************
905  *           __wine_kernel_init
906  *
907  * Wine initialisation: load and start the main exe file.
908  */
909 void __wine_kernel_init(void)
910 {
911     static const WCHAR dotW[] = {'.',0};
912     static const WCHAR exeW[] = {'.','e','x','e',0};
913     static char winevdm[] = "winevdm.exe";
914
915     WCHAR *p, main_exe_name[MAX_PATH];
916     HMODULE module;
917     DWORD type, error = 0;
918     PEB *peb = NtCurrentTeb()->Peb;
919     char *new_argv0 = NULL;
920
921     /* Initialize everything */
922     if (!process_init()) exit(1);
923
924     if (peb->ProcessParameters->ImagePathName.Buffer)
925     {
926         strcpyW( main_exe_name, peb->ProcessParameters->ImagePathName.Buffer );
927     }
928     else
929     {
930         WCHAR exe_nameW[MAX_PATH];
931
932         MultiByteToWideChar( CP_UNIXCP, 0, __wine_main_argv[1], -1, exe_nameW, MAX_PATH );
933         if (!SearchPathW( NULL, exe_nameW, exeW, MAX_PATH, main_exe_name, NULL ) &&
934             !get_builtin_path( exe_nameW, exeW, main_exe_name, MAX_PATH ))
935         {
936             MESSAGE( "wine: cannot find '%s'\n", __wine_main_argv[1] );
937             ExitProcess( GetLastError() );
938         }
939     }
940
941     /* if there's no extension, append a dot to prevent LoadLibrary from appending .dll */
942     p = strrchrW( main_exe_name, '.' );
943     if (!p || strchrW( p, '/' ) || strchrW( p, '\\' )) strcatW( main_exe_name, dotW );
944
945     TRACE( "starting process name=%s argv[0]=%s\n",
946            debugstr_w(main_exe_name), debugstr_a(__wine_main_argv[1]) );
947
948     RtlInitUnicodeString( &NtCurrentTeb()->Peb->ProcessParameters->DllPath,
949                           MODULE_get_dll_load_path(main_exe_name) );
950
951     if (!(module = LoadLibraryExW( main_exe_name, 0, DONT_RESOLVE_DLL_REFERENCES )))
952     {
953         error = GetLastError();
954         /* check for a DOS binary and start winevdm if needed */
955         if (error == ERROR_BAD_EXE_FORMAT && GetBinaryTypeW( main_exe_name, &type ))
956         {
957             if (type == SCS_WOW_BINARY || type == SCS_DOS_BINARY ||
958                 type == SCS_OS216_BINARY || type == SCS_PIF_BINARY)
959             {
960                 new_argv0 = winevdm;
961                 module = LoadLibraryExW( winevdmW, 0, DONT_RESOLVE_DLL_REFERENCES );
962             }
963         }
964     }
965
966     if (!module)
967     {
968         char msg[1024];
969         FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, msg, sizeof(msg), NULL );
970         MESSAGE( "wine: could not load %s: %s", debugstr_w(main_exe_name), msg );
971         ExitProcess( error );
972     }
973
974     set_process_name( &__wine_main_argc, __wine_main_argv, new_argv0 );
975
976     peb->ImageBaseAddress = module;
977
978     /* build command line */
979     set_library_wargv( __wine_main_argv );
980     if (!build_command_line( __wine_main_wargv )) goto error;
981
982     /* switch to the new stack */
983     wine_switch_to_stack( start_process, NULL, init_stack() );
984
985  error:
986     ExitProcess( GetLastError() );
987 }
988
989
990 /***********************************************************************
991  *           build_argv
992  *
993  * Build an argv array from a command-line.
994  * 'reserved' is the number of args to reserve before the first one.
995  */
996 static char **build_argv( const WCHAR *cmdlineW, int reserved )
997 {
998     int argc;
999     char** argv;
1000     char *arg,*s,*d,*cmdline;
1001     int in_quotes,bcount,len;
1002
1003     len = WideCharToMultiByte( CP_UNIXCP, 0, cmdlineW, -1, NULL, 0, NULL, NULL );
1004     if (!(cmdline = malloc(len))) return NULL;
1005     WideCharToMultiByte( CP_UNIXCP, 0, cmdlineW, -1, cmdline, len, NULL, NULL );
1006
1007     argc=reserved+1;
1008     bcount=0;
1009     in_quotes=0;
1010     s=cmdline;
1011     while (1) {
1012         if (*s=='\0' || ((*s==' ' || *s=='\t') && !in_quotes)) {
1013             /* space */
1014             argc++;
1015             /* skip the remaining spaces */
1016             while (*s==' ' || *s=='\t') {
1017                 s++;
1018             }
1019             if (*s=='\0')
1020                 break;
1021             bcount=0;
1022             continue;
1023         } else if (*s=='\\') {
1024             /* '\', count them */
1025             bcount++;
1026         } else if ((*s=='"') && ((bcount & 1)==0)) {
1027             /* unescaped '"' */
1028             in_quotes=!in_quotes;
1029             bcount=0;
1030         } else {
1031             /* a regular character */
1032             bcount=0;
1033         }
1034         s++;
1035     }
1036     argv=malloc(argc*sizeof(*argv));
1037     if (!argv)
1038         return NULL;
1039
1040     arg=d=s=cmdline;
1041     bcount=0;
1042     in_quotes=0;
1043     argc=reserved;
1044     while (*s) {
1045         if ((*s==' ' || *s=='\t') && !in_quotes) {
1046             /* Close the argument and copy it */
1047             *d=0;
1048             argv[argc++]=arg;
1049
1050             /* skip the remaining spaces */
1051             do {
1052                 s++;
1053             } while (*s==' ' || *s=='\t');
1054
1055             /* Start with a new argument */
1056             arg=d=s;
1057             bcount=0;
1058         } else if (*s=='\\') {
1059             /* '\\' */
1060             *d++=*s++;
1061             bcount++;
1062         } else if (*s=='"') {
1063             /* '"' */
1064             if ((bcount & 1)==0) {
1065                 /* Preceded by an even number of '\', this is half that
1066                  * number of '\', plus a '"' which we discard.
1067                  */
1068                 d-=bcount/2;
1069                 s++;
1070                 in_quotes=!in_quotes;
1071             } else {
1072                 /* Preceded by an odd number of '\', this is half that
1073                  * number of '\' followed by a '"'
1074                  */
1075                 d=d-bcount/2-1;
1076                 *d++='"';
1077                 s++;
1078             }
1079             bcount=0;
1080         } else {
1081             /* a regular character */
1082             *d++=*s++;
1083             bcount=0;
1084         }
1085     }
1086     if (*arg) {
1087         *d='\0';
1088         argv[argc++]=arg;
1089     }
1090     argv[argc]=NULL;
1091
1092     return argv;
1093 }
1094
1095
1096 /***********************************************************************
1097  *           alloc_env_string
1098  *
1099  * Allocate an environment string; helper for build_envp
1100  */
1101 static char *alloc_env_string( const char *name, const char *value )
1102 {
1103     char *ret = malloc( strlen(name) + strlen(value) + 1 );
1104     strcpy( ret, name );
1105     strcat( ret, value );
1106     return ret;
1107 }
1108
1109 /***********************************************************************
1110  *           build_envp
1111  *
1112  * Build the environment of a new child process.
1113  */
1114 static char **build_envp( const WCHAR *envW )
1115 {
1116     const WCHAR *end;
1117     char **envp;
1118     char *env, *p;
1119     int count = 0, length;
1120
1121     for (end = envW; *end; count++) end += strlenW(end) + 1;
1122     end++;
1123     length = WideCharToMultiByte( CP_UNIXCP, 0, envW, end - envW, NULL, 0, NULL, NULL );
1124     if (!(env = malloc( length ))) return NULL;
1125     WideCharToMultiByte( CP_UNIXCP, 0, envW, end - envW, env, length, NULL, NULL );
1126
1127     count += 4;
1128
1129     if ((envp = malloc( count * sizeof(*envp) )))
1130     {
1131         char **envptr = envp;
1132
1133         /* some variables must not be modified, so we get them directly from the unix env */
1134         if ((p = getenv("PATH"))) *envptr++ = alloc_env_string( "PATH=", p );
1135         if ((p = getenv("TEMP"))) *envptr++ = alloc_env_string( "TEMP=", p );
1136         if ((p = getenv("TMP")))  *envptr++ = alloc_env_string( "TMP=", p );
1137         if ((p = getenv("HOME"))) *envptr++ = alloc_env_string( "HOME=", p );
1138         /* now put the Windows environment strings */
1139         for (p = env; *p; p += strlen(p) + 1)
1140         {
1141             if (*p == '=') continue;  /* skip drive curdirs, this crashes some unix apps */
1142             if (!strncmp( p, "WINEPRELOADRESERVE=", sizeof("WINEPRELOADRESERVE=")-1 )) continue;
1143             if (is_special_env_var( p ))  /* prefix it with "WINE" */
1144                 *envptr++ = alloc_env_string( "WINE", p );
1145             else
1146                 *envptr++ = p;
1147         }
1148         *envptr = 0;
1149     }
1150     return envp;
1151 }
1152
1153
1154 /***********************************************************************
1155  *           fork_and_exec
1156  *
1157  * Fork and exec a new Unix binary, checking for errors.
1158  */
1159 static int fork_and_exec( const char *filename, const WCHAR *cmdline,
1160                           const WCHAR *env, const char *newdir, DWORD flags )
1161 {
1162     int fd[2];
1163     int pid, err;
1164
1165     if (!env) env = GetEnvironmentStringsW();
1166
1167     if (pipe(fd) == -1)
1168     {
1169         SetLastError( ERROR_TOO_MANY_OPEN_FILES );
1170         return -1;
1171     }
1172     fcntl( fd[1], F_SETFD, 1 );  /* set close on exec */
1173     if (!(pid = fork()))  /* child */
1174     {
1175         char **argv = build_argv( cmdline, 0 );
1176         char **envp = build_envp( env );
1177         close( fd[0] );
1178
1179         if (flags & (CREATE_NEW_PROCESS_GROUP | CREATE_NEW_CONSOLE | DETACHED_PROCESS)) setsid();
1180
1181         /* Reset signals that we previously set to SIG_IGN */
1182         signal( SIGPIPE, SIG_DFL );
1183         signal( SIGCHLD, SIG_DFL );
1184
1185         if (newdir) chdir(newdir);
1186
1187         if (argv && envp) execve( filename, argv, envp );
1188         err = errno;
1189         write( fd[1], &err, sizeof(err) );
1190         _exit(1);
1191     }
1192     close( fd[1] );
1193     if ((pid != -1) && (read( fd[0], &err, sizeof(err) ) > 0))  /* exec failed */
1194     {
1195         errno = err;
1196         pid = -1;
1197     }
1198     if (pid == -1) FILE_SetDosError();
1199     close( fd[0] );
1200     return pid;
1201 }
1202
1203
1204 /***********************************************************************
1205  *           create_user_params
1206  */
1207 static RTL_USER_PROCESS_PARAMETERS *create_user_params( LPCWSTR filename, LPCWSTR cmdline,
1208                                                         LPCWSTR cur_dir, LPWSTR env, DWORD flags,
1209                                                         const STARTUPINFOW *startup )
1210 {
1211     RTL_USER_PROCESS_PARAMETERS *params;
1212     UNICODE_STRING image_str, cmdline_str, curdir_str, desktop, title, runtime;
1213     NTSTATUS status;
1214     WCHAR buffer[MAX_PATH];
1215
1216     if(!GetLongPathNameW( filename, buffer, MAX_PATH ))
1217         lstrcpynW( buffer, filename, MAX_PATH );
1218     if(!GetFullPathNameW( buffer, MAX_PATH, buffer, NULL ))
1219         lstrcpynW( buffer, filename, MAX_PATH );
1220     RtlInitUnicodeString( &image_str, buffer );
1221
1222     RtlInitUnicodeString( &cmdline_str, cmdline );
1223     if (cur_dir) RtlInitUnicodeString( &curdir_str, cur_dir );
1224     if (startup->lpDesktop) RtlInitUnicodeString( &desktop, startup->lpDesktop );
1225     if (startup->lpTitle) RtlInitUnicodeString( &title, startup->lpTitle );
1226     if (startup->lpReserved2 && startup->cbReserved2)
1227     {
1228         runtime.Length = 0;
1229         runtime.MaximumLength = startup->cbReserved2;
1230         runtime.Buffer = (WCHAR*)startup->lpReserved2;
1231     }
1232
1233     status = RtlCreateProcessParameters( &params, &image_str, NULL,
1234                                          cur_dir ? &curdir_str : NULL,
1235                                          &cmdline_str, env,
1236                                          startup->lpTitle ? &title : NULL,
1237                                          startup->lpDesktop ? &desktop : NULL,
1238                                          NULL, 
1239                                          (startup->lpReserved2 && startup->cbReserved2) ? &runtime : NULL );
1240     if (status != STATUS_SUCCESS)
1241     {
1242         SetLastError( RtlNtStatusToDosError(status) );
1243         return NULL;
1244     }
1245
1246     if (flags & CREATE_NEW_PROCESS_GROUP) params->ConsoleFlags = 1;
1247     if (flags & CREATE_NEW_CONSOLE) params->ConsoleHandle = (HANDLE)1;  /* FIXME: cf. kernel_main.c */
1248
1249     params->hStdInput       = startup->hStdInput;
1250     params->hStdOutput      = startup->hStdOutput;
1251     params->hStdError       = startup->hStdError;
1252     params->dwX             = startup->dwX;
1253     params->dwY             = startup->dwY;
1254     params->dwXSize         = startup->dwXSize;
1255     params->dwYSize         = startup->dwYSize;
1256     params->dwXCountChars   = startup->dwXCountChars;
1257     params->dwYCountChars   = startup->dwYCountChars;
1258     params->dwFillAttribute = startup->dwFillAttribute;
1259     params->dwFlags         = startup->dwFlags;
1260     params->wShowWindow     = startup->wShowWindow;
1261     return params;
1262 }
1263
1264
1265 /***********************************************************************
1266  *           create_process
1267  *
1268  * Create a new process. If hFile is a valid handle we have an exe
1269  * file, otherwise it is a Winelib app.
1270  */
1271 static BOOL create_process( HANDLE hFile, LPCWSTR filename, LPWSTR cmd_line, LPWSTR env,
1272                             LPCWSTR cur_dir, LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES tsa,
1273                             BOOL inherit, DWORD flags, LPSTARTUPINFOW startup,
1274                             LPPROCESS_INFORMATION info, LPCSTR unixdir,
1275                             void *res_start, void *res_end )
1276 {
1277     BOOL ret, success = FALSE;
1278     HANDLE process_info;
1279     WCHAR *env_end;
1280     char *winedebug = NULL;
1281     RTL_USER_PROCESS_PARAMETERS *params;
1282     int startfd[2];
1283     int execfd[2];
1284     pid_t pid;
1285     int err;
1286     char dummy = 0;
1287     char preloader_reserve[64];
1288
1289     if (!env) RtlAcquirePebLock();
1290
1291     if (!(params = create_user_params( filename, cmd_line, cur_dir, env, flags, startup )))
1292     {
1293         if (!env) RtlReleasePebLock();
1294         return FALSE;
1295     }
1296     env_end = params->Environment;
1297     while (*env_end)
1298     {
1299         static const WCHAR WINEDEBUG[] = {'W','I','N','E','D','E','B','U','G','=',0};
1300         if (!winedebug && !strncmpW( env_end, WINEDEBUG, sizeof(WINEDEBUG)/sizeof(WCHAR) - 1 ))
1301         {
1302             DWORD len = WideCharToMultiByte( CP_UNIXCP, 0, env_end, -1, NULL, 0, NULL, NULL );
1303             if ((winedebug = HeapAlloc( GetProcessHeap(), 0, len )))
1304                 WideCharToMultiByte( CP_UNIXCP, 0, env_end, -1, winedebug, len, NULL, NULL );
1305         }
1306         env_end += strlenW(env_end) + 1;
1307     }
1308     env_end++;
1309
1310     sprintf( preloader_reserve, "WINEPRELOADRESERVE=%lx-%lx%c",
1311              (unsigned long)res_start, (unsigned long)res_end, 0 );
1312
1313     /* create the synchronization pipes */
1314
1315     if (pipe( startfd ) == -1)
1316     {
1317         if (!env) RtlReleasePebLock();
1318         HeapFree( GetProcessHeap(), 0, winedebug );
1319         SetLastError( ERROR_TOO_MANY_OPEN_FILES );
1320         RtlDestroyProcessParameters( params );
1321         return FALSE;
1322     }
1323     if (pipe( execfd ) == -1)
1324     {
1325         if (!env) RtlReleasePebLock();
1326         HeapFree( GetProcessHeap(), 0, winedebug );
1327         SetLastError( ERROR_TOO_MANY_OPEN_FILES );
1328         close( startfd[0] );
1329         close( startfd[1] );
1330         RtlDestroyProcessParameters( params );
1331         return FALSE;
1332     }
1333     fcntl( execfd[1], F_SETFD, 1 );  /* set close on exec */
1334
1335     /* create the child process */
1336
1337     if (!(pid = fork()))  /* child */
1338     {
1339         char **argv = build_argv( cmd_line, 1 );
1340
1341         close( startfd[1] );
1342         close( execfd[0] );
1343
1344         /* wait for parent to tell us to start */
1345         if (read( startfd[0], &dummy, 1 ) != 1) _exit(1);
1346
1347         close( startfd[0] );
1348         if (flags & (CREATE_NEW_PROCESS_GROUP | CREATE_NEW_CONSOLE | DETACHED_PROCESS)) setsid();
1349
1350         /* Reset signals that we previously set to SIG_IGN */
1351         signal( SIGPIPE, SIG_DFL );
1352         signal( SIGCHLD, SIG_DFL );
1353
1354         putenv( preloader_reserve );
1355         if (winedebug) putenv( winedebug );
1356         if (unixdir) chdir(unixdir);
1357
1358         if (argv) wine_exec_wine_binary( NULL, argv, getenv("WINELOADER") );
1359
1360         err = errno;
1361         write( execfd[1], &err, sizeof(err) );
1362         _exit(1);
1363     }
1364
1365     /* this is the parent */
1366
1367     close( startfd[0] );
1368     close( execfd[1] );
1369     HeapFree( GetProcessHeap(), 0, winedebug );
1370     if (pid == -1)
1371     {
1372         if (!env) RtlReleasePebLock();
1373         close( startfd[1] );
1374         close( execfd[0] );
1375         FILE_SetDosError();
1376         RtlDestroyProcessParameters( params );
1377         return FALSE;
1378     }
1379
1380     /* create the process on the server side */
1381
1382     SERVER_START_REQ( new_process )
1383     {
1384         req->inherit_all  = inherit;
1385         req->create_flags = flags;
1386         req->unix_pid     = pid;
1387         req->exe_file     = hFile;
1388         if (startup->dwFlags & STARTF_USESTDHANDLES)
1389         {
1390             req->hstdin  = startup->hStdInput;
1391             req->hstdout = startup->hStdOutput;
1392             req->hstderr = startup->hStdError;
1393         }
1394         else
1395         {
1396             req->hstdin  = GetStdHandle( STD_INPUT_HANDLE );
1397             req->hstdout = GetStdHandle( STD_OUTPUT_HANDLE );
1398             req->hstderr = GetStdHandle( STD_ERROR_HANDLE );
1399         }
1400
1401         if ((flags & (CREATE_NEW_CONSOLE | DETACHED_PROCESS)) != 0)
1402         {
1403             /* this is temporary (for console handles). We have no way to control that the handle is invalid in child process otherwise */
1404             if (is_console_handle(req->hstdin))  req->hstdin  = INVALID_HANDLE_VALUE;
1405             if (is_console_handle(req->hstdout)) req->hstdout = INVALID_HANDLE_VALUE;
1406             if (is_console_handle(req->hstderr)) req->hstderr = INVALID_HANDLE_VALUE;
1407         }
1408         else
1409         {
1410             if (is_console_handle(req->hstdin))  req->hstdin  = console_handle_unmap(req->hstdin);
1411             if (is_console_handle(req->hstdout)) req->hstdout = console_handle_unmap(req->hstdout);
1412             if (is_console_handle(req->hstderr)) req->hstderr = console_handle_unmap(req->hstderr);
1413         }
1414
1415         wine_server_add_data( req, params, params->Size );
1416         wine_server_add_data( req, params->Environment, (env_end-params->Environment)*sizeof(WCHAR) );
1417         ret = !wine_server_call_err( req );
1418         process_info = reply->info;
1419     }
1420     SERVER_END_REQ;
1421
1422     if (!env) RtlReleasePebLock();
1423     RtlDestroyProcessParameters( params );
1424     if (!ret)
1425     {
1426         close( startfd[1] );
1427         close( execfd[0] );
1428         return FALSE;
1429     }
1430
1431     /* tell child to start and wait for it to exec */
1432
1433     write( startfd[1], &dummy, 1 );
1434     close( startfd[1] );
1435
1436     if (read( execfd[0], &err, sizeof(err) ) > 0) /* exec failed */
1437     {
1438         errno = err;
1439         FILE_SetDosError();
1440         close( execfd[0] );
1441         CloseHandle( process_info );
1442         return FALSE;
1443     }
1444     close( execfd[0] );
1445
1446     /* wait for the new process info to be ready */
1447
1448     WaitForSingleObject( process_info, INFINITE );
1449     SERVER_START_REQ( get_new_process_info )
1450     {
1451         req->info           = process_info;
1452         req->process_access = PROCESS_ALL_ACCESS;
1453         req->process_attr   = (psa && (psa->nLength >= sizeof(*psa)) && psa->bInheritHandle) ? OBJ_INHERIT : 0;
1454         req->thread_access  = THREAD_ALL_ACCESS;
1455         req->thread_attr    = (tsa && (tsa->nLength >= sizeof(*tsa)) && tsa->bInheritHandle) ? OBJ_INHERIT : 0;
1456         if ((ret = !wine_server_call_err( req )))
1457         {
1458             info->dwProcessId = (DWORD)reply->pid;
1459             info->dwThreadId  = (DWORD)reply->tid;
1460             info->hProcess    = reply->phandle;
1461             info->hThread     = reply->thandle;
1462             success           = reply->success;
1463         }
1464     }
1465     SERVER_END_REQ;
1466
1467     if (ret && !success)  /* new process failed to start */
1468     {
1469         DWORD exitcode;
1470         if (GetExitCodeProcess( info->hProcess, &exitcode )) SetLastError( exitcode );
1471         CloseHandle( info->hThread );
1472         CloseHandle( info->hProcess );
1473         ret = FALSE;
1474     }
1475     CloseHandle( process_info );
1476     return ret;
1477 }
1478
1479
1480 /***********************************************************************
1481  *           create_vdm_process
1482  *
1483  * Create a new VDM process for a 16-bit or DOS application.
1484  */
1485 static BOOL create_vdm_process( LPCWSTR filename, LPWSTR cmd_line, LPWSTR env, LPCWSTR cur_dir,
1486                                 LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES tsa,
1487                                 BOOL inherit, DWORD flags, LPSTARTUPINFOW startup,
1488                                 LPPROCESS_INFORMATION info, LPCSTR unixdir )
1489 {
1490     static const WCHAR argsW[] = {'%','s',' ','-','-','a','p','p','-','n','a','m','e',' ','"','%','s','"',' ','%','s',0};
1491
1492     BOOL ret;
1493     LPWSTR new_cmd_line = HeapAlloc( GetProcessHeap(), 0,
1494                                      (strlenW(filename) + strlenW(cmd_line) + 30) * sizeof(WCHAR) );
1495
1496     if (!new_cmd_line)
1497     {
1498         SetLastError( ERROR_OUTOFMEMORY );
1499         return FALSE;
1500     }
1501     sprintfW( new_cmd_line, argsW, winevdmW, filename, cmd_line );
1502     ret = create_process( 0, winevdmW, new_cmd_line, env, cur_dir, psa, tsa, inherit,
1503                           flags, startup, info, unixdir, NULL, NULL );
1504     HeapFree( GetProcessHeap(), 0, new_cmd_line );
1505     return ret;
1506 }
1507
1508
1509 /***********************************************************************
1510  *           create_cmd_process
1511  *
1512  * Create a new cmd shell process for a .BAT file.
1513  */
1514 static BOOL create_cmd_process( LPCWSTR filename, LPWSTR cmd_line, LPVOID env, LPCWSTR cur_dir,
1515                                 LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES tsa,
1516                                 BOOL inherit, DWORD flags, LPSTARTUPINFOW startup,
1517                                 LPPROCESS_INFORMATION info )
1518
1519 {
1520     static const WCHAR comspecW[] = {'C','O','M','S','P','E','C',0};
1521     static const WCHAR slashcW[] = {' ','/','c',' ',0};
1522     WCHAR comspec[MAX_PATH];
1523     WCHAR *newcmdline;
1524     BOOL ret;
1525
1526     if (!GetEnvironmentVariableW( comspecW, comspec, sizeof(comspec)/sizeof(WCHAR) ))
1527         return FALSE;
1528     if (!(newcmdline = HeapAlloc( GetProcessHeap(), 0,
1529                                   (strlenW(comspec) + 4 + strlenW(cmd_line) + 1) * sizeof(WCHAR))))
1530         return FALSE;
1531
1532     strcpyW( newcmdline, comspec );
1533     strcatW( newcmdline, slashcW );
1534     strcatW( newcmdline, cmd_line );
1535     ret = CreateProcessW( comspec, newcmdline, psa, tsa, inherit,
1536                           flags, env, cur_dir, startup, info );
1537     HeapFree( GetProcessHeap(), 0, newcmdline );
1538     return ret;
1539 }
1540
1541
1542 /*************************************************************************
1543  *               get_file_name
1544  *
1545  * Helper for CreateProcess: retrieve the file name to load from the
1546  * app name and command line. Store the file name in buffer, and
1547  * return a possibly modified command line.
1548  * Also returns a handle to the opened file if it's a Windows binary.
1549  */
1550 static LPWSTR get_file_name( LPCWSTR appname, LPWSTR cmdline, LPWSTR buffer,
1551                              int buflen, HANDLE *handle )
1552 {
1553     static const WCHAR quotesW[] = {'"','%','s','"',0};
1554
1555     WCHAR *name, *pos, *ret = NULL;
1556     const WCHAR *p;
1557     BOOL got_space;
1558
1559     /* if we have an app name, everything is easy */
1560
1561     if (appname)
1562     {
1563         /* use the unmodified app name as file name */
1564         lstrcpynW( buffer, appname, buflen );
1565         *handle = open_exe_file( buffer );
1566         if (!(ret = cmdline) || !cmdline[0])
1567         {
1568             /* no command-line, create one */
1569             if ((ret = HeapAlloc( GetProcessHeap(), 0, (strlenW(appname) + 3) * sizeof(WCHAR) )))
1570                 sprintfW( ret, quotesW, appname );
1571         }
1572         return ret;
1573     }
1574
1575     if (!cmdline)
1576     {
1577         SetLastError( ERROR_INVALID_PARAMETER );
1578         return NULL;
1579     }
1580
1581     /* first check for a quoted file name */
1582
1583     if ((cmdline[0] == '"') && ((p = strchrW( cmdline + 1, '"' ))))
1584     {
1585         int len = p - cmdline - 1;
1586         /* extract the quoted portion as file name */
1587         if (!(name = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return NULL;
1588         memcpy( name, cmdline + 1, len * sizeof(WCHAR) );
1589         name[len] = 0;
1590
1591         if (find_exe_file( name, buffer, buflen, handle ))
1592             ret = cmdline;  /* no change necessary */
1593         goto done;
1594     }
1595
1596     /* now try the command-line word by word */
1597
1598     if (!(name = HeapAlloc( GetProcessHeap(), 0, (strlenW(cmdline) + 1) * sizeof(WCHAR) )))
1599         return NULL;
1600     pos = name;
1601     p = cmdline;
1602     got_space = FALSE;
1603
1604     while (*p)
1605     {
1606         do *pos++ = *p++; while (*p && *p != ' ' && *p != '\t');
1607         *pos = 0;
1608         if (find_exe_file( name, buffer, buflen, handle ))
1609         {
1610             ret = cmdline;
1611             break;
1612         }
1613         if (*p) got_space = TRUE;
1614     }
1615
1616     if (ret && got_space)  /* now build a new command-line with quotes */
1617     {
1618         if (!(ret = HeapAlloc( GetProcessHeap(), 0, (strlenW(cmdline) + 3) * sizeof(WCHAR) )))
1619             goto done;
1620         sprintfW( ret, quotesW, name );
1621         strcatW( ret, p );
1622     }
1623
1624  done:
1625     HeapFree( GetProcessHeap(), 0, name );
1626     return ret;
1627 }
1628
1629
1630 /**********************************************************************
1631  *       CreateProcessA          (KERNEL32.@)
1632  */
1633 BOOL WINAPI CreateProcessA( LPCSTR app_name, LPSTR cmd_line, LPSECURITY_ATTRIBUTES process_attr,
1634                             LPSECURITY_ATTRIBUTES thread_attr, BOOL inherit,
1635                             DWORD flags, LPVOID env, LPCSTR cur_dir,
1636                             LPSTARTUPINFOA startup_info, LPPROCESS_INFORMATION info )
1637 {
1638     BOOL ret = FALSE;
1639     WCHAR *app_nameW = NULL, *cmd_lineW = NULL, *cur_dirW = NULL;
1640     UNICODE_STRING desktopW, titleW;
1641     STARTUPINFOW infoW;
1642
1643     desktopW.Buffer = NULL;
1644     titleW.Buffer = NULL;
1645     if (app_name && !(app_nameW = FILE_name_AtoW( app_name, TRUE ))) goto done;
1646     if (cmd_line && !(cmd_lineW = FILE_name_AtoW( cmd_line, TRUE ))) goto done;
1647     if (cur_dir && !(cur_dirW = FILE_name_AtoW( cur_dir, TRUE ))) goto done;
1648
1649     if (startup_info->lpDesktop) RtlCreateUnicodeStringFromAsciiz( &desktopW, startup_info->lpDesktop );
1650     if (startup_info->lpTitle) RtlCreateUnicodeStringFromAsciiz( &titleW, startup_info->lpTitle );
1651
1652     memcpy( &infoW, startup_info, sizeof(infoW) );
1653     infoW.lpDesktop = desktopW.Buffer;
1654     infoW.lpTitle = titleW.Buffer;
1655
1656     if (startup_info->lpReserved)
1657       FIXME("StartupInfo.lpReserved is used, please report (%s)\n",
1658             debugstr_a(startup_info->lpReserved));
1659
1660     ret = CreateProcessW( app_nameW, cmd_lineW, process_attr, thread_attr,
1661                           inherit, flags, env, cur_dirW, &infoW, info );
1662 done:
1663     HeapFree( GetProcessHeap(), 0, app_nameW );
1664     HeapFree( GetProcessHeap(), 0, cmd_lineW );
1665     HeapFree( GetProcessHeap(), 0, cur_dirW );
1666     RtlFreeUnicodeString( &desktopW );
1667     RtlFreeUnicodeString( &titleW );
1668     return ret;
1669 }
1670
1671
1672 /**********************************************************************
1673  *       CreateProcessW          (KERNEL32.@)
1674  */
1675 BOOL WINAPI CreateProcessW( LPCWSTR app_name, LPWSTR cmd_line, LPSECURITY_ATTRIBUTES process_attr,
1676                             LPSECURITY_ATTRIBUTES thread_attr, BOOL inherit, DWORD flags,
1677                             LPVOID env, LPCWSTR cur_dir, LPSTARTUPINFOW startup_info,
1678                             LPPROCESS_INFORMATION info )
1679 {
1680     BOOL retv = FALSE;
1681     HANDLE hFile = 0;
1682     char *unixdir = NULL;
1683     WCHAR name[MAX_PATH];
1684     WCHAR *tidy_cmdline, *p, *envW = env;
1685     void *res_start, *res_end;
1686
1687     /* Process the AppName and/or CmdLine to get module name and path */
1688
1689     TRACE("app %s cmdline %s\n", debugstr_w(app_name), debugstr_w(cmd_line) );
1690
1691     if (!(tidy_cmdline = get_file_name( app_name, cmd_line, name, sizeof(name)/sizeof(WCHAR), &hFile )))
1692         return FALSE;
1693     if (hFile == INVALID_HANDLE_VALUE) goto done;
1694
1695     /* Warn if unsupported features are used */
1696
1697     if (flags & (IDLE_PRIORITY_CLASS | HIGH_PRIORITY_CLASS | REALTIME_PRIORITY_CLASS |
1698                  CREATE_NEW_PROCESS_GROUP | CREATE_SEPARATE_WOW_VDM | CREATE_SHARED_WOW_VDM |
1699                  CREATE_DEFAULT_ERROR_MODE | CREATE_NO_WINDOW |
1700                  PROFILE_USER | PROFILE_KERNEL | PROFILE_SERVER))
1701         WARN("(%s,...): ignoring some flags in %lx\n", debugstr_w(name), flags);
1702
1703     if (cur_dir)
1704     {
1705         if (!(unixdir = wine_get_unix_file_name( cur_dir )))
1706         {
1707             SetLastError(ERROR_DIRECTORY);
1708             goto done;
1709         }
1710     }
1711     else
1712     {
1713         WCHAR buf[MAX_PATH];
1714         if (GetCurrentDirectoryW(MAX_PATH, buf)) unixdir = wine_get_unix_file_name( buf );
1715     }
1716
1717     if (env && !(flags & CREATE_UNICODE_ENVIRONMENT))  /* convert environment to unicode */
1718     {
1719         char *p = env;
1720         DWORD lenW;
1721
1722         while (*p) p += strlen(p) + 1;
1723         p++;  /* final null */
1724         lenW = MultiByteToWideChar( CP_ACP, 0, env, p - (char*)env, NULL, 0 );
1725         envW = HeapAlloc( GetProcessHeap(), 0, lenW * sizeof(WCHAR) );
1726         MultiByteToWideChar( CP_ACP, 0, env, p - (char*)env, envW, lenW );
1727         flags |= CREATE_UNICODE_ENVIRONMENT;
1728     }
1729
1730     info->hThread = info->hProcess = 0;
1731     info->dwProcessId = info->dwThreadId = 0;
1732
1733     /* Determine executable type */
1734
1735     if (!hFile)  /* builtin exe */
1736     {
1737         TRACE( "starting %s as Winelib app\n", debugstr_w(name) );
1738         retv = create_process( 0, name, tidy_cmdline, envW, cur_dir, process_attr, thread_attr,
1739                                inherit, flags, startup_info, info, unixdir, NULL, NULL );
1740         goto done;
1741     }
1742
1743     switch( MODULE_GetBinaryType( hFile, &res_start, &res_end ))
1744     {
1745     case BINARY_PE_EXE:
1746         TRACE( "starting %s as Win32 binary (%p-%p)\n", debugstr_w(name), res_start, res_end );
1747         retv = create_process( hFile, name, tidy_cmdline, envW, cur_dir, process_attr, thread_attr,
1748                                inherit, flags, startup_info, info, unixdir, res_start, res_end );
1749         break;
1750     case BINARY_OS216:
1751     case BINARY_WIN16:
1752     case BINARY_DOS:
1753         TRACE( "starting %s as Win16/DOS binary\n", debugstr_w(name) );
1754         retv = create_vdm_process( name, tidy_cmdline, envW, cur_dir, process_attr, thread_attr,
1755                                    inherit, flags, startup_info, info, unixdir );
1756         break;
1757     case BINARY_PE_DLL:
1758         TRACE( "not starting %s since it is a dll\n", debugstr_w(name) );
1759         SetLastError( ERROR_BAD_EXE_FORMAT );
1760         break;
1761     case BINARY_UNIX_LIB:
1762         TRACE( "%s is a Unix library, starting as Winelib app\n", debugstr_w(name) );
1763         retv = create_process( hFile, name, tidy_cmdline, envW, cur_dir, process_attr, thread_attr,
1764                                inherit, flags, startup_info, info, unixdir, NULL, NULL );
1765         break;
1766     case BINARY_UNKNOWN:
1767         /* check for .com or .bat extension */
1768         if ((p = strrchrW( name, '.' )))
1769         {
1770             if (!strcmpiW( p, comW ) || !strcmpiW( p, pifW ))
1771             {
1772                 TRACE( "starting %s as DOS binary\n", debugstr_w(name) );
1773                 retv = create_vdm_process( name, tidy_cmdline, envW, cur_dir, process_attr, thread_attr,
1774                                            inherit, flags, startup_info, info, unixdir );
1775                 break;
1776             }
1777             if (!strcmpiW( p, batW ))
1778             {
1779                 TRACE( "starting %s as batch binary\n", debugstr_w(name) );
1780                 retv = create_cmd_process( name, tidy_cmdline, envW, cur_dir, process_attr, thread_attr,
1781                                            inherit, flags, startup_info, info );
1782                 break;
1783             }
1784         }
1785         /* fall through */
1786     case BINARY_UNIX_EXE:
1787         {
1788             /* unknown file, try as unix executable */
1789             char *unix_name;
1790
1791             TRACE( "starting %s as Unix binary\n", debugstr_w(name) );
1792
1793             if ((unix_name = wine_get_unix_file_name( name )))
1794             {
1795                 retv = (fork_and_exec( unix_name, tidy_cmdline, envW, unixdir, flags ) != -1);
1796                 HeapFree( GetProcessHeap(), 0, unix_name );
1797             }
1798         }
1799         break;
1800     }
1801     CloseHandle( hFile );
1802
1803  done:
1804     if (tidy_cmdline != cmd_line) HeapFree( GetProcessHeap(), 0, tidy_cmdline );
1805     if (envW != env) HeapFree( GetProcessHeap(), 0, envW );
1806     HeapFree( GetProcessHeap(), 0, unixdir );
1807     return retv;
1808 }
1809
1810
1811 /***********************************************************************
1812  *           wait_input_idle
1813  *
1814  * Wrapper to call WaitForInputIdle USER function
1815  */
1816 typedef DWORD (WINAPI *WaitForInputIdle_ptr)( HANDLE hProcess, DWORD dwTimeOut );
1817
1818 static DWORD wait_input_idle( HANDLE process, DWORD timeout )
1819 {
1820     HMODULE mod = GetModuleHandleA( "user32.dll" );
1821     if (mod)
1822     {
1823         WaitForInputIdle_ptr ptr = (WaitForInputIdle_ptr)GetProcAddress( mod, "WaitForInputIdle" );
1824         if (ptr) return ptr( process, timeout );
1825     }
1826     return 0;
1827 }
1828
1829
1830 /***********************************************************************
1831  *           WinExec   (KERNEL32.@)
1832  */
1833 UINT WINAPI WinExec( LPCSTR lpCmdLine, UINT nCmdShow )
1834 {
1835     PROCESS_INFORMATION info;
1836     STARTUPINFOA startup;
1837     char *cmdline;
1838     UINT ret;
1839
1840     memset( &startup, 0, sizeof(startup) );
1841     startup.cb = sizeof(startup);
1842     startup.dwFlags = STARTF_USESHOWWINDOW;
1843     startup.wShowWindow = nCmdShow;
1844
1845     /* cmdline needs to be writeable for CreateProcess */
1846     if (!(cmdline = HeapAlloc( GetProcessHeap(), 0, strlen(lpCmdLine)+1 ))) return 0;
1847     strcpy( cmdline, lpCmdLine );
1848
1849     if (CreateProcessA( NULL, cmdline, NULL, NULL, FALSE,
1850                         0, NULL, NULL, &startup, &info ))
1851     {
1852         /* Give 30 seconds to the app to come up */
1853         if (wait_input_idle( info.hProcess, 30000 ) == WAIT_FAILED)
1854             WARN("WaitForInputIdle failed: Error %ld\n", GetLastError() );
1855         ret = 33;
1856         /* Close off the handles */
1857         CloseHandle( info.hThread );
1858         CloseHandle( info.hProcess );
1859     }
1860     else if ((ret = GetLastError()) >= 32)
1861     {
1862         FIXME("Strange error set by CreateProcess: %d\n", ret );
1863         ret = 11;
1864     }
1865     HeapFree( GetProcessHeap(), 0, cmdline );
1866     return ret;
1867 }
1868
1869
1870 /**********************************************************************
1871  *          LoadModule    (KERNEL32.@)
1872  */
1873 HINSTANCE WINAPI LoadModule( LPCSTR name, LPVOID paramBlock )
1874 {
1875     LOADPARMS32 *params = paramBlock;
1876     PROCESS_INFORMATION info;
1877     STARTUPINFOA startup;
1878     HINSTANCE hInstance;
1879     LPSTR cmdline, p;
1880     char filename[MAX_PATH];
1881     BYTE len;
1882
1883     if (!name) return (HINSTANCE)ERROR_FILE_NOT_FOUND;
1884
1885     if (!SearchPathA( NULL, name, ".exe", sizeof(filename), filename, NULL ) &&
1886         !SearchPathA( NULL, name, NULL, sizeof(filename), filename, NULL ))
1887         return (HINSTANCE)GetLastError();
1888
1889     len = (BYTE)params->lpCmdLine[0];
1890     if (!(cmdline = HeapAlloc( GetProcessHeap(), 0, strlen(filename) + len + 2 )))
1891         return (HINSTANCE)ERROR_NOT_ENOUGH_MEMORY;
1892
1893     strcpy( cmdline, filename );
1894     p = cmdline + strlen(cmdline);
1895     *p++ = ' ';
1896     memcpy( p, params->lpCmdLine + 1, len );
1897     p[len] = 0;
1898
1899     memset( &startup, 0, sizeof(startup) );
1900     startup.cb = sizeof(startup);
1901     if (params->lpCmdShow)
1902     {
1903         startup.dwFlags = STARTF_USESHOWWINDOW;
1904         startup.wShowWindow = ((WORD *)params->lpCmdShow)[1];
1905     }
1906
1907     if (CreateProcessA( filename, cmdline, NULL, NULL, FALSE, 0,
1908                         params->lpEnvAddress, NULL, &startup, &info ))
1909     {
1910         /* Give 30 seconds to the app to come up */
1911         if (wait_input_idle( info.hProcess, 30000 ) == WAIT_FAILED)
1912             WARN("WaitForInputIdle failed: Error %ld\n", GetLastError() );
1913         hInstance = (HINSTANCE)33;
1914         /* Close off the handles */
1915         CloseHandle( info.hThread );
1916         CloseHandle( info.hProcess );
1917     }
1918     else if ((hInstance = (HINSTANCE)GetLastError()) >= (HINSTANCE)32)
1919     {
1920         FIXME("Strange error set by CreateProcess: %p\n", hInstance );
1921         hInstance = (HINSTANCE)11;
1922     }
1923
1924     HeapFree( GetProcessHeap(), 0, cmdline );
1925     return hInstance;
1926 }
1927
1928
1929 /******************************************************************************
1930  *           TerminateProcess   (KERNEL32.@)
1931  *
1932  * Terminates a process.
1933  *
1934  * PARAMS
1935  *  handle    [I] Process to terminate.
1936  *  exit_code [I] Exit code.
1937  *
1938  * RETURNS
1939  *  Success: TRUE.
1940  *  Failure: FALSE, check GetLastError().
1941  */
1942 BOOL WINAPI TerminateProcess( HANDLE handle, DWORD exit_code )
1943 {
1944     NTSTATUS status = NtTerminateProcess( handle, exit_code );
1945     if (status) SetLastError( RtlNtStatusToDosError(status) );
1946     return !status;
1947 }
1948
1949
1950 /***********************************************************************
1951  *           ExitProcess   (KERNEL32.@)
1952  *
1953  * Exits the current process.
1954  *
1955  * PARAMS
1956  *  status [I] Status code to exit with.
1957  *
1958  * RETURNS
1959  *  Nothing.
1960  */
1961 void WINAPI ExitProcess( DWORD status )
1962 {
1963     LdrShutdownProcess();
1964     NtTerminateProcess(GetCurrentProcess(), status);
1965     exit(status);
1966 }
1967
1968
1969 /***********************************************************************
1970  * GetExitCodeProcess           [KERNEL32.@]
1971  *
1972  * Gets termination status of specified process.
1973  *
1974  * PARAMS
1975  *   hProcess   [in]  Handle to the process.
1976  *   lpExitCode [out] Address to receive termination status.
1977  *
1978  * RETURNS
1979  *   Success: TRUE
1980  *   Failure: FALSE
1981  */
1982 BOOL WINAPI GetExitCodeProcess( HANDLE hProcess, LPDWORD lpExitCode )
1983 {
1984     NTSTATUS status;
1985     PROCESS_BASIC_INFORMATION pbi;
1986
1987     status = NtQueryInformationProcess(hProcess, ProcessBasicInformation, &pbi,
1988                                        sizeof(pbi), NULL);
1989     if (status == STATUS_SUCCESS)
1990     {
1991         if (lpExitCode) *lpExitCode = pbi.ExitStatus;
1992         return TRUE;
1993     }
1994     SetLastError( RtlNtStatusToDosError(status) );
1995     return FALSE;
1996 }
1997
1998
1999 /***********************************************************************
2000  *           SetErrorMode   (KERNEL32.@)
2001  */
2002 UINT WINAPI SetErrorMode( UINT mode )
2003 {
2004     UINT old = process_error_mode;
2005     process_error_mode = mode;
2006     return old;
2007 }
2008
2009
2010 /**********************************************************************
2011  * TlsAlloc             [KERNEL32.@]
2012  *
2013  * Allocates a thread local storage index.
2014  *
2015  * RETURNS
2016  *    Success: TLS index.
2017  *    Failure: 0xFFFFFFFF
2018  */
2019 DWORD WINAPI TlsAlloc( void )
2020 {
2021     DWORD index;
2022     PEB * const peb = NtCurrentTeb()->Peb;
2023
2024     RtlAcquirePebLock();
2025     index = RtlFindClearBitsAndSet( peb->TlsBitmap, 1, 0 );
2026     if (index != ~0U) NtCurrentTeb()->TlsSlots[index] = 0; /* clear the value */
2027     else
2028     {
2029         index = RtlFindClearBitsAndSet( peb->TlsExpansionBitmap, 1, 0 );
2030         if (index != ~0U)
2031         {
2032             if (!NtCurrentTeb()->TlsExpansionSlots &&
2033                 !(NtCurrentTeb()->TlsExpansionSlots = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
2034                                          8 * sizeof(peb->TlsExpansionBitmapBits) * sizeof(void*) )))
2035             {
2036                 RtlClearBits( peb->TlsExpansionBitmap, index, 1 );
2037                 index = ~0U;
2038                 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
2039             }
2040             else
2041             {
2042                 NtCurrentTeb()->TlsExpansionSlots[index] = 0; /* clear the value */
2043                 index += TLS_MINIMUM_AVAILABLE;
2044             }
2045         }
2046         else SetLastError( ERROR_NO_MORE_ITEMS );
2047     }
2048     RtlReleasePebLock();
2049     return index;
2050 }
2051
2052
2053 /**********************************************************************
2054  * TlsFree              [KERNEL32.@]
2055  *
2056  * Releases a thread local storage index, making it available for reuse.
2057  *
2058  * PARAMS
2059  *    index [in] TLS index to free.
2060  *
2061  * RETURNS
2062  *    Success: TRUE
2063  *    Failure: FALSE
2064  */
2065 BOOL WINAPI TlsFree( DWORD index )
2066 {
2067     BOOL ret;
2068
2069     RtlAcquirePebLock();
2070     if (index >= TLS_MINIMUM_AVAILABLE)
2071     {
2072         ret = RtlAreBitsSet( NtCurrentTeb()->Peb->TlsExpansionBitmap, index - TLS_MINIMUM_AVAILABLE, 1 );
2073         if (ret) RtlClearBits( NtCurrentTeb()->Peb->TlsExpansionBitmap, index - TLS_MINIMUM_AVAILABLE, 1 );
2074     }
2075     else
2076     {
2077         ret = RtlAreBitsSet( NtCurrentTeb()->Peb->TlsBitmap, index, 1 );
2078         if (ret) RtlClearBits( NtCurrentTeb()->Peb->TlsBitmap, index, 1 );
2079     }
2080     if (ret) NtSetInformationThread( GetCurrentThread(), ThreadZeroTlsCell, &index, sizeof(index) );
2081     else SetLastError( ERROR_INVALID_PARAMETER );
2082     RtlReleasePebLock();
2083     return TRUE;
2084 }
2085
2086
2087 /**********************************************************************
2088  * TlsGetValue          [KERNEL32.@]
2089  *
2090  * Gets value in a thread's TLS slot.
2091  *
2092  * PARAMS
2093  *    index [in] TLS index to retrieve value for.
2094  *
2095  * RETURNS
2096  *    Success: Value stored in calling thread's TLS slot for index.
2097  *    Failure: 0 and GetLastError() returns NO_ERROR.
2098  */
2099 LPVOID WINAPI TlsGetValue( DWORD index )
2100 {
2101     LPVOID ret;
2102
2103     if (index < TLS_MINIMUM_AVAILABLE)
2104     {
2105         ret = NtCurrentTeb()->TlsSlots[index];
2106     }
2107     else
2108     {
2109         index -= TLS_MINIMUM_AVAILABLE;
2110         if (index >= 8 * sizeof(NtCurrentTeb()->Peb->TlsExpansionBitmapBits))
2111         {
2112             SetLastError( ERROR_INVALID_PARAMETER );
2113             return NULL;
2114         }
2115         if (!NtCurrentTeb()->TlsExpansionSlots) ret = NULL;
2116         else ret = NtCurrentTeb()->TlsExpansionSlots[index];
2117     }
2118     SetLastError( ERROR_SUCCESS );
2119     return ret;
2120 }
2121
2122
2123 /**********************************************************************
2124  * TlsSetValue          [KERNEL32.@]
2125  *
2126  * Stores a value in the thread's TLS slot.
2127  *
2128  * PARAMS
2129  *    index [in] TLS index to set value for.
2130  *    value [in] Value to be stored.
2131  *
2132  * RETURNS
2133  *    Success: TRUE
2134  *    Failure: FALSE
2135  */
2136 BOOL WINAPI TlsSetValue( DWORD index, LPVOID value )
2137 {
2138     if (index < TLS_MINIMUM_AVAILABLE)
2139     {
2140         NtCurrentTeb()->TlsSlots[index] = value;
2141     }
2142     else
2143     {
2144         index -= TLS_MINIMUM_AVAILABLE;
2145         if (index >= 8 * sizeof(NtCurrentTeb()->Peb->TlsExpansionBitmapBits))
2146         {
2147             SetLastError( ERROR_INVALID_PARAMETER );
2148             return FALSE;
2149         }
2150         if (!NtCurrentTeb()->TlsExpansionSlots &&
2151             !(NtCurrentTeb()->TlsExpansionSlots = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
2152                          8 * sizeof(NtCurrentTeb()->Peb->TlsExpansionBitmapBits) * sizeof(void*) )))
2153         {
2154             SetLastError( ERROR_NOT_ENOUGH_MEMORY );
2155             return FALSE;
2156         }
2157         NtCurrentTeb()->TlsExpansionSlots[index] = value;
2158     }
2159     return TRUE;
2160 }
2161
2162
2163 /***********************************************************************
2164  *           GetProcessFlags    (KERNEL32.@)
2165  */
2166 DWORD WINAPI GetProcessFlags( DWORD processid )
2167 {
2168     IMAGE_NT_HEADERS *nt;
2169     DWORD flags = 0;
2170
2171     if (processid && processid != GetCurrentProcessId()) return 0;
2172
2173     if ((nt = RtlImageNtHeader( NtCurrentTeb()->Peb->ImageBaseAddress )))
2174     {
2175         if (nt->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI)
2176             flags |= PDB32_CONSOLE_PROC;
2177     }
2178     if (!AreFileApisANSI()) flags |= PDB32_FILE_APIS_OEM;
2179     if (IsDebuggerPresent()) flags |= PDB32_DEBUGGED;
2180     return flags;
2181 }
2182
2183
2184 /***********************************************************************
2185  *           GetProcessDword    (KERNEL.485)
2186  *           GetProcessDword    (KERNEL32.18)
2187  * 'Of course you cannot directly access Windows internal structures'
2188  */
2189 DWORD WINAPI GetProcessDword( DWORD dwProcessID, INT offset )
2190 {
2191     DWORD               x, y;
2192     STARTUPINFOW        siw;
2193
2194     TRACE("(%ld, %d)\n", dwProcessID, offset );
2195
2196     if (dwProcessID && dwProcessID != GetCurrentProcessId())
2197     {
2198         ERR("%d: process %lx not accessible\n", offset, dwProcessID);
2199         return 0;
2200     }
2201
2202     switch ( offset )
2203     {
2204     case GPD_APP_COMPAT_FLAGS:
2205         return GetAppCompatFlags16(0);
2206     case GPD_LOAD_DONE_EVENT:
2207         return 0;
2208     case GPD_HINSTANCE16:
2209         return GetTaskDS16();
2210     case GPD_WINDOWS_VERSION:
2211         return GetExeVersion16();
2212     case GPD_THDB:
2213         return (DWORD)NtCurrentTeb() - 0x10 /* FIXME */;
2214     case GPD_PDB:
2215         return (DWORD)NtCurrentTeb()->Peb;
2216     case GPD_STARTF_SHELLDATA: /* return stdoutput handle from startupinfo ??? */
2217         GetStartupInfoW(&siw);
2218         return (DWORD)siw.hStdOutput;
2219     case GPD_STARTF_HOTKEY: /* return stdinput handle from startupinfo ??? */
2220         GetStartupInfoW(&siw);
2221         return (DWORD)siw.hStdInput;
2222     case GPD_STARTF_SHOWWINDOW:
2223         GetStartupInfoW(&siw);
2224         return siw.wShowWindow;
2225     case GPD_STARTF_SIZE:
2226         GetStartupInfoW(&siw);
2227         x = siw.dwXSize;
2228         if ( (INT)x == CW_USEDEFAULT ) x = CW_USEDEFAULT16;
2229         y = siw.dwYSize;
2230         if ( (INT)y == CW_USEDEFAULT ) y = CW_USEDEFAULT16;
2231         return MAKELONG( x, y );
2232     case GPD_STARTF_POSITION:
2233         GetStartupInfoW(&siw);
2234         x = siw.dwX;
2235         if ( (INT)x == CW_USEDEFAULT ) x = CW_USEDEFAULT16;
2236         y = siw.dwY;
2237         if ( (INT)y == CW_USEDEFAULT ) y = CW_USEDEFAULT16;
2238         return MAKELONG( x, y );
2239     case GPD_STARTF_FLAGS:
2240         GetStartupInfoW(&siw);
2241         return siw.dwFlags;
2242     case GPD_PARENT:
2243         return 0;
2244     case GPD_FLAGS:
2245         return GetProcessFlags(0);
2246     case GPD_USERDATA:
2247         return process_dword;
2248     default:
2249         ERR("Unknown offset %d\n", offset );
2250         return 0;
2251     }
2252 }
2253
2254 /***********************************************************************
2255  *           SetProcessDword    (KERNEL.484)
2256  * 'Of course you cannot directly access Windows internal structures'
2257  */
2258 void WINAPI SetProcessDword( DWORD dwProcessID, INT offset, DWORD value )
2259 {
2260     TRACE("(%ld, %d)\n", dwProcessID, offset );
2261
2262     if (dwProcessID && dwProcessID != GetCurrentProcessId())
2263     {
2264         ERR("%d: process %lx not accessible\n", offset, dwProcessID);
2265         return;
2266     }
2267
2268     switch ( offset )
2269     {
2270     case GPD_APP_COMPAT_FLAGS:
2271     case GPD_LOAD_DONE_EVENT:
2272     case GPD_HINSTANCE16:
2273     case GPD_WINDOWS_VERSION:
2274     case GPD_THDB:
2275     case GPD_PDB:
2276     case GPD_STARTF_SHELLDATA:
2277     case GPD_STARTF_HOTKEY:
2278     case GPD_STARTF_SHOWWINDOW:
2279     case GPD_STARTF_SIZE:
2280     case GPD_STARTF_POSITION:
2281     case GPD_STARTF_FLAGS:
2282     case GPD_PARENT:
2283     case GPD_FLAGS:
2284         ERR("Not allowed to modify offset %d\n", offset );
2285         break;
2286     case GPD_USERDATA:
2287         process_dword = value;
2288         break;
2289     default:
2290         ERR("Unknown offset %d\n", offset );
2291         break;
2292     }
2293 }
2294
2295
2296 /***********************************************************************
2297  *           ExitProcess   (KERNEL.466)
2298  */
2299 void WINAPI ExitProcess16( WORD status )
2300 {
2301     DWORD count;
2302     ReleaseThunkLock( &count );
2303     ExitProcess( status );
2304 }
2305
2306
2307 /*********************************************************************
2308  *           OpenProcess   (KERNEL32.@)
2309  *
2310  * Opens a handle to a process.
2311  *
2312  * PARAMS
2313  *  access  [I] Desired access rights assigned to the returned handle.
2314  *  inherit [I] Determines whether or not child processes will inherit the handle.
2315  *  id      [I] Process identifier of the process to get a handle to.
2316  *
2317  * RETURNS
2318  *  Success: Valid handle to the specified process.
2319  *  Failure: NULL, check GetLastError().
2320  */
2321 HANDLE WINAPI OpenProcess( DWORD access, BOOL inherit, DWORD id )
2322 {
2323     NTSTATUS            status;
2324     HANDLE              handle;
2325     OBJECT_ATTRIBUTES   attr;
2326     CLIENT_ID           cid;
2327
2328     cid.UniqueProcess = (HANDLE)id;
2329     cid.UniqueThread = 0; /* FIXME ? */
2330
2331     attr.Length = sizeof(OBJECT_ATTRIBUTES);
2332     attr.RootDirectory = NULL;
2333     attr.Attributes = inherit ? OBJ_INHERIT : 0;
2334     attr.SecurityDescriptor = NULL;
2335     attr.SecurityQualityOfService = NULL;
2336     attr.ObjectName = NULL;
2337
2338     if (GetVersion() & 0x80000000) access = PROCESS_ALL_ACCESS;
2339
2340     status = NtOpenProcess(&handle, access, &attr, &cid);
2341     if (status != STATUS_SUCCESS)
2342     {
2343         SetLastError( RtlNtStatusToDosError(status) );
2344         return NULL;
2345     }
2346     return handle;
2347 }
2348
2349
2350 /*********************************************************************
2351  *           MapProcessHandle   (KERNEL.483)
2352  *           GetProcessId       (KERNEL32.@)
2353  *
2354  * Gets the a unique identifier of a process.
2355  *
2356  * PARAMS
2357  *  hProcess [I] Handle to the process.
2358  *
2359  * RETURNS
2360  *  Success: TRUE.
2361  *  Failure: FALSE, check GetLastError().
2362  *
2363  * NOTES
2364  *
2365  * The identifier is unique only on the machine and only until the process
2366  * exits (including system shutdown).
2367  */
2368 DWORD WINAPI GetProcessId( HANDLE hProcess )
2369 {
2370     NTSTATUS status;
2371     PROCESS_BASIC_INFORMATION pbi;
2372
2373     status = NtQueryInformationProcess(hProcess, ProcessBasicInformation, &pbi,
2374                                        sizeof(pbi), NULL);
2375     if (status == STATUS_SUCCESS) return pbi.UniqueProcessId;
2376     SetLastError( RtlNtStatusToDosError(status) );
2377     return 0;
2378 }
2379
2380
2381 /*********************************************************************
2382  *           CloseW32Handle (KERNEL.474)
2383  *           CloseHandle    (KERNEL32.@)
2384  *
2385  * Closes a handle.
2386  *
2387  * PARAMS
2388  *  handle [I] Handle to close.
2389  *
2390  * RETURNS
2391  *  Success: TRUE.
2392  *  Failure: FALSE, check GetLastError().
2393  */
2394 BOOL WINAPI CloseHandle( HANDLE handle )
2395 {
2396     NTSTATUS status;
2397
2398     /* stdio handles need special treatment */
2399     if ((handle == (HANDLE)STD_INPUT_HANDLE) ||
2400         (handle == (HANDLE)STD_OUTPUT_HANDLE) ||
2401         (handle == (HANDLE)STD_ERROR_HANDLE))
2402         handle = GetStdHandle( (DWORD)handle );
2403
2404     if (is_console_handle(handle))
2405         return CloseConsoleHandle(handle);
2406
2407     status = NtClose( handle );
2408     if (status) SetLastError( RtlNtStatusToDosError(status) );
2409     return !status;
2410 }
2411
2412
2413 /*********************************************************************
2414  *           GetHandleInformation   (KERNEL32.@)
2415  */
2416 BOOL WINAPI GetHandleInformation( HANDLE handle, LPDWORD flags )
2417 {
2418     OBJECT_DATA_INFORMATION info;
2419     NTSTATUS status = NtQueryObject( handle, ObjectDataInformation, &info, sizeof(info), NULL );
2420
2421     if (status) SetLastError( RtlNtStatusToDosError(status) );
2422     else if (flags)
2423     {
2424         *flags = 0;
2425         if (info.InheritHandle) *flags |= HANDLE_FLAG_INHERIT;
2426         if (info.ProtectFromClose) *flags |= HANDLE_FLAG_PROTECT_FROM_CLOSE;
2427     }
2428     return !status;
2429 }
2430
2431
2432 /*********************************************************************
2433  *           SetHandleInformation   (KERNEL32.@)
2434  */
2435 BOOL WINAPI SetHandleInformation( HANDLE handle, DWORD mask, DWORD flags )
2436 {
2437     OBJECT_DATA_INFORMATION info;
2438     NTSTATUS status;
2439
2440     /* if not setting both fields, retrieve current value first */
2441     if ((mask & (HANDLE_FLAG_INHERIT | HANDLE_FLAG_PROTECT_FROM_CLOSE)) !=
2442         (HANDLE_FLAG_INHERIT | HANDLE_FLAG_PROTECT_FROM_CLOSE))
2443     {
2444         if ((status = NtQueryObject( handle, ObjectDataInformation, &info, sizeof(info), NULL )))
2445         {
2446             SetLastError( RtlNtStatusToDosError(status) );
2447             return FALSE;
2448         }
2449     }
2450     if (mask & HANDLE_FLAG_INHERIT)
2451         info.InheritHandle = (flags & HANDLE_FLAG_INHERIT) != 0;
2452     if (mask & HANDLE_FLAG_PROTECT_FROM_CLOSE)
2453         info.ProtectFromClose = (flags & HANDLE_FLAG_PROTECT_FROM_CLOSE) != 0;
2454
2455     status = NtSetInformationObject( handle, ObjectDataInformation, &info, sizeof(info) );
2456     if (status) SetLastError( RtlNtStatusToDosError(status) );
2457     return !status;
2458 }
2459
2460
2461 /*********************************************************************
2462  *           DuplicateHandle   (KERNEL32.@)
2463  */
2464 BOOL WINAPI DuplicateHandle( HANDLE source_process, HANDLE source,
2465                              HANDLE dest_process, HANDLE *dest,
2466                              DWORD access, BOOL inherit, DWORD options )
2467 {
2468     NTSTATUS status;
2469
2470     if (is_console_handle(source))
2471     {
2472         /* FIXME: this test is not sufficient, we need to test process ids, not handles */
2473         if (source_process != dest_process ||
2474             source_process != GetCurrentProcess())
2475         {
2476             SetLastError(ERROR_INVALID_PARAMETER);
2477             return FALSE;
2478         }
2479         *dest = DuplicateConsoleHandle( source, access, inherit, options );
2480         return (*dest != INVALID_HANDLE_VALUE);
2481     }
2482     status = NtDuplicateObject( source_process, source, dest_process, dest,
2483                                 access, inherit ? OBJ_INHERIT : 0, options );
2484     if (status) SetLastError( RtlNtStatusToDosError(status) );
2485     return !status;
2486 }
2487
2488
2489 /***********************************************************************
2490  *           ConvertToGlobalHandle   (KERNEL.476)
2491  *           ConvertToGlobalHandle  (KERNEL32.@)
2492  */
2493 HANDLE WINAPI ConvertToGlobalHandle(HANDLE hSrc)
2494 {
2495     HANDLE ret = INVALID_HANDLE_VALUE;
2496     DuplicateHandle( GetCurrentProcess(), hSrc, GetCurrentProcess(), &ret, 0, FALSE,
2497                      DUP_HANDLE_MAKE_GLOBAL | DUP_HANDLE_SAME_ACCESS | DUP_HANDLE_CLOSE_SOURCE );
2498     return ret;
2499 }
2500
2501
2502 /***********************************************************************
2503  *           SetHandleContext   (KERNEL32.@)
2504  */
2505 BOOL WINAPI SetHandleContext(HANDLE hnd,DWORD context)
2506 {
2507     FIXME("(%p,%ld), stub. In case this got called by WSOCK32/WS2_32: "
2508           "the external WINSOCK DLLs won't work with WINE, don't use them.\n",hnd,context);
2509     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2510     return FALSE;
2511 }
2512
2513
2514 /***********************************************************************
2515  *           GetHandleContext   (KERNEL32.@)
2516  */
2517 DWORD WINAPI GetHandleContext(HANDLE hnd)
2518 {
2519     FIXME("(%p), stub. In case this got called by WSOCK32/WS2_32: "
2520           "the external WINSOCK DLLs won't work with WINE, don't use them.\n",hnd);
2521     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2522     return 0;
2523 }
2524
2525
2526 /***********************************************************************
2527  *           CreateSocketHandle   (KERNEL32.@)
2528  */
2529 HANDLE WINAPI CreateSocketHandle(void)
2530 {
2531     FIXME("(), stub. In case this got called by WSOCK32/WS2_32: "
2532           "the external WINSOCK DLLs won't work with WINE, don't use them.\n");
2533     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
2534     return INVALID_HANDLE_VALUE;
2535 }
2536
2537
2538 /***********************************************************************
2539  *           SetPriorityClass   (KERNEL32.@)
2540  */
2541 BOOL WINAPI SetPriorityClass( HANDLE hprocess, DWORD priorityclass )
2542 {
2543     NTSTATUS                    status;
2544     PROCESS_PRIORITY_CLASS      ppc;
2545
2546     ppc.Foreground = FALSE;
2547     switch (priorityclass)
2548     {
2549     case IDLE_PRIORITY_CLASS:
2550         ppc.PriorityClass = PROCESS_PRIOCLASS_IDLE; break;
2551     case BELOW_NORMAL_PRIORITY_CLASS:
2552         ppc.PriorityClass = PROCESS_PRIOCLASS_BELOW_NORMAL; break;
2553     case NORMAL_PRIORITY_CLASS:
2554         ppc.PriorityClass = PROCESS_PRIOCLASS_NORMAL; break;
2555     case ABOVE_NORMAL_PRIORITY_CLASS:
2556         ppc.PriorityClass = PROCESS_PRIOCLASS_ABOVE_NORMAL; break;
2557     case HIGH_PRIORITY_CLASS:
2558         ppc.PriorityClass = PROCESS_PRIOCLASS_HIGH; break;
2559     case REALTIME_PRIORITY_CLASS:
2560         ppc.PriorityClass = PROCESS_PRIOCLASS_REALTIME; break;
2561     default:
2562         SetLastError(ERROR_INVALID_PARAMETER);
2563         return FALSE;
2564     }
2565
2566     status = NtSetInformationProcess(hprocess, ProcessPriorityClass,
2567                                      &ppc, sizeof(ppc));
2568
2569     if (status != STATUS_SUCCESS)
2570     {
2571         SetLastError( RtlNtStatusToDosError(status) );
2572         return FALSE;
2573     }
2574     return TRUE;
2575 }
2576
2577
2578 /***********************************************************************
2579  *           GetPriorityClass   (KERNEL32.@)
2580  */
2581 DWORD WINAPI GetPriorityClass(HANDLE hProcess)
2582 {
2583     NTSTATUS status;
2584     PROCESS_BASIC_INFORMATION pbi;
2585
2586     status = NtQueryInformationProcess(hProcess, ProcessBasicInformation, &pbi,
2587                                        sizeof(pbi), NULL);
2588     if (status != STATUS_SUCCESS)
2589     {
2590         SetLastError( RtlNtStatusToDosError(status) );
2591         return 0;
2592     }
2593     switch (pbi.BasePriority)
2594     {
2595     case PROCESS_PRIOCLASS_IDLE: return IDLE_PRIORITY_CLASS;
2596     case PROCESS_PRIOCLASS_BELOW_NORMAL: return BELOW_NORMAL_PRIORITY_CLASS;
2597     case PROCESS_PRIOCLASS_NORMAL: return NORMAL_PRIORITY_CLASS;
2598     case PROCESS_PRIOCLASS_ABOVE_NORMAL: return ABOVE_NORMAL_PRIORITY_CLASS;
2599     case PROCESS_PRIOCLASS_HIGH: return HIGH_PRIORITY_CLASS;
2600     case PROCESS_PRIOCLASS_REALTIME: return REALTIME_PRIORITY_CLASS;
2601     }
2602     SetLastError( ERROR_INVALID_PARAMETER );
2603     return 0;
2604 }
2605
2606
2607 /***********************************************************************
2608  *          SetProcessAffinityMask   (KERNEL32.@)
2609  */
2610 BOOL WINAPI SetProcessAffinityMask( HANDLE hProcess, DWORD_PTR affmask )
2611 {
2612     NTSTATUS status;
2613
2614     status = NtSetInformationProcess(hProcess, ProcessAffinityMask,
2615                                      &affmask, sizeof(DWORD_PTR));
2616     if (!status)
2617     {
2618         SetLastError( RtlNtStatusToDosError(status) );
2619         return FALSE;
2620     }
2621     return TRUE;
2622 }
2623
2624
2625 /**********************************************************************
2626  *          GetProcessAffinityMask    (KERNEL32.@)
2627  */
2628 BOOL WINAPI GetProcessAffinityMask( HANDLE hProcess,
2629                                     PDWORD_PTR lpProcessAffinityMask,
2630                                     PDWORD_PTR lpSystemAffinityMask )
2631 {
2632     PROCESS_BASIC_INFORMATION   pbi;
2633     NTSTATUS                    status;
2634
2635     status = NtQueryInformationProcess(hProcess,
2636                                        ProcessBasicInformation,
2637                                        &pbi, sizeof(pbi), NULL);
2638     if (status)
2639     {
2640         SetLastError( RtlNtStatusToDosError(status) );
2641         return FALSE;
2642     }
2643     if (lpProcessAffinityMask) *lpProcessAffinityMask = pbi.AffinityMask;
2644     /* FIXME */
2645     if (lpSystemAffinityMask)  *lpSystemAffinityMask = 1;
2646     return TRUE;
2647 }
2648
2649
2650 /***********************************************************************
2651  *           GetProcessVersion    (KERNEL32.@)
2652  */
2653 DWORD WINAPI GetProcessVersion( DWORD processid )
2654 {
2655     IMAGE_NT_HEADERS *nt;
2656
2657     if (processid && processid != GetCurrentProcessId())
2658     {
2659         FIXME("should use ReadProcessMemory\n");
2660         return 0;
2661     }
2662     if ((nt = RtlImageNtHeader( NtCurrentTeb()->Peb->ImageBaseAddress )))
2663         return ((nt->OptionalHeader.MajorSubsystemVersion << 16) |
2664                 nt->OptionalHeader.MinorSubsystemVersion);
2665     return 0;
2666 }
2667
2668
2669 /***********************************************************************
2670  *              SetProcessWorkingSetSize        [KERNEL32.@]
2671  * Sets the min/max working set sizes for a specified process.
2672  *
2673  * PARAMS
2674  *    hProcess [I] Handle to the process of interest
2675  *    minset   [I] Specifies minimum working set size
2676  *    maxset   [I] Specifies maximum working set size
2677  *
2678  * RETURNS
2679  *  Success: TRUE
2680  *  Failure: FALSE
2681  */
2682 BOOL WINAPI SetProcessWorkingSetSize(HANDLE hProcess, SIZE_T minset,
2683                                      SIZE_T maxset)
2684 {
2685     FIXME("(%p,%ld,%ld): stub - harmless\n",hProcess,minset,maxset);
2686     if(( minset == (SIZE_T)-1) && (maxset == (SIZE_T)-1)) {
2687         /* Trim the working set to zero */
2688         /* Swap the process out of physical RAM */
2689     }
2690     return TRUE;
2691 }
2692
2693 /***********************************************************************
2694  *           GetProcessWorkingSetSize    (KERNEL32.@)
2695  */
2696 BOOL WINAPI GetProcessWorkingSetSize(HANDLE hProcess, PSIZE_T minset,
2697                                      PSIZE_T maxset)
2698 {
2699     FIXME("(%p,%p,%p): stub\n",hProcess,minset,maxset);
2700     /* 32 MB working set size */
2701     if (minset) *minset = 32*1024*1024;
2702     if (maxset) *maxset = 32*1024*1024;
2703     return TRUE;
2704 }
2705
2706
2707 /***********************************************************************
2708  *           SetProcessShutdownParameters    (KERNEL32.@)
2709  */
2710 BOOL WINAPI SetProcessShutdownParameters(DWORD level, DWORD flags)
2711 {
2712     FIXME("(%08lx, %08lx): partial stub.\n", level, flags);
2713     shutdown_flags = flags;
2714     shutdown_priority = level;
2715     return TRUE;
2716 }
2717
2718
2719 /***********************************************************************
2720  * GetProcessShutdownParameters                 (KERNEL32.@)
2721  *
2722  */
2723 BOOL WINAPI GetProcessShutdownParameters( LPDWORD lpdwLevel, LPDWORD lpdwFlags )
2724 {
2725     *lpdwLevel = shutdown_priority;
2726     *lpdwFlags = shutdown_flags;
2727     return TRUE;
2728 }
2729
2730
2731 /***********************************************************************
2732  *           GetProcessPriorityBoost    (KERNEL32.@)
2733  */
2734 BOOL WINAPI GetProcessPriorityBoost(HANDLE hprocess,PBOOL pDisablePriorityBoost)
2735 {
2736     FIXME("(%p,%p): semi-stub\n", hprocess, pDisablePriorityBoost);
2737     
2738     /* Report that no boost is present.. */
2739     *pDisablePriorityBoost = FALSE;
2740     
2741     return TRUE;
2742 }
2743
2744 /***********************************************************************
2745  *           SetProcessPriorityBoost    (KERNEL32.@)
2746  */
2747 BOOL WINAPI SetProcessPriorityBoost(HANDLE hprocess,BOOL disableboost)
2748 {
2749     FIXME("(%p,%d): stub\n",hprocess,disableboost);
2750     /* Say we can do it. I doubt the program will notice that we don't. */
2751     return TRUE;
2752 }
2753
2754
2755 /***********************************************************************
2756  *              ReadProcessMemory (KERNEL32.@)
2757  */
2758 BOOL WINAPI ReadProcessMemory( HANDLE process, LPCVOID addr, LPVOID buffer, SIZE_T size,
2759                                SIZE_T *bytes_read )
2760 {
2761     NTSTATUS status = NtReadVirtualMemory( process, addr, buffer, size, bytes_read );
2762     if (status) SetLastError( RtlNtStatusToDosError(status) );
2763     return !status;
2764 }
2765
2766
2767 /***********************************************************************
2768  *           WriteProcessMemory                 (KERNEL32.@)
2769  */
2770 BOOL WINAPI WriteProcessMemory( HANDLE process, LPVOID addr, LPCVOID buffer, SIZE_T size,
2771                                 SIZE_T *bytes_written )
2772 {
2773     NTSTATUS status = NtWriteVirtualMemory( process, addr, buffer, size, bytes_written );
2774     if (status) SetLastError( RtlNtStatusToDosError(status) );
2775     return !status;
2776 }
2777
2778
2779 /****************************************************************************
2780  *              FlushInstructionCache (KERNEL32.@)
2781  */
2782 BOOL WINAPI FlushInstructionCache(HANDLE hProcess, LPCVOID lpBaseAddress, SIZE_T dwSize)
2783 {
2784     NTSTATUS status;
2785     status = NtFlushInstructionCache( hProcess, lpBaseAddress, dwSize );
2786     if (status) SetLastError( RtlNtStatusToDosError(status) );
2787     return !status;
2788 }
2789
2790
2791 /******************************************************************
2792  *              GetProcessIoCounters (KERNEL32.@)
2793  */
2794 BOOL WINAPI GetProcessIoCounters(HANDLE hProcess, PIO_COUNTERS ioc)
2795 {
2796     NTSTATUS    status;
2797
2798     status = NtQueryInformationProcess(hProcess, ProcessIoCounters, 
2799                                        ioc, sizeof(*ioc), NULL);
2800     if (status) SetLastError( RtlNtStatusToDosError(status) );
2801     return !status;
2802 }
2803
2804 /***********************************************************************
2805  * ProcessIdToSessionId   (KERNEL32.@)
2806  * This function is available on Terminal Server 4SP4 and Windows 2000
2807  */
2808 BOOL WINAPI ProcessIdToSessionId( DWORD procid, DWORD *sessionid_ptr )
2809 {
2810     /* According to MSDN, if the calling process is not in a terminal
2811      * services environment, then the sessionid returned is zero.
2812      */
2813     *sessionid_ptr = 0;
2814     return TRUE;
2815 }
2816
2817
2818 /***********************************************************************
2819  *              RegisterServiceProcess (KERNEL.491)
2820  *              RegisterServiceProcess (KERNEL32.@)
2821  *
2822  * A service process calls this function to ensure that it continues to run
2823  * even after a user logged off.
2824  */
2825 DWORD WINAPI RegisterServiceProcess(DWORD dwProcessId, DWORD dwType)
2826 {
2827     /* I don't think that Wine needs to do anything in this function */
2828     return 1; /* success */
2829 }
2830
2831
2832 /***********************************************************************
2833  *           GetCurrentProcess   (KERNEL32.@)
2834  *
2835  * Get a handle to the current process.
2836  *
2837  * PARAMS
2838  *  None.
2839  *
2840  * RETURNS
2841  *  A handle representing the current process.
2842  */
2843 #undef GetCurrentProcess
2844 HANDLE WINAPI GetCurrentProcess(void)
2845 {
2846     return (HANDLE)0xffffffff;
2847 }
2848
2849 /***********************************************************************
2850  *           CmdBatNotification   (KERNEL32.@)
2851  *
2852  * Notifies the system that a batch file has started or finished.
2853  *
2854  * PARAMS
2855  *  bBatchRunning [I]  TRUE if a batch file has started or 
2856  *                     FALSE if a batch file has finished executing.
2857  *
2858  * RETURNS
2859  *  Unknown.
2860  */
2861 BOOL WINAPI CmdBatNotification( BOOL bBatchRunning )
2862 {
2863     FIXME("%d\n", bBatchRunning);
2864     return FALSE;
2865 }