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