Changed process initialisation to use the new server requests.
[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
292     /* Initialize virtual memory management */
293     if (!VIRTUAL_Init()) return FALSE;
294
295     /* Create the initial thread structure and socket pair */
296     if (!(thdb = THREAD_CreateInitialThread( &initial_pdb, server_fd ))) return FALSE;
297
298     /* Remember TEB selector of initial process for emergency use */
299     SYSLEVEL_EmergencyTeb = thdb->teb_sel;
300
301     /* Create the system heap */
302     if (!(SystemHeap = HeapCreate( HEAP_GROWABLE, 0x10000, 0 ))) return FALSE;
303     initial_pdb.system_heap = initial_pdb.heap = SystemHeap;
304
305     /* Create the environment DB of the first process */
306     if (!PROCESS_BuildEnvDB( &initial_pdb )) return FALSE;
307
308     /* Initialize the first thread */
309     if (CLIENT_InitThread()) return FALSE;
310
311     /* Create the SEGPTR heap */
312     if (!(SegptrHeap = HeapCreate( HEAP_WINE_SEGPTR, 0, 0 ))) return FALSE;
313
314     /* Initialize the first process critical section */
315     InitializeCriticalSection( &initial_pdb.crit_section );
316
317     return TRUE;
318 }
319
320
321 /***********************************************************************
322  *           PROCESS_Start
323  *
324  * Startup routine of a new process. Called in the context of the new process.
325  */
326 void PROCESS_Start(void)
327 {
328     DWORD size, commit;
329     UINT cmdShow = 0;
330     LPTHREAD_START_ROUTINE entry;
331     THDB *thdb = THREAD_Current();
332     PDB *pdb = thdb->process;
333     NE_MODULE *pModule = (NE_MODULE *)thdb->entry_arg;  /* hack */
334
335     /* Initialize the critical section */
336
337     InitializeCriticalSection( &pdb->crit_section );
338
339     /* Create the heap */
340
341     size  = PE_HEADER(pModule->module32)->OptionalHeader.SizeOfHeapReserve;
342     commit = PE_HEADER(pModule->module32)->OptionalHeader.SizeOfHeapCommit;
343     if (!(pdb->heap = HeapCreate( HEAP_GROWABLE, size, commit ))) goto error;
344     pdb->heap_list = pdb->heap;
345
346     /* Create the environment db */
347
348     if (!PROCESS_CreateEnvDB()) goto error;
349
350 #if 0
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 #endif
355
356     /* Map system DLLs into this process (from initial process) */
357     /* FIXME: this is a hack */
358     pdb->modref_list = PROCESS_Initial()->modref_list;
359
360     /* Create 32-bit MODREF */
361     {
362         OFSTRUCT *ofs = (OFSTRUCT *)((char*)(pModule) + (pModule)->fileinfo);
363         if (!PE_CreateModule( pModule->module32, ofs, 0, FALSE )) goto error;
364     }
365
366     /* Initialize thread-local storage */
367
368     PE_InitTls( thdb );
369
370     if (PE_HEADER(pModule->module32)->OptionalHeader.Subsystem==IMAGE_SUBSYSTEM_WINDOWS_CUI)
371         AllocConsole();
372
373     /* Now call the entry point */
374
375     MODULE_InitializeDLLs( 0, DLL_PROCESS_ATTACH, (LPVOID)-1 );
376     entry = (LPTHREAD_START_ROUTINE)RVA_PTR(pModule->module32,
377                                             OptionalHeader.AddressOfEntryPoint);
378     TRACE(relay, "(entryproc=%p)\n", entry );
379     ExitProcess( entry(NULL) );
380
381  error:
382     ExitProcess(1);
383 }
384
385
386 /***********************************************************************
387  *           PROCESS_Create
388  *
389  * Create a new process database and associated info.
390  */
391 PDB *PROCESS_Create( NE_MODULE *pModule, LPCSTR cmd_line, LPCSTR env,
392                      HINSTANCE16 hInstance, HINSTANCE16 hPrevInstance,
393                      LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES tsa,
394                      BOOL inherit, STARTUPINFOA *startup,
395                      PROCESS_INFORMATION *info )
396 {
397     DWORD size, commit;
398     int server_thandle;
399     struct new_process_request req;
400     struct new_process_reply reply;
401     UINT cmdShow = 0;
402     THDB *thdb = NULL;
403     PDB *parent = PROCESS_Current();
404     PDB *pdb = PROCESS_CreatePDB( parent, inherit );
405
406     if (!pdb) return NULL;
407     info->hThread = info->hProcess = INVALID_HANDLE_VALUE;
408
409     /* Create the process on the server side */
410
411     req.inherit     = (psa && (psa->nLength >= sizeof(*psa)) && psa->bInheritHandle);
412     req.inherit_all = inherit;
413     req.start_flags = startup->dwFlags;
414     if (startup->dwFlags & STARTF_USESTDHANDLES)
415     {
416         req.hstdin  = startup->hStdInput;
417         req.hstdout = startup->hStdOutput;
418         req.hstderr = startup->hStdError;
419     }
420     else
421     {
422         req.hstdin  = GetStdHandle( STD_INPUT_HANDLE );
423         req.hstdout = GetStdHandle( STD_OUTPUT_HANDLE );
424         req.hstderr = GetStdHandle( STD_ERROR_HANDLE );
425     }
426     CLIENT_SendRequest( REQ_NEW_PROCESS, -1, 1, &req, sizeof(req) );
427     if (CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL )) goto error;
428     pdb->server_pid   = reply.pid;
429     info->hProcess    = reply.handle;
430     info->dwProcessId = (DWORD)pdb->server_pid;
431
432     /* Initialize the critical section */
433
434     InitializeCriticalSection( &pdb->crit_section );
435
436     /* Create the heap */
437
438     if (pModule->module32)
439     {
440         size  = PE_HEADER(pModule->module32)->OptionalHeader.SizeOfHeapReserve;
441         commit = PE_HEADER(pModule->module32)->OptionalHeader.SizeOfHeapCommit;
442     }
443     else
444     {
445         size = 0x10000;
446         commit = 0;
447         pdb->flags |= PDB32_WIN16_PROC;  /* This is a Win16 process */
448     }
449     if (!(pdb->heap = HeapCreate( HEAP_GROWABLE, size, commit ))) goto error;
450     pdb->heap_list = pdb->heap;
451
452     /* Inherit the env DB from the parent */
453
454     if (!PROCESS_InheritEnvDB( pdb, cmd_line, env, inherit, startup )) goto error;
455
456     /* Create the main thread */
457
458     if (pModule->module32)
459         size = PE_HEADER(pModule->module32)->OptionalHeader.SizeOfStackReserve;
460     else
461         size = 0;
462     if (!(thdb = THREAD_Create( pdb, 0L, size, hInstance == 0, tsa, &server_thandle ))) 
463         goto error;
464     info->hThread     = server_thandle;
465     info->dwThreadId  = (DWORD)thdb->server_tid;
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     PDB *pdb = PROCESS_Current();
513     TDB *pTask = (TDB *)GlobalLock16( pdb->task );
514     if ( pTask ) pTask->nEvents++;
515
516     MODULE_InitializeDLLs( 0, DLL_PROCESS_DETACH, NULL );
517
518     if ( pTask && pTask->thdb != THREAD_Current() )
519         TerminateProcess( GetCurrentProcess(), status );
520
521     /* FIXME: should kill all running threads of this process */
522     pdb->exit_code = status;
523
524     __RESTORE_ES;  /* Necessary for Pietrek's showseh example program */
525     TASK_KillCurrentTask( status );
526 }
527
528
529 /******************************************************************************
530  *           TerminateProcess   (KERNEL32.684)
531  */
532 BOOL WINAPI TerminateProcess( HANDLE handle, DWORD exit_code )
533 {
534     struct terminate_process_request req;
535     req.handle    = handle;
536     req.exit_code = exit_code;
537     CLIENT_SendRequest( REQ_TERMINATE_PROCESS, -1, 1, &req, sizeof(req) );
538     return !CLIENT_WaitReply( NULL, NULL, 0 );
539 }
540
541 /***********************************************************************
542  *           GetCurrentProcess   (KERNEL32.198)
543  */
544 HANDLE WINAPI GetCurrentProcess(void)
545 {
546     return CURRENT_PROCESS_PSEUDOHANDLE;
547 }
548
549
550 /*********************************************************************
551  *           OpenProcess   (KERNEL32.543)
552  */
553 HANDLE WINAPI OpenProcess( DWORD access, BOOL inherit, DWORD id )
554 {
555     struct open_process_request req;
556     struct open_process_reply reply;
557
558     req.pid     = (void *)id;
559     req.access  = access;
560     req.inherit = inherit;
561     CLIENT_SendRequest( REQ_OPEN_PROCESS, -1, 1, &req, sizeof(req) );
562     if (CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL )) return 0;
563     return reply.handle;
564 }                             
565
566
567 /***********************************************************************
568  *           GetCurrentProcessId   (KERNEL32.199)
569  */
570 DWORD WINAPI GetCurrentProcessId(void)
571 {
572     return (DWORD)PROCESS_Current()->server_pid;
573 }
574
575
576 /***********************************************************************
577  *           GetProcessHeap    (KERNEL32.259)
578  */
579 HANDLE WINAPI GetProcessHeap(void)
580 {
581     PDB *pdb = PROCESS_Current();
582     return pdb->heap ? pdb->heap : SystemHeap;
583 }
584
585
586 /***********************************************************************
587  *           GetThreadLocale    (KERNEL32.295)
588  */
589 LCID WINAPI GetThreadLocale(void)
590 {
591     return PROCESS_Current()->locale;
592 }
593
594
595 /***********************************************************************
596  *           SetPriorityClass   (KERNEL32.503)
597  */
598 BOOL WINAPI SetPriorityClass( HANDLE hprocess, DWORD priorityclass )
599 {
600     struct set_process_info_request req;
601     req.handle   = hprocess;
602     req.priority = priorityclass;
603     req.mask     = SET_PROCESS_INFO_PRIORITY;
604     CLIENT_SendRequest( REQ_SET_PROCESS_INFO, -1, 1, &req, sizeof(req) );
605     return !CLIENT_WaitReply( NULL, NULL, 0 );
606 }
607
608
609 /***********************************************************************
610  *           GetPriorityClass   (KERNEL32.250)
611  */
612 DWORD WINAPI GetPriorityClass(HANDLE hprocess)
613 {
614     struct get_process_info_reply reply;
615     if (!PROCESS_QueryInfo( hprocess, &reply )) return 0;
616     return reply.priority;
617 }
618
619
620 /***********************************************************************
621  *          SetProcessAffinityMask   (KERNEL32.662)
622  */
623 BOOL WINAPI SetProcessAffinityMask( HANDLE hProcess, DWORD affmask )
624 {
625     struct set_process_info_request req;
626     req.handle   = hProcess;
627     req.affinity = affmask;
628     req.mask     = SET_PROCESS_INFO_AFFINITY;
629     CLIENT_SendRequest( REQ_SET_PROCESS_INFO, -1, 1, &req, sizeof(req) );
630     return !CLIENT_WaitReply( NULL, NULL, 0 );
631 }
632
633 /**********************************************************************
634  *          GetProcessAffinityMask    (KERNEL32.373)
635  */
636 BOOL WINAPI GetProcessAffinityMask( HANDLE hProcess,
637                                       LPDWORD lpProcessAffinityMask,
638                                       LPDWORD lpSystemAffinityMask )
639 {
640     struct get_process_info_reply reply;
641     if (!PROCESS_QueryInfo( hProcess, &reply )) return FALSE;
642     if (lpProcessAffinityMask) *lpProcessAffinityMask = reply.process_affinity;
643     if (lpSystemAffinityMask) *lpSystemAffinityMask = reply.system_affinity;
644     return TRUE;
645 }
646
647
648 /***********************************************************************
649  *           GetStdHandle    (KERNEL32.276)
650  */
651 HANDLE WINAPI GetStdHandle( DWORD std_handle )
652 {
653     PDB *pdb = PROCESS_Current();
654
655     switch(std_handle)
656     {
657     case STD_INPUT_HANDLE:  return pdb->env_db->hStdin;
658     case STD_OUTPUT_HANDLE: return pdb->env_db->hStdout;
659     case STD_ERROR_HANDLE:  return pdb->env_db->hStderr;
660     }
661     SetLastError( ERROR_INVALID_PARAMETER );
662     return INVALID_HANDLE_VALUE;
663 }
664
665
666 /***********************************************************************
667  *           SetStdHandle    (KERNEL32.506)
668  */
669 BOOL WINAPI SetStdHandle( DWORD std_handle, HANDLE handle )
670 {
671     PDB *pdb = PROCESS_Current();
672     /* FIXME: should we close the previous handle? */
673     switch(std_handle)
674     {
675     case STD_INPUT_HANDLE:
676         pdb->env_db->hStdin = handle;
677         return TRUE;
678     case STD_OUTPUT_HANDLE:
679         pdb->env_db->hStdout = handle;
680         return TRUE;
681     case STD_ERROR_HANDLE:
682         pdb->env_db->hStderr = handle;
683         return TRUE;
684     }
685     SetLastError( ERROR_INVALID_PARAMETER );
686     return FALSE;
687 }
688
689 /***********************************************************************
690  *           GetProcessVersion    (KERNEL32)
691  */
692 DWORD WINAPI GetProcessVersion( DWORD processid )
693 {
694     TDB *pTask;
695     PDB *pdb = PROCESS_IdToPDB( processid );
696
697     if (!pdb) return 0;
698     if (!(pTask = (TDB *)GlobalLock16( pdb->task ))) return 0;
699     return (pTask->version&0xff) | (((pTask->version >>8) & 0xff)<<16);
700 }
701
702 /***********************************************************************
703  *           GetProcessFlags    (KERNEL32)
704  */
705 DWORD WINAPI GetProcessFlags( DWORD processid )
706 {
707     PDB *pdb = PROCESS_IdToPDB( processid );
708     if (!pdb) return 0;
709     return pdb->flags;
710 }
711
712 /***********************************************************************
713  *              SetProcessWorkingSetSize        [KERNEL32.662]
714  * Sets the min/max working set sizes for a specified process.
715  *
716  * PARAMS
717  *    hProcess [I] Handle to the process of interest
718  *    minset   [I] Specifies minimum working set size
719  *    maxset   [I] Specifies maximum working set size
720  *
721  * RETURNS  STD
722  */
723 BOOL WINAPI SetProcessWorkingSetSize(HANDLE hProcess,DWORD minset,
724                                        DWORD maxset)
725 {
726     FIXME(process,"(0x%08x,%ld,%ld): stub - harmless\n",hProcess,minset,maxset);
727     if(( minset == -1) && (maxset == -1)) {
728         /* Trim the working set to zero */
729         /* Swap the process out of physical RAM */
730     }
731     return TRUE;
732 }
733
734 /***********************************************************************
735  *           GetProcessWorkingSetSize    (KERNEL32)
736  */
737 BOOL WINAPI GetProcessWorkingSetSize(HANDLE hProcess,LPDWORD minset,
738                                        LPDWORD maxset)
739 {
740         FIXME(process,"(0x%08x,%p,%p): stub\n",hProcess,minset,maxset);
741         /* 32 MB working set size */
742         if (minset) *minset = 32*1024*1024;
743         if (maxset) *maxset = 32*1024*1024;
744         return TRUE;
745 }
746
747 /***********************************************************************
748  *           SetProcessShutdownParameters    (KERNEL32)
749  *
750  * CHANGED - James Sutherland (JamesSutherland@gmx.de)
751  * Now tracks changes made (but does not act on these changes)
752  * NOTE: the definition for SHUTDOWN_NORETRY was done on guesswork.
753  * It really shouldn't be here, but I'll move it when it's been checked!
754  */
755 #define SHUTDOWN_NORETRY 1
756 static unsigned int shutdown_noretry = 0;
757 static unsigned int shutdown_priority = 0x280L;
758 BOOL WINAPI SetProcessShutdownParameters(DWORD level,DWORD flags)
759 {
760     if (flags & SHUTDOWN_NORETRY)
761       shutdown_noretry = 1;
762     else
763       shutdown_noretry = 0;
764     if (level > 0x100L && level < 0x3FFL)
765       shutdown_priority = level;
766     else
767       {
768         ERR(process,"invalid priority level 0x%08lx\n", level);
769         return FALSE;
770       }
771     return TRUE;
772 }
773
774
775 /***********************************************************************
776  * GetProcessShutdownParameters                 (KERNEL32)
777  *
778  */
779 BOOL WINAPI GetProcessShutdownParameters( LPDWORD lpdwLevel,
780                                             LPDWORD lpdwFlags )
781 {
782   (*lpdwLevel) = shutdown_priority;
783   (*lpdwFlags) = (shutdown_noretry * SHUTDOWN_NORETRY);
784   return TRUE;
785 }
786 /***********************************************************************
787  *           SetProcessPriorityBoost    (KERNEL32)
788  */
789 BOOL WINAPI SetProcessPriorityBoost(HANDLE hprocess,BOOL disableboost)
790 {
791     FIXME(process,"(%d,%d): stub\n",hprocess,disableboost);
792     /* Say we can do it. I doubt the program will notice that we don't. */
793     return TRUE;
794 }
795
796 /***********************************************************************
797  *           ReadProcessMemory                  (KERNEL32)
798  * FIXME: check this, if we ever run win32 binaries in different addressspaces
799  *        ... and add a sizecheck
800  */
801 BOOL WINAPI ReadProcessMemory( HANDLE hProcess, LPCVOID lpBaseAddress,
802                                  LPVOID lpBuffer, DWORD nSize,
803                                  LPDWORD lpNumberOfBytesRead )
804 {
805         memcpy(lpBuffer,lpBaseAddress,nSize);
806         if (lpNumberOfBytesRead) *lpNumberOfBytesRead = nSize;
807         return TRUE;
808 }
809
810 /***********************************************************************
811  *           WriteProcessMemory                 (KERNEL32)
812  * FIXME: check this, if we ever run win32 binaries in different addressspaces
813  *        ... and add a sizecheck
814  */
815 BOOL WINAPI WriteProcessMemory(HANDLE hProcess, LPVOID lpBaseAddress,
816                                  LPVOID lpBuffer, DWORD nSize,
817                                  LPDWORD lpNumberOfBytesWritten )
818 {
819         memcpy(lpBaseAddress,lpBuffer,nSize);
820         if (lpNumberOfBytesWritten) *lpNumberOfBytesWritten = nSize;
821         return TRUE;
822 }
823
824 /***********************************************************************
825  *           RegisterServiceProcess             (KERNEL, KERNEL32)
826  *
827  * A service process calls this function to ensure that it continues to run
828  * even after a user logged off.
829  */
830 DWORD WINAPI RegisterServiceProcess(DWORD dwProcessId, DWORD dwType)
831 {
832         /* I don't think that Wine needs to do anything in that function */
833         return 1; /* success */
834 }
835
836 /***********************************************************************
837  * GetExitCodeProcess [KERNEL32.325]
838  *
839  * Gets termination status of specified process
840  * 
841  * RETURNS
842  *   Success: TRUE
843  *   Failure: FALSE
844  */
845 BOOL WINAPI GetExitCodeProcess(
846     HANDLE hProcess,  /* [I] handle to the process */
847     LPDWORD lpExitCode) /* [O] address to receive termination status */
848 {
849     struct get_process_info_reply reply;
850     if (!PROCESS_QueryInfo( hProcess, &reply )) return FALSE;
851     if (lpExitCode) *lpExitCode = reply.exit_code;
852     return TRUE;
853 }
854
855
856 /***********************************************************************
857  * GetProcessHeaps [KERNEL32.376]
858  */
859 DWORD WINAPI GetProcessHeaps(DWORD nrofheaps,HANDLE *heaps) {
860         FIXME(win32,"(%ld,%p), incomplete implementation.\n",nrofheaps,heaps);
861
862         if (nrofheaps) {
863                 heaps[0] = GetProcessHeap();
864                 /* ... probably SystemHeap too ? */
865                 return 1;
866         }
867         /* number of available heaps */
868         return 1;
869 }
870
871 /***********************************************************************
872  * PROCESS_SuspendOtherThreads
873  */
874
875 void PROCESS_SuspendOtherThreads(void)
876 {
877 #if 0
878     PDB *pdb;
879     THREAD_ENTRY *entry;
880
881     SYSTEM_LOCK();
882
883     pdb = PROCESS_Current();
884     entry = pdb->thread_list->next;
885     for (;;)
886     {
887          if (entry->thread != THREAD_Current() && !THREAD_IsWin16(entry->thread))
888          {
889              HANDLE handle = HANDLE_Alloc( PROCESS_Current(), 
890                                              &entry->thread->header,
891                                              THREAD_ALL_ACCESS, FALSE, -1 );
892              SuspendThread(handle);
893              CloseHandle(handle);
894          }
895          if (entry == pdb->thread_list) break;
896          entry = entry->next;
897     }
898
899     SYSTEM_UNLOCK();
900 #endif
901 }
902
903 /***********************************************************************
904  * PROCESS_ResumeOtherThreads
905  */
906
907 void PROCESS_ResumeOtherThreads(void)
908 {
909 #if 0
910     PDB *pdb;
911     THREAD_ENTRY *entry;
912
913     SYSTEM_LOCK();
914
915     pdb = PROCESS_Current();
916     entry = pdb->thread_list->next;
917     for (;;)
918     {
919          if (entry->thread != THREAD_Current() && !THREAD_IsWin16(entry->thread))
920          {
921              HANDLE handle = HANDLE_Alloc( PROCESS_Current(), 
922                                              &entry->thread->header,
923                                              THREAD_ALL_ACCESS, FALSE, -1 );
924              ResumeThread(handle);
925              CloseHandle(handle);
926          }
927          if (entry == pdb->thread_list) break;
928          entry = entry->next;
929     }
930
931     SYSTEM_UNLOCK();
932 #endif
933 }
934