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 /* The initial process PDB */
41 static PDB initial_pdb
;
42 static ENVDB initial_envdb
;
43 static STARTUPINFOA initial_startup
;
45 static PDB
*PROCESS_First
= &initial_pdb
;
48 /***********************************************************************
51 * Convert a process id to a PDB, making sure it is valid.
53 PDB
*PROCESS_IdToPDB( DWORD pid
)
57 if (!pid
) return PROCESS_Current();
61 if ((DWORD
)pdb
->server_pid
== pid
) return pdb
;
64 SetLastError( ERROR_INVALID_PARAMETER
);
69 /***********************************************************************
70 * PROCESS_CallUserSignalProc
72 * FIXME: Some of the signals aren't sent correctly!
74 * The exact meaning of the USER signals is undocumented, but this
75 * should cover the basic idea:
77 * USIG_DLL_UNLOAD_WIN16
78 * This is sent when a 16-bit module is unloaded.
80 * USIG_DLL_UNLOAD_WIN32
81 * This is sent when a 32-bit module is unloaded.
83 * USIG_DLL_UNLOAD_ORPHANS
84 * This is sent after the last Win3.1 module is unloaded,
85 * to allow removal of orphaned menus.
87 * USIG_FAULT_DIALOG_PUSH
88 * USIG_FAULT_DIALOG_POP
89 * These are called to allow USER to prepare for displaying a
90 * fault dialog, even though the fault might have happened while
91 * inside a USER critical section.
94 * This is called from the context of a new thread, as soon as it
98 * This is called, still in its context, just before a thread is
101 * USIG_PROCESS_CREATE
102 * This is called, in the parent process context, after a new process
106 * This is called in the new process context, just after the main thread
107 * has started execution (after the main thread's USIG_THREAD_INIT has
110 * USIG_PROCESS_LOADED
111 * This is called after the executable file has been loaded into the
112 * new process context.
114 * USIG_PROCESS_RUNNING
115 * This is called immediately before the main entry point is called.
118 * This is called in the context of a process that is about to
119 * terminate (but before the last thread's USIG_THREAD_EXIT has
122 * USIG_PROCESS_DESTROY
123 * This is called after a process has terminated.
126 * The meaning of the dwFlags bits is as follows:
129 * Current process is 32-bit.
132 * Current process is a (Win32) GUI process.
134 * USIG_FLAGS_FEEDBACK
135 * Current process needs 'feedback' (determined from the STARTUPINFO
136 * flags STARTF_FORCEONFEEDBACK / STARTF_FORCEOFFFEEDBACK).
139 * The signal is being sent due to a fault.
141 void PROCESS_CallUserSignalProc( UINT uCode
, HMODULE hModule
)
143 DWORD flags
= PROCESS_Current()->flags
;
144 DWORD startup_flags
= PROCESS_Current()->env_db
->startup_info
->dwFlags
;
147 /* Determine dwFlags */
149 if ( !(flags
& PDB32_WIN16_PROC
) ) dwFlags
|= USIG_FLAGS_WIN32
;
151 if ( !(flags
& PDB32_CONSOLE_PROC
) ) dwFlags
|= USIG_FLAGS_GUI
;
153 if ( dwFlags
& USIG_FLAGS_GUI
)
155 /* Feedback defaults to ON */
156 if ( !(startup_flags
& STARTF_FORCEOFFFEEDBACK
) )
157 dwFlags
|= USIG_FLAGS_FEEDBACK
;
161 /* Feedback defaults to OFF */
162 if (startup_flags
& STARTF_FORCEONFEEDBACK
)
163 dwFlags
|= USIG_FLAGS_FEEDBACK
;
166 /* Convert module handle to 16-bit */
168 if ( HIWORD( hModule
) )
169 hModule
= MapHModuleLS( hModule
);
171 /* Call USER signal proc */
173 if ( Callout
.UserSignalProc
)
175 if ( uCode
== USIG_THREAD_INIT
|| uCode
== USIG_THREAD_EXIT
)
176 Callout
.UserSignalProc( uCode
, GetCurrentThreadId(), dwFlags
, hModule
);
178 Callout
.UserSignalProc( uCode
, GetCurrentProcessId(), dwFlags
, hModule
);
182 /***********************************************************************
183 * PROCESS_CreateEnvDB
185 * Create the env DB for a newly started process.
187 static BOOL
PROCESS_CreateEnvDB(void)
189 struct init_process_request
*req
= get_req_buffer();
190 PDB
*pdb
= PROCESS_Current();
191 ENVDB
*env_db
= pdb
->env_db
;
192 STARTUPINFOA
*startup
= env_db
->startup_info
;
194 /* Retrieve startup info from the server */
196 req
->ldt_copy
= ldt_copy
;
197 req
->ldt_flags
= ldt_flags_copy
;
198 req
->ppid
= getppid();
199 if (server_call( REQ_INIT_PROCESS
)) return FALSE
;
200 pdb
->exe_file
= req
->exe_file
;
201 startup
->dwFlags
= req
->start_flags
;
202 startup
->wShowWindow
= req
->cmd_show
;
203 env_db
->hStdin
= startup
->hStdInput
= req
->hstdin
;
204 env_db
->hStdout
= startup
->hStdOutput
= req
->hstdout
;
205 env_db
->hStderr
= startup
->hStdError
= req
->hstderr
;
211 /***********************************************************************
214 * Free a PDB and all associated storage.
216 void PROCESS_FreePDB( PDB
*pdb
)
218 PDB
**pptr
= &PROCESS_First
;
220 ENV_FreeEnvironment( pdb
);
221 while (*pptr
&& (*pptr
!= pdb
)) pptr
= &(*pptr
)->next
;
222 if (*pptr
) *pptr
= pdb
->next
;
223 HeapFree( GetProcessHeap(), 0, pdb
);
227 /***********************************************************************
230 * Allocate and fill a PDB structure.
231 * Runs in the context of the parent process.
233 static PDB
*PROCESS_CreatePDB( PDB
*parent
, BOOL inherit
)
235 PDB
*pdb
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
236 sizeof(PDB
) + sizeof(ENVDB
) + sizeof(STARTUPINFOA
) );
238 if (!pdb
) return NULL
;
239 pdb
->exit_code
= STILL_ACTIVE
;
240 pdb
->heap
= GetProcessHeap();
242 pdb
->running_threads
= 1;
243 pdb
->ring0_threads
= 1;
244 pdb
->parent
= parent
;
246 pdb
->priority
= 8; /* Normal */
247 pdb
->next
= PROCESS_First
;
248 pdb
->winver
= 0xffff; /* to be determined */
249 pdb
->main_queue
= INVALID_HANDLE_VALUE16
;
250 pdb
->env_db
= (ENVDB
*)(pdb
+ 1);
251 pdb
->env_db
->startup_info
= (STARTUPINFOA
*)(pdb
->env_db
+ 1);
253 InitializeCriticalSection( &pdb
->env_db
->section
);
260 /***********************************************************************
263 BOOL
PROCESS_Init( BOOL win32
)
265 struct init_process_request
*req
;
268 /* Fill the initial process structure */
269 initial_pdb
.exit_code
= STILL_ACTIVE
;
270 initial_pdb
.threads
= 1;
271 initial_pdb
.running_threads
= 1;
272 initial_pdb
.ring0_threads
= 1;
273 initial_pdb
.env_db
= &initial_envdb
;
274 initial_pdb
.group
= &initial_pdb
;
275 initial_pdb
.priority
= 8; /* Normal */
276 initial_pdb
.flags
= win32
? 0 : PDB32_WIN16_PROC
;
277 initial_pdb
.winver
= 0xffff; /* to be determined */
278 initial_pdb
.main_queue
= INVALID_HANDLE_VALUE16
;
279 initial_envdb
.startup_info
= &initial_startup
;
280 teb
= THREAD_Init( &initial_pdb
);
282 /* Setup the server connection */
283 teb
->socket
= CLIENT_InitServer();
284 if (CLIENT_InitThread()) return FALSE
;
286 /* Initialize virtual memory management */
287 if (!VIRTUAL_Init()) 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 initial_pdb
.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
= teb
->teb_sel
;
309 /* Create the system and process heaps */
310 if (!HEAP_CreateSystemHeap()) return FALSE
;
311 initial_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 initial_pdb
.idle_event
= CreateEventA ( NULL
, TRUE
, FALSE
, NULL
);
319 initial_pdb
.idle_event
= ConvertToGlobalHandle ( initial_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( &initial_pdb
.crit_section
);
329 InitializeCriticalSection( &initial_envdb
.section
);
335 /***********************************************************************
338 * Load system DLLs into the initial process (and initialize them)
340 static 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
)
451 PDB
*pdb
= PROCESS_Current();
453 pdb
->env_db
->cmd_line
= HEAP_strdupA( GetProcessHeap(), 0, cmd_line
);
455 /* load main module */
456 if ((main_module
= PE_LoadImage( hFile
, filename
, &version
)) < 32)
457 ExitProcess( main_module
);
459 if (PE_HEADER(main_module
)->FileHeader
.Characteristics
& IMAGE_FILE_DLL
)
461 SetLastError( 20 ); /* FIXME: not the right error code */
466 /* Create 32-bit MODREF */
467 if (!PE_CreateModule( main_module
, filename
, 0, FALSE
)) goto error
;
469 /* allocate main thread stack */
470 if (!THREAD_InitStack( NtCurrentTeb(), pdb
,
471 PE_HEADER(main_module
)->OptionalHeader
.SizeOfStackReserve
, TRUE
))
474 SIGNAL_Init(); /* reinitialize signal stack */
476 /* switch to the new stack */
477 CALL32_Init( &IF1632_CallLargeStack
, start_process
, NtCurrentTeb()->stack_top
);
479 ExitProcess( GetLastError() );
483 /***********************************************************************
484 * PROCESS_InitWinelib
486 * Initialisation of a new Winelib process.
488 void PROCESS_InitWinelib( int argc
, char *argv
[] )
496 if (!MAIN_MainInit( argc
, argv
, TRUE
)) exit(1);
497 pdb
= PROCESS_Current();
499 /* build command-line */
500 for (i
= 0; Options
.argv
[i
]; i
++) len
+= strlen(Options
.argv
[i
]) + 1;
501 if (!(cmdline
= HeapAlloc( GetProcessHeap(), 0, len
))) goto error
;
502 for (p
= cmdline
, i
= 0; Options
.argv
[i
]; i
++)
504 strcpy( p
, Options
.argv
[i
] );
508 if (p
> cmdline
) p
--;
510 pdb
->env_db
->cmd_line
= cmdline
;
512 /* create 32-bit module for main exe */
513 if ((main_module
= BUILTIN32_LoadExeModule( &filename
)) < 32 ) goto error
;
515 /* Create 32-bit MODREF */
516 if (!PE_CreateModule( main_module
, filename
, 0, FALSE
)) goto error
;
518 /* allocate main thread stack */
519 if (!THREAD_InitStack( NtCurrentTeb(), pdb
,
520 PE_HEADER(main_module
)->OptionalHeader
.SizeOfStackReserve
, TRUE
))
523 SIGNAL_Init(); /* reinitialize signal stack */
525 /* switch to the new stack */
526 CALL32_Init( &IF1632_CallLargeStack
, start_process
, NtCurrentTeb()->stack_top
);
528 ExitProcess( GetLastError() );
532 /***********************************************************************
535 * Build an argv array from a command-line.
536 * The command-line is modified to insert nulls.
538 static char **build_argv( char *cmdline
, char *argv0
)
546 while (*p
&& isspace(*p
)) p
++;
549 while (*p
&& !isspace(*p
)) p
++;
552 if ((argv
= malloc( count
* sizeof(*argv
) )))
554 char **argvptr
= argv
;
555 if (argv0
) *argvptr
++ = argv0
;
559 while (*p
&& isspace(*p
)) *p
++ = 0;
562 while (*p
&& !isspace(*p
)) p
++;
570 /***********************************************************************
573 * Build the environment of a new child process.
575 static char **build_envp( const char *env
)
581 for (p
= env
, count
= 0; *p
; count
++) p
+= strlen(p
) + 1;
583 if ((envp
= malloc( count
* sizeof(*envp
) )))
585 extern char **environ
;
586 char **envptr
= envp
;
587 char **unixptr
= environ
;
588 /* first put PATH, HOME and WINEPREFIX from the unix env */
589 for (unixptr
= environ
; unixptr
&& *unixptr
; unixptr
++)
590 if (!memcmp( *unixptr
, "PATH=", 5 ) ||
591 !memcmp( *unixptr
, "HOME=", 5 ) ||
592 !memcmp( *unixptr
, "WINEPREFIX=", 11 )) *envptr
++ = *unixptr
;
593 /* now put the Windows environment strings */
594 for (p
= env
; *p
; p
+= strlen(p
) + 1)
596 if (memcmp( p
, "PATH=", 5 ) &&
597 memcmp( p
, "HOME=", 5 ) &&
598 memcmp( p
, "WINEPREFIX=", 11 )) *envptr
++ = (char *)p
;
606 /***********************************************************************
609 * Locate the Wine binary to exec for a new Win32 process.
611 static void exec_wine_binary( char **argv
, char **envp
)
613 const char *path
, *pos
, *ptr
;
615 /* first try bin directory */
616 argv
[0] = BINDIR
"/wine";
617 execve( argv
[0], argv
, envp
);
619 /* now try the path of argv0 of the current binary */
620 if (!(argv
[0] = malloc( strlen(argv0
) + 6 ))) return;
621 if ((ptr
= strrchr( argv0
, '/' )))
623 memcpy( argv
[0], argv0
, ptr
- argv0
);
624 strcpy( argv
[0] + (ptr
- argv0
), "/wine" );
625 execve( argv
[0], argv
, envp
);
629 /* now search in the Unix path */
630 if ((path
= getenv( "PATH" )))
632 if (!(argv
[0] = malloc( strlen(path
) + 6 ))) return;
636 while (*pos
== ':') pos
++;
638 if (!(ptr
= strchr( pos
, ':' ))) ptr
= pos
+ strlen(pos
);
639 memcpy( argv
[0], pos
, ptr
- pos
);
640 strcpy( argv
[0] + (ptr
- pos
), "/wine" );
641 execve( argv
[0], argv
, envp
);
647 /* finally try the current directory */
649 execve( argv
[0], argv
, envp
);
653 /***********************************************************************
656 * Fork and exec a new Unix process, checking for errors.
658 static int fork_and_exec( const char *filename
, const char *cmdline
, const char *env
)
668 fcntl( fd
[1], F_SETFD
, 1 ); /* set close on exec */
669 if (!(pid
= fork())) /* child */
671 char **argv
= build_argv( (char *)cmdline
, NULL
);
672 char **envp
= build_envp( env
);
674 if (argv
&& envp
) execve( filename
, argv
, envp
);
676 write( fd
[1], &err
, sizeof(err
) );
680 if ((pid
!= -1) && (read( fd
[0], &err
, sizeof(err
) ) > 0)) /* exec failed */
685 if (pid
== -1) FILE_SetDosError();
691 /***********************************************************************
692 * PROCESS_CreateUnixProcess
694 BOOL
PROCESS_CreateUnixProcess( LPCSTR filename
, LPCSTR cmd_line
, LPCSTR env
,
695 LPSECURITY_ATTRIBUTES psa
, LPSECURITY_ATTRIBUTES tsa
,
696 BOOL inherit
, DWORD flags
, LPSTARTUPINFOA startup
,
697 LPPROCESS_INFORMATION info
)
700 const char *unixfilename
= filename
;
701 DOS_FULL_NAME full_name
;
702 HANDLE load_done_evt
= -1;
703 struct new_process_request
*req
= get_req_buffer();
704 struct wait_process_request
*wait_req
= get_req_buffer();
706 info
->hThread
= info
->hProcess
= INVALID_HANDLE_VALUE
;
708 if (DOSFS_GetFullName( filename
, TRUE
, &full_name
)) unixfilename
= full_name
.long_name
;
710 /* create the process on the server side */
712 req
->inherit_all
= inherit
;
713 req
->create_flags
= flags
;
714 req
->start_flags
= startup
->dwFlags
;
716 if (startup
->dwFlags
& STARTF_USESTDHANDLES
)
718 req
->hstdin
= startup
->hStdInput
;
719 req
->hstdout
= startup
->hStdOutput
;
720 req
->hstderr
= startup
->hStdError
;
724 req
->hstdin
= GetStdHandle( STD_INPUT_HANDLE
);
725 req
->hstdout
= GetStdHandle( STD_OUTPUT_HANDLE
);
726 req
->hstderr
= GetStdHandle( STD_ERROR_HANDLE
);
728 req
->cmd_show
= startup
->wShowWindow
;
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 if (server_call_fd( REQ_NEW_PROCESS
, -1, &fd
)) goto error
;
953 if (pModule
->module32
) /* Win32 process */
955 IMAGE_OPTIONAL_HEADER
*header
= &PE_HEADER(pModule
->module32
)->OptionalHeader
;
956 size
= header
->SizeOfStackReserve
;
957 if (header
->Subsystem
== IMAGE_SUBSYSTEM_WINDOWS_CUI
)
958 pdb
->flags
|= PDB32_CONSOLE_PROC
;
959 alloc_stack16
= TRUE
;
961 else if (!pModule
->dos_image
) /* Win16 process */
963 alloc_stack16
= FALSE
;
965 pdb
->flags
|= PDB32_WIN16_PROC
;
967 else /* DOS process */
969 alloc_stack16
= FALSE
;
971 pdb
->flags
|= PDB32_DOS_PROC
;
974 /* Create the main thread */
976 if ((teb
= THREAD_Create( pdb
, fd
, size
, alloc_stack16
)))
978 teb
->startup
= PROCESS_Start
;
979 fd
= -1; /* don't close it */
981 /* Pass module to new process (FIXME: hack) */
982 pdb
->module
= pModule
->self
;
983 SYSDEPS_SpawnThread( teb
);
986 wait_req
->cancel
= !teb
;
987 wait_req
->pinherit
= (psa
&& (psa
->nLength
>= sizeof(*psa
)) && psa
->bInheritHandle
);
988 wait_req
->tinherit
= (tsa
&& (tsa
->nLength
>= sizeof(*tsa
)) && tsa
->bInheritHandle
);
989 wait_req
->timeout
= 2000;
990 if (server_call( REQ_WAIT_PROCESS
) || !teb
) goto error
;
991 info
->dwProcessId
= (DWORD
)wait_req
->pid
;
992 info
->dwThreadId
= (DWORD
)wait_req
->tid
;
993 info
->hProcess
= wait_req
->phandle
;
994 info
->hThread
= wait_req
->thandle
;
995 load_done_evt
= wait_req
->event
;
997 /* Wait until process is initialized (or initialization failed) */
998 handles
[0] = info
->hProcess
;
999 handles
[1] = load_done_evt
;
1001 switch ( WaitForMultipleObjects( 2, handles
, FALSE
, INFINITE
) )
1004 ERR( "WaitForMultipleObjects failed\n" );
1008 /* Child initialization code returns error condition as exitcode */
1009 if ( GetExitCodeProcess( info
->hProcess
, &exitcode
) )
1010 SetLastError( exitcode
);
1014 /* Get 16-bit task up and running */
1015 if ( pdb
->flags
& PDB32_WIN16_PROC
)
1017 /* Post event to start the task */
1018 PostEvent16( pdb
->task
);
1020 /* If we ourselves are a 16-bit task, we Yield() directly. */
1021 if ( parent
->flags
& PDB32_WIN16_PROC
)
1027 CloseHandle( load_done_evt
);
1031 if (load_done_evt
!= -1) CloseHandle( load_done_evt
);
1032 if (info
->hThread
!= INVALID_HANDLE_VALUE
) CloseHandle( info
->hThread
);
1033 if (info
->hProcess
!= INVALID_HANDLE_VALUE
) CloseHandle( info
->hProcess
);
1034 PROCESS_FreePDB( pdb
);
1035 if (fd
!= -1) close( fd
);
1040 /***********************************************************************
1041 * ExitProcess (KERNEL32.100)
1043 void WINAPI
ExitProcess( DWORD status
)
1045 struct terminate_process_request
*req
= get_req_buffer();
1047 MODULE_DllProcessDetach( TRUE
, (LPVOID
)1 );
1050 /* send the exit code to the server */
1051 req
->handle
= GetCurrentProcess();
1052 req
->exit_code
= status
;
1053 server_call( REQ_TERMINATE_PROCESS
);
1054 /* FIXME: need separate address spaces for that */
1055 /* exit( status ); */
1056 SYSDEPS_ExitThread( status
);
1059 /***********************************************************************
1060 * ExitProcess16 (KERNEL.466)
1062 void WINAPI
ExitProcess16( WORD status
)
1064 SYSLEVEL_ReleaseWin16Lock();
1065 ExitProcess( status
);
1068 /******************************************************************************
1069 * TerminateProcess (KERNEL32.684)
1071 BOOL WINAPI
TerminateProcess( HANDLE handle
, DWORD exit_code
)
1074 struct terminate_process_request
*req
= get_req_buffer();
1075 req
->handle
= handle
;
1076 req
->exit_code
= exit_code
;
1077 if ((ret
= !server_call( REQ_TERMINATE_PROCESS
)) && req
->self
) exit( exit_code
);
1082 /***********************************************************************
1083 * GetProcessDword (KERNEL32.18) (KERNEL.485)
1084 * 'Of course you cannot directly access Windows internal structures'
1086 DWORD WINAPI
GetProcessDword( DWORD dwProcessID
, INT offset
)
1088 PDB
*process
= PROCESS_IdToPDB( dwProcessID
);
1092 TRACE_(win32
)("(%ld, %d)\n", dwProcessID
, offset
);
1093 if ( !process
) return 0;
1097 case GPD_APP_COMPAT_FLAGS
:
1098 pTask
= (TDB
*)GlobalLock16( process
->task
);
1099 return pTask
? pTask
->compat_flags
: 0;
1101 case GPD_LOAD_DONE_EVENT
:
1102 return process
->load_done_evt
;
1104 case GPD_HINSTANCE16
:
1105 pTask
= (TDB
*)GlobalLock16( process
->task
);
1106 return pTask
? pTask
->hInstance
: 0;
1108 case GPD_WINDOWS_VERSION
:
1109 pTask
= (TDB
*)GlobalLock16( process
->task
);
1110 return pTask
? pTask
->version
: 0;
1113 if ( process
!= PROCESS_Current() ) return 0;
1114 return (DWORD
)NtCurrentTeb() - 0x10 /* FIXME */;
1117 return (DWORD
)process
;
1119 case GPD_STARTF_SHELLDATA
: /* return stdoutput handle from startupinfo ??? */
1120 return process
->env_db
->startup_info
->hStdOutput
;
1122 case GPD_STARTF_HOTKEY
: /* return stdinput handle from startupinfo ??? */
1123 return process
->env_db
->startup_info
->hStdInput
;
1125 case GPD_STARTF_SHOWWINDOW
:
1126 return process
->env_db
->startup_info
->wShowWindow
;
1128 case GPD_STARTF_SIZE
:
1129 x
= process
->env_db
->startup_info
->dwXSize
;
1130 if ( x
== CW_USEDEFAULT
) x
= CW_USEDEFAULT16
;
1131 y
= process
->env_db
->startup_info
->dwYSize
;
1132 if ( y
== CW_USEDEFAULT
) y
= CW_USEDEFAULT16
;
1133 return MAKELONG( x
, y
);
1135 case GPD_STARTF_POSITION
:
1136 x
= process
->env_db
->startup_info
->dwX
;
1137 if ( x
== CW_USEDEFAULT
) x
= CW_USEDEFAULT16
;
1138 y
= process
->env_db
->startup_info
->dwY
;
1139 if ( y
== CW_USEDEFAULT
) y
= CW_USEDEFAULT16
;
1140 return MAKELONG( x
, y
);
1142 case GPD_STARTF_FLAGS
:
1143 return process
->env_db
->startup_info
->dwFlags
;
1146 return process
->parent
? (DWORD
)process
->parent
->server_pid
: 0;
1149 return process
->flags
;
1152 return process
->process_dword
;
1155 ERR_(win32
)("Unknown offset %d\n", offset
);
1160 /***********************************************************************
1161 * SetProcessDword (KERNEL.484)
1162 * 'Of course you cannot directly access Windows internal structures'
1164 void WINAPI
SetProcessDword( DWORD dwProcessID
, INT offset
, DWORD value
)
1166 PDB
*process
= PROCESS_IdToPDB( dwProcessID
);
1168 TRACE_(win32
)("(%ld, %d)\n", dwProcessID
, offset
);
1169 if ( !process
) return;
1173 case GPD_APP_COMPAT_FLAGS
:
1174 case GPD_LOAD_DONE_EVENT
:
1175 case GPD_HINSTANCE16
:
1176 case GPD_WINDOWS_VERSION
:
1179 case GPD_STARTF_SHELLDATA
:
1180 case GPD_STARTF_HOTKEY
:
1181 case GPD_STARTF_SHOWWINDOW
:
1182 case GPD_STARTF_SIZE
:
1183 case GPD_STARTF_POSITION
:
1184 case GPD_STARTF_FLAGS
:
1187 ERR_(win32
)("Not allowed to modify offset %d\n", offset
);
1191 process
->process_dword
= value
;
1195 ERR_(win32
)("Unknown offset %d\n", offset
);
1201 /*********************************************************************
1202 * OpenProcess (KERNEL32.543)
1204 HANDLE WINAPI
OpenProcess( DWORD access
, BOOL inherit
, DWORD id
)
1207 struct open_process_request
*req
= get_req_buffer();
1209 req
->pid
= (void *)id
;
1210 req
->access
= access
;
1211 req
->inherit
= inherit
;
1212 if (!server_call( REQ_OPEN_PROCESS
)) ret
= req
->handle
;
1216 /*********************************************************************
1217 * MapProcessHandle (KERNEL.483)
1219 DWORD WINAPI
MapProcessHandle( HANDLE handle
)
1222 struct get_process_info_request
*req
= get_req_buffer();
1223 req
->handle
= handle
;
1224 if (!server_call( REQ_GET_PROCESS_INFO
)) ret
= (DWORD
)req
->pid
;
1228 /***********************************************************************
1229 * GetThreadLocale (KERNEL32.295)
1231 LCID WINAPI
GetThreadLocale(void)
1233 return PROCESS_Current()->locale
;
1237 /***********************************************************************
1238 * SetPriorityClass (KERNEL32.503)
1240 BOOL WINAPI
SetPriorityClass( HANDLE hprocess
, DWORD priorityclass
)
1242 struct set_process_info_request
*req
= get_req_buffer();
1243 req
->handle
= hprocess
;
1244 req
->priority
= priorityclass
;
1245 req
->mask
= SET_PROCESS_INFO_PRIORITY
;
1246 return !server_call( REQ_SET_PROCESS_INFO
);
1250 /***********************************************************************
1251 * GetPriorityClass (KERNEL32.250)
1253 DWORD WINAPI
GetPriorityClass(HANDLE hprocess
)
1256 struct get_process_info_request
*req
= get_req_buffer();
1257 req
->handle
= hprocess
;
1258 if (!server_call( REQ_GET_PROCESS_INFO
)) ret
= req
->priority
;
1263 /***********************************************************************
1264 * SetProcessAffinityMask (KERNEL32.662)
1266 BOOL WINAPI
SetProcessAffinityMask( HANDLE hProcess
, DWORD affmask
)
1268 struct set_process_info_request
*req
= get_req_buffer();
1269 req
->handle
= hProcess
;
1270 req
->affinity
= affmask
;
1271 req
->mask
= SET_PROCESS_INFO_AFFINITY
;
1272 return !server_call( REQ_SET_PROCESS_INFO
);
1275 /**********************************************************************
1276 * GetProcessAffinityMask (KERNEL32.373)
1278 BOOL WINAPI
GetProcessAffinityMask( HANDLE hProcess
,
1279 LPDWORD lpProcessAffinityMask
,
1280 LPDWORD lpSystemAffinityMask
)
1283 struct get_process_info_request
*req
= get_req_buffer();
1284 req
->handle
= hProcess
;
1285 if (!server_call( REQ_GET_PROCESS_INFO
))
1287 if (lpProcessAffinityMask
) *lpProcessAffinityMask
= req
->process_affinity
;
1288 if (lpSystemAffinityMask
) *lpSystemAffinityMask
= req
->system_affinity
;
1295 /***********************************************************************
1296 * GetStdHandle (KERNEL32.276)
1298 HANDLE WINAPI
GetStdHandle( DWORD std_handle
)
1300 PDB
*pdb
= PROCESS_Current();
1304 case STD_INPUT_HANDLE
: return pdb
->env_db
->hStdin
;
1305 case STD_OUTPUT_HANDLE
: return pdb
->env_db
->hStdout
;
1306 case STD_ERROR_HANDLE
: return pdb
->env_db
->hStderr
;
1308 SetLastError( ERROR_INVALID_PARAMETER
);
1309 return INVALID_HANDLE_VALUE
;
1313 /***********************************************************************
1314 * SetStdHandle (KERNEL32.506)
1316 BOOL WINAPI
SetStdHandle( DWORD std_handle
, HANDLE handle
)
1318 PDB
*pdb
= PROCESS_Current();
1319 /* FIXME: should we close the previous handle? */
1322 case STD_INPUT_HANDLE
:
1323 pdb
->env_db
->hStdin
= handle
;
1325 case STD_OUTPUT_HANDLE
:
1326 pdb
->env_db
->hStdout
= handle
;
1328 case STD_ERROR_HANDLE
:
1329 pdb
->env_db
->hStderr
= handle
;
1332 SetLastError( ERROR_INVALID_PARAMETER
);
1336 /***********************************************************************
1337 * GetProcessVersion (KERNEL32)
1339 DWORD WINAPI
GetProcessVersion( DWORD processid
)
1342 PDB
*pdb
= PROCESS_IdToPDB( processid
);
1345 if (!(pTask
= (TDB
*)GlobalLock16( pdb
->task
))) return 0;
1346 return (pTask
->version
&0xff) | (((pTask
->version
>>8) & 0xff)<<16);
1349 /***********************************************************************
1350 * GetProcessFlags (KERNEL32)
1352 DWORD WINAPI
GetProcessFlags( DWORD processid
)
1354 PDB
*pdb
= PROCESS_IdToPDB( processid
);
1359 /***********************************************************************
1360 * SetProcessWorkingSetSize [KERNEL32.662]
1361 * Sets the min/max working set sizes for a specified process.
1364 * hProcess [I] Handle to the process of interest
1365 * minset [I] Specifies minimum working set size
1366 * maxset [I] Specifies maximum working set size
1370 BOOL WINAPI
SetProcessWorkingSetSize(HANDLE hProcess
,DWORD minset
,
1373 FIXME("(0x%08x,%ld,%ld): stub - harmless\n",hProcess
,minset
,maxset
);
1374 if(( minset
== -1) && (maxset
== -1)) {
1375 /* Trim the working set to zero */
1376 /* Swap the process out of physical RAM */
1381 /***********************************************************************
1382 * GetProcessWorkingSetSize (KERNEL32)
1384 BOOL WINAPI
GetProcessWorkingSetSize(HANDLE hProcess
,LPDWORD minset
,
1387 FIXME("(0x%08x,%p,%p): stub\n",hProcess
,minset
,maxset
);
1388 /* 32 MB working set size */
1389 if (minset
) *minset
= 32*1024*1024;
1390 if (maxset
) *maxset
= 32*1024*1024;
1394 /***********************************************************************
1395 * SetProcessShutdownParameters (KERNEL32)
1397 * CHANGED - James Sutherland (JamesSutherland@gmx.de)
1398 * Now tracks changes made (but does not act on these changes)
1399 * NOTE: the definition for SHUTDOWN_NORETRY was done on guesswork.
1400 * It really shouldn't be here, but I'll move it when it's been checked!
1402 #define SHUTDOWN_NORETRY 1
1403 static unsigned int shutdown_noretry
= 0;
1404 static unsigned int shutdown_priority
= 0x280L
;
1405 BOOL WINAPI
SetProcessShutdownParameters(DWORD level
,DWORD flags
)
1407 if (flags
& SHUTDOWN_NORETRY
)
1408 shutdown_noretry
= 1;
1410 shutdown_noretry
= 0;
1411 if (level
> 0x100L
&& level
< 0x3FFL
)
1412 shutdown_priority
= level
;
1415 ERR("invalid priority level 0x%08lx\n", level
);
1422 /***********************************************************************
1423 * GetProcessShutdownParameters (KERNEL32)
1426 BOOL WINAPI
GetProcessShutdownParameters( LPDWORD lpdwLevel
,
1429 (*lpdwLevel
) = shutdown_priority
;
1430 (*lpdwFlags
) = (shutdown_noretry
* SHUTDOWN_NORETRY
);
1433 /***********************************************************************
1434 * SetProcessPriorityBoost (KERNEL32)
1436 BOOL WINAPI
SetProcessPriorityBoost(HANDLE hprocess
,BOOL disableboost
)
1438 FIXME("(%d,%d): stub\n",hprocess
,disableboost
);
1439 /* Say we can do it. I doubt the program will notice that we don't. */
1444 /***********************************************************************
1445 * ReadProcessMemory (KERNEL32)
1447 BOOL WINAPI
ReadProcessMemory( HANDLE process
, LPCVOID addr
, LPVOID buffer
, DWORD size
,
1448 LPDWORD bytes_read
)
1450 struct read_process_memory_request
*req
= get_req_buffer();
1451 unsigned int offset
= (unsigned int)addr
% sizeof(int);
1452 unsigned int max
= server_remaining( req
->data
); /* max length in one request */
1455 if (bytes_read
) *bytes_read
= size
;
1457 /* first time, read total length to check for permissions */
1458 req
->handle
= process
;
1459 req
->addr
= (char *)addr
- offset
;
1460 req
->len
= (size
+ offset
+ sizeof(int) - 1) / sizeof(int);
1461 if (server_call( REQ_READ_PROCESS_MEMORY
)) goto error
;
1463 if (size
<= max
- offset
)
1465 memcpy( buffer
, (char *)req
->data
+ offset
, size
);
1469 /* now take care of the remaining data */
1470 memcpy( buffer
, (char *)req
->data
+ offset
, max
- offset
);
1475 if (max
> size
) max
= size
;
1476 req
->handle
= process
;
1477 req
->addr
= (char *)addr
+ pos
;
1478 req
->len
= (max
+ sizeof(int) - 1) / sizeof(int);
1479 if (server_call( REQ_READ_PROCESS_MEMORY
)) goto error
;
1480 memcpy( (char *)buffer
+ pos
, (char *)req
->data
, max
);
1487 if (bytes_read
) *bytes_read
= 0;
1492 /***********************************************************************
1493 * WriteProcessMemory (KERNEL32)
1495 BOOL WINAPI
WriteProcessMemory( HANDLE process
, LPVOID addr
, LPVOID buffer
, DWORD size
,
1496 LPDWORD bytes_written
)
1498 unsigned int first_offset
, last_offset
;
1499 struct write_process_memory_request
*req
= get_req_buffer();
1500 unsigned int max
= server_remaining( req
->data
); /* max length in one request */
1501 unsigned int pos
, last_mask
;
1505 SetLastError( ERROR_INVALID_PARAMETER
);
1508 if (bytes_written
) *bytes_written
= size
;
1510 /* compute the mask for the first int */
1511 req
->first_mask
= ~0;
1512 first_offset
= (unsigned int)addr
% sizeof(int);
1513 memset( &req
->first_mask
, 0, first_offset
);
1515 /* compute the mask for the last int */
1516 last_offset
= (size
+ first_offset
) % sizeof(int);
1518 memset( &last_mask
, 0xff, last_offset
? last_offset
: sizeof(int) );
1520 req
->handle
= process
;
1521 req
->addr
= (char *)addr
- first_offset
;
1522 /* for the first request, use the total length */
1523 req
->len
= (size
+ first_offset
+ sizeof(int) - 1) / sizeof(int);
1525 if (size
+ first_offset
< max
) /* we can do it in one round */
1527 memcpy( (char *)req
->data
+ first_offset
, buffer
, size
);
1528 req
->last_mask
= last_mask
;
1529 if (server_call( REQ_WRITE_PROCESS_MEMORY
)) goto error
;
1533 /* needs multiple server calls */
1535 memcpy( (char *)req
->data
+ first_offset
, buffer
, max
- first_offset
);
1536 req
->last_mask
= ~0;
1537 if (server_call( REQ_WRITE_PROCESS_MEMORY
)) goto error
;
1538 pos
= max
- first_offset
;
1542 if (size
<= max
) /* last one */
1544 req
->last_mask
= last_mask
;
1547 req
->handle
= process
;
1548 req
->addr
= (char *)addr
+ pos
;
1549 req
->len
= (max
+ sizeof(int) - 1) / sizeof(int);
1550 req
->first_mask
= ~0;
1551 memcpy( req
->data
, (char *) buffer
+ pos
, max
);
1552 if (server_call( REQ_WRITE_PROCESS_MEMORY
)) goto error
;
1559 if (bytes_written
) *bytes_written
= 0;
1565 /***********************************************************************
1566 * RegisterServiceProcess (KERNEL, KERNEL32)
1568 * A service process calls this function to ensure that it continues to run
1569 * even after a user logged off.
1571 DWORD WINAPI
RegisterServiceProcess(DWORD dwProcessId
, DWORD dwType
)
1573 /* I don't think that Wine needs to do anything in that function */
1574 return 1; /* success */
1577 /***********************************************************************
1578 * GetExitCodeProcess [KERNEL32.325]
1580 * Gets termination status of specified process
1586 BOOL WINAPI
GetExitCodeProcess(
1587 HANDLE hProcess
, /* [I] handle to the process */
1588 LPDWORD lpExitCode
) /* [O] address to receive termination status */
1591 struct get_process_info_request
*req
= get_req_buffer();
1592 req
->handle
= hProcess
;
1593 if (!server_call( REQ_GET_PROCESS_INFO
))
1595 if (lpExitCode
) *lpExitCode
= req
->exit_code
;
1602 /***********************************************************************
1603 * SetErrorMode (KERNEL32.486)
1605 UINT WINAPI
SetErrorMode( UINT mode
)
1607 UINT old
= PROCESS_Current()->error_mode
;
1608 PROCESS_Current()->error_mode
= mode
;
1612 /***********************************************************************
1613 * GetCurrentProcess (KERNEL32.198)
1615 #undef GetCurrentProcess
1616 HANDLE WINAPI
GetCurrentProcess(void)