Added an option to disable XVidMode support.
[wine] / scheduler / process.c
1 /*
2  * Win32 processes
3  *
4  * Copyright 1996, 1998 Alexandre Julliard
5  */
6
7 #include <assert.h>
8 #include <ctype.h>
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <stdlib.h>
12 #include <stdio.h>
13 #include <string.h>
14 #include <unistd.h>
15 #include "wine/winbase16.h"
16 #include "wine/exception.h"
17 #include "wine/library.h"
18 #include "drive.h"
19 #include "module.h"
20 #include "file.h"
21 #include "thread.h"
22 #include "winerror.h"
23 #include "wine/server.h"
24 #include "options.h"
25 #include "callback.h"
26 #include "debugtools.h"
27
28 DEFAULT_DEBUG_CHANNEL(process);
29 DECLARE_DEBUG_CHANNEL(relay);
30 DECLARE_DEBUG_CHANNEL(win32);
31
32 struct _ENVDB;
33
34 /* Win32 process database */
35 typedef struct _PDB
36 {
37     LONG             header[2];        /* 00 Kernel object header */
38     HMODULE          module;           /* 08 Main exe module (NT) */
39     void            *event;            /* 0c Pointer to an event object (unused) */
40     DWORD            exit_code;        /* 10 Process exit code */
41     DWORD            unknown2;         /* 14 Unknown */
42     HANDLE           heap;             /* 18 Default process heap */
43     HANDLE           mem_context;      /* 1c Process memory context */
44     DWORD            flags;            /* 20 Flags */
45     void            *pdb16;            /* 24 DOS PSP */
46     WORD             PSP_sel;          /* 28 Selector to DOS PSP */
47     WORD             imte;             /* 2a IMTE for the process module */
48     WORD             threads;          /* 2c Number of threads */
49     WORD             running_threads;  /* 2e Number of running threads */
50     WORD             free_lib_count;   /* 30 Recursion depth of FreeLibrary calls */
51     WORD             ring0_threads;    /* 32 Number of ring 0 threads */
52     HANDLE           system_heap;      /* 34 System heap to allocate handles */
53     HTASK            task;             /* 38 Win16 task */
54     void            *mem_map_files;    /* 3c Pointer to mem-mapped files */
55     struct _ENVDB   *env_db;           /* 40 Environment database */
56     void            *handle_table;     /* 44 Handle table */
57     struct _PDB     *parent;           /* 48 Parent process */
58     void            *modref_list;      /* 4c MODREF list */
59     void            *thread_list;      /* 50 List of threads */
60     void            *debuggee_CB;      /* 54 Debuggee context block */
61     void            *local_heap_free;  /* 58 Head of local heap free list */
62     DWORD            unknown4;         /* 5c Unknown */
63     CRITICAL_SECTION crit_section;     /* 60 Critical section */
64     DWORD            unknown5[3];      /* 78 Unknown */
65     void            *console;          /* 84 Console */
66     DWORD            tls_bits[2];      /* 88 TLS in-use bits */
67     DWORD            process_dword;    /* 90 Unknown */
68     struct _PDB     *group;            /* 94 Process group */
69     void            *exe_modref;       /* 98 MODREF for the process EXE */
70     void            *top_filter;       /* 9c Top exception filter */
71     DWORD            priority;         /* a0 Priority level */
72     HANDLE           heap_list;        /* a4 Head of process heap list */
73     void            *heap_handles;     /* a8 Head of heap handles list */
74     DWORD            unknown6;         /* ac Unknown */
75     void            *console_provider; /* b0 Console provider (??) */
76     WORD             env_selector;     /* b4 Selector to process environment */
77     WORD             error_mode;       /* b6 Error mode */
78     HANDLE           load_done_evt;    /* b8 Event for process loading done */
79     void            *UTState;          /* bc Head of Univeral Thunk list */
80     DWORD            unknown8;         /* c0 Unknown (NT) */
81     LCID             locale;           /* c4 Locale to be queried by GetThreadLocale (NT) */
82 } PDB;
83
84 PDB current_process;
85
86 /* Process flags */
87 #define PDB32_DEBUGGED      0x0001  /* Process is being debugged */
88 #define PDB32_WIN16_PROC    0x0008  /* Win16 process */
89 #define PDB32_DOS_PROC      0x0010  /* Dos process */
90 #define PDB32_CONSOLE_PROC  0x0020  /* Console process */
91 #define PDB32_FILE_APIS_OEM 0x0040  /* File APIs are OEM */
92 #define PDB32_WIN32S_PROC   0x8000  /* Win32s process */
93
94 static char **main_exe_argv;
95 static char main_exe_name[MAX_PATH];
96 static char *main_exe_name_ptr = main_exe_name;
97 static HANDLE main_exe_file;
98
99 unsigned int server_startticks;
100
101 /* memory/environ.c */
102 extern struct _ENVDB *ENV_BuildEnvironment(void);
103 extern BOOL ENV_BuildCommandLine( char **argv );
104 extern STARTUPINFOA current_startupinfo;
105
106 /* scheduler/pthread.c */
107 extern void PTHREAD_init_done(void);
108
109 extern BOOL MAIN_MainInit(void);
110
111
112 /***********************************************************************
113  *           PROCESS_CallUserSignalProc
114  *
115  * FIXME:  Some of the signals aren't sent correctly!
116  *
117  * The exact meaning of the USER signals is undocumented, but this 
118  * should cover the basic idea:
119  *
120  * USIG_DLL_UNLOAD_WIN16
121  *     This is sent when a 16-bit module is unloaded.
122  *
123  * USIG_DLL_UNLOAD_WIN32
124  *     This is sent when a 32-bit module is unloaded.
125  *
126  * USIG_DLL_UNLOAD_ORPHANS
127  *     This is sent after the last Win3.1 module is unloaded,
128  *     to allow removal of orphaned menus.
129  *
130  * USIG_FAULT_DIALOG_PUSH
131  * USIG_FAULT_DIALOG_POP
132  *     These are called to allow USER to prepare for displaying a
133  *     fault dialog, even though the fault might have happened while
134  *     inside a USER critical section.
135  *
136  * USIG_THREAD_INIT
137  *     This is called from the context of a new thread, as soon as it
138  *     has started to run.
139  *
140  * USIG_THREAD_EXIT
141  *     This is called, still in its context, just before a thread is
142  *     about to terminate.
143  *
144  * USIG_PROCESS_CREATE
145  *     This is called, in the parent process context, after a new process
146  *     has been created.
147  *
148  * USIG_PROCESS_INIT
149  *     This is called in the new process context, just after the main thread
150  *     has started execution (after the main thread's USIG_THREAD_INIT has
151  *     been sent).
152  *
153  * USIG_PROCESS_LOADED
154  *     This is called after the executable file has been loaded into the
155  *     new process context.
156  *
157  * USIG_PROCESS_RUNNING
158  *     This is called immediately before the main entry point is called.
159  *
160  * USIG_PROCESS_EXIT
161  *     This is called in the context of a process that is about to
162  *     terminate (but before the last thread's USIG_THREAD_EXIT has
163  *     been sent).
164  *
165  * USIG_PROCESS_DESTROY
166  *     This is called after a process has terminated.
167  *
168  *
169  * The meaning of the dwFlags bits is as follows:
170  *
171  * USIG_FLAGS_WIN32
172  *     Current process is 32-bit.
173  *
174  * USIG_FLAGS_GUI
175  *     Current process is a (Win32) GUI process.
176  *
177  * USIG_FLAGS_FEEDBACK 
178  *     Current process needs 'feedback' (determined from the STARTUPINFO
179  *     flags STARTF_FORCEONFEEDBACK / STARTF_FORCEOFFFEEDBACK).
180  *
181  * USIG_FLAGS_FAULT
182  *     The signal is being sent due to a fault.
183  */
184 void PROCESS_CallUserSignalProc( UINT uCode, HMODULE16 hModule )
185 {
186     DWORD flags = current_process.flags;
187     DWORD startup_flags = current_startupinfo.dwFlags;
188     DWORD dwFlags = 0;
189
190     if (!Callout.UserSignalProc) return;
191
192     /* Determine dwFlags */
193
194     if ( !(flags & PDB32_WIN16_PROC) ) dwFlags |= USIG_FLAGS_WIN32;
195
196     if ( !(flags & PDB32_CONSOLE_PROC) ) dwFlags |= USIG_FLAGS_GUI;
197
198     if ( dwFlags & USIG_FLAGS_GUI )
199     {
200         /* Feedback defaults to ON */
201         if ( !(startup_flags & STARTF_FORCEOFFFEEDBACK) )
202             dwFlags |= USIG_FLAGS_FEEDBACK;
203     }
204     else
205     {
206         /* Feedback defaults to OFF */
207         if (startup_flags & STARTF_FORCEONFEEDBACK)
208             dwFlags |= USIG_FLAGS_FEEDBACK;
209     }
210
211     /* Call USER signal proc */
212
213     if ( uCode == USIG_THREAD_INIT || uCode == USIG_THREAD_EXIT )
214         Callout.UserSignalProc( uCode, GetCurrentThreadId(), dwFlags, hModule );
215     else
216         Callout.UserSignalProc( uCode, GetCurrentProcessId(), dwFlags, hModule );
217 }
218
219
220 /***********************************************************************
221  *           set_console_handles
222  *
223  * Set the console handles to use stdin/stdout.
224  */
225 static void set_console_handles( HANDLE console )
226 {
227     wine_server_send_fd( 0 );
228     wine_server_send_fd( 1 );
229
230     SERVER_START_REQ( set_console_fd )
231     {
232         req->handle = console;
233         req->fd_in  = 0;
234         req->fd_out = 1;
235         req->pid    = 0;
236         SERVER_CALL();
237     }
238     SERVER_END_REQ;
239 }
240
241
242 /***********************************************************************
243  *           process_init
244  *
245  * Main process initialisation code
246  */
247 static BOOL process_init( char *argv[] )
248 {
249     BOOL ret;
250     int create_flags = 0;
251
252     /* store the program name */
253     argv0 = argv[0];
254     main_exe_argv = argv;
255
256     /* Fill the initial process structure */
257     current_process.exit_code       = STILL_ACTIVE;
258     current_process.threads         = 1;
259     current_process.running_threads = 1;
260     current_process.ring0_threads   = 1;
261     current_process.group           = &current_process;
262     current_process.priority        = 8;  /* Normal */
263
264     /* Setup the server connection */
265     CLIENT_InitServer();
266
267     /* Retrieve startup info from the server */
268     SERVER_START_VAR_REQ( init_process, sizeof(main_exe_name)-1 )
269     {
270         req->ldt_copy  = &wine_ldt_copy;
271         req->ppid      = getppid();
272         if ((ret = !SERVER_CALL_ERR()))
273         {
274             size_t len = server_data_size( req );
275             memcpy( main_exe_name, server_data_ptr(req), len );
276             main_exe_name[len] = 0;
277             main_exe_file = req->exe_file;
278             create_flags  = req->create_flags;
279             current_startupinfo.dwFlags     = req->start_flags;
280             server_startticks               = req->server_start;
281             current_startupinfo.wShowWindow = req->cmd_show;
282             current_startupinfo.hStdInput   = req->hstdin;
283             current_startupinfo.hStdOutput  = req->hstdout;
284             current_startupinfo.hStdError   = req->hstderr;
285         }
286     }
287     SERVER_END_VAR_REQ;
288     if (!ret) return FALSE;
289
290     SetStdHandle( STD_INPUT_HANDLE,  current_startupinfo.hStdInput );
291     SetStdHandle( STD_OUTPUT_HANDLE, current_startupinfo.hStdOutput );
292     SetStdHandle( STD_ERROR_HANDLE,  current_startupinfo.hStdError );
293     if (create_flags & CREATE_NEW_CONSOLE)
294         set_console_handles( current_startupinfo.hStdOutput );
295
296     /* Create the process heap */
297     current_process.heap = HeapCreate( HEAP_GROWABLE, 0, 0 );
298
299     /* Now we can use the pthreads routines */
300     PTHREAD_init_done();
301
302     /* Copy the parent environment */
303     if (!(current_process.env_db = ENV_BuildEnvironment())) return FALSE;
304
305     /* Parse command line arguments */
306     OPTIONS_ParseOptions( argv );
307
308     return MAIN_MainInit();
309 }
310
311
312 /***********************************************************************
313  *           start_process
314  *
315  * Startup routine of a new process. Runs on the new process stack.
316  */
317 static void start_process(void)
318 {
319     int debugged, console_app;
320     LPTHREAD_START_ROUTINE entry;
321     WINE_MODREF *wm;
322
323     /* use original argv[0] as name for the main module */
324     if (!main_exe_name[0])
325     {
326         if (!GetLongPathNameA( full_argv0, main_exe_name, sizeof(main_exe_name) ))
327             lstrcpynA( main_exe_name, full_argv0, sizeof(main_exe_name) );
328     }
329
330     /* Retrieve entry point address */
331     entry = (LPTHREAD_START_ROUTINE)((char*)current_process.module +
332                          PE_HEADER(current_process.module)->OptionalHeader.AddressOfEntryPoint);
333     console_app = (PE_HEADER(current_process.module)->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI);
334     if (console_app) current_process.flags |= PDB32_CONSOLE_PROC;
335
336     /* Signal the parent process to continue */
337     SERVER_START_REQ( init_process_done )
338     {
339         req->module   = (void *)current_process.module;
340         req->entry    = entry;
341         /* API requires a double indirection */
342         req->name     = &main_exe_name_ptr;
343         req->exe_file = main_exe_file;
344         req->gui      = !console_app;
345         SERVER_CALL();
346         debugged = req->debugged;
347     }
348     SERVER_END_REQ;
349
350     /* Install signal handlers; this cannot be done before, since we cannot
351      * send exceptions to the debugger before the create process event that
352      * is sent by REQ_INIT_PROCESS_DONE */
353     if (!SIGNAL_Init()) goto error;
354
355     /* create the main modref and load dependencies */
356     if (!(wm = PE_CreateModule( current_process.module, main_exe_name, 0, 0, FALSE )))
357         goto error;
358     wm->refCount++;
359
360     RtlAcquirePebLock();
361     PE_InitTls();
362     MODULE_DllProcessAttach( NULL, (LPVOID)1 );
363     RtlReleasePebLock();
364
365     /* Get pointers to USER routines called by KERNEL */
366     THUNK_InitCallout();
367
368     /* Note: The USIG_PROCESS_CREATE signal is supposed to be sent in the
369      *       context of the parent process.  Actually, the USER signal proc
370      *       doesn't really care about that, but it *does* require that the
371      *       startup parameters are correctly set up, so that GetProcessDword
372      *       works.  Furthermore, before calling the USER signal proc the 
373      *       16-bit stack must be set up, which it is only after TASK_Create
374      *       in the case of a 16-bit process. Thus, we send the signal here.
375      */
376     PROCESS_CallUserSignalProc( USIG_PROCESS_CREATE, 0 );
377     PROCESS_CallUserSignalProc( USIG_THREAD_INIT, 0 );
378     PROCESS_CallUserSignalProc( USIG_PROCESS_INIT, 0 );
379     PROCESS_CallUserSignalProc( USIG_PROCESS_LOADED, 0 );
380     /* Call UserSignalProc ( USIG_PROCESS_RUNNING ... ) only for non-GUI win32 apps */
381     if (console_app) PROCESS_CallUserSignalProc( USIG_PROCESS_RUNNING, 0 );
382
383     if (TRACE_ON(relay))
384         DPRINTF( "%08lx:Starting process %s (entryproc=%p)\n",
385                  GetCurrentThreadId(), main_exe_name, entry );
386     if (debugged) DbgBreakPoint();
387     /* FIXME: should use _PEB as parameter for NT 3.5 programs !
388      * Dunno about other OSs */
389     SetLastError(0);  /* clear error code */
390     ExitThread( entry(NULL) );
391
392  error:
393     ExitProcess( GetLastError() );
394 }
395
396
397 /***********************************************************************
398  *           open_winelib_app
399  *
400  * Try to open the Winelib app .so file based on argv[0] or WINEPRELOAD.
401  */
402 void *open_winelib_app( char *argv[] )
403 {
404     void *ret = NULL;
405     char *tmp;
406     const char *name;
407     char errStr[100];
408
409     if ((name = getenv( "WINEPRELOAD" )))
410     {
411         if (!(ret = wine_dll_load_main_exe( name, 0, errStr, sizeof(errStr) )))
412         {
413             MESSAGE( "%s: could not load '%s' as specified in the WINEPRELOAD environment variable: %s\n",
414                      argv[0], name, errStr );
415             ExitProcess(1);
416         }
417     }
418     else
419     {
420         const char *argv0 = main_exe_name;
421         if (!*argv0)
422         {
423             /* if argv[0] is "wine", don't try to load anything */
424             argv0 = argv[0];
425             if (!(name = strrchr( argv0, '/' ))) name = argv0;
426             else name++;
427             if (!strcmp( name, "wine" )) return NULL;
428         }
429
430         /* now try argv[0] with ".so" appended */
431         if ((tmp = HeapAlloc( GetProcessHeap(), 0, strlen(argv0) + 4 )))
432         {
433             strcpy( tmp, argv0 );
434             strcat( tmp, ".so" );
435             /* search in PATH only if there was no '/' in argv[0] */
436             ret = wine_dll_load_main_exe( tmp, (name == argv0), errStr, sizeof(errStr) );
437             if (!ret && !argv[1])
438             {
439                 /* if no argv[1], this will be better than displaying usage */
440                 MESSAGE( "%s: could not load library '%s' as Winelib application: %s\n",
441                          argv[0], tmp, errStr );
442                 ExitProcess(1);
443             }
444             HeapFree( GetProcessHeap(), 0, tmp );
445         }
446     }
447     return ret;
448 }
449
450 /***********************************************************************
451  *           PROCESS_InitWine
452  *
453  * Wine initialisation: load and start the main exe file.
454  */
455 void PROCESS_InitWine( int argc, char *argv[], LPSTR win16_exe_name, HANDLE *win16_exe_file )
456 {
457     DWORD stack_size = 0;
458
459     /* Initialize everything */
460     if (!process_init( argv )) exit(1);
461
462     if (open_winelib_app( argv )) goto found; /* try to open argv[0] as a winelib app */
463
464     main_exe_argv = ++argv;  /* remove argv[0] (wine itself) */
465
466     if (!main_exe_name[0])
467     {
468         if (!argv[0]) OPTIONS_Usage();
469
470         /* open the exe file */
471         if (!SearchPathA( NULL, argv[0], ".exe", sizeof(main_exe_name), main_exe_name, NULL ) &&
472             !SearchPathA( NULL, argv[0], NULL, sizeof(main_exe_name), main_exe_name, NULL ))
473         {
474             MESSAGE( "%s: cannot find '%s'\n", argv0, argv[0] );
475             goto error;
476         }
477     }
478
479     if (!main_exe_file)
480     {
481         if ((main_exe_file = CreateFileA( main_exe_name, GENERIC_READ, FILE_SHARE_READ,
482                                           NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
483         {
484             MESSAGE( "%s: cannot open '%s'\n", argv0, main_exe_name );
485             goto error;
486         }
487     }
488
489     /* first try Win32 format; this will fail if the file is not a PE binary */
490     if ((current_process.module = PE_LoadImage( main_exe_file, main_exe_name, 0 )))
491     {
492         if (PE_HEADER(current_process.module)->FileHeader.Characteristics & IMAGE_FILE_DLL)
493             ExitProcess( ERROR_BAD_EXE_FORMAT );
494         goto found;
495     }
496
497     /* it must be 16-bit or DOS format */
498     NtCurrentTeb()->tibflags &= ~TEBF_WIN32;
499     current_process.flags |= PDB32_WIN16_PROC;
500     strcpy( win16_exe_name, main_exe_name );
501     main_exe_name[0] = 0;
502     *win16_exe_file = main_exe_file;
503     main_exe_file = 0;
504     _EnterWin16Lock();
505
506  found:
507     /* build command line */
508     if (!ENV_BuildCommandLine( main_exe_argv )) goto error;
509
510     /* create 32-bit module for main exe */
511     if (!(current_process.module = BUILTIN32_LoadExeModule( current_process.module ))) goto error;
512     stack_size = PE_HEADER(current_process.module)->OptionalHeader.SizeOfStackReserve;
513
514     /* allocate main thread stack */
515     if (!THREAD_InitStack( NtCurrentTeb(), stack_size )) goto error;
516
517     /* switch to the new stack */
518     SYSDEPS_SwitchToThreadStack( start_process );
519
520  error:
521     ExitProcess( GetLastError() );
522 }
523
524
525 /***********************************************************************
526  *           build_argv
527  *
528  * Build an argv array from a command-line.
529  * The command-line is modified to insert nulls.
530  * 'reserved' is the number of args to reserve before the first one.
531  */
532 static char **build_argv( char *cmdline, int reserved )
533 {
534     char **argv;
535     int count = reserved + 1;
536     char *p = cmdline;
537
538     /* if first word is quoted store it as a single arg */
539     if (*cmdline == '\"')
540     {
541         if ((p = strchr( cmdline + 1, '\"' )))
542         {
543             p++;
544             count++;
545         }
546         else p = cmdline;
547     }
548     while (*p)
549     {
550         while (*p && isspace(*p)) p++;
551         if (!*p) break;
552         count++;
553         while (*p && !isspace(*p)) p++;
554     }
555
556     if ((argv = malloc( count * sizeof(*argv) )))
557     {
558         char **argvptr = argv + reserved;
559         p = cmdline;
560         if (*cmdline == '\"')
561         {
562             if ((p = strchr( cmdline + 1, '\"' )))
563             {
564                 *argvptr++ = cmdline + 1;
565                 *p++ = 0;
566             }
567             else p = cmdline;
568         }
569         while (*p)
570         {
571             while (*p && isspace(*p)) *p++ = 0;
572             if (!*p) break;
573             *argvptr++ = p;
574             while (*p && !isspace(*p)) p++;
575         }
576         *argvptr = 0;
577     }
578     return argv;
579 }
580
581
582 /***********************************************************************
583  *           build_envp
584  *
585  * Build the environment of a new child process.
586  */
587 static char **build_envp( const char *env, const char *extra_env )
588 {
589     const char *p;
590     char **envp;
591     int count = 0;
592
593     if (extra_env) for (p = extra_env; *p; count++) p += strlen(p) + 1;
594     for (p = env; *p; count++) p += strlen(p) + 1;
595     count += 3;
596
597     if ((envp = malloc( count * sizeof(*envp) )))
598     {
599         extern char **environ;
600         char **envptr = envp;
601         char **unixptr = environ;
602         /* first the extra strings */
603         if (extra_env) for (p = extra_env; *p; p += strlen(p) + 1) *envptr++ = (char *)p;
604         /* then put PATH, HOME and WINEPREFIX from the unix env */
605         for (unixptr = environ; unixptr && *unixptr; unixptr++)
606             if (!memcmp( *unixptr, "PATH=", 5 ) ||
607                 !memcmp( *unixptr, "HOME=", 5 ) ||
608                 !memcmp( *unixptr, "WINEPREFIX=", 11 )) *envptr++ = *unixptr;
609         /* now put the Windows environment strings */
610         for (p = env; *p; p += strlen(p) + 1)
611         {
612             if (memcmp( p, "PATH=", 5 ) &&
613                 memcmp( p, "HOME=", 5 ) &&
614                 memcmp( p, "WINEPRELOAD=", 12 ) &&
615                 memcmp( p, "WINEPREFIX=", 11 )) *envptr++ = (char *)p;
616         }
617         *envptr = 0;
618     }
619     return envp;
620 }
621
622
623 /***********************************************************************
624  *           exec_wine_binary
625  *
626  * Locate the Wine binary to exec for a new Win32 process.
627  */
628 static void exec_wine_binary( char **argv, char **envp )
629 {
630     const char *path, *pos, *ptr;
631
632     /* first, try for a WINELOADER environment variable */
633     argv[0] = getenv("WINELOADER");
634     if (argv[0])
635         execve( argv[0], argv, envp );
636
637     /* next, try bin directory */
638     argv[0] = BINDIR "/wine";
639     execve( argv[0], argv, envp );
640
641     /* now try the path of argv0 of the current binary */
642     if (!(argv[0] = malloc( strlen(full_argv0) + 6 ))) return;
643     if ((ptr = strrchr( full_argv0, '/' )))
644     {
645         memcpy( argv[0], full_argv0, ptr - full_argv0 );
646         strcpy( argv[0] + (ptr - full_argv0), "/wine" );
647         execve( argv[0], argv, envp );
648     }
649     free( argv[0] );
650
651     /* now search in the Unix path */
652     if ((path = getenv( "PATH" )))
653     {
654         if (!(argv[0] = malloc( strlen(path) + 6 ))) return;
655         pos = path;
656         for (;;)
657         {
658             while (*pos == ':') pos++;
659             if (!*pos) break;
660             if (!(ptr = strchr( pos, ':' ))) ptr = pos + strlen(pos);
661             memcpy( argv[0], pos, ptr - pos );
662             strcpy( argv[0] + (ptr - pos), "/wine" );
663             execve( argv[0], argv, envp );
664             pos = ptr;
665         }
666     }
667     free( argv[0] );
668
669     /* finally try the current directory */
670     argv[0] = "./wine";
671     execve( argv[0], argv, envp );
672 }
673
674
675 /***********************************************************************
676  *           fork_and_exec
677  *
678  * Fork and exec a new Unix process, checking for errors.
679  */
680 static int fork_and_exec( const char *filename, char *cmdline,
681                           const char *env, const char *newdir )
682 {
683     int fd[2];
684     int pid, err;
685     char *extra_env = NULL;
686
687     if (!env)
688     {
689         env = GetEnvironmentStringsA();
690         extra_env = DRIVE_BuildEnv();
691     }
692
693     if (pipe(fd) == -1)
694     {
695         FILE_SetDosError();
696         return -1;
697     }
698     fcntl( fd[1], F_SETFD, 1 );  /* set close on exec */
699     if (!(pid = fork()))  /* child */
700     {
701         char **argv = build_argv( cmdline, filename ? 0 : 2 );
702         char **envp = build_envp( env, extra_env );
703         close( fd[0] );
704
705         if (newdir) chdir(newdir);
706
707         if (argv && envp)
708         {
709             if (!filename)
710             {
711                 argv[1] = "--";
712                 exec_wine_binary( argv, envp );
713             }
714             else execve( filename, argv, envp );
715         }
716         err = errno;
717         write( fd[1], &err, sizeof(err) );
718         _exit(1);
719     }
720     close( fd[1] );
721     if ((pid != -1) && (read( fd[0], &err, sizeof(err) ) > 0))  /* exec failed */
722     {
723         errno = err;
724         pid = -1;
725     }
726     if (pid == -1) FILE_SetDosError();
727     close( fd[0] );
728     if (extra_env) HeapFree( GetProcessHeap(), 0, extra_env );
729     return pid;
730 }
731
732
733 /***********************************************************************
734  *           PROCESS_Create
735  *
736  * Create a new process. If hFile is a valid handle we have an exe
737  * file, and we exec a new copy of wine to load it; otherwise we
738  * simply exec the specified filename as a Unix process.
739  */
740 BOOL PROCESS_Create( HANDLE hFile, LPCSTR filename, LPSTR cmd_line, LPCSTR env,
741                      LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES tsa,
742                      BOOL inherit, DWORD flags, LPSTARTUPINFOA startup,
743                      LPPROCESS_INFORMATION info, LPCSTR lpCurrentDirectory )
744 {
745     BOOL ret;
746     int pid;
747     const char *unixfilename = NULL;
748     const char *unixdir = NULL;
749     DOS_FULL_NAME full_dir, full_name;
750     HANDLE load_done_evt = 0;
751     HANDLE process_info;
752
753     info->hThread = info->hProcess = 0;
754
755     if (lpCurrentDirectory)
756     {
757         if (DOSFS_GetFullName( lpCurrentDirectory, TRUE, &full_dir ))
758             unixdir = full_dir.long_name;
759     }
760     else
761     {
762         char buf[MAX_PATH];
763         if (GetCurrentDirectoryA(sizeof(buf),buf))
764         {
765             if (DOSFS_GetFullName( buf, TRUE, &full_dir ))
766                 unixdir = full_dir.long_name;
767         }
768     }
769
770     /* create the process on the server side */
771
772     SERVER_START_VAR_REQ( new_process, MAX_PATH )
773     {
774         req->inherit_all  = inherit;
775         req->create_flags = flags;
776         req->start_flags  = startup->dwFlags;
777         req->exe_file     = hFile;
778         if (startup->dwFlags & STARTF_USESTDHANDLES)
779         {
780             req->hstdin  = startup->hStdInput;
781             req->hstdout = startup->hStdOutput;
782             req->hstderr = startup->hStdError;
783         }
784         else
785         {
786             req->hstdin  = GetStdHandle( STD_INPUT_HANDLE );
787             req->hstdout = GetStdHandle( STD_OUTPUT_HANDLE );
788             req->hstderr = GetStdHandle( STD_ERROR_HANDLE );
789         }
790         req->cmd_show = startup->wShowWindow;
791
792         if (!hFile)  /* unix process */
793         {
794             unixfilename = filename;
795             if (DOSFS_GetFullName( filename, TRUE, &full_name ))
796                 unixfilename = full_name.long_name;
797             lstrcpynA( server_data_ptr(req), unixfilename, MAX_PATH );
798         }
799         else  /* new wine process */
800         {
801             if (!GetLongPathNameA( filename, server_data_ptr(req), MAX_PATH ))
802                 lstrcpynA( server_data_ptr(req), filename, MAX_PATH );
803         }
804         ret = !SERVER_CALL_ERR();
805         process_info = req->info;
806     }
807     SERVER_END_VAR_REQ;
808     if (!ret) return FALSE;
809
810     /* fork and execute */
811
812     pid = fork_and_exec( unixfilename, cmd_line, env, unixdir );
813
814     /* wait for the new process info to be ready */
815
816     ret = FALSE;
817     if ((pid != -1) && (WaitForSingleObject( process_info, 2000 ) == STATUS_WAIT_0))
818     {
819         SERVER_START_REQ( get_new_process_info )
820         {
821             req->info     = process_info;
822             req->pinherit = (psa && (psa->nLength >= sizeof(*psa)) && psa->bInheritHandle);
823             req->tinherit = (tsa && (tsa->nLength >= sizeof(*tsa)) && tsa->bInheritHandle);
824             if ((ret = !SERVER_CALL_ERR()))
825             {
826                 info->dwProcessId = (DWORD)req->pid;
827                 info->dwThreadId  = (DWORD)req->tid;
828                 info->hProcess    = req->phandle;
829                 info->hThread     = req->thandle;
830                 load_done_evt     = req->event;
831             }
832         }
833         SERVER_END_REQ;
834     }
835     CloseHandle( process_info );
836     if (!ret) goto error;
837
838     /* Wait until process is initialized (or initialization failed) */
839     if (load_done_evt)
840     {
841         DWORD res;
842         HANDLE handles[2];
843
844         handles[0] = info->hProcess;
845         handles[1] = load_done_evt;
846         res = WaitForMultipleObjects( 2, handles, FALSE, INFINITE );
847         CloseHandle( load_done_evt );
848         if (res == STATUS_WAIT_0)  /* the process died */
849         {
850             DWORD exitcode;
851             if (GetExitCodeProcess( info->hProcess, &exitcode )) SetLastError( exitcode );
852             CloseHandle( info->hThread );
853             CloseHandle( info->hProcess );
854             return FALSE;
855         }
856     }
857     return TRUE;
858
859 error:
860     if (load_done_evt) CloseHandle( load_done_evt );
861     if (info->hThread) CloseHandle( info->hThread );
862     if (info->hProcess) CloseHandle( info->hProcess );
863     return FALSE;
864 }
865
866
867 /***********************************************************************
868  *           ExitProcess   (KERNEL32.@)
869  */
870 void WINAPI ExitProcess( DWORD status )
871 {
872     MODULE_DllProcessDetach( TRUE, (LPVOID)1 );
873     SERVER_START_REQ( terminate_process )
874     {
875         /* send the exit code to the server */
876         req->handle    = GetCurrentProcess();
877         req->exit_code = status;
878         SERVER_CALL();
879     }
880     SERVER_END_REQ;
881     exit( status );
882 }
883
884 /***********************************************************************
885  *           ExitProcess   (KERNEL.466)
886  */
887 void WINAPI ExitProcess16( WORD status )
888 {
889     DWORD count;
890     ReleaseThunkLock( &count );
891     ExitProcess( status );
892 }
893
894 /******************************************************************************
895  *           TerminateProcess   (KERNEL32.@)
896  */
897 BOOL WINAPI TerminateProcess( HANDLE handle, DWORD exit_code )
898 {
899     NTSTATUS status = NtTerminateProcess( handle, exit_code );
900     if (status) SetLastError( RtlNtStatusToDosError(status) );
901     return !status;
902 }
903
904
905 /***********************************************************************
906  *           GetProcessDword    (KERNEL.485)
907  *           GetProcessDword    (KERNEL32.18)
908  * 'Of course you cannot directly access Windows internal structures'
909  */
910 DWORD WINAPI GetProcessDword( DWORD dwProcessID, INT offset )
911 {
912     DWORD x, y;
913
914     TRACE_(win32)("(%ld, %d)\n", dwProcessID, offset );
915
916     if (dwProcessID && dwProcessID != GetCurrentProcessId())
917     {
918         ERR("%d: process %lx not accessible\n", offset, dwProcessID);
919         return 0;
920     }
921
922     switch ( offset ) 
923     {
924     case GPD_APP_COMPAT_FLAGS:
925         return GetAppCompatFlags16(0);
926
927     case GPD_LOAD_DONE_EVENT:
928         return current_process.load_done_evt;
929
930     case GPD_HINSTANCE16:
931         return GetTaskDS16();
932
933     case GPD_WINDOWS_VERSION:
934         return GetExeVersion16();
935
936     case GPD_THDB:
937         return (DWORD)NtCurrentTeb() - 0x10 /* FIXME */;
938
939     case GPD_PDB:
940         return (DWORD)&current_process;
941
942     case GPD_STARTF_SHELLDATA: /* return stdoutput handle from startupinfo ??? */
943         return current_startupinfo.hStdOutput;
944
945     case GPD_STARTF_HOTKEY: /* return stdinput handle from startupinfo ??? */
946         return current_startupinfo.hStdInput;
947
948     case GPD_STARTF_SHOWWINDOW:
949         return current_startupinfo.wShowWindow;
950
951     case GPD_STARTF_SIZE:
952         x = current_startupinfo.dwXSize;
953         if ( (INT)x == CW_USEDEFAULT ) x = CW_USEDEFAULT16;
954         y = current_startupinfo.dwYSize;
955         if ( (INT)y == CW_USEDEFAULT ) y = CW_USEDEFAULT16;
956         return MAKELONG( x, y );
957
958     case GPD_STARTF_POSITION:
959         x = current_startupinfo.dwX;
960         if ( (INT)x == CW_USEDEFAULT ) x = CW_USEDEFAULT16;
961         y = current_startupinfo.dwY;
962         if ( (INT)y == CW_USEDEFAULT ) y = CW_USEDEFAULT16;
963         return MAKELONG( x, y );
964
965     case GPD_STARTF_FLAGS:
966         return current_startupinfo.dwFlags;
967
968     case GPD_PARENT:
969         return 0;
970
971     case GPD_FLAGS:
972         return current_process.flags;
973
974     case GPD_USERDATA:
975         return current_process.process_dword;
976
977     default:
978         ERR_(win32)("Unknown offset %d\n", offset );
979         return 0;
980     }
981 }
982
983 /***********************************************************************
984  *           SetProcessDword    (KERNEL.484)
985  * 'Of course you cannot directly access Windows internal structures'
986  */
987 void WINAPI SetProcessDword( DWORD dwProcessID, INT offset, DWORD value )
988 {
989     TRACE_(win32)("(%ld, %d)\n", dwProcessID, offset );
990
991     if (dwProcessID && dwProcessID != GetCurrentProcessId())
992     {
993         ERR("%d: process %lx not accessible\n", offset, dwProcessID);
994         return;
995     }
996
997     switch ( offset ) 
998     {
999     case GPD_APP_COMPAT_FLAGS:
1000     case GPD_LOAD_DONE_EVENT:
1001     case GPD_HINSTANCE16:
1002     case GPD_WINDOWS_VERSION:
1003     case GPD_THDB:
1004     case GPD_PDB:
1005     case GPD_STARTF_SHELLDATA:
1006     case GPD_STARTF_HOTKEY:
1007     case GPD_STARTF_SHOWWINDOW:
1008     case GPD_STARTF_SIZE:
1009     case GPD_STARTF_POSITION:
1010     case GPD_STARTF_FLAGS:
1011     case GPD_PARENT:
1012     case GPD_FLAGS:
1013         ERR_(win32)("Not allowed to modify offset %d\n", offset );
1014         break;
1015
1016     case GPD_USERDATA:
1017         current_process.process_dword = value; 
1018         break;
1019
1020     default:
1021         ERR_(win32)("Unknown offset %d\n", offset );
1022         break;
1023     }
1024 }
1025
1026
1027 /*********************************************************************
1028  *           OpenProcess   (KERNEL32.@)
1029  */
1030 HANDLE WINAPI OpenProcess( DWORD access, BOOL inherit, DWORD id )
1031 {
1032     HANDLE ret = 0;
1033     SERVER_START_REQ( open_process )
1034     {
1035         req->pid     = (void *)id;
1036         req->access  = access;
1037         req->inherit = inherit;
1038         if (!SERVER_CALL_ERR()) ret = req->handle;
1039     }
1040     SERVER_END_REQ;
1041     return ret;
1042 }
1043
1044 /*********************************************************************
1045  *           MapProcessHandle   (KERNEL.483)
1046  */
1047 DWORD WINAPI MapProcessHandle( HANDLE handle )
1048 {
1049     DWORD ret = 0;
1050     SERVER_START_REQ( get_process_info )
1051     {
1052         req->handle = handle;
1053         if (!SERVER_CALL_ERR()) ret = (DWORD)req->pid;
1054     }
1055     SERVER_END_REQ;
1056     return ret;
1057 }
1058
1059 /***********************************************************************
1060  *           SetPriorityClass   (KERNEL32.@)
1061  */
1062 BOOL WINAPI SetPriorityClass( HANDLE hprocess, DWORD priorityclass )
1063 {
1064     BOOL ret;
1065     SERVER_START_REQ( set_process_info )
1066     {
1067         req->handle   = hprocess;
1068         req->priority = priorityclass;
1069         req->mask     = SET_PROCESS_INFO_PRIORITY;
1070         ret = !SERVER_CALL_ERR();
1071     }
1072     SERVER_END_REQ;
1073     return ret;
1074 }
1075
1076
1077 /***********************************************************************
1078  *           GetPriorityClass   (KERNEL32.@)
1079  */
1080 DWORD WINAPI GetPriorityClass(HANDLE hprocess)
1081 {
1082     DWORD ret = 0;
1083     SERVER_START_REQ( get_process_info )
1084     {
1085         req->handle = hprocess;
1086         if (!SERVER_CALL_ERR()) ret = req->priority;
1087     }
1088     SERVER_END_REQ;
1089     return ret;
1090 }
1091
1092
1093 /***********************************************************************
1094  *          SetProcessAffinityMask   (KERNEL32.@)
1095  */
1096 BOOL WINAPI SetProcessAffinityMask( HANDLE hProcess, DWORD affmask )
1097 {
1098     BOOL ret;
1099     SERVER_START_REQ( set_process_info )
1100     {
1101         req->handle   = hProcess;
1102         req->affinity = affmask;
1103         req->mask     = SET_PROCESS_INFO_AFFINITY;
1104         ret = !SERVER_CALL_ERR();
1105     }
1106     SERVER_END_REQ;
1107     return ret;
1108 }
1109
1110 /**********************************************************************
1111  *          GetProcessAffinityMask    (KERNEL32.@)
1112  */
1113 BOOL WINAPI GetProcessAffinityMask( HANDLE hProcess,
1114                                       LPDWORD lpProcessAffinityMask,
1115                                       LPDWORD lpSystemAffinityMask )
1116 {
1117     BOOL ret = FALSE;
1118     SERVER_START_REQ( get_process_info )
1119     {
1120         req->handle = hProcess;
1121         if (!SERVER_CALL_ERR())
1122         {
1123             if (lpProcessAffinityMask) *lpProcessAffinityMask = req->process_affinity;
1124             if (lpSystemAffinityMask) *lpSystemAffinityMask = req->system_affinity;
1125             ret = TRUE;
1126         }
1127     }
1128     SERVER_END_REQ;
1129     return ret;
1130 }
1131
1132
1133 /***********************************************************************
1134  *           GetProcessVersion    (KERNEL32.@)
1135  */
1136 DWORD WINAPI GetProcessVersion( DWORD processid )
1137 {
1138     IMAGE_NT_HEADERS *nt;
1139
1140     if (processid && processid != GetCurrentProcessId())
1141     {
1142         FIXME("should use ReadProcessMemory\n");
1143         return 0;
1144     }
1145     if ((nt = RtlImageNtHeader( current_process.module )))
1146         return ((nt->OptionalHeader.MajorSubsystemVersion << 16) |
1147                 nt->OptionalHeader.MinorSubsystemVersion);
1148     return 0;
1149 }
1150
1151 /***********************************************************************
1152  *           GetProcessFlags    (KERNEL32.@)
1153  */
1154 DWORD WINAPI GetProcessFlags( DWORD processid )
1155 {
1156     if (processid && processid != GetCurrentProcessId()) return 0;
1157     return current_process.flags;
1158 }
1159
1160
1161 /***********************************************************************
1162  *              SetProcessWorkingSetSize        [KERNEL32.@]
1163  * Sets the min/max working set sizes for a specified process.
1164  *
1165  * PARAMS
1166  *    hProcess [I] Handle to the process of interest
1167  *    minset   [I] Specifies minimum working set size
1168  *    maxset   [I] Specifies maximum working set size
1169  *
1170  * RETURNS  STD
1171  */
1172 BOOL WINAPI SetProcessWorkingSetSize(HANDLE hProcess,DWORD minset,
1173                                        DWORD maxset)
1174 {
1175     FIXME("(0x%08x,%ld,%ld): stub - harmless\n",hProcess,minset,maxset);
1176     if(( minset == (DWORD)-1) && (maxset == (DWORD)-1)) {
1177         /* Trim the working set to zero */
1178         /* Swap the process out of physical RAM */
1179     }
1180     return TRUE;
1181 }
1182
1183 /***********************************************************************
1184  *           GetProcessWorkingSetSize    (KERNEL32.@)
1185  */
1186 BOOL WINAPI GetProcessWorkingSetSize(HANDLE hProcess,LPDWORD minset,
1187                                        LPDWORD maxset)
1188 {
1189         FIXME("(0x%08x,%p,%p): stub\n",hProcess,minset,maxset);
1190         /* 32 MB working set size */
1191         if (minset) *minset = 32*1024*1024;
1192         if (maxset) *maxset = 32*1024*1024;
1193         return TRUE;
1194 }
1195
1196 /***********************************************************************
1197  *           SetProcessShutdownParameters    (KERNEL32.@)
1198  *
1199  * CHANGED - James Sutherland (JamesSutherland@gmx.de)
1200  * Now tracks changes made (but does not act on these changes)
1201  */
1202 static DWORD shutdown_flags = 0;
1203 static DWORD shutdown_priority = 0x280;
1204
1205 BOOL WINAPI SetProcessShutdownParameters(DWORD level, DWORD flags)
1206 {
1207     FIXME("(%08lx, %08lx): partial stub.\n", level, flags);
1208     shutdown_flags = flags;
1209     shutdown_priority = level;
1210     return TRUE;
1211 }
1212
1213
1214 /***********************************************************************
1215  * GetProcessShutdownParameters                 (KERNEL32.@)
1216  *
1217  */
1218 BOOL WINAPI GetProcessShutdownParameters( LPDWORD lpdwLevel, LPDWORD lpdwFlags )
1219 {
1220     *lpdwLevel = shutdown_priority;
1221     *lpdwFlags = shutdown_flags;
1222     return TRUE;
1223 }
1224
1225
1226 /***********************************************************************
1227  *           SetProcessPriorityBoost    (KERNEL32.@)
1228  */
1229 BOOL WINAPI SetProcessPriorityBoost(HANDLE hprocess,BOOL disableboost)
1230 {
1231     FIXME("(%d,%d): stub\n",hprocess,disableboost);
1232     /* Say we can do it. I doubt the program will notice that we don't. */
1233     return TRUE;
1234 }
1235
1236
1237 /***********************************************************************
1238  *              ReadProcessMemory (KERNEL32.@)
1239  */
1240 BOOL WINAPI ReadProcessMemory( HANDLE process, LPCVOID addr, LPVOID buffer, DWORD size,
1241                                LPDWORD bytes_read )
1242 {
1243     unsigned int offset = (unsigned int)addr % sizeof(int);
1244     unsigned int pos = 0, len, max;
1245     int res;
1246
1247     if (bytes_read) *bytes_read = size;
1248
1249     /* first time, read total length to check for permissions */
1250     len = (size + offset + sizeof(int) - 1) / sizeof(int);
1251     max = min( REQUEST_MAX_VAR_SIZE, len * sizeof(int) );
1252
1253     for (;;)
1254     {
1255         SERVER_START_VAR_REQ( read_process_memory, max )
1256         {
1257             req->handle = process;
1258             req->addr   = (char *)addr + pos - offset;
1259             req->len    = len;
1260             if (!(res = SERVER_CALL_ERR()))
1261             {
1262                 size_t result = server_data_size( req );
1263                 if (result > size + offset) result = size + offset;
1264                 memcpy( (char *)buffer + pos, server_data_ptr(req) + offset, result - offset );
1265                 size -= result - offset;
1266                 pos += result - offset;
1267             }
1268         }
1269         SERVER_END_VAR_REQ;
1270         if (res)
1271         {
1272             if (bytes_read) *bytes_read = 0;
1273             return FALSE;
1274         }
1275         if (!size) return TRUE;
1276         max = min( REQUEST_MAX_VAR_SIZE, size );
1277         len = (max + sizeof(int) - 1) / sizeof(int);
1278         offset = 0;
1279     }
1280 }
1281
1282
1283 /***********************************************************************
1284  *           WriteProcessMemory                 (KERNEL32.@)
1285  */
1286 BOOL WINAPI WriteProcessMemory( HANDLE process, LPVOID addr, LPVOID buffer, DWORD size,
1287                                 LPDWORD bytes_written )
1288 {
1289     unsigned int first_offset, last_offset;
1290     unsigned int pos = 0, len, max, first_mask, last_mask;
1291     int res;
1292
1293     if (!size)
1294     {
1295         SetLastError( ERROR_INVALID_PARAMETER );
1296         return FALSE;
1297     }
1298     if (bytes_written) *bytes_written = size;
1299
1300     /* compute the mask for the first int */
1301     first_mask = ~0;
1302     first_offset = (unsigned int)addr % sizeof(int);
1303     memset( &first_mask, 0, first_offset );
1304
1305     /* compute the mask for the last int */
1306     last_offset = (size + first_offset) % sizeof(int);
1307     last_mask = 0;
1308     memset( &last_mask, 0xff, last_offset ? last_offset : sizeof(int) );
1309
1310     /* for the first request, use the total length */
1311     len = (size + first_offset + sizeof(int) - 1) / sizeof(int);
1312     max = min( REQUEST_MAX_VAR_SIZE, len * sizeof(int) );
1313
1314     for (;;)
1315     {
1316         SERVER_START_VAR_REQ( write_process_memory, max )
1317         {
1318             req->handle = process;
1319             req->addr = (char *)addr - first_offset + pos;
1320             req->len = len;
1321             req->first_mask = (!pos) ? first_mask : ~0;
1322             if (size + first_offset <= max)  /* last round */
1323             {
1324                 req->last_mask = last_mask;
1325                 max = size + first_offset;
1326             }
1327             else req->last_mask = ~0;
1328
1329             memcpy( (char *)server_data_ptr(req) + first_offset, (char *)buffer + pos,
1330                     max - first_offset );
1331             if (!(res = SERVER_CALL_ERR()))
1332             {
1333                 pos += max - first_offset;
1334                 size -= max - first_offset;
1335             }
1336         }
1337         SERVER_END_VAR_REQ;
1338         if (res)
1339         {
1340             if (bytes_written) *bytes_written = 0;
1341             return FALSE;
1342         }
1343         if (!size) return TRUE;
1344         first_offset = 0;
1345         len = min( size + sizeof(int) - 1, REQUEST_MAX_VAR_SIZE ) / sizeof(int);
1346         max = len * sizeof(int);
1347     }
1348 }
1349
1350
1351 /***********************************************************************
1352  *              RegisterServiceProcess (KERNEL.491)
1353  *              RegisterServiceProcess (KERNEL32.@)
1354  *
1355  * A service process calls this function to ensure that it continues to run
1356  * even after a user logged off.
1357  */
1358 DWORD WINAPI RegisterServiceProcess(DWORD dwProcessId, DWORD dwType)
1359 {
1360         /* I don't think that Wine needs to do anything in that function */
1361         return 1; /* success */
1362 }
1363
1364 /***********************************************************************
1365  * GetExitCodeProcess [KERNEL32.@]
1366  *
1367  * Gets termination status of specified process
1368  * 
1369  * RETURNS
1370  *   Success: TRUE
1371  *   Failure: FALSE
1372  */
1373 BOOL WINAPI GetExitCodeProcess(
1374     HANDLE hProcess,    /* [in] handle to the process */
1375     LPDWORD lpExitCode) /* [out] address to receive termination status */
1376 {
1377     BOOL ret;
1378     SERVER_START_REQ( get_process_info )
1379     {
1380         req->handle = hProcess;
1381         ret = !SERVER_CALL_ERR();
1382         if (ret && lpExitCode) *lpExitCode = req->exit_code;
1383     }
1384     SERVER_END_REQ;
1385     return ret;
1386 }
1387
1388
1389 /***********************************************************************
1390  *           SetErrorMode   (KERNEL32.@)
1391  */
1392 UINT WINAPI SetErrorMode( UINT mode )
1393 {
1394     UINT old = current_process.error_mode;
1395     current_process.error_mode = mode;
1396     return old;
1397 }
1398
1399
1400 /**************************************************************************
1401  *              SetFileApisToOEM   (KERNEL32.@)
1402  */
1403 VOID WINAPI SetFileApisToOEM(void)
1404 {
1405     current_process.flags |= PDB32_FILE_APIS_OEM;
1406 }
1407
1408
1409 /**************************************************************************
1410  *              SetFileApisToANSI   (KERNEL32.@)
1411  */
1412 VOID WINAPI SetFileApisToANSI(void)
1413 {
1414     current_process.flags &= ~PDB32_FILE_APIS_OEM;
1415 }
1416
1417
1418 /******************************************************************************
1419  * AreFileApisANSI [KERNEL32.@]  Determines if file functions are using ANSI
1420  *
1421  * RETURNS
1422  *    TRUE:  Set of file functions is using ANSI code page
1423  *    FALSE: Set of file functions is using OEM code page
1424  */
1425 BOOL WINAPI AreFileApisANSI(void)
1426 {
1427     return !(current_process.flags & PDB32_FILE_APIS_OEM);
1428 }
1429
1430
1431 /**********************************************************************
1432  * TlsAlloc [KERNEL32.@]  Allocates a TLS index.
1433  *
1434  * Allocates a thread local storage index
1435  *
1436  * RETURNS
1437  *    Success: TLS Index
1438  *    Failure: 0xFFFFFFFF
1439  */
1440 DWORD WINAPI TlsAlloc( void )
1441 {
1442     DWORD i, mask, ret = 0;
1443     DWORD *bits = current_process.tls_bits;
1444     RtlAcquirePebLock();
1445     if (*bits == 0xffffffff)
1446     {
1447         bits++;
1448         ret = 32;
1449         if (*bits == 0xffffffff)
1450         {
1451             RtlReleasePebLock();
1452             SetLastError( ERROR_NO_MORE_ITEMS );
1453             return 0xffffffff;
1454         }
1455     }
1456     for (i = 0, mask = 1; i < 32; i++, mask <<= 1) if (!(*bits & mask)) break;
1457     *bits |= mask;
1458     RtlReleasePebLock();
1459     return ret + i;
1460 }
1461
1462
1463 /**********************************************************************
1464  * TlsFree [KERNEL32.@]  Releases a TLS index.
1465  *
1466  * Releases a thread local storage index, making it available for reuse
1467  * 
1468  * RETURNS
1469  *    Success: TRUE
1470  *    Failure: FALSE
1471  */
1472 BOOL WINAPI TlsFree(
1473     DWORD index) /* [in] TLS Index to free */
1474 {
1475     DWORD mask = (1 << (index & 31));
1476     DWORD *bits = current_process.tls_bits;
1477     if (index >= 64)
1478     {
1479         SetLastError( ERROR_INVALID_PARAMETER );
1480         return FALSE;
1481     }
1482     if (index >= 32) bits++;
1483     RtlAcquirePebLock();
1484     if (!(*bits & mask))  /* already free? */
1485     {
1486         RtlReleasePebLock();
1487         SetLastError( ERROR_INVALID_PARAMETER );
1488         return FALSE;
1489     }
1490     *bits &= ~mask;
1491     NtCurrentTeb()->tls_array[index] = 0;
1492     /* FIXME: should zero all other thread values */
1493     RtlReleasePebLock();
1494     return TRUE;
1495 }
1496
1497
1498 /**********************************************************************
1499  * TlsGetValue [KERNEL32.@]  Gets value in a thread's TLS slot
1500  *
1501  * RETURNS
1502  *    Success: Value stored in calling thread's TLS slot for index
1503  *    Failure: 0 and GetLastError returns NO_ERROR
1504  */
1505 LPVOID WINAPI TlsGetValue(
1506     DWORD index) /* [in] TLS index to retrieve value for */
1507 {
1508     if (index >= 64)
1509     {
1510         SetLastError( ERROR_INVALID_PARAMETER );
1511         return NULL;
1512     }
1513     SetLastError( ERROR_SUCCESS );
1514     return NtCurrentTeb()->tls_array[index];
1515 }
1516
1517
1518 /**********************************************************************
1519  * TlsSetValue [KERNEL32.@]  Stores a value in the thread's TLS slot.
1520  *
1521  * RETURNS
1522  *    Success: TRUE
1523  *    Failure: FALSE
1524  */
1525 BOOL WINAPI TlsSetValue(
1526     DWORD index,  /* [in] TLS index to set value for */
1527     LPVOID value) /* [in] Value to be stored */
1528 {
1529     if (index >= 64)
1530     {
1531         SetLastError( ERROR_INVALID_PARAMETER );
1532         return FALSE;
1533     }
1534     NtCurrentTeb()->tls_array[index] = value;
1535     return TRUE;
1536 }
1537
1538
1539 /***********************************************************************
1540  *           GetCurrentProcess   (KERNEL32.@)
1541  */
1542 #undef GetCurrentProcess
1543 HANDLE WINAPI GetCurrentProcess(void)
1544 {
1545     return 0xffffffff;
1546 }