Use the normal environment routines to build the env db of the initial
[wine] / scheduler / process.c
1 /*
2  * Win32 processes
3  *
4  * Copyright 1996, 1998 Alexandre Julliard
5  */
6
7 #include <assert.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <unistd.h>
11 #include "wine/winbase16.h"
12 #include "process.h"
13 #include "module.h"
14 #include "neexe.h"
15 #include "file.h"
16 #include "global.h"
17 #include "heap.h"
18 #include "task.h"
19 #include "ldt.h"
20 #include "syslevel.h"
21 #include "thread.h"
22 #include "winerror.h"
23 #include "pe_image.h"
24 #include "task.h"
25 #include "server.h"
26 #include "callback.h"
27 #include "debugtools.h"
28
29 DECLARE_DEBUG_CHANNEL(process)
30 DECLARE_DEBUG_CHANNEL(relay)
31 DECLARE_DEBUG_CHANNEL(win32)
32
33
34 /* The initial process PDB */
35 static PDB initial_pdb;
36
37 static PDB *PROCESS_First = &initial_pdb;
38
39 /***********************************************************************
40  *           PROCESS_Current
41  */
42 PDB *PROCESS_Current(void)
43 {
44     return THREAD_Current()->process;
45 }
46
47 /***********************************************************************
48  *           PROCESS_Initial
49  *
50  * FIXME: This works only while running all processes in the same
51  *        address space (or, at least, the initial process is mapped
52  *        into all address spaces as is KERNEL32 in Windows 95)
53  *
54  */
55 PDB *PROCESS_Initial(void)
56 {
57     return &initial_pdb;
58 }
59
60 /***********************************************************************
61  *           PROCESS_QueryInfo
62  *
63  * Retrieve information about a process
64  */
65 static BOOL PROCESS_QueryInfo( HANDLE handle,
66                                  struct get_process_info_reply *reply )
67 {
68     struct get_process_info_request req;
69     req.handle = handle;
70     CLIENT_SendRequest( REQ_GET_PROCESS_INFO, -1, 1, &req, sizeof(req) );
71     return !CLIENT_WaitSimpleReply( reply, sizeof(*reply), NULL );
72 }
73
74 /***********************************************************************
75  *           PROCESS_IsCurrent
76  *
77  * Check if a handle is to the current process
78  */
79 BOOL PROCESS_IsCurrent( HANDLE handle )
80 {
81     struct get_process_info_reply reply;
82     return (PROCESS_QueryInfo( handle, &reply ) &&
83             (reply.pid == PROCESS_Current()->server_pid));
84 }
85
86
87 /***********************************************************************
88  *           PROCESS_IdToPDB
89  *
90  * Convert a process id to a PDB, making sure it is valid.
91  */
92 PDB *PROCESS_IdToPDB( DWORD id )
93 {
94     PDB *pdb;
95
96     if (!id) return PROCESS_Current();
97     pdb = PROCESS_First;
98     while (pdb)
99     {
100         if ((DWORD)pdb->server_pid == id) return pdb;
101         pdb = pdb->next;
102     }
103     SetLastError( ERROR_INVALID_PARAMETER );
104     return NULL;
105 }
106
107
108 /***********************************************************************
109  *           PROCESS_CallUserSignalProc
110  *
111  * FIXME:  Some of the signals aren't sent correctly!
112  *
113  * The exact meaning of the USER signals is undocumented, but this 
114  * should cover the basic idea:
115  *
116  * USIG_DLL_UNLOAD_WIN16
117  *     This is sent when a 16-bit module is unloaded.
118  *
119  * USIG_DLL_UNLOAD_WIN32
120  *     This is sent when a 32-bit module is unloaded.
121  *
122  * USIG_DLL_UNLOAD_ORPHANS
123  *     This is sent after the last Win3.1 module is unloaded,
124  *     to allow removal of orphaned menus.
125  *
126  * USIG_FAULT_DIALOG_PUSH
127  * USIG_FAULT_DIALOG_POP
128  *     These are called to allow USER to prepare for displaying a
129  *     fault dialog, even though the fault might have happened while
130  *     inside a USER critical section.
131  *
132  * USIG_THREAD_INIT
133  *     This is called from the context of a new thread, as soon as it
134  *     has started to run.
135  *
136  * USIG_THREAD_EXIT
137  *     This is called, still in its context, just before a thread is
138  *     about to terminate.
139  *
140  * USIG_PROCESS_CREATE
141  *     This is called, in the parent process context, after a new process
142  *     has been created.
143  *
144  * USIG_PROCESS_INIT
145  *     This is called in the new process context, just after the main thread
146  *     has started execution (after the main thread's USIG_THREAD_INIT has
147  *     been sent).
148  *
149  * USIG_PROCESS_LOADED
150  *     This is called after the executable file has been loaded into the
151  *     new process context.
152  *
153  * USIG_PROCESS_RUNNING
154  *     This is called immediately before the main entry point is called.
155  *
156  * USIG_PROCESS_EXIT
157  *     This is called in the context of a process that is about to
158  *     terminate (but before the last thread's USIG_THREAD_EXIT has
159  *     been sent).
160  *
161  * USIG_PROCESS_DESTROY
162  *     This is called after a process has terminated.
163  *
164  *
165  * The meaning of the dwFlags bits is as follows:
166  *
167  * USIG_FLAGS_WIN32
168  *     Current process is 32-bit.
169  *
170  * USIG_FLAGS_GUI
171  *     Current process is a (Win32) GUI process.
172  *
173  * USIG_FLAGS_FEEDBACK 
174  *     Current process needs 'feedback' (determined from the STARTUPINFO
175  *     flags STARTF_FORCEONFEEDBACK / STARTF_FORCEOFFFEEDBACK).
176  *
177  * USIG_FLAGS_FAULT
178  *     The signal is being sent due to a fault.
179  */
180 static void PROCESS_CallUserSignalProcHelper( UINT uCode, DWORD dwThreadOrProcessId,
181                                               HMODULE hModule, DWORD flags, DWORD startup_flags )
182 {
183     DWORD dwFlags = 0;
184
185     /* Determine dwFlags */
186
187     if ( !(flags & PDB32_WIN16_PROC) ) dwFlags |= USIG_FLAGS_WIN32;
188
189     if ( !(flags & PDB32_CONSOLE_PROC) ) dwFlags |= USIG_FLAGS_GUI;
190
191     if ( dwFlags & USIG_FLAGS_GUI )
192     {
193         /* Feedback defaults to ON */
194         if ( !(startup_flags & STARTF_FORCEOFFFEEDBACK) )
195             dwFlags |= USIG_FLAGS_FEEDBACK;
196     }
197     else
198     {
199         /* Feedback defaults to OFF */
200         if (startup_flags & STARTF_FORCEONFEEDBACK)
201             dwFlags |= USIG_FLAGS_FEEDBACK;
202     }
203
204     /* Convert module handle to 16-bit */
205
206     if ( HIWORD( hModule ) )
207         hModule = MapHModuleLS( hModule );
208
209     /* Call USER signal proc */
210
211     if ( Callout.UserSignalProc )
212         Callout.UserSignalProc( uCode, dwThreadOrProcessId, dwFlags, hModule );
213 }
214
215 /* Call USER signal proc for the current thread/process */
216 void PROCESS_CallUserSignalProc( UINT uCode, HMODULE hModule )
217 {
218     DWORD dwThreadOrProcessId;
219
220     /* Get thread or process ID */
221     if ( uCode == USIG_THREAD_INIT || uCode == USIG_THREAD_EXIT )
222         dwThreadOrProcessId = GetCurrentThreadId();
223     else
224         dwThreadOrProcessId = GetCurrentProcessId();
225
226     PROCESS_CallUserSignalProcHelper( uCode, dwThreadOrProcessId, hModule,
227                                       PROCESS_Current()->flags,
228                                       PROCESS_Current()->env_db->startup_info->dwFlags );
229 }
230
231
232 /***********************************************************************
233  *           PROCESS_CreateEnvDB
234  *
235  * Create the env DB for a newly started process.
236  */
237 static BOOL PROCESS_CreateEnvDB(void)
238 {
239     struct init_process_request req;
240     struct init_process_reply reply;
241     STARTUPINFOA *startup;
242     ENVDB *env_db;
243     char cmd_line[4096];
244     int len;
245     PDB *pdb = PROCESS_Current();
246
247     /* Retrieve startup info from the server */
248
249     req.dummy = 0;
250     CLIENT_SendRequest( REQ_INIT_PROCESS, -1, 1, &req, sizeof(req) );
251     if (CLIENT_WaitReply( &len, NULL, 2, &reply, sizeof(reply), cmd_line, sizeof(cmd_line) ))
252         return FALSE;
253
254     /* Allocate the env DB */
255
256     if (!(env_db = HeapAlloc( pdb->heap, HEAP_ZERO_MEMORY, sizeof(ENVDB) )))
257         return FALSE;
258     pdb->env_db = env_db;
259     InitializeCriticalSection( &env_db->section );
260
261     /* Allocate and fill the startup info */
262     if (!(startup = HeapAlloc( pdb->heap, HEAP_ZERO_MEMORY, sizeof(STARTUPINFOA) )))
263         return FALSE;
264     env_db->startup_info = startup;
265     startup->dwFlags     = reply.start_flags;
266     startup->wShowWindow = reply.cmd_show;
267     env_db->hStdin  = startup->hStdInput  = reply.hstdin;
268     env_db->hStdout = startup->hStdOutput = reply.hstdout;
269     env_db->hStderr = startup->hStdError  = reply.hstderr;
270
271     /* Copy the parent environment */
272
273     if (!ENV_InheritEnvironment( pdb, reply.env_ptr )) return FALSE;
274
275     /* Copy the command line */
276
277     if (!(pdb->env_db->cmd_line = HEAP_strdupA( pdb->heap, 0, cmd_line )))
278         return FALSE;
279
280     return TRUE;
281 }
282
283
284 /***********************************************************************
285  *           PROCESS_FreePDB
286  *
287  * Free a PDB and all associated storage.
288  */
289 void PROCESS_FreePDB( PDB *pdb )
290 {
291     PDB **pptr = &PROCESS_First;
292
293     ENV_FreeEnvironment( pdb );
294     while (*pptr && (*pptr != pdb)) pptr = &(*pptr)->next;
295     if (*pptr) *pptr = pdb->next;
296     if (pdb->heap && (pdb->heap != pdb->system_heap)) HeapDestroy( pdb->heap );
297     HeapFree( SystemHeap, 0, pdb );
298 }
299
300
301 /***********************************************************************
302  *           PROCESS_CreatePDB
303  *
304  * Allocate and fill a PDB structure.
305  * Runs in the context of the parent process.
306  */
307 static PDB *PROCESS_CreatePDB( PDB *parent, BOOL inherit )
308 {
309     PDB *pdb = HeapAlloc( SystemHeap, HEAP_ZERO_MEMORY, sizeof(PDB) );
310
311     if (!pdb) return NULL;
312     pdb->exit_code       = 0x103; /* STILL_ACTIVE */
313     pdb->threads         = 1;
314     pdb->running_threads = 1;
315     pdb->ring0_threads   = 1;
316     pdb->system_heap     = SystemHeap;
317     pdb->parent          = parent;
318     pdb->group           = pdb;
319     pdb->priority        = 8;  /* Normal */
320     pdb->heap            = pdb->system_heap;  /* will be changed later on */
321     pdb->next            = PROCESS_First;
322     PROCESS_First = pdb;
323     return pdb;
324 }
325
326
327 /***********************************************************************
328  *           PROCESS_Init
329  */
330 BOOL PROCESS_Init(void)
331 {
332     THDB *thdb;
333     int server_fd;
334
335     /* Start the server */
336     server_fd = CLIENT_InitServer();
337
338     /* Fill the initial process structure */
339     initial_pdb.exit_code       = 0x103; /* STILL_ACTIVE */
340     initial_pdb.threads         = 1;
341     initial_pdb.running_threads = 1;
342     initial_pdb.ring0_threads   = 1;
343     initial_pdb.group           = &initial_pdb;
344     initial_pdb.priority        = 8;  /* Normal */
345     initial_pdb.flags           = PDB32_WIN16_PROC;
346
347     /* Initialize virtual memory management */
348     if (!VIRTUAL_Init()) return FALSE;
349
350     /* Create the initial thread structure and socket pair */
351     if (!(thdb = THREAD_CreateInitialThread( &initial_pdb, server_fd ))) return FALSE;
352
353     /* Remember TEB selector of initial process for emergency use */
354     SYSLEVEL_EmergencyTeb = thdb->teb_sel;
355
356     /* Create the system heap */
357     if (!(SystemHeap = HeapCreate( HEAP_GROWABLE, 0x10000, 0 ))) return FALSE;
358     initial_pdb.system_heap = initial_pdb.heap = SystemHeap;
359
360     /* Create the environment DB of the first process */
361     if (!PROCESS_CreateEnvDB()) return FALSE;
362
363     /* Create the SEGPTR heap */
364     if (!(SegptrHeap = HeapCreate( HEAP_WINE_SEGPTR, 0, 0 ))) return FALSE;
365
366     /* Initialize the first process critical section */
367     InitializeCriticalSection( &initial_pdb.crit_section );
368
369     return TRUE;
370 }
371
372
373 /***********************************************************************
374  *           PROCESS_Start
375  *
376  * Startup routine of a new process. Called in the context of the new process.
377  */
378 void PROCESS_Start(void)
379 {
380     UINT cmdShow = 0;
381     LPTHREAD_START_ROUTINE entry = NULL;
382     THDB *thdb = THREAD_Current();
383     PDB *pdb = thdb->process;
384     NE_MODULE *pModule = NE_GetPtr( pdb->module );
385     OFSTRUCT *ofs = (OFSTRUCT *)((char*)(pModule) + (pModule)->fileinfo);
386     IMAGE_OPTIONAL_HEADER *header = !pModule->module32? NULL :
387                                     &PE_HEADER(pModule->module32)->OptionalHeader;
388
389     /* Get process type */
390     enum { PROC_DOS, PROC_WIN16, PROC_WIN32 } type;
391     if ( pdb->flags & PDB32_DOS_PROC )
392         type = PROC_DOS;
393     else if ( pdb->flags & PDB32_WIN16_PROC )
394         type = PROC_WIN16;
395     else
396         type = PROC_WIN32;
397
398     /* Map system DLLs into this process (from initial process) */
399     /* FIXME: this is a hack */
400     pdb->modref_list = PROCESS_Initial()->modref_list;
401
402     /* Initialize the critical section */
403     InitializeCriticalSection( &pdb->crit_section );
404
405     /* Create the heap */
406     if (!(pdb->heap = HeapCreate( HEAP_GROWABLE, 
407                                   header? header->SizeOfHeapReserve : 0x10000,
408                                   header? header->SizeOfHeapCommit  : 0 ))) 
409         goto error;
410     pdb->heap_list = pdb->heap;
411
412     /* Create the environment db */
413     if (!PROCESS_CreateEnvDB()) goto error;
414
415     /* Create a task for this process */
416     if (pdb->env_db->startup_info->dwFlags & STARTF_USESHOWWINDOW)
417         cmdShow = pdb->env_db->startup_info->wShowWindow;
418     if (!TASK_Create( thdb, pModule, pdb->hInstance, pdb->hPrevInstance, cmdShow ))
419         goto error;
420
421     /* Note: The USIG_PROCESS_CREATE signal is supposed to be sent in the
422      *       context of the parent process.  Actually, the USER signal proc
423      *       doesn't really care about that, but it *does* require that the
424      *       startup parameters are correctly set up, so that GetProcessDword
425      *       works.  Furthermore, before calling the USER signal proc the 
426      *       16-bit stack must be set up, which it is only after TASK_Create
427      *       in the case of a 16-bit process. Thus, we send the signal here.
428      */
429     PROCESS_CallUserSignalProc( USIG_PROCESS_CREATE, 0 );
430
431     PROCESS_CallUserSignalProc( USIG_THREAD_INIT, 0 );  /* for initial thread */
432
433     PROCESS_CallUserSignalProc( USIG_PROCESS_INIT, 0 );
434
435     /* Signal the parent process to continue */
436     SetEvent( pdb->load_done_evt );
437     CloseHandle( pdb->load_done_evt );
438     pdb->load_done_evt = INVALID_HANDLE_VALUE;
439
440     /* Perform Win32 specific process initialization */
441     if ( type == PROC_WIN32 )
442     {
443         /* Send the debug event to the debugger */
444         entry = (LPTHREAD_START_ROUTINE)RVA_PTR(pModule->module32,
445                                                 OptionalHeader.AddressOfEntryPoint);
446         if (pdb->flags & PDB32_DEBUGGED)
447             DEBUG_SendCreateProcessEvent( -1 /*FIXME*/, pModule->module32, entry );
448
449         /* Create 32-bit MODREF */
450         if (!PE_CreateModule( pModule->module32, ofs, 0, FALSE )) goto error;
451
452         /* Increment EXE refcount */
453         assert( pdb->exe_modref );
454         pdb->exe_modref->refCount++;
455
456         /* Initialize thread-local storage */
457         PE_InitTls();
458     }
459
460     PROCESS_CallUserSignalProc( USIG_PROCESS_LOADED, 0 );   /* FIXME: correct location? */
461
462     if ( (pdb->flags & PDB32_CONSOLE_PROC) || (pdb->flags & PDB32_DOS_PROC) )
463         AllocConsole();
464
465     if ( type == PROC_WIN32 )
466     {
467         EnterCriticalSection( &pdb->crit_section );
468         MODULE_DllProcessAttach( pdb->exe_modref, (LPVOID)1 );
469         LeaveCriticalSection( &pdb->crit_section );
470     }
471
472     /* Now call the entry point */
473     PROCESS_CallUserSignalProc( USIG_PROCESS_RUNNING, 0 );
474
475     switch ( type )
476     {
477     case PROC_DOS:
478         TRACE_(relay)( "Starting DOS process\n" );
479         DOSVM_Enter( NULL );
480         ERR_(relay)( "DOSVM_Enter returned; should not happen!\n" );
481         ExitProcess( 0 );
482
483     case PROC_WIN16:
484         TRACE_(relay)( "Starting Win16 process\n" );
485         TASK_CallToStart();
486         ERR_(relay)( "TASK_CallToStart returned; should not happen!\n" );
487         ExitProcess( 0 );
488
489     case PROC_WIN32:
490         TRACE_(relay)( "Starting Win32 process (entryproc=%p)\n", entry );
491         ExitProcess( entry(NULL) );
492     }
493
494  error:
495     ExitProcess( GetLastError() );
496 }
497
498
499 /***********************************************************************
500  *           PROCESS_Create
501  *
502  * Create a new process database and associated info.
503  */
504 PDB *PROCESS_Create( NE_MODULE *pModule, LPCSTR cmd_line, LPCSTR env,
505                      HINSTANCE16 hInstance, HINSTANCE16 hPrevInstance,
506                      LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES tsa,
507                      BOOL inherit, DWORD flags, STARTUPINFOA *startup,
508                      PROCESS_INFORMATION *info )
509 {
510     HANDLE handles[2], load_done_evt = INVALID_HANDLE_VALUE;
511     DWORD exitcode, size;
512     int server_thandle;
513     struct new_process_request req;
514     struct new_process_reply reply;
515     THDB *thdb = NULL;
516     PDB *parent = PROCESS_Current();
517     PDB *pdb = PROCESS_CreatePDB( parent, inherit );
518
519     if (!pdb) return NULL;
520     info->hThread = info->hProcess = INVALID_HANDLE_VALUE;
521
522     /* Create the process on the server side */
523
524     req.inherit      = (psa && (psa->nLength >= sizeof(*psa)) && psa->bInheritHandle);
525     req.inherit_all  = inherit;
526     req.create_flags = flags;
527     req.start_flags  = startup->dwFlags;
528     if (startup->dwFlags & STARTF_USESTDHANDLES)
529     {
530         req.hstdin  = startup->hStdInput;
531         req.hstdout = startup->hStdOutput;
532         req.hstderr = startup->hStdError;
533     }
534     else
535     {
536         req.hstdin  = GetStdHandle( STD_INPUT_HANDLE );
537         req.hstdout = GetStdHandle( STD_OUTPUT_HANDLE );
538         req.hstderr = GetStdHandle( STD_ERROR_HANDLE );
539     }
540     req.cmd_show = startup->wShowWindow;
541     req.env_ptr = (void*)env;  /* FIXME: hack */
542     CLIENT_SendRequest( REQ_NEW_PROCESS, -1, 2,
543                         &req, sizeof(req), cmd_line, strlen(cmd_line) + 1 );
544     if (CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL )) goto error;
545     pdb->server_pid   = reply.pid;
546     info->hProcess    = reply.handle;
547     info->dwProcessId = (DWORD)pdb->server_pid;
548
549     if ((flags & DEBUG_PROCESS) ||
550         ((parent->flags & PDB32_DEBUGGED) && !(flags & DEBUG_ONLY_THIS_PROCESS)))
551         pdb->flags |= PDB32_DEBUGGED;
552
553     if (pModule->module32)   /* Win32 process */
554     {
555         IMAGE_OPTIONAL_HEADER *header = &PE_HEADER(pModule->module32)->OptionalHeader;
556         size = header->SizeOfStackReserve;
557         if (header->Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI) 
558             pdb->flags |= PDB32_CONSOLE_PROC;
559     }
560     else if (!pModule->dos_image) /* Win16 process */
561     {
562         size = 0;
563         pdb->flags |= PDB32_WIN16_PROC;
564     }
565     else  /* DOS process */
566     {
567         size = 0;
568         pdb->flags |= PDB32_DOS_PROC;
569     }
570
571     /* Create the main thread */
572
573     if (!(thdb = THREAD_Create( pdb, 0L, size, hInstance == 0, tsa, &server_thandle ))) 
574         goto error;
575     info->hThread     = server_thandle;
576     info->dwThreadId  = (DWORD)thdb->teb.tid;
577     thdb->startup     = PROCESS_Start;
578
579     /* Create the load-done event */
580     load_done_evt = CreateEventA( NULL, TRUE, FALSE, NULL );
581     DuplicateHandle( GetCurrentProcess(), load_done_evt,
582                      info->hProcess, &pdb->load_done_evt, 0, TRUE, DUPLICATE_SAME_ACCESS );
583
584     /* Pass module/instance to new process (FIXME: hack) */
585     pdb->module = pModule->self;
586     pdb->hInstance = hInstance;
587     pdb->hPrevInstance = hPrevInstance;
588     SYSDEPS_SpawnThread( thdb );
589
590     /* Wait until process is initialized (or initialization failed) */
591     handles[0] = info->hProcess;
592     handles[1] = load_done_evt;
593
594     switch ( WaitForMultipleObjects( 2, handles, FALSE, INFINITE ) )
595     {
596     default: 
597         ERR_(process)( "WaitForMultipleObjects failed\n" );
598         break;
599
600     case 0:
601         /* Child initialization code returns error condition as exitcode */
602         if ( GetExitCodeProcess( info->hProcess, &exitcode ) )
603             SetLastError( exitcode );
604         goto error;
605
606     case 1:
607         /* Get 16-bit task up and running */
608         if ( pdb->flags & PDB32_WIN16_PROC )
609         {
610             /* Post event to start the task */
611             PostEvent16( pdb->task );
612
613             /* If we ourselves are a 16-bit task, we Yield() directly. */
614             if ( parent->flags & PDB32_WIN16_PROC )
615                 OldYield16();
616         }
617         break;
618     } 
619
620     CloseHandle( load_done_evt );
621     load_done_evt = INVALID_HANDLE_VALUE;
622
623     return pdb;
624
625 error:
626     if (load_done_evt != INVALID_HANDLE_VALUE) CloseHandle( load_done_evt );
627     if (info->hThread != INVALID_HANDLE_VALUE) CloseHandle( info->hThread );
628     if (info->hProcess != INVALID_HANDLE_VALUE) CloseHandle( info->hProcess );
629     PROCESS_FreePDB( pdb );
630     return NULL;
631 }
632
633
634 /***********************************************************************
635  *           ExitProcess   (KERNEL32.100)
636  */
637 void WINAPI ExitProcess( DWORD status )
638 {
639     EnterCriticalSection( &PROCESS_Current()->crit_section );
640     MODULE_DllProcessDetach( TRUE, (LPVOID)1 );
641     LeaveCriticalSection( &PROCESS_Current()->crit_section );
642
643     TASK_KillTask( 0 );
644     TerminateProcess( GetCurrentProcess(), status );
645 }
646
647 /***********************************************************************
648  *           ExitProcess16   (KERNEL.466)
649  */
650 void WINAPI ExitProcess16( WORD status )
651 {
652     SYSLEVEL_ReleaseWin16Lock();
653     ExitProcess( status );
654 }
655
656 /******************************************************************************
657  *           TerminateProcess   (KERNEL32.684)
658  */
659 BOOL WINAPI TerminateProcess( HANDLE handle, DWORD exit_code )
660 {
661     struct terminate_process_request req;
662     req.handle    = handle;
663     req.exit_code = exit_code;
664     CLIENT_SendRequest( REQ_TERMINATE_PROCESS, -1, 1, &req, sizeof(req) );
665     return !CLIENT_WaitReply( NULL, NULL, 0 );
666 }
667
668
669 /***********************************************************************
670  *           GetProcessDword    (KERNEL32.18) (KERNEL.485)
671  * 'Of course you cannot directly access Windows internal structures'
672  */
673 DWORD WINAPI GetProcessDword( DWORD dwProcessID, INT offset )
674 {
675     PDB *process = PROCESS_IdToPDB( dwProcessID );
676     TDB *pTask;
677     DWORD x, y;
678
679     TRACE_(win32)("(%ld, %d)\n", dwProcessID, offset );
680     if ( !process ) return 0;
681
682     switch ( offset ) 
683     {
684     case GPD_APP_COMPAT_FLAGS:
685         pTask = (TDB *)GlobalLock16( process->task );
686         return pTask? pTask->compat_flags : 0;
687
688     case GPD_LOAD_DONE_EVENT:
689         return process->load_done_evt;
690
691     case GPD_HINSTANCE16:
692         pTask = (TDB *)GlobalLock16( process->task );
693         return pTask? pTask->hInstance : 0;
694
695     case GPD_WINDOWS_VERSION:
696         pTask = (TDB *)GlobalLock16( process->task );
697         return pTask? pTask->version : 0;
698
699     case GPD_THDB:
700         if ( process != PROCESS_Current() ) return 0;
701         return (DWORD)THREAD_Current();
702
703     case GPD_PDB:
704         return (DWORD)process;
705
706     case GPD_STARTF_SHELLDATA: /* return stdoutput handle from startupinfo ??? */
707         return process->env_db->startup_info->hStdOutput;
708
709     case GPD_STARTF_HOTKEY: /* return stdinput handle from startupinfo ??? */
710         return process->env_db->startup_info->hStdInput;
711
712     case GPD_STARTF_SHOWWINDOW:
713         return process->env_db->startup_info->wShowWindow;
714
715     case GPD_STARTF_SIZE:
716         x = process->env_db->startup_info->dwXSize;
717         if ( x == CW_USEDEFAULT ) x = CW_USEDEFAULT16;
718         y = process->env_db->startup_info->dwYSize;
719         if ( y == CW_USEDEFAULT ) y = CW_USEDEFAULT16;
720         return MAKELONG( x, y );
721
722     case GPD_STARTF_POSITION:
723         x = process->env_db->startup_info->dwX;
724         if ( x == CW_USEDEFAULT ) x = CW_USEDEFAULT16;
725         y = process->env_db->startup_info->dwY;
726         if ( y == CW_USEDEFAULT ) y = CW_USEDEFAULT16;
727         return MAKELONG( x, y );
728
729     case GPD_STARTF_FLAGS:
730         return process->env_db->startup_info->dwFlags;
731
732     case GPD_PARENT:
733         return (DWORD)process->parent->server_pid;
734
735     case GPD_FLAGS:
736         return process->flags;
737
738     case GPD_USERDATA:
739         return process->process_dword;
740
741     default:
742         ERR_(win32)("Unknown offset %d\n", offset );
743         return 0;
744     }
745 }
746
747 /***********************************************************************
748  *           SetProcessDword    (KERNEL.484)
749  * 'Of course you cannot directly access Windows internal structures'
750  */
751 void WINAPI SetProcessDword( DWORD dwProcessID, INT offset, DWORD value )
752 {
753     PDB *process = PROCESS_IdToPDB( dwProcessID );
754
755     TRACE_(win32)("(%ld, %d)\n", dwProcessID, offset );
756     if ( !process ) return;
757
758     switch ( offset ) 
759     {
760     case GPD_APP_COMPAT_FLAGS:
761     case GPD_LOAD_DONE_EVENT:
762     case GPD_HINSTANCE16:
763     case GPD_WINDOWS_VERSION:
764     case GPD_THDB:
765     case GPD_PDB:
766     case GPD_STARTF_SHELLDATA:
767     case GPD_STARTF_HOTKEY:
768     case GPD_STARTF_SHOWWINDOW:
769     case GPD_STARTF_SIZE:
770     case GPD_STARTF_POSITION:
771     case GPD_STARTF_FLAGS:
772     case GPD_PARENT:
773     case GPD_FLAGS:
774         ERR_(win32)("Not allowed to modify offset %d\n", offset );
775         break;
776
777     case GPD_USERDATA:
778         process->process_dword = value; 
779         break;
780
781     default:
782         ERR_(win32)("Unknown offset %d\n", offset );
783         break;
784     }
785 }
786
787
788 /***********************************************************************
789  *           GetCurrentProcess   (KERNEL32.198)
790  */
791 HANDLE WINAPI GetCurrentProcess(void)
792 {
793     return CURRENT_PROCESS_PSEUDOHANDLE;
794 }
795
796
797 /*********************************************************************
798  *           OpenProcess   (KERNEL32.543)
799  */
800 HANDLE WINAPI OpenProcess( DWORD access, BOOL inherit, DWORD id )
801 {
802     struct open_process_request req;
803     struct open_process_reply reply;
804
805     req.pid     = (void *)id;
806     req.access  = access;
807     req.inherit = inherit;
808     CLIENT_SendRequest( REQ_OPEN_PROCESS, -1, 1, &req, sizeof(req) );
809     if (CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL )) return 0;
810     return reply.handle;
811 }                             
812
813 /*********************************************************************
814  *           MapProcessHandle   (KERNEL.483)
815  */
816 DWORD WINAPI MapProcessHandle( HANDLE handle )
817 {
818     struct get_process_info_reply reply;
819     if ( !PROCESS_QueryInfo( handle, &reply ) ) return 0;
820     return (DWORD)reply.pid;
821 }
822
823 /***********************************************************************
824  *           GetCurrentProcessId   (KERNEL32.199)
825  */
826 DWORD WINAPI GetCurrentProcessId(void)
827 {
828     return (DWORD)PROCESS_Current()->server_pid;
829 }
830
831
832 /***********************************************************************
833  *           GetProcessHeap    (KERNEL32.259)
834  */
835 HANDLE WINAPI GetProcessHeap(void)
836 {
837     PDB *pdb = PROCESS_Current();
838     return pdb->heap ? pdb->heap : SystemHeap;
839 }
840
841
842 /***********************************************************************
843  *           GetThreadLocale    (KERNEL32.295)
844  */
845 LCID WINAPI GetThreadLocale(void)
846 {
847     return PROCESS_Current()->locale;
848 }
849
850
851 /***********************************************************************
852  *           SetPriorityClass   (KERNEL32.503)
853  */
854 BOOL WINAPI SetPriorityClass( HANDLE hprocess, DWORD priorityclass )
855 {
856     struct set_process_info_request req;
857     req.handle   = hprocess;
858     req.priority = priorityclass;
859     req.mask     = SET_PROCESS_INFO_PRIORITY;
860     CLIENT_SendRequest( REQ_SET_PROCESS_INFO, -1, 1, &req, sizeof(req) );
861     return !CLIENT_WaitReply( NULL, NULL, 0 );
862 }
863
864
865 /***********************************************************************
866  *           GetPriorityClass   (KERNEL32.250)
867  */
868 DWORD WINAPI GetPriorityClass(HANDLE hprocess)
869 {
870     struct get_process_info_reply reply;
871     if (!PROCESS_QueryInfo( hprocess, &reply )) return 0;
872     return reply.priority;
873 }
874
875
876 /***********************************************************************
877  *          SetProcessAffinityMask   (KERNEL32.662)
878  */
879 BOOL WINAPI SetProcessAffinityMask( HANDLE hProcess, DWORD affmask )
880 {
881     struct set_process_info_request req;
882     req.handle   = hProcess;
883     req.affinity = affmask;
884     req.mask     = SET_PROCESS_INFO_AFFINITY;
885     CLIENT_SendRequest( REQ_SET_PROCESS_INFO, -1, 1, &req, sizeof(req) );
886     return !CLIENT_WaitReply( NULL, NULL, 0 );
887 }
888
889 /**********************************************************************
890  *          GetProcessAffinityMask    (KERNEL32.373)
891  */
892 BOOL WINAPI GetProcessAffinityMask( HANDLE hProcess,
893                                       LPDWORD lpProcessAffinityMask,
894                                       LPDWORD lpSystemAffinityMask )
895 {
896     struct get_process_info_reply reply;
897     if (!PROCESS_QueryInfo( hProcess, &reply )) return FALSE;
898     if (lpProcessAffinityMask) *lpProcessAffinityMask = reply.process_affinity;
899     if (lpSystemAffinityMask) *lpSystemAffinityMask = reply.system_affinity;
900     return TRUE;
901 }
902
903
904 /***********************************************************************
905  *           GetStdHandle    (KERNEL32.276)
906  */
907 HANDLE WINAPI GetStdHandle( DWORD std_handle )
908 {
909     PDB *pdb = PROCESS_Current();
910
911     switch(std_handle)
912     {
913     case STD_INPUT_HANDLE:  return pdb->env_db->hStdin;
914     case STD_OUTPUT_HANDLE: return pdb->env_db->hStdout;
915     case STD_ERROR_HANDLE:  return pdb->env_db->hStderr;
916     }
917     SetLastError( ERROR_INVALID_PARAMETER );
918     return INVALID_HANDLE_VALUE;
919 }
920
921
922 /***********************************************************************
923  *           SetStdHandle    (KERNEL32.506)
924  */
925 BOOL WINAPI SetStdHandle( DWORD std_handle, HANDLE handle )
926 {
927     PDB *pdb = PROCESS_Current();
928     /* FIXME: should we close the previous handle? */
929     switch(std_handle)
930     {
931     case STD_INPUT_HANDLE:
932         pdb->env_db->hStdin = handle;
933         return TRUE;
934     case STD_OUTPUT_HANDLE:
935         pdb->env_db->hStdout = handle;
936         return TRUE;
937     case STD_ERROR_HANDLE:
938         pdb->env_db->hStderr = handle;
939         return TRUE;
940     }
941     SetLastError( ERROR_INVALID_PARAMETER );
942     return FALSE;
943 }
944
945 /***********************************************************************
946  *           GetProcessVersion    (KERNEL32)
947  */
948 DWORD WINAPI GetProcessVersion( DWORD processid )
949 {
950     TDB *pTask;
951     PDB *pdb = PROCESS_IdToPDB( processid );
952
953     if (!pdb) return 0;
954     if (!(pTask = (TDB *)GlobalLock16( pdb->task ))) return 0;
955     return (pTask->version&0xff) | (((pTask->version >>8) & 0xff)<<16);
956 }
957
958 /***********************************************************************
959  *           GetProcessFlags    (KERNEL32)
960  */
961 DWORD WINAPI GetProcessFlags( DWORD processid )
962 {
963     PDB *pdb = PROCESS_IdToPDB( processid );
964     if (!pdb) return 0;
965     return pdb->flags;
966 }
967
968 /***********************************************************************
969  *              SetProcessWorkingSetSize        [KERNEL32.662]
970  * Sets the min/max working set sizes for a specified process.
971  *
972  * PARAMS
973  *    hProcess [I] Handle to the process of interest
974  *    minset   [I] Specifies minimum working set size
975  *    maxset   [I] Specifies maximum working set size
976  *
977  * RETURNS  STD
978  */
979 BOOL WINAPI SetProcessWorkingSetSize(HANDLE hProcess,DWORD minset,
980                                        DWORD maxset)
981 {
982     FIXME_(process)("(0x%08x,%ld,%ld): stub - harmless\n",hProcess,minset,maxset);
983     if(( minset == -1) && (maxset == -1)) {
984         /* Trim the working set to zero */
985         /* Swap the process out of physical RAM */
986     }
987     return TRUE;
988 }
989
990 /***********************************************************************
991  *           GetProcessWorkingSetSize    (KERNEL32)
992  */
993 BOOL WINAPI GetProcessWorkingSetSize(HANDLE hProcess,LPDWORD minset,
994                                        LPDWORD maxset)
995 {
996         FIXME_(process)("(0x%08x,%p,%p): stub\n",hProcess,minset,maxset);
997         /* 32 MB working set size */
998         if (minset) *minset = 32*1024*1024;
999         if (maxset) *maxset = 32*1024*1024;
1000         return TRUE;
1001 }
1002
1003 /***********************************************************************
1004  *           SetProcessShutdownParameters    (KERNEL32)
1005  *
1006  * CHANGED - James Sutherland (JamesSutherland@gmx.de)
1007  * Now tracks changes made (but does not act on these changes)
1008  * NOTE: the definition for SHUTDOWN_NORETRY was done on guesswork.
1009  * It really shouldn't be here, but I'll move it when it's been checked!
1010  */
1011 #define SHUTDOWN_NORETRY 1
1012 static unsigned int shutdown_noretry = 0;
1013 static unsigned int shutdown_priority = 0x280L;
1014 BOOL WINAPI SetProcessShutdownParameters(DWORD level,DWORD flags)
1015 {
1016     if (flags & SHUTDOWN_NORETRY)
1017       shutdown_noretry = 1;
1018     else
1019       shutdown_noretry = 0;
1020     if (level > 0x100L && level < 0x3FFL)
1021       shutdown_priority = level;
1022     else
1023       {
1024         ERR_(process)("invalid priority level 0x%08lx\n", level);
1025         return FALSE;
1026       }
1027     return TRUE;
1028 }
1029
1030
1031 /***********************************************************************
1032  * GetProcessShutdownParameters                 (KERNEL32)
1033  *
1034  */
1035 BOOL WINAPI GetProcessShutdownParameters( LPDWORD lpdwLevel,
1036                                             LPDWORD lpdwFlags )
1037 {
1038   (*lpdwLevel) = shutdown_priority;
1039   (*lpdwFlags) = (shutdown_noretry * SHUTDOWN_NORETRY);
1040   return TRUE;
1041 }
1042 /***********************************************************************
1043  *           SetProcessPriorityBoost    (KERNEL32)
1044  */
1045 BOOL WINAPI SetProcessPriorityBoost(HANDLE hprocess,BOOL disableboost)
1046 {
1047     FIXME_(process)("(%d,%d): stub\n",hprocess,disableboost);
1048     /* Say we can do it. I doubt the program will notice that we don't. */
1049     return TRUE;
1050 }
1051
1052 /***********************************************************************
1053  *           ReadProcessMemory                  (KERNEL32)
1054  * FIXME: check this, if we ever run win32 binaries in different addressspaces
1055  *        ... and add a sizecheck
1056  */
1057 BOOL WINAPI ReadProcessMemory( HANDLE hProcess, LPCVOID lpBaseAddress,
1058                                  LPVOID lpBuffer, DWORD nSize,
1059                                  LPDWORD lpNumberOfBytesRead )
1060 {
1061         memcpy(lpBuffer,lpBaseAddress,nSize);
1062         if (lpNumberOfBytesRead) *lpNumberOfBytesRead = nSize;
1063         return TRUE;
1064 }
1065
1066 /***********************************************************************
1067  *           WriteProcessMemory                 (KERNEL32)
1068  * FIXME: check this, if we ever run win32 binaries in different addressspaces
1069  *        ... and add a sizecheck
1070  */
1071 BOOL WINAPI WriteProcessMemory(HANDLE hProcess, LPVOID lpBaseAddress,
1072                                  LPVOID lpBuffer, DWORD nSize,
1073                                  LPDWORD lpNumberOfBytesWritten )
1074 {
1075         memcpy(lpBaseAddress,lpBuffer,nSize);
1076         if (lpNumberOfBytesWritten) *lpNumberOfBytesWritten = nSize;
1077         return TRUE;
1078 }
1079
1080 /***********************************************************************
1081  *           RegisterServiceProcess             (KERNEL, KERNEL32)
1082  *
1083  * A service process calls this function to ensure that it continues to run
1084  * even after a user logged off.
1085  */
1086 DWORD WINAPI RegisterServiceProcess(DWORD dwProcessId, DWORD dwType)
1087 {
1088         /* I don't think that Wine needs to do anything in that function */
1089         return 1; /* success */
1090 }
1091
1092 /***********************************************************************
1093  * GetExitCodeProcess [KERNEL32.325]
1094  *
1095  * Gets termination status of specified process
1096  * 
1097  * RETURNS
1098  *   Success: TRUE
1099  *   Failure: FALSE
1100  */
1101 BOOL WINAPI GetExitCodeProcess(
1102     HANDLE hProcess,  /* [I] handle to the process */
1103     LPDWORD lpExitCode) /* [O] address to receive termination status */
1104 {
1105     struct get_process_info_reply reply;
1106     if (!PROCESS_QueryInfo( hProcess, &reply )) return FALSE;
1107     if (lpExitCode) *lpExitCode = reply.exit_code;
1108     return TRUE;
1109 }
1110
1111
1112 /***********************************************************************
1113  * GetProcessHeaps [KERNEL32.376]
1114  */
1115 DWORD WINAPI GetProcessHeaps(DWORD nrofheaps,HANDLE *heaps) {
1116         FIXME_(win32)("(%ld,%p), incomplete implementation.\n",nrofheaps,heaps);
1117
1118         if (nrofheaps) {
1119                 heaps[0] = GetProcessHeap();
1120                 /* ... probably SystemHeap too ? */
1121                 return 1;
1122         }
1123         /* number of available heaps */
1124         return 1;
1125 }
1126