Added server pid and tid in init_thread request, and use them in
[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 "debug.h"
26
27
28 /* The initial process PDB */
29 static PDB initial_pdb;
30
31 static PDB *PROCESS_First = &initial_pdb;
32
33 /***********************************************************************
34  *           PROCESS_Current
35  */
36 PDB *PROCESS_Current(void)
37 {
38     return THREAD_Current()->process;
39 }
40
41 /***********************************************************************
42  *           PROCESS_Initial
43  *
44  * FIXME: This works only while running all processes in the same
45  *        address space (or, at least, the initial process is mapped
46  *        into all address spaces as is KERNEL32 in Windows 95)
47  *
48  */
49 PDB *PROCESS_Initial(void)
50 {
51     return &initial_pdb;
52 }
53
54 /***********************************************************************
55  *           PROCESS_QueryInfo
56  *
57  * Retrieve information about a process
58  */
59 static BOOL PROCESS_QueryInfo( HANDLE handle,
60                                  struct get_process_info_reply *reply )
61 {
62     struct get_process_info_request req;
63     req.handle = handle;
64     CLIENT_SendRequest( REQ_GET_PROCESS_INFO, -1, 1, &req, sizeof(req) );
65     return !CLIENT_WaitSimpleReply( reply, sizeof(*reply), NULL );
66 }
67
68 /***********************************************************************
69  *           PROCESS_IsCurrent
70  *
71  * Check if a handle is to the current process
72  */
73 BOOL PROCESS_IsCurrent( HANDLE handle )
74 {
75     struct get_process_info_reply reply;
76     return (PROCESS_QueryInfo( handle, &reply ) &&
77             (reply.pid == PROCESS_Current()->server_pid));
78 }
79
80
81 /***********************************************************************
82  *           PROCESS_IdToPDB
83  *
84  * Convert a process id to a PDB, making sure it is valid.
85  */
86 PDB *PROCESS_IdToPDB( DWORD id )
87 {
88     PDB *pdb;
89
90     if (!id) return PROCESS_Current();
91     pdb = PROCESS_First;
92     while (pdb)
93     {
94         if ((DWORD)pdb->server_pid == id) return pdb;
95         pdb = pdb->next;
96     }
97     SetLastError( ERROR_INVALID_PARAMETER );
98     return NULL;
99 }
100
101
102
103 /***********************************************************************
104  *           PROCESS_BuildEnvDB
105  *
106  * Build the env DB for the initial process
107  */
108 static BOOL PROCESS_BuildEnvDB( PDB *pdb )
109 {
110     /* Allocate the env DB (FIXME: should not be on the system heap) */
111
112     if (!(pdb->env_db = HeapAlloc(SystemHeap,HEAP_ZERO_MEMORY,sizeof(ENVDB))))
113         return FALSE;
114     InitializeCriticalSection( &pdb->env_db->section );
115
116     /* Allocate startup info */
117     if (!(pdb->env_db->startup_info = 
118           HeapAlloc( SystemHeap, HEAP_ZERO_MEMORY, sizeof(STARTUPINFOA) )))
119         return FALSE;
120
121     /* Allocate the standard handles */
122
123     pdb->env_db->hStdin  = FILE_DupUnixHandle( 0, GENERIC_READ );
124     pdb->env_db->hStdout = FILE_DupUnixHandle( 1, GENERIC_WRITE );
125     pdb->env_db->hStderr = FILE_DupUnixHandle( 2, GENERIC_WRITE );
126
127     /* Build the command-line */
128
129     pdb->env_db->cmd_line = HEAP_strdupA( SystemHeap, 0, "kernel32" );
130
131     /* Build the environment strings */
132
133     return ENV_BuildEnvironment( pdb );
134 }
135
136
137 /***********************************************************************
138  *           PROCESS_InheritEnvDB
139  */
140 static BOOL PROCESS_InheritEnvDB( PDB *pdb, LPCSTR cmd_line, LPCSTR env,
141                                     BOOL inherit_handles, STARTUPINFOA *startup )
142 {
143     if (!(pdb->env_db = HeapAlloc(pdb->heap, HEAP_ZERO_MEMORY, sizeof(ENVDB))))
144         return FALSE;
145     InitializeCriticalSection( &pdb->env_db->section );
146
147     /* Copy the parent environment */
148
149     if (!ENV_InheritEnvironment( pdb, env )) return FALSE;
150
151     /* Copy the command line */
152
153     if (!(pdb->env_db->cmd_line = HEAP_strdupA( pdb->heap, 0, cmd_line )))
154         return FALSE;
155
156     /* Remember startup info */
157     if (!(pdb->env_db->startup_info = 
158           HeapAlloc( pdb->heap, HEAP_ZERO_MEMORY, sizeof(STARTUPINFOA) )))
159         return FALSE;
160     *pdb->env_db->startup_info = *startup;
161
162     /* Inherit the standard handles */
163     if (pdb->env_db->startup_info->dwFlags & STARTF_USESTDHANDLES)
164     {
165         pdb->env_db->hStdin  = pdb->env_db->startup_info->hStdInput;
166         pdb->env_db->hStdout = pdb->env_db->startup_info->hStdOutput;
167         pdb->env_db->hStderr = pdb->env_db->startup_info->hStdError;
168     }
169     else if (inherit_handles)
170     {
171         pdb->env_db->hStdin  = pdb->parent->env_db->hStdin;
172         pdb->env_db->hStdout = pdb->parent->env_db->hStdout;
173         pdb->env_db->hStderr = pdb->parent->env_db->hStderr;
174     }
175     /* else will be done later on in PROCESS_Create */
176
177     return TRUE;
178 }
179
180
181 /***********************************************************************
182  *           PROCESS_CreateEnvDB
183  *
184  * Create the env DB for a newly started process.
185  */
186 static BOOL PROCESS_CreateEnvDB(void)
187 {
188     struct init_process_request req;
189     struct init_process_reply reply;
190     STARTUPINFOA *startup;
191     ENVDB *env_db;
192     PDB *pdb = PROCESS_Current();
193
194     /* Retrieve startup info from the server */
195
196     req.dummy = 0;
197     CLIENT_SendRequest( REQ_INIT_PROCESS, -1, 1, &req, sizeof(req) );
198     if (CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL )) return FALSE;
199
200     /* Allocate the env DB */
201
202     if (!(env_db = HeapAlloc( pdb->heap, HEAP_ZERO_MEMORY, sizeof(ENVDB) )))
203         return FALSE;
204     pdb->env_db = env_db;
205     InitializeCriticalSection( &env_db->section );
206
207     /* Allocate and fill the startup info */
208     if (!(startup = HeapAlloc( pdb->heap, HEAP_ZERO_MEMORY, sizeof(STARTUPINFOA) )))
209         return FALSE;
210     pdb->env_db->startup_info = startup;
211     startup->dwFlags = reply.start_flags;
212     pdb->env_db->hStdin  = startup->hStdInput  = reply.hstdin;
213     pdb->env_db->hStdout = startup->hStdOutput = reply.hstdout;
214     pdb->env_db->hStderr = startup->hStdError  = reply.hstderr;
215
216 #if 0  /* FIXME */
217     /* Copy the parent environment */
218
219     if (!ENV_InheritEnvironment( pdb, env )) return FALSE;
220
221     /* Copy the command line */
222
223     if (!(pdb->env_db->cmd_line = HEAP_strdupA( pdb->heap, 0, cmd_line )))
224         return FALSE;
225 #endif
226     return TRUE;
227 }
228
229
230 /***********************************************************************
231  *           PROCESS_FreePDB
232  *
233  * Free a PDB and all associated storage.
234  */
235 void PROCESS_FreePDB( PDB *pdb )
236 {
237     PDB **pptr = &PROCESS_First;
238
239     ENV_FreeEnvironment( pdb );
240     while (*pptr && (*pptr != pdb)) pptr = &(*pptr)->next;
241     if (*pptr) *pptr = pdb->next;
242     if (pdb->heap && (pdb->heap != pdb->system_heap)) HeapDestroy( pdb->heap );
243     HeapFree( SystemHeap, 0, pdb );
244 }
245
246
247 /***********************************************************************
248  *           PROCESS_CreatePDB
249  *
250  * Allocate and fill a PDB structure.
251  * Runs in the context of the parent process.
252  */
253 static PDB *PROCESS_CreatePDB( PDB *parent, BOOL inherit )
254 {
255     PDB *pdb = HeapAlloc( SystemHeap, HEAP_ZERO_MEMORY, sizeof(PDB) );
256
257     if (!pdb) return NULL;
258     pdb->exit_code       = 0x103; /* STILL_ACTIVE */
259     pdb->threads         = 1;
260     pdb->running_threads = 1;
261     pdb->ring0_threads   = 1;
262     pdb->system_heap     = SystemHeap;
263     pdb->parent          = parent;
264     pdb->group           = pdb;
265     pdb->priority        = 8;  /* Normal */
266     pdb->heap            = pdb->system_heap;  /* will be changed later on */
267     pdb->next            = PROCESS_First;
268     PROCESS_First = pdb;
269     return pdb;
270 }
271
272
273 /***********************************************************************
274  *           PROCESS_Init
275  */
276 BOOL PROCESS_Init(void)
277 {
278     THDB *thdb;
279     int server_fd;
280
281     /* Start the server */
282     server_fd = CLIENT_InitServer();
283
284     /* Fill the initial process structure */
285     initial_pdb.exit_code       = 0x103; /* STILL_ACTIVE */
286     initial_pdb.threads         = 1;
287     initial_pdb.running_threads = 1;
288     initial_pdb.ring0_threads   = 1;
289     initial_pdb.group           = &initial_pdb;
290     initial_pdb.priority        = 8;  /* Normal */
291     initial_pdb.flags           = PDB32_WIN16_PROC;
292
293     /* Initialize virtual memory management */
294     if (!VIRTUAL_Init()) return FALSE;
295
296     /* Create the initial thread structure and socket pair */
297     if (!(thdb = THREAD_CreateInitialThread( &initial_pdb, server_fd ))) return FALSE;
298
299     /* Remember TEB selector of initial process for emergency use */
300     SYSLEVEL_EmergencyTeb = thdb->teb_sel;
301
302     /* Create the system heap */
303     if (!(SystemHeap = HeapCreate( HEAP_GROWABLE, 0x10000, 0 ))) return FALSE;
304     initial_pdb.system_heap = initial_pdb.heap = SystemHeap;
305
306     /* Create the environment DB of the first process */
307     if (!PROCESS_BuildEnvDB( &initial_pdb )) return FALSE;
308
309     /* Create the SEGPTR heap */
310     if (!(SegptrHeap = HeapCreate( HEAP_WINE_SEGPTR, 0, 0 ))) return FALSE;
311
312     /* Initialize the first process critical section */
313     InitializeCriticalSection( &initial_pdb.crit_section );
314
315     return TRUE;
316 }
317
318
319 /***********************************************************************
320  *           PROCESS_Start
321  *
322  * Startup routine of a new process. Called in the context of the new process.
323  */
324 void PROCESS_Start(void)
325 {
326     DWORD size, commit;
327     UINT cmdShow = 0;
328     LPTHREAD_START_ROUTINE entry;
329     THDB *thdb = THREAD_Current();
330     PDB *pdb = thdb->process;
331     TDB *pTask = (TDB *)GlobalLock16( pdb->task );
332     NE_MODULE *pModule = NE_GetPtr( pTask->hModule );
333     OFSTRUCT *ofs = (OFSTRUCT *)((char*)(pModule) + (pModule)->fileinfo);
334
335 #if 0
336     /* Initialize the critical section */
337
338     InitializeCriticalSection( &pdb->crit_section );
339
340     /* Create the heap */
341
342     size  = PE_HEADER(pModule->module32)->OptionalHeader.SizeOfHeapReserve;
343     commit = PE_HEADER(pModule->module32)->OptionalHeader.SizeOfHeapCommit;
344     if (!(pdb->heap = HeapCreate( HEAP_GROWABLE, size, commit ))) goto error;
345     pdb->heap_list = pdb->heap;
346
347     /* Create the environment db */
348
349     if (!PROCESS_CreateEnvDB()) goto error;
350
351     if (pdb->env_db->startup_info->dwFlags & STARTF_USESHOWWINDOW)
352         cmdShow = pdb->env_db->startup_info->wShowWindow;
353     if (!TASK_Create( thdb, pModule, 0, 0, cmdShow )) goto error;
354
355 #endif
356
357     /* Map system DLLs into this process (from initial process) */
358     /* FIXME: this is a hack */
359     pdb->modref_list = PROCESS_Initial()->modref_list;
360
361     /* Create 32-bit MODREF */
362     if (!PE_CreateModule( pModule->module32, ofs, 0, FALSE )) goto error;
363
364     /* Initialize thread-local storage */
365
366     PE_InitTls( thdb );
367
368     if (PE_HEADER(pModule->module32)->OptionalHeader.Subsystem==IMAGE_SUBSYSTEM_WINDOWS_CUI)
369         AllocConsole();
370
371     /* Now call the entry point */
372
373     MODULE_InitializeDLLs( 0, DLL_PROCESS_ATTACH, (LPVOID)-1 );
374     entry = (LPTHREAD_START_ROUTINE)RVA_PTR(pModule->module32,
375                                             OptionalHeader.AddressOfEntryPoint);
376     TRACE(relay, "(entryproc=%p)\n", entry );
377     ExitProcess( entry(NULL) );
378
379  error:
380     ExitProcess(1);
381 }
382
383
384 /***********************************************************************
385  *           PROCESS_Create
386  *
387  * Create a new process database and associated info.
388  */
389 PDB *PROCESS_Create( NE_MODULE *pModule, LPCSTR cmd_line, LPCSTR env,
390                      HINSTANCE16 hInstance, HINSTANCE16 hPrevInstance,
391                      LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES tsa,
392                      BOOL inherit, STARTUPINFOA *startup,
393                      PROCESS_INFORMATION *info )
394 {
395     DWORD size, commit;
396     int server_thandle;
397     struct new_process_request req;
398     struct new_process_reply reply;
399     UINT cmdShow = 0;
400     THDB *thdb = NULL;
401     PDB *parent = PROCESS_Current();
402     PDB *pdb = PROCESS_CreatePDB( parent, inherit );
403
404     if (!pdb) return NULL;
405     info->hThread = info->hProcess = INVALID_HANDLE_VALUE;
406
407     /* Create the process on the server side */
408
409     req.inherit     = (psa && (psa->nLength >= sizeof(*psa)) && psa->bInheritHandle);
410     req.inherit_all = inherit;
411     req.start_flags = startup->dwFlags;
412     if (startup->dwFlags & STARTF_USESTDHANDLES)
413     {
414         req.hstdin  = startup->hStdInput;
415         req.hstdout = startup->hStdOutput;
416         req.hstderr = startup->hStdError;
417     }
418     else
419     {
420         req.hstdin  = GetStdHandle( STD_INPUT_HANDLE );
421         req.hstdout = GetStdHandle( STD_OUTPUT_HANDLE );
422         req.hstderr = GetStdHandle( STD_ERROR_HANDLE );
423     }
424     CLIENT_SendRequest( REQ_NEW_PROCESS, -1, 1, &req, sizeof(req) );
425     if (CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL )) goto error;
426     pdb->server_pid   = reply.pid;
427     info->hProcess    = reply.handle;
428     info->dwProcessId = (DWORD)pdb->server_pid;
429
430     /* Initialize the critical section */
431
432     InitializeCriticalSection( &pdb->crit_section );
433
434     /* Create the heap */
435
436     if (pModule->module32)
437     {
438         size  = PE_HEADER(pModule->module32)->OptionalHeader.SizeOfHeapReserve;
439         commit = PE_HEADER(pModule->module32)->OptionalHeader.SizeOfHeapCommit;
440     }
441     else
442     {
443         size = 0x10000;
444         commit = 0;
445         pdb->flags |= PDB32_WIN16_PROC;  /* This is a Win16 process */
446     }
447     if (!(pdb->heap = HeapCreate( HEAP_GROWABLE, size, commit ))) goto error;
448     pdb->heap_list = pdb->heap;
449
450     /* Inherit the env DB from the parent */
451
452     if (!PROCESS_InheritEnvDB( pdb, cmd_line, env, inherit, startup )) goto error;
453
454     /* Create the main thread */
455
456     if (pModule->module32)
457         size = PE_HEADER(pModule->module32)->OptionalHeader.SizeOfStackReserve;
458     else
459         size = 0;
460     if (!(thdb = THREAD_Create( pdb, 0L, size, hInstance == 0, tsa, &server_thandle ))) 
461         goto error;
462     info->hThread     = server_thandle;
463     info->dwThreadId  = (DWORD)thdb->server_tid;
464     thdb->startup     = PROCESS_Start;
465
466     /* Duplicate the standard handles */
467
468     if ((!(pdb->env_db->startup_info->dwFlags & STARTF_USESTDHANDLES)) && !inherit)
469     {
470         DuplicateHandle( GetCurrentProcess(), pdb->parent->env_db->hStdin,
471                          info->hProcess, &pdb->env_db->hStdin, 0, TRUE, DUPLICATE_SAME_ACCESS );
472         DuplicateHandle( GetCurrentProcess(), pdb->parent->env_db->hStdout,
473                          info->hProcess, &pdb->env_db->hStdout, 0, TRUE, DUPLICATE_SAME_ACCESS );
474         DuplicateHandle( GetCurrentProcess(), pdb->parent->env_db->hStderr,
475                          info->hProcess, &pdb->env_db->hStderr, 0, TRUE, DUPLICATE_SAME_ACCESS );
476     }
477
478     /* Create a Win16 task for this process */
479
480     if (startup->dwFlags & STARTF_USESHOWWINDOW)
481         cmdShow = startup->wShowWindow;
482
483     if ( !TASK_Create( thdb, pModule, hInstance, hPrevInstance, cmdShow) )
484         goto error;
485
486
487     /* Map system DLLs into this process (from initial process) */
488     /* FIXME: this is a hack */
489     pdb->modref_list = PROCESS_Initial()->modref_list;
490     
491
492     /* Start the task */
493
494     TASK_StartTask( pdb->task );
495
496     return pdb;
497
498 error:
499     if (info->hThread != INVALID_HANDLE_VALUE) CloseHandle( info->hThread );
500     if (info->hProcess != INVALID_HANDLE_VALUE) CloseHandle( info->hProcess );
501     PROCESS_FreePDB( pdb );
502     return NULL;
503 }
504
505
506 /***********************************************************************
507  *           ExitProcess   (KERNEL32.100)
508  */
509 void WINAPI ExitProcess( DWORD status )
510 {
511     MODULE_InitializeDLLs( 0, DLL_PROCESS_DETACH, NULL );
512
513     if ( THREAD_IsWin16( THREAD_Current() ) )
514         TASK_KillCurrentTask( status );
515
516     TASK_KillTask( 0 );
517     TerminateProcess( GetCurrentProcess(), status );
518 }
519
520
521 /******************************************************************************
522  *           TerminateProcess   (KERNEL32.684)
523  */
524 BOOL WINAPI TerminateProcess( HANDLE handle, DWORD exit_code )
525 {
526     struct terminate_process_request req;
527     req.handle    = handle;
528     req.exit_code = exit_code;
529     CLIENT_SendRequest( REQ_TERMINATE_PROCESS, -1, 1, &req, sizeof(req) );
530     return !CLIENT_WaitReply( NULL, NULL, 0 );
531 }
532
533 /***********************************************************************
534  *           GetCurrentProcess   (KERNEL32.198)
535  */
536 HANDLE WINAPI GetCurrentProcess(void)
537 {
538     return CURRENT_PROCESS_PSEUDOHANDLE;
539 }
540
541
542 /*********************************************************************
543  *           OpenProcess   (KERNEL32.543)
544  */
545 HANDLE WINAPI OpenProcess( DWORD access, BOOL inherit, DWORD id )
546 {
547     struct open_process_request req;
548     struct open_process_reply reply;
549
550     req.pid     = (void *)id;
551     req.access  = access;
552     req.inherit = inherit;
553     CLIENT_SendRequest( REQ_OPEN_PROCESS, -1, 1, &req, sizeof(req) );
554     if (CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL )) return 0;
555     return reply.handle;
556 }                             
557
558
559 /***********************************************************************
560  *           GetCurrentProcessId   (KERNEL32.199)
561  */
562 DWORD WINAPI GetCurrentProcessId(void)
563 {
564     return (DWORD)PROCESS_Current()->server_pid;
565 }
566
567
568 /***********************************************************************
569  *           GetProcessHeap    (KERNEL32.259)
570  */
571 HANDLE WINAPI GetProcessHeap(void)
572 {
573     PDB *pdb = PROCESS_Current();
574     return pdb->heap ? pdb->heap : SystemHeap;
575 }
576
577
578 /***********************************************************************
579  *           GetThreadLocale    (KERNEL32.295)
580  */
581 LCID WINAPI GetThreadLocale(void)
582 {
583     return PROCESS_Current()->locale;
584 }
585
586
587 /***********************************************************************
588  *           SetPriorityClass   (KERNEL32.503)
589  */
590 BOOL WINAPI SetPriorityClass( HANDLE hprocess, DWORD priorityclass )
591 {
592     struct set_process_info_request req;
593     req.handle   = hprocess;
594     req.priority = priorityclass;
595     req.mask     = SET_PROCESS_INFO_PRIORITY;
596     CLIENT_SendRequest( REQ_SET_PROCESS_INFO, -1, 1, &req, sizeof(req) );
597     return !CLIENT_WaitReply( NULL, NULL, 0 );
598 }
599
600
601 /***********************************************************************
602  *           GetPriorityClass   (KERNEL32.250)
603  */
604 DWORD WINAPI GetPriorityClass(HANDLE hprocess)
605 {
606     struct get_process_info_reply reply;
607     if (!PROCESS_QueryInfo( hprocess, &reply )) return 0;
608     return reply.priority;
609 }
610
611
612 /***********************************************************************
613  *          SetProcessAffinityMask   (KERNEL32.662)
614  */
615 BOOL WINAPI SetProcessAffinityMask( HANDLE hProcess, DWORD affmask )
616 {
617     struct set_process_info_request req;
618     req.handle   = hProcess;
619     req.affinity = affmask;
620     req.mask     = SET_PROCESS_INFO_AFFINITY;
621     CLIENT_SendRequest( REQ_SET_PROCESS_INFO, -1, 1, &req, sizeof(req) );
622     return !CLIENT_WaitReply( NULL, NULL, 0 );
623 }
624
625 /**********************************************************************
626  *          GetProcessAffinityMask    (KERNEL32.373)
627  */
628 BOOL WINAPI GetProcessAffinityMask( HANDLE hProcess,
629                                       LPDWORD lpProcessAffinityMask,
630                                       LPDWORD lpSystemAffinityMask )
631 {
632     struct get_process_info_reply reply;
633     if (!PROCESS_QueryInfo( hProcess, &reply )) return FALSE;
634     if (lpProcessAffinityMask) *lpProcessAffinityMask = reply.process_affinity;
635     if (lpSystemAffinityMask) *lpSystemAffinityMask = reply.system_affinity;
636     return TRUE;
637 }
638
639
640 /***********************************************************************
641  *           GetStdHandle    (KERNEL32.276)
642  */
643 HANDLE WINAPI GetStdHandle( DWORD std_handle )
644 {
645     PDB *pdb = PROCESS_Current();
646
647     switch(std_handle)
648     {
649     case STD_INPUT_HANDLE:  return pdb->env_db->hStdin;
650     case STD_OUTPUT_HANDLE: return pdb->env_db->hStdout;
651     case STD_ERROR_HANDLE:  return pdb->env_db->hStderr;
652     }
653     SetLastError( ERROR_INVALID_PARAMETER );
654     return INVALID_HANDLE_VALUE;
655 }
656
657
658 /***********************************************************************
659  *           SetStdHandle    (KERNEL32.506)
660  */
661 BOOL WINAPI SetStdHandle( DWORD std_handle, HANDLE handle )
662 {
663     PDB *pdb = PROCESS_Current();
664     /* FIXME: should we close the previous handle? */
665     switch(std_handle)
666     {
667     case STD_INPUT_HANDLE:
668         pdb->env_db->hStdin = handle;
669         return TRUE;
670     case STD_OUTPUT_HANDLE:
671         pdb->env_db->hStdout = handle;
672         return TRUE;
673     case STD_ERROR_HANDLE:
674         pdb->env_db->hStderr = handle;
675         return TRUE;
676     }
677     SetLastError( ERROR_INVALID_PARAMETER );
678     return FALSE;
679 }
680
681 /***********************************************************************
682  *           GetProcessVersion    (KERNEL32)
683  */
684 DWORD WINAPI GetProcessVersion( DWORD processid )
685 {
686     TDB *pTask;
687     PDB *pdb = PROCESS_IdToPDB( processid );
688
689     if (!pdb) return 0;
690     if (!(pTask = (TDB *)GlobalLock16( pdb->task ))) return 0;
691     return (pTask->version&0xff) | (((pTask->version >>8) & 0xff)<<16);
692 }
693
694 /***********************************************************************
695  *           GetProcessFlags    (KERNEL32)
696  */
697 DWORD WINAPI GetProcessFlags( DWORD processid )
698 {
699     PDB *pdb = PROCESS_IdToPDB( processid );
700     if (!pdb) return 0;
701     return pdb->flags;
702 }
703
704 /***********************************************************************
705  *              SetProcessWorkingSetSize        [KERNEL32.662]
706  * Sets the min/max working set sizes for a specified process.
707  *
708  * PARAMS
709  *    hProcess [I] Handle to the process of interest
710  *    minset   [I] Specifies minimum working set size
711  *    maxset   [I] Specifies maximum working set size
712  *
713  * RETURNS  STD
714  */
715 BOOL WINAPI SetProcessWorkingSetSize(HANDLE hProcess,DWORD minset,
716                                        DWORD maxset)
717 {
718     FIXME(process,"(0x%08x,%ld,%ld): stub - harmless\n",hProcess,minset,maxset);
719     if(( minset == -1) && (maxset == -1)) {
720         /* Trim the working set to zero */
721         /* Swap the process out of physical RAM */
722     }
723     return TRUE;
724 }
725
726 /***********************************************************************
727  *           GetProcessWorkingSetSize    (KERNEL32)
728  */
729 BOOL WINAPI GetProcessWorkingSetSize(HANDLE hProcess,LPDWORD minset,
730                                        LPDWORD maxset)
731 {
732         FIXME(process,"(0x%08x,%p,%p): stub\n",hProcess,minset,maxset);
733         /* 32 MB working set size */
734         if (minset) *minset = 32*1024*1024;
735         if (maxset) *maxset = 32*1024*1024;
736         return TRUE;
737 }
738
739 /***********************************************************************
740  *           SetProcessShutdownParameters    (KERNEL32)
741  *
742  * CHANGED - James Sutherland (JamesSutherland@gmx.de)
743  * Now tracks changes made (but does not act on these changes)
744  * NOTE: the definition for SHUTDOWN_NORETRY was done on guesswork.
745  * It really shouldn't be here, but I'll move it when it's been checked!
746  */
747 #define SHUTDOWN_NORETRY 1
748 static unsigned int shutdown_noretry = 0;
749 static unsigned int shutdown_priority = 0x280L;
750 BOOL WINAPI SetProcessShutdownParameters(DWORD level,DWORD flags)
751 {
752     if (flags & SHUTDOWN_NORETRY)
753       shutdown_noretry = 1;
754     else
755       shutdown_noretry = 0;
756     if (level > 0x100L && level < 0x3FFL)
757       shutdown_priority = level;
758     else
759       {
760         ERR(process,"invalid priority level 0x%08lx\n", level);
761         return FALSE;
762       }
763     return TRUE;
764 }
765
766
767 /***********************************************************************
768  * GetProcessShutdownParameters                 (KERNEL32)
769  *
770  */
771 BOOL WINAPI GetProcessShutdownParameters( LPDWORD lpdwLevel,
772                                             LPDWORD lpdwFlags )
773 {
774   (*lpdwLevel) = shutdown_priority;
775   (*lpdwFlags) = (shutdown_noretry * SHUTDOWN_NORETRY);
776   return TRUE;
777 }
778 /***********************************************************************
779  *           SetProcessPriorityBoost    (KERNEL32)
780  */
781 BOOL WINAPI SetProcessPriorityBoost(HANDLE hprocess,BOOL disableboost)
782 {
783     FIXME(process,"(%d,%d): stub\n",hprocess,disableboost);
784     /* Say we can do it. I doubt the program will notice that we don't. */
785     return TRUE;
786 }
787
788 /***********************************************************************
789  *           ReadProcessMemory                  (KERNEL32)
790  * FIXME: check this, if we ever run win32 binaries in different addressspaces
791  *        ... and add a sizecheck
792  */
793 BOOL WINAPI ReadProcessMemory( HANDLE hProcess, LPCVOID lpBaseAddress,
794                                  LPVOID lpBuffer, DWORD nSize,
795                                  LPDWORD lpNumberOfBytesRead )
796 {
797         memcpy(lpBuffer,lpBaseAddress,nSize);
798         if (lpNumberOfBytesRead) *lpNumberOfBytesRead = nSize;
799         return TRUE;
800 }
801
802 /***********************************************************************
803  *           WriteProcessMemory                 (KERNEL32)
804  * FIXME: check this, if we ever run win32 binaries in different addressspaces
805  *        ... and add a sizecheck
806  */
807 BOOL WINAPI WriteProcessMemory(HANDLE hProcess, LPVOID lpBaseAddress,
808                                  LPVOID lpBuffer, DWORD nSize,
809                                  LPDWORD lpNumberOfBytesWritten )
810 {
811         memcpy(lpBaseAddress,lpBuffer,nSize);
812         if (lpNumberOfBytesWritten) *lpNumberOfBytesWritten = nSize;
813         return TRUE;
814 }
815
816 /***********************************************************************
817  *           RegisterServiceProcess             (KERNEL, KERNEL32)
818  *
819  * A service process calls this function to ensure that it continues to run
820  * even after a user logged off.
821  */
822 DWORD WINAPI RegisterServiceProcess(DWORD dwProcessId, DWORD dwType)
823 {
824         /* I don't think that Wine needs to do anything in that function */
825         return 1; /* success */
826 }
827
828 /***********************************************************************
829  * GetExitCodeProcess [KERNEL32.325]
830  *
831  * Gets termination status of specified process
832  * 
833  * RETURNS
834  *   Success: TRUE
835  *   Failure: FALSE
836  */
837 BOOL WINAPI GetExitCodeProcess(
838     HANDLE hProcess,  /* [I] handle to the process */
839     LPDWORD lpExitCode) /* [O] address to receive termination status */
840 {
841     struct get_process_info_reply reply;
842     if (!PROCESS_QueryInfo( hProcess, &reply )) return FALSE;
843     if (lpExitCode) *lpExitCode = reply.exit_code;
844     return TRUE;
845 }
846
847
848 /***********************************************************************
849  * GetProcessHeaps [KERNEL32.376]
850  */
851 DWORD WINAPI GetProcessHeaps(DWORD nrofheaps,HANDLE *heaps) {
852         FIXME(win32,"(%ld,%p), incomplete implementation.\n",nrofheaps,heaps);
853
854         if (nrofheaps) {
855                 heaps[0] = GetProcessHeap();
856                 /* ... probably SystemHeap too ? */
857                 return 1;
858         }
859         /* number of available heaps */
860         return 1;
861 }
862
863 /***********************************************************************
864  * PROCESS_SuspendOtherThreads
865  */
866
867 void PROCESS_SuspendOtherThreads(void)
868 {
869 #if 0
870     PDB *pdb;
871     THREAD_ENTRY *entry;
872
873     SYSTEM_LOCK();
874
875     pdb = PROCESS_Current();
876     entry = pdb->thread_list->next;
877     for (;;)
878     {
879          if (entry->thread != THREAD_Current() && !THREAD_IsWin16(entry->thread))
880          {
881              HANDLE handle = HANDLE_Alloc( PROCESS_Current(), 
882                                              &entry->thread->header,
883                                              THREAD_ALL_ACCESS, FALSE, -1 );
884              SuspendThread(handle);
885              CloseHandle(handle);
886          }
887          if (entry == pdb->thread_list) break;
888          entry = entry->next;
889     }
890
891     SYSTEM_UNLOCK();
892 #endif
893 }
894
895 /***********************************************************************
896  * PROCESS_ResumeOtherThreads
897  */
898
899 void PROCESS_ResumeOtherThreads(void)
900 {
901 #if 0
902     PDB *pdb;
903     THREAD_ENTRY *entry;
904
905     SYSTEM_LOCK();
906
907     pdb = PROCESS_Current();
908     entry = pdb->thread_list->next;
909     for (;;)
910     {
911          if (entry->thread != THREAD_Current() && !THREAD_IsWin16(entry->thread))
912          {
913              HANDLE handle = HANDLE_Alloc( PROCESS_Current(), 
914                                              &entry->thread->header,
915                                              THREAD_ALL_ACCESS, FALSE, -1 );
916              ResumeThread(handle);
917              CloseHandle(handle);
918          }
919          if (entry == pdb->thread_list) break;
920          entry = entry->next;
921     }
922
923     SYSTEM_UNLOCK();
924 #endif
925 }
926