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