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