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