4 * Copyright 1996, 1998 Alexandre Julliard
15 #include "wine/winbase16.h"
16 #include "wine/exception.h"
33 #include "debugtools.h"
35 DEFAULT_DEBUG_CHANNEL(process
);
36 DECLARE_DEBUG_CHANNEL(relay
);
37 DECLARE_DEBUG_CHANNEL(win32
);
40 static ENVDB initial_envdb
;
41 static STARTUPINFOA initial_startup
;
42 static HFILE main_exe_file
= -1;
44 static PDB
*PROCESS_First
;
47 /***********************************************************************
50 * Convert a process id to a PDB, making sure it is valid.
52 PDB
*PROCESS_IdToPDB( DWORD pid
)
56 if (!pid
) return PROCESS_Current();
60 if ((DWORD
)pdb
->server_pid
== pid
) return pdb
;
63 SetLastError( ERROR_INVALID_PARAMETER
);
68 /***********************************************************************
69 * PROCESS_CallUserSignalProc
71 * FIXME: Some of the signals aren't sent correctly!
73 * The exact meaning of the USER signals is undocumented, but this
74 * should cover the basic idea:
76 * USIG_DLL_UNLOAD_WIN16
77 * This is sent when a 16-bit module is unloaded.
79 * USIG_DLL_UNLOAD_WIN32
80 * This is sent when a 32-bit module is unloaded.
82 * USIG_DLL_UNLOAD_ORPHANS
83 * This is sent after the last Win3.1 module is unloaded,
84 * to allow removal of orphaned menus.
86 * USIG_FAULT_DIALOG_PUSH
87 * USIG_FAULT_DIALOG_POP
88 * These are called to allow USER to prepare for displaying a
89 * fault dialog, even though the fault might have happened while
90 * inside a USER critical section.
93 * This is called from the context of a new thread, as soon as it
97 * This is called, still in its context, just before a thread is
100 * USIG_PROCESS_CREATE
101 * This is called, in the parent process context, after a new process
105 * This is called in the new process context, just after the main thread
106 * has started execution (after the main thread's USIG_THREAD_INIT has
109 * USIG_PROCESS_LOADED
110 * This is called after the executable file has been loaded into the
111 * new process context.
113 * USIG_PROCESS_RUNNING
114 * This is called immediately before the main entry point is called.
117 * This is called in the context of a process that is about to
118 * terminate (but before the last thread's USIG_THREAD_EXIT has
121 * USIG_PROCESS_DESTROY
122 * This is called after a process has terminated.
125 * The meaning of the dwFlags bits is as follows:
128 * Current process is 32-bit.
131 * Current process is a (Win32) GUI process.
133 * USIG_FLAGS_FEEDBACK
134 * Current process needs 'feedback' (determined from the STARTUPINFO
135 * flags STARTF_FORCEONFEEDBACK / STARTF_FORCEOFFFEEDBACK).
138 * The signal is being sent due to a fault.
140 void PROCESS_CallUserSignalProc( UINT uCode
, HMODULE hModule
)
142 DWORD flags
= PROCESS_Current()->flags
;
143 DWORD startup_flags
= PROCESS_Current()->env_db
->startup_info
->dwFlags
;
146 /* Determine dwFlags */
148 if ( !(flags
& PDB32_WIN16_PROC
) ) dwFlags
|= USIG_FLAGS_WIN32
;
150 if ( !(flags
& PDB32_CONSOLE_PROC
) ) dwFlags
|= USIG_FLAGS_GUI
;
152 if ( dwFlags
& USIG_FLAGS_GUI
)
154 /* Feedback defaults to ON */
155 if ( !(startup_flags
& STARTF_FORCEOFFFEEDBACK
) )
156 dwFlags
|= USIG_FLAGS_FEEDBACK
;
160 /* Feedback defaults to OFF */
161 if (startup_flags
& STARTF_FORCEONFEEDBACK
)
162 dwFlags
|= USIG_FLAGS_FEEDBACK
;
165 /* Convert module handle to 16-bit */
167 if ( HIWORD( hModule
) )
168 hModule
= MapHModuleLS( hModule
);
170 /* Call USER signal proc */
172 if ( Callout
.UserSignalProc
)
174 if ( uCode
== USIG_THREAD_INIT
|| uCode
== USIG_THREAD_EXIT
)
175 Callout
.UserSignalProc( uCode
, GetCurrentThreadId(), dwFlags
, hModule
);
177 Callout
.UserSignalProc( uCode
, GetCurrentProcessId(), dwFlags
, hModule
);
181 /***********************************************************************
182 * PROCESS_CreateEnvDB
184 * Create the env DB for a newly started process.
186 static BOOL
PROCESS_CreateEnvDB(void)
188 struct init_process_request
*req
= get_req_buffer();
189 PDB
*pdb
= PROCESS_Current();
190 ENVDB
*env_db
= pdb
->env_db
;
191 STARTUPINFOA
*startup
= env_db
->startup_info
;
193 /* Retrieve startup info from the server */
195 req
->ldt_copy
= ldt_copy
;
196 req
->ldt_flags
= ldt_flags_copy
;
197 req
->ppid
= getppid();
198 if (server_call( REQ_INIT_PROCESS
)) return FALSE
;
199 startup
->dwFlags
= req
->start_flags
;
200 startup
->wShowWindow
= req
->cmd_show
;
201 env_db
->hStdin
= startup
->hStdInput
= req
->hstdin
;
202 env_db
->hStdout
= startup
->hStdOutput
= req
->hstdout
;
203 env_db
->hStderr
= startup
->hStdError
= req
->hstderr
;
209 /***********************************************************************
212 * Free a PDB and all associated storage.
214 static void PROCESS_FreePDB( PDB
*pdb
)
216 PDB
**pptr
= &PROCESS_First
;
218 ENV_FreeEnvironment( pdb
);
219 while (*pptr
&& (*pptr
!= pdb
)) pptr
= &(*pptr
)->next
;
220 if (*pptr
) *pptr
= pdb
->next
;
221 HeapFree( GetProcessHeap(), 0, pdb
);
225 /***********************************************************************
228 * Allocate and fill a PDB structure.
229 * Runs in the context of the parent process.
231 static PDB
*PROCESS_CreatePDB( PDB
*parent
, BOOL inherit
)
233 PDB
*pdb
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
234 sizeof(PDB
) + sizeof(ENVDB
) + sizeof(STARTUPINFOA
) );
236 if (!pdb
) return NULL
;
237 pdb
->exit_code
= STILL_ACTIVE
;
238 pdb
->heap
= GetProcessHeap();
240 pdb
->running_threads
= 1;
241 pdb
->ring0_threads
= 1;
242 pdb
->parent
= parent
;
244 pdb
->priority
= 8; /* Normal */
245 pdb
->next
= PROCESS_First
;
246 pdb
->winver
= 0xffff; /* to be determined */
247 pdb
->main_queue
= INVALID_HANDLE_VALUE16
;
248 pdb
->env_db
= (ENVDB
*)(pdb
+ 1);
249 pdb
->env_db
->startup_info
= (STARTUPINFOA
*)(pdb
->env_db
+ 1);
251 InitializeCriticalSection( &pdb
->env_db
->section
);
258 /***********************************************************************
261 BOOL
PROCESS_Init( BOOL win32
)
263 struct init_process_request
*req
;
264 PDB
*pdb
= PROCESS_Current();
266 /* Fill the initial process structure */
267 pdb
->exit_code
= STILL_ACTIVE
;
269 pdb
->running_threads
= 1;
270 pdb
->ring0_threads
= 1;
271 pdb
->env_db
= &initial_envdb
;
273 pdb
->priority
= 8; /* Normal */
274 pdb
->winver
= 0xffff; /* to be determined */
275 pdb
->main_queue
= INVALID_HANDLE_VALUE16
;
276 initial_envdb
.startup_info
= &initial_startup
;
281 pdb
->flags
= PDB32_WIN16_PROC
;
282 NtCurrentTeb()->tibflags
&= ~TEBF_WIN32
;
285 /* Setup the server connection */
286 NtCurrentTeb()->socket
= CLIENT_InitServer();
287 if (CLIENT_InitThread()) return FALSE
;
289 /* Retrieve startup info from the server */
290 req
= get_req_buffer();
291 req
->ldt_copy
= ldt_copy
;
292 req
->ldt_flags
= ldt_flags_copy
;
293 req
->ppid
= getppid();
294 if (server_call( REQ_INIT_PROCESS
)) return FALSE
;
295 main_exe_file
= req
->exe_file
;
296 initial_startup
.dwFlags
= req
->start_flags
;
297 initial_startup
.wShowWindow
= req
->cmd_show
;
298 initial_envdb
.hStdin
= initial_startup
.hStdInput
= req
->hstdin
;
299 initial_envdb
.hStdout
= initial_startup
.hStdOutput
= req
->hstdout
;
300 initial_envdb
.hStderr
= initial_startup
.hStdError
= req
->hstderr
;
301 initial_envdb
.cmd_line
= "";
303 /* Initialize signal handling */
304 if (!SIGNAL_Init()) return FALSE
;
306 /* Remember TEB selector of initial process for emergency use */
307 SYSLEVEL_EmergencyTeb
= NtCurrentTeb()->teb_sel
;
309 /* Create the system and process heaps */
310 if (!HEAP_CreateSystemHeap()) return FALSE
;
311 pdb
->heap
= HeapCreate( HEAP_GROWABLE
, 0, 0 );
313 /* Create the idle event for the initial process
314 FIXME 1: Shouldn't we call UserSignalProc for the initial process too?
315 FIXME 2: It seems to me that the initial pdb becomes never freed, so I don't now
316 where to release the idle event for the initial process.
318 pdb
->idle_event
= CreateEventA ( NULL
, TRUE
, FALSE
, NULL
);
319 pdb
->idle_event
= ConvertToGlobalHandle ( pdb
->idle_event
);
321 /* Copy the parent environment */
322 if (!ENV_BuildEnvironment()) return FALSE
;
324 /* Create the SEGPTR heap */
325 if (!(SegptrHeap
= HeapCreate( HEAP_WINE_SEGPTR
, 0, 0 ))) return FALSE
;
327 /* Initialize the critical sections */
328 InitializeCriticalSection( &pdb
->crit_section
);
329 InitializeCriticalSection( &initial_envdb
.section
);
335 /***********************************************************************
338 * Load system DLLs into the initial process (and initialize them)
340 static inline int load_system_dlls(void)
342 char driver
[MAX_PATH
];
344 if (!LoadLibraryA( "KERNEL32" )) return 0;
346 PROFILE_GetWineIniString( "Wine", "GraphicsDriver", "x11drv", driver
, sizeof(driver
) );
347 if (!LoadLibraryA( driver
))
349 MESSAGE( "Could not load graphics driver '%s'\n", driver
);
353 if (!LoadLibraryA("GDI32.DLL")) return 0;
354 if (!LoadLibrary16("GDI.EXE")) return 0;
355 if (!LoadLibrary16("USER.EXE")) return 0;
356 if (!LoadLibraryA("USER32.DLL")) return 0;
362 /***********************************************************************
365 * Startup routine of a new Win32 process. Runs on the new process stack.
367 static void start_process(void)
369 struct init_process_done_request
*req
= get_req_buffer();
372 UINT cmdShow
= SW_SHOWNORMAL
;
373 LPTHREAD_START_ROUTINE entry
;
374 PDB
*pdb
= PROCESS_Current();
375 HMODULE main_module
= pdb
->exe_modref
->module
;
377 /* Increment EXE refcount */
378 pdb
->exe_modref
->refCount
++;
380 /* Retrieve entry point address */
381 entry
= (LPTHREAD_START_ROUTINE
)RVA_PTR( main_module
, OptionalHeader
.AddressOfEntryPoint
);
383 /* Create 16-bit dummy module */
384 if ((hModule16
= MODULE_CreateDummyModule( pdb
->exe_modref
->filename
, main_module
)) < 32)
385 ExitProcess( hModule16
);
387 if (pdb
->env_db
->startup_info
->dwFlags
& STARTF_USESHOWWINDOW
)
388 cmdShow
= pdb
->env_db
->startup_info
->wShowWindow
;
389 if (!TASK_Create( (NE_MODULE
*)GlobalLock16( hModule16
), cmdShow
)) goto error
;
391 /* Signal the parent process to continue */
392 req
->module
= (void *)main_module
;
394 server_call( REQ_INIT_PROCESS_DONE
);
395 debugged
= req
->debugged
;
397 if (pdb
->flags
& PDB32_CONSOLE_PROC
) AllocConsole();
399 /* Load the system dlls */
400 if (!load_system_dlls()) goto error
;
402 /* Get pointers to USER routines called by KERNEL */
405 /* Call FinalUserInit routine */
406 Callout
.FinalUserInit16();
408 /* Note: The USIG_PROCESS_CREATE signal is supposed to be sent in the
409 * context of the parent process. Actually, the USER signal proc
410 * doesn't really care about that, but it *does* require that the
411 * startup parameters are correctly set up, so that GetProcessDword
412 * works. Furthermore, before calling the USER signal proc the
413 * 16-bit stack must be set up, which it is only after TASK_Create
414 * in the case of a 16-bit process. Thus, we send the signal here.
417 PROCESS_CallUserSignalProc( USIG_PROCESS_CREATE
, 0 );
418 PROCESS_CallUserSignalProc( USIG_THREAD_INIT
, 0 );
419 PROCESS_CallUserSignalProc( USIG_PROCESS_INIT
, 0 );
420 PROCESS_CallUserSignalProc( USIG_PROCESS_LOADED
, 0 );
422 EnterCriticalSection( &pdb
->crit_section
);
424 MODULE_DllProcessAttach( pdb
->exe_modref
, (LPVOID
)1 );
425 LeaveCriticalSection( &pdb
->crit_section
);
427 /* Call UserSignalProc ( USIG_PROCESS_RUNNING ... ) only for non-GUI win32 apps */
428 if (pdb
->flags
& PDB32_CONSOLE_PROC
)
429 PROCESS_CallUserSignalProc( USIG_PROCESS_RUNNING
, 0 );
431 TRACE_(relay
)( "Starting Win32 process (entryproc=%p)\n", entry
);
432 if (debugged
) DbgBreakPoint();
433 /* FIXME: should use _PEB as parameter for NT 3.5 programs !
434 * Dunno about other OSs */
435 ExitProcess( entry(NULL
) );
438 ExitProcess( GetLastError() );
442 /***********************************************************************
445 * Initialisation of a new Win32 process.
447 void PROCESS_Init32( HFILE hFile
, LPCSTR filename
, LPCSTR cmd_line
)
450 PDB
*pdb
= PROCESS_Current();
452 pdb
->env_db
->cmd_line
= HEAP_strdupA( GetProcessHeap(), 0, cmd_line
);
454 /* load main module */
455 if ((main_module
= PE_LoadImage( hFile
, filename
)) < 32)
456 ExitProcess( main_module
);
458 if (PE_HEADER(main_module
)->FileHeader
.Characteristics
& IMAGE_FILE_DLL
)
460 SetLastError( 20 ); /* FIXME: not the right error code */
465 /* Create 32-bit MODREF */
466 if (!PE_CreateModule( main_module
, filename
, 0, FALSE
)) goto error
;
468 /* allocate main thread stack */
469 if (!THREAD_InitStack( NtCurrentTeb(),
470 PE_HEADER(main_module
)->OptionalHeader
.SizeOfStackReserve
, TRUE
))
473 SIGNAL_Init(); /* reinitialize signal stack */
475 /* switch to the new stack */
476 CALL32_Init( &IF1632_CallLargeStack
, start_process
, NtCurrentTeb()->stack_top
);
478 ExitProcess( GetLastError() );
482 /***********************************************************************
483 * PROCESS_InitWinelib
485 * Initialisation of a new Winelib process.
487 void PROCESS_InitWinelib( int argc
, char *argv
[] )
495 if (!MAIN_MainInit( argc
, argv
, TRUE
)) exit(1);
496 pdb
= PROCESS_Current();
498 /* build command-line */
499 for (i
= 0; Options
.argv
[i
]; i
++) len
+= strlen(Options
.argv
[i
]) + 1;
500 if (!(cmdline
= HeapAlloc( GetProcessHeap(), 0, len
))) goto error
;
501 for (p
= cmdline
, i
= 0; Options
.argv
[i
]; i
++)
503 strcpy( p
, Options
.argv
[i
] );
507 if (p
> cmdline
) p
--;
509 pdb
->env_db
->cmd_line
= cmdline
;
511 /* create 32-bit module for main exe */
512 if ((main_module
= BUILTIN32_LoadExeModule( &filename
)) < 32 ) goto error
;
514 /* Create 32-bit MODREF */
515 if (!PE_CreateModule( main_module
, filename
, 0, FALSE
)) goto error
;
517 /* allocate main thread stack */
518 if (!THREAD_InitStack( NtCurrentTeb(),
519 PE_HEADER(main_module
)->OptionalHeader
.SizeOfStackReserve
, TRUE
))
522 SIGNAL_Init(); /* reinitialize signal stack */
524 /* switch to the new stack */
525 CALL32_Init( &IF1632_CallLargeStack
, start_process
, NtCurrentTeb()->stack_top
);
527 ExitProcess( GetLastError() );
531 /***********************************************************************
534 * Build an argv array from a command-line.
535 * The command-line is modified to insert nulls.
537 static char **build_argv( char *cmdline
, char *argv0
)
545 while (*p
&& isspace(*p
)) p
++;
548 while (*p
&& !isspace(*p
)) p
++;
551 if ((argv
= malloc( count
* sizeof(*argv
) )))
553 char **argvptr
= argv
;
554 if (argv0
) *argvptr
++ = argv0
;
558 while (*p
&& isspace(*p
)) *p
++ = 0;
561 while (*p
&& !isspace(*p
)) p
++;
569 /***********************************************************************
572 * Build the environment of a new child process.
574 static char **build_envp( const char *env
)
580 for (p
= env
, count
= 0; *p
; count
++) p
+= strlen(p
) + 1;
582 if ((envp
= malloc( count
* sizeof(*envp
) )))
584 extern char **environ
;
585 char **envptr
= envp
;
586 char **unixptr
= environ
;
587 /* first put PATH, HOME and WINEPREFIX from the unix env */
588 for (unixptr
= environ
; unixptr
&& *unixptr
; unixptr
++)
589 if (!memcmp( *unixptr
, "PATH=", 5 ) ||
590 !memcmp( *unixptr
, "HOME=", 5 ) ||
591 !memcmp( *unixptr
, "WINEPREFIX=", 11 )) *envptr
++ = *unixptr
;
592 /* now put the Windows environment strings */
593 for (p
= env
; *p
; p
+= strlen(p
) + 1)
595 if (memcmp( p
, "PATH=", 5 ) &&
596 memcmp( p
, "HOME=", 5 ) &&
597 memcmp( p
, "WINEPREFIX=", 11 )) *envptr
++ = (char *)p
;
605 /***********************************************************************
608 * Locate the Wine binary to exec for a new Win32 process.
610 static void exec_wine_binary( char **argv
, char **envp
)
612 const char *path
, *pos
, *ptr
;
614 /* first try bin directory */
615 argv
[0] = BINDIR
"/wine";
616 execve( argv
[0], argv
, envp
);
618 /* now try the path of argv0 of the current binary */
619 if (!(argv
[0] = malloc( strlen(argv0
) + 6 ))) return;
620 if ((ptr
= strrchr( argv0
, '/' )))
622 memcpy( argv
[0], argv0
, ptr
- argv0
);
623 strcpy( argv
[0] + (ptr
- argv0
), "/wine" );
624 execve( argv
[0], argv
, envp
);
628 /* now search in the Unix path */
629 if ((path
= getenv( "PATH" )))
631 if (!(argv
[0] = malloc( strlen(path
) + 6 ))) return;
635 while (*pos
== ':') pos
++;
637 if (!(ptr
= strchr( pos
, ':' ))) ptr
= pos
+ strlen(pos
);
638 memcpy( argv
[0], pos
, ptr
- pos
);
639 strcpy( argv
[0] + (ptr
- pos
), "/wine" );
640 execve( argv
[0], argv
, envp
);
646 /* finally try the current directory */
648 execve( argv
[0], argv
, envp
);
652 /***********************************************************************
655 * Fork and exec a new Unix process, checking for errors.
657 static int fork_and_exec( const char *filename
, const char *cmdline
, const char *env
)
667 fcntl( fd
[1], F_SETFD
, 1 ); /* set close on exec */
668 if (!(pid
= fork())) /* child */
670 char **argv
= build_argv( (char *)cmdline
, NULL
);
671 char **envp
= build_envp( env
);
673 if (argv
&& envp
) execve( filename
, argv
, envp
);
675 write( fd
[1], &err
, sizeof(err
) );
679 if ((pid
!= -1) && (read( fd
[0], &err
, sizeof(err
) ) > 0)) /* exec failed */
684 if (pid
== -1) FILE_SetDosError();
690 /***********************************************************************
691 * PROCESS_CreateUnixProcess
693 BOOL
PROCESS_CreateUnixProcess( LPCSTR filename
, LPCSTR cmd_line
, LPCSTR env
,
694 LPSECURITY_ATTRIBUTES psa
, LPSECURITY_ATTRIBUTES tsa
,
695 BOOL inherit
, DWORD flags
, LPSTARTUPINFOA startup
,
696 LPPROCESS_INFORMATION info
)
699 const char *unixfilename
= filename
;
700 DOS_FULL_NAME full_name
;
701 HANDLE load_done_evt
= -1;
702 struct new_process_request
*req
= get_req_buffer();
703 struct wait_process_request
*wait_req
= get_req_buffer();
705 info
->hThread
= info
->hProcess
= INVALID_HANDLE_VALUE
;
707 if (DOSFS_GetFullName( filename
, TRUE
, &full_name
)) unixfilename
= full_name
.long_name
;
709 /* create the process on the server side */
711 req
->inherit_all
= inherit
;
712 req
->create_flags
= flags
;
713 req
->start_flags
= startup
->dwFlags
;
715 if (startup
->dwFlags
& STARTF_USESTDHANDLES
)
717 req
->hstdin
= startup
->hStdInput
;
718 req
->hstdout
= startup
->hStdOutput
;
719 req
->hstderr
= startup
->hStdError
;
723 req
->hstdin
= GetStdHandle( STD_INPUT_HANDLE
);
724 req
->hstdout
= GetStdHandle( STD_OUTPUT_HANDLE
);
725 req
->hstderr
= GetStdHandle( STD_ERROR_HANDLE
);
727 req
->cmd_show
= startup
->wShowWindow
;
729 lstrcpynA( req
->filename
, unixfilename
, server_remaining(req
->filename
) );
730 if (server_call( REQ_NEW_PROCESS
)) return FALSE
;
732 /* fork and execute */
734 pid
= fork_and_exec( unixfilename
, cmd_line
, env
? env
: GetEnvironmentStringsA() );
736 wait_req
->cancel
= (pid
== -1);
737 wait_req
->pinherit
= (psa
&& (psa
->nLength
>= sizeof(*psa
)) && psa
->bInheritHandle
);
738 wait_req
->tinherit
= (tsa
&& (tsa
->nLength
>= sizeof(*tsa
)) && tsa
->bInheritHandle
);
739 wait_req
->timeout
= 2000;
740 if (server_call( REQ_WAIT_PROCESS
) || (pid
== -1)) goto error
;
741 info
->dwProcessId
= (DWORD
)wait_req
->pid
;
742 info
->dwThreadId
= (DWORD
)wait_req
->tid
;
743 info
->hProcess
= wait_req
->phandle
;
744 info
->hThread
= wait_req
->thandle
;
745 load_done_evt
= wait_req
->event
;
747 /* Wait until process is initialized (or initialization failed) */
748 if (load_done_evt
!= -1)
753 handles
[0] = info
->hProcess
;
754 handles
[1] = load_done_evt
;
755 res
= WaitForMultipleObjects( 2, handles
, FALSE
, INFINITE
);
756 CloseHandle( load_done_evt
);
757 if (res
== STATUS_WAIT_0
) /* the process died */
760 if (GetExitCodeProcess( info
->hProcess
, &exitcode
)) SetLastError( exitcode
);
761 CloseHandle( info
->hThread
);
762 CloseHandle( info
->hProcess
);
769 if (load_done_evt
!= -1) CloseHandle( load_done_evt
);
770 if (info
->hThread
!= INVALID_HANDLE_VALUE
) CloseHandle( info
->hThread
);
771 if (info
->hProcess
!= INVALID_HANDLE_VALUE
) CloseHandle( info
->hProcess
);
776 /***********************************************************************
779 * Startup routine of a new process. Called in the context of the new process.
781 void PROCESS_Start(void)
783 struct init_process_done_request
*req
= get_req_buffer();
785 UINT cmdShow
= SW_SHOWNORMAL
;
786 LPTHREAD_START_ROUTINE entry
= NULL
;
787 PDB
*pdb
= PROCESS_Current();
788 NE_MODULE
*pModule
= NE_GetPtr( pdb
->module
);
789 LPCSTR filename
= ((OFSTRUCT
*)((char*)(pModule
) + (pModule
)->fileinfo
))->szPathName
;
791 /* Get process type */
792 enum { PROC_DOS
, PROC_WIN16
, PROC_WIN32
} type
;
793 if ( pdb
->flags
& PDB32_DOS_PROC
)
795 else if ( pdb
->flags
& PDB32_WIN16_PROC
)
800 /* Initialize the critical section */
801 InitializeCriticalSection( &pdb
->crit_section
);
803 /* Create the environment db */
804 if (!PROCESS_CreateEnvDB()) goto error
;
806 /* Create a task for this process */
807 if (pdb
->env_db
->startup_info
->dwFlags
& STARTF_USESHOWWINDOW
)
808 cmdShow
= pdb
->env_db
->startup_info
->wShowWindow
;
809 if (!TASK_Create( pModule
, cmdShow
))
812 /* Load all process modules */
816 if ( !NE_InitProcess( pModule
) )
821 /* Create 32-bit MODREF */
822 if ( !PE_CreateModule( pModule
->module32
, filename
, 0, FALSE
) )
825 /* Increment EXE refcount */
826 assert( pdb
->exe_modref
);
827 pdb
->exe_modref
->refCount
++;
829 /* Retrieve entry point address */
830 entry
= (LPTHREAD_START_ROUTINE
)RVA_PTR(pModule
->module32
,
831 OptionalHeader
.AddressOfEntryPoint
);
835 /* FIXME: move DOS startup code here */
840 /* Note: The USIG_PROCESS_CREATE signal is supposed to be sent in the
841 * context of the parent process. Actually, the USER signal proc
842 * doesn't really care about that, but it *does* require that the
843 * startup parameters are correctly set up, so that GetProcessDword
844 * works. Furthermore, before calling the USER signal proc the
845 * 16-bit stack must be set up, which it is only after TASK_Create
846 * in the case of a 16-bit process. Thus, we send the signal here.
849 PROCESS_CallUserSignalProc( USIG_PROCESS_CREATE
, 0 );
850 PROCESS_CallUserSignalProc( USIG_THREAD_INIT
, 0 );
851 PROCESS_CallUserSignalProc( USIG_PROCESS_INIT
, 0 );
852 PROCESS_CallUserSignalProc( USIG_PROCESS_LOADED
, 0 );
854 /* Signal the parent process to continue */
855 req
->module
= (void *)pModule
->module32
;
857 server_call( REQ_INIT_PROCESS_DONE
);
858 debugged
= req
->debugged
;
860 if ( (pdb
->flags
& PDB32_CONSOLE_PROC
) || (pdb
->flags
& PDB32_DOS_PROC
) )
863 /* Perform Win32 specific process initialization */
864 if ( type
== PROC_WIN32
)
866 EnterCriticalSection( &pdb
->crit_section
);
869 MODULE_DllProcessAttach( pdb
->exe_modref
, (LPVOID
)1 );
871 LeaveCriticalSection( &pdb
->crit_section
);
874 /* Call UserSignalProc ( USIG_PROCESS_RUNNING ... ) only for non-GUI win32 apps */
875 if ( type
!= PROC_WIN16
&& (pdb
->flags
& PDB32_CONSOLE_PROC
))
876 PROCESS_CallUserSignalProc( USIG_PROCESS_RUNNING
, 0 );
881 TRACE_(relay
)( "Starting DOS process\n" );
883 ERR_(relay
)( "DOSVM_Enter returned; should not happen!\n" );
887 TRACE_(relay
)( "Starting Win16 process\n" );
889 ERR_(relay
)( "TASK_CallToStart returned; should not happen!\n" );
893 TRACE_(relay
)( "Starting Win32 process (entryproc=%p)\n", entry
);
894 if (debugged
) DbgBreakPoint();
895 /* FIXME: should use _PEB as parameter for NT 3.5 programs !
896 * Dunno about other OSs */
897 ExitProcess( entry(NULL
) );
901 ExitProcess( GetLastError() );
905 /***********************************************************************
908 * Create a new process database and associated info.
910 PDB
*PROCESS_Create( NE_MODULE
*pModule
, HFILE hFile
, LPCSTR cmd_line
, LPCSTR env
,
911 LPSECURITY_ATTRIBUTES psa
, LPSECURITY_ATTRIBUTES tsa
,
912 BOOL inherit
, DWORD flags
, STARTUPINFOA
*startup
,
913 PROCESS_INFORMATION
*info
)
915 HANDLE handles
[2], load_done_evt
= -1;
916 DWORD exitcode
, size
;
919 struct new_process_request
*req
= get_req_buffer();
920 struct wait_process_request
*wait_req
= get_req_buffer();
922 PDB
*parent
= PROCESS_Current();
923 PDB
*pdb
= PROCESS_CreatePDB( parent
, inherit
);
925 if (!pdb
) return NULL
;
926 info
->hThread
= info
->hProcess
= INVALID_HANDLE_VALUE
;
928 if (!(pdb
->env_db
->cmd_line
= HEAP_strdupA( GetProcessHeap(), 0, cmd_line
))) goto error
;
929 if (!ENV_InheritEnvironment( pdb
, env
? env
: GetEnvironmentStringsA() )) goto error
;
931 /* Create the process on the server side */
933 req
->inherit_all
= 2 /*inherit*/; /* HACK! */
934 req
->create_flags
= flags
;
935 req
->start_flags
= startup
->dwFlags
;
936 req
->exe_file
= hFile
;
937 if (startup
->dwFlags
& STARTF_USESTDHANDLES
)
939 req
->hstdin
= startup
->hStdInput
;
940 req
->hstdout
= startup
->hStdOutput
;
941 req
->hstderr
= startup
->hStdError
;
945 req
->hstdin
= GetStdHandle( STD_INPUT_HANDLE
);
946 req
->hstdout
= GetStdHandle( STD_OUTPUT_HANDLE
);
947 req
->hstderr
= GetStdHandle( STD_ERROR_HANDLE
);
949 req
->cmd_show
= startup
->wShowWindow
;
951 req
->filename
[0] = 0;
952 if (server_call_fd( REQ_NEW_PROCESS
, -1, &fd
)) goto error
;
954 if (pModule
->module32
) /* Win32 process */
956 IMAGE_OPTIONAL_HEADER
*header
= &PE_HEADER(pModule
->module32
)->OptionalHeader
;
957 size
= header
->SizeOfStackReserve
;
958 if (header
->Subsystem
== IMAGE_SUBSYSTEM_WINDOWS_CUI
)
959 pdb
->flags
|= PDB32_CONSOLE_PROC
;
960 alloc_stack16
= TRUE
;
962 else if (!pModule
->dos_image
) /* Win16 process */
964 alloc_stack16
= FALSE
;
966 pdb
->flags
|= PDB32_WIN16_PROC
;
968 else /* DOS process */
970 alloc_stack16
= FALSE
;
972 pdb
->flags
|= PDB32_DOS_PROC
;
975 /* Create the main thread */
977 if ((teb
= THREAD_Create( pdb
, fd
, size
, alloc_stack16
)))
979 teb
->startup
= PROCESS_Start
;
980 fd
= -1; /* don't close it */
982 /* Pass module to new process (FIXME: hack) */
983 pdb
->module
= pModule
->self
;
984 SYSDEPS_SpawnThread( teb
);
987 wait_req
->cancel
= !teb
;
988 wait_req
->pinherit
= (psa
&& (psa
->nLength
>= sizeof(*psa
)) && psa
->bInheritHandle
);
989 wait_req
->tinherit
= (tsa
&& (tsa
->nLength
>= sizeof(*tsa
)) && tsa
->bInheritHandle
);
990 wait_req
->timeout
= 2000;
991 if (server_call( REQ_WAIT_PROCESS
) || !teb
) goto error
;
992 info
->dwProcessId
= (DWORD
)wait_req
->pid
;
993 info
->dwThreadId
= (DWORD
)wait_req
->tid
;
994 info
->hProcess
= wait_req
->phandle
;
995 info
->hThread
= wait_req
->thandle
;
996 load_done_evt
= wait_req
->event
;
998 /* Wait until process is initialized (or initialization failed) */
999 handles
[0] = info
->hProcess
;
1000 handles
[1] = load_done_evt
;
1002 switch ( WaitForMultipleObjects( 2, handles
, FALSE
, INFINITE
) )
1005 ERR( "WaitForMultipleObjects failed\n" );
1009 /* Child initialization code returns error condition as exitcode */
1010 if ( GetExitCodeProcess( info
->hProcess
, &exitcode
) )
1011 SetLastError( exitcode
);
1015 /* Get 16-bit task up and running */
1016 if ( pdb
->flags
& PDB32_WIN16_PROC
)
1018 /* Post event to start the task */
1019 PostEvent16( pdb
->task
);
1021 /* If we ourselves are a 16-bit task, we Yield() directly. */
1022 if ( parent
->flags
& PDB32_WIN16_PROC
)
1028 CloseHandle( load_done_evt
);
1032 if (load_done_evt
!= -1) CloseHandle( load_done_evt
);
1033 if (info
->hThread
!= INVALID_HANDLE_VALUE
) CloseHandle( info
->hThread
);
1034 if (info
->hProcess
!= INVALID_HANDLE_VALUE
) CloseHandle( info
->hProcess
);
1035 PROCESS_FreePDB( pdb
);
1036 if (fd
!= -1) close( fd
);
1041 /***********************************************************************
1042 * ExitProcess (KERNEL32.100)
1044 void WINAPI
ExitProcess( DWORD status
)
1046 struct terminate_process_request
*req
= get_req_buffer();
1048 MODULE_DllProcessDetach( TRUE
, (LPVOID
)1 );
1051 /* send the exit code to the server */
1052 req
->handle
= GetCurrentProcess();
1053 req
->exit_code
= status
;
1054 server_call( REQ_TERMINATE_PROCESS
);
1055 /* FIXME: need separate address spaces for that */
1056 /* exit( status ); */
1057 SYSDEPS_ExitThread( status
);
1060 /***********************************************************************
1061 * ExitProcess16 (KERNEL.466)
1063 void WINAPI
ExitProcess16( WORD status
)
1065 SYSLEVEL_ReleaseWin16Lock();
1066 ExitProcess( status
);
1069 /******************************************************************************
1070 * TerminateProcess (KERNEL32.684)
1072 BOOL WINAPI
TerminateProcess( HANDLE handle
, DWORD exit_code
)
1075 struct terminate_process_request
*req
= get_req_buffer();
1076 req
->handle
= handle
;
1077 req
->exit_code
= exit_code
;
1078 if ((ret
= !server_call( REQ_TERMINATE_PROCESS
)) && req
->self
) exit( exit_code
);
1083 /***********************************************************************
1084 * GetProcessDword (KERNEL32.18) (KERNEL.485)
1085 * 'Of course you cannot directly access Windows internal structures'
1087 DWORD WINAPI
GetProcessDword( DWORD dwProcessID
, INT offset
)
1089 PDB
*process
= PROCESS_IdToPDB( dwProcessID
);
1093 TRACE_(win32
)("(%ld, %d)\n", dwProcessID
, offset
);
1094 if ( !process
) return 0;
1098 case GPD_APP_COMPAT_FLAGS
:
1099 pTask
= (TDB
*)GlobalLock16( process
->task
);
1100 return pTask
? pTask
->compat_flags
: 0;
1102 case GPD_LOAD_DONE_EVENT
:
1103 return process
->load_done_evt
;
1105 case GPD_HINSTANCE16
:
1106 pTask
= (TDB
*)GlobalLock16( process
->task
);
1107 return pTask
? pTask
->hInstance
: 0;
1109 case GPD_WINDOWS_VERSION
:
1110 pTask
= (TDB
*)GlobalLock16( process
->task
);
1111 return pTask
? pTask
->version
: 0;
1114 if ( process
!= PROCESS_Current() ) return 0;
1115 return (DWORD
)NtCurrentTeb() - 0x10 /* FIXME */;
1118 return (DWORD
)process
;
1120 case GPD_STARTF_SHELLDATA
: /* return stdoutput handle from startupinfo ??? */
1121 return process
->env_db
->startup_info
->hStdOutput
;
1123 case GPD_STARTF_HOTKEY
: /* return stdinput handle from startupinfo ??? */
1124 return process
->env_db
->startup_info
->hStdInput
;
1126 case GPD_STARTF_SHOWWINDOW
:
1127 return process
->env_db
->startup_info
->wShowWindow
;
1129 case GPD_STARTF_SIZE
:
1130 x
= process
->env_db
->startup_info
->dwXSize
;
1131 if ( x
== CW_USEDEFAULT
) x
= CW_USEDEFAULT16
;
1132 y
= process
->env_db
->startup_info
->dwYSize
;
1133 if ( y
== CW_USEDEFAULT
) y
= CW_USEDEFAULT16
;
1134 return MAKELONG( x
, y
);
1136 case GPD_STARTF_POSITION
:
1137 x
= process
->env_db
->startup_info
->dwX
;
1138 if ( x
== CW_USEDEFAULT
) x
= CW_USEDEFAULT16
;
1139 y
= process
->env_db
->startup_info
->dwY
;
1140 if ( y
== CW_USEDEFAULT
) y
= CW_USEDEFAULT16
;
1141 return MAKELONG( x
, y
);
1143 case GPD_STARTF_FLAGS
:
1144 return process
->env_db
->startup_info
->dwFlags
;
1147 return process
->parent
? (DWORD
)process
->parent
->server_pid
: 0;
1150 return process
->flags
;
1153 return process
->process_dword
;
1156 ERR_(win32
)("Unknown offset %d\n", offset
);
1161 /***********************************************************************
1162 * SetProcessDword (KERNEL.484)
1163 * 'Of course you cannot directly access Windows internal structures'
1165 void WINAPI
SetProcessDword( DWORD dwProcessID
, INT offset
, DWORD value
)
1167 PDB
*process
= PROCESS_IdToPDB( dwProcessID
);
1169 TRACE_(win32
)("(%ld, %d)\n", dwProcessID
, offset
);
1170 if ( !process
) return;
1174 case GPD_APP_COMPAT_FLAGS
:
1175 case GPD_LOAD_DONE_EVENT
:
1176 case GPD_HINSTANCE16
:
1177 case GPD_WINDOWS_VERSION
:
1180 case GPD_STARTF_SHELLDATA
:
1181 case GPD_STARTF_HOTKEY
:
1182 case GPD_STARTF_SHOWWINDOW
:
1183 case GPD_STARTF_SIZE
:
1184 case GPD_STARTF_POSITION
:
1185 case GPD_STARTF_FLAGS
:
1188 ERR_(win32
)("Not allowed to modify offset %d\n", offset
);
1192 process
->process_dword
= value
;
1196 ERR_(win32
)("Unknown offset %d\n", offset
);
1202 /*********************************************************************
1203 * OpenProcess (KERNEL32.543)
1205 HANDLE WINAPI
OpenProcess( DWORD access
, BOOL inherit
, DWORD id
)
1208 struct open_process_request
*req
= get_req_buffer();
1210 req
->pid
= (void *)id
;
1211 req
->access
= access
;
1212 req
->inherit
= inherit
;
1213 if (!server_call( REQ_OPEN_PROCESS
)) ret
= req
->handle
;
1217 /*********************************************************************
1218 * MapProcessHandle (KERNEL.483)
1220 DWORD WINAPI
MapProcessHandle( HANDLE handle
)
1223 struct get_process_info_request
*req
= get_req_buffer();
1224 req
->handle
= handle
;
1225 if (!server_call( REQ_GET_PROCESS_INFO
)) ret
= (DWORD
)req
->pid
;
1229 /***********************************************************************
1230 * GetThreadLocale (KERNEL32.295)
1232 LCID WINAPI
GetThreadLocale(void)
1234 return PROCESS_Current()->locale
;
1238 /***********************************************************************
1239 * SetPriorityClass (KERNEL32.503)
1241 BOOL WINAPI
SetPriorityClass( HANDLE hprocess
, DWORD priorityclass
)
1243 struct set_process_info_request
*req
= get_req_buffer();
1244 req
->handle
= hprocess
;
1245 req
->priority
= priorityclass
;
1246 req
->mask
= SET_PROCESS_INFO_PRIORITY
;
1247 return !server_call( REQ_SET_PROCESS_INFO
);
1251 /***********************************************************************
1252 * GetPriorityClass (KERNEL32.250)
1254 DWORD WINAPI
GetPriorityClass(HANDLE hprocess
)
1257 struct get_process_info_request
*req
= get_req_buffer();
1258 req
->handle
= hprocess
;
1259 if (!server_call( REQ_GET_PROCESS_INFO
)) ret
= req
->priority
;
1264 /***********************************************************************
1265 * SetProcessAffinityMask (KERNEL32.662)
1267 BOOL WINAPI
SetProcessAffinityMask( HANDLE hProcess
, DWORD affmask
)
1269 struct set_process_info_request
*req
= get_req_buffer();
1270 req
->handle
= hProcess
;
1271 req
->affinity
= affmask
;
1272 req
->mask
= SET_PROCESS_INFO_AFFINITY
;
1273 return !server_call( REQ_SET_PROCESS_INFO
);
1276 /**********************************************************************
1277 * GetProcessAffinityMask (KERNEL32.373)
1279 BOOL WINAPI
GetProcessAffinityMask( HANDLE hProcess
,
1280 LPDWORD lpProcessAffinityMask
,
1281 LPDWORD lpSystemAffinityMask
)
1284 struct get_process_info_request
*req
= get_req_buffer();
1285 req
->handle
= hProcess
;
1286 if (!server_call( REQ_GET_PROCESS_INFO
))
1288 if (lpProcessAffinityMask
) *lpProcessAffinityMask
= req
->process_affinity
;
1289 if (lpSystemAffinityMask
) *lpSystemAffinityMask
= req
->system_affinity
;
1296 /***********************************************************************
1297 * GetStdHandle (KERNEL32.276)
1299 HANDLE WINAPI
GetStdHandle( DWORD std_handle
)
1301 PDB
*pdb
= PROCESS_Current();
1305 case STD_INPUT_HANDLE
: return pdb
->env_db
->hStdin
;
1306 case STD_OUTPUT_HANDLE
: return pdb
->env_db
->hStdout
;
1307 case STD_ERROR_HANDLE
: return pdb
->env_db
->hStderr
;
1309 SetLastError( ERROR_INVALID_PARAMETER
);
1310 return INVALID_HANDLE_VALUE
;
1314 /***********************************************************************
1315 * SetStdHandle (KERNEL32.506)
1317 BOOL WINAPI
SetStdHandle( DWORD std_handle
, HANDLE handle
)
1319 PDB
*pdb
= PROCESS_Current();
1320 /* FIXME: should we close the previous handle? */
1323 case STD_INPUT_HANDLE
:
1324 pdb
->env_db
->hStdin
= handle
;
1326 case STD_OUTPUT_HANDLE
:
1327 pdb
->env_db
->hStdout
= handle
;
1329 case STD_ERROR_HANDLE
:
1330 pdb
->env_db
->hStderr
= handle
;
1333 SetLastError( ERROR_INVALID_PARAMETER
);
1337 /***********************************************************************
1338 * GetProcessVersion (KERNEL32)
1340 DWORD WINAPI
GetProcessVersion( DWORD processid
)
1343 PDB
*pdb
= PROCESS_IdToPDB( processid
);
1346 if (!(pTask
= (TDB
*)GlobalLock16( pdb
->task
))) return 0;
1347 return (pTask
->version
&0xff) | (((pTask
->version
>>8) & 0xff)<<16);
1350 /***********************************************************************
1351 * GetProcessFlags (KERNEL32)
1353 DWORD WINAPI
GetProcessFlags( DWORD processid
)
1355 PDB
*pdb
= PROCESS_IdToPDB( processid
);
1360 /***********************************************************************
1361 * SetProcessWorkingSetSize [KERNEL32.662]
1362 * Sets the min/max working set sizes for a specified process.
1365 * hProcess [I] Handle to the process of interest
1366 * minset [I] Specifies minimum working set size
1367 * maxset [I] Specifies maximum working set size
1371 BOOL WINAPI
SetProcessWorkingSetSize(HANDLE hProcess
,DWORD minset
,
1374 FIXME("(0x%08x,%ld,%ld): stub - harmless\n",hProcess
,minset
,maxset
);
1375 if(( minset
== -1) && (maxset
== -1)) {
1376 /* Trim the working set to zero */
1377 /* Swap the process out of physical RAM */
1382 /***********************************************************************
1383 * GetProcessWorkingSetSize (KERNEL32)
1385 BOOL WINAPI
GetProcessWorkingSetSize(HANDLE hProcess
,LPDWORD minset
,
1388 FIXME("(0x%08x,%p,%p): stub\n",hProcess
,minset
,maxset
);
1389 /* 32 MB working set size */
1390 if (minset
) *minset
= 32*1024*1024;
1391 if (maxset
) *maxset
= 32*1024*1024;
1395 /***********************************************************************
1396 * SetProcessShutdownParameters (KERNEL32)
1398 * CHANGED - James Sutherland (JamesSutherland@gmx.de)
1399 * Now tracks changes made (but does not act on these changes)
1400 * NOTE: the definition for SHUTDOWN_NORETRY was done on guesswork.
1401 * It really shouldn't be here, but I'll move it when it's been checked!
1403 #define SHUTDOWN_NORETRY 1
1404 static unsigned int shutdown_noretry
= 0;
1405 static unsigned int shutdown_priority
= 0x280L
;
1406 BOOL WINAPI
SetProcessShutdownParameters(DWORD level
,DWORD flags
)
1408 if (flags
& SHUTDOWN_NORETRY
)
1409 shutdown_noretry
= 1;
1411 shutdown_noretry
= 0;
1412 if (level
> 0x100L
&& level
< 0x3FFL
)
1413 shutdown_priority
= level
;
1416 ERR("invalid priority level 0x%08lx\n", level
);
1423 /***********************************************************************
1424 * GetProcessShutdownParameters (KERNEL32)
1427 BOOL WINAPI
GetProcessShutdownParameters( LPDWORD lpdwLevel
,
1430 (*lpdwLevel
) = shutdown_priority
;
1431 (*lpdwFlags
) = (shutdown_noretry
* SHUTDOWN_NORETRY
);
1434 /***********************************************************************
1435 * SetProcessPriorityBoost (KERNEL32)
1437 BOOL WINAPI
SetProcessPriorityBoost(HANDLE hprocess
,BOOL disableboost
)
1439 FIXME("(%d,%d): stub\n",hprocess
,disableboost
);
1440 /* Say we can do it. I doubt the program will notice that we don't. */
1445 /***********************************************************************
1446 * ReadProcessMemory (KERNEL32)
1448 BOOL WINAPI
ReadProcessMemory( HANDLE process
, LPCVOID addr
, LPVOID buffer
, DWORD size
,
1449 LPDWORD bytes_read
)
1451 struct read_process_memory_request
*req
= get_req_buffer();
1452 unsigned int offset
= (unsigned int)addr
% sizeof(int);
1453 unsigned int max
= server_remaining( req
->data
); /* max length in one request */
1456 if (bytes_read
) *bytes_read
= size
;
1458 /* first time, read total length to check for permissions */
1459 req
->handle
= process
;
1460 req
->addr
= (char *)addr
- offset
;
1461 req
->len
= (size
+ offset
+ sizeof(int) - 1) / sizeof(int);
1462 if (server_call( REQ_READ_PROCESS_MEMORY
)) goto error
;
1464 if (size
<= max
- offset
)
1466 memcpy( buffer
, (char *)req
->data
+ offset
, size
);
1470 /* now take care of the remaining data */
1471 memcpy( buffer
, (char *)req
->data
+ offset
, max
- offset
);
1476 if (max
> size
) max
= size
;
1477 req
->handle
= process
;
1478 req
->addr
= (char *)addr
+ pos
;
1479 req
->len
= (max
+ sizeof(int) - 1) / sizeof(int);
1480 if (server_call( REQ_READ_PROCESS_MEMORY
)) goto error
;
1481 memcpy( (char *)buffer
+ pos
, (char *)req
->data
, max
);
1488 if (bytes_read
) *bytes_read
= 0;
1493 /***********************************************************************
1494 * WriteProcessMemory (KERNEL32)
1496 BOOL WINAPI
WriteProcessMemory( HANDLE process
, LPVOID addr
, LPVOID buffer
, DWORD size
,
1497 LPDWORD bytes_written
)
1499 unsigned int first_offset
, last_offset
;
1500 struct write_process_memory_request
*req
= get_req_buffer();
1501 unsigned int max
= server_remaining( req
->data
); /* max length in one request */
1502 unsigned int pos
, last_mask
;
1506 SetLastError( ERROR_INVALID_PARAMETER
);
1509 if (bytes_written
) *bytes_written
= size
;
1511 /* compute the mask for the first int */
1512 req
->first_mask
= ~0;
1513 first_offset
= (unsigned int)addr
% sizeof(int);
1514 memset( &req
->first_mask
, 0, first_offset
);
1516 /* compute the mask for the last int */
1517 last_offset
= (size
+ first_offset
) % sizeof(int);
1519 memset( &last_mask
, 0xff, last_offset
? last_offset
: sizeof(int) );
1521 req
->handle
= process
;
1522 req
->addr
= (char *)addr
- first_offset
;
1523 /* for the first request, use the total length */
1524 req
->len
= (size
+ first_offset
+ sizeof(int) - 1) / sizeof(int);
1526 if (size
+ first_offset
< max
) /* we can do it in one round */
1528 memcpy( (char *)req
->data
+ first_offset
, buffer
, size
);
1529 req
->last_mask
= last_mask
;
1530 if (server_call( REQ_WRITE_PROCESS_MEMORY
)) goto error
;
1534 /* needs multiple server calls */
1536 memcpy( (char *)req
->data
+ first_offset
, buffer
, max
- first_offset
);
1537 req
->last_mask
= ~0;
1538 if (server_call( REQ_WRITE_PROCESS_MEMORY
)) goto error
;
1539 pos
= max
- first_offset
;
1543 if (size
<= max
) /* last one */
1545 req
->last_mask
= last_mask
;
1548 req
->handle
= process
;
1549 req
->addr
= (char *)addr
+ pos
;
1550 req
->len
= (max
+ sizeof(int) - 1) / sizeof(int);
1551 req
->first_mask
= ~0;
1552 memcpy( req
->data
, (char *) buffer
+ pos
, max
);
1553 if (server_call( REQ_WRITE_PROCESS_MEMORY
)) goto error
;
1560 if (bytes_written
) *bytes_written
= 0;
1566 /***********************************************************************
1567 * RegisterServiceProcess (KERNEL, KERNEL32)
1569 * A service process calls this function to ensure that it continues to run
1570 * even after a user logged off.
1572 DWORD WINAPI
RegisterServiceProcess(DWORD dwProcessId
, DWORD dwType
)
1574 /* I don't think that Wine needs to do anything in that function */
1575 return 1; /* success */
1578 /***********************************************************************
1579 * GetExitCodeProcess [KERNEL32.325]
1581 * Gets termination status of specified process
1587 BOOL WINAPI
GetExitCodeProcess(
1588 HANDLE hProcess
, /* [I] handle to the process */
1589 LPDWORD lpExitCode
) /* [O] address to receive termination status */
1592 struct get_process_info_request
*req
= get_req_buffer();
1593 req
->handle
= hProcess
;
1594 if (!server_call( REQ_GET_PROCESS_INFO
))
1596 if (lpExitCode
) *lpExitCode
= req
->exit_code
;
1603 /***********************************************************************
1604 * SetErrorMode (KERNEL32.486)
1606 UINT WINAPI
SetErrorMode( UINT mode
)
1608 UINT old
= PROCESS_Current()->error_mode
;
1609 PROCESS_Current()->error_mode
= mode
;
1613 /***********************************************************************
1614 * GetCurrentProcess (KERNEL32.198)
1616 #undef GetCurrentProcess
1617 HANDLE WINAPI
GetCurrentProcess(void)