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