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