4 * Copyright 1996, 1998 Alexandre Julliard
11 #include "wine/winbase16.h"
28 #include "debugtools.h"
30 DECLARE_DEBUG_CHANNEL(process
)
31 DECLARE_DEBUG_CHANNEL(relay
)
32 DECLARE_DEBUG_CHANNEL(win32
)
35 /* The initial process PDB */
36 static PDB initial_pdb
;
38 static PDB
*PROCESS_First
= &initial_pdb
;
40 /* Pointer to debugger callback routine */
41 void (*TASK_AddTaskEntryBreakpoint
)( HTASK16 hTask
) = NULL
;
44 /***********************************************************************
47 void PROCESS_WalkProcess(void)
53 MESSAGE( " pid PDB #th modref module \n" );
56 if (pdb
== &initial_pdb
)
59 name
= (pdb
->exe_modref
) ? pdb
->exe_modref
->shortname
: "";
61 MESSAGE( " %8p %8p %5d %8p %s\n", pdb
->server_pid
, pdb
,
62 pdb
->threads
, pdb
->exe_modref
, name
);
68 /***********************************************************************
71 * FIXME: This works only while running all processes in the same
72 * address space (or, at least, the initial process is mapped
73 * into all address spaces as is KERNEL32 in Windows 95)
76 PDB
*PROCESS_Initial(void)
81 /***********************************************************************
84 * Check if a handle is to the current process
86 BOOL
PROCESS_IsCurrent( HANDLE handle
)
88 struct get_process_info_request
*req
= get_req_buffer();
90 return (!server_call( REQ_GET_PROCESS_INFO
) &&
91 (req
->pid
== PROCESS_Current()->server_pid
));
95 /***********************************************************************
98 * Convert a process id to a PDB, making sure it is valid.
100 PDB
*PROCESS_IdToPDB( DWORD id
)
104 if (!id
) return PROCESS_Current();
108 if ((DWORD
)pdb
->server_pid
== id
) return pdb
;
111 SetLastError( ERROR_INVALID_PARAMETER
);
116 /***********************************************************************
117 * PROCESS_CallUserSignalProc
119 * FIXME: Some of the signals aren't sent correctly!
121 * The exact meaning of the USER signals is undocumented, but this
122 * should cover the basic idea:
124 * USIG_DLL_UNLOAD_WIN16
125 * This is sent when a 16-bit module is unloaded.
127 * USIG_DLL_UNLOAD_WIN32
128 * This is sent when a 32-bit module is unloaded.
130 * USIG_DLL_UNLOAD_ORPHANS
131 * This is sent after the last Win3.1 module is unloaded,
132 * to allow removal of orphaned menus.
134 * USIG_FAULT_DIALOG_PUSH
135 * USIG_FAULT_DIALOG_POP
136 * These are called to allow USER to prepare for displaying a
137 * fault dialog, even though the fault might have happened while
138 * inside a USER critical section.
141 * This is called from the context of a new thread, as soon as it
142 * has started to run.
145 * This is called, still in its context, just before a thread is
146 * about to terminate.
148 * USIG_PROCESS_CREATE
149 * This is called, in the parent process context, after a new process
153 * This is called in the new process context, just after the main thread
154 * has started execution (after the main thread's USIG_THREAD_INIT has
157 * USIG_PROCESS_LOADED
158 * This is called after the executable file has been loaded into the
159 * new process context.
161 * USIG_PROCESS_RUNNING
162 * This is called immediately before the main entry point is called.
165 * This is called in the context of a process that is about to
166 * terminate (but before the last thread's USIG_THREAD_EXIT has
169 * USIG_PROCESS_DESTROY
170 * This is called after a process has terminated.
173 * The meaning of the dwFlags bits is as follows:
176 * Current process is 32-bit.
179 * Current process is a (Win32) GUI process.
181 * USIG_FLAGS_FEEDBACK
182 * Current process needs 'feedback' (determined from the STARTUPINFO
183 * flags STARTF_FORCEONFEEDBACK / STARTF_FORCEOFFFEEDBACK).
186 * The signal is being sent due to a fault.
188 static void PROCESS_CallUserSignalProcHelper( UINT uCode
, DWORD dwThreadOrProcessId
,
189 HMODULE hModule
, DWORD flags
, DWORD startup_flags
)
193 /* Determine dwFlags */
195 if ( !(flags
& PDB32_WIN16_PROC
) ) dwFlags
|= USIG_FLAGS_WIN32
;
197 if ( !(flags
& PDB32_CONSOLE_PROC
) ) dwFlags
|= USIG_FLAGS_GUI
;
199 if ( dwFlags
& USIG_FLAGS_GUI
)
201 /* Feedback defaults to ON */
202 if ( !(startup_flags
& STARTF_FORCEOFFFEEDBACK
) )
203 dwFlags
|= USIG_FLAGS_FEEDBACK
;
207 /* Feedback defaults to OFF */
208 if (startup_flags
& STARTF_FORCEONFEEDBACK
)
209 dwFlags
|= USIG_FLAGS_FEEDBACK
;
212 /* Convert module handle to 16-bit */
214 if ( HIWORD( hModule
) )
215 hModule
= MapHModuleLS( hModule
);
217 /* Call USER signal proc */
219 if ( Callout
.UserSignalProc
)
220 Callout
.UserSignalProc( uCode
, dwThreadOrProcessId
, dwFlags
, hModule
);
223 /* Call USER signal proc for the current thread/process */
224 void PROCESS_CallUserSignalProc( UINT uCode
, HMODULE hModule
)
226 DWORD dwThreadOrProcessId
;
228 /* Get thread or process ID */
229 if ( uCode
== USIG_THREAD_INIT
|| uCode
== USIG_THREAD_EXIT
)
230 dwThreadOrProcessId
= GetCurrentThreadId();
232 dwThreadOrProcessId
= GetCurrentProcessId();
234 PROCESS_CallUserSignalProcHelper( uCode
, dwThreadOrProcessId
, hModule
,
235 PROCESS_Current()->flags
,
236 PROCESS_Current()->env_db
->startup_info
->dwFlags
);
240 /***********************************************************************
241 * PROCESS_CreateEnvDB
243 * Create the env DB for a newly started process.
245 static BOOL
PROCESS_CreateEnvDB(void)
247 struct init_process_request
*req
= get_req_buffer();
248 STARTUPINFOA
*startup
;
251 PDB
*pdb
= PROCESS_Current();
253 /* Allocate the env DB */
255 if (!(env_db
= HeapAlloc( pdb
->heap
, HEAP_ZERO_MEMORY
, sizeof(ENVDB
) )))
257 pdb
->env_db
= env_db
;
258 InitializeCriticalSection( &env_db
->section
);
260 /* Allocate and fill the startup info */
261 if (!(startup
= HeapAlloc( pdb
->heap
, HEAP_ZERO_MEMORY
, sizeof(STARTUPINFOA
) )))
263 env_db
->startup_info
= startup
;
265 /* Retrieve startup info from the server */
267 if (server_call( REQ_INIT_PROCESS
)) return FALSE
;
268 startup
->dwFlags
= req
->start_flags
;
269 startup
->wShowWindow
= req
->cmd_show
;
270 env_db
->hStdin
= startup
->hStdInput
= req
->hstdin
;
271 env_db
->hStdout
= startup
->hStdOutput
= req
->hstdout
;
272 env_db
->hStderr
= startup
->hStdError
= req
->hstderr
;
273 lstrcpynA( cmd_line
, req
->cmdline
, sizeof(cmd_line
) );
275 /* Copy the parent environment */
277 if (!ENV_InheritEnvironment( pdb
, req
->env_ptr
)) return FALSE
;
279 /* Copy the command line */
281 if (!(pdb
->env_db
->cmd_line
= HEAP_strdupA( pdb
->heap
, 0, cmd_line
)))
288 /***********************************************************************
291 * Free a PDB and all associated storage.
293 void PROCESS_FreePDB( PDB
*pdb
)
295 PDB
**pptr
= &PROCESS_First
;
297 ENV_FreeEnvironment( pdb
);
298 while (*pptr
&& (*pptr
!= pdb
)) pptr
= &(*pptr
)->next
;
299 if (*pptr
) *pptr
= pdb
->next
;
300 if (pdb
->heap
&& (pdb
->heap
!= pdb
->system_heap
)) HeapDestroy( pdb
->heap
);
301 HeapFree( SystemHeap
, 0, pdb
);
305 /***********************************************************************
308 * Allocate and fill a PDB structure.
309 * Runs in the context of the parent process.
311 static PDB
*PROCESS_CreatePDB( PDB
*parent
, BOOL inherit
)
313 PDB
*pdb
= HeapAlloc( SystemHeap
, HEAP_ZERO_MEMORY
, sizeof(PDB
) );
315 if (!pdb
) return NULL
;
316 pdb
->exit_code
= 0x103; /* STILL_ACTIVE */
318 pdb
->running_threads
= 1;
319 pdb
->ring0_threads
= 1;
320 pdb
->system_heap
= SystemHeap
;
321 pdb
->parent
= parent
;
323 pdb
->priority
= 8; /* Normal */
324 pdb
->heap
= pdb
->system_heap
; /* will be changed later on */
325 pdb
->next
= PROCESS_First
;
326 pdb
->winver
= 0xffff; /* to be determined */
332 /***********************************************************************
335 BOOL
PROCESS_Init(void)
340 /* Start the server */
341 server_fd
= CLIENT_InitServer();
343 /* Fill the initial process structure */
344 initial_pdb
.exit_code
= 0x103; /* STILL_ACTIVE */
345 initial_pdb
.threads
= 1;
346 initial_pdb
.running_threads
= 1;
347 initial_pdb
.ring0_threads
= 1;
348 initial_pdb
.group
= &initial_pdb
;
349 initial_pdb
.priority
= 8; /* Normal */
350 initial_pdb
.flags
= PDB32_WIN16_PROC
;
351 initial_pdb
.winver
= 0xffff; /* to be determined */
353 /* Initialize virtual memory management */
354 if (!VIRTUAL_Init()) return FALSE
;
356 /* Create the initial thread structure and socket pair */
357 if (!(teb
= THREAD_CreateInitialThread( &initial_pdb
, server_fd
))) return FALSE
;
359 /* Remember TEB selector of initial process for emergency use */
360 SYSLEVEL_EmergencyTeb
= teb
->teb_sel
;
362 /* Create the system heap */
363 if (!(SystemHeap
= HeapCreate( HEAP_GROWABLE
, 0x10000, 0 ))) return FALSE
;
364 initial_pdb
.system_heap
= initial_pdb
.heap
= SystemHeap
;
366 /* Initialize signal handling */
367 if (!SIGNAL_Init()) return FALSE
;
369 /* Create the environment DB of the first process */
370 if (!PROCESS_CreateEnvDB()) return FALSE
;
372 /* Create the SEGPTR heap */
373 if (!(SegptrHeap
= HeapCreate( HEAP_WINE_SEGPTR
, 0, 0 ))) return FALSE
;
375 /* Initialize the first process critical section */
376 InitializeCriticalSection( &initial_pdb
.crit_section
);
382 /***********************************************************************
385 * Startup routine of a new process. Called in the context of the new process.
387 void PROCESS_Start(void)
390 LPTHREAD_START_ROUTINE entry
= NULL
;
391 PDB
*pdb
= PROCESS_Current();
392 NE_MODULE
*pModule
= NE_GetPtr( pdb
->module
);
393 OFSTRUCT
*ofs
= (OFSTRUCT
*)((char*)(pModule
) + (pModule
)->fileinfo
);
394 IMAGE_OPTIONAL_HEADER
*header
= !pModule
->module32
? NULL
:
395 &PE_HEADER(pModule
->module32
)->OptionalHeader
;
397 /* Get process type */
398 enum { PROC_DOS
, PROC_WIN16
, PROC_WIN32
} type
;
399 if ( pdb
->flags
& PDB32_DOS_PROC
)
401 else if ( pdb
->flags
& PDB32_WIN16_PROC
)
406 /* Initialize the critical section */
407 InitializeCriticalSection( &pdb
->crit_section
);
409 /* Create the heap */
410 if (!(pdb
->heap
= HeapCreate( HEAP_GROWABLE
,
411 header
? header
->SizeOfHeapReserve
: 0x10000,
412 header
? header
->SizeOfHeapCommit
: 0 )))
414 pdb
->heap_list
= pdb
->heap
;
416 /* Create the environment db */
417 if (!PROCESS_CreateEnvDB()) goto error
;
419 /* Create a task for this process */
420 if (pdb
->env_db
->startup_info
->dwFlags
& STARTF_USESHOWWINDOW
)
421 cmdShow
= pdb
->env_db
->startup_info
->wShowWindow
;
422 if (!TASK_Create( pModule
, cmdShow
))
425 /* Perform Win16 specific process initialization */
426 if ( type
== PROC_WIN16
)
427 if ( !NE_InitProcess( pModule
) )
430 /* Note: The USIG_PROCESS_CREATE signal is supposed to be sent in the
431 * context of the parent process. Actually, the USER signal proc
432 * doesn't really care about that, but it *does* require that the
433 * startup parameters are correctly set up, so that GetProcessDword
434 * works. Furthermore, before calling the USER signal proc the
435 * 16-bit stack must be set up, which it is only after TASK_Create
436 * in the case of a 16-bit process. Thus, we send the signal here.
439 /* Load USER32.DLL before calling UserSignalProc (relay debugging!) */
440 LoadLibraryA( "USER32.DLL" );
442 PROCESS_CallUserSignalProc( USIG_PROCESS_CREATE
, 0 );
444 PROCESS_CallUserSignalProc( USIG_THREAD_INIT
, 0 ); /* for initial thread */
446 PROCESS_CallUserSignalProc( USIG_PROCESS_INIT
, 0 );
448 /* Signal the parent process to continue */
449 server_call( REQ_INIT_PROCESS_DONE
);
451 /* Perform Win32 specific process initialization */
452 if ( type
== PROC_WIN32
)
454 /* Send the debug event to the debugger */
455 entry
= (LPTHREAD_START_ROUTINE
)RVA_PTR(pModule
->module32
,
456 OptionalHeader
.AddressOfEntryPoint
);
457 if (pdb
->flags
& PDB32_DEBUGGED
)
458 DEBUG_SendCreateProcessEvent( -1 /*FIXME*/, pModule
->module32
, entry
);
460 /* Create 32-bit MODREF */
461 if (!PE_CreateModule( pModule
->module32
, ofs
, 0, FALSE
)) goto error
;
463 /* Increment EXE refcount */
464 assert( pdb
->exe_modref
);
465 pdb
->exe_modref
->refCount
++;
467 /* Initialize thread-local storage */
471 PROCESS_CallUserSignalProc( USIG_PROCESS_LOADED
, 0 ); /* FIXME: correct location? */
473 if ( (pdb
->flags
& PDB32_CONSOLE_PROC
) || (pdb
->flags
& PDB32_DOS_PROC
) )
476 if ( type
== PROC_WIN32
)
478 EnterCriticalSection( &pdb
->crit_section
);
479 MODULE_DllProcessAttach( pdb
->exe_modref
, (LPVOID
)1 );
480 LeaveCriticalSection( &pdb
->crit_section
);
483 /* If requested, add entry point breakpoint */
484 if ( Options
.debug
&& TASK_AddTaskEntryBreakpoint
)
485 TASK_AddTaskEntryBreakpoint( pdb
->task
);
487 /* Now call the entry point */
488 PROCESS_CallUserSignalProc( USIG_PROCESS_RUNNING
, 0 );
493 TRACE_(relay
)( "Starting DOS process\n" );
495 ERR_(relay
)( "DOSVM_Enter returned; should not happen!\n" );
499 TRACE_(relay
)( "Starting Win16 process\n" );
501 ERR_(relay
)( "TASK_CallToStart returned; should not happen!\n" );
505 TRACE_(relay
)( "Starting Win32 process (entryproc=%p)\n", entry
);
506 ExitProcess( entry(NULL
) );
510 ExitProcess( GetLastError() );
514 /***********************************************************************
517 * Create a new process database and associated info.
519 PDB
*PROCESS_Create( NE_MODULE
*pModule
, LPCSTR cmd_line
, LPCSTR env
,
520 LPSECURITY_ATTRIBUTES psa
, LPSECURITY_ATTRIBUTES tsa
,
521 BOOL inherit
, DWORD flags
, STARTUPINFOA
*startup
,
522 PROCESS_INFORMATION
*info
)
524 HANDLE handles
[2], load_done_evt
= 0;
525 DWORD exitcode
, size
;
528 struct new_process_request
*req
= get_req_buffer();
530 PDB
*parent
= PROCESS_Current();
531 PDB
*pdb
= PROCESS_CreatePDB( parent
, inherit
);
533 if (!pdb
) return NULL
;
534 info
->hThread
= info
->hProcess
= INVALID_HANDLE_VALUE
;
535 if (!(load_done_evt
= CreateEventA( NULL
, TRUE
, FALSE
, NULL
))) goto error
;
537 /* the DEBUG_ONLY_THIS_PROCESS flag seems simply equivalent
538 * to DEBUG_PROCESS, contrary to Microsoft documentation (surprised?) */
539 if (flags
& DEBUG_ONLY_THIS_PROCESS
)
540 flags
= (flags
& ~DEBUG_ONLY_THIS_PROCESS
) | DEBUG_PROCESS
;
542 /* Create the process on the server side */
544 req
->inherit
= (psa
&& (psa
->nLength
>= sizeof(*psa
)) && psa
->bInheritHandle
);
545 req
->inherit_all
= inherit
;
546 req
->create_flags
= flags
;
547 req
->start_flags
= startup
->dwFlags
;
548 req
->event
= load_done_evt
;
549 if (startup
->dwFlags
& STARTF_USESTDHANDLES
)
551 req
->hstdin
= startup
->hStdInput
;
552 req
->hstdout
= startup
->hStdOutput
;
553 req
->hstderr
= startup
->hStdError
;
557 req
->hstdin
= GetStdHandle( STD_INPUT_HANDLE
);
558 req
->hstdout
= GetStdHandle( STD_OUTPUT_HANDLE
);
559 req
->hstderr
= GetStdHandle( STD_ERROR_HANDLE
);
561 req
->cmd_show
= startup
->wShowWindow
;
562 req
->env_ptr
= (void*)env
; /* FIXME: hack */
563 lstrcpynA( req
->cmdline
, cmd_line
, server_remaining(req
->cmdline
) );
564 if (server_call( REQ_NEW_PROCESS
)) goto error
;
565 pdb
->server_pid
= req
->pid
;
566 info
->hProcess
= req
->handle
;
567 info
->dwProcessId
= (DWORD
)pdb
->server_pid
;
569 if ((flags
& DEBUG_PROCESS
) ||
570 ((parent
->flags
& PDB32_DEBUGGED
) && !(flags
& DEBUG_ONLY_THIS_PROCESS
)))
571 pdb
->flags
|= PDB32_DEBUGGED
;
573 if (pModule
->module32
) /* Win32 process */
575 IMAGE_OPTIONAL_HEADER
*header
= &PE_HEADER(pModule
->module32
)->OptionalHeader
;
576 size
= header
->SizeOfStackReserve
;
577 if (header
->Subsystem
== IMAGE_SUBSYSTEM_WINDOWS_CUI
)
578 pdb
->flags
|= PDB32_CONSOLE_PROC
;
579 alloc_stack16
= TRUE
;
581 else if (!pModule
->dos_image
) /* Win16 process */
583 alloc_stack16
= FALSE
;
585 pdb
->flags
|= PDB32_WIN16_PROC
;
587 else /* DOS process */
589 alloc_stack16
= FALSE
;
591 pdb
->flags
|= PDB32_DOS_PROC
;
594 /* Create the main thread */
596 if (!(teb
= THREAD_Create( pdb
, flags
& CREATE_SUSPENDED
, size
,
597 alloc_stack16
, tsa
, &server_thandle
))) goto error
;
598 info
->hThread
= server_thandle
;
599 info
->dwThreadId
= (DWORD
)teb
->tid
;
600 teb
->startup
= PROCESS_Start
;
602 /* Pass module to new process (FIXME: hack) */
603 pdb
->module
= pModule
->self
;
604 SYSDEPS_SpawnThread( teb
);
606 /* Wait until process is initialized (or initialization failed) */
607 handles
[0] = info
->hProcess
;
608 handles
[1] = load_done_evt
;
610 switch ( WaitForMultipleObjects( 2, handles
, FALSE
, INFINITE
) )
613 ERR_(process
)( "WaitForMultipleObjects failed\n" );
617 /* Child initialization code returns error condition as exitcode */
618 if ( GetExitCodeProcess( info
->hProcess
, &exitcode
) )
619 SetLastError( exitcode
);
623 /* Get 16-bit task up and running */
624 if ( pdb
->flags
& PDB32_WIN16_PROC
)
626 /* Post event to start the task */
627 PostEvent16( pdb
->task
);
629 /* If we ourselves are a 16-bit task, we Yield() directly. */
630 if ( parent
->flags
& PDB32_WIN16_PROC
)
636 CloseHandle( load_done_evt
);
642 if (load_done_evt
) CloseHandle( load_done_evt
);
643 if (info
->hThread
!= INVALID_HANDLE_VALUE
) CloseHandle( info
->hThread
);
644 if (info
->hProcess
!= INVALID_HANDLE_VALUE
) CloseHandle( info
->hProcess
);
645 PROCESS_FreePDB( pdb
);
650 /***********************************************************************
651 * ExitProcess (KERNEL32.100)
653 void WINAPI
ExitProcess( DWORD status
)
655 EnterCriticalSection( &PROCESS_Current()->crit_section
);
656 MODULE_DllProcessDetach( TRUE
, (LPVOID
)1 );
657 LeaveCriticalSection( &PROCESS_Current()->crit_section
);
660 TerminateProcess( GetCurrentProcess(), status
);
663 /***********************************************************************
664 * ExitProcess16 (KERNEL.466)
666 void WINAPI
ExitProcess16( WORD status
)
668 SYSLEVEL_ReleaseWin16Lock();
669 ExitProcess( status
);
672 /******************************************************************************
673 * TerminateProcess (KERNEL32.684)
675 BOOL WINAPI
TerminateProcess( HANDLE handle
, DWORD exit_code
)
677 struct terminate_process_request
*req
= get_req_buffer();
678 req
->handle
= handle
;
679 req
->exit_code
= exit_code
;
680 return !server_call( REQ_TERMINATE_PROCESS
);
684 /***********************************************************************
685 * GetProcessDword (KERNEL32.18) (KERNEL.485)
686 * 'Of course you cannot directly access Windows internal structures'
688 DWORD WINAPI
GetProcessDword( DWORD dwProcessID
, INT offset
)
690 PDB
*process
= PROCESS_IdToPDB( dwProcessID
);
694 TRACE_(win32
)("(%ld, %d)\n", dwProcessID
, offset
);
695 if ( !process
) return 0;
699 case GPD_APP_COMPAT_FLAGS
:
700 pTask
= (TDB
*)GlobalLock16( process
->task
);
701 return pTask
? pTask
->compat_flags
: 0;
703 case GPD_LOAD_DONE_EVENT
:
704 return process
->load_done_evt
;
706 case GPD_HINSTANCE16
:
707 pTask
= (TDB
*)GlobalLock16( process
->task
);
708 return pTask
? pTask
->hInstance
: 0;
710 case GPD_WINDOWS_VERSION
:
711 pTask
= (TDB
*)GlobalLock16( process
->task
);
712 return pTask
? pTask
->version
: 0;
715 if ( process
!= PROCESS_Current() ) return 0;
716 return (DWORD
)NtCurrentTeb() - 0x10 /* FIXME */;
719 return (DWORD
)process
;
721 case GPD_STARTF_SHELLDATA
: /* return stdoutput handle from startupinfo ??? */
722 return process
->env_db
->startup_info
->hStdOutput
;
724 case GPD_STARTF_HOTKEY
: /* return stdinput handle from startupinfo ??? */
725 return process
->env_db
->startup_info
->hStdInput
;
727 case GPD_STARTF_SHOWWINDOW
:
728 return process
->env_db
->startup_info
->wShowWindow
;
730 case GPD_STARTF_SIZE
:
731 x
= process
->env_db
->startup_info
->dwXSize
;
732 if ( x
== CW_USEDEFAULT
) x
= CW_USEDEFAULT16
;
733 y
= process
->env_db
->startup_info
->dwYSize
;
734 if ( y
== CW_USEDEFAULT
) y
= CW_USEDEFAULT16
;
735 return MAKELONG( x
, y
);
737 case GPD_STARTF_POSITION
:
738 x
= process
->env_db
->startup_info
->dwX
;
739 if ( x
== CW_USEDEFAULT
) x
= CW_USEDEFAULT16
;
740 y
= process
->env_db
->startup_info
->dwY
;
741 if ( y
== CW_USEDEFAULT
) y
= CW_USEDEFAULT16
;
742 return MAKELONG( x
, y
);
744 case GPD_STARTF_FLAGS
:
745 return process
->env_db
->startup_info
->dwFlags
;
748 return (DWORD
)process
->parent
->server_pid
;
751 return process
->flags
;
754 return process
->process_dword
;
757 ERR_(win32
)("Unknown offset %d\n", offset
);
762 /***********************************************************************
763 * SetProcessDword (KERNEL.484)
764 * 'Of course you cannot directly access Windows internal structures'
766 void WINAPI
SetProcessDword( DWORD dwProcessID
, INT offset
, DWORD value
)
768 PDB
*process
= PROCESS_IdToPDB( dwProcessID
);
770 TRACE_(win32
)("(%ld, %d)\n", dwProcessID
, offset
);
771 if ( !process
) return;
775 case GPD_APP_COMPAT_FLAGS
:
776 case GPD_LOAD_DONE_EVENT
:
777 case GPD_HINSTANCE16
:
778 case GPD_WINDOWS_VERSION
:
781 case GPD_STARTF_SHELLDATA
:
782 case GPD_STARTF_HOTKEY
:
783 case GPD_STARTF_SHOWWINDOW
:
784 case GPD_STARTF_SIZE
:
785 case GPD_STARTF_POSITION
:
786 case GPD_STARTF_FLAGS
:
789 ERR_(win32
)("Not allowed to modify offset %d\n", offset
);
793 process
->process_dword
= value
;
797 ERR_(win32
)("Unknown offset %d\n", offset
);
803 /***********************************************************************
804 * GetCurrentProcess (KERNEL32.198)
806 HANDLE WINAPI
GetCurrentProcess(void)
808 return CURRENT_PROCESS_PSEUDOHANDLE
;
812 /*********************************************************************
813 * OpenProcess (KERNEL32.543)
815 HANDLE WINAPI
OpenProcess( DWORD access
, BOOL inherit
, DWORD id
)
818 struct open_process_request
*req
= get_req_buffer();
820 req
->pid
= (void *)id
;
821 req
->access
= access
;
822 req
->inherit
= inherit
;
823 if (!server_call( REQ_OPEN_PROCESS
)) ret
= req
->handle
;
827 /*********************************************************************
828 * MapProcessHandle (KERNEL.483)
830 DWORD WINAPI
MapProcessHandle( HANDLE handle
)
833 struct get_process_info_request
*req
= get_req_buffer();
834 req
->handle
= handle
;
835 if (!server_call( REQ_GET_PROCESS_INFO
)) ret
= (DWORD
)req
->pid
;
839 /***********************************************************************
840 * GetCurrentProcessId (KERNEL32.199)
842 DWORD WINAPI
GetCurrentProcessId(void)
844 return (DWORD
)PROCESS_Current()->server_pid
;
848 /***********************************************************************
849 * GetProcessHeap (KERNEL32.259)
851 HANDLE WINAPI
GetProcessHeap(void)
853 PDB
*pdb
= PROCESS_Current();
854 return pdb
->heap
? pdb
->heap
: SystemHeap
;
858 /***********************************************************************
859 * GetThreadLocale (KERNEL32.295)
861 LCID WINAPI
GetThreadLocale(void)
863 return PROCESS_Current()->locale
;
867 /***********************************************************************
868 * SetPriorityClass (KERNEL32.503)
870 BOOL WINAPI
SetPriorityClass( HANDLE hprocess
, DWORD priorityclass
)
872 struct set_process_info_request
*req
= get_req_buffer();
873 req
->handle
= hprocess
;
874 req
->priority
= priorityclass
;
875 req
->mask
= SET_PROCESS_INFO_PRIORITY
;
876 return !server_call( REQ_SET_PROCESS_INFO
);
880 /***********************************************************************
881 * GetPriorityClass (KERNEL32.250)
883 DWORD WINAPI
GetPriorityClass(HANDLE hprocess
)
886 struct get_process_info_request
*req
= get_req_buffer();
887 req
->handle
= hprocess
;
888 if (!server_call( REQ_GET_PROCESS_INFO
)) ret
= req
->priority
;
893 /***********************************************************************
894 * SetProcessAffinityMask (KERNEL32.662)
896 BOOL WINAPI
SetProcessAffinityMask( HANDLE hProcess
, DWORD affmask
)
898 struct set_process_info_request
*req
= get_req_buffer();
899 req
->handle
= hProcess
;
900 req
->affinity
= affmask
;
901 req
->mask
= SET_PROCESS_INFO_AFFINITY
;
902 return !server_call( REQ_SET_PROCESS_INFO
);
905 /**********************************************************************
906 * GetProcessAffinityMask (KERNEL32.373)
908 BOOL WINAPI
GetProcessAffinityMask( HANDLE hProcess
,
909 LPDWORD lpProcessAffinityMask
,
910 LPDWORD lpSystemAffinityMask
)
913 struct get_process_info_request
*req
= get_req_buffer();
914 req
->handle
= hProcess
;
915 if (!server_call( REQ_GET_PROCESS_INFO
))
917 if (lpProcessAffinityMask
) *lpProcessAffinityMask
= req
->process_affinity
;
918 if (lpSystemAffinityMask
) *lpSystemAffinityMask
= req
->system_affinity
;
925 /***********************************************************************
926 * GetStdHandle (KERNEL32.276)
928 HANDLE WINAPI
GetStdHandle( DWORD std_handle
)
930 PDB
*pdb
= PROCESS_Current();
934 case STD_INPUT_HANDLE
: return pdb
->env_db
->hStdin
;
935 case STD_OUTPUT_HANDLE
: return pdb
->env_db
->hStdout
;
936 case STD_ERROR_HANDLE
: return pdb
->env_db
->hStderr
;
938 SetLastError( ERROR_INVALID_PARAMETER
);
939 return INVALID_HANDLE_VALUE
;
943 /***********************************************************************
944 * SetStdHandle (KERNEL32.506)
946 BOOL WINAPI
SetStdHandle( DWORD std_handle
, HANDLE handle
)
948 PDB
*pdb
= PROCESS_Current();
949 /* FIXME: should we close the previous handle? */
952 case STD_INPUT_HANDLE
:
953 pdb
->env_db
->hStdin
= handle
;
955 case STD_OUTPUT_HANDLE
:
956 pdb
->env_db
->hStdout
= handle
;
958 case STD_ERROR_HANDLE
:
959 pdb
->env_db
->hStderr
= handle
;
962 SetLastError( ERROR_INVALID_PARAMETER
);
966 /***********************************************************************
967 * GetProcessVersion (KERNEL32)
969 DWORD WINAPI
GetProcessVersion( DWORD processid
)
972 PDB
*pdb
= PROCESS_IdToPDB( processid
);
975 if (!(pTask
= (TDB
*)GlobalLock16( pdb
->task
))) return 0;
976 return (pTask
->version
&0xff) | (((pTask
->version
>>8) & 0xff)<<16);
979 /***********************************************************************
980 * GetProcessFlags (KERNEL32)
982 DWORD WINAPI
GetProcessFlags( DWORD processid
)
984 PDB
*pdb
= PROCESS_IdToPDB( processid
);
989 /***********************************************************************
990 * SetProcessWorkingSetSize [KERNEL32.662]
991 * Sets the min/max working set sizes for a specified process.
994 * hProcess [I] Handle to the process of interest
995 * minset [I] Specifies minimum working set size
996 * maxset [I] Specifies maximum working set size
1000 BOOL WINAPI
SetProcessWorkingSetSize(HANDLE hProcess
,DWORD minset
,
1003 FIXME_(process
)("(0x%08x,%ld,%ld): stub - harmless\n",hProcess
,minset
,maxset
);
1004 if(( minset
== -1) && (maxset
== -1)) {
1005 /* Trim the working set to zero */
1006 /* Swap the process out of physical RAM */
1011 /***********************************************************************
1012 * GetProcessWorkingSetSize (KERNEL32)
1014 BOOL WINAPI
GetProcessWorkingSetSize(HANDLE hProcess
,LPDWORD minset
,
1017 FIXME_(process
)("(0x%08x,%p,%p): stub\n",hProcess
,minset
,maxset
);
1018 /* 32 MB working set size */
1019 if (minset
) *minset
= 32*1024*1024;
1020 if (maxset
) *maxset
= 32*1024*1024;
1024 /***********************************************************************
1025 * SetProcessShutdownParameters (KERNEL32)
1027 * CHANGED - James Sutherland (JamesSutherland@gmx.de)
1028 * Now tracks changes made (but does not act on these changes)
1029 * NOTE: the definition for SHUTDOWN_NORETRY was done on guesswork.
1030 * It really shouldn't be here, but I'll move it when it's been checked!
1032 #define SHUTDOWN_NORETRY 1
1033 static unsigned int shutdown_noretry
= 0;
1034 static unsigned int shutdown_priority
= 0x280L
;
1035 BOOL WINAPI
SetProcessShutdownParameters(DWORD level
,DWORD flags
)
1037 if (flags
& SHUTDOWN_NORETRY
)
1038 shutdown_noretry
= 1;
1040 shutdown_noretry
= 0;
1041 if (level
> 0x100L
&& level
< 0x3FFL
)
1042 shutdown_priority
= level
;
1045 ERR_(process
)("invalid priority level 0x%08lx\n", level
);
1052 /***********************************************************************
1053 * GetProcessShutdownParameters (KERNEL32)
1056 BOOL WINAPI
GetProcessShutdownParameters( LPDWORD lpdwLevel
,
1059 (*lpdwLevel
) = shutdown_priority
;
1060 (*lpdwFlags
) = (shutdown_noretry
* SHUTDOWN_NORETRY
);
1063 /***********************************************************************
1064 * SetProcessPriorityBoost (KERNEL32)
1066 BOOL WINAPI
SetProcessPriorityBoost(HANDLE hprocess
,BOOL disableboost
)
1068 FIXME_(process
)("(%d,%d): stub\n",hprocess
,disableboost
);
1069 /* Say we can do it. I doubt the program will notice that we don't. */
1074 /***********************************************************************
1075 * ReadProcessMemory (KERNEL32)
1077 BOOL WINAPI
ReadProcessMemory( HANDLE process
, LPCVOID addr
, LPVOID buffer
, DWORD size
,
1078 LPDWORD bytes_read
)
1080 struct read_process_memory_request
*req
= get_req_buffer();
1081 unsigned int offset
= (unsigned int)addr
% sizeof(int);
1082 unsigned int max
= server_remaining( req
->data
); /* max length in one request */
1085 if (bytes_read
) *bytes_read
= size
;
1087 /* first time, read total length to check for permissions */
1088 req
->handle
= process
;
1089 req
->addr
= (char *)addr
- offset
;
1090 req
->len
= (size
+ offset
+ sizeof(int) - 1) / sizeof(int);
1091 if (server_call( REQ_READ_PROCESS_MEMORY
)) goto error
;
1093 if (size
<= max
- offset
)
1095 memcpy( buffer
, (char *)req
->data
+ offset
, size
);
1099 /* now take care of the remaining data */
1100 memcpy( buffer
, (char *)req
->data
+ offset
, max
- offset
);
1105 if (max
> size
) max
= size
;
1106 req
->handle
= process
;
1107 req
->addr
= (char *)addr
+ pos
;
1108 req
->len
= (max
+ sizeof(int) - 1) / sizeof(int);
1109 if (server_call( REQ_READ_PROCESS_MEMORY
)) goto error
;
1110 memcpy( (char *)buffer
+ pos
, (char *)req
->data
, max
);
1117 if (bytes_read
) *bytes_read
= 0;
1122 /***********************************************************************
1123 * WriteProcessMemory (KERNEL32)
1125 BOOL WINAPI
WriteProcessMemory( HANDLE process
, LPVOID addr
, LPVOID buffer
, DWORD size
,
1126 LPDWORD bytes_written
)
1128 unsigned int first_offset
, last_offset
;
1129 struct write_process_memory_request
*req
= get_req_buffer();
1130 unsigned int max
= server_remaining( req
->data
); /* max length in one request */
1131 unsigned int pos
, last_mask
;
1135 SetLastError( ERROR_INVALID_PARAMETER
);
1138 if (bytes_written
) *bytes_written
= size
;
1140 /* compute the mask for the first int */
1141 req
->first_mask
= ~0;
1142 first_offset
= (unsigned int)addr
% sizeof(int);
1143 memset( &req
->first_mask
, 0, first_offset
);
1145 /* compute the mask for the last int */
1146 last_offset
= (size
+ first_offset
) % sizeof(int);
1148 memset( &last_mask
, 0xff, last_offset
? last_offset
: sizeof(int) );
1150 req
->handle
= process
;
1151 req
->addr
= (char *)addr
- first_offset
;
1152 /* for the first request, use the total length */
1153 req
->len
= (size
+ first_offset
+ sizeof(int) - 1) / sizeof(int);
1155 if (size
+ first_offset
< max
) /* we can do it in one round */
1157 memcpy( (char *)req
->data
+ first_offset
, buffer
, size
);
1158 req
->last_mask
= last_mask
;
1159 if (server_call( REQ_WRITE_PROCESS_MEMORY
)) goto error
;
1163 /* needs multiple server calls */
1165 memcpy( (char *)req
->data
+ first_offset
, buffer
, max
- first_offset
);
1166 req
->last_mask
= ~0;
1167 if (server_call( REQ_WRITE_PROCESS_MEMORY
)) goto error
;
1168 pos
= max
- first_offset
;
1172 if (size
<= max
) /* last one */
1174 req
->last_mask
= last_mask
;
1177 req
->handle
= process
;
1178 req
->addr
= (char *)addr
+ pos
;
1179 req
->len
= (max
+ sizeof(int) - 1) / sizeof(int);
1180 req
->first_mask
= ~0;
1181 memcpy( req
->data
, buffer
+ pos
, max
);
1182 if (server_call( REQ_WRITE_PROCESS_MEMORY
)) goto error
;
1189 if (bytes_written
) *bytes_written
= 0;
1195 /***********************************************************************
1196 * RegisterServiceProcess (KERNEL, KERNEL32)
1198 * A service process calls this function to ensure that it continues to run
1199 * even after a user logged off.
1201 DWORD WINAPI
RegisterServiceProcess(DWORD dwProcessId
, DWORD dwType
)
1203 /* I don't think that Wine needs to do anything in that function */
1204 return 1; /* success */
1207 /***********************************************************************
1208 * GetExitCodeProcess [KERNEL32.325]
1210 * Gets termination status of specified process
1216 BOOL WINAPI
GetExitCodeProcess(
1217 HANDLE hProcess
, /* [I] handle to the process */
1218 LPDWORD lpExitCode
) /* [O] address to receive termination status */
1221 struct get_process_info_request
*req
= get_req_buffer();
1222 req
->handle
= hProcess
;
1223 if (!server_call( REQ_GET_PROCESS_INFO
))
1225 if (lpExitCode
) *lpExitCode
= req
->exit_code
;
1232 /***********************************************************************
1233 * GetProcessHeaps [KERNEL32.376]
1235 DWORD WINAPI
GetProcessHeaps(DWORD nrofheaps
,HANDLE
*heaps
) {
1236 FIXME_(win32
)("(%ld,%p), incomplete implementation.\n",nrofheaps
,heaps
);
1239 heaps
[0] = GetProcessHeap();
1240 /* ... probably SystemHeap too ? */
1243 /* number of available heaps */
1248 /***********************************************************************
1249 * SetErrorMode (KERNEL32.486)
1251 UINT WINAPI
SetErrorMode( UINT mode
)
1253 UINT old
= PROCESS_Current()->error_mode
;
1254 PROCESS_Current()->error_mode
= mode
;