Added more conversion routines (rate conversion is implemented).
[wine.git] / scheduler / process.c
blob795527be6f93026098478628e1b7dcfc51700985
1 /*
2 * Win32 processes
4 * Copyright 1996, 1998 Alexandre Julliard
5 */
7 #include <assert.h>
8 #include <ctype.h>
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <stdlib.h>
12 #include <stdio.h>
13 #include <string.h>
14 #include <unistd.h>
15 #include "wine/winbase16.h"
16 #include "wine/exception.h"
17 #include "process.h"
18 #include "drive.h"
19 #include "main.h"
20 #include "module.h"
21 #include "neexe.h"
22 #include "dosexe.h"
23 #include "file.h"
24 #include "global.h"
25 #include "heap.h"
26 #include "task.h"
27 #include "ldt.h"
28 #include "syslevel.h"
29 #include "thread.h"
30 #include "winerror.h"
31 #include "server.h"
32 #include "options.h"
33 #include "callback.h"
34 #include "debugtools.h"
36 DEFAULT_DEBUG_CHANNEL(process);
37 DECLARE_DEBUG_CHANNEL(relay);
38 DECLARE_DEBUG_CHANNEL(win32);
40 PDB current_process;
42 static char **main_exe_argv;
43 static char main_exe_name[MAX_PATH];
44 static HFILE main_exe_file = INVALID_HANDLE_VALUE;
46 unsigned int server_startticks;
48 /***********************************************************************
49 * PROCESS_CallUserSignalProc
51 * FIXME: Some of the signals aren't sent correctly!
53 * The exact meaning of the USER signals is undocumented, but this
54 * should cover the basic idea:
56 * USIG_DLL_UNLOAD_WIN16
57 * This is sent when a 16-bit module is unloaded.
59 * USIG_DLL_UNLOAD_WIN32
60 * This is sent when a 32-bit module is unloaded.
62 * USIG_DLL_UNLOAD_ORPHANS
63 * This is sent after the last Win3.1 module is unloaded,
64 * to allow removal of orphaned menus.
66 * USIG_FAULT_DIALOG_PUSH
67 * USIG_FAULT_DIALOG_POP
68 * These are called to allow USER to prepare for displaying a
69 * fault dialog, even though the fault might have happened while
70 * inside a USER critical section.
72 * USIG_THREAD_INIT
73 * This is called from the context of a new thread, as soon as it
74 * has started to run.
76 * USIG_THREAD_EXIT
77 * This is called, still in its context, just before a thread is
78 * about to terminate.
80 * USIG_PROCESS_CREATE
81 * This is called, in the parent process context, after a new process
82 * has been created.
84 * USIG_PROCESS_INIT
85 * This is called in the new process context, just after the main thread
86 * has started execution (after the main thread's USIG_THREAD_INIT has
87 * been sent).
89 * USIG_PROCESS_LOADED
90 * This is called after the executable file has been loaded into the
91 * new process context.
93 * USIG_PROCESS_RUNNING
94 * This is called immediately before the main entry point is called.
96 * USIG_PROCESS_EXIT
97 * This is called in the context of a process that is about to
98 * terminate (but before the last thread's USIG_THREAD_EXIT has
99 * been sent).
101 * USIG_PROCESS_DESTROY
102 * This is called after a process has terminated.
105 * The meaning of the dwFlags bits is as follows:
107 * USIG_FLAGS_WIN32
108 * Current process is 32-bit.
110 * USIG_FLAGS_GUI
111 * Current process is a (Win32) GUI process.
113 * USIG_FLAGS_FEEDBACK
114 * Current process needs 'feedback' (determined from the STARTUPINFO
115 * flags STARTF_FORCEONFEEDBACK / STARTF_FORCEOFFFEEDBACK).
117 * USIG_FLAGS_FAULT
118 * The signal is being sent due to a fault.
120 void PROCESS_CallUserSignalProc( UINT uCode, HMODULE hModule )
122 DWORD flags = current_process.flags;
123 DWORD startup_flags = current_startupinfo.dwFlags;
124 DWORD dwFlags = 0;
126 /* Determine dwFlags */
128 if ( !(flags & PDB32_WIN16_PROC) ) dwFlags |= USIG_FLAGS_WIN32;
130 if ( !(flags & PDB32_CONSOLE_PROC) ) dwFlags |= USIG_FLAGS_GUI;
132 if ( dwFlags & USIG_FLAGS_GUI )
134 /* Feedback defaults to ON */
135 if ( !(startup_flags & STARTF_FORCEOFFFEEDBACK) )
136 dwFlags |= USIG_FLAGS_FEEDBACK;
138 else
140 /* Feedback defaults to OFF */
141 if (startup_flags & STARTF_FORCEONFEEDBACK)
142 dwFlags |= USIG_FLAGS_FEEDBACK;
145 /* Convert module handle to 16-bit */
147 if ( HIWORD( hModule ) )
148 hModule = MapHModuleLS( hModule );
150 /* Call USER signal proc */
152 if ( Callout.UserSignalProc )
154 if ( uCode == USIG_THREAD_INIT || uCode == USIG_THREAD_EXIT )
155 Callout.UserSignalProc( uCode, GetCurrentThreadId(), dwFlags, hModule );
156 else
157 Callout.UserSignalProc( uCode, GetCurrentProcessId(), dwFlags, hModule );
162 /***********************************************************************
163 * process_init
165 * Main process initialisation code
167 static BOOL process_init( char *argv[] )
169 BOOL ret;
171 /* store the program name */
172 argv0 = argv[0];
174 /* Fill the initial process structure */
175 current_process.exit_code = STILL_ACTIVE;
176 current_process.threads = 1;
177 current_process.running_threads = 1;
178 current_process.ring0_threads = 1;
179 current_process.group = &current_process;
180 current_process.priority = 8; /* Normal */
181 current_process.env_db = &current_envdb;
183 /* Setup the server connection */
184 NtCurrentTeb()->socket = CLIENT_InitServer();
185 if (CLIENT_InitThread()) return FALSE;
187 /* Retrieve startup info from the server */
188 SERVER_START_REQ
190 struct init_process_request *req = server_alloc_req( sizeof(*req),
191 sizeof(main_exe_name)-1 );
193 req->ldt_copy = ldt_copy;
194 req->ldt_flags = ldt_flags_copy;
195 req->ppid = getppid();
196 if ((ret = !server_call( REQ_INIT_PROCESS )))
198 size_t len = server_data_size( req );
199 memcpy( main_exe_name, server_data_ptr(req), len );
200 main_exe_name[len] = 0;
201 main_exe_file = req->exe_file;
202 current_startupinfo.dwFlags = req->start_flags;
203 server_startticks = req->server_start;
204 current_startupinfo.wShowWindow = req->cmd_show;
205 current_envdb.hStdin = current_startupinfo.hStdInput = req->hstdin;
206 current_envdb.hStdout = current_startupinfo.hStdOutput = req->hstdout;
207 current_envdb.hStderr = current_startupinfo.hStdError = req->hstderr;
210 SERVER_END_REQ;
211 if (!ret) return FALSE;
213 /* Remember TEB selector of initial process for emergency use */
214 SYSLEVEL_EmergencyTeb = NtCurrentTeb()->teb_sel;
216 /* Create the system and process heaps */
217 if (!HEAP_CreateSystemHeap()) return FALSE;
218 current_process.heap = HeapCreate( HEAP_GROWABLE, 0, 0 );
220 /* Copy the parent environment */
221 if (!ENV_BuildEnvironment()) return FALSE;
223 /* Create the SEGPTR heap */
224 if (!(SegptrHeap = HeapCreate( HEAP_WINE_SEGPTR, 0, 0 ))) return FALSE;
226 /* Initialize the critical sections */
227 InitializeCriticalSection( &current_process.crit_section );
229 /* Initialize syslevel handling */
230 SYSLEVEL_Init();
232 /* Parse command line arguments */
233 OPTIONS_ParseOptions( argv );
235 return MAIN_MainInit();
239 /***********************************************************************
240 * load_system_dlls
242 * Load system DLLs into the initial process (and initialize them)
244 static int load_system_dlls(void)
246 /* Load KERNEL */
247 if (!LoadLibraryA( "KERNEL32" )) return 0;
249 /* Get pointers to USER routines called by KERNEL */
250 THUNK_InitCallout();
252 /* Call FinalUserInit routine */
253 Callout.FinalUserInit16();
255 /* Note: The USIG_PROCESS_CREATE signal is supposed to be sent in the
256 * context of the parent process. Actually, the USER signal proc
257 * doesn't really care about that, but it *does* require that the
258 * startup parameters are correctly set up, so that GetProcessDword
259 * works. Furthermore, before calling the USER signal proc the
260 * 16-bit stack must be set up, which it is only after TASK_Create
261 * in the case of a 16-bit process. Thus, we send the signal here.
263 PROCESS_CallUserSignalProc( USIG_PROCESS_CREATE, 0 );
264 PROCESS_CallUserSignalProc( USIG_THREAD_INIT, 0 );
265 PROCESS_CallUserSignalProc( USIG_PROCESS_INIT, 0 );
266 PROCESS_CallUserSignalProc( USIG_PROCESS_LOADED, 0 );
268 return 1;
272 /***********************************************************************
273 * build_command_line
275 * Build the command line of a process from the argv array.
277 * Note that it does NOT necessarily include the file name.
278 * Sometimes we don't even have any command line options at all.
280 static inline char *build_command_line( char **argv )
282 int len, quote = 0;
283 char *cmdline, *p, **arg;
285 for (arg = argv, len = 0; *arg; arg++) len += strlen(*arg) + 1;
286 if ((argv[0]) && (quote = (strchr( argv[0], ' ' ) != NULL))) len += 2;
287 if (!(p = cmdline = HeapAlloc( GetProcessHeap(), 0, len ))) return NULL;
288 arg = argv;
289 if (quote)
291 *p++ = '\"';
292 strcpy( p, *arg );
293 p += strlen(p);
294 *p++ = '\"';
295 *p++ = ' ';
296 arg++;
298 while (*arg)
300 strcpy( p, *arg );
301 p += strlen(p);
302 *p++ = ' ';
303 arg++;
305 if (p > cmdline) p--; /* remove last space */
306 *p = 0;
307 return cmdline;
311 /***********************************************************************
312 * start_process
314 * Startup routine of a new process. Runs on the new process stack.
316 static void start_process(void)
318 int debugged, console_app;
319 LPTHREAD_START_ROUTINE entry;
320 HMODULE module = current_process.exe_modref->module;
322 /* Increment EXE refcount */
323 current_process.exe_modref->refCount++;
325 /* build command line */
326 if (!(current_envdb.cmd_line = build_command_line( main_exe_argv ))) goto error;
328 /* Retrieve entry point address */
329 entry = (LPTHREAD_START_ROUTINE)((char*)module + PE_HEADER(module)->OptionalHeader.AddressOfEntryPoint);
330 console_app = (PE_HEADER(module)->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI);
332 if (console_app) current_process.flags |= PDB32_CONSOLE_PROC;
334 /* Signal the parent process to continue */
335 SERVER_START_REQ
337 struct init_process_done_request *req = server_alloc_req( sizeof(*req), 0 );
338 req->module = (void *)module;
339 req->entry = entry;
340 req->name = &current_process.exe_modref->filename;
341 req->gui = !console_app;
342 server_call( REQ_INIT_PROCESS_DONE );
343 debugged = req->debugged;
345 SERVER_END_REQ;
347 /* Install signal handlers; this cannot be done before, since we cannot
348 * send exceptions to the debugger before the create process event that
349 * is sent by REQ_INIT_PROCESS_DONE */
350 if (!SIGNAL_Init()) goto error;
352 /* Load the system dlls */
353 if (!load_system_dlls()) goto error;
355 EnterCriticalSection( &current_process.crit_section );
356 PE_InitTls();
357 MODULE_DllProcessAttach( current_process.exe_modref, (LPVOID)1 );
358 LeaveCriticalSection( &current_process.crit_section );
360 /* Call UserSignalProc ( USIG_PROCESS_RUNNING ... ) only for non-GUI win32 apps */
361 if (console_app) PROCESS_CallUserSignalProc( USIG_PROCESS_RUNNING, 0 );
363 TRACE_(relay)( "Starting Win32 process (entryproc=%p)\n", entry );
364 if (debugged) DbgBreakPoint();
365 /* FIXME: should use _PEB as parameter for NT 3.5 programs !
366 * Dunno about other OSs */
367 SetLastError(0); /* clear error code */
368 ExitThread( entry(NULL) );
370 error:
371 ExitProcess( GetLastError() );
375 /***********************************************************************
376 * PROCESS_Start
378 * Startup routine of a new Win32 process once the main module has been loaded.
380 static void PROCESS_Start( HMODULE main_module, HFILE hFile, LPCSTR filename ) WINE_NORETURN;
381 static void PROCESS_Start( HMODULE main_module, HFILE hFile, LPCSTR filename )
383 if (!filename)
385 /* if no explicit filename, use argv[0] */
386 filename = main_exe_name;
387 if (!GetLongPathNameA( full_argv0, main_exe_name, sizeof(main_exe_name) ))
388 lstrcpynA( main_exe_name, full_argv0, sizeof(main_exe_name) );
391 /* load main module */
392 if (PE_HEADER(main_module)->FileHeader.Characteristics & IMAGE_FILE_DLL)
393 ExitProcess( ERROR_BAD_EXE_FORMAT );
395 /* Create 32-bit MODREF */
396 if (!PE_CreateModule( main_module, filename, 0, hFile, FALSE ))
397 goto error;
399 /* allocate main thread stack */
400 if (!THREAD_InitStack( NtCurrentTeb(),
401 PE_HEADER(main_module)->OptionalHeader.SizeOfStackReserve, TRUE ))
402 goto error;
404 /* switch to the new stack */
405 SYSDEPS_SwitchToThreadStack( start_process );
407 error:
408 ExitProcess( GetLastError() );
412 /***********************************************************************
413 * PROCESS_InitWine
415 * Wine initialisation: load and start the main exe file.
417 void PROCESS_InitWine( int argc, char *argv[] )
419 DWORD type;
421 /* Initialize everything */
422 if (!process_init( argv )) exit(1);
424 main_exe_argv = ++argv; /* remove argv[0] (wine itself) */
426 if (!main_exe_name[0])
428 if (!argv[0]) OPTIONS_Usage();
430 /* open the exe file */
431 if (!SearchPathA( NULL, argv[0], ".exe", sizeof(main_exe_name), main_exe_name, NULL ) &&
432 !SearchPathA( NULL, argv[0], NULL, sizeof(main_exe_name), main_exe_name, NULL ))
434 MESSAGE( "%s: cannot find '%s'\n", argv0, argv[0] );
435 goto error;
439 if (main_exe_file == INVALID_HANDLE_VALUE)
441 if ((main_exe_file = CreateFileA( main_exe_name, GENERIC_READ, FILE_SHARE_READ,
442 NULL, OPEN_EXISTING, 0, -1 )) == INVALID_HANDLE_VALUE)
444 MESSAGE( "%s: cannot open '%s'\n", argv0, main_exe_name );
445 goto error;
449 if (!MODULE_GetBinaryType( main_exe_file, main_exe_name, &type ))
451 MESSAGE( "%s: unrecognized executable '%s'\n", argv0, main_exe_name );
452 goto error;
455 switch (type)
457 case SCS_32BIT_BINARY:
459 HMODULE main_module = PE_LoadImage( main_exe_file, main_exe_name, 0 );
460 if (main_module) PROCESS_Start( main_module, main_exe_file, main_exe_name );
462 break;
464 case SCS_WOW_BINARY:
466 HMODULE main_module;
467 /* create 32-bit module for main exe */
468 if (!(main_module = BUILTIN32_LoadExeModule())) goto error;
469 NtCurrentTeb()->tibflags &= ~TEBF_WIN32;
470 current_process.flags |= PDB32_WIN16_PROC;
471 SYSLEVEL_EnterWin16Lock();
472 PROCESS_Start( main_module, -1, NULL );
474 break;
476 case SCS_DOS_BINARY:
478 HMODULE main_module;
479 /* create 32-bit module for main exe */
480 if (!(main_module = BUILTIN32_LoadExeModule())) goto error;
481 NtCurrentTeb()->tibflags &= ~TEBF_WIN32;
482 if (!MZ_LoadImage( main_module, main_exe_file, main_exe_name )) goto error;
483 PROCESS_Start( main_module, main_exe_file, NULL );
485 break;
487 case SCS_PIF_BINARY:
488 case SCS_POSIX_BINARY:
489 case SCS_OS216_BINARY:
490 default:
491 MESSAGE( "%s: unrecognized executable '%s'\n", argv0, main_exe_name );
492 SetLastError( ERROR_BAD_FORMAT );
493 break;
495 error:
496 ExitProcess( GetLastError() );
500 /***********************************************************************
501 * PROCESS_InitWinelib
503 * Initialisation of a new Winelib process.
505 void PROCESS_InitWinelib( int argc, char *argv[] )
507 HMODULE main_module;
509 if (!process_init( argv )) exit(1);
511 /* create 32-bit module for main exe */
512 if (!(main_module = BUILTIN32_LoadExeModule())) ExitProcess( GetLastError() );
514 main_exe_argv = argv;
515 PROCESS_Start( main_module, -1, NULL );
519 /***********************************************************************
520 * build_argv
522 * Build an argv array from a command-line.
523 * The command-line is modified to insert nulls.
524 * 'reserved' is the number of args to reserve before the first one.
526 static char **build_argv( char *cmdline, int reserved )
528 char **argv;
529 int count = reserved + 1;
530 char *p = cmdline;
532 /* if first word is quoted store it as a single arg */
533 if (*cmdline == '\"')
535 if ((p = strchr( cmdline + 1, '\"' )))
537 p++;
538 count++;
540 else p = cmdline;
542 while (*p)
544 while (*p && isspace(*p)) p++;
545 if (!*p) break;
546 count++;
547 while (*p && !isspace(*p)) p++;
550 if ((argv = malloc( count * sizeof(*argv) )))
552 char **argvptr = argv + reserved;
553 p = cmdline;
554 if (*cmdline == '\"')
556 if ((p = strchr( cmdline + 1, '\"' )))
558 *argvptr++ = cmdline + 1;
559 *p++ = 0;
561 else p = cmdline;
563 while (*p)
565 while (*p && isspace(*p)) *p++ = 0;
566 if (!*p) break;
567 *argvptr++ = p;
568 while (*p && !isspace(*p)) p++;
570 *argvptr = 0;
572 return argv;
576 /***********************************************************************
577 * build_envp
579 * Build the environment of a new child process.
581 static char **build_envp( const char *env, const char *extra_env )
583 const char *p;
584 char **envp;
585 int count = 0;
587 if (extra_env) for (p = extra_env; *p; count++) p += strlen(p) + 1;
588 for (p = env; *p; count++) p += strlen(p) + 1;
589 count += 3;
591 if ((envp = malloc( count * sizeof(*envp) )))
593 extern char **environ;
594 char **envptr = envp;
595 char **unixptr = environ;
596 /* first the extra strings */
597 if (extra_env) for (p = extra_env; *p; p += strlen(p) + 1) *envptr++ = (char *)p;
598 /* then put PATH, HOME and WINEPREFIX from the unix env */
599 for (unixptr = environ; unixptr && *unixptr; unixptr++)
600 if (!memcmp( *unixptr, "PATH=", 5 ) ||
601 !memcmp( *unixptr, "HOME=", 5 ) ||
602 !memcmp( *unixptr, "WINEPREFIX=", 11 )) *envptr++ = *unixptr;
603 /* now put the Windows environment strings */
604 for (p = env; *p; p += strlen(p) + 1)
606 if (memcmp( p, "PATH=", 5 ) &&
607 memcmp( p, "HOME=", 5 ) &&
608 memcmp( p, "WINEPREFIX=", 11 )) *envptr++ = (char *)p;
610 *envptr = 0;
612 return envp;
616 /***********************************************************************
617 * exec_wine_binary
619 * Locate the Wine binary to exec for a new Win32 process.
621 static void exec_wine_binary( char **argv, char **envp )
623 const char *path, *pos, *ptr;
625 /* first try bin directory */
626 argv[0] = BINDIR "/wine";
627 execve( argv[0], argv, envp );
629 /* now try the path of argv0 of the current binary */
630 if (!(argv[0] = malloc( strlen(full_argv0) + 6 ))) return;
631 if ((ptr = strrchr( full_argv0, '/' )))
633 memcpy( argv[0], full_argv0, ptr - full_argv0 );
634 strcpy( argv[0] + (ptr - full_argv0), "/wine" );
635 execve( argv[0], argv, envp );
637 free( argv[0] );
639 /* now search in the Unix path */
640 if ((path = getenv( "PATH" )))
642 if (!(argv[0] = malloc( strlen(path) + 6 ))) return;
643 pos = path;
644 for (;;)
646 while (*pos == ':') pos++;
647 if (!*pos) break;
648 if (!(ptr = strchr( pos, ':' ))) ptr = pos + strlen(pos);
649 memcpy( argv[0], pos, ptr - pos );
650 strcpy( argv[0] + (ptr - pos), "/wine" );
651 execve( argv[0], argv, envp );
652 pos = ptr;
655 free( argv[0] );
657 /* finally try the current directory */
658 argv[0] = "./wine";
659 execve( argv[0], argv, envp );
663 /***********************************************************************
664 * fork_and_exec
666 * Fork and exec a new Unix process, checking for errors.
668 static int fork_and_exec( const char *filename, char *cmdline,
669 const char *env, const char *newdir )
671 int fd[2];
672 int pid, err;
673 char *extra_env = NULL;
675 if (!env)
677 env = GetEnvironmentStringsA();
678 extra_env = DRIVE_BuildEnv();
681 if (pipe(fd) == -1)
683 FILE_SetDosError();
684 return -1;
686 fcntl( fd[1], F_SETFD, 1 ); /* set close on exec */
687 if (!(pid = fork())) /* child */
689 char **argv = build_argv( cmdline, filename ? 0 : 2 );
690 char **envp = build_envp( env, extra_env );
691 close( fd[0] );
693 if (newdir) chdir(newdir);
695 if (argv && envp)
697 if (!filename)
699 argv[1] = "--";
700 exec_wine_binary( argv, envp );
702 else execve( filename, argv, envp );
704 err = errno;
705 write( fd[1], &err, sizeof(err) );
706 _exit(1);
708 close( fd[1] );
709 if ((pid != -1) && (read( fd[0], &err, sizeof(err) ) > 0)) /* exec failed */
711 errno = err;
712 pid = -1;
714 if (pid == -1) FILE_SetDosError();
715 close( fd[0] );
716 if (extra_env) HeapFree( GetProcessHeap(), 0, extra_env );
717 return pid;
721 /***********************************************************************
722 * PROCESS_Create
724 * Create a new process. If hFile is a valid handle we have an exe
725 * file, and we exec a new copy of wine to load it; otherwise we
726 * simply exec the specified filename as a Unix process.
728 BOOL PROCESS_Create( HFILE hFile, LPCSTR filename, LPSTR cmd_line, LPCSTR env,
729 LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES tsa,
730 BOOL inherit, DWORD flags, LPSTARTUPINFOA startup,
731 LPPROCESS_INFORMATION info, LPCSTR lpCurrentDirectory )
733 BOOL ret;
734 int pid;
735 const char *unixfilename = NULL;
736 const char *unixdir = NULL;
737 DOS_FULL_NAME full_name;
738 HANDLE load_done_evt = -1;
740 info->hThread = info->hProcess = INVALID_HANDLE_VALUE;
742 if (lpCurrentDirectory)
744 if (DOSFS_GetFullName( lpCurrentDirectory, TRUE, &full_name ))
745 unixdir = full_name.long_name;
747 else
749 char buf[MAX_PATH];
750 if (GetCurrentDirectoryA(sizeof(buf),buf))
752 if (DOSFS_GetFullName( buf, TRUE, &full_name ))
753 unixdir = full_name.long_name;
757 /* create the process on the server side */
759 SERVER_START_REQ
761 size_t len = (hFile == -1) ? 0 : MAX_PATH;
762 struct new_process_request *req = server_alloc_req( sizeof(*req), len );
763 req->inherit_all = inherit;
764 req->create_flags = flags;
765 req->start_flags = startup->dwFlags;
766 req->exe_file = hFile;
767 if (startup->dwFlags & STARTF_USESTDHANDLES)
769 req->hstdin = startup->hStdInput;
770 req->hstdout = startup->hStdOutput;
771 req->hstderr = startup->hStdError;
773 else
775 req->hstdin = GetStdHandle( STD_INPUT_HANDLE );
776 req->hstdout = GetStdHandle( STD_OUTPUT_HANDLE );
777 req->hstderr = GetStdHandle( STD_ERROR_HANDLE );
779 req->cmd_show = startup->wShowWindow;
780 req->alloc_fd = 0;
782 if (hFile == -1) /* unix process */
784 unixfilename = filename;
785 if (DOSFS_GetFullName( filename, TRUE, &full_name ))
786 unixfilename = full_name.long_name;
788 else /* new wine process */
790 if (!GetLongPathNameA( filename, server_data_ptr(req), MAX_PATH ))
791 lstrcpynA( server_data_ptr(req), filename, MAX_PATH );
793 ret = !server_call( REQ_NEW_PROCESS );
795 SERVER_END_REQ;
796 if (!ret) return FALSE;
798 /* fork and execute */
800 pid = fork_and_exec( unixfilename, cmd_line, env, unixdir );
802 SERVER_START_REQ
804 struct wait_process_request *req = server_alloc_req( sizeof(*req), 0 );
805 req->cancel = (pid == -1);
806 req->pinherit = (psa && (psa->nLength >= sizeof(*psa)) && psa->bInheritHandle);
807 req->tinherit = (tsa && (tsa->nLength >= sizeof(*tsa)) && tsa->bInheritHandle);
808 req->timeout = 2000;
809 if ((ret = !server_call( REQ_WAIT_PROCESS )) && (pid != -1))
811 info->dwProcessId = (DWORD)req->pid;
812 info->dwThreadId = (DWORD)req->tid;
813 info->hProcess = req->phandle;
814 info->hThread = req->thandle;
815 load_done_evt = req->event;
818 SERVER_END_REQ;
819 if (!ret || (pid == -1)) goto error;
821 /* Wait until process is initialized (or initialization failed) */
822 if (load_done_evt != -1)
824 DWORD res;
825 HANDLE handles[2];
827 handles[0] = info->hProcess;
828 handles[1] = load_done_evt;
829 res = WaitForMultipleObjects( 2, handles, FALSE, INFINITE );
830 CloseHandle( load_done_evt );
831 if (res == STATUS_WAIT_0) /* the process died */
833 DWORD exitcode;
834 if (GetExitCodeProcess( info->hProcess, &exitcode )) SetLastError( exitcode );
835 CloseHandle( info->hThread );
836 CloseHandle( info->hProcess );
837 return FALSE;
840 return TRUE;
842 error:
843 if (load_done_evt != -1) CloseHandle( load_done_evt );
844 if (info->hThread != INVALID_HANDLE_VALUE) CloseHandle( info->hThread );
845 if (info->hProcess != INVALID_HANDLE_VALUE) CloseHandle( info->hProcess );
846 return FALSE;
850 /***********************************************************************
851 * ExitProcess (KERNEL32.100)
853 void WINAPI ExitProcess( DWORD status )
855 MODULE_DllProcessDetach( TRUE, (LPVOID)1 );
856 SERVER_START_REQ
858 struct terminate_process_request *req = server_alloc_req( sizeof(*req), 0 );
859 /* send the exit code to the server */
860 req->handle = GetCurrentProcess();
861 req->exit_code = status;
862 server_call( REQ_TERMINATE_PROCESS );
864 SERVER_END_REQ;
865 exit( status );
868 /***********************************************************************
869 * ExitProcess16 (KERNEL.466)
871 void WINAPI ExitProcess16( WORD status )
873 SYSLEVEL_ReleaseWin16Lock();
874 ExitProcess( status );
877 /******************************************************************************
878 * TerminateProcess (KERNEL32.684)
880 BOOL WINAPI TerminateProcess( HANDLE handle, DWORD exit_code )
882 NTSTATUS status = NtTerminateProcess( handle, exit_code );
883 if (status) SetLastError( RtlNtStatusToDosError(status) );
884 return !status;
888 /***********************************************************************
889 * GetProcessDword (KERNEL32.18) (KERNEL.485)
890 * 'Of course you cannot directly access Windows internal structures'
892 DWORD WINAPI GetProcessDword( DWORD dwProcessID, INT offset )
894 TDB *pTask;
895 DWORD x, y;
897 TRACE_(win32)("(%ld, %d)\n", dwProcessID, offset );
899 if (dwProcessID && dwProcessID != GetCurrentProcessId())
901 ERR("%d: process %lx not accessible\n", offset, dwProcessID);
902 return 0;
905 switch ( offset )
907 case GPD_APP_COMPAT_FLAGS:
908 pTask = (TDB *)GlobalLock16( GetCurrentTask() );
909 return pTask? pTask->compat_flags : 0;
911 case GPD_LOAD_DONE_EVENT:
912 return current_process.load_done_evt;
914 case GPD_HINSTANCE16:
915 pTask = (TDB *)GlobalLock16( GetCurrentTask() );
916 return pTask? pTask->hInstance : 0;
918 case GPD_WINDOWS_VERSION:
919 pTask = (TDB *)GlobalLock16( GetCurrentTask() );
920 return pTask? pTask->version : 0;
922 case GPD_THDB:
923 return (DWORD)NtCurrentTeb() - 0x10 /* FIXME */;
925 case GPD_PDB:
926 return (DWORD)&current_process;
928 case GPD_STARTF_SHELLDATA: /* return stdoutput handle from startupinfo ??? */
929 return current_startupinfo.hStdOutput;
931 case GPD_STARTF_HOTKEY: /* return stdinput handle from startupinfo ??? */
932 return current_startupinfo.hStdInput;
934 case GPD_STARTF_SHOWWINDOW:
935 return current_startupinfo.wShowWindow;
937 case GPD_STARTF_SIZE:
938 x = current_startupinfo.dwXSize;
939 if ( x == CW_USEDEFAULT ) x = CW_USEDEFAULT16;
940 y = current_startupinfo.dwYSize;
941 if ( y == CW_USEDEFAULT ) y = CW_USEDEFAULT16;
942 return MAKELONG( x, y );
944 case GPD_STARTF_POSITION:
945 x = current_startupinfo.dwX;
946 if ( x == CW_USEDEFAULT ) x = CW_USEDEFAULT16;
947 y = current_startupinfo.dwY;
948 if ( y == CW_USEDEFAULT ) y = CW_USEDEFAULT16;
949 return MAKELONG( x, y );
951 case GPD_STARTF_FLAGS:
952 return current_startupinfo.dwFlags;
954 case GPD_PARENT:
955 return 0;
957 case GPD_FLAGS:
958 return current_process.flags;
960 case GPD_USERDATA:
961 return current_process.process_dword;
963 default:
964 ERR_(win32)("Unknown offset %d\n", offset );
965 return 0;
969 /***********************************************************************
970 * SetProcessDword (KERNEL.484)
971 * 'Of course you cannot directly access Windows internal structures'
973 void WINAPI SetProcessDword( DWORD dwProcessID, INT offset, DWORD value )
975 TRACE_(win32)("(%ld, %d)\n", dwProcessID, offset );
977 if (dwProcessID && dwProcessID != GetCurrentProcessId())
979 ERR("%d: process %lx not accessible\n", offset, dwProcessID);
980 return;
983 switch ( offset )
985 case GPD_APP_COMPAT_FLAGS:
986 case GPD_LOAD_DONE_EVENT:
987 case GPD_HINSTANCE16:
988 case GPD_WINDOWS_VERSION:
989 case GPD_THDB:
990 case GPD_PDB:
991 case GPD_STARTF_SHELLDATA:
992 case GPD_STARTF_HOTKEY:
993 case GPD_STARTF_SHOWWINDOW:
994 case GPD_STARTF_SIZE:
995 case GPD_STARTF_POSITION:
996 case GPD_STARTF_FLAGS:
997 case GPD_PARENT:
998 case GPD_FLAGS:
999 ERR_(win32)("Not allowed to modify offset %d\n", offset );
1000 break;
1002 case GPD_USERDATA:
1003 current_process.process_dword = value;
1004 break;
1006 default:
1007 ERR_(win32)("Unknown offset %d\n", offset );
1008 break;
1013 /*********************************************************************
1014 * OpenProcess (KERNEL32.543)
1016 HANDLE WINAPI OpenProcess( DWORD access, BOOL inherit, DWORD id )
1018 HANDLE ret = 0;
1019 SERVER_START_REQ
1021 struct open_process_request *req = server_alloc_req( sizeof(*req), 0 );
1023 req->pid = (void *)id;
1024 req->access = access;
1025 req->inherit = inherit;
1026 if (!server_call( REQ_OPEN_PROCESS )) ret = req->handle;
1028 SERVER_END_REQ;
1029 return ret;
1032 /*********************************************************************
1033 * MapProcessHandle (KERNEL.483)
1035 DWORD WINAPI MapProcessHandle( HANDLE handle )
1037 DWORD ret = 0;
1038 SERVER_START_REQ
1040 struct get_process_info_request *req = server_alloc_req( sizeof(*req), 0 );
1041 req->handle = handle;
1042 if (!server_call( REQ_GET_PROCESS_INFO )) ret = (DWORD)req->pid;
1044 SERVER_END_REQ;
1045 return ret;
1048 /***********************************************************************
1049 * SetPriorityClass (KERNEL32.503)
1051 BOOL WINAPI SetPriorityClass( HANDLE hprocess, DWORD priorityclass )
1053 BOOL ret;
1054 SERVER_START_REQ
1056 struct set_process_info_request *req = server_alloc_req( sizeof(*req), 0 );
1057 req->handle = hprocess;
1058 req->priority = priorityclass;
1059 req->mask = SET_PROCESS_INFO_PRIORITY;
1060 ret = !server_call( REQ_SET_PROCESS_INFO );
1062 SERVER_END_REQ;
1063 return ret;
1067 /***********************************************************************
1068 * GetPriorityClass (KERNEL32.250)
1070 DWORD WINAPI GetPriorityClass(HANDLE hprocess)
1072 DWORD ret = 0;
1073 SERVER_START_REQ
1075 struct get_process_info_request *req = server_alloc_req( sizeof(*req), 0 );
1076 req->handle = hprocess;
1077 if (!server_call( REQ_GET_PROCESS_INFO )) ret = req->priority;
1079 SERVER_END_REQ;
1080 return ret;
1084 /***********************************************************************
1085 * SetProcessAffinityMask (KERNEL32.662)
1087 BOOL WINAPI SetProcessAffinityMask( HANDLE hProcess, DWORD affmask )
1089 BOOL ret;
1090 SERVER_START_REQ
1092 struct set_process_info_request *req = server_alloc_req( sizeof(*req), 0 );
1093 req->handle = hProcess;
1094 req->affinity = affmask;
1095 req->mask = SET_PROCESS_INFO_AFFINITY;
1096 ret = !server_call( REQ_SET_PROCESS_INFO );
1098 SERVER_END_REQ;
1099 return ret;
1102 /**********************************************************************
1103 * GetProcessAffinityMask (KERNEL32.373)
1105 BOOL WINAPI GetProcessAffinityMask( HANDLE hProcess,
1106 LPDWORD lpProcessAffinityMask,
1107 LPDWORD lpSystemAffinityMask )
1109 BOOL ret = FALSE;
1110 SERVER_START_REQ
1112 struct get_process_info_request *req = server_alloc_req( sizeof(*req), 0 );
1113 req->handle = hProcess;
1114 if (!server_call( REQ_GET_PROCESS_INFO ))
1116 if (lpProcessAffinityMask) *lpProcessAffinityMask = req->process_affinity;
1117 if (lpSystemAffinityMask) *lpSystemAffinityMask = req->system_affinity;
1118 ret = TRUE;
1121 SERVER_END_REQ;
1122 return ret;
1126 /***********************************************************************
1127 * GetProcessVersion (KERNEL32)
1129 DWORD WINAPI GetProcessVersion( DWORD processid )
1131 IMAGE_NT_HEADERS *nt;
1133 if (processid && processid != GetCurrentProcessId())
1134 return 0; /* FIXME: should use ReadProcessMemory */
1135 if ((nt = RtlImageNtHeader( current_process.module )))
1136 return ((nt->OptionalHeader.MajorSubsystemVersion << 16) |
1137 nt->OptionalHeader.MinorSubsystemVersion);
1138 return 0;
1141 /***********************************************************************
1142 * GetProcessFlags (KERNEL32)
1144 DWORD WINAPI GetProcessFlags( DWORD processid )
1146 if (processid && processid != GetCurrentProcessId()) return 0;
1147 return current_process.flags;
1151 /***********************************************************************
1152 * SetProcessWorkingSetSize [KERNEL32.662]
1153 * Sets the min/max working set sizes for a specified process.
1155 * PARAMS
1156 * hProcess [I] Handle to the process of interest
1157 * minset [I] Specifies minimum working set size
1158 * maxset [I] Specifies maximum working set size
1160 * RETURNS STD
1162 BOOL WINAPI SetProcessWorkingSetSize(HANDLE hProcess,DWORD minset,
1163 DWORD maxset)
1165 FIXME("(0x%08x,%ld,%ld): stub - harmless\n",hProcess,minset,maxset);
1166 if(( minset == -1) && (maxset == -1)) {
1167 /* Trim the working set to zero */
1168 /* Swap the process out of physical RAM */
1170 return TRUE;
1173 /***********************************************************************
1174 * GetProcessWorkingSetSize (KERNEL32)
1176 BOOL WINAPI GetProcessWorkingSetSize(HANDLE hProcess,LPDWORD minset,
1177 LPDWORD maxset)
1179 FIXME("(0x%08x,%p,%p): stub\n",hProcess,minset,maxset);
1180 /* 32 MB working set size */
1181 if (minset) *minset = 32*1024*1024;
1182 if (maxset) *maxset = 32*1024*1024;
1183 return TRUE;
1186 /***********************************************************************
1187 * SetProcessShutdownParameters (KERNEL32)
1189 * CHANGED - James Sutherland (JamesSutherland@gmx.de)
1190 * Now tracks changes made (but does not act on these changes)
1192 static DWORD shutdown_flags = 0;
1193 static DWORD shutdown_priority = 0x280;
1195 BOOL WINAPI SetProcessShutdownParameters(DWORD level, DWORD flags)
1197 FIXME("(%08lx, %08lx): partial stub.\n", level, flags);
1198 shutdown_flags = flags;
1199 shutdown_priority = level;
1200 return TRUE;
1204 /***********************************************************************
1205 * GetProcessShutdownParameters (KERNEL32)
1208 BOOL WINAPI GetProcessShutdownParameters( LPDWORD lpdwLevel, LPDWORD lpdwFlags )
1210 *lpdwLevel = shutdown_priority;
1211 *lpdwFlags = shutdown_flags;
1212 return TRUE;
1216 /***********************************************************************
1217 * SetProcessPriorityBoost (KERNEL32)
1219 BOOL WINAPI SetProcessPriorityBoost(HANDLE hprocess,BOOL disableboost)
1221 FIXME("(%d,%d): stub\n",hprocess,disableboost);
1222 /* Say we can do it. I doubt the program will notice that we don't. */
1223 return TRUE;
1227 /***********************************************************************
1228 * ReadProcessMemory (KERNEL32)
1230 BOOL WINAPI ReadProcessMemory( HANDLE process, LPCVOID addr, LPVOID buffer, DWORD size,
1231 LPDWORD bytes_read )
1233 unsigned int offset = (unsigned int)addr % sizeof(int);
1234 unsigned int pos = 0, len, max;
1235 int res;
1237 if (bytes_read) *bytes_read = size;
1239 /* first time, read total length to check for permissions */
1240 len = (size + offset + sizeof(int) - 1) / sizeof(int);
1241 max = min( REQUEST_MAX_VAR_SIZE, len * sizeof(int) );
1243 for (;;)
1245 SERVER_START_REQ
1247 struct read_process_memory_request *req = server_alloc_req( sizeof(*req), max );
1248 req->handle = process;
1249 req->addr = (char *)addr + pos - offset;
1250 req->len = len;
1251 if (!(res = server_call( REQ_READ_PROCESS_MEMORY )))
1253 size_t result = server_data_size( req );
1254 if (result > size + offset) result = size + offset;
1255 memcpy( (char *)buffer + pos, server_data_ptr(req) + offset, result - offset );
1256 size -= result - offset;
1257 pos += result - offset;
1260 SERVER_END_REQ;
1261 if (res)
1263 if (bytes_read) *bytes_read = 0;
1264 return FALSE;
1266 if (!size) return TRUE;
1267 max = min( REQUEST_MAX_VAR_SIZE, size );
1268 len = (max + sizeof(int) - 1) / sizeof(int);
1269 offset = 0;
1274 /***********************************************************************
1275 * WriteProcessMemory (KERNEL32)
1277 BOOL WINAPI WriteProcessMemory( HANDLE process, LPVOID addr, LPVOID buffer, DWORD size,
1278 LPDWORD bytes_written )
1280 unsigned int first_offset, last_offset;
1281 unsigned int pos = 0, len, max, first_mask, last_mask;
1282 int res;
1284 if (!size)
1286 SetLastError( ERROR_INVALID_PARAMETER );
1287 return FALSE;
1289 if (bytes_written) *bytes_written = size;
1291 /* compute the mask for the first int */
1292 first_mask = ~0;
1293 first_offset = (unsigned int)addr % sizeof(int);
1294 memset( &first_mask, 0, first_offset );
1296 /* compute the mask for the last int */
1297 last_offset = (size + first_offset) % sizeof(int);
1298 last_mask = 0;
1299 memset( &last_mask, 0xff, last_offset ? last_offset : sizeof(int) );
1301 /* for the first request, use the total length */
1302 len = (size + first_offset + sizeof(int) - 1) / sizeof(int);
1303 max = min( REQUEST_MAX_VAR_SIZE, len * sizeof(int) );
1305 for (;;)
1307 SERVER_START_REQ
1309 struct write_process_memory_request *req = server_alloc_req( sizeof(*req), max );
1310 req->handle = process;
1311 req->addr = (char *)addr - first_offset + pos;
1312 req->len = len;
1313 req->first_mask = (!pos) ? first_mask : ~0;
1314 if (size + first_offset <= max) /* last round */
1316 req->last_mask = last_mask;
1317 max = size + first_offset;
1319 else req->last_mask = ~0;
1321 memcpy( (char *)server_data_ptr(req) + first_offset, (char *)buffer + pos,
1322 max - first_offset );
1323 if (!(res = server_call( REQ_WRITE_PROCESS_MEMORY )))
1325 pos += max - first_offset;
1326 size -= max - first_offset;
1329 SERVER_END_REQ;
1330 if (res)
1332 if (bytes_written) *bytes_written = 0;
1333 return FALSE;
1335 if (!size) return TRUE;
1336 first_offset = 0;
1337 len = min( size + sizeof(int) - 1, REQUEST_MAX_VAR_SIZE ) / sizeof(int);
1338 max = len * sizeof(int);
1343 /***********************************************************************
1344 * RegisterServiceProcess (KERNEL, KERNEL32)
1346 * A service process calls this function to ensure that it continues to run
1347 * even after a user logged off.
1349 DWORD WINAPI RegisterServiceProcess(DWORD dwProcessId, DWORD dwType)
1351 /* I don't think that Wine needs to do anything in that function */
1352 return 1; /* success */
1355 /***********************************************************************
1356 * GetExitCodeProcess [KERNEL32.325]
1358 * Gets termination status of specified process
1360 * RETURNS
1361 * Success: TRUE
1362 * Failure: FALSE
1364 BOOL WINAPI GetExitCodeProcess(
1365 HANDLE hProcess, /* [I] handle to the process */
1366 LPDWORD lpExitCode) /* [O] address to receive termination status */
1368 BOOL ret;
1369 SERVER_START_REQ
1371 struct get_process_info_request *req = server_alloc_req( sizeof(*req), 0 );
1372 req->handle = hProcess;
1373 ret = !server_call( REQ_GET_PROCESS_INFO );
1374 if (ret && lpExitCode) *lpExitCode = req->exit_code;
1376 SERVER_END_REQ;
1377 return ret;
1381 /***********************************************************************
1382 * SetErrorMode (KERNEL32.486)
1384 UINT WINAPI SetErrorMode( UINT mode )
1386 UINT old = current_process.error_mode;
1387 current_process.error_mode = mode;
1388 return old;
1391 /***********************************************************************
1392 * GetCurrentProcess (KERNEL32.198)
1394 #undef GetCurrentProcess
1395 HANDLE WINAPI GetCurrentProcess(void)
1397 return 0xffffffff;