Implemented new Wine startup sequence, separating startup into
[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 "file.h"
14 #include "global.h"
15 #include "heap.h"
16 #include "task.h"
17 #include "ldt.h"
18 #include "syslevel.h"
19 #include "thread.h"
20 #include "winerror.h"
21 #include "pe_image.h"
22 #include "task.h"
23 #include "server.h"
24 #include "debug.h"
25
26 static BOOL32 PROCESS_Signaled( K32OBJ *obj, DWORD thread_id );
27 static BOOL32 PROCESS_Satisfied( K32OBJ *obj, DWORD thread_id );
28 static void PROCESS_AddWait( K32OBJ *obj, DWORD thread_id );
29 static void PROCESS_RemoveWait( K32OBJ *obj, DWORD thread_id );
30 static void PROCESS_Destroy( K32OBJ *obj );
31
32 const K32OBJ_OPS PROCESS_Ops =
33 {
34     PROCESS_Signaled,    /* signaled */
35     PROCESS_Satisfied,   /* satisfied */
36     PROCESS_AddWait,     /* add_wait */
37     PROCESS_RemoveWait,  /* remove_wait */
38     NULL,                /* read */
39     NULL,                /* write */
40     PROCESS_Destroy      /* destroy */
41 };
42
43 static DWORD PROCESS_InitialProcessID = 0;
44
45
46 /***********************************************************************
47  *           PROCESS_Current
48  */
49 PDB32 *PROCESS_Current(void)
50 {
51     return THREAD_Current()->process;
52 }
53
54 /***********************************************************************
55  *           PROCESS_Initial
56  *
57  * FIXME: This works only while running all processes in the same
58  *        address space (or, at least, the initial process is mapped
59  *        into all address spaces as is KERNEL32 in Windows 95)
60  *
61  */
62 PDB32 *PROCESS_Initial(void)
63 {
64     return PROCESS_IdToPDB( PROCESS_InitialProcessID );
65 }
66
67 /***********************************************************************
68  *           PROCESS_GetPtr
69  *
70  * Get a process from a handle, incrementing the PDB refcount.
71  */
72 PDB32 *PROCESS_GetPtr( HANDLE32 handle, DWORD access, int *server_handle )
73 {
74     return (PDB32 *)HANDLE_GetObjPtr( PROCESS_Current(), handle,
75                                      K32OBJ_PROCESS, access, server_handle );
76 }
77
78
79 /***********************************************************************
80  *           PROCESS_IdToPDB
81  *
82  * Convert a process id to a PDB, making sure it is valid.
83  */
84 PDB32 *PROCESS_IdToPDB( DWORD id )
85 {
86     PDB32 *pdb;
87
88     if (!id) return PROCESS_Current();
89     pdb = PROCESS_ID_TO_PDB( id );
90     if (!K32OBJ_IsValid( &pdb->header, K32OBJ_PROCESS ))
91     {
92         SetLastError( ERROR_INVALID_PARAMETER );
93         return NULL;
94     }
95     return pdb;
96 }
97
98
99
100 /***********************************************************************
101  *           PROCESS_BuildEnvDB
102  *
103  * Build the env DB for the initial process
104  */
105 static BOOL32 PROCESS_BuildEnvDB( PDB32 *pdb )
106 {
107     /* Allocate the env DB (FIXME: should not be on the system heap) */
108
109     if (!(pdb->env_db = HeapAlloc(SystemHeap,HEAP_ZERO_MEMORY,sizeof(ENVDB))))
110         return FALSE;
111     InitializeCriticalSection( &pdb->env_db->section );
112
113     /* Allocate startup info */
114     if (!(pdb->env_db->startup_info = 
115           HeapAlloc( SystemHeap, HEAP_ZERO_MEMORY, sizeof(STARTUPINFO32A) )))
116         return FALSE;
117
118     /* Allocate the standard handles */
119
120     pdb->env_db->hStdin  = FILE_DupUnixHandle( 0 );
121     pdb->env_db->hStdout = FILE_DupUnixHandle( 1 );
122     pdb->env_db->hStderr = FILE_DupUnixHandle( 2 );
123     FILE_SetFileType( pdb->env_db->hStdin,  FILE_TYPE_CHAR );
124     FILE_SetFileType( pdb->env_db->hStdout, FILE_TYPE_CHAR );
125     FILE_SetFileType( pdb->env_db->hStderr, FILE_TYPE_CHAR );
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 BOOL32 PROCESS_InheritEnvDB( PDB32 *pdb, LPCSTR cmd_line, LPCSTR env,
141                                     STARTUPINFO32A *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(STARTUPINFO32A) )))
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
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
176     return TRUE;
177 }
178
179
180 /***********************************************************************
181  *           PROCESS_FreePDB
182  *
183  * Free a PDB and all associated storage.
184  */
185 static void PROCESS_FreePDB( PDB32 *pdb )
186 {
187     pdb->header.type = K32OBJ_UNKNOWN;
188     if (pdb->handle_table) HANDLE_CloseAll( pdb, NULL );
189     ENV_FreeEnvironment( pdb );
190     if (pdb->heap && (pdb->heap != pdb->system_heap)) HeapDestroy( pdb->heap );
191     if (pdb->load_done_evt) K32OBJ_DecCount( pdb->load_done_evt );
192     if (pdb->event) K32OBJ_DecCount( pdb->event );
193     DeleteCriticalSection( &pdb->crit_section );
194     HeapFree( SystemHeap, 0, pdb );
195 }
196
197
198 /***********************************************************************
199  *           PROCESS_CreatePDB
200  *
201  * Allocate and fill a PDB structure.
202  * Runs in the context of the parent process.
203  */
204 static PDB32 *PROCESS_CreatePDB( PDB32 *parent )
205 {
206     PDB32 *pdb = HeapAlloc( SystemHeap, HEAP_ZERO_MEMORY, sizeof(PDB32) );
207
208     if (!pdb) return NULL;
209     pdb->header.type     = K32OBJ_PROCESS;
210     pdb->header.refcount = 1;
211     pdb->exit_code       = 0x103; /* STILL_ACTIVE */
212     pdb->threads         = 1;
213     pdb->running_threads = 1;
214     pdb->ring0_threads   = 1;
215     pdb->system_heap     = SystemHeap;
216     pdb->parent          = parent;
217     pdb->group           = pdb;
218     pdb->priority        = 8;  /* Normal */
219     pdb->heap            = pdb->system_heap;  /* will be changed later on */
220
221     InitializeCriticalSection( &pdb->crit_section );
222
223     /* Allocate the events */
224
225     if (!(pdb->event = EVENT_Create( TRUE, FALSE ))) goto error;
226     if (!(pdb->load_done_evt = EVENT_Create( TRUE, FALSE ))) goto error;
227
228     /* Create the handle table */
229
230     if (!HANDLE_CreateTable( pdb, TRUE )) goto error;
231
232     return pdb;
233
234 error:
235     PROCESS_FreePDB( pdb );
236     return NULL;
237 }
238
239
240 /***********************************************************************
241  *           PROCESS_Init
242  */
243 BOOL32 PROCESS_Init(void)
244 {
245     PDB32 *pdb;
246     THDB *thdb;
247
248     /* Initialize virtual memory management */
249     if (!VIRTUAL_Init()) return FALSE;
250
251     /* Create the system and SEGPTR heaps */
252     if (!(SystemHeap = HeapCreate( HEAP_GROWABLE, 0x10000, 0 ))) return FALSE;
253     if (!(SegptrHeap = HeapCreate( HEAP_WINE_SEGPTR, 0, 0 ))) return FALSE;
254
255     /* Create the initial process and thread structures */
256     if (!(pdb = PROCESS_CreatePDB( NULL ))) return FALSE;
257     if (!(thdb = THREAD_Create( pdb, 0, FALSE, NULL, NULL, NULL, NULL ))) return FALSE;
258     thdb->unix_pid = getpid();
259
260     PROCESS_InitialProcessID = PDB_TO_PROCESS_ID(pdb);
261
262     /* Remember TEB selector of initial process for emergency use */
263     SYSLEVEL_EmergencyTeb = thdb->teb_sel;
264
265     /* Create the environment DB of the first process */
266     if (!PROCESS_BuildEnvDB( pdb )) return FALSE;
267
268     /* Initialize the first thread */
269     if (CLIENT_InitThread()) return FALSE;
270
271     return TRUE;
272 }
273
274
275 /***********************************************************************
276  *           PROCESS_Create
277  *
278  * Create a new process database and associated info.
279  */
280 PDB32 *PROCESS_Create( NE_MODULE *pModule, LPCSTR cmd_line, LPCSTR env,
281                        HINSTANCE16 hInstance, HINSTANCE16 hPrevInstance,
282                        STARTUPINFO32A *startup, PROCESS_INFORMATION *info )
283 {
284     DWORD size, commit;
285     int server_thandle, server_phandle;
286     UINT32 cmdShow = 0;
287     THDB *thdb = NULL;
288     PDB32 *parent = PROCESS_Current();
289     PDB32 *pdb = PROCESS_CreatePDB( parent );
290     TDB *pTask;
291
292     if (!pdb) return NULL;
293     info->hThread = info->hProcess = INVALID_HANDLE_VALUE32;
294
295     /* Create the heap */
296
297     if (pModule->module32)
298     {
299         size  = PE_HEADER(pModule->module32)->OptionalHeader.SizeOfHeapReserve;
300         commit = PE_HEADER(pModule->module32)->OptionalHeader.SizeOfHeapCommit;
301     }
302     else
303     {
304         size = 0x10000;
305         commit = 0;
306         pdb->flags |= PDB32_WIN16_PROC;  /* This is a Win16 process */
307     }
308     if (!(pdb->heap = HeapCreate( HEAP_GROWABLE, size, commit ))) goto error;
309     pdb->heap_list = pdb->heap;
310
311     /* Inherit the env DB from the parent */
312
313     if (!PROCESS_InheritEnvDB( pdb, cmd_line, env, startup )) goto error;
314
315     /* Create the main thread */
316
317     if (pModule->module32)
318         size = PE_HEADER(pModule->module32)->OptionalHeader.SizeOfStackReserve;
319     else
320         size = 0;
321     if (!(thdb = THREAD_Create( pdb, size, FALSE, &server_thandle, &server_phandle,
322                                 NULL, NULL ))) goto error;
323     if ((info->hThread = HANDLE_Alloc( parent, &thdb->header, THREAD_ALL_ACCESS,
324                                        FALSE, server_thandle )) == INVALID_HANDLE_VALUE32)
325         goto error;
326     if ((info->hProcess = HANDLE_Alloc( parent, &pdb->header, PROCESS_ALL_ACCESS,
327                                         FALSE, server_phandle )) == INVALID_HANDLE_VALUE32)
328         goto error;
329     info->dwProcessId = PDB_TO_PROCESS_ID(pdb);
330     info->dwThreadId  = THDB_TO_THREAD_ID(thdb);
331
332 #if 0
333     thdb->unix_pid = getpid(); /* FIXME: wrong here ... */
334 #else
335     /* All Win16 'threads' have the same unix_pid, no matter by which thread
336        they were created ! */
337     pTask = (TDB *)GlobalLock16( parent->task );
338     thdb->unix_pid = pTask? pTask->thdb->unix_pid : THREAD_Current()->unix_pid;
339 #endif
340
341     /* Create a Win16 task for this process */
342
343     if (startup->dwFlags & STARTF_USESHOWWINDOW)
344         cmdShow = startup->wShowWindow;
345
346     pdb->task = TASK_Create( thdb, pModule, hInstance, hPrevInstance, cmdShow);
347     if (!pdb->task) goto error;
348
349
350     /* Map system DLLs into this process (from initial process) */
351     /* FIXME: this is a hack */
352     pdb->modref_list = PROCESS_Initial()->modref_list;
353     
354
355     return pdb;
356
357 error:
358     if (info->hThread != INVALID_HANDLE_VALUE32) CloseHandle( info->hThread );
359     if (info->hProcess != INVALID_HANDLE_VALUE32) CloseHandle( info->hProcess );
360     if (thdb) K32OBJ_DecCount( &thdb->header );
361     PROCESS_FreePDB( pdb );
362     return NULL;
363 }
364
365
366 /***********************************************************************
367  *           PROCESS_Signaled
368  */
369 static BOOL32 PROCESS_Signaled( K32OBJ *obj, DWORD thread_id )
370 {
371     PDB32 *pdb = (PDB32 *)obj;
372     assert( obj->type == K32OBJ_PROCESS );
373     return K32OBJ_OPS( pdb->event )->signaled( pdb->event, thread_id );
374 }
375
376
377 /***********************************************************************
378  *           PROCESS_Satisfied
379  *
380  * Wait on this object has been satisfied.
381  */
382 static BOOL32 PROCESS_Satisfied( K32OBJ *obj, DWORD thread_id )
383 {
384     PDB32 *pdb = (PDB32 *)obj;
385     assert( obj->type == K32OBJ_PROCESS );
386     return K32OBJ_OPS( pdb->event )->satisfied( pdb->event, thread_id );
387 }
388
389
390 /***********************************************************************
391  *           PROCESS_AddWait
392  *
393  * Add thread to object wait queue.
394  */
395 static void PROCESS_AddWait( K32OBJ *obj, DWORD thread_id )
396 {
397     PDB32 *pdb = (PDB32 *)obj;
398     assert( obj->type == K32OBJ_PROCESS );
399     return K32OBJ_OPS( pdb->event )->add_wait( pdb->event, thread_id );
400 }
401
402
403 /***********************************************************************
404  *           PROCESS_RemoveWait
405  *
406  * Remove thread from object wait queue.
407  */
408 static void PROCESS_RemoveWait( K32OBJ *obj, DWORD thread_id )
409 {
410     PDB32 *pdb = (PDB32 *)obj;
411     assert( obj->type == K32OBJ_PROCESS );
412     return K32OBJ_OPS( pdb->event )->remove_wait( pdb->event, thread_id );
413 }
414
415
416 /***********************************************************************
417  *           PROCESS_Destroy
418  */
419 static void PROCESS_Destroy( K32OBJ *ptr )
420 {
421     PDB32 *pdb = (PDB32 *)ptr;
422     assert( ptr->type == K32OBJ_PROCESS );
423
424     /* Free everything */
425
426     ptr->type = K32OBJ_UNKNOWN;
427     PROCESS_FreePDB( pdb );
428 }
429
430
431 /***********************************************************************
432  *           ExitProcess   (KERNEL32.100)
433  */
434 void WINAPI ExitProcess( DWORD status )
435 {
436     PDB32 *pdb = PROCESS_Current();
437     TDB *pTask = (TDB *)GlobalLock16( pdb->task );
438     if ( pTask ) pTask->nEvents++;
439
440     if ( pTask && pTask->thdb != THREAD_Current() )
441         ExitThread( status );
442
443     SYSTEM_LOCK();
444     /* FIXME: should kill all running threads of this process */
445     pdb->exit_code = status;
446     EVENT_Set( pdb->event );
447     if (pdb->console) FreeConsole();
448     SYSTEM_UNLOCK();
449
450     __RESTORE_ES;  /* Necessary for Pietrek's showseh example program */
451     TASK_KillCurrentTask( status );
452 }
453
454
455 /******************************************************************************
456  *           TerminateProcess   (KERNEL32.684)
457  */
458 BOOL32 WINAPI TerminateProcess( HANDLE32 handle, DWORD exit_code )
459 {
460     int server_handle;
461     BOOL32 ret;
462     PDB32 *pdb = PROCESS_GetPtr( handle, PROCESS_TERMINATE, &server_handle );
463     if (!pdb) return FALSE;
464     ret = !CLIENT_TerminateProcess( server_handle, exit_code );
465     K32OBJ_DecCount( &pdb->header );
466     return ret;
467 }
468
469 /***********************************************************************
470  *           GetCurrentProcess   (KERNEL32.198)
471  */
472 HANDLE32 WINAPI GetCurrentProcess(void)
473 {
474     return CURRENT_PROCESS_PSEUDOHANDLE;
475 }
476
477
478 /*********************************************************************
479  *           OpenProcess   (KERNEL32.543)
480  */
481 HANDLE32 WINAPI OpenProcess( DWORD access, BOOL32 inherit, DWORD id )
482 {
483     int server_handle;
484     PDB32 *pdb = PROCESS_ID_TO_PDB(id);
485     if (!K32OBJ_IsValid( &pdb->header, K32OBJ_PROCESS ))
486     {
487         SetLastError( ERROR_INVALID_HANDLE );
488         return 0;
489     }
490     if ((server_handle = CLIENT_OpenProcess( pdb->server_pid, access, inherit )) == -1)
491     {
492         SetLastError( ERROR_INVALID_HANDLE );
493         return 0;
494     }
495     return HANDLE_Alloc( PROCESS_Current(), &pdb->header, access,
496                          inherit, server_handle );
497 }                             
498
499
500 /***********************************************************************
501  *           GetCurrentProcessId   (KERNEL32.199)
502  */
503 DWORD WINAPI GetCurrentProcessId(void)
504 {
505     PDB32 *pdb = PROCESS_Current();
506     return PDB_TO_PROCESS_ID( pdb );
507 }
508
509
510 /***********************************************************************
511  *           GetProcessHeap    (KERNEL32.259)
512  */
513 HANDLE32 WINAPI GetProcessHeap(void)
514 {
515     PDB32 *pdb = PROCESS_Current();
516     return pdb->heap ? pdb->heap : SystemHeap;
517 }
518
519
520 /***********************************************************************
521  *           GetThreadLocale    (KERNEL32.295)
522  */
523 LCID WINAPI GetThreadLocale(void)
524 {
525     return PROCESS_Current()->locale;
526 }
527
528
529 /***********************************************************************
530  *           SetPriorityClass   (KERNEL32.503)
531  */
532 BOOL32 WINAPI SetPriorityClass( HANDLE32 hprocess, DWORD priorityclass )
533 {
534     PDB32 *pdb = PROCESS_GetPtr( hprocess, PROCESS_SET_INFORMATION, NULL );
535     if (!pdb) return FALSE;
536     switch (priorityclass)
537     {
538     case NORMAL_PRIORITY_CLASS:
539         pdb->priority = 0x00000008;
540         break;
541     case IDLE_PRIORITY_CLASS:
542         pdb->priority = 0x00000004;
543         break;
544     case HIGH_PRIORITY_CLASS:
545         pdb->priority = 0x0000000d;
546         break;
547     case REALTIME_PRIORITY_CLASS:
548         pdb->priority = 0x00000018;
549         break;
550     default:
551         WARN(process,"Unknown priority class %ld\n",priorityclass);
552         break;
553     }
554     K32OBJ_DecCount( &pdb->header );
555     return TRUE;
556 }
557
558
559 /***********************************************************************
560  *           GetPriorityClass   (KERNEL32.250)
561  */
562 DWORD WINAPI GetPriorityClass(HANDLE32 hprocess)
563 {
564     PDB32 *pdb = PROCESS_GetPtr( hprocess, PROCESS_QUERY_INFORMATION, NULL );
565     DWORD ret = 0;
566     if (pdb)
567     {
568         switch (pdb->priority)
569         {
570         case 0x00000008:
571             ret = NORMAL_PRIORITY_CLASS;
572             break;
573         case 0x00000004:
574             ret = IDLE_PRIORITY_CLASS;
575             break;
576         case 0x0000000d:
577             ret = HIGH_PRIORITY_CLASS;
578             break;
579         case 0x00000018:
580             ret = REALTIME_PRIORITY_CLASS;
581             break;
582         default:
583             WARN(process,"Unknown priority %ld\n",pdb->priority);
584         }
585         K32OBJ_DecCount( &pdb->header );
586     }
587     return ret;
588 }
589
590
591 /***********************************************************************
592  *           GetStdHandle    (KERNEL32.276)
593  *
594  * FIXME: These should be allocated when a console is created, or inherited
595  *        from the parent.
596  */
597 HANDLE32 WINAPI GetStdHandle( DWORD std_handle )
598 {
599     HFILE32 hFile;
600     int fd;
601     PDB32 *pdb = PROCESS_Current();
602
603     switch(std_handle)
604     {
605     case STD_INPUT_HANDLE:
606         if (pdb->env_db->hStdin) return pdb->env_db->hStdin;
607         fd = 0;
608         break;
609     case STD_OUTPUT_HANDLE:
610         if (pdb->env_db->hStdout) return pdb->env_db->hStdout;
611         fd = 1;
612         break;
613     case STD_ERROR_HANDLE:
614         if (pdb->env_db->hStderr) return pdb->env_db->hStderr;
615         fd = 2;
616         break;
617     default:
618         SetLastError( ERROR_INVALID_PARAMETER );
619         return INVALID_HANDLE_VALUE32;
620     }
621     hFile = FILE_DupUnixHandle( fd );
622     if (hFile != HFILE_ERROR32)
623     {
624         FILE_SetFileType( hFile, FILE_TYPE_CHAR );
625         switch(std_handle)
626         {
627         case STD_INPUT_HANDLE:  pdb->env_db->hStdin  = hFile; break;
628         case STD_OUTPUT_HANDLE: pdb->env_db->hStdout = hFile; break;
629         case STD_ERROR_HANDLE:  pdb->env_db->hStderr = hFile; break;
630         }
631     }
632     return hFile;
633 }
634
635
636 /***********************************************************************
637  *           SetStdHandle    (KERNEL32.506)
638  */
639 BOOL32 WINAPI SetStdHandle( DWORD std_handle, HANDLE32 handle )
640 {
641     PDB32 *pdb = PROCESS_Current();
642     /* FIXME: should we close the previous handle? */
643     switch(std_handle)
644     {
645     case STD_INPUT_HANDLE:
646         pdb->env_db->hStdin = handle;
647         return TRUE;
648     case STD_OUTPUT_HANDLE:
649         pdb->env_db->hStdout = handle;
650         return TRUE;
651     case STD_ERROR_HANDLE:
652         pdb->env_db->hStderr = handle;
653         return TRUE;
654     }
655     SetLastError( ERROR_INVALID_PARAMETER );
656     return FALSE;
657 }
658
659 /***********************************************************************
660  *           GetProcessVersion    (KERNEL32)
661  */
662 DWORD WINAPI GetProcessVersion( DWORD processid )
663 {
664     TDB *pTask;
665     PDB32 *pdb = PROCESS_IdToPDB( processid );
666
667     if (!pdb) return 0;
668     if (!(pTask = (TDB *)GlobalLock16( pdb->task ))) return 0;
669     return (pTask->version&0xff) | (((pTask->version >>8) & 0xff)<<16);
670 }
671
672 /***********************************************************************
673  *           GetProcessFlags    (KERNEL32)
674  */
675 DWORD WINAPI GetProcessFlags( DWORD processid )
676 {
677     PDB32 *pdb = PROCESS_IdToPDB( processid );
678     if (!pdb) return 0;
679     return pdb->flags;
680 }
681
682 /***********************************************************************
683  *              SetProcessWorkingSetSize        [KERNEL32.662]
684  * Sets the min/max working set sizes for a specified process.
685  *
686  * PARAMS
687  *    hProcess [I] Handle to the process of interest
688  *    minset   [I] Specifies minimum working set size
689  *    maxset   [I] Specifies maximum working set size
690  *
691  * RETURNS  STD
692  */
693 BOOL32 WINAPI SetProcessWorkingSetSize(HANDLE32 hProcess,DWORD minset,
694                                        DWORD maxset)
695 {
696     FIXME(process,"(0x%08x,%ld,%ld): stub - harmless\n",hProcess,minset,maxset);
697     if(( minset == -1) && (maxset == -1)) {
698         /* Trim the working set to zero */
699         /* Swap the process out of physical RAM */
700     }
701     return TRUE;
702 }
703
704 /***********************************************************************
705  *           GetProcessWorkingSetSize    (KERNEL32)
706  */
707 BOOL32 WINAPI GetProcessWorkingSetSize(HANDLE32 hProcess,LPDWORD minset,
708                                        LPDWORD maxset)
709 {
710         FIXME(process,"(0x%08x,%p,%p): stub\n",hProcess,minset,maxset);
711         /* 32 MB working set size */
712         if (minset) *minset = 32*1024*1024;
713         if (maxset) *maxset = 32*1024*1024;
714         return TRUE;
715 }
716
717 /***********************************************************************
718  *           SetProcessShutdownParameters    (KERNEL32)
719  */
720 BOOL32 WINAPI SetProcessShutdownParameters(DWORD level,DWORD flags)
721 {
722     FIXME(process,"(%ld,0x%08lx): stub\n",level,flags);
723     return TRUE;
724 }
725
726 /***********************************************************************
727  *           SetProcessPriorityBoost    (KERNEL32)
728  */
729 BOOL32 WINAPI SetProcessPriorityBoost(HANDLE32 hprocess,BOOL32 disableboost)
730 {
731     FIXME(process,"(%d,%d): stub\n",hprocess,disableboost);
732     /* Say we can do it. I doubt the program will notice that we don't. */
733     return TRUE;
734 }
735
736 /***********************************************************************
737  *           ReadProcessMemory                  (KERNEL32)
738  * FIXME: check this, if we ever run win32 binaries in different addressspaces
739  *        ... and add a sizecheck
740  */
741 BOOL32 WINAPI ReadProcessMemory( HANDLE32 hProcess, LPCVOID lpBaseAddress,
742                                  LPVOID lpBuffer, DWORD nSize,
743                                  LPDWORD lpNumberOfBytesRead )
744 {
745         memcpy(lpBuffer,lpBaseAddress,nSize);
746         if (lpNumberOfBytesRead) *lpNumberOfBytesRead = nSize;
747         return TRUE;
748 }
749
750 /***********************************************************************
751  *           WriteProcessMemory                 (KERNEL32)
752  * FIXME: check this, if we ever run win32 binaries in different addressspaces
753  *        ... and add a sizecheck
754  */
755 BOOL32 WINAPI WriteProcessMemory(HANDLE32 hProcess, LPVOID lpBaseAddress,
756                                  LPVOID lpBuffer, DWORD nSize,
757                                  LPDWORD lpNumberOfBytesWritten )
758 {
759         memcpy(lpBaseAddress,lpBuffer,nSize);
760         if (lpNumberOfBytesWritten) *lpNumberOfBytesWritten = nSize;
761         return TRUE;
762 }
763
764 /***********************************************************************
765  *           ConvertToGlobalHandle              (KERNEL32)
766  */
767 HANDLE32 WINAPI ConvertToGlobalHandle(HANDLE32 hSrc)
768 {
769     HANDLE32 hProcessInit, hDest;
770
771     /* Get a handle to the initial process */
772     hProcessInit = OpenProcess( PROCESS_ALL_ACCESS, FALSE, PROCESS_InitialProcessID );
773
774     /* Duplicate the handle into the initial process */
775     if ( !DuplicateHandle( GetCurrentProcess(), hSrc, hProcessInit, &hDest,
776                            0, FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE ) )
777         hDest = 0;
778
779     /* Close initial process handle */
780     CloseHandle( hProcessInit );
781
782     /* Return obfuscated global handle */
783     return hDest? HANDLE_LOCAL_TO_GLOBAL( hDest ) : 0;
784 }
785
786 /***********************************************************************
787  *           RegisterServiceProcess             (KERNEL, KERNEL32)
788  *
789  * A service process calls this function to ensure that it continues to run
790  * even after a user logged off.
791  */
792 DWORD WINAPI RegisterServiceProcess(DWORD dwProcessId, DWORD dwType)
793 {
794         /* I don't think that Wine needs to do anything in that function */
795         return 1; /* success */
796 }
797
798 /***********************************************************************
799  * GetExitCodeProcess [KERNEL32.325]
800  *
801  * Gets termination status of specified process
802  * 
803  * RETURNS
804  *   Success: TRUE
805  *   Failure: FALSE
806  * 
807  * FIXME
808  *   Should call SetLastError (but doesn't).
809  */
810 BOOL32 WINAPI GetExitCodeProcess(
811     HANDLE32 hProcess,  /* [I] handle to the process */
812     LPDWORD lpExitCode) /* [O] address to receive termination status */
813 {
814     PDB32 *process;
815     int server_handle;
816     struct get_process_info_reply info;
817
818     if (!(process = PROCESS_GetPtr( hProcess, PROCESS_QUERY_INFORMATION,
819                                     &server_handle )))
820         return FALSE;
821     if (server_handle != -1)
822     {
823         CLIENT_GetProcessInfo( server_handle, &info );
824         if (lpExitCode) *lpExitCode = info.exit_code;
825     }
826     else if (lpExitCode) *lpExitCode = process->exit_code;
827     K32OBJ_DecCount( &process->header );
828     return TRUE;
829 }
830
831 /***********************************************************************
832  * GetProcessHeaps [KERNEL32.376]
833  */
834 DWORD WINAPI GetProcessHeaps(DWORD nrofheaps,HANDLE32 *heaps) {
835         FIXME(win32,"(%ld,%p), incomplete implementation.\n",nrofheaps,heaps);
836
837         if (nrofheaps) {
838                 heaps[0] = GetProcessHeap();
839                 /* ... probably SystemHeap too ? */
840                 return 1;
841         }
842         /* number of available heaps */
843         return 1;
844 }
845
846 /***********************************************************************
847  * PROCESS_SuspendOtherThreads
848  */
849
850 void PROCESS_SuspendOtherThreads(void)
851 {
852     PDB32 *pdb;
853     THREAD_ENTRY *entry;
854
855     SYSTEM_LOCK();
856
857     pdb = PROCESS_Current();
858     entry = pdb->thread_list->next;
859     for (;;)
860     {
861          if (entry->thread != THREAD_Current() && !THREAD_IsWin16(entry->thread))
862          {
863              HANDLE32 handle = HANDLE_Alloc( PROCESS_Current(), 
864                                              &entry->thread->header,
865                                              THREAD_ALL_ACCESS, FALSE, -1 );
866              SuspendThread(handle);
867              CloseHandle(handle);
868          }
869          if (entry == pdb->thread_list) break;
870          entry = entry->next;
871     }
872
873     SYSTEM_UNLOCK();
874 }
875
876 /***********************************************************************
877  * PROCESS_ResumeOtherThreads
878  */
879
880 void PROCESS_ResumeOtherThreads(void)
881 {
882     PDB32 *pdb;
883     THREAD_ENTRY *entry;
884
885     SYSTEM_LOCK();
886
887     pdb = PROCESS_Current();
888     entry = pdb->thread_list->next;
889     for (;;)
890     {
891          if (entry->thread != THREAD_Current() && !THREAD_IsWin16(entry->thread))
892          {
893              HANDLE32 handle = HANDLE_Alloc( PROCESS_Current(), 
894                                              &entry->thread->header,
895                                              THREAD_ALL_ACCESS, FALSE, -1 );
896              ResumeThread(handle);
897              CloseHandle(handle);
898          }
899          if (entry == pdb->thread_list) break;
900          entry = entry->next;
901     }
902
903     SYSTEM_UNLOCK();
904 }
905
906 BOOL32 WINAPI Process32First(HANDLE32 hSnapshot, LPPROCESSENTRY32 lppe)
907 {
908   FIXME (process, "(0x%08lx,0x%08lx), stub!\n", hSnapshot, lppe);
909   SetLastError (ERROR_NO_MORE_FILES);
910   return FALSE;
911 }
912
913 BOOL32 WINAPI Process32Next(HANDLE32 hSnapshot, LPPROCESSENTRY32 lppe)
914 {
915   FIXME (process, "(0x%08lx,0x%08lx), stub!\n", hSnapshot, lppe);
916   SetLastError (ERROR_NO_MORE_FILES);
917   return FALSE;
918 }
919