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