Enhanced OABuildVersion() to return different version values for
[wine/multimedia.git] / scheduler / process.c
blob19d7503b78ae107df2e1bd776d75e8371f7b064b
1 /*
2 * Win32 processes
4 * Copyright 1996, 1998 Alexandre Julliard
5 */
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 #include "toolhelp.h"
27 static BOOL32 PROCESS_Signaled( K32OBJ *obj, DWORD thread_id );
28 static BOOL32 PROCESS_Satisfied( K32OBJ *obj, DWORD thread_id );
29 static void PROCESS_AddWait( K32OBJ *obj, DWORD thread_id );
30 static void PROCESS_RemoveWait( K32OBJ *obj, DWORD thread_id );
31 static void PROCESS_Destroy( K32OBJ *obj );
33 const K32OBJ_OPS PROCESS_Ops =
35 PROCESS_Signaled, /* signaled */
36 PROCESS_Satisfied, /* satisfied */
37 PROCESS_AddWait, /* add_wait */
38 PROCESS_RemoveWait, /* remove_wait */
39 NULL, /* read */
40 NULL, /* write */
41 PROCESS_Destroy /* destroy */
44 static DWORD PROCESS_InitialProcessID = 0;
47 /***********************************************************************
48 * PROCESS_Current
50 PDB32 *PROCESS_Current(void)
52 return THREAD_Current()->process;
55 /***********************************************************************
56 * PROCESS_Initial
58 * FIXME: This works only while running all processes in the same
59 * address space (or, at least, the initial process is mapped
60 * into all address spaces as is KERNEL32 in Windows 95)
63 PDB32 *PROCESS_Initial(void)
65 return PROCESS_IdToPDB( PROCESS_InitialProcessID );
68 /***********************************************************************
69 * PROCESS_GetPtr
71 * Get a process from a handle, incrementing the PDB refcount.
73 PDB32 *PROCESS_GetPtr( HANDLE32 handle, DWORD access, int *server_handle )
75 return (PDB32 *)HANDLE_GetObjPtr( PROCESS_Current(), handle,
76 K32OBJ_PROCESS, access, server_handle );
80 /***********************************************************************
81 * PROCESS_IdToPDB
83 * Convert a process id to a PDB, making sure it is valid.
85 PDB32 *PROCESS_IdToPDB( DWORD id )
87 PDB32 *pdb;
89 if (!id) return PROCESS_Current();
90 pdb = PROCESS_ID_TO_PDB( id );
91 if (!K32OBJ_IsValid( &pdb->header, K32OBJ_PROCESS ))
93 SetLastError( ERROR_INVALID_PARAMETER );
94 return NULL;
96 return pdb;
101 /***********************************************************************
102 * PROCESS_BuildEnvDB
104 * Build the env DB for the initial process
106 static BOOL32 PROCESS_BuildEnvDB( PDB32 *pdb )
108 /* Allocate the env DB (FIXME: should not be on the system heap) */
110 if (!(pdb->env_db = HeapAlloc(SystemHeap,HEAP_ZERO_MEMORY,sizeof(ENVDB))))
111 return FALSE;
112 InitializeCriticalSection( &pdb->env_db->section );
114 /* Allocate startup info */
115 if (!(pdb->env_db->startup_info =
116 HeapAlloc( SystemHeap, HEAP_ZERO_MEMORY, sizeof(STARTUPINFO32A) )))
117 return FALSE;
119 /* Allocate the standard handles */
121 pdb->env_db->hStdin = FILE_DupUnixHandle( 0 );
122 pdb->env_db->hStdout = FILE_DupUnixHandle( 1 );
123 pdb->env_db->hStderr = FILE_DupUnixHandle( 2 );
124 FILE_SetFileType( pdb->env_db->hStdin, FILE_TYPE_CHAR );
125 FILE_SetFileType( pdb->env_db->hStdout, FILE_TYPE_CHAR );
126 FILE_SetFileType( pdb->env_db->hStderr, FILE_TYPE_CHAR );
128 /* Build the command-line */
130 pdb->env_db->cmd_line = HEAP_strdupA( SystemHeap, 0, "kernel32" );
132 /* Build the environment strings */
134 return ENV_BuildEnvironment( pdb );
138 /***********************************************************************
139 * PROCESS_InheritEnvDB
141 static BOOL32 PROCESS_InheritEnvDB( PDB32 *pdb, LPCSTR cmd_line, LPCSTR env,
142 STARTUPINFO32A *startup )
144 if (!(pdb->env_db = HeapAlloc(pdb->heap, HEAP_ZERO_MEMORY, sizeof(ENVDB))))
145 return FALSE;
146 InitializeCriticalSection( &pdb->env_db->section );
148 /* Copy the parent environment */
150 if (!ENV_InheritEnvironment( pdb, env )) return FALSE;
152 /* Copy the command line */
154 if (!(pdb->env_db->cmd_line = HEAP_strdupA( pdb->heap, 0, cmd_line )))
155 return FALSE;
157 /* Remember startup info */
158 if (!(pdb->env_db->startup_info =
159 HeapAlloc( pdb->heap, HEAP_ZERO_MEMORY, sizeof(STARTUPINFO32A) )))
160 return FALSE;
161 *pdb->env_db->startup_info = *startup;
163 /* Inherit the standard handles */
164 if (pdb->env_db->startup_info->dwFlags & STARTF_USESTDHANDLES)
166 pdb->env_db->hStdin = pdb->env_db->startup_info->hStdInput;
167 pdb->env_db->hStdout = pdb->env_db->startup_info->hStdOutput;
168 pdb->env_db->hStderr = pdb->env_db->startup_info->hStdError;
170 else
172 pdb->env_db->hStdin = pdb->parent->env_db->hStdin;
173 pdb->env_db->hStdout = pdb->parent->env_db->hStdout;
174 pdb->env_db->hStderr = pdb->parent->env_db->hStderr;
177 return TRUE;
181 /***********************************************************************
182 * PROCESS_FreePDB
184 * Free a PDB and all associated storage.
186 static void PROCESS_FreePDB( PDB32 *pdb )
188 pdb->header.type = K32OBJ_UNKNOWN;
189 if (pdb->handle_table) HANDLE_CloseAll( pdb, NULL );
190 ENV_FreeEnvironment( pdb );
191 if (pdb->heap && (pdb->heap != pdb->system_heap)) HeapDestroy( pdb->heap );
192 if (pdb->load_done_evt) K32OBJ_DecCount( pdb->load_done_evt );
193 if (pdb->event) K32OBJ_DecCount( pdb->event );
194 DeleteCriticalSection( &pdb->crit_section );
195 HeapFree( SystemHeap, 0, pdb );
199 /***********************************************************************
200 * PROCESS_CreatePDB
202 * Allocate and fill a PDB structure.
203 * Runs in the context of the parent process.
205 static PDB32 *PROCESS_CreatePDB( PDB32 *parent )
207 PDB32 *pdb = HeapAlloc( SystemHeap, HEAP_ZERO_MEMORY, sizeof(PDB32) );
209 if (!pdb) return NULL;
210 pdb->header.type = K32OBJ_PROCESS;
211 pdb->header.refcount = 1;
212 pdb->exit_code = 0x103; /* STILL_ACTIVE */
213 pdb->threads = 1;
214 pdb->running_threads = 1;
215 pdb->ring0_threads = 1;
216 pdb->system_heap = SystemHeap;
217 pdb->parent = parent;
218 pdb->group = pdb;
219 pdb->priority = 8; /* Normal */
220 pdb->heap = pdb->system_heap; /* will be changed later on */
222 InitializeCriticalSection( &pdb->crit_section );
224 /* Allocate the events */
226 if (!(pdb->event = EVENT_Create( TRUE, FALSE ))) goto error;
227 if (!(pdb->load_done_evt = EVENT_Create( TRUE, FALSE ))) goto error;
229 /* Create the handle table */
231 if (!HANDLE_CreateTable( pdb, TRUE )) goto error;
233 return pdb;
235 error:
236 PROCESS_FreePDB( pdb );
237 return NULL;
241 /***********************************************************************
242 * PROCESS_Init
244 BOOL32 PROCESS_Init(void)
246 PDB32 *pdb;
247 THDB *thdb;
249 /* Initialize virtual memory management */
250 if (!VIRTUAL_Init()) return FALSE;
252 /* Create the system and SEGPTR heaps */
253 if (!(SystemHeap = HeapCreate( HEAP_GROWABLE, 0x10000, 0 ))) return FALSE;
254 if (!(SegptrHeap = HeapCreate( HEAP_WINE_SEGPTR, 0, 0 ))) return FALSE;
256 /* Create the initial process and thread structures */
257 if (!(pdb = PROCESS_CreatePDB( NULL ))) return FALSE;
258 if (!(thdb = THREAD_Create( pdb, 0, FALSE, NULL, NULL, NULL, NULL ))) return FALSE;
259 thdb->unix_pid = getpid();
261 PROCESS_InitialProcessID = PDB_TO_PROCESS_ID(pdb);
263 /* Remember TEB selector of initial process for emergency use */
264 SYSLEVEL_EmergencyTeb = thdb->teb_sel;
266 /* Create the environment DB of the first process */
267 if (!PROCESS_BuildEnvDB( pdb )) return FALSE;
269 /* Initialize the first thread */
270 if (CLIENT_InitThread()) return FALSE;
272 return TRUE;
276 /***********************************************************************
277 * PROCESS_Create
279 * Create a new process database and associated info.
281 PDB32 *PROCESS_Create( NE_MODULE *pModule, LPCSTR cmd_line, LPCSTR env,
282 HINSTANCE16 hInstance, HINSTANCE16 hPrevInstance,
283 STARTUPINFO32A *startup, PROCESS_INFORMATION *info )
285 DWORD size, commit;
286 int server_thandle, server_phandle;
287 UINT32 cmdShow = 0;
288 THDB *thdb = NULL;
289 PDB32 *parent = PROCESS_Current();
290 PDB32 *pdb = PROCESS_CreatePDB( parent );
291 TDB *pTask;
293 if (!pdb) return NULL;
294 info->hThread = info->hProcess = INVALID_HANDLE_VALUE32;
296 /* Create the heap */
298 if (pModule->module32)
300 size = PE_HEADER(pModule->module32)->OptionalHeader.SizeOfHeapReserve;
301 commit = PE_HEADER(pModule->module32)->OptionalHeader.SizeOfHeapCommit;
303 else
305 size = 0x10000;
306 commit = 0;
307 pdb->flags |= PDB32_WIN16_PROC; /* This is a Win16 process */
309 if (!(pdb->heap = HeapCreate( HEAP_GROWABLE, size, commit ))) goto error;
310 pdb->heap_list = pdb->heap;
312 /* Inherit the env DB from the parent */
314 if (!PROCESS_InheritEnvDB( pdb, cmd_line, env, startup )) goto error;
316 /* Create the main thread */
318 if (pModule->module32)
319 size = PE_HEADER(pModule->module32)->OptionalHeader.SizeOfStackReserve;
320 else
321 size = 0;
322 if (!(thdb = THREAD_Create( pdb, size, FALSE, &server_thandle, &server_phandle,
323 NULL, NULL ))) goto error;
324 if ((info->hThread = HANDLE_Alloc( parent, &thdb->header, THREAD_ALL_ACCESS,
325 FALSE, server_thandle )) == INVALID_HANDLE_VALUE32)
326 goto error;
327 if ((info->hProcess = HANDLE_Alloc( parent, &pdb->header, PROCESS_ALL_ACCESS,
328 FALSE, server_phandle )) == INVALID_HANDLE_VALUE32)
329 goto error;
330 info->dwProcessId = PDB_TO_PROCESS_ID(pdb);
331 info->dwThreadId = THDB_TO_THREAD_ID(thdb);
333 #if 0
334 thdb->unix_pid = getpid(); /* FIXME: wrong here ... */
335 #else
336 /* All Win16 'threads' have the same unix_pid, no matter by which thread
337 they were created ! */
338 pTask = (TDB *)GlobalLock16( parent->task );
339 thdb->unix_pid = pTask? pTask->thdb->unix_pid : THREAD_Current()->unix_pid;
340 #endif
342 /* Create a Win16 task for this process */
344 if (startup->dwFlags & STARTF_USESHOWWINDOW)
345 cmdShow = startup->wShowWindow;
347 pdb->task = TASK_Create( thdb, pModule, hInstance, hPrevInstance, cmdShow);
348 if (!pdb->task) goto error;
351 /* Map system DLLs into this process (from initial process) */
352 /* FIXME: this is a hack */
353 pdb->modref_list = PROCESS_Initial()->modref_list;
356 return pdb;
358 error:
359 if (info->hThread != INVALID_HANDLE_VALUE32) CloseHandle( info->hThread );
360 if (info->hProcess != INVALID_HANDLE_VALUE32) CloseHandle( info->hProcess );
361 if (thdb) K32OBJ_DecCount( &thdb->header );
362 PROCESS_FreePDB( pdb );
363 return NULL;
367 /***********************************************************************
368 * PROCESS_Signaled
370 static BOOL32 PROCESS_Signaled( K32OBJ *obj, DWORD thread_id )
372 PDB32 *pdb = (PDB32 *)obj;
373 assert( obj->type == K32OBJ_PROCESS );
374 return K32OBJ_OPS( pdb->event )->signaled( pdb->event, thread_id );
378 /***********************************************************************
379 * PROCESS_Satisfied
381 * Wait on this object has been satisfied.
383 static BOOL32 PROCESS_Satisfied( K32OBJ *obj, DWORD thread_id )
385 PDB32 *pdb = (PDB32 *)obj;
386 assert( obj->type == K32OBJ_PROCESS );
387 return K32OBJ_OPS( pdb->event )->satisfied( pdb->event, thread_id );
391 /***********************************************************************
392 * PROCESS_AddWait
394 * Add thread to object wait queue.
396 static void PROCESS_AddWait( K32OBJ *obj, DWORD thread_id )
398 PDB32 *pdb = (PDB32 *)obj;
399 assert( obj->type == K32OBJ_PROCESS );
400 return K32OBJ_OPS( pdb->event )->add_wait( pdb->event, thread_id );
404 /***********************************************************************
405 * PROCESS_RemoveWait
407 * Remove thread from object wait queue.
409 static void PROCESS_RemoveWait( K32OBJ *obj, DWORD thread_id )
411 PDB32 *pdb = (PDB32 *)obj;
412 assert( obj->type == K32OBJ_PROCESS );
413 return K32OBJ_OPS( pdb->event )->remove_wait( pdb->event, thread_id );
417 /***********************************************************************
418 * PROCESS_Destroy
420 static void PROCESS_Destroy( K32OBJ *ptr )
422 PDB32 *pdb = (PDB32 *)ptr;
423 assert( ptr->type == K32OBJ_PROCESS );
425 /* Free everything */
427 ptr->type = K32OBJ_UNKNOWN;
428 PROCESS_FreePDB( pdb );
432 /***********************************************************************
433 * ExitProcess (KERNEL32.100)
435 void WINAPI ExitProcess( DWORD status )
437 PDB32 *pdb = PROCESS_Current();
438 TDB *pTask = (TDB *)GlobalLock16( pdb->task );
439 if ( pTask ) pTask->nEvents++;
441 if ( pTask && pTask->thdb != THREAD_Current() )
442 ExitThread( status );
444 SYSTEM_LOCK();
445 /* FIXME: should kill all running threads of this process */
446 pdb->exit_code = status;
447 EVENT_Set( pdb->event );
448 if (pdb->console) FreeConsole();
449 SYSTEM_UNLOCK();
451 __RESTORE_ES; /* Necessary for Pietrek's showseh example program */
452 TASK_KillCurrentTask( status );
456 /******************************************************************************
457 * TerminateProcess (KERNEL32.684)
459 BOOL32 WINAPI TerminateProcess( HANDLE32 handle, DWORD exit_code )
461 int server_handle;
462 BOOL32 ret;
463 PDB32 *pdb = PROCESS_GetPtr( handle, PROCESS_TERMINATE, &server_handle );
464 if (!pdb) return FALSE;
465 ret = !CLIENT_TerminateProcess( server_handle, exit_code );
466 K32OBJ_DecCount( &pdb->header );
467 return ret;
470 /***********************************************************************
471 * GetCurrentProcess (KERNEL32.198)
473 HANDLE32 WINAPI GetCurrentProcess(void)
475 return CURRENT_PROCESS_PSEUDOHANDLE;
479 /*********************************************************************
480 * OpenProcess (KERNEL32.543)
482 HANDLE32 WINAPI OpenProcess( DWORD access, BOOL32 inherit, DWORD id )
484 int server_handle;
485 PDB32 *pdb = PROCESS_ID_TO_PDB(id);
486 if (!K32OBJ_IsValid( &pdb->header, K32OBJ_PROCESS ))
488 SetLastError( ERROR_INVALID_HANDLE );
489 return 0;
491 if ((server_handle = CLIENT_OpenProcess( pdb->server_pid, access, inherit )) == -1)
493 SetLastError( ERROR_INVALID_HANDLE );
494 return 0;
496 return HANDLE_Alloc( PROCESS_Current(), &pdb->header, access,
497 inherit, server_handle );
501 /***********************************************************************
502 * GetCurrentProcessId (KERNEL32.199)
504 DWORD WINAPI GetCurrentProcessId(void)
506 PDB32 *pdb = PROCESS_Current();
507 return PDB_TO_PROCESS_ID( pdb );
511 /***********************************************************************
512 * GetProcessHeap (KERNEL32.259)
514 HANDLE32 WINAPI GetProcessHeap(void)
516 PDB32 *pdb = PROCESS_Current();
517 return pdb->heap ? pdb->heap : SystemHeap;
521 /***********************************************************************
522 * GetThreadLocale (KERNEL32.295)
524 LCID WINAPI GetThreadLocale(void)
526 return PROCESS_Current()->locale;
530 /***********************************************************************
531 * SetPriorityClass (KERNEL32.503)
533 BOOL32 WINAPI SetPriorityClass( HANDLE32 hprocess, DWORD priorityclass )
535 PDB32 *pdb = PROCESS_GetPtr( hprocess, PROCESS_SET_INFORMATION, NULL );
536 if (!pdb) return FALSE;
537 switch (priorityclass)
539 case NORMAL_PRIORITY_CLASS:
540 pdb->priority = 0x00000008;
541 break;
542 case IDLE_PRIORITY_CLASS:
543 pdb->priority = 0x00000004;
544 break;
545 case HIGH_PRIORITY_CLASS:
546 pdb->priority = 0x0000000d;
547 break;
548 case REALTIME_PRIORITY_CLASS:
549 pdb->priority = 0x00000018;
550 break;
551 default:
552 WARN(process,"Unknown priority class %ld\n",priorityclass);
553 break;
555 K32OBJ_DecCount( &pdb->header );
556 return TRUE;
560 /***********************************************************************
561 * GetPriorityClass (KERNEL32.250)
563 DWORD WINAPI GetPriorityClass(HANDLE32 hprocess)
565 PDB32 *pdb = PROCESS_GetPtr( hprocess, PROCESS_QUERY_INFORMATION, NULL );
566 DWORD ret = 0;
567 if (pdb)
569 switch (pdb->priority)
571 case 0x00000008:
572 ret = NORMAL_PRIORITY_CLASS;
573 break;
574 case 0x00000004:
575 ret = IDLE_PRIORITY_CLASS;
576 break;
577 case 0x0000000d:
578 ret = HIGH_PRIORITY_CLASS;
579 break;
580 case 0x00000018:
581 ret = REALTIME_PRIORITY_CLASS;
582 break;
583 default:
584 WARN(process,"Unknown priority %ld\n",pdb->priority);
586 K32OBJ_DecCount( &pdb->header );
588 return ret;
592 /***********************************************************************
593 * GetStdHandle (KERNEL32.276)
595 * FIXME: These should be allocated when a console is created, or inherited
596 * from the parent.
598 HANDLE32 WINAPI GetStdHandle( DWORD std_handle )
600 HFILE32 hFile;
601 int fd;
602 PDB32 *pdb = PROCESS_Current();
604 switch(std_handle)
606 case STD_INPUT_HANDLE:
607 if (pdb->env_db->hStdin) return pdb->env_db->hStdin;
608 fd = 0;
609 break;
610 case STD_OUTPUT_HANDLE:
611 if (pdb->env_db->hStdout) return pdb->env_db->hStdout;
612 fd = 1;
613 break;
614 case STD_ERROR_HANDLE:
615 if (pdb->env_db->hStderr) return pdb->env_db->hStderr;
616 fd = 2;
617 break;
618 default:
619 SetLastError( ERROR_INVALID_PARAMETER );
620 return INVALID_HANDLE_VALUE32;
622 hFile = FILE_DupUnixHandle( fd );
623 if (hFile != HFILE_ERROR32)
625 FILE_SetFileType( hFile, FILE_TYPE_CHAR );
626 switch(std_handle)
628 case STD_INPUT_HANDLE: pdb->env_db->hStdin = hFile; break;
629 case STD_OUTPUT_HANDLE: pdb->env_db->hStdout = hFile; break;
630 case STD_ERROR_HANDLE: pdb->env_db->hStderr = hFile; break;
633 return hFile;
637 /***********************************************************************
638 * SetStdHandle (KERNEL32.506)
640 BOOL32 WINAPI SetStdHandle( DWORD std_handle, HANDLE32 handle )
642 PDB32 *pdb = PROCESS_Current();
643 /* FIXME: should we close the previous handle? */
644 switch(std_handle)
646 case STD_INPUT_HANDLE:
647 pdb->env_db->hStdin = handle;
648 return TRUE;
649 case STD_OUTPUT_HANDLE:
650 pdb->env_db->hStdout = handle;
651 return TRUE;
652 case STD_ERROR_HANDLE:
653 pdb->env_db->hStderr = handle;
654 return TRUE;
656 SetLastError( ERROR_INVALID_PARAMETER );
657 return FALSE;
660 /***********************************************************************
661 * GetProcessVersion (KERNEL32)
663 DWORD WINAPI GetProcessVersion( DWORD processid )
665 TDB *pTask;
666 PDB32 *pdb = PROCESS_IdToPDB( processid );
668 if (!pdb) return 0;
669 if (!(pTask = (TDB *)GlobalLock16( pdb->task ))) return 0;
670 return (pTask->version&0xff) | (((pTask->version >>8) & 0xff)<<16);
673 /***********************************************************************
674 * GetProcessFlags (KERNEL32)
676 DWORD WINAPI GetProcessFlags( DWORD processid )
678 PDB32 *pdb = PROCESS_IdToPDB( processid );
679 if (!pdb) return 0;
680 return pdb->flags;
683 /***********************************************************************
684 * SetProcessWorkingSetSize [KERNEL32.662]
685 * Sets the min/max working set sizes for a specified process.
687 * PARAMS
688 * hProcess [I] Handle to the process of interest
689 * minset [I] Specifies minimum working set size
690 * maxset [I] Specifies maximum working set size
692 * RETURNS STD
694 BOOL32 WINAPI SetProcessWorkingSetSize(HANDLE32 hProcess,DWORD minset,
695 DWORD maxset)
697 FIXME(process,"(0x%08x,%ld,%ld): stub - harmless\n",hProcess,minset,maxset);
698 if(( minset == -1) && (maxset == -1)) {
699 /* Trim the working set to zero */
700 /* Swap the process out of physical RAM */
702 return TRUE;
705 /***********************************************************************
706 * GetProcessWorkingSetSize (KERNEL32)
708 BOOL32 WINAPI GetProcessWorkingSetSize(HANDLE32 hProcess,LPDWORD minset,
709 LPDWORD maxset)
711 FIXME(process,"(0x%08x,%p,%p): stub\n",hProcess,minset,maxset);
712 /* 32 MB working set size */
713 if (minset) *minset = 32*1024*1024;
714 if (maxset) *maxset = 32*1024*1024;
715 return TRUE;
718 /***********************************************************************
719 * SetProcessShutdownParameters (KERNEL32)
721 * CHANGED - James Sutherland (JamesSutherland@gmx.de)
722 * Now tracks changes made (but does not act on these changes)
723 * NOTE: the definition for SHUTDOWN_NORETRY was done on guesswork.
724 * It really shouldn't be here, but I'll move it when it's been checked!
726 #define SHUTDOWN_NORETRY 1
727 extern unsigned int shutdown_noretry = 0;
728 extern unsigned int shutdown_priority = 0x280L;
729 BOOL32 WINAPI SetProcessShutdownParameters(DWORD level,DWORD flags)
731 if (flags & SHUTDOWN_NORETRY)
732 shutdown_noretry = 1;
733 else
734 shutdown_noretry = 0;
735 if (level > 0x100L && level < 0x3FFL)
736 shutdown_priority = level;
737 else
739 ERR(process,"invalid priority level 0x%08lx\n", level);
740 return FALSE;
742 return TRUE;
746 /***********************************************************************
747 * GetProcessShutdownParameters (KERNEL32)
750 BOOL32 WINAPI GetProcessShutdownParameters( LPDWORD lpdwLevel,
751 LPDWORD lpdwFlags )
753 (*lpdwLevel) = shutdown_priority;
754 (*lpdwFlags) = (shutdown_noretry * SHUTDOWN_NORETRY);
755 return TRUE;
757 /***********************************************************************
758 * SetProcessPriorityBoost (KERNEL32)
760 BOOL32 WINAPI SetProcessPriorityBoost(HANDLE32 hprocess,BOOL32 disableboost)
762 FIXME(process,"(%d,%d): stub\n",hprocess,disableboost);
763 /* Say we can do it. I doubt the program will notice that we don't. */
764 return TRUE;
767 /***********************************************************************
768 * ReadProcessMemory (KERNEL32)
769 * FIXME: check this, if we ever run win32 binaries in different addressspaces
770 * ... and add a sizecheck
772 BOOL32 WINAPI ReadProcessMemory( HANDLE32 hProcess, LPCVOID lpBaseAddress,
773 LPVOID lpBuffer, DWORD nSize,
774 LPDWORD lpNumberOfBytesRead )
776 memcpy(lpBuffer,lpBaseAddress,nSize);
777 if (lpNumberOfBytesRead) *lpNumberOfBytesRead = nSize;
778 return TRUE;
781 /***********************************************************************
782 * WriteProcessMemory (KERNEL32)
783 * FIXME: check this, if we ever run win32 binaries in different addressspaces
784 * ... and add a sizecheck
786 BOOL32 WINAPI WriteProcessMemory(HANDLE32 hProcess, LPVOID lpBaseAddress,
787 LPVOID lpBuffer, DWORD nSize,
788 LPDWORD lpNumberOfBytesWritten )
790 memcpy(lpBaseAddress,lpBuffer,nSize);
791 if (lpNumberOfBytesWritten) *lpNumberOfBytesWritten = nSize;
792 return TRUE;
795 /***********************************************************************
796 * ConvertToGlobalHandle (KERNEL32)
798 HANDLE32 WINAPI ConvertToGlobalHandle(HANDLE32 hSrc)
800 HANDLE32 hProcessInit, hDest;
802 /* Get a handle to the initial process */
803 hProcessInit = OpenProcess( PROCESS_ALL_ACCESS, FALSE, PROCESS_InitialProcessID );
805 /* Duplicate the handle into the initial process */
806 if ( !DuplicateHandle( GetCurrentProcess(), hSrc, hProcessInit, &hDest,
807 0, FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE ) )
808 hDest = 0;
810 /* Close initial process handle */
811 CloseHandle( hProcessInit );
813 /* Return obfuscated global handle */
814 return hDest? HANDLE_LOCAL_TO_GLOBAL( hDest ) : 0;
817 /***********************************************************************
818 * RegisterServiceProcess (KERNEL, KERNEL32)
820 * A service process calls this function to ensure that it continues to run
821 * even after a user logged off.
823 DWORD WINAPI RegisterServiceProcess(DWORD dwProcessId, DWORD dwType)
825 /* I don't think that Wine needs to do anything in that function */
826 return 1; /* success */
829 /***********************************************************************
830 * GetExitCodeProcess [KERNEL32.325]
832 * Gets termination status of specified process
834 * RETURNS
835 * Success: TRUE
836 * Failure: FALSE
838 * FIXME
839 * Should call SetLastError (but doesn't).
841 BOOL32 WINAPI GetExitCodeProcess(
842 HANDLE32 hProcess, /* [I] handle to the process */
843 LPDWORD lpExitCode) /* [O] address to receive termination status */
845 PDB32 *process;
846 int server_handle;
847 struct get_process_info_reply info;
849 if (!(process = PROCESS_GetPtr( hProcess, PROCESS_QUERY_INFORMATION,
850 &server_handle )))
851 return FALSE;
852 if (server_handle != -1)
854 CLIENT_GetProcessInfo( server_handle, &info );
855 if (lpExitCode) *lpExitCode = info.exit_code;
857 else if (lpExitCode) *lpExitCode = process->exit_code;
858 K32OBJ_DecCount( &process->header );
859 return TRUE;
862 /***********************************************************************
863 * GetProcessHeaps [KERNEL32.376]
865 DWORD WINAPI GetProcessHeaps(DWORD nrofheaps,HANDLE32 *heaps) {
866 FIXME(win32,"(%ld,%p), incomplete implementation.\n",nrofheaps,heaps);
868 if (nrofheaps) {
869 heaps[0] = GetProcessHeap();
870 /* ... probably SystemHeap too ? */
871 return 1;
873 /* number of available heaps */
874 return 1;
877 /***********************************************************************
878 * PROCESS_SuspendOtherThreads
881 void PROCESS_SuspendOtherThreads(void)
883 PDB32 *pdb;
884 THREAD_ENTRY *entry;
886 SYSTEM_LOCK();
888 pdb = PROCESS_Current();
889 entry = pdb->thread_list->next;
890 for (;;)
892 if (entry->thread != THREAD_Current() && !THREAD_IsWin16(entry->thread))
894 HANDLE32 handle = HANDLE_Alloc( PROCESS_Current(),
895 &entry->thread->header,
896 THREAD_ALL_ACCESS, FALSE, -1 );
897 SuspendThread(handle);
898 CloseHandle(handle);
900 if (entry == pdb->thread_list) break;
901 entry = entry->next;
904 SYSTEM_UNLOCK();
907 /***********************************************************************
908 * PROCESS_ResumeOtherThreads
911 void PROCESS_ResumeOtherThreads(void)
913 PDB32 *pdb;
914 THREAD_ENTRY *entry;
916 SYSTEM_LOCK();
918 pdb = PROCESS_Current();
919 entry = pdb->thread_list->next;
920 for (;;)
922 if (entry->thread != THREAD_Current() && !THREAD_IsWin16(entry->thread))
924 HANDLE32 handle = HANDLE_Alloc( PROCESS_Current(),
925 &entry->thread->header,
926 THREAD_ALL_ACCESS, FALSE, -1 );
927 ResumeThread(handle);
928 CloseHandle(handle);
930 if (entry == pdb->thread_list) break;
931 entry = entry->next;
934 SYSTEM_UNLOCK();
937 BOOL32 WINAPI Process32First(HANDLE32 hSnapshot, LPPROCESSENTRY32 lppe)
939 FIXME (process, "(0x%08x,%p), stub!\n", hSnapshot, lppe);
940 SetLastError (ERROR_NO_MORE_FILES);
941 return FALSE;
944 BOOL32 WINAPI Process32Next(HANDLE32 hSnapshot, LPPROCESSENTRY32 lppe)
946 FIXME (process, "(0x%08x,%p), stub!\n", hSnapshot, lppe);
947 SetLastError (ERROR_NO_MORE_FILES);
948 return FALSE;