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