Use the standard CreateThread routine to create 16-bit tasks instead
[wine/multimedia.git] / scheduler / process.c
blob482cedb0d6da0e724a8749da8ca6b936fb07ced5
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 "wine/library.h"
18 #include "drive.h"
19 #include "module.h"
20 #include "file.h"
21 #include "thread.h"
22 #include "winerror.h"
23 #include "server.h"
24 #include "options.h"
25 #include "callback.h"
26 #include "debugtools.h"
28 DEFAULT_DEBUG_CHANNEL(process);
29 DECLARE_DEBUG_CHANNEL(relay);
30 DECLARE_DEBUG_CHANNEL(win32);
32 struct _ENVDB;
34 /* Win32 process database */
35 typedef struct _PDB
37 LONG header[2]; /* 00 Kernel object header */
38 HMODULE module; /* 08 Main exe module (NT) */
39 void *event; /* 0c Pointer to an event object (unused) */
40 DWORD exit_code; /* 10 Process exit code */
41 DWORD unknown2; /* 14 Unknown */
42 HANDLE heap; /* 18 Default process heap */
43 HANDLE mem_context; /* 1c Process memory context */
44 DWORD flags; /* 20 Flags */
45 void *pdb16; /* 24 DOS PSP */
46 WORD PSP_sel; /* 28 Selector to DOS PSP */
47 WORD imte; /* 2a IMTE for the process module */
48 WORD threads; /* 2c Number of threads */
49 WORD running_threads; /* 2e Number of running threads */
50 WORD free_lib_count; /* 30 Recursion depth of FreeLibrary calls */
51 WORD ring0_threads; /* 32 Number of ring 0 threads */
52 HANDLE system_heap; /* 34 System heap to allocate handles */
53 HTASK task; /* 38 Win16 task */
54 void *mem_map_files; /* 3c Pointer to mem-mapped files */
55 struct _ENVDB *env_db; /* 40 Environment database */
56 void *handle_table; /* 44 Handle table */
57 struct _PDB *parent; /* 48 Parent process */
58 void *modref_list; /* 4c MODREF list */
59 void *thread_list; /* 50 List of threads */
60 void *debuggee_CB; /* 54 Debuggee context block */
61 void *local_heap_free; /* 58 Head of local heap free list */
62 DWORD unknown4; /* 5c Unknown */
63 CRITICAL_SECTION crit_section; /* 60 Critical section */
64 DWORD unknown5[3]; /* 78 Unknown */
65 void *console; /* 84 Console */
66 DWORD tls_bits[2]; /* 88 TLS in-use bits */
67 DWORD process_dword; /* 90 Unknown */
68 struct _PDB *group; /* 94 Process group */
69 void *exe_modref; /* 98 MODREF for the process EXE */
70 void *top_filter; /* 9c Top exception filter */
71 DWORD priority; /* a0 Priority level */
72 HANDLE heap_list; /* a4 Head of process heap list */
73 void *heap_handles; /* a8 Head of heap handles list */
74 DWORD unknown6; /* ac Unknown */
75 void *console_provider; /* b0 Console provider (??) */
76 WORD env_selector; /* b4 Selector to process environment */
77 WORD error_mode; /* b6 Error mode */
78 HANDLE load_done_evt; /* b8 Event for process loading done */
79 void *UTState; /* bc Head of Univeral Thunk list */
80 DWORD unknown8; /* c0 Unknown (NT) */
81 LCID locale; /* c4 Locale to be queried by GetThreadLocale (NT) */
82 } PDB;
84 PDB current_process;
86 /* Process flags */
87 #define PDB32_DEBUGGED 0x0001 /* Process is being debugged */
88 #define PDB32_WIN16_PROC 0x0008 /* Win16 process */
89 #define PDB32_DOS_PROC 0x0010 /* Dos process */
90 #define PDB32_CONSOLE_PROC 0x0020 /* Console process */
91 #define PDB32_FILE_APIS_OEM 0x0040 /* File APIs are OEM */
92 #define PDB32_WIN32S_PROC 0x8000 /* Win32s process */
94 static char **main_exe_argv;
95 static char main_exe_name[MAX_PATH];
96 static HANDLE main_exe_file;
98 unsigned int server_startticks;
100 /* memory/environ.c */
101 extern struct _ENVDB *ENV_BuildEnvironment(void);
102 extern BOOL ENV_BuildCommandLine( char **argv );
103 extern STARTUPINFOA current_startupinfo;
105 /* scheduler/pthread.c */
106 extern void PTHREAD_init_done(void);
108 extern BOOL MAIN_MainInit(void);
111 /***********************************************************************
112 * PROCESS_CallUserSignalProc
114 * FIXME: Some of the signals aren't sent correctly!
116 * The exact meaning of the USER signals is undocumented, but this
117 * should cover the basic idea:
119 * USIG_DLL_UNLOAD_WIN16
120 * This is sent when a 16-bit module is unloaded.
122 * USIG_DLL_UNLOAD_WIN32
123 * This is sent when a 32-bit module is unloaded.
125 * USIG_DLL_UNLOAD_ORPHANS
126 * This is sent after the last Win3.1 module is unloaded,
127 * to allow removal of orphaned menus.
129 * USIG_FAULT_DIALOG_PUSH
130 * USIG_FAULT_DIALOG_POP
131 * These are called to allow USER to prepare for displaying a
132 * fault dialog, even though the fault might have happened while
133 * inside a USER critical section.
135 * USIG_THREAD_INIT
136 * This is called from the context of a new thread, as soon as it
137 * has started to run.
139 * USIG_THREAD_EXIT
140 * This is called, still in its context, just before a thread is
141 * about to terminate.
143 * USIG_PROCESS_CREATE
144 * This is called, in the parent process context, after a new process
145 * has been created.
147 * USIG_PROCESS_INIT
148 * This is called in the new process context, just after the main thread
149 * has started execution (after the main thread's USIG_THREAD_INIT has
150 * been sent).
152 * USIG_PROCESS_LOADED
153 * This is called after the executable file has been loaded into the
154 * new process context.
156 * USIG_PROCESS_RUNNING
157 * This is called immediately before the main entry point is called.
159 * USIG_PROCESS_EXIT
160 * This is called in the context of a process that is about to
161 * terminate (but before the last thread's USIG_THREAD_EXIT has
162 * been sent).
164 * USIG_PROCESS_DESTROY
165 * This is called after a process has terminated.
168 * The meaning of the dwFlags bits is as follows:
170 * USIG_FLAGS_WIN32
171 * Current process is 32-bit.
173 * USIG_FLAGS_GUI
174 * Current process is a (Win32) GUI process.
176 * USIG_FLAGS_FEEDBACK
177 * Current process needs 'feedback' (determined from the STARTUPINFO
178 * flags STARTF_FORCEONFEEDBACK / STARTF_FORCEOFFFEEDBACK).
180 * USIG_FLAGS_FAULT
181 * The signal is being sent due to a fault.
183 void PROCESS_CallUserSignalProc( UINT uCode, HMODULE hModule )
185 DWORD flags = current_process.flags;
186 DWORD startup_flags = current_startupinfo.dwFlags;
187 DWORD dwFlags = 0;
189 /* Determine dwFlags */
191 if ( !(flags & PDB32_WIN16_PROC) ) dwFlags |= USIG_FLAGS_WIN32;
193 if ( !(flags & PDB32_CONSOLE_PROC) ) dwFlags |= USIG_FLAGS_GUI;
195 if ( dwFlags & USIG_FLAGS_GUI )
197 /* Feedback defaults to ON */
198 if ( !(startup_flags & STARTF_FORCEOFFFEEDBACK) )
199 dwFlags |= USIG_FLAGS_FEEDBACK;
201 else
203 /* Feedback defaults to OFF */
204 if (startup_flags & STARTF_FORCEONFEEDBACK)
205 dwFlags |= USIG_FLAGS_FEEDBACK;
208 /* Convert module handle to 16-bit */
210 if ( HIWORD( hModule ) )
211 hModule = MapHModuleLS( hModule );
213 /* Call USER signal proc */
215 if ( Callout.UserSignalProc )
217 if ( uCode == USIG_THREAD_INIT || uCode == USIG_THREAD_EXIT )
218 Callout.UserSignalProc( uCode, GetCurrentThreadId(), dwFlags, hModule );
219 else
220 Callout.UserSignalProc( uCode, GetCurrentProcessId(), dwFlags, hModule );
225 /***********************************************************************
226 * set_console_handles
228 * Set the console handles to use stdin/stdout.
230 static void set_console_handles( HANDLE console )
232 HANDLE in = FILE_DupUnixHandle( 0, GENERIC_READ );
233 HANDLE out = FILE_DupUnixHandle( 1, GENERIC_WRITE );
235 SERVER_START_REQ( set_console_fd )
237 req->handle = console;
238 req->handle_in = in;
239 req->handle_out = out;
240 req->pid = 0;
241 SERVER_CALL();
243 SERVER_END_REQ;
244 NtClose( in );
245 NtClose( out );
249 /***********************************************************************
250 * process_init
252 * Main process initialisation code
254 static BOOL process_init( char *argv[] )
256 BOOL ret;
257 int create_flags = 0;
259 /* store the program name */
260 argv0 = argv[0];
261 main_exe_argv = argv;
263 /* Fill the initial process structure */
264 current_process.exit_code = STILL_ACTIVE;
265 current_process.threads = 1;
266 current_process.running_threads = 1;
267 current_process.ring0_threads = 1;
268 current_process.group = &current_process;
269 current_process.priority = 8; /* Normal */
271 /* Setup the server connection */
272 NtCurrentTeb()->socket = CLIENT_InitServer();
273 if (CLIENT_InitThread()) return FALSE;
275 /* Retrieve startup info from the server */
276 SERVER_START_VAR_REQ( init_process, sizeof(main_exe_name)-1 )
278 req->ldt_copy = &wine_ldt_copy;
279 req->ppid = getppid();
280 if ((ret = !SERVER_CALL_ERR()))
282 size_t len = server_data_size( req );
283 memcpy( main_exe_name, server_data_ptr(req), len );
284 main_exe_name[len] = 0;
285 main_exe_file = req->exe_file;
286 create_flags = req->create_flags;
287 current_startupinfo.dwFlags = req->start_flags;
288 server_startticks = req->server_start;
289 current_startupinfo.wShowWindow = req->cmd_show;
290 current_startupinfo.hStdInput = req->hstdin;
291 current_startupinfo.hStdOutput = req->hstdout;
292 current_startupinfo.hStdError = req->hstderr;
295 SERVER_END_VAR_REQ;
296 if (!ret) return FALSE;
298 SetStdHandle( STD_INPUT_HANDLE, current_startupinfo.hStdInput );
299 SetStdHandle( STD_OUTPUT_HANDLE, current_startupinfo.hStdOutput );
300 SetStdHandle( STD_ERROR_HANDLE, current_startupinfo.hStdError );
301 if (create_flags & CREATE_NEW_CONSOLE)
302 set_console_handles( current_startupinfo.hStdOutput );
304 /* Create the process heap */
305 current_process.heap = HeapCreate( HEAP_GROWABLE, 0, 0 );
307 /* Now we can use the pthreads routines */
308 PTHREAD_init_done();
310 /* Copy the parent environment */
311 if (!(current_process.env_db = ENV_BuildEnvironment())) return FALSE;
313 /* Parse command line arguments */
314 OPTIONS_ParseOptions( argv );
316 return MAIN_MainInit();
320 /***********************************************************************
321 * start_process
323 * Startup routine of a new process. Runs on the new process stack.
325 static void start_process(void)
327 int debugged, console_app;
328 LPTHREAD_START_ROUTINE entry;
329 WINE_MODREF *wm;
331 /* build command line */
332 if (!ENV_BuildCommandLine( main_exe_argv )) goto error;
334 /* create 32-bit module for main exe */
335 if (!(current_process.module = BUILTIN32_LoadExeModule( current_process.module ))) goto error;
337 /* use original argv[0] as name for the main module */
338 if (!main_exe_name[0])
340 if (!GetLongPathNameA( full_argv0, main_exe_name, sizeof(main_exe_name) ))
341 lstrcpynA( main_exe_name, full_argv0, sizeof(main_exe_name) );
344 /* Retrieve entry point address */
345 entry = (LPTHREAD_START_ROUTINE)((char*)current_process.module +
346 PE_HEADER(current_process.module)->OptionalHeader.AddressOfEntryPoint);
347 console_app = (PE_HEADER(current_process.module)->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI);
348 if (console_app) current_process.flags |= PDB32_CONSOLE_PROC;
350 /* Signal the parent process to continue */
351 SERVER_START_REQ( init_process_done )
353 req->module = (void *)current_process.module;
354 req->entry = entry;
355 req->name = main_exe_name;
356 req->exe_file = main_exe_file;
357 req->gui = !console_app;
358 SERVER_CALL();
359 debugged = req->debugged;
361 SERVER_END_REQ;
363 /* Install signal handlers; this cannot be done before, since we cannot
364 * send exceptions to the debugger before the create process event that
365 * is sent by REQ_INIT_PROCESS_DONE */
366 if (!SIGNAL_Init()) goto error;
368 /* create the main modref and load dependencies */
369 if (!(wm = PE_CreateModule( current_process.module, main_exe_name, 0, 0, FALSE )))
370 goto error;
371 wm->refCount++;
373 RtlAcquirePebLock();
374 PE_InitTls();
375 MODULE_DllProcessAttach( NULL, (LPVOID)1 );
376 RtlReleasePebLock();
378 /* Get pointers to USER routines called by KERNEL */
379 THUNK_InitCallout();
381 /* Call FinalUserInit routine */
382 if (Callout.FinalUserInit16) Callout.FinalUserInit16();
384 /* Note: The USIG_PROCESS_CREATE signal is supposed to be sent in the
385 * context of the parent process. Actually, the USER signal proc
386 * doesn't really care about that, but it *does* require that the
387 * startup parameters are correctly set up, so that GetProcessDword
388 * works. Furthermore, before calling the USER signal proc the
389 * 16-bit stack must be set up, which it is only after TASK_Create
390 * in the case of a 16-bit process. Thus, we send the signal here.
392 PROCESS_CallUserSignalProc( USIG_PROCESS_CREATE, 0 );
393 PROCESS_CallUserSignalProc( USIG_THREAD_INIT, 0 );
394 PROCESS_CallUserSignalProc( USIG_PROCESS_INIT, 0 );
395 PROCESS_CallUserSignalProc( USIG_PROCESS_LOADED, 0 );
396 /* Call UserSignalProc ( USIG_PROCESS_RUNNING ... ) only for non-GUI win32 apps */
397 if (console_app) PROCESS_CallUserSignalProc( USIG_PROCESS_RUNNING, 0 );
399 TRACE_(relay)( "Starting Win32 process %s (entryproc=%p)\n", main_exe_name, entry );
400 if (debugged) DbgBreakPoint();
401 /* FIXME: should use _PEB as parameter for NT 3.5 programs !
402 * Dunno about other OSs */
403 SetLastError(0); /* clear error code */
404 ExitThread( entry(NULL) );
406 error:
407 ExitProcess( GetLastError() );
411 /***********************************************************************
412 * open_winelib_app
414 * Try to open the Winelib app .so file based on argv[0] or WINEPRELOAD.
416 void *open_winelib_app( char *argv[] )
418 void *ret = NULL;
419 char *tmp;
420 const char *name;
421 char errStr[100];
423 if ((name = getenv( "WINEPRELOAD" )))
425 if (!(ret = wine_dll_load_main_exe( name, 0, errStr, sizeof(errStr) )))
427 MESSAGE( "%s: could not load '%s' as specified in the WINEPRELOAD environment variable: %s\n",
428 argv[0], name, errStr );
429 ExitProcess(1);
432 else
434 const char *argv0 = main_exe_name;
435 if (!*argv0)
437 /* if argv[0] is "wine", don't try to load anything */
438 argv0 = argv[0];
439 if (!(name = strrchr( argv0, '/' ))) name = argv0;
440 else name++;
441 if (!strcmp( name, "wine" )) return NULL;
444 /* now try argv[0] with ".so" appended */
445 if ((tmp = HeapAlloc( GetProcessHeap(), 0, strlen(argv0) + 4 )))
447 strcpy( tmp, argv0 );
448 strcat( tmp, ".so" );
449 /* search in PATH only if there was no '/' in argv[0] */
450 ret = wine_dll_load_main_exe( tmp, (name == argv0), errStr, sizeof(errStr) );
451 if (!ret && !argv[1])
453 /* if no argv[1], this will be better than displaying usage */
454 MESSAGE( "%s: could not load library '%s' as Winelib application: %s\n",
455 argv[0], tmp, errStr );
456 ExitProcess(1);
458 HeapFree( GetProcessHeap(), 0, tmp );
461 return ret;
464 /***********************************************************************
465 * PROCESS_InitWine
467 * Wine initialisation: load and start the main exe file.
469 void PROCESS_InitWine( int argc, char *argv[], LPSTR win16_exe_name, HANDLE *win16_exe_file )
471 DWORD stack_size = 0;
473 /* Initialize everything */
474 if (!process_init( argv )) exit(1);
476 if (open_winelib_app( argv )) goto found; /* try to open argv[0] as a winelib app */
478 main_exe_argv = ++argv; /* remove argv[0] (wine itself) */
480 if (!main_exe_name[0])
482 if (!argv[0]) OPTIONS_Usage();
484 /* open the exe file */
485 if (!SearchPathA( NULL, argv[0], ".exe", sizeof(main_exe_name), main_exe_name, NULL ) &&
486 !SearchPathA( NULL, argv[0], NULL, sizeof(main_exe_name), main_exe_name, NULL ))
488 MESSAGE( "%s: cannot find '%s'\n", argv0, argv[0] );
489 goto error;
493 if (!main_exe_file)
495 if ((main_exe_file = CreateFileA( main_exe_name, GENERIC_READ, FILE_SHARE_READ,
496 NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
498 MESSAGE( "%s: cannot open '%s'\n", argv0, main_exe_name );
499 goto error;
503 /* first try Win32 format; this will fail if the file is not a PE binary */
504 if ((current_process.module = PE_LoadImage( main_exe_file, main_exe_name, 0 )))
506 if (PE_HEADER(current_process.module)->FileHeader.Characteristics & IMAGE_FILE_DLL)
507 ExitProcess( ERROR_BAD_EXE_FORMAT );
508 stack_size = PE_HEADER(current_process.module)->OptionalHeader.SizeOfStackReserve;
509 goto found;
512 /* it must be 16-bit or DOS format */
513 NtCurrentTeb()->tibflags &= ~TEBF_WIN32;
514 current_process.flags |= PDB32_WIN16_PROC;
515 strcpy( win16_exe_name, main_exe_name );
516 main_exe_name[0] = 0;
517 *win16_exe_file = main_exe_file;
518 main_exe_file = 0;
519 _EnterWin16Lock();
521 found:
522 /* allocate main thread stack */
523 if (!THREAD_InitStack( NtCurrentTeb(), stack_size )) goto error;
525 /* switch to the new stack */
526 SYSDEPS_SwitchToThreadStack( start_process );
528 error:
529 ExitProcess( GetLastError() );
533 /***********************************************************************
534 * PROCESS_InitWinelib
536 * Initialisation of a new Winelib process.
538 void PROCESS_InitWinelib( int argc, char *argv[] )
540 if (!process_init( argv )) exit(1);
542 /* allocate main thread stack */
543 if (!THREAD_InitStack( NtCurrentTeb(), 0 )) ExitProcess( GetLastError() );
545 /* switch to the new stack */
546 SYSDEPS_SwitchToThreadStack( start_process );
550 /***********************************************************************
551 * build_argv
553 * Build an argv array from a command-line.
554 * The command-line is modified to insert nulls.
555 * 'reserved' is the number of args to reserve before the first one.
557 static char **build_argv( char *cmdline, int reserved )
559 char **argv;
560 int count = reserved + 1;
561 char *p = cmdline;
563 /* if first word is quoted store it as a single arg */
564 if (*cmdline == '\"')
566 if ((p = strchr( cmdline + 1, '\"' )))
568 p++;
569 count++;
571 else p = cmdline;
573 while (*p)
575 while (*p && isspace(*p)) p++;
576 if (!*p) break;
577 count++;
578 while (*p && !isspace(*p)) p++;
581 if ((argv = malloc( count * sizeof(*argv) )))
583 char **argvptr = argv + reserved;
584 p = cmdline;
585 if (*cmdline == '\"')
587 if ((p = strchr( cmdline + 1, '\"' )))
589 *argvptr++ = cmdline + 1;
590 *p++ = 0;
592 else p = cmdline;
594 while (*p)
596 while (*p && isspace(*p)) *p++ = 0;
597 if (!*p) break;
598 *argvptr++ = p;
599 while (*p && !isspace(*p)) p++;
601 *argvptr = 0;
603 return argv;
607 /***********************************************************************
608 * build_envp
610 * Build the environment of a new child process.
612 static char **build_envp( const char *env, const char *extra_env )
614 const char *p;
615 char **envp;
616 int count = 0;
618 if (extra_env) for (p = extra_env; *p; count++) p += strlen(p) + 1;
619 for (p = env; *p; count++) p += strlen(p) + 1;
620 count += 3;
622 if ((envp = malloc( count * sizeof(*envp) )))
624 extern char **environ;
625 char **envptr = envp;
626 char **unixptr = environ;
627 /* first the extra strings */
628 if (extra_env) for (p = extra_env; *p; p += strlen(p) + 1) *envptr++ = (char *)p;
629 /* then put PATH, HOME and WINEPREFIX from the unix env */
630 for (unixptr = environ; unixptr && *unixptr; unixptr++)
631 if (!memcmp( *unixptr, "PATH=", 5 ) ||
632 !memcmp( *unixptr, "HOME=", 5 ) ||
633 !memcmp( *unixptr, "WINEPREFIX=", 11 )) *envptr++ = *unixptr;
634 /* now put the Windows environment strings */
635 for (p = env; *p; p += strlen(p) + 1)
637 if (memcmp( p, "PATH=", 5 ) &&
638 memcmp( p, "HOME=", 5 ) &&
639 memcmp( p, "WINEPRELOAD=", 12 ) &&
640 memcmp( p, "WINEPREFIX=", 11 )) *envptr++ = (char *)p;
642 *envptr = 0;
644 return envp;
648 /***********************************************************************
649 * exec_wine_binary
651 * Locate the Wine binary to exec for a new Win32 process.
653 static void exec_wine_binary( char **argv, char **envp )
655 const char *path, *pos, *ptr;
657 /* first, try for a WINELOADER environment variable */
658 argv[0] = getenv("WINELOADER");
659 if (argv[0])
660 execve( argv[0], argv, envp );
662 /* next, try bin directory */
663 argv[0] = BINDIR "/wine";
664 execve( argv[0], argv, envp );
666 /* now try the path of argv0 of the current binary */
667 if (!(argv[0] = malloc( strlen(full_argv0) + 6 ))) return;
668 if ((ptr = strrchr( full_argv0, '/' )))
670 memcpy( argv[0], full_argv0, ptr - full_argv0 );
671 strcpy( argv[0] + (ptr - full_argv0), "/wine" );
672 execve( argv[0], argv, envp );
674 free( argv[0] );
676 /* now search in the Unix path */
677 if ((path = getenv( "PATH" )))
679 if (!(argv[0] = malloc( strlen(path) + 6 ))) return;
680 pos = path;
681 for (;;)
683 while (*pos == ':') pos++;
684 if (!*pos) break;
685 if (!(ptr = strchr( pos, ':' ))) ptr = pos + strlen(pos);
686 memcpy( argv[0], pos, ptr - pos );
687 strcpy( argv[0] + (ptr - pos), "/wine" );
688 execve( argv[0], argv, envp );
689 pos = ptr;
692 free( argv[0] );
694 /* finally try the current directory */
695 argv[0] = "./wine";
696 execve( argv[0], argv, envp );
700 /***********************************************************************
701 * fork_and_exec
703 * Fork and exec a new Unix process, checking for errors.
705 static int fork_and_exec( const char *filename, char *cmdline,
706 const char *env, const char *newdir )
708 int fd[2];
709 int pid, err;
710 char *extra_env = NULL;
712 if (!env)
714 env = GetEnvironmentStringsA();
715 extra_env = DRIVE_BuildEnv();
718 if (pipe(fd) == -1)
720 FILE_SetDosError();
721 return -1;
723 fcntl( fd[1], F_SETFD, 1 ); /* set close on exec */
724 if (!(pid = fork())) /* child */
726 char **argv = build_argv( cmdline, filename ? 0 : 2 );
727 char **envp = build_envp( env, extra_env );
728 close( fd[0] );
730 if (newdir) chdir(newdir);
732 if (argv && envp)
734 if (!filename)
736 argv[1] = "--";
737 exec_wine_binary( argv, envp );
739 else execve( filename, argv, envp );
741 err = errno;
742 write( fd[1], &err, sizeof(err) );
743 _exit(1);
745 close( fd[1] );
746 if ((pid != -1) && (read( fd[0], &err, sizeof(err) ) > 0)) /* exec failed */
748 errno = err;
749 pid = -1;
751 if (pid == -1) FILE_SetDosError();
752 close( fd[0] );
753 if (extra_env) HeapFree( GetProcessHeap(), 0, extra_env );
754 return pid;
758 /***********************************************************************
759 * PROCESS_Create
761 * Create a new process. If hFile is a valid handle we have an exe
762 * file, and we exec a new copy of wine to load it; otherwise we
763 * simply exec the specified filename as a Unix process.
765 BOOL PROCESS_Create( HANDLE hFile, LPCSTR filename, LPSTR cmd_line, LPCSTR env,
766 LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES tsa,
767 BOOL inherit, DWORD flags, LPSTARTUPINFOA startup,
768 LPPROCESS_INFORMATION info, LPCSTR lpCurrentDirectory )
770 BOOL ret;
771 int pid;
772 const char *unixfilename = NULL;
773 const char *unixdir = NULL;
774 DOS_FULL_NAME full_dir, full_name;
775 HANDLE load_done_evt = 0;
776 HANDLE process_info;
778 info->hThread = info->hProcess = 0;
780 if (lpCurrentDirectory)
782 if (DOSFS_GetFullName( lpCurrentDirectory, TRUE, &full_dir ))
783 unixdir = full_dir.long_name;
785 else
787 char buf[MAX_PATH];
788 if (GetCurrentDirectoryA(sizeof(buf),buf))
790 if (DOSFS_GetFullName( buf, TRUE, &full_dir ))
791 unixdir = full_dir.long_name;
795 /* create the process on the server side */
797 SERVER_START_VAR_REQ( new_process, MAX_PATH )
799 req->inherit_all = inherit;
800 req->create_flags = flags;
801 req->start_flags = startup->dwFlags;
802 req->exe_file = hFile;
803 if (startup->dwFlags & STARTF_USESTDHANDLES)
805 req->hstdin = startup->hStdInput;
806 req->hstdout = startup->hStdOutput;
807 req->hstderr = startup->hStdError;
809 else
811 req->hstdin = GetStdHandle( STD_INPUT_HANDLE );
812 req->hstdout = GetStdHandle( STD_OUTPUT_HANDLE );
813 req->hstderr = GetStdHandle( STD_ERROR_HANDLE );
815 req->cmd_show = startup->wShowWindow;
817 if (!hFile) /* unix process */
819 unixfilename = filename;
820 if (DOSFS_GetFullName( filename, TRUE, &full_name ))
821 unixfilename = full_name.long_name;
822 lstrcpynA( server_data_ptr(req), unixfilename, MAX_PATH );
824 else /* new wine process */
826 if (!GetLongPathNameA( filename, server_data_ptr(req), MAX_PATH ))
827 lstrcpynA( server_data_ptr(req), filename, MAX_PATH );
829 ret = !SERVER_CALL_ERR();
830 process_info = req->info;
832 SERVER_END_VAR_REQ;
833 if (!ret) return FALSE;
835 /* fork and execute */
837 pid = fork_and_exec( unixfilename, cmd_line, env, unixdir );
839 /* wait for the new process info to be ready */
841 ret = FALSE;
842 if ((pid != -1) && (WaitForSingleObject( process_info, 2000 ) == STATUS_WAIT_0))
844 SERVER_START_REQ( get_new_process_info )
846 req->info = process_info;
847 req->pinherit = (psa && (psa->nLength >= sizeof(*psa)) && psa->bInheritHandle);
848 req->tinherit = (tsa && (tsa->nLength >= sizeof(*tsa)) && tsa->bInheritHandle);
849 if ((ret = !SERVER_CALL_ERR()))
851 info->dwProcessId = (DWORD)req->pid;
852 info->dwThreadId = (DWORD)req->tid;
853 info->hProcess = req->phandle;
854 info->hThread = req->thandle;
855 load_done_evt = req->event;
858 SERVER_END_REQ;
860 CloseHandle( process_info );
861 if (!ret) goto error;
863 /* Wait until process is initialized (or initialization failed) */
864 if (load_done_evt)
866 DWORD res;
867 HANDLE handles[2];
869 handles[0] = info->hProcess;
870 handles[1] = load_done_evt;
871 res = WaitForMultipleObjects( 2, handles, FALSE, INFINITE );
872 CloseHandle( load_done_evt );
873 if (res == STATUS_WAIT_0) /* the process died */
875 DWORD exitcode;
876 if (GetExitCodeProcess( info->hProcess, &exitcode )) SetLastError( exitcode );
877 CloseHandle( info->hThread );
878 CloseHandle( info->hProcess );
879 return FALSE;
882 return TRUE;
884 error:
885 if (load_done_evt) CloseHandle( load_done_evt );
886 if (info->hThread) CloseHandle( info->hThread );
887 if (info->hProcess) CloseHandle( info->hProcess );
888 return FALSE;
892 /***********************************************************************
893 * ExitProcess (KERNEL32.@)
895 void WINAPI ExitProcess( DWORD status )
897 MODULE_DllProcessDetach( TRUE, (LPVOID)1 );
898 SERVER_START_REQ( terminate_process )
900 /* send the exit code to the server */
901 req->handle = GetCurrentProcess();
902 req->exit_code = status;
903 SERVER_CALL();
905 SERVER_END_REQ;
906 exit( status );
909 /***********************************************************************
910 * ExitProcess16 (KERNEL.466)
912 void WINAPI ExitProcess16( WORD status )
914 DWORD count;
915 ReleaseThunkLock( &count );
916 ExitProcess( status );
919 /******************************************************************************
920 * TerminateProcess (KERNEL32.684)
922 BOOL WINAPI TerminateProcess( HANDLE handle, DWORD exit_code )
924 NTSTATUS status = NtTerminateProcess( handle, exit_code );
925 if (status) SetLastError( RtlNtStatusToDosError(status) );
926 return !status;
930 /***********************************************************************
931 * GetProcessDword (KERNEL32.18) (KERNEL.485)
932 * 'Of course you cannot directly access Windows internal structures'
934 DWORD WINAPI GetProcessDword( DWORD dwProcessID, INT offset )
936 DWORD x, y;
938 TRACE_(win32)("(%ld, %d)\n", dwProcessID, offset );
940 if (dwProcessID && dwProcessID != GetCurrentProcessId())
942 ERR("%d: process %lx not accessible\n", offset, dwProcessID);
943 return 0;
946 switch ( offset )
948 case GPD_APP_COMPAT_FLAGS:
949 return GetAppCompatFlags16(0);
951 case GPD_LOAD_DONE_EVENT:
952 return current_process.load_done_evt;
954 case GPD_HINSTANCE16:
955 return GetTaskDS16();
957 case GPD_WINDOWS_VERSION:
958 return GetExeVersion16();
960 case GPD_THDB:
961 return (DWORD)NtCurrentTeb() - 0x10 /* FIXME */;
963 case GPD_PDB:
964 return (DWORD)&current_process;
966 case GPD_STARTF_SHELLDATA: /* return stdoutput handle from startupinfo ??? */
967 return current_startupinfo.hStdOutput;
969 case GPD_STARTF_HOTKEY: /* return stdinput handle from startupinfo ??? */
970 return current_startupinfo.hStdInput;
972 case GPD_STARTF_SHOWWINDOW:
973 return current_startupinfo.wShowWindow;
975 case GPD_STARTF_SIZE:
976 x = current_startupinfo.dwXSize;
977 if ( (INT)x == CW_USEDEFAULT ) x = CW_USEDEFAULT16;
978 y = current_startupinfo.dwYSize;
979 if ( (INT)y == CW_USEDEFAULT ) y = CW_USEDEFAULT16;
980 return MAKELONG( x, y );
982 case GPD_STARTF_POSITION:
983 x = current_startupinfo.dwX;
984 if ( (INT)x == CW_USEDEFAULT ) x = CW_USEDEFAULT16;
985 y = current_startupinfo.dwY;
986 if ( (INT)y == CW_USEDEFAULT ) y = CW_USEDEFAULT16;
987 return MAKELONG( x, y );
989 case GPD_STARTF_FLAGS:
990 return current_startupinfo.dwFlags;
992 case GPD_PARENT:
993 return 0;
995 case GPD_FLAGS:
996 return current_process.flags;
998 case GPD_USERDATA:
999 return current_process.process_dword;
1001 default:
1002 ERR_(win32)("Unknown offset %d\n", offset );
1003 return 0;
1007 /***********************************************************************
1008 * SetProcessDword (KERNEL.484)
1009 * 'Of course you cannot directly access Windows internal structures'
1011 void WINAPI SetProcessDword( DWORD dwProcessID, INT offset, DWORD value )
1013 TRACE_(win32)("(%ld, %d)\n", dwProcessID, offset );
1015 if (dwProcessID && dwProcessID != GetCurrentProcessId())
1017 ERR("%d: process %lx not accessible\n", offset, dwProcessID);
1018 return;
1021 switch ( offset )
1023 case GPD_APP_COMPAT_FLAGS:
1024 case GPD_LOAD_DONE_EVENT:
1025 case GPD_HINSTANCE16:
1026 case GPD_WINDOWS_VERSION:
1027 case GPD_THDB:
1028 case GPD_PDB:
1029 case GPD_STARTF_SHELLDATA:
1030 case GPD_STARTF_HOTKEY:
1031 case GPD_STARTF_SHOWWINDOW:
1032 case GPD_STARTF_SIZE:
1033 case GPD_STARTF_POSITION:
1034 case GPD_STARTF_FLAGS:
1035 case GPD_PARENT:
1036 case GPD_FLAGS:
1037 ERR_(win32)("Not allowed to modify offset %d\n", offset );
1038 break;
1040 case GPD_USERDATA:
1041 current_process.process_dword = value;
1042 break;
1044 default:
1045 ERR_(win32)("Unknown offset %d\n", offset );
1046 break;
1051 /*********************************************************************
1052 * OpenProcess (KERNEL32.543)
1054 HANDLE WINAPI OpenProcess( DWORD access, BOOL inherit, DWORD id )
1056 HANDLE ret = 0;
1057 SERVER_START_REQ( open_process )
1059 req->pid = (void *)id;
1060 req->access = access;
1061 req->inherit = inherit;
1062 if (!SERVER_CALL_ERR()) ret = req->handle;
1064 SERVER_END_REQ;
1065 return ret;
1068 /*********************************************************************
1069 * MapProcessHandle (KERNEL.483)
1071 DWORD WINAPI MapProcessHandle( HANDLE handle )
1073 DWORD ret = 0;
1074 SERVER_START_REQ( get_process_info )
1076 req->handle = handle;
1077 if (!SERVER_CALL_ERR()) ret = (DWORD)req->pid;
1079 SERVER_END_REQ;
1080 return ret;
1083 /***********************************************************************
1084 * SetPriorityClass (KERNEL32.@)
1086 BOOL WINAPI SetPriorityClass( HANDLE hprocess, DWORD priorityclass )
1088 BOOL ret;
1089 SERVER_START_REQ( set_process_info )
1091 req->handle = hprocess;
1092 req->priority = priorityclass;
1093 req->mask = SET_PROCESS_INFO_PRIORITY;
1094 ret = !SERVER_CALL_ERR();
1096 SERVER_END_REQ;
1097 return ret;
1101 /***********************************************************************
1102 * GetPriorityClass (KERNEL32.@)
1104 DWORD WINAPI GetPriorityClass(HANDLE hprocess)
1106 DWORD ret = 0;
1107 SERVER_START_REQ( get_process_info )
1109 req->handle = hprocess;
1110 if (!SERVER_CALL_ERR()) ret = req->priority;
1112 SERVER_END_REQ;
1113 return ret;
1117 /***********************************************************************
1118 * SetProcessAffinityMask (KERNEL32.@)
1120 BOOL WINAPI SetProcessAffinityMask( HANDLE hProcess, DWORD affmask )
1122 BOOL ret;
1123 SERVER_START_REQ( set_process_info )
1125 req->handle = hProcess;
1126 req->affinity = affmask;
1127 req->mask = SET_PROCESS_INFO_AFFINITY;
1128 ret = !SERVER_CALL_ERR();
1130 SERVER_END_REQ;
1131 return ret;
1134 /**********************************************************************
1135 * GetProcessAffinityMask (KERNEL32.373)
1137 BOOL WINAPI GetProcessAffinityMask( HANDLE hProcess,
1138 LPDWORD lpProcessAffinityMask,
1139 LPDWORD lpSystemAffinityMask )
1141 BOOL ret = FALSE;
1142 SERVER_START_REQ( get_process_info )
1144 req->handle = hProcess;
1145 if (!SERVER_CALL_ERR())
1147 if (lpProcessAffinityMask) *lpProcessAffinityMask = req->process_affinity;
1148 if (lpSystemAffinityMask) *lpSystemAffinityMask = req->system_affinity;
1149 ret = TRUE;
1152 SERVER_END_REQ;
1153 return ret;
1157 /***********************************************************************
1158 * GetProcessVersion (KERNEL32.@)
1160 DWORD WINAPI GetProcessVersion( DWORD processid )
1162 IMAGE_NT_HEADERS *nt;
1164 if (processid && processid != GetCurrentProcessId())
1166 FIXME("should use ReadProcessMemory\n");
1167 return 0;
1169 if ((nt = RtlImageNtHeader( current_process.module )))
1170 return ((nt->OptionalHeader.MajorSubsystemVersion << 16) |
1171 nt->OptionalHeader.MinorSubsystemVersion);
1172 return 0;
1175 /***********************************************************************
1176 * GetProcessFlags (KERNEL32.@)
1178 DWORD WINAPI GetProcessFlags( DWORD processid )
1180 if (processid && processid != GetCurrentProcessId()) return 0;
1181 return current_process.flags;
1185 /***********************************************************************
1186 * SetProcessWorkingSetSize [KERNEL32.662]
1187 * Sets the min/max working set sizes for a specified process.
1189 * PARAMS
1190 * hProcess [I] Handle to the process of interest
1191 * minset [I] Specifies minimum working set size
1192 * maxset [I] Specifies maximum working set size
1194 * RETURNS STD
1196 BOOL WINAPI SetProcessWorkingSetSize(HANDLE hProcess,DWORD minset,
1197 DWORD maxset)
1199 FIXME("(0x%08x,%ld,%ld): stub - harmless\n",hProcess,minset,maxset);
1200 if(( minset == (DWORD)-1) && (maxset == (DWORD)-1)) {
1201 /* Trim the working set to zero */
1202 /* Swap the process out of physical RAM */
1204 return TRUE;
1207 /***********************************************************************
1208 * GetProcessWorkingSetSize (KERNEL32.@)
1210 BOOL WINAPI GetProcessWorkingSetSize(HANDLE hProcess,LPDWORD minset,
1211 LPDWORD maxset)
1213 FIXME("(0x%08x,%p,%p): stub\n",hProcess,minset,maxset);
1214 /* 32 MB working set size */
1215 if (minset) *minset = 32*1024*1024;
1216 if (maxset) *maxset = 32*1024*1024;
1217 return TRUE;
1220 /***********************************************************************
1221 * SetProcessShutdownParameters (KERNEL32.@)
1223 * CHANGED - James Sutherland (JamesSutherland@gmx.de)
1224 * Now tracks changes made (but does not act on these changes)
1226 static DWORD shutdown_flags = 0;
1227 static DWORD shutdown_priority = 0x280;
1229 BOOL WINAPI SetProcessShutdownParameters(DWORD level, DWORD flags)
1231 FIXME("(%08lx, %08lx): partial stub.\n", level, flags);
1232 shutdown_flags = flags;
1233 shutdown_priority = level;
1234 return TRUE;
1238 /***********************************************************************
1239 * GetProcessShutdownParameters (KERNEL32.@)
1242 BOOL WINAPI GetProcessShutdownParameters( LPDWORD lpdwLevel, LPDWORD lpdwFlags )
1244 *lpdwLevel = shutdown_priority;
1245 *lpdwFlags = shutdown_flags;
1246 return TRUE;
1250 /***********************************************************************
1251 * SetProcessPriorityBoost (KERNEL32.@)
1253 BOOL WINAPI SetProcessPriorityBoost(HANDLE hprocess,BOOL disableboost)
1255 FIXME("(%d,%d): stub\n",hprocess,disableboost);
1256 /* Say we can do it. I doubt the program will notice that we don't. */
1257 return TRUE;
1261 /***********************************************************************
1262 * ReadProcessMemory (KERNEL32.@)
1263 * ReadProcessMemory (WIN32S16.6)
1265 BOOL WINAPI ReadProcessMemory( HANDLE process, LPCVOID addr, LPVOID buffer, DWORD size,
1266 LPDWORD bytes_read )
1268 unsigned int offset = (unsigned int)addr % sizeof(int);
1269 unsigned int pos = 0, len, max;
1270 int res;
1272 if (bytes_read) *bytes_read = size;
1274 /* first time, read total length to check for permissions */
1275 len = (size + offset + sizeof(int) - 1) / sizeof(int);
1276 max = min( REQUEST_MAX_VAR_SIZE, len * sizeof(int) );
1278 for (;;)
1280 SERVER_START_VAR_REQ( read_process_memory, max )
1282 req->handle = process;
1283 req->addr = (char *)addr + pos - offset;
1284 req->len = len;
1285 if (!(res = SERVER_CALL_ERR()))
1287 size_t result = server_data_size( req );
1288 if (result > size + offset) result = size + offset;
1289 memcpy( (char *)buffer + pos, server_data_ptr(req) + offset, result - offset );
1290 size -= result - offset;
1291 pos += result - offset;
1294 SERVER_END_VAR_REQ;
1295 if (res)
1297 if (bytes_read) *bytes_read = 0;
1298 return FALSE;
1300 if (!size) return TRUE;
1301 max = min( REQUEST_MAX_VAR_SIZE, size );
1302 len = (max + sizeof(int) - 1) / sizeof(int);
1303 offset = 0;
1308 /***********************************************************************
1309 * WriteProcessMemory (KERNEL32.@)
1311 BOOL WINAPI WriteProcessMemory( HANDLE process, LPVOID addr, LPVOID buffer, DWORD size,
1312 LPDWORD bytes_written )
1314 unsigned int first_offset, last_offset;
1315 unsigned int pos = 0, len, max, first_mask, last_mask;
1316 int res;
1318 if (!size)
1320 SetLastError( ERROR_INVALID_PARAMETER );
1321 return FALSE;
1323 if (bytes_written) *bytes_written = size;
1325 /* compute the mask for the first int */
1326 first_mask = ~0;
1327 first_offset = (unsigned int)addr % sizeof(int);
1328 memset( &first_mask, 0, first_offset );
1330 /* compute the mask for the last int */
1331 last_offset = (size + first_offset) % sizeof(int);
1332 last_mask = 0;
1333 memset( &last_mask, 0xff, last_offset ? last_offset : sizeof(int) );
1335 /* for the first request, use the total length */
1336 len = (size + first_offset + sizeof(int) - 1) / sizeof(int);
1337 max = min( REQUEST_MAX_VAR_SIZE, len * sizeof(int) );
1339 for (;;)
1341 SERVER_START_VAR_REQ( write_process_memory, max )
1343 req->handle = process;
1344 req->addr = (char *)addr - first_offset + pos;
1345 req->len = len;
1346 req->first_mask = (!pos) ? first_mask : ~0;
1347 if (size + first_offset <= max) /* last round */
1349 req->last_mask = last_mask;
1350 max = size + first_offset;
1352 else req->last_mask = ~0;
1354 memcpy( (char *)server_data_ptr(req) + first_offset, (char *)buffer + pos,
1355 max - first_offset );
1356 if (!(res = SERVER_CALL_ERR()))
1358 pos += max - first_offset;
1359 size -= max - first_offset;
1362 SERVER_END_VAR_REQ;
1363 if (res)
1365 if (bytes_written) *bytes_written = 0;
1366 return FALSE;
1368 if (!size) return TRUE;
1369 first_offset = 0;
1370 len = min( size + sizeof(int) - 1, REQUEST_MAX_VAR_SIZE ) / sizeof(int);
1371 max = len * sizeof(int);
1376 /***********************************************************************
1377 * RegisterServiceProcess (KERNEL.491)
1378 * RegisterServiceProcess (KERNEL32.@)
1380 * A service process calls this function to ensure that it continues to run
1381 * even after a user logged off.
1383 DWORD WINAPI RegisterServiceProcess(DWORD dwProcessId, DWORD dwType)
1385 /* I don't think that Wine needs to do anything in that function */
1386 return 1; /* success */
1389 /***********************************************************************
1390 * GetExitCodeProcess [KERNEL32.325]
1392 * Gets termination status of specified process
1394 * RETURNS
1395 * Success: TRUE
1396 * Failure: FALSE
1398 BOOL WINAPI GetExitCodeProcess(
1399 HANDLE hProcess, /* [in] handle to the process */
1400 LPDWORD lpExitCode) /* [out] address to receive termination status */
1402 BOOL ret;
1403 SERVER_START_REQ( get_process_info )
1405 req->handle = hProcess;
1406 ret = !SERVER_CALL_ERR();
1407 if (ret && lpExitCode) *lpExitCode = req->exit_code;
1409 SERVER_END_REQ;
1410 return ret;
1414 /***********************************************************************
1415 * SetErrorMode (KERNEL32.@)
1417 UINT WINAPI SetErrorMode( UINT mode )
1419 UINT old = current_process.error_mode;
1420 current_process.error_mode = mode;
1421 return old;
1425 /**********************************************************************
1426 * TlsAlloc [KERNEL32.@] Allocates a TLS index.
1428 * Allocates a thread local storage index
1430 * RETURNS
1431 * Success: TLS Index
1432 * Failure: 0xFFFFFFFF
1434 DWORD WINAPI TlsAlloc( void )
1436 DWORD i, mask, ret = 0;
1437 DWORD *bits = current_process.tls_bits;
1438 RtlAcquirePebLock();
1439 if (*bits == 0xffffffff)
1441 bits++;
1442 ret = 32;
1443 if (*bits == 0xffffffff)
1445 RtlReleasePebLock();
1446 SetLastError( ERROR_NO_MORE_ITEMS );
1447 return 0xffffffff;
1450 for (i = 0, mask = 1; i < 32; i++, mask <<= 1) if (!(*bits & mask)) break;
1451 *bits |= mask;
1452 RtlReleasePebLock();
1453 return ret + i;
1457 /**********************************************************************
1458 * TlsFree [KERNEL32.@] Releases a TLS index.
1460 * Releases a thread local storage index, making it available for reuse
1462 * RETURNS
1463 * Success: TRUE
1464 * Failure: FALSE
1466 BOOL WINAPI TlsFree(
1467 DWORD index) /* [in] TLS Index to free */
1469 DWORD mask = (1 << (index & 31));
1470 DWORD *bits = current_process.tls_bits;
1471 if (index >= 64)
1473 SetLastError( ERROR_INVALID_PARAMETER );
1474 return FALSE;
1476 if (index >= 32) bits++;
1477 RtlAcquirePebLock();
1478 if (!(*bits & mask)) /* already free? */
1480 RtlReleasePebLock();
1481 SetLastError( ERROR_INVALID_PARAMETER );
1482 return FALSE;
1484 *bits &= ~mask;
1485 NtCurrentTeb()->tls_array[index] = 0;
1486 /* FIXME: should zero all other thread values */
1487 RtlReleasePebLock();
1488 return TRUE;
1492 /**********************************************************************
1493 * TlsGetValue [KERNEL32.@] Gets value in a thread's TLS slot
1495 * RETURNS
1496 * Success: Value stored in calling thread's TLS slot for index
1497 * Failure: 0 and GetLastError returns NO_ERROR
1499 LPVOID WINAPI TlsGetValue(
1500 DWORD index) /* [in] TLS index to retrieve value for */
1502 if (index >= 64)
1504 SetLastError( ERROR_INVALID_PARAMETER );
1505 return NULL;
1507 SetLastError( ERROR_SUCCESS );
1508 return NtCurrentTeb()->tls_array[index];
1512 /**********************************************************************
1513 * TlsSetValue [KERNEL32.@] Stores a value in the thread's TLS slot.
1515 * RETURNS
1516 * Success: TRUE
1517 * Failure: FALSE
1519 BOOL WINAPI TlsSetValue(
1520 DWORD index, /* [in] TLS index to set value for */
1521 LPVOID value) /* [in] Value to be stored */
1523 if (index >= 64)
1525 SetLastError( ERROR_INVALID_PARAMETER );
1526 return FALSE;
1528 NtCurrentTeb()->tls_array[index] = value;
1529 return TRUE;
1533 /***********************************************************************
1534 * GetCurrentProcess (KERNEL32.@)
1536 #undef GetCurrentProcess
1537 HANDLE WINAPI GetCurrentProcess(void)
1539 return 0xffffffff;