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