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