4 * Copyright 1996, 1998 Alexandre Julliard
28 /* The initial process PDB */
29 static PDB initial_pdb;
31 static PDB *PROCESS_First = &initial_pdb;
33 /***********************************************************************
36 PDB *PROCESS_Current(void)
38 return THREAD_Current()->process;
41 /***********************************************************************
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)
49 PDB *PROCESS_Initial(void)
54 /***********************************************************************
57 * Retrieve information about a process
59 static BOOL PROCESS_QueryInfo( HANDLE handle,
60 struct get_process_info_reply *reply )
62 struct get_process_info_request req;
64 CLIENT_SendRequest( REQ_GET_PROCESS_INFO, -1, 1, &req, sizeof(req) );
65 return !CLIENT_WaitSimpleReply( reply, sizeof(*reply), NULL );
68 /***********************************************************************
71 * Check if a handle is to the current process
73 BOOL PROCESS_IsCurrent( HANDLE handle )
75 struct get_process_info_reply reply;
76 return (PROCESS_QueryInfo( handle, &reply ) &&
77 (reply.pid == PROCESS_Current()->server_pid));
81 /***********************************************************************
84 * Convert a process id to a PDB, making sure it is valid.
86 PDB *PROCESS_IdToPDB( DWORD id )
90 if (!id) return PROCESS_Current();
94 if ((DWORD)pdb->server_pid == id) return pdb;
97 SetLastError( ERROR_INVALID_PARAMETER );
103 /***********************************************************************
106 * Build the env DB for the initial process
108 static BOOL PROCESS_BuildEnvDB( PDB *pdb )
110 /* Allocate the env DB (FIXME: should not be on the system heap) */
112 if (!(pdb->env_db = HeapAlloc(SystemHeap,HEAP_ZERO_MEMORY,sizeof(ENVDB))))
114 InitializeCriticalSection( &pdb->env_db->section );
116 /* Allocate startup info */
117 if (!(pdb->env_db->startup_info =
118 HeapAlloc( SystemHeap, HEAP_ZERO_MEMORY, sizeof(STARTUPINFOA) )))
121 /* Allocate the standard handles */
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 );
127 /* Build the command-line */
129 pdb->env_db->cmd_line = HEAP_strdupA( SystemHeap, 0, "kernel32" );
131 /* Build the environment strings */
133 return ENV_BuildEnvironment( pdb );
137 /***********************************************************************
138 * PROCESS_InheritEnvDB
140 static BOOL PROCESS_InheritEnvDB( PDB *pdb, LPCSTR cmd_line, LPCSTR env,
141 BOOL inherit_handles, STARTUPINFOA *startup )
143 if (!(pdb->env_db = HeapAlloc(pdb->heap, HEAP_ZERO_MEMORY, sizeof(ENVDB))))
145 InitializeCriticalSection( &pdb->env_db->section );
147 /* Copy the parent environment */
149 if (!ENV_InheritEnvironment( pdb, env )) return FALSE;
151 /* Copy the command line */
153 if (!(pdb->env_db->cmd_line = HEAP_strdupA( pdb->heap, 0, cmd_line )))
156 /* Remember startup info */
157 if (!(pdb->env_db->startup_info =
158 HeapAlloc( pdb->heap, HEAP_ZERO_MEMORY, sizeof(STARTUPINFOA) )))
160 *pdb->env_db->startup_info = *startup;
162 /* Inherit the standard handles */
163 if (pdb->env_db->startup_info->dwFlags & STARTF_USESTDHANDLES)
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;
169 else if (inherit_handles)
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;
175 /* else will be done later on in PROCESS_Create */
181 /***********************************************************************
184 * Free a PDB and all associated storage.
186 void PROCESS_FreePDB( PDB *pdb )
188 PDB **pptr = &PROCESS_First;
190 ENV_FreeEnvironment( pdb );
191 while (*pptr && (*pptr != pdb)) pptr = &(*pptr)->next;
192 if (*pptr) *pptr = pdb->next;
193 if (pdb->heap && (pdb->heap != pdb->system_heap)) HeapDestroy( pdb->heap );
194 DeleteCriticalSection( &pdb->crit_section );
195 HeapFree( SystemHeap, 0, pdb );
199 /***********************************************************************
202 * Allocate and fill a PDB structure.
203 * Runs in the context of the parent process.
205 static PDB *PROCESS_CreatePDB( PDB *parent, BOOL inherit )
207 PDB *pdb = HeapAlloc( SystemHeap, HEAP_ZERO_MEMORY, sizeof(PDB) );
209 if (!pdb) return NULL;
210 pdb->exit_code = 0x103; /* STILL_ACTIVE */
212 pdb->running_threads = 1;
213 pdb->ring0_threads = 1;
214 pdb->system_heap = SystemHeap;
215 pdb->parent = parent;
217 pdb->priority = 8; /* Normal */
218 pdb->heap = pdb->system_heap; /* will be changed later on */
219 pdb->next = PROCESS_First;
225 /***********************************************************************
226 * PROCESS_FinishCreatePDB
228 * Second part of CreatePDB
230 static BOOL PROCESS_FinishCreatePDB( PDB *pdb )
232 InitializeCriticalSection( &pdb->crit_section );
233 /* Allocate the event */
234 if (!(pdb->load_done_evt = CreateEventA( NULL, TRUE, FALSE, NULL )))
240 /***********************************************************************
243 BOOL PROCESS_Init(void)
247 /* Fill the initial process structure */
248 initial_pdb.exit_code = 0x103; /* STILL_ACTIVE */
249 initial_pdb.threads = 1;
250 initial_pdb.running_threads = 1;
251 initial_pdb.ring0_threads = 1;
252 initial_pdb.group = &initial_pdb;
253 initial_pdb.priority = 8; /* Normal */
255 /* Initialize virtual memory management */
256 if (!VIRTUAL_Init()) return FALSE;
258 /* Create the initial thread structure */
259 if (!(thdb = THREAD_CreateInitialThread( &initial_pdb ))) return FALSE;
261 /* Remember TEB selector of initial process for emergency use */
262 SYSLEVEL_EmergencyTeb = thdb->teb_sel;
264 /* Create the system heap */
265 if (!(SystemHeap = HeapCreate( HEAP_GROWABLE, 0x10000, 0 ))) return FALSE;
266 initial_pdb.system_heap = initial_pdb.heap = SystemHeap;
268 /* Create the environment DB of the first process */
269 if (!PROCESS_BuildEnvDB( &initial_pdb )) return FALSE;
271 /* Initialize the first thread */
272 if (CLIENT_InitThread()) return FALSE;
273 if (!PROCESS_FinishCreatePDB( &initial_pdb )) return FALSE;
275 /* Create the SEGPTR heap */
276 if (!(SegptrHeap = HeapCreate( HEAP_WINE_SEGPTR, 0, 0 ))) return FALSE;
282 /***********************************************************************
285 * Create a new process database and associated info.
287 PDB *PROCESS_Create( NE_MODULE *pModule, LPCSTR cmd_line, LPCSTR env,
288 HINSTANCE16 hInstance, HINSTANCE16 hPrevInstance,
289 LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES tsa,
290 BOOL inherit, STARTUPINFOA *startup,
291 PROCESS_INFORMATION *info )
294 int server_thandle, server_phandle;
297 PDB *parent = PROCESS_Current();
298 PDB *pdb = PROCESS_CreatePDB( parent, inherit );
300 if (!pdb) return NULL;
301 info->hThread = info->hProcess = INVALID_HANDLE_VALUE;
302 if (!PROCESS_FinishCreatePDB( pdb )) goto error;
304 /* Create the heap */
306 if (pModule->module32)
308 size = PE_HEADER(pModule->module32)->OptionalHeader.SizeOfHeapReserve;
309 commit = PE_HEADER(pModule->module32)->OptionalHeader.SizeOfHeapCommit;
315 pdb->flags |= PDB32_WIN16_PROC; /* This is a Win16 process */
317 if (!(pdb->heap = HeapCreate( HEAP_GROWABLE, size, commit ))) goto error;
318 pdb->heap_list = pdb->heap;
320 /* Inherit the env DB from the parent */
322 if (!PROCESS_InheritEnvDB( pdb, cmd_line, env, inherit, startup )) goto error;
324 /* Create the main thread */
326 if (pModule->module32)
327 size = PE_HEADER(pModule->module32)->OptionalHeader.SizeOfStackReserve;
330 if (!(thdb = THREAD_Create( pdb, 0L, size, hInstance == 0,
331 tsa, psa, &server_thandle, &server_phandle,
334 info->hThread = server_thandle;
335 info->hProcess = server_phandle;
336 info->dwProcessId = (DWORD)pdb->server_pid;
337 info->dwThreadId = (DWORD)thdb->server_tid;
339 /* Duplicate the standard handles */
341 if ((!(pdb->env_db->startup_info->dwFlags & STARTF_USESTDHANDLES)) && !inherit)
343 DuplicateHandle( GetCurrentProcess(), pdb->parent->env_db->hStdin,
344 info->hProcess, &pdb->env_db->hStdin, 0, TRUE, DUPLICATE_SAME_ACCESS );
345 DuplicateHandle( GetCurrentProcess(), pdb->parent->env_db->hStdout,
346 info->hProcess, &pdb->env_db->hStdout, 0, TRUE, DUPLICATE_SAME_ACCESS );
347 DuplicateHandle( GetCurrentProcess(), pdb->parent->env_db->hStderr,
348 info->hProcess, &pdb->env_db->hStderr, 0, TRUE, DUPLICATE_SAME_ACCESS );
351 /* Create a Win16 task for this process */
353 if (startup->dwFlags & STARTF_USESHOWWINDOW)
354 cmdShow = startup->wShowWindow;
356 if ( !TASK_Create( thdb, pModule, hInstance, hPrevInstance, cmdShow) )
360 /* Map system DLLs into this process (from initial process) */
361 /* FIXME: this is a hack */
362 pdb->modref_list = PROCESS_Initial()->modref_list;
368 if (info->hThread != INVALID_HANDLE_VALUE) CloseHandle( info->hThread );
369 if (info->hProcess != INVALID_HANDLE_VALUE) CloseHandle( info->hProcess );
370 PROCESS_FreePDB( pdb );
375 /***********************************************************************
376 * ExitProcess (KERNEL32.100)
378 void WINAPI ExitProcess( DWORD status )
380 PDB *pdb = PROCESS_Current();
381 TDB *pTask = (TDB *)GlobalLock16( pdb->task );
382 if ( pTask ) pTask->nEvents++;
384 if ( pTask && pTask->thdb != THREAD_Current() )
385 ExitThread( status );
387 /* FIXME: should kill all running threads of this process */
388 pdb->exit_code = status;
391 __RESTORE_ES; /* Necessary for Pietrek's showseh example program */
392 TASK_KillCurrentTask( status );
396 /******************************************************************************
397 * TerminateProcess (KERNEL32.684)
399 BOOL WINAPI TerminateProcess( HANDLE handle, DWORD exit_code )
401 struct terminate_process_request req;
403 req.exit_code = exit_code;
404 CLIENT_SendRequest( REQ_TERMINATE_PROCESS, -1, 1, &req, sizeof(req) );
405 return !CLIENT_WaitReply( NULL, NULL, 0 );
408 /***********************************************************************
409 * GetCurrentProcess (KERNEL32.198)
411 HANDLE WINAPI GetCurrentProcess(void)
413 return CURRENT_PROCESS_PSEUDOHANDLE;
417 /*********************************************************************
418 * OpenProcess (KERNEL32.543)
420 HANDLE WINAPI OpenProcess( DWORD access, BOOL inherit, DWORD id )
422 struct open_process_request req;
423 struct open_process_reply reply;
425 req.pid = (void *)id;
427 req.inherit = inherit;
428 CLIENT_SendRequest( REQ_OPEN_PROCESS, -1, 1, &req, sizeof(req) );
429 if (CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL )) return 0;
434 /***********************************************************************
435 * GetCurrentProcessId (KERNEL32.199)
437 DWORD WINAPI GetCurrentProcessId(void)
439 return (DWORD)PROCESS_Current()->server_pid;
443 /***********************************************************************
444 * GetProcessHeap (KERNEL32.259)
446 HANDLE WINAPI GetProcessHeap(void)
448 PDB *pdb = PROCESS_Current();
449 return pdb->heap ? pdb->heap : SystemHeap;
453 /***********************************************************************
454 * GetThreadLocale (KERNEL32.295)
456 LCID WINAPI GetThreadLocale(void)
458 return PROCESS_Current()->locale;
462 /***********************************************************************
463 * SetPriorityClass (KERNEL32.503)
465 BOOL WINAPI SetPriorityClass( HANDLE hprocess, DWORD priorityclass )
467 struct set_process_info_request req;
468 req.handle = hprocess;
469 req.priority = priorityclass;
470 req.mask = SET_PROCESS_INFO_PRIORITY;
471 CLIENT_SendRequest( REQ_SET_PROCESS_INFO, -1, 1, &req, sizeof(req) );
472 return !CLIENT_WaitReply( NULL, NULL, 0 );
476 /***********************************************************************
477 * GetPriorityClass (KERNEL32.250)
479 DWORD WINAPI GetPriorityClass(HANDLE hprocess)
481 struct get_process_info_reply reply;
482 if (!PROCESS_QueryInfo( hprocess, &reply )) return 0;
483 return reply.priority;
487 /***********************************************************************
488 * SetProcessAffinityMask (KERNEL32.662)
490 BOOL WINAPI SetProcessAffinityMask( HANDLE hProcess, DWORD affmask )
492 struct set_process_info_request req;
493 req.handle = hProcess;
494 req.affinity = affmask;
495 req.mask = SET_PROCESS_INFO_AFFINITY;
496 CLIENT_SendRequest( REQ_SET_PROCESS_INFO, -1, 1, &req, sizeof(req) );
497 return !CLIENT_WaitReply( NULL, NULL, 0 );
500 /**********************************************************************
501 * GetProcessAffinityMask (KERNEL32.373)
503 BOOL WINAPI GetProcessAffinityMask( HANDLE hProcess,
504 LPDWORD lpProcessAffinityMask,
505 LPDWORD lpSystemAffinityMask )
507 struct get_process_info_reply reply;
508 if (!PROCESS_QueryInfo( hProcess, &reply )) return FALSE;
509 if (lpProcessAffinityMask) *lpProcessAffinityMask = reply.process_affinity;
510 if (lpSystemAffinityMask) *lpSystemAffinityMask = reply.system_affinity;
515 /***********************************************************************
516 * GetStdHandle (KERNEL32.276)
518 HANDLE WINAPI GetStdHandle( DWORD std_handle )
520 PDB *pdb = PROCESS_Current();
524 case STD_INPUT_HANDLE: return pdb->env_db->hStdin;
525 case STD_OUTPUT_HANDLE: return pdb->env_db->hStdout;
526 case STD_ERROR_HANDLE: return pdb->env_db->hStderr;
528 SetLastError( ERROR_INVALID_PARAMETER );
529 return INVALID_HANDLE_VALUE;
533 /***********************************************************************
534 * SetStdHandle (KERNEL32.506)
536 BOOL WINAPI SetStdHandle( DWORD std_handle, HANDLE handle )
538 PDB *pdb = PROCESS_Current();
539 /* FIXME: should we close the previous handle? */
542 case STD_INPUT_HANDLE:
543 pdb->env_db->hStdin = handle;
545 case STD_OUTPUT_HANDLE:
546 pdb->env_db->hStdout = handle;
548 case STD_ERROR_HANDLE:
549 pdb->env_db->hStderr = handle;
552 SetLastError( ERROR_INVALID_PARAMETER );
556 /***********************************************************************
557 * GetProcessVersion (KERNEL32)
559 DWORD WINAPI GetProcessVersion( DWORD processid )
562 PDB *pdb = PROCESS_IdToPDB( processid );
565 if (!(pTask = (TDB *)GlobalLock16( pdb->task ))) return 0;
566 return (pTask->version&0xff) | (((pTask->version >>8) & 0xff)<<16);
569 /***********************************************************************
570 * GetProcessFlags (KERNEL32)
572 DWORD WINAPI GetProcessFlags( DWORD processid )
574 PDB *pdb = PROCESS_IdToPDB( processid );
579 /***********************************************************************
580 * SetProcessWorkingSetSize [KERNEL32.662]
581 * Sets the min/max working set sizes for a specified process.
584 * hProcess [I] Handle to the process of interest
585 * minset [I] Specifies minimum working set size
586 * maxset [I] Specifies maximum working set size
590 BOOL WINAPI SetProcessWorkingSetSize(HANDLE hProcess,DWORD minset,
593 FIXME(process,"(0x%08x,%ld,%ld): stub - harmless\n",hProcess,minset,maxset);
594 if(( minset == -1) && (maxset == -1)) {
595 /* Trim the working set to zero */
596 /* Swap the process out of physical RAM */
601 /***********************************************************************
602 * GetProcessWorkingSetSize (KERNEL32)
604 BOOL WINAPI GetProcessWorkingSetSize(HANDLE hProcess,LPDWORD minset,
607 FIXME(process,"(0x%08x,%p,%p): stub\n",hProcess,minset,maxset);
608 /* 32 MB working set size */
609 if (minset) *minset = 32*1024*1024;
610 if (maxset) *maxset = 32*1024*1024;
614 /***********************************************************************
615 * SetProcessShutdownParameters (KERNEL32)
617 * CHANGED - James Sutherland (JamesSutherland@gmx.de)
618 * Now tracks changes made (but does not act on these changes)
619 * NOTE: the definition for SHUTDOWN_NORETRY was done on guesswork.
620 * It really shouldn't be here, but I'll move it when it's been checked!
622 #define SHUTDOWN_NORETRY 1
623 static unsigned int shutdown_noretry = 0;
624 static unsigned int shutdown_priority = 0x280L;
625 BOOL WINAPI SetProcessShutdownParameters(DWORD level,DWORD flags)
627 if (flags & SHUTDOWN_NORETRY)
628 shutdown_noretry = 1;
630 shutdown_noretry = 0;
631 if (level > 0x100L && level < 0x3FFL)
632 shutdown_priority = level;
635 ERR(process,"invalid priority level 0x%08lx\n", level);
642 /***********************************************************************
643 * GetProcessShutdownParameters (KERNEL32)
646 BOOL WINAPI GetProcessShutdownParameters( LPDWORD lpdwLevel,
649 (*lpdwLevel) = shutdown_priority;
650 (*lpdwFlags) = (shutdown_noretry * SHUTDOWN_NORETRY);
653 /***********************************************************************
654 * SetProcessPriorityBoost (KERNEL32)
656 BOOL WINAPI SetProcessPriorityBoost(HANDLE hprocess,BOOL disableboost)
658 FIXME(process,"(%d,%d): stub\n",hprocess,disableboost);
659 /* Say we can do it. I doubt the program will notice that we don't. */
663 /***********************************************************************
664 * ReadProcessMemory (KERNEL32)
665 * FIXME: check this, if we ever run win32 binaries in different addressspaces
666 * ... and add a sizecheck
668 BOOL WINAPI ReadProcessMemory( HANDLE hProcess, LPCVOID lpBaseAddress,
669 LPVOID lpBuffer, DWORD nSize,
670 LPDWORD lpNumberOfBytesRead )
672 memcpy(lpBuffer,lpBaseAddress,nSize);
673 if (lpNumberOfBytesRead) *lpNumberOfBytesRead = nSize;
677 /***********************************************************************
678 * WriteProcessMemory (KERNEL32)
679 * FIXME: check this, if we ever run win32 binaries in different addressspaces
680 * ... and add a sizecheck
682 BOOL WINAPI WriteProcessMemory(HANDLE hProcess, LPVOID lpBaseAddress,
683 LPVOID lpBuffer, DWORD nSize,
684 LPDWORD lpNumberOfBytesWritten )
686 memcpy(lpBaseAddress,lpBuffer,nSize);
687 if (lpNumberOfBytesWritten) *lpNumberOfBytesWritten = nSize;
691 /***********************************************************************
692 * RegisterServiceProcess (KERNEL, KERNEL32)
694 * A service process calls this function to ensure that it continues to run
695 * even after a user logged off.
697 DWORD WINAPI RegisterServiceProcess(DWORD dwProcessId, DWORD dwType)
699 /* I don't think that Wine needs to do anything in that function */
700 return 1; /* success */
703 /***********************************************************************
704 * GetExitCodeProcess [KERNEL32.325]
706 * Gets termination status of specified process
712 BOOL WINAPI GetExitCodeProcess(
713 HANDLE hProcess, /* [I] handle to the process */
714 LPDWORD lpExitCode) /* [O] address to receive termination status */
716 struct get_process_info_reply reply;
717 if (!PROCESS_QueryInfo( hProcess, &reply )) return FALSE;
718 if (lpExitCode) *lpExitCode = reply.exit_code;
723 /***********************************************************************
724 * GetProcessHeaps [KERNEL32.376]
726 DWORD WINAPI GetProcessHeaps(DWORD nrofheaps,HANDLE *heaps) {
727 FIXME(win32,"(%ld,%p), incomplete implementation.\n",nrofheaps,heaps);
730 heaps[0] = GetProcessHeap();
731 /* ... probably SystemHeap too ? */
734 /* number of available heaps */
738 /***********************************************************************
739 * PROCESS_SuspendOtherThreads
742 void PROCESS_SuspendOtherThreads(void)
750 pdb = PROCESS_Current();
751 entry = pdb->thread_list->next;
754 if (entry->thread != THREAD_Current() && !THREAD_IsWin16(entry->thread))
756 HANDLE handle = HANDLE_Alloc( PROCESS_Current(),
757 &entry->thread->header,
758 THREAD_ALL_ACCESS, FALSE, -1 );
759 SuspendThread(handle);
762 if (entry == pdb->thread_list) break;
770 /***********************************************************************
771 * PROCESS_ResumeOtherThreads
774 void PROCESS_ResumeOtherThreads(void)
782 pdb = PROCESS_Current();
783 entry = pdb->thread_list->next;
786 if (entry->thread != THREAD_Current() && !THREAD_IsWin16(entry->thread))
788 HANDLE handle = HANDLE_Alloc( PROCESS_Current(),
789 &entry->thread->header,
790 THREAD_ALL_ACCESS, FALSE, -1 );
791 ResumeThread(handle);
794 if (entry == pdb->thread_list) break;