kernel32: Move MODULE_get_binary_info implementation to process.c.
[wine.git] / dlls / kernel32 / process.c
blobdb82a0625a86a6dd19f63da6526a8107229333c7
1 /*
2 * Win32 processes
4 * Copyright 1996, 1998 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "config.h"
22 #include "wine/port.h"
24 #include <assert.h>
25 #include <ctype.h>
26 #include <errno.h>
27 #include <signal.h>
28 #include <stdarg.h>
29 #include <stdio.h>
30 #include <time.h>
31 #ifdef HAVE_SYS_TIME_H
32 # include <sys/time.h>
33 #endif
34 #ifdef HAVE_SYS_IOCTL_H
35 #include <sys/ioctl.h>
36 #endif
37 #ifdef HAVE_SYS_SOCKET_H
38 #include <sys/socket.h>
39 #endif
40 #ifdef HAVE_SYS_PRCTL_H
41 # include <sys/prctl.h>
42 #endif
43 #include <sys/types.h>
44 #ifdef HAVE_SYS_WAIT_H
45 # include <sys/wait.h>
46 #endif
47 #ifdef HAVE_UNISTD_H
48 # include <unistd.h>
49 #endif
50 #ifdef __APPLE__
51 #include <CoreFoundation/CoreFoundation.h>
52 #include <pthread.h>
53 #endif
55 #include "ntstatus.h"
56 #define WIN32_NO_STATUS
57 #include "winternl.h"
58 #include "kernel_private.h"
59 #include "psapi.h"
60 #include "wine/exception.h"
61 #include "wine/library.h"
62 #include "wine/server.h"
63 #include "wine/unicode.h"
64 #include "wine/debug.h"
66 WINE_DEFAULT_DEBUG_CHANNEL(process);
67 WINE_DECLARE_DEBUG_CHANNEL(relay);
69 #ifdef __APPLE__
70 extern char **__wine_get_main_environment(void);
71 #else
72 extern char **__wine_main_environ;
73 static char **__wine_get_main_environment(void) { return __wine_main_environ; }
74 #endif
76 typedef struct
78 LPSTR lpEnvAddress;
79 LPSTR lpCmdLine;
80 LPSTR lpCmdShow;
81 DWORD dwReserved;
82 } LOADPARMS32;
84 static DWORD shutdown_flags = 0;
85 static DWORD shutdown_priority = 0x280;
86 static BOOL is_wow64;
87 static const BOOL is_win64 = (sizeof(void *) > sizeof(int));
89 HMODULE kernel32_handle = 0;
90 SYSTEM_BASIC_INFORMATION system_info = { 0 };
92 const WCHAR DIR_Windows[] = {'C',':','\\','w','i','n','d','o','w','s',0};
93 const WCHAR DIR_System[] = {'C',':','\\','w','i','n','d','o','w','s',
94 '\\','s','y','s','t','e','m','3','2',0};
95 const WCHAR *DIR_SysWow64 = NULL;
97 /* Process flags */
98 #define PDB32_DEBUGGED 0x0001 /* Process is being debugged */
99 #define PDB32_WIN16_PROC 0x0008 /* Win16 process */
100 #define PDB32_DOS_PROC 0x0010 /* Dos process */
101 #define PDB32_CONSOLE_PROC 0x0020 /* Console process */
102 #define PDB32_FILE_APIS_OEM 0x0040 /* File APIs are OEM */
103 #define PDB32_WIN32S_PROC 0x8000 /* Win32s process */
105 static const WCHAR exeW[] = {'.','e','x','e',0};
106 static const WCHAR comW[] = {'.','c','o','m',0};
107 static const WCHAR batW[] = {'.','b','a','t',0};
108 static const WCHAR cmdW[] = {'.','c','m','d',0};
109 static const WCHAR pifW[] = {'.','p','i','f',0};
110 static const WCHAR winevdmW[] = {'w','i','n','e','v','d','m','.','e','x','e',0};
112 static void exec_process( LPCWSTR name );
114 extern void SHELL_LoadRegistry(void);
116 /* return values for get_binary_info */
117 enum binary_type
119 BINARY_UNKNOWN = 0,
120 BINARY_PE,
121 BINARY_WIN16,
122 BINARY_UNIX_EXE,
123 BINARY_UNIX_LIB
126 #define BINARY_FLAG_DLL 0x01
127 #define BINARY_FLAG_64BIT 0x02
128 #define BINARY_FLAG_FAKEDLL 0x04
130 struct binary_info
132 enum binary_type type;
133 DWORD arch;
134 DWORD flags;
135 ULONGLONG res_start;
136 ULONGLONG res_end;
140 /***********************************************************************
141 * contains_path
143 static inline BOOL contains_path( LPCWSTR name )
145 return ((*name && (name[1] == ':')) || strchrW(name, '/') || strchrW(name, '\\'));
149 /***********************************************************************
150 * is_special_env_var
152 * Check if an environment variable needs to be handled specially when
153 * passed through the Unix environment (i.e. prefixed with "WINE").
155 static inline BOOL is_special_env_var( const char *var )
157 return (!strncmp( var, "PATH=", sizeof("PATH=")-1 ) ||
158 !strncmp( var, "PWD=", sizeof("PWD=")-1 ) ||
159 !strncmp( var, "HOME=", sizeof("HOME=")-1 ) ||
160 !strncmp( var, "TEMP=", sizeof("TEMP=")-1 ) ||
161 !strncmp( var, "TMP=", sizeof("TMP=")-1 ) ||
162 !strncmp( var, "QT_", sizeof("QT_")-1 ) ||
163 !strncmp( var, "VK_", sizeof("VK_")-1 ));
167 /***********************************************************************
168 * is_path_prefix
170 static inline unsigned int is_path_prefix( const WCHAR *prefix, const WCHAR *filename )
172 unsigned int len = strlenW( prefix );
174 if (strncmpiW( filename, prefix, len ) || filename[len] != '\\') return 0;
175 while (filename[len] == '\\') len++;
176 return len;
180 /***********************************************************************
181 * get_binary_info
183 static void get_binary_info( HANDLE hfile, struct binary_info *info )
185 union
187 struct
189 unsigned char magic[4];
190 unsigned char class;
191 unsigned char data;
192 unsigned char ignored1[10];
193 unsigned short type;
194 unsigned short machine;
195 unsigned char ignored2[8];
196 unsigned int phoff;
197 unsigned char ignored3[12];
198 unsigned short phnum;
199 } elf;
200 struct
202 unsigned char magic[4];
203 unsigned char class;
204 unsigned char data;
205 unsigned char ignored1[10];
206 unsigned short type;
207 unsigned short machine;
208 unsigned char ignored2[12];
209 unsigned __int64 phoff;
210 unsigned char ignored3[16];
211 unsigned short phnum;
212 } elf64;
213 struct
215 unsigned int magic;
216 unsigned int cputype;
217 unsigned int cpusubtype;
218 unsigned int filetype;
219 } macho;
220 IMAGE_DOS_HEADER mz;
221 } header;
223 DWORD len;
225 memset( info, 0, sizeof(*info) );
227 /* Seek to the start of the file and read the header information. */
228 if (SetFilePointer( hfile, 0, NULL, SEEK_SET ) == -1) return;
229 if (!ReadFile( hfile, &header, sizeof(header), &len, NULL ) || len != sizeof(header)) return;
231 if (!memcmp( header.elf.magic, "\177ELF", 4 ))
233 #ifdef WORDS_BIGENDIAN
234 BOOL byteswap = (header.elf.data == 1);
235 #else
236 BOOL byteswap = (header.elf.data == 2);
237 #endif
238 if (header.elf.class == 2) info->flags |= BINARY_FLAG_64BIT;
239 if (byteswap)
241 header.elf.type = RtlUshortByteSwap( header.elf.type );
242 header.elf.machine = RtlUshortByteSwap( header.elf.machine );
244 switch(header.elf.type)
246 case 2:
247 info->type = BINARY_UNIX_EXE;
248 break;
249 case 3:
251 LARGE_INTEGER phoff;
252 unsigned short phnum;
253 unsigned int type;
254 if (header.elf.class == 2)
256 phoff.QuadPart = byteswap ? RtlUlonglongByteSwap( header.elf64.phoff ) : header.elf64.phoff;
257 phnum = byteswap ? RtlUshortByteSwap( header.elf64.phnum ) : header.elf64.phnum;
259 else
261 phoff.QuadPart = byteswap ? RtlUlongByteSwap( header.elf.phoff ) : header.elf.phoff;
262 phnum = byteswap ? RtlUshortByteSwap( header.elf.phnum ) : header.elf.phnum;
264 while (phnum--)
266 if (SetFilePointerEx( hfile, phoff, NULL, FILE_BEGIN ) == -1) return;
267 if (!ReadFile( hfile, &type, sizeof(type), &len, NULL ) || len < sizeof(type)) return;
268 if (byteswap) type = RtlUlongByteSwap( type );
269 if (type == 3)
271 info->type = BINARY_UNIX_EXE;
272 break;
274 phoff.QuadPart += (header.elf.class == 2) ? 56 : 32;
276 if (!info->type) info->type = BINARY_UNIX_LIB;
277 break;
279 default:
280 return;
282 switch(header.elf.machine)
284 case 3: info->arch = IMAGE_FILE_MACHINE_I386; break;
285 case 20: info->arch = IMAGE_FILE_MACHINE_POWERPC; break;
286 case 40: info->arch = IMAGE_FILE_MACHINE_ARMNT; break;
287 case 50: info->arch = IMAGE_FILE_MACHINE_IA64; break;
288 case 62: info->arch = IMAGE_FILE_MACHINE_AMD64; break;
289 case 183: info->arch = IMAGE_FILE_MACHINE_ARM64; break;
292 /* Mach-o File with Endian set to Big Endian or Little Endian */
293 else if (header.macho.magic == 0xfeedface || header.macho.magic == 0xcefaedfe ||
294 header.macho.magic == 0xfeedfacf || header.macho.magic == 0xcffaedfe)
296 if ((header.macho.cputype >> 24) == 1) info->flags |= BINARY_FLAG_64BIT;
297 if (header.macho.magic == 0xcefaedfe || header.macho.magic == 0xcffaedfe)
299 header.macho.filetype = RtlUlongByteSwap( header.macho.filetype );
300 header.macho.cputype = RtlUlongByteSwap( header.macho.cputype );
302 switch(header.macho.filetype)
304 case 2: info->type = BINARY_UNIX_EXE; break;
305 case 8: info->type = BINARY_UNIX_LIB; break;
307 switch(header.macho.cputype)
309 case 0x00000007: info->arch = IMAGE_FILE_MACHINE_I386; break;
310 case 0x01000007: info->arch = IMAGE_FILE_MACHINE_AMD64; break;
311 case 0x0000000c: info->arch = IMAGE_FILE_MACHINE_ARMNT; break;
312 case 0x0100000c: info->arch = IMAGE_FILE_MACHINE_ARM64; break;
313 case 0x00000012: info->arch = IMAGE_FILE_MACHINE_POWERPC; break;
316 /* Not ELF, try DOS */
317 else if (header.mz.e_magic == IMAGE_DOS_SIGNATURE)
319 union
321 IMAGE_OS2_HEADER os2;
322 IMAGE_NT_HEADERS32 nt;
323 IMAGE_NT_HEADERS64 nt64;
324 } ext_header;
326 /* We do have a DOS image so we will now try to seek into
327 * the file by the amount indicated by the field
328 * "Offset to extended header" and read in the
329 * "magic" field information at that location.
330 * This will tell us if there is more header information
331 * to read or not.
333 info->type = BINARY_WIN16;
334 info->arch = IMAGE_FILE_MACHINE_I386;
335 if (SetFilePointer( hfile, header.mz.e_lfanew, NULL, SEEK_SET ) == -1) return;
336 if (!ReadFile( hfile, &ext_header, sizeof(ext_header), &len, NULL ) || len < 4) return;
338 /* Reading the magic field succeeded so
339 * we will try to determine what type it is.
341 if (!memcmp( &ext_header.nt.Signature, "PE\0\0", 4 ))
343 if (len >= sizeof(ext_header.nt.FileHeader))
345 static const char fakedll_signature[] = "Wine placeholder DLL";
346 char buffer[sizeof(fakedll_signature)];
348 info->type = BINARY_PE;
349 info->arch = ext_header.nt.FileHeader.Machine;
350 if (ext_header.nt.FileHeader.Characteristics & IMAGE_FILE_DLL)
351 info->flags |= BINARY_FLAG_DLL;
352 if (len < sizeof(ext_header)) /* clear remaining part of header if missing */
353 memset( (char *)&ext_header + len, 0, sizeof(ext_header) - len );
354 switch (ext_header.nt.OptionalHeader.Magic)
356 case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
357 info->res_start = ext_header.nt.OptionalHeader.ImageBase;
358 info->res_end = info->res_start + ext_header.nt.OptionalHeader.SizeOfImage;
359 break;
360 case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
361 info->res_start = ext_header.nt64.OptionalHeader.ImageBase;
362 info->res_end = info->res_start + ext_header.nt64.OptionalHeader.SizeOfImage;
363 info->flags |= BINARY_FLAG_64BIT;
364 break;
367 if (header.mz.e_lfanew >= sizeof(header.mz) + sizeof(fakedll_signature) &&
368 SetFilePointer( hfile, sizeof(header.mz), NULL, SEEK_SET ) == sizeof(header.mz) &&
369 ReadFile( hfile, buffer, sizeof(fakedll_signature), &len, NULL ) &&
370 len == sizeof(fakedll_signature) &&
371 !memcmp( buffer, fakedll_signature, sizeof(fakedll_signature) ))
373 info->flags |= BINARY_FLAG_FAKEDLL;
381 /***************************************************************************
382 * get_builtin_path
384 * Get the path of a builtin module when the native file does not exist.
386 static BOOL get_builtin_path( const WCHAR *libname, const WCHAR *ext, WCHAR *filename,
387 UINT size, struct binary_info *binary_info )
389 WCHAR *file_part;
390 UINT len;
391 void *redir_disabled = 0;
392 unsigned int flags = (sizeof(void*) > sizeof(int) ? BINARY_FLAG_64BIT : 0);
394 /* builtin names cannot be empty or contain spaces */
395 if (!libname[0] || strchrW( libname, ' ' ) || strchrW( libname, '\t' )) return FALSE;
397 if (is_wow64 && Wow64DisableWow64FsRedirection( &redir_disabled ))
398 Wow64RevertWow64FsRedirection( redir_disabled );
400 if (contains_path( libname ))
402 if (RtlGetFullPathName_U( libname, size * sizeof(WCHAR),
403 filename, &file_part ) > size * sizeof(WCHAR))
404 return FALSE; /* too long */
406 if ((len = is_path_prefix( DIR_System, filename )))
408 if (is_wow64 && redir_disabled) flags = BINARY_FLAG_64BIT;
410 else if (DIR_SysWow64 && (len = is_path_prefix( DIR_SysWow64, filename )))
412 flags = 0;
414 else return FALSE;
416 if (filename + len != file_part) return FALSE;
418 else
420 len = strlenW( DIR_System );
421 if (strlenW(libname) + len + 2 >= size) return FALSE; /* too long */
422 memcpy( filename, DIR_System, len * sizeof(WCHAR) );
423 file_part = filename + len;
424 if (file_part > filename && file_part[-1] != '\\') *file_part++ = '\\';
425 strcpyW( file_part, libname );
426 if (is_wow64 && redir_disabled) flags = BINARY_FLAG_64BIT;
428 if (ext && !strchrW( file_part, '.' ))
430 if (file_part + strlenW(file_part) + strlenW(ext) + 1 > filename + size)
431 return FALSE; /* too long */
432 strcatW( file_part, ext );
434 binary_info->type = BINARY_UNIX_LIB;
435 binary_info->flags = flags;
436 binary_info->res_start = 0;
437 binary_info->res_end = 0;
438 /* assume current arch */
439 #if defined(__i386__) || defined(__x86_64__)
440 binary_info->arch = (flags & BINARY_FLAG_64BIT) ? IMAGE_FILE_MACHINE_AMD64 : IMAGE_FILE_MACHINE_I386;
441 #elif defined(__powerpc__)
442 binary_info->arch = IMAGE_FILE_MACHINE_POWERPC;
443 #elif defined(__arm__) && !defined(__ARMEB__)
444 binary_info->arch = IMAGE_FILE_MACHINE_ARMNT;
445 #elif defined(__aarch64__)
446 binary_info->arch = IMAGE_FILE_MACHINE_ARM64;
447 #else
448 binary_info->arch = IMAGE_FILE_MACHINE_UNKNOWN;
449 #endif
450 return TRUE;
454 /***********************************************************************
455 * open_exe_file
457 * Open a specific exe file, taking load order into account.
458 * Returns the file handle or 0 for a builtin exe.
460 static HANDLE open_exe_file( const WCHAR *name, struct binary_info *binary_info )
462 HANDLE handle;
464 TRACE("looking for %s\n", debugstr_w(name) );
466 if ((handle = CreateFileW( name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_DELETE,
467 NULL, OPEN_EXISTING, 0, 0 )) == INVALID_HANDLE_VALUE)
469 WCHAR buffer[MAX_PATH];
470 /* file doesn't exist, check for builtin */
471 if (contains_path( name ) && get_builtin_path( name, NULL, buffer, sizeof(buffer), binary_info ))
472 handle = 0;
474 else get_binary_info( handle, binary_info );
476 return handle;
480 /***********************************************************************
481 * find_exe_file
483 * Open an exe file, and return the full name and file handle.
484 * Returns FALSE if file could not be found.
486 static BOOL find_exe_file( const WCHAR *name, WCHAR *buffer, int buflen,
487 HANDLE *handle, struct binary_info *binary_info )
489 TRACE("looking for %s\n", debugstr_w(name) );
491 if (!SearchPathW( NULL, name, exeW, buflen, buffer, NULL ) &&
492 /* no builtin found, try native without extension in case it is a Unix app */
493 !SearchPathW( NULL, name, NULL, buflen, buffer, NULL )) return FALSE;
495 TRACE( "Trying native exe %s\n", debugstr_w(buffer) );
496 if ((*handle = CreateFileW( buffer, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_DELETE,
497 NULL, OPEN_EXISTING, 0, 0 )) != INVALID_HANDLE_VALUE)
499 get_binary_info( *handle, binary_info );
500 return TRUE;
502 return FALSE;
506 /***********************************************************************
507 * build_initial_environment
509 * Build the Win32 environment from the Unix environment
511 static BOOL build_initial_environment(void)
513 SIZE_T size = 1;
514 char **e;
515 WCHAR *p, *endptr;
516 void *ptr;
517 char **env = __wine_get_main_environment();
519 /* Compute the total size of the Unix environment */
520 for (e = env; *e; e++)
522 if (is_special_env_var( *e )) continue;
523 size += MultiByteToWideChar( CP_UNIXCP, 0, *e, -1, NULL, 0 );
525 size *= sizeof(WCHAR);
527 /* Now allocate the environment */
528 ptr = NULL;
529 if (NtAllocateVirtualMemory(NtCurrentProcess(), &ptr, 0, &size,
530 MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE) != STATUS_SUCCESS)
531 return FALSE;
533 NtCurrentTeb()->Peb->ProcessParameters->Environment = p = ptr;
534 endptr = p + size / sizeof(WCHAR);
536 /* And fill it with the Unix environment */
537 for (e = env; *e; e++)
539 char *str = *e;
541 /* skip Unix special variables and use the Wine variants instead */
542 if (!strncmp( str, "WINE", 4 ))
544 if (is_special_env_var( str + 4 )) str += 4;
545 else if (!strncmp( str, "WINEPRELOADRESERVE=", 19 )) continue; /* skip it */
547 else if (is_special_env_var( str )) continue; /* skip it */
549 MultiByteToWideChar( CP_UNIXCP, 0, str, -1, p, endptr - p );
550 p += strlenW(p) + 1;
552 *p = 0;
553 return TRUE;
557 /***********************************************************************
558 * set_registry_variables
560 * Set environment variables by enumerating the values of a key;
561 * helper for set_registry_environment().
562 * Note that Windows happily truncates the value if it's too big.
564 static void set_registry_variables( HANDLE hkey, ULONG type )
566 static const WCHAR pathW[] = {'P','A','T','H'};
567 static const WCHAR sep[] = {';',0};
568 UNICODE_STRING env_name, env_value;
569 NTSTATUS status;
570 DWORD size;
571 int index;
572 char buffer[1024*sizeof(WCHAR) + sizeof(KEY_VALUE_FULL_INFORMATION)];
573 WCHAR tmpbuf[1024];
574 UNICODE_STRING tmp;
575 KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
577 tmp.Buffer = tmpbuf;
578 tmp.MaximumLength = sizeof(tmpbuf);
580 for (index = 0; ; index++)
582 status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
583 buffer, sizeof(buffer), &size );
584 if (status != STATUS_SUCCESS && status != STATUS_BUFFER_OVERFLOW)
585 break;
586 if (info->Type != type)
587 continue;
588 env_name.Buffer = info->Name;
589 env_name.Length = env_name.MaximumLength = info->NameLength;
590 env_value.Buffer = (WCHAR *)(buffer + info->DataOffset);
591 env_value.Length = info->DataLength;
592 env_value.MaximumLength = sizeof(buffer) - info->DataOffset;
593 if (env_value.Length && !env_value.Buffer[env_value.Length/sizeof(WCHAR)-1])
594 env_value.Length -= sizeof(WCHAR); /* don't count terminating null if any */
595 if (!env_value.Length) continue;
596 if (info->Type == REG_EXPAND_SZ)
598 status = RtlExpandEnvironmentStrings_U( NULL, &env_value, &tmp, NULL );
599 if (status != STATUS_SUCCESS && status != STATUS_BUFFER_OVERFLOW) continue;
600 RtlCopyUnicodeString( &env_value, &tmp );
602 /* PATH is magic */
603 if (env_name.Length == sizeof(pathW) &&
604 !memicmpW( env_name.Buffer, pathW, ARRAY_SIZE( pathW )) &&
605 !RtlQueryEnvironmentVariable_U( NULL, &env_name, &tmp ))
607 RtlAppendUnicodeToString( &tmp, sep );
608 if (RtlAppendUnicodeStringToString( &tmp, &env_value )) continue;
609 RtlCopyUnicodeString( &env_value, &tmp );
611 RtlSetEnvironmentVariable( NULL, &env_name, &env_value );
616 /***********************************************************************
617 * set_registry_environment
619 * Set the environment variables specified in the registry.
621 * Note: Windows handles REG_SZ and REG_EXPAND_SZ in one pass with the
622 * consequence that REG_EXPAND_SZ cannot be used reliably as it depends
623 * on the order in which the variables are processed. But on Windows it
624 * does not really matter since they only use %SystemDrive% and
625 * %SystemRoot% which are predefined. But Wine defines these in the
626 * registry, so we need two passes.
628 static BOOL set_registry_environment( BOOL volatile_only )
630 static const WCHAR env_keyW[] = {'\\','R','e','g','i','s','t','r','y','\\',
631 'M','a','c','h','i','n','e','\\',
632 'S','y','s','t','e','m','\\',
633 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
634 'C','o','n','t','r','o','l','\\',
635 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
636 'E','n','v','i','r','o','n','m','e','n','t',0};
637 static const WCHAR envW[] = {'E','n','v','i','r','o','n','m','e','n','t',0};
638 static const WCHAR volatile_envW[] = {'V','o','l','a','t','i','l','e',' ','E','n','v','i','r','o','n','m','e','n','t',0};
640 OBJECT_ATTRIBUTES attr;
641 UNICODE_STRING nameW;
642 HANDLE hkey;
643 BOOL ret = FALSE;
645 attr.Length = sizeof(attr);
646 attr.RootDirectory = 0;
647 attr.ObjectName = &nameW;
648 attr.Attributes = 0;
649 attr.SecurityDescriptor = NULL;
650 attr.SecurityQualityOfService = NULL;
652 /* first the system environment variables */
653 RtlInitUnicodeString( &nameW, env_keyW );
654 if (!volatile_only && NtOpenKey( &hkey, KEY_READ, &attr ) == STATUS_SUCCESS)
656 set_registry_variables( hkey, REG_SZ );
657 set_registry_variables( hkey, REG_EXPAND_SZ );
658 NtClose( hkey );
659 ret = TRUE;
662 /* then the ones for the current user */
663 if (RtlOpenCurrentUser( KEY_READ, &attr.RootDirectory ) != STATUS_SUCCESS) return ret;
664 RtlInitUnicodeString( &nameW, envW );
665 if (!volatile_only && NtOpenKey( &hkey, KEY_READ, &attr ) == STATUS_SUCCESS)
667 set_registry_variables( hkey, REG_SZ );
668 set_registry_variables( hkey, REG_EXPAND_SZ );
669 NtClose( hkey );
672 RtlInitUnicodeString( &nameW, volatile_envW );
673 if (NtOpenKey( &hkey, KEY_READ, &attr ) == STATUS_SUCCESS)
675 set_registry_variables( hkey, REG_SZ );
676 set_registry_variables( hkey, REG_EXPAND_SZ );
677 NtClose( hkey );
680 NtClose( attr.RootDirectory );
681 return ret;
685 /***********************************************************************
686 * get_reg_value
688 static WCHAR *get_reg_value( HKEY hkey, const WCHAR *name )
690 char buffer[1024 * sizeof(WCHAR) + sizeof(KEY_VALUE_PARTIAL_INFORMATION)];
691 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
692 DWORD len, size = sizeof(buffer);
693 WCHAR *ret = NULL;
694 UNICODE_STRING nameW;
696 RtlInitUnicodeString( &nameW, name );
697 if (NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, buffer, size, &size ))
698 return NULL;
700 if (size <= FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data )) return NULL;
701 len = (size - FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data )) / sizeof(WCHAR);
703 if (info->Type == REG_EXPAND_SZ)
705 UNICODE_STRING value, expanded;
707 value.MaximumLength = len * sizeof(WCHAR);
708 value.Buffer = (WCHAR *)info->Data;
709 if (!value.Buffer[len - 1]) len--; /* don't count terminating null if any */
710 value.Length = len * sizeof(WCHAR);
711 expanded.Length = expanded.MaximumLength = 1024 * sizeof(WCHAR);
712 if (!(expanded.Buffer = HeapAlloc( GetProcessHeap(), 0, expanded.MaximumLength ))) return NULL;
713 if (!RtlExpandEnvironmentStrings_U( NULL, &value, &expanded, NULL )) ret = expanded.Buffer;
714 else RtlFreeUnicodeString( &expanded );
716 else if (info->Type == REG_SZ)
718 if ((ret = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) )))
720 memcpy( ret, info->Data, len * sizeof(WCHAR) );
721 ret[len] = 0;
724 return ret;
728 /***********************************************************************
729 * set_additional_environment
731 * Set some additional environment variables not specified in the registry.
733 static void set_additional_environment(void)
735 static const WCHAR profile_keyW[] = {'\\','R','e','g','i','s','t','r','y','\\',
736 'M','a','c','h','i','n','e','\\',
737 'S','o','f','t','w','a','r','e','\\',
738 'M','i','c','r','o','s','o','f','t','\\',
739 'W','i','n','d','o','w','s',' ','N','T','\\',
740 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
741 'P','r','o','f','i','l','e','L','i','s','t',0};
742 static const WCHAR profiles_valueW[] = {'P','r','o','f','i','l','e','s','D','i','r','e','c','t','o','r','y',0};
743 static const WCHAR public_valueW[] = {'P','u','b','l','i','c',0};
744 static const WCHAR computernameW[] = {'C','O','M','P','U','T','E','R','N','A','M','E',0};
745 static const WCHAR allusersW[] = {'A','L','L','U','S','E','R','S','P','R','O','F','I','L','E',0};
746 static const WCHAR programdataW[] = {'P','r','o','g','r','a','m','D','a','t','a',0};
747 static const WCHAR publicW[] = {'P','U','B','L','I','C',0};
748 OBJECT_ATTRIBUTES attr;
749 UNICODE_STRING nameW;
750 WCHAR *profile_dir = NULL, *program_data_dir = NULL, *public_dir = NULL;
751 WCHAR buf[MAX_COMPUTERNAME_LENGTH+1];
752 HANDLE hkey;
753 DWORD len;
755 /* ComputerName */
756 len = ARRAY_SIZE( buf );
757 if (GetComputerNameW( buf, &len ))
758 SetEnvironmentVariableW( computernameW, buf );
760 /* set the ALLUSERSPROFILE variables */
762 attr.Length = sizeof(attr);
763 attr.RootDirectory = 0;
764 attr.ObjectName = &nameW;
765 attr.Attributes = 0;
766 attr.SecurityDescriptor = NULL;
767 attr.SecurityQualityOfService = NULL;
768 RtlInitUnicodeString( &nameW, profile_keyW );
769 if (!NtOpenKey( &hkey, KEY_READ, &attr ))
771 profile_dir = get_reg_value( hkey, profiles_valueW );
772 program_data_dir = get_reg_value( hkey, programdataW );
773 public_dir = get_reg_value( hkey, public_valueW );
774 NtClose( hkey );
777 if (program_data_dir)
779 SetEnvironmentVariableW( allusersW, program_data_dir );
780 SetEnvironmentVariableW( programdataW, program_data_dir );
783 if (public_dir)
785 SetEnvironmentVariableW( publicW, public_dir );
788 HeapFree( GetProcessHeap(), 0, profile_dir );
789 HeapFree( GetProcessHeap(), 0, program_data_dir );
790 HeapFree( GetProcessHeap(), 0, public_dir );
793 /***********************************************************************
794 * set_wow64_environment
796 * Set the environment variables that change across 32/64/Wow64.
798 static void set_wow64_environment(void)
800 static const WCHAR archW[] = {'P','R','O','C','E','S','S','O','R','_','A','R','C','H','I','T','E','C','T','U','R','E',0};
801 static const WCHAR arch6432W[] = {'P','R','O','C','E','S','S','O','R','_','A','R','C','H','I','T','E','W','6','4','3','2',0};
802 static const WCHAR x86W[] = {'x','8','6',0};
803 static const WCHAR versionW[] = {'\\','R','e','g','i','s','t','r','y','\\',
804 'M','a','c','h','i','n','e','\\',
805 'S','o','f','t','w','a','r','e','\\',
806 'M','i','c','r','o','s','o','f','t','\\',
807 'W','i','n','d','o','w','s','\\',
808 'C','u','r','r','e','n','t','V','e','r','s','i','o','n',0};
809 static const WCHAR progdirW[] = {'P','r','o','g','r','a','m','F','i','l','e','s','D','i','r',0};
810 static const WCHAR progdir86W[] = {'P','r','o','g','r','a','m','F','i','l','e','s','D','i','r',' ','(','x','8','6',')',0};
811 static const WCHAR progfilesW[] = {'P','r','o','g','r','a','m','F','i','l','e','s',0};
812 static const WCHAR progw6432W[] = {'P','r','o','g','r','a','m','W','6','4','3','2',0};
813 static const WCHAR commondirW[] = {'C','o','m','m','o','n','F','i','l','e','s','D','i','r',0};
814 static const WCHAR commondir86W[] = {'C','o','m','m','o','n','F','i','l','e','s','D','i','r',' ','(','x','8','6',')',0};
815 static const WCHAR commonfilesW[] = {'C','o','m','m','o','n','P','r','o','g','r','a','m','F','i','l','e','s',0};
816 static const WCHAR commonw6432W[] = {'C','o','m','m','o','n','P','r','o','g','r','a','m','W','6','4','3','2',0};
818 OBJECT_ATTRIBUTES attr;
819 UNICODE_STRING nameW;
820 WCHAR arch[64];
821 WCHAR *value;
822 HANDLE hkey;
824 /* set the PROCESSOR_ARCHITECTURE variable */
826 if (GetEnvironmentVariableW( arch6432W, arch, ARRAY_SIZE( arch )))
828 if (is_win64)
830 SetEnvironmentVariableW( archW, arch );
831 SetEnvironmentVariableW( arch6432W, NULL );
834 else if (GetEnvironmentVariableW( archW, arch, ARRAY_SIZE( arch )))
836 if (is_wow64)
838 SetEnvironmentVariableW( arch6432W, arch );
839 SetEnvironmentVariableW( archW, x86W );
843 attr.Length = sizeof(attr);
844 attr.RootDirectory = 0;
845 attr.ObjectName = &nameW;
846 attr.Attributes = 0;
847 attr.SecurityDescriptor = NULL;
848 attr.SecurityQualityOfService = NULL;
849 RtlInitUnicodeString( &nameW, versionW );
850 if (NtOpenKey( &hkey, KEY_READ | KEY_WOW64_64KEY, &attr )) return;
852 /* set the ProgramFiles variables */
854 if ((value = get_reg_value( hkey, progdirW )))
856 if (is_win64 || is_wow64) SetEnvironmentVariableW( progw6432W, value );
857 if (is_win64 || !is_wow64) SetEnvironmentVariableW( progfilesW, value );
858 HeapFree( GetProcessHeap(), 0, value );
860 if (is_wow64 && (value = get_reg_value( hkey, progdir86W )))
862 SetEnvironmentVariableW( progfilesW, value );
863 HeapFree( GetProcessHeap(), 0, value );
866 /* set the CommonProgramFiles variables */
868 if ((value = get_reg_value( hkey, commondirW )))
870 if (is_win64 || is_wow64) SetEnvironmentVariableW( commonw6432W, value );
871 if (is_win64 || !is_wow64) SetEnvironmentVariableW( commonfilesW, value );
872 HeapFree( GetProcessHeap(), 0, value );
874 if (is_wow64 && (value = get_reg_value( hkey, commondir86W )))
876 SetEnvironmentVariableW( commonfilesW, value );
877 HeapFree( GetProcessHeap(), 0, value );
880 NtClose( hkey );
883 /***********************************************************************
884 * set_library_wargv
886 * Set the Wine library Unicode argv global variables.
888 static void set_library_wargv( char **argv )
890 int argc;
891 char *q;
892 WCHAR *p;
893 WCHAR **wargv;
894 DWORD total = 0;
896 for (argc = 0; argv[argc]; argc++)
897 total += MultiByteToWideChar( CP_UNIXCP, 0, argv[argc], -1, NULL, 0 );
899 wargv = RtlAllocateHeap( GetProcessHeap(), 0,
900 total * sizeof(WCHAR) + (argc + 1) * sizeof(*wargv) );
901 p = (WCHAR *)(wargv + argc + 1);
902 for (argc = 0; argv[argc]; argc++)
904 DWORD reslen = MultiByteToWideChar( CP_UNIXCP, 0, argv[argc], -1, p, total );
905 wargv[argc] = p;
906 p += reslen;
907 total -= reslen;
909 wargv[argc] = NULL;
911 /* convert argv back from Unicode since it has to be in the Ansi codepage not the Unix one */
913 for (argc = 0; wargv[argc]; argc++)
914 total += WideCharToMultiByte( CP_ACP, 0, wargv[argc], -1, NULL, 0, NULL, NULL );
916 argv = RtlAllocateHeap( GetProcessHeap(), 0, total + (argc + 1) * sizeof(*argv) );
917 q = (char *)(argv + argc + 1);
918 for (argc = 0; wargv[argc]; argc++)
920 DWORD reslen = WideCharToMultiByte( CP_ACP, 0, wargv[argc], -1, q, total, NULL, NULL );
921 argv[argc] = q;
922 q += reslen;
923 total -= reslen;
925 argv[argc] = NULL;
927 __wine_main_argc = argc;
928 __wine_main_argv = argv;
929 __wine_main_wargv = wargv;
933 /***********************************************************************
934 * update_library_argv0
936 * Update the argv[0] global variable with the binary we have found.
938 static void update_library_argv0( const WCHAR *argv0 )
940 DWORD len = strlenW( argv0 );
942 if (len > strlenW( __wine_main_wargv[0] ))
944 __wine_main_wargv[0] = RtlAllocateHeap( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) );
946 strcpyW( __wine_main_wargv[0], argv0 );
948 len = WideCharToMultiByte( CP_ACP, 0, argv0, -1, NULL, 0, NULL, NULL );
949 if (len > strlen( __wine_main_argv[0] ) + 1)
951 __wine_main_argv[0] = RtlAllocateHeap( GetProcessHeap(), 0, len );
953 WideCharToMultiByte( CP_ACP, 0, argv0, -1, __wine_main_argv[0], len, NULL, NULL );
957 /***********************************************************************
958 * build_command_line
960 * Build the command line of a process from the argv array.
962 * Note that it does NOT necessarily include the file name.
963 * Sometimes we don't even have any command line options at all.
965 * We must quote and escape characters so that the argv array can be rebuilt
966 * from the command line:
967 * - spaces and tabs must be quoted
968 * 'a b' -> '"a b"'
969 * - quotes must be escaped
970 * '"' -> '\"'
971 * - if '\'s are followed by a '"', they must be doubled and followed by '\"',
972 * resulting in an odd number of '\' followed by a '"'
973 * '\"' -> '\\\"'
974 * '\\"' -> '\\\\\"'
975 * - '\'s are followed by the closing '"' must be doubled,
976 * resulting in an even number of '\' followed by a '"'
977 * ' \' -> '" \\"'
978 * ' \\' -> '" \\\\"'
979 * - '\'s that are not followed by a '"' can be left as is
980 * 'a\b' == 'a\b'
981 * 'a\\b' == 'a\\b'
983 static BOOL build_command_line( WCHAR **argv )
985 int len;
986 WCHAR **arg;
987 LPWSTR p;
988 RTL_USER_PROCESS_PARAMETERS* rupp = NtCurrentTeb()->Peb->ProcessParameters;
990 if (rupp->CommandLine.Buffer) return TRUE; /* already got it from the server */
992 len = 0;
993 for (arg = argv; *arg; arg++)
995 BOOL has_space;
996 int bcount;
997 WCHAR* a;
999 has_space=FALSE;
1000 bcount=0;
1001 a=*arg;
1002 if( !*a ) has_space=TRUE;
1003 while (*a!='\0') {
1004 if (*a=='\\') {
1005 bcount++;
1006 } else {
1007 if (*a==' ' || *a=='\t') {
1008 has_space=TRUE;
1009 } else if (*a=='"') {
1010 /* doubling of '\' preceding a '"',
1011 * plus escaping of said '"'
1013 len+=2*bcount+1;
1015 bcount=0;
1017 a++;
1019 len+=(a-*arg)+1 /* for the separating space */;
1020 if (has_space)
1021 len+=2+bcount; /* for the quotes and doubling of '\' preceding the closing quote */
1024 if (!(rupp->CommandLine.Buffer = RtlAllocateHeap( GetProcessHeap(), 0, len * sizeof(WCHAR))))
1025 return FALSE;
1027 p = rupp->CommandLine.Buffer;
1028 rupp->CommandLine.Length = (len - 1) * sizeof(WCHAR);
1029 rupp->CommandLine.MaximumLength = len * sizeof(WCHAR);
1030 for (arg = argv; *arg; arg++)
1032 BOOL has_space,has_quote;
1033 WCHAR* a;
1034 int bcount;
1036 /* Check for quotes and spaces in this argument */
1037 has_space=has_quote=FALSE;
1038 a=*arg;
1039 if( !*a ) has_space=TRUE;
1040 while (*a!='\0') {
1041 if (*a==' ' || *a=='\t') {
1042 has_space=TRUE;
1043 if (has_quote)
1044 break;
1045 } else if (*a=='"') {
1046 has_quote=TRUE;
1047 if (has_space)
1048 break;
1050 a++;
1053 /* Now transfer it to the command line */
1054 if (has_space)
1055 *p++='"';
1056 if (has_quote || has_space) {
1057 bcount=0;
1058 a=*arg;
1059 while (*a!='\0') {
1060 if (*a=='\\') {
1061 *p++=*a;
1062 bcount++;
1063 } else {
1064 if (*a=='"') {
1065 int i;
1067 /* Double all the '\\' preceding this '"', plus one */
1068 for (i=0;i<=bcount;i++)
1069 *p++='\\';
1070 *p++='"';
1071 } else {
1072 *p++=*a;
1074 bcount=0;
1076 a++;
1078 } else {
1079 WCHAR* x = *arg;
1080 while ((*p=*x++)) p++;
1082 if (has_space) {
1083 int i;
1085 /* Double all the '\' preceding the closing quote */
1086 for (i=0;i<bcount;i++)
1087 *p++='\\';
1088 *p++='"';
1090 *p++=' ';
1092 if (p > rupp->CommandLine.Buffer)
1093 p--; /* remove last space */
1094 *p = '\0';
1096 return TRUE;
1100 /***********************************************************************
1101 * init_current_directory
1103 * Initialize the current directory from the Unix cwd or the parent info.
1105 static void init_current_directory( CURDIR *cur_dir )
1107 UNICODE_STRING dir_str;
1108 const char *pwd;
1109 char *cwd;
1110 int size;
1112 /* if we received a cur dir from the parent, try this first */
1114 if (cur_dir->DosPath.Length)
1116 if (RtlSetCurrentDirectory_U( &cur_dir->DosPath ) == STATUS_SUCCESS) goto done;
1119 /* now try to get it from the Unix cwd */
1121 for (size = 256; ; size *= 2)
1123 if (!(cwd = HeapAlloc( GetProcessHeap(), 0, size ))) break;
1124 if (getcwd( cwd, size )) break;
1125 HeapFree( GetProcessHeap(), 0, cwd );
1126 if (errno == ERANGE) continue;
1127 cwd = NULL;
1128 break;
1131 /* try to use PWD if it is valid, so that we don't resolve symlinks */
1133 pwd = getenv( "PWD" );
1134 if (cwd)
1136 struct stat st1, st2;
1138 if (!pwd || stat( pwd, &st1 ) == -1 ||
1139 (!stat( cwd, &st2 ) && (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)))
1140 pwd = cwd;
1143 if (pwd)
1145 ANSI_STRING unix_name;
1146 UNICODE_STRING nt_name;
1147 RtlInitAnsiString( &unix_name, pwd );
1148 if (!wine_unix_to_nt_file_name( &unix_name, &nt_name ))
1150 UNICODE_STRING dos_path;
1151 /* skip the \??\ prefix, nt_name is 0 terminated */
1152 RtlInitUnicodeString( &dos_path, nt_name.Buffer + 4 );
1153 RtlSetCurrentDirectory_U( &dos_path );
1154 RtlFreeUnicodeString( &nt_name );
1158 if (!cur_dir->DosPath.Length) /* still not initialized */
1160 MESSAGE("Warning: could not find DOS drive for current working directory '%s', "
1161 "starting in the Windows directory.\n", cwd ? cwd : "" );
1162 RtlInitUnicodeString( &dir_str, DIR_Windows );
1163 RtlSetCurrentDirectory_U( &dir_str );
1165 HeapFree( GetProcessHeap(), 0, cwd );
1167 done:
1168 TRACE( "starting in %s %p\n", debugstr_w( cur_dir->DosPath.Buffer ), cur_dir->Handle );
1172 /***********************************************************************
1173 * init_windows_dirs
1175 * Create the windows and system directories if necessary.
1177 static void init_windows_dirs(void)
1179 static const WCHAR default_syswow64W[] = {'C',':','\\','w','i','n','d','o','w','s',
1180 '\\','s','y','s','w','o','w','6','4',0};
1182 if (!CreateDirectoryW( DIR_Windows, NULL ) && GetLastError() != ERROR_ALREADY_EXISTS)
1183 ERR( "directory %s could not be created, error %u\n",
1184 debugstr_w(DIR_Windows), GetLastError() );
1185 if (!CreateDirectoryW( DIR_System, NULL ) && GetLastError() != ERROR_ALREADY_EXISTS)
1186 ERR( "directory %s could not be created, error %u\n",
1187 debugstr_w(DIR_System), GetLastError() );
1189 if (is_win64 || is_wow64) /* SysWow64 is always defined on 64-bit */
1191 DIR_SysWow64 = default_syswow64W;
1192 if (!CreateDirectoryW( DIR_SysWow64, NULL ) && GetLastError() != ERROR_ALREADY_EXISTS)
1193 ERR( "directory %s could not be created, error %u\n",
1194 debugstr_w(DIR_SysWow64), GetLastError() );
1199 /***********************************************************************
1200 * start_wineboot
1202 * Start the wineboot process if necessary. Return the handles to wait on.
1204 static void start_wineboot( HANDLE handles[2] )
1206 static const WCHAR wineboot_eventW[] = {'_','_','w','i','n','e','b','o','o','t','_','e','v','e','n','t',0};
1208 handles[1] = 0;
1209 if (!(handles[0] = CreateEventW( NULL, TRUE, FALSE, wineboot_eventW )))
1211 ERR( "failed to create wineboot event, expect trouble\n" );
1212 return;
1214 if (GetLastError() != ERROR_ALREADY_EXISTS) /* we created it */
1216 static const WCHAR wineboot[] = {'\\','w','i','n','e','b','o','o','t','.','e','x','e',0};
1217 static const WCHAR args[] = {' ','-','-','i','n','i','t',0};
1218 STARTUPINFOW si;
1219 PROCESS_INFORMATION pi;
1220 void *redir;
1221 WCHAR app[MAX_PATH];
1222 WCHAR cmdline[MAX_PATH + ARRAY_SIZE( wineboot ) + ARRAY_SIZE( args )];
1224 memset( &si, 0, sizeof(si) );
1225 si.cb = sizeof(si);
1226 si.dwFlags = STARTF_USESTDHANDLES;
1227 si.hStdInput = 0;
1228 si.hStdOutput = 0;
1229 si.hStdError = GetStdHandle( STD_ERROR_HANDLE );
1231 GetSystemDirectoryW( app, MAX_PATH - ARRAY_SIZE( wineboot ));
1232 lstrcatW( app, wineboot );
1234 Wow64DisableWow64FsRedirection( &redir );
1235 strcpyW( cmdline, app );
1236 strcatW( cmdline, args );
1237 if (CreateProcessW( app, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &si, &pi ))
1239 TRACE( "started wineboot pid %04x tid %04x\n", pi.dwProcessId, pi.dwThreadId );
1240 CloseHandle( pi.hThread );
1241 handles[1] = pi.hProcess;
1243 else
1245 ERR( "failed to start wineboot, err %u\n", GetLastError() );
1246 CloseHandle( handles[0] );
1247 handles[0] = 0;
1249 Wow64RevertWow64FsRedirection( redir );
1254 #ifdef __i386__
1255 extern DWORD call_process_entry( PEB *peb, LPTHREAD_START_ROUTINE entry );
1256 __ASM_GLOBAL_FUNC( call_process_entry,
1257 "pushl %ebp\n\t"
1258 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
1259 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
1260 "movl %esp,%ebp\n\t"
1261 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
1262 "pushl 4(%ebp)\n\t" /* deliberately mis-align the stack by 8, Doom 3 needs this */
1263 "pushl 4(%ebp)\n\t" /* Driller expects readable address at this offset */
1264 "pushl 4(%ebp)\n\t"
1265 "pushl 8(%ebp)\n\t"
1266 "call *12(%ebp)\n\t"
1267 "leave\n\t"
1268 __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
1269 __ASM_CFI(".cfi_same_value %ebp\n\t")
1270 "ret" )
1272 extern void WINAPI start_process( LPTHREAD_START_ROUTINE entry, PEB *peb ) DECLSPEC_HIDDEN;
1273 extern void WINAPI start_process_wrapper(void) DECLSPEC_HIDDEN;
1274 __ASM_GLOBAL_FUNC( start_process_wrapper,
1275 "pushl %ebp\n\t"
1276 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
1277 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
1278 "movl %esp,%ebp\n\t"
1279 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
1280 "pushl %ebx\n\t" /* arg */
1281 "pushl %eax\n\t" /* entry */
1282 "call " __ASM_NAME("start_process") )
1283 #else
1284 static inline DWORD call_process_entry( PEB *peb, LPTHREAD_START_ROUTINE entry )
1286 return entry( peb );
1288 static void WINAPI start_process( LPTHREAD_START_ROUTINE entry, PEB *peb );
1289 #define start_process_wrapper start_process
1290 #endif
1292 /***********************************************************************
1293 * start_process
1295 * Startup routine of a new process. Runs on the new process stack.
1297 void WINAPI start_process( LPTHREAD_START_ROUTINE entry, PEB *peb )
1299 BOOL being_debugged;
1301 if (!entry)
1303 ERR( "%s doesn't have an entry point, it cannot be executed\n",
1304 debugstr_w(peb->ProcessParameters->ImagePathName.Buffer) );
1305 ExitThread( 1 );
1308 TRACE_(relay)( "\1Starting process %s (entryproc=%p)\n",
1309 debugstr_w(peb->ProcessParameters->ImagePathName.Buffer), entry );
1311 __TRY
1313 if (!CheckRemoteDebuggerPresent( GetCurrentProcess(), &being_debugged ))
1314 being_debugged = FALSE;
1316 SetLastError( 0 ); /* clear error code */
1317 if (being_debugged) DbgBreakPoint();
1318 ExitThread( call_process_entry( peb, entry ));
1320 __EXCEPT(UnhandledExceptionFilter)
1322 TerminateThread( GetCurrentThread(), GetExceptionCode() );
1324 __ENDTRY
1325 abort(); /* should not be reached */
1329 /***********************************************************************
1330 * set_process_name
1332 * Change the process name in the ps output.
1334 static void set_process_name( int argc, char *argv[] )
1336 BOOL shift_strings;
1337 char *p, *name;
1338 int i;
1340 #ifdef HAVE_SETPROCTITLE
1341 setproctitle("-%s", argv[1]);
1342 shift_strings = FALSE;
1343 #else
1344 p = argv[0];
1346 shift_strings = (argc >= 2);
1347 for (i = 1; i < argc; i++)
1349 p += strlen(p) + 1;
1350 if (p != argv[i])
1352 shift_strings = FALSE;
1353 break;
1356 #endif
1358 if (shift_strings)
1360 int offset = argv[1] - argv[0];
1361 char *end = argv[argc-1] + strlen(argv[argc-1]) + 1;
1362 memmove( argv[0], argv[1], end - argv[1] );
1363 memset( end - offset, 0, offset );
1364 for (i = 1; i < argc; i++)
1365 argv[i-1] = argv[i] - offset;
1366 argv[i-1] = NULL;
1368 else
1370 /* remove argv[0] */
1371 memmove( argv, argv + 1, argc * sizeof(argv[0]) );
1374 name = argv[0];
1375 if ((p = strrchr( name, '\\' ))) name = p + 1;
1376 if ((p = strrchr( name, '/' ))) name = p + 1;
1378 #if defined(HAVE_SETPROGNAME)
1379 setprogname( name );
1380 #endif
1382 #ifdef HAVE_PRCTL
1383 #ifndef PR_SET_NAME
1384 # define PR_SET_NAME 15
1385 #endif
1386 prctl( PR_SET_NAME, name );
1387 #endif /* HAVE_PRCTL */
1391 /***********************************************************************
1392 * __wine_kernel_init
1394 * Wine initialisation: load and start the main exe file.
1396 void CDECL __wine_kernel_init(void)
1398 static const WCHAR kernel32W[] = {'k','e','r','n','e','l','3','2',0};
1399 static const WCHAR dotW[] = {'.',0};
1401 WCHAR *p, main_exe_name[MAX_PATH+1];
1402 PEB *peb = NtCurrentTeb()->Peb;
1403 RTL_USER_PROCESS_PARAMETERS *params = peb->ProcessParameters;
1404 HANDLE boot_events[2];
1405 BOOL got_environment = TRUE;
1407 /* Initialize everything */
1409 setbuf(stdout,NULL);
1410 setbuf(stderr,NULL);
1411 kernel32_handle = GetModuleHandleW(kernel32W);
1412 IsWow64Process( GetCurrentProcess(), &is_wow64 );
1414 LOCALE_Init();
1416 if (!params->Environment)
1418 /* Copy the parent environment */
1419 if (!build_initial_environment()) exit(1);
1421 /* convert old configuration to new format */
1422 convert_old_config();
1424 got_environment = set_registry_environment( FALSE );
1425 set_additional_environment();
1428 init_windows_dirs();
1429 init_current_directory( &params->CurrentDirectory );
1431 set_process_name( __wine_main_argc, __wine_main_argv );
1432 set_library_wargv( __wine_main_argv );
1433 boot_events[0] = boot_events[1] = 0;
1435 if (peb->ProcessParameters->ImagePathName.Buffer)
1437 strcpyW( main_exe_name, peb->ProcessParameters->ImagePathName.Buffer );
1439 else
1441 struct binary_info binary_info;
1443 if (!SearchPathW( NULL, __wine_main_wargv[0], exeW, MAX_PATH, main_exe_name, NULL ) &&
1444 !get_builtin_path( __wine_main_wargv[0], exeW, main_exe_name, MAX_PATH, &binary_info ))
1446 MESSAGE( "wine: cannot find '%s'\n", __wine_main_argv[0] );
1447 ExitProcess( GetLastError() );
1449 update_library_argv0( main_exe_name );
1450 if (!build_command_line( __wine_main_wargv )) goto error;
1451 start_wineboot( boot_events );
1454 /* if there's no extension, append a dot to prevent LoadLibrary from appending .dll */
1455 p = strrchrW( main_exe_name, '.' );
1456 if (!p || strchrW( p, '/' ) || strchrW( p, '\\' )) strcatW( main_exe_name, dotW );
1458 TRACE( "starting process name=%s argv[0]=%s\n",
1459 debugstr_w(main_exe_name), debugstr_w(__wine_main_wargv[0]) );
1461 RtlInitUnicodeString( &NtCurrentTeb()->Peb->ProcessParameters->DllPath,
1462 MODULE_get_dll_load_path( main_exe_name, -1 ));
1464 if (boot_events[0])
1466 DWORD timeout = 2 * 60 * 1000, count = 1;
1468 if (boot_events[1]) count++;
1469 if (!got_environment) timeout = 5 * 60 * 1000; /* initial prefix creation can take longer */
1470 if (WaitForMultipleObjects( count, boot_events, FALSE, timeout ) == WAIT_TIMEOUT)
1471 ERR( "boot event wait timed out\n" );
1472 CloseHandle( boot_events[0] );
1473 if (boot_events[1]) CloseHandle( boot_events[1] );
1474 /* reload environment now that wineboot has run */
1475 set_registry_environment( got_environment );
1476 set_additional_environment();
1478 set_wow64_environment();
1480 if (!(peb->ImageBaseAddress = LoadLibraryExW( main_exe_name, 0, DONT_RESOLVE_DLL_REFERENCES )))
1482 DWORD_PTR args[1];
1483 WCHAR msgW[1024];
1484 char msg[1024];
1485 DWORD error = GetLastError();
1487 /* if Win16/DOS format, or unavailable address, exec a new process with the proper setup */
1488 if (error == ERROR_BAD_EXE_FORMAT ||
1489 error == ERROR_INVALID_ADDRESS ||
1490 error == ERROR_NOT_ENOUGH_MEMORY)
1492 if (!getenv("WINEPRELOADRESERVE")) exec_process( main_exe_name );
1493 /* if we get back here, it failed */
1495 else if (error == ERROR_MOD_NOT_FOUND)
1497 if ((p = strrchrW( main_exe_name, '\\' ))) p++;
1498 else p = main_exe_name;
1499 if (!strcmpiW( p, winevdmW ) && __wine_main_argc > 3)
1501 /* args 1 and 2 are --app-name full_path */
1502 MESSAGE( "wine: could not run %s: 16-bit/DOS support missing\n",
1503 debugstr_w(__wine_main_wargv[3]) );
1504 ExitProcess( ERROR_BAD_EXE_FORMAT );
1506 MESSAGE( "wine: cannot find %s\n", debugstr_w(main_exe_name) );
1507 ExitProcess( ERROR_FILE_NOT_FOUND );
1509 args[0] = (DWORD_PTR)main_exe_name;
1510 FormatMessageW( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY,
1511 NULL, error, 0, msgW, ARRAY_SIZE( msgW ), (__ms_va_list *)args );
1512 WideCharToMultiByte( CP_UNIXCP, 0, msgW, -1, msg, sizeof(msg), NULL, NULL );
1513 MESSAGE( "wine: %s", msg );
1514 ExitProcess( error );
1517 if (!params->CurrentDirectory.Handle) chdir("/"); /* avoid locking removable devices */
1519 LdrInitializeThunk( start_process_wrapper, 0, 0, 0 );
1521 error:
1522 ExitProcess( GetLastError() );
1526 /***********************************************************************
1527 * build_argv
1529 * Build an argv array from a command-line.
1530 * 'reserved' is the number of args to reserve before the first one.
1532 static char **build_argv( const WCHAR *cmdlineW, int reserved )
1534 int argc;
1535 char** argv;
1536 char *arg,*s,*d,*cmdline;
1537 int in_quotes,bcount,len;
1539 len = WideCharToMultiByte( CP_UNIXCP, 0, cmdlineW, -1, NULL, 0, NULL, NULL );
1540 if (!(cmdline = HeapAlloc( GetProcessHeap(), 0, len ))) return NULL;
1541 WideCharToMultiByte( CP_UNIXCP, 0, cmdlineW, -1, cmdline, len, NULL, NULL );
1543 argc=reserved+1;
1544 bcount=0;
1545 in_quotes=0;
1546 s=cmdline;
1547 while (1) {
1548 if (*s=='\0' || ((*s==' ' || *s=='\t') && !in_quotes)) {
1549 /* space */
1550 argc++;
1551 /* skip the remaining spaces */
1552 while (*s==' ' || *s=='\t') {
1553 s++;
1555 if (*s=='\0')
1556 break;
1557 bcount=0;
1558 continue;
1559 } else if (*s=='\\') {
1560 /* '\', count them */
1561 bcount++;
1562 } else if ((*s=='"') && ((bcount & 1)==0)) {
1563 /* unescaped '"' */
1564 in_quotes=!in_quotes;
1565 bcount=0;
1566 } else {
1567 /* a regular character */
1568 bcount=0;
1570 s++;
1572 if (!(argv = HeapAlloc( GetProcessHeap(), 0, argc*sizeof(*argv) + len )))
1574 HeapFree( GetProcessHeap(), 0, cmdline );
1575 return NULL;
1578 arg = d = s = (char *)(argv + argc);
1579 memcpy( d, cmdline, len );
1580 bcount=0;
1581 in_quotes=0;
1582 argc=reserved;
1583 while (*s) {
1584 if ((*s==' ' || *s=='\t') && !in_quotes) {
1585 /* Close the argument and copy it */
1586 *d=0;
1587 argv[argc++]=arg;
1589 /* skip the remaining spaces */
1590 do {
1591 s++;
1592 } while (*s==' ' || *s=='\t');
1594 /* Start with a new argument */
1595 arg=d=s;
1596 bcount=0;
1597 } else if (*s=='\\') {
1598 /* '\\' */
1599 *d++=*s++;
1600 bcount++;
1601 } else if (*s=='"') {
1602 /* '"' */
1603 if ((bcount & 1)==0) {
1604 /* Preceded by an even number of '\', this is half that
1605 * number of '\', plus a '"' which we discard.
1607 d-=bcount/2;
1608 s++;
1609 in_quotes=!in_quotes;
1610 } else {
1611 /* Preceded by an odd number of '\', this is half that
1612 * number of '\' followed by a '"'
1614 d=d-bcount/2-1;
1615 *d++='"';
1616 s++;
1618 bcount=0;
1619 } else {
1620 /* a regular character */
1621 *d++=*s++;
1622 bcount=0;
1625 if (*arg) {
1626 *d='\0';
1627 argv[argc++]=arg;
1629 argv[argc]=NULL;
1631 HeapFree( GetProcessHeap(), 0, cmdline );
1632 return argv;
1636 /***********************************************************************
1637 * build_envp
1639 * Build the environment of a new child process.
1641 static char **build_envp( const WCHAR *envW )
1643 static const char * const unix_vars[] = { "PATH", "TEMP", "TMP", "HOME" };
1645 const WCHAR *end;
1646 char **envp;
1647 char *env, *p;
1648 int count = 1, length;
1649 unsigned int i;
1651 for (end = envW; *end; count++) end += strlenW(end) + 1;
1652 end++;
1653 length = WideCharToMultiByte( CP_UNIXCP, 0, envW, end - envW, NULL, 0, NULL, NULL );
1654 if (!(env = HeapAlloc( GetProcessHeap(), 0, length ))) return NULL;
1655 WideCharToMultiByte( CP_UNIXCP, 0, envW, end - envW, env, length, NULL, NULL );
1657 for (p = env; *p; p += strlen(p) + 1)
1658 if (is_special_env_var( p )) length += 4; /* prefix it with "WINE" */
1660 for (i = 0; i < ARRAY_SIZE( unix_vars ); i++)
1662 if (!(p = getenv(unix_vars[i]))) continue;
1663 length += strlen(unix_vars[i]) + strlen(p) + 2;
1664 count++;
1667 if ((envp = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*envp) + length )))
1669 char **envptr = envp;
1670 char *dst = (char *)(envp + count);
1672 /* some variables must not be modified, so we get them directly from the unix env */
1673 for (i = 0; i < ARRAY_SIZE( unix_vars ); i++)
1675 if (!(p = getenv(unix_vars[i]))) continue;
1676 *envptr++ = strcpy( dst, unix_vars[i] );
1677 strcat( dst, "=" );
1678 strcat( dst, p );
1679 dst += strlen(dst) + 1;
1682 /* now put the Windows environment strings */
1683 for (p = env; *p; p += strlen(p) + 1)
1685 if (*p == '=') continue; /* skip drive curdirs, this crashes some unix apps */
1686 if (!strncmp( p, "WINEPRELOADRESERVE=", sizeof("WINEPRELOADRESERVE=")-1 )) continue;
1687 if (!strncmp( p, "WINELOADERNOEXEC=", sizeof("WINELOADERNOEXEC=")-1 )) continue;
1688 if (!strncmp( p, "WINESERVERSOCKET=", sizeof("WINESERVERSOCKET=")-1 )) continue;
1689 if (is_special_env_var( p )) /* prefix it with "WINE" */
1691 *envptr++ = strcpy( dst, "WINE" );
1692 strcat( dst, p );
1694 else
1696 *envptr++ = strcpy( dst, p );
1698 dst += strlen(dst) + 1;
1700 *envptr = 0;
1702 HeapFree( GetProcessHeap(), 0, env );
1703 return envp;
1707 /***********************************************************************
1708 * fork_and_exec
1710 * Fork and exec a new Unix binary, checking for errors.
1712 static int fork_and_exec( const char *filename, const WCHAR *cmdline, const WCHAR *env,
1713 const char *newdir, DWORD flags, STARTUPINFOW *startup )
1715 int fd[2], stdin_fd = -1, stdout_fd = -1, stderr_fd = -1;
1716 int pid, err;
1717 char **argv, **envp;
1719 if (!env) env = GetEnvironmentStringsW();
1721 #ifdef HAVE_PIPE2
1722 if (pipe2( fd, O_CLOEXEC ) == -1)
1723 #endif
1725 if (pipe(fd) == -1)
1727 SetLastError( ERROR_TOO_MANY_OPEN_FILES );
1728 return -1;
1730 fcntl( fd[0], F_SETFD, FD_CLOEXEC );
1731 fcntl( fd[1], F_SETFD, FD_CLOEXEC );
1734 if (!(flags & (CREATE_NEW_PROCESS_GROUP | CREATE_NEW_CONSOLE | DETACHED_PROCESS)))
1736 HANDLE hstdin, hstdout, hstderr;
1738 if (startup->dwFlags & STARTF_USESTDHANDLES)
1740 hstdin = startup->hStdInput;
1741 hstdout = startup->hStdOutput;
1742 hstderr = startup->hStdError;
1744 else
1746 hstdin = GetStdHandle(STD_INPUT_HANDLE);
1747 hstdout = GetStdHandle(STD_OUTPUT_HANDLE);
1748 hstderr = GetStdHandle(STD_ERROR_HANDLE);
1751 if (is_console_handle( hstdin ))
1752 hstdin = wine_server_ptr_handle( console_handle_unmap( hstdin ));
1753 if (is_console_handle( hstdout ))
1754 hstdout = wine_server_ptr_handle( console_handle_unmap( hstdout ));
1755 if (is_console_handle( hstderr ))
1756 hstderr = wine_server_ptr_handle( console_handle_unmap( hstderr ));
1757 wine_server_handle_to_fd( hstdin, FILE_READ_DATA, &stdin_fd, NULL );
1758 wine_server_handle_to_fd( hstdout, FILE_WRITE_DATA, &stdout_fd, NULL );
1759 wine_server_handle_to_fd( hstderr, FILE_WRITE_DATA, &stderr_fd, NULL );
1762 argv = build_argv( cmdline, 0 );
1763 envp = build_envp( env );
1765 if (!(pid = fork())) /* child */
1767 if (!(pid = fork())) /* grandchild */
1769 close( fd[0] );
1771 if (flags & (CREATE_NEW_PROCESS_GROUP | CREATE_NEW_CONSOLE | DETACHED_PROCESS))
1773 int nullfd = open( "/dev/null", O_RDWR );
1774 setsid();
1775 /* close stdin and stdout */
1776 if (nullfd != -1)
1778 dup2( nullfd, 0 );
1779 dup2( nullfd, 1 );
1780 close( nullfd );
1783 else
1785 if (stdin_fd != -1)
1787 dup2( stdin_fd, 0 );
1788 close( stdin_fd );
1790 if (stdout_fd != -1)
1792 dup2( stdout_fd, 1 );
1793 close( stdout_fd );
1795 if (stderr_fd != -1)
1797 dup2( stderr_fd, 2 );
1798 close( stderr_fd );
1802 /* Reset signals that we previously set to SIG_IGN */
1803 signal( SIGPIPE, SIG_DFL );
1805 if (newdir) chdir(newdir);
1807 if (argv && envp) execve( filename, argv, envp );
1810 if (pid <= 0) /* grandchild if exec failed or child if fork failed */
1812 err = errno;
1813 write( fd[1], &err, sizeof(err) );
1814 _exit(1);
1817 _exit(0); /* child if fork succeeded */
1819 HeapFree( GetProcessHeap(), 0, argv );
1820 HeapFree( GetProcessHeap(), 0, envp );
1821 if (stdin_fd != -1) close( stdin_fd );
1822 if (stdout_fd != -1) close( stdout_fd );
1823 if (stderr_fd != -1) close( stderr_fd );
1824 close( fd[1] );
1825 if (pid != -1)
1827 /* reap child */
1828 do {
1829 err = waitpid(pid, NULL, 0);
1830 } while (err < 0 && errno == EINTR);
1832 if (read( fd[0], &err, sizeof(err) ) > 0) /* exec or second fork failed */
1834 errno = err;
1835 pid = -1;
1838 if (pid == -1) FILE_SetDosError();
1839 close( fd[0] );
1840 return pid;
1844 static inline DWORD append_string( void **ptr, const WCHAR *str )
1846 DWORD len = strlenW( str );
1847 memcpy( *ptr, str, len * sizeof(WCHAR) );
1848 *ptr = (WCHAR *)*ptr + len;
1849 return len * sizeof(WCHAR);
1852 /***********************************************************************
1853 * create_startup_info
1855 static startup_info_t *create_startup_info( LPCWSTR filename, LPCWSTR cmdline,
1856 LPCWSTR cur_dir, LPWSTR env, DWORD flags,
1857 const STARTUPINFOW *startup, DWORD *info_size )
1859 const RTL_USER_PROCESS_PARAMETERS *cur_params;
1860 const WCHAR *title;
1861 startup_info_t *info;
1862 DWORD size;
1863 void *ptr;
1864 UNICODE_STRING newdir;
1865 WCHAR imagepath[MAX_PATH];
1866 HANDLE hstdin, hstdout, hstderr;
1868 if(!GetLongPathNameW( filename, imagepath, MAX_PATH ))
1869 lstrcpynW( imagepath, filename, MAX_PATH );
1870 if(!GetFullPathNameW( imagepath, MAX_PATH, imagepath, NULL ))
1871 lstrcpynW( imagepath, filename, MAX_PATH );
1873 cur_params = NtCurrentTeb()->Peb->ProcessParameters;
1875 newdir.Buffer = NULL;
1876 if (cur_dir)
1878 if (RtlDosPathNameToNtPathName_U( cur_dir, &newdir, NULL, NULL ))
1879 cur_dir = newdir.Buffer + 4; /* skip \??\ prefix */
1880 else
1881 cur_dir = NULL;
1883 if (!cur_dir)
1885 if (NtCurrentTeb()->Tib.SubSystemTib) /* FIXME: hack */
1886 cur_dir = ((WIN16_SUBSYSTEM_TIB *)NtCurrentTeb()->Tib.SubSystemTib)->curdir.DosPath.Buffer;
1887 else
1888 cur_dir = cur_params->CurrentDirectory.DosPath.Buffer;
1890 title = startup->lpTitle ? startup->lpTitle : imagepath;
1892 size = sizeof(*info);
1893 size += strlenW( cur_dir ) * sizeof(WCHAR);
1894 size += cur_params->DllPath.Length;
1895 size += strlenW( imagepath ) * sizeof(WCHAR);
1896 size += strlenW( cmdline ) * sizeof(WCHAR);
1897 size += strlenW( title ) * sizeof(WCHAR);
1898 if (startup->lpDesktop) size += strlenW( startup->lpDesktop ) * sizeof(WCHAR);
1899 /* FIXME: shellinfo */
1900 if (startup->lpReserved2 && startup->cbReserved2) size += startup->cbReserved2;
1901 size = (size + 1) & ~1;
1902 *info_size = size;
1904 if (!(info = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size ))) goto done;
1906 info->console_flags = cur_params->ConsoleFlags;
1907 if (flags & CREATE_NEW_PROCESS_GROUP) info->console_flags = 1;
1908 if (flags & CREATE_NEW_CONSOLE) info->console = wine_server_obj_handle(KERNEL32_CONSOLE_ALLOC);
1910 if (startup->dwFlags & STARTF_USESTDHANDLES)
1912 hstdin = startup->hStdInput;
1913 hstdout = startup->hStdOutput;
1914 hstderr = startup->hStdError;
1916 else if (flags & DETACHED_PROCESS)
1918 hstdin = INVALID_HANDLE_VALUE;
1919 hstdout = INVALID_HANDLE_VALUE;
1920 hstderr = INVALID_HANDLE_VALUE;
1922 else
1924 hstdin = GetStdHandle( STD_INPUT_HANDLE );
1925 hstdout = GetStdHandle( STD_OUTPUT_HANDLE );
1926 hstderr = GetStdHandle( STD_ERROR_HANDLE );
1928 info->hstdin = wine_server_obj_handle( hstdin );
1929 info->hstdout = wine_server_obj_handle( hstdout );
1930 info->hstderr = wine_server_obj_handle( hstderr );
1931 if ((flags & CREATE_NEW_CONSOLE) != 0)
1933 /* this is temporary (for console handles). We have no way to control that the handle is invalid in child process otherwise */
1934 if (is_console_handle(hstdin)) info->hstdin = wine_server_obj_handle( INVALID_HANDLE_VALUE );
1935 if (is_console_handle(hstdout)) info->hstdout = wine_server_obj_handle( INVALID_HANDLE_VALUE );
1936 if (is_console_handle(hstderr)) info->hstderr = wine_server_obj_handle( INVALID_HANDLE_VALUE );
1938 else
1940 if (is_console_handle(hstdin)) info->hstdin = console_handle_unmap(hstdin);
1941 if (is_console_handle(hstdout)) info->hstdout = console_handle_unmap(hstdout);
1942 if (is_console_handle(hstderr)) info->hstderr = console_handle_unmap(hstderr);
1945 info->x = startup->dwX;
1946 info->y = startup->dwY;
1947 info->xsize = startup->dwXSize;
1948 info->ysize = startup->dwYSize;
1949 info->xchars = startup->dwXCountChars;
1950 info->ychars = startup->dwYCountChars;
1951 info->attribute = startup->dwFillAttribute;
1952 info->flags = startup->dwFlags;
1953 info->show = startup->wShowWindow;
1955 ptr = info + 1;
1956 info->curdir_len = append_string( &ptr, cur_dir );
1957 info->dllpath_len = cur_params->DllPath.Length;
1958 memcpy( ptr, cur_params->DllPath.Buffer, cur_params->DllPath.Length );
1959 ptr = (char *)ptr + cur_params->DllPath.Length;
1960 info->imagepath_len = append_string( &ptr, imagepath );
1961 info->cmdline_len = append_string( &ptr, cmdline );
1962 info->title_len = append_string( &ptr, title );
1963 if (startup->lpDesktop) info->desktop_len = append_string( &ptr, startup->lpDesktop );
1964 if (startup->lpReserved2 && startup->cbReserved2)
1966 info->runtime_len = startup->cbReserved2;
1967 memcpy( ptr, startup->lpReserved2, startup->cbReserved2 );
1970 done:
1971 RtlFreeUnicodeString( &newdir );
1972 return info;
1975 /***********************************************************************
1976 * get_alternate_loader
1978 * Get the name of the alternate (32 or 64 bit) Wine loader.
1980 static const char *get_alternate_loader( char **ret_env )
1982 char *env;
1983 const char *loader = NULL;
1984 const char *loader_env = getenv( "WINELOADER" );
1986 *ret_env = NULL;
1988 if (wine_get_build_dir()) loader = is_win64 ? "loader/wine" : "server/../loader/wine64";
1990 if (loader_env)
1992 int len = strlen( loader_env );
1993 if (!is_win64)
1995 if (!(env = HeapAlloc( GetProcessHeap(), 0, sizeof("WINELOADER=") + len + 2 ))) return NULL;
1996 strcpy( env, "WINELOADER=" );
1997 strcat( env, loader_env );
1998 strcat( env, "64" );
2000 else
2002 if (!(env = HeapAlloc( GetProcessHeap(), 0, sizeof("WINELOADER=") + len ))) return NULL;
2003 strcpy( env, "WINELOADER=" );
2004 strcat( env, loader_env );
2005 len += sizeof("WINELOADER=") - 1;
2006 if (!strcmp( env + len - 2, "64" )) env[len - 2] = 0;
2008 if (!loader)
2010 if ((loader = strrchr( env, '/' ))) loader++;
2011 else loader = env;
2013 *ret_env = env;
2015 if (!loader) loader = is_win64 ? "wine" : "wine64";
2016 return loader;
2019 #ifdef __APPLE__
2020 /***********************************************************************
2021 * terminate_main_thread
2023 * On some versions of Mac OS X, the execve system call fails with
2024 * ENOTSUP if the process has multiple threads. Wine is always multi-
2025 * threaded on Mac OS X because it specifically reserves the main thread
2026 * for use by the system frameworks (see apple_main_thread() in
2027 * libs/wine/loader.c). So, when we need to exec without first forking,
2028 * we need to terminate the main thread first. We do this by installing
2029 * a custom run loop source onto the main run loop and signaling it.
2030 * The source's "perform" callback is pthread_exit and it will be
2031 * executed on the main thread, terminating it.
2033 * Returns TRUE if there's still hope the main thread has terminated or
2034 * will soon. Return FALSE if we've given up.
2036 static BOOL terminate_main_thread(void)
2038 static int delayms;
2040 if (!delayms)
2042 CFRunLoopSourceContext source_context = { 0 };
2043 CFRunLoopSourceRef source;
2045 source_context.perform = pthread_exit;
2046 if (!(source = CFRunLoopSourceCreate( NULL, 0, &source_context )))
2047 return FALSE;
2049 CFRunLoopAddSource( CFRunLoopGetMain(), source, kCFRunLoopCommonModes );
2050 CFRunLoopSourceSignal( source );
2051 CFRunLoopWakeUp( CFRunLoopGetMain() );
2052 CFRelease( source );
2054 delayms = 20;
2057 if (delayms > 1000)
2058 return FALSE;
2060 usleep(delayms * 1000);
2061 delayms *= 2;
2063 return TRUE;
2065 #endif
2067 /***********************************************************************
2068 * get_process_cpu
2070 static int get_process_cpu( const WCHAR *filename, const struct binary_info *binary_info )
2072 switch (binary_info->arch)
2074 case IMAGE_FILE_MACHINE_I386: return CPU_x86;
2075 case IMAGE_FILE_MACHINE_AMD64: return CPU_x86_64;
2076 case IMAGE_FILE_MACHINE_POWERPC: return CPU_POWERPC;
2077 case IMAGE_FILE_MACHINE_ARM:
2078 case IMAGE_FILE_MACHINE_THUMB:
2079 case IMAGE_FILE_MACHINE_ARMNT: return CPU_ARM;
2080 case IMAGE_FILE_MACHINE_ARM64: return CPU_ARM64;
2082 ERR( "%s uses unsupported architecture (%04x)\n", debugstr_w(filename), binary_info->arch );
2083 return -1;
2086 /***********************************************************************
2087 * exec_loader
2089 static pid_t exec_loader( LPCWSTR cmd_line, unsigned int flags, int socketfd,
2090 int stdin_fd, int stdout_fd, const char *unixdir, char *winedebug,
2091 const struct binary_info *binary_info, int exec_only )
2093 pid_t pid;
2094 char *wineloader = NULL;
2095 const char *loader = NULL;
2096 char **argv;
2098 argv = build_argv( cmd_line, 1 );
2100 if (!is_win64 ^ !(binary_info->flags & BINARY_FLAG_64BIT))
2101 loader = get_alternate_loader( &wineloader );
2103 if (exec_only || !(pid = fork())) /* child */
2105 if (exec_only || !(pid = fork())) /* grandchild */
2107 char preloader_reserve[64], socket_env[64];
2109 if (flags & (CREATE_NEW_PROCESS_GROUP | CREATE_NEW_CONSOLE | DETACHED_PROCESS))
2111 int fd = open( "/dev/null", O_RDWR );
2112 setsid();
2113 /* close stdin and stdout */
2114 if (fd != -1)
2116 dup2( fd, 0 );
2117 dup2( fd, 1 );
2118 close( fd );
2121 else
2123 if (stdin_fd != -1) dup2( stdin_fd, 0 );
2124 if (stdout_fd != -1) dup2( stdout_fd, 1 );
2127 if (stdin_fd != -1) close( stdin_fd );
2128 if (stdout_fd != -1) close( stdout_fd );
2130 /* Reset signals that we previously set to SIG_IGN */
2131 signal( SIGPIPE, SIG_DFL );
2133 sprintf( socket_env, "WINESERVERSOCKET=%u", socketfd );
2134 sprintf( preloader_reserve, "WINEPRELOADRESERVE=%x%08x-%x%08x",
2135 (ULONG)(binary_info->res_start >> 32), (ULONG)binary_info->res_start,
2136 (ULONG)(binary_info->res_end >> 32), (ULONG)binary_info->res_end );
2138 putenv( preloader_reserve );
2139 putenv( socket_env );
2140 if (winedebug) putenv( winedebug );
2141 if (wineloader) putenv( wineloader );
2142 if (unixdir) chdir(unixdir);
2144 if (argv)
2148 wine_exec_wine_binary( loader, argv, getenv("WINELOADER") );
2150 #ifdef __APPLE__
2151 while (errno == ENOTSUP && exec_only && terminate_main_thread());
2152 #else
2153 while (0);
2154 #endif
2156 _exit(1);
2159 _exit(pid == -1);
2162 if (pid != -1)
2164 /* reap child */
2165 pid_t wret;
2166 do {
2167 wret = waitpid(pid, NULL, 0);
2168 } while (wret < 0 && errno == EINTR);
2171 HeapFree( GetProcessHeap(), 0, wineloader );
2172 HeapFree( GetProcessHeap(), 0, argv );
2173 return pid;
2176 /* creates a struct security_descriptor and contained information in one contiguous piece of memory */
2177 static NTSTATUS alloc_object_attributes( const SECURITY_ATTRIBUTES *attr, struct object_attributes **ret,
2178 data_size_t *ret_len )
2180 unsigned int len = sizeof(**ret);
2181 PSID owner = NULL, group = NULL;
2182 ACL *dacl, *sacl;
2183 BOOLEAN dacl_present, sacl_present, defaulted;
2184 PSECURITY_DESCRIPTOR sd = NULL;
2185 NTSTATUS status;
2187 *ret = NULL;
2188 *ret_len = 0;
2190 if (attr) sd = attr->lpSecurityDescriptor;
2192 if (sd)
2194 len += sizeof(struct security_descriptor);
2196 if ((status = RtlGetOwnerSecurityDescriptor( sd, &owner, &defaulted ))) return status;
2197 if ((status = RtlGetGroupSecurityDescriptor( sd, &group, &defaulted ))) return status;
2198 if ((status = RtlGetSaclSecurityDescriptor( sd, &sacl_present, &sacl, &defaulted ))) return status;
2199 if ((status = RtlGetDaclSecurityDescriptor( sd, &dacl_present, &dacl, &defaulted ))) return status;
2200 if (owner) len += RtlLengthSid( owner );
2201 if (group) len += RtlLengthSid( group );
2202 if (sacl_present && sacl) len += sacl->AclSize;
2203 if (dacl_present && dacl) len += dacl->AclSize;
2206 len = (len + 3) & ~3; /* DWORD-align the entire structure */
2208 *ret = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, len );
2209 if (!*ret) return STATUS_NO_MEMORY;
2211 (*ret)->attributes = (attr && attr->bInheritHandle) ? OBJ_INHERIT : 0;
2213 if (sd)
2215 struct security_descriptor *descr = (struct security_descriptor *)(*ret + 1);
2216 unsigned char *ptr = (unsigned char *)(descr + 1);
2218 descr->control = ((SECURITY_DESCRIPTOR *)sd)->Control & ~SE_SELF_RELATIVE;
2219 if (owner) descr->owner_len = RtlLengthSid( owner );
2220 if (group) descr->group_len = RtlLengthSid( group );
2221 if (sacl_present && sacl) descr->sacl_len = sacl->AclSize;
2222 if (dacl_present && dacl) descr->dacl_len = dacl->AclSize;
2224 memcpy( ptr, owner, descr->owner_len );
2225 ptr += descr->owner_len;
2226 memcpy( ptr, group, descr->group_len );
2227 ptr += descr->group_len;
2228 memcpy( ptr, sacl, descr->sacl_len );
2229 ptr += descr->sacl_len;
2230 memcpy( ptr, dacl, descr->dacl_len );
2231 (*ret)->sd_len = (sizeof(*descr) + descr->owner_len + descr->group_len + descr->sacl_len +
2232 descr->dacl_len + sizeof(WCHAR) - 1) & ~(sizeof(WCHAR) - 1);
2234 *ret_len = len;
2235 return STATUS_SUCCESS;
2238 /***********************************************************************
2239 * create_process
2241 * Create a new process. If hFile is a valid handle we have an exe
2242 * file, otherwise it is a Winelib app.
2244 static BOOL create_process( HANDLE hFile, LPCWSTR filename, LPWSTR cmd_line, LPWSTR env,
2245 LPCWSTR cur_dir, LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES tsa,
2246 BOOL inherit, DWORD flags, LPSTARTUPINFOW startup,
2247 LPPROCESS_INFORMATION info, LPCSTR unixdir,
2248 const struct binary_info *binary_info, int exec_only )
2250 static const char *cpu_names[] = { "x86", "x86_64", "PowerPC", "ARM", "ARM64" };
2251 NTSTATUS status;
2252 BOOL success = FALSE;
2253 HANDLE process_info, process_handle = 0;
2254 struct object_attributes *objattr;
2255 data_size_t attr_len;
2256 WCHAR *env_end;
2257 char *winedebug = NULL;
2258 startup_info_t *startup_info;
2259 DWORD startup_info_size;
2260 int socketfd[2], stdin_fd = -1, stdout_fd = -1;
2261 pid_t pid;
2262 int err, cpu;
2264 if ((cpu = get_process_cpu( filename, binary_info )) == -1)
2266 SetLastError( ERROR_BAD_EXE_FORMAT );
2267 return FALSE;
2270 /* create the socket for the new process */
2272 if (socketpair( PF_UNIX, SOCK_STREAM, 0, socketfd ) == -1)
2274 SetLastError( ERROR_TOO_MANY_OPEN_FILES );
2275 return FALSE;
2277 #ifdef SO_PASSCRED
2278 else
2280 int enable = 1;
2281 setsockopt( socketfd[0], SOL_SOCKET, SO_PASSCRED, &enable, sizeof(enable) );
2283 #endif
2285 if (exec_only) /* things are much simpler in this case */
2287 wine_server_send_fd( socketfd[1] );
2288 close( socketfd[1] );
2289 SERVER_START_REQ( new_process )
2291 req->create_flags = flags;
2292 req->socket_fd = socketfd[1];
2293 req->exe_file = wine_server_obj_handle( hFile );
2294 req->cpu = cpu;
2295 status = wine_server_call( req );
2297 SERVER_END_REQ;
2299 switch (status)
2301 case STATUS_INVALID_IMAGE_WIN_64:
2302 ERR( "64-bit application %s not supported in 32-bit prefix\n", debugstr_w(filename) );
2303 break;
2304 case STATUS_INVALID_IMAGE_FORMAT:
2305 ERR( "%s not supported on this installation (%s binary)\n",
2306 debugstr_w(filename), cpu_names[cpu] );
2307 break;
2308 case STATUS_SUCCESS:
2309 exec_loader( cmd_line, flags, socketfd[0], stdin_fd, stdout_fd, unixdir,
2310 winedebug, binary_info, TRUE );
2312 close( socketfd[0] );
2313 SetLastError( RtlNtStatusToDosError( status ));
2314 return FALSE;
2317 RtlAcquirePebLock();
2319 if (!(startup_info = create_startup_info( filename, cmd_line, cur_dir, env, flags, startup,
2320 &startup_info_size )))
2322 RtlReleasePebLock();
2323 close( socketfd[0] );
2324 close( socketfd[1] );
2325 return FALSE;
2327 if (!env) env = NtCurrentTeb()->Peb->ProcessParameters->Environment;
2328 env_end = env;
2329 while (*env_end)
2331 static const WCHAR WINEDEBUG[] = {'W','I','N','E','D','E','B','U','G','=',0};
2332 if (!winedebug && !strncmpW( env_end, WINEDEBUG, ARRAY_SIZE( WINEDEBUG ) - 1 ))
2334 DWORD len = WideCharToMultiByte( CP_UNIXCP, 0, env_end, -1, NULL, 0, NULL, NULL );
2335 if ((winedebug = HeapAlloc( GetProcessHeap(), 0, len )))
2336 WideCharToMultiByte( CP_UNIXCP, 0, env_end, -1, winedebug, len, NULL, NULL );
2338 env_end += strlenW(env_end) + 1;
2340 env_end++;
2342 wine_server_send_fd( socketfd[1] );
2343 close( socketfd[1] );
2345 /* create the process on the server side */
2347 alloc_object_attributes( psa, &objattr, &attr_len );
2348 SERVER_START_REQ( new_process )
2350 req->inherit_all = inherit;
2351 req->create_flags = flags;
2352 req->socket_fd = socketfd[1];
2353 req->exe_file = wine_server_obj_handle( hFile );
2354 req->access = PROCESS_ALL_ACCESS;
2355 req->cpu = cpu;
2356 req->info_size = startup_info_size;
2357 wine_server_add_data( req, objattr, attr_len );
2358 wine_server_add_data( req, startup_info, startup_info_size );
2359 wine_server_add_data( req, env, (env_end - env) * sizeof(WCHAR) );
2360 if (!(status = wine_server_call( req )))
2362 info->dwProcessId = (DWORD)reply->pid;
2363 process_handle = wine_server_ptr_handle( reply->handle );
2365 process_info = wine_server_ptr_handle( reply->info );
2367 SERVER_END_REQ;
2368 HeapFree( GetProcessHeap(), 0, objattr );
2370 if (!status)
2372 alloc_object_attributes( tsa, &objattr, &attr_len );
2373 SERVER_START_REQ( new_thread )
2375 req->process = wine_server_obj_handle( process_handle );
2376 req->access = THREAD_ALL_ACCESS;
2377 req->suspend = !!(flags & CREATE_SUSPENDED);
2378 req->request_fd = -1;
2379 wine_server_add_data( req, objattr, attr_len );
2380 if (!(status = wine_server_call( req )))
2382 info->hProcess = process_handle;
2383 info->hThread = wine_server_ptr_handle( reply->handle );
2384 info->dwThreadId = reply->tid;
2387 SERVER_END_REQ;
2388 HeapFree( GetProcessHeap(), 0, objattr );
2391 RtlReleasePebLock();
2392 if (status)
2394 switch (status)
2396 case STATUS_INVALID_IMAGE_WIN_64:
2397 ERR( "64-bit application %s not supported in 32-bit prefix\n", debugstr_w(filename) );
2398 break;
2399 case STATUS_INVALID_IMAGE_FORMAT:
2400 ERR( "%s not supported on this installation (%s binary)\n",
2401 debugstr_w(filename), cpu_names[cpu] );
2402 break;
2404 close( socketfd[0] );
2405 CloseHandle( process_handle );
2406 HeapFree( GetProcessHeap(), 0, startup_info );
2407 HeapFree( GetProcessHeap(), 0, winedebug );
2408 SetLastError( RtlNtStatusToDosError( status ));
2409 return FALSE;
2412 if (!(flags & (CREATE_NEW_CONSOLE | DETACHED_PROCESS)))
2414 if (startup_info->hstdin)
2415 wine_server_handle_to_fd( wine_server_ptr_handle(startup_info->hstdin),
2416 FILE_READ_DATA, &stdin_fd, NULL );
2417 if (startup_info->hstdout)
2418 wine_server_handle_to_fd( wine_server_ptr_handle(startup_info->hstdout),
2419 FILE_WRITE_DATA, &stdout_fd, NULL );
2421 HeapFree( GetProcessHeap(), 0, startup_info );
2423 /* create the child process */
2425 pid = exec_loader( cmd_line, flags, socketfd[0], stdin_fd, stdout_fd, unixdir,
2426 winedebug, binary_info, FALSE );
2428 if (stdin_fd != -1) close( stdin_fd );
2429 if (stdout_fd != -1) close( stdout_fd );
2430 close( socketfd[0] );
2431 HeapFree( GetProcessHeap(), 0, winedebug );
2432 if (pid == -1)
2434 FILE_SetDosError();
2435 goto error;
2438 /* wait for the new process info to be ready */
2440 WaitForSingleObject( process_info, INFINITE );
2441 SERVER_START_REQ( get_new_process_info )
2443 req->info = wine_server_obj_handle( process_info );
2444 wine_server_call( req );
2445 success = reply->success;
2446 err = reply->exit_code;
2448 SERVER_END_REQ;
2450 if (!success)
2452 SetLastError( err ? err : ERROR_INTERNAL_ERROR );
2453 goto error;
2455 CloseHandle( process_info );
2456 return success;
2458 error:
2459 CloseHandle( process_info );
2460 CloseHandle( info->hProcess );
2461 CloseHandle( info->hThread );
2462 info->hProcess = info->hThread = 0;
2463 info->dwProcessId = info->dwThreadId = 0;
2464 return FALSE;
2468 /***********************************************************************
2469 * create_vdm_process
2471 * Create a new VDM process for a 16-bit or DOS application.
2473 static BOOL create_vdm_process( LPCWSTR filename, LPWSTR cmd_line, LPWSTR env, LPCWSTR cur_dir,
2474 LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES tsa,
2475 BOOL inherit, DWORD flags, LPSTARTUPINFOW startup,
2476 LPPROCESS_INFORMATION info, LPCSTR unixdir,
2477 const struct binary_info *binary_info, int exec_only )
2479 static const WCHAR argsW[] = {'%','s',' ','-','-','a','p','p','-','n','a','m','e',' ','"','%','s','"',' ','%','s',0};
2481 BOOL ret;
2482 WCHAR buffer[MAX_PATH];
2483 LPWSTR new_cmd_line;
2485 if (!(ret = GetFullPathNameW(filename, MAX_PATH, buffer, NULL)))
2486 return FALSE;
2488 new_cmd_line = HeapAlloc(GetProcessHeap(), 0,
2489 (strlenW(buffer) + strlenW(cmd_line) + 30) * sizeof(WCHAR));
2491 if (!new_cmd_line)
2493 SetLastError( ERROR_OUTOFMEMORY );
2494 return FALSE;
2496 sprintfW(new_cmd_line, argsW, winevdmW, buffer, cmd_line);
2497 ret = create_process( 0, winevdmW, new_cmd_line, env, cur_dir, psa, tsa, inherit,
2498 flags, startup, info, unixdir, binary_info, exec_only );
2499 HeapFree( GetProcessHeap(), 0, new_cmd_line );
2500 return ret;
2504 /***********************************************************************
2505 * create_cmd_process
2507 * Create a new cmd shell process for a .BAT file.
2509 static BOOL create_cmd_process( LPCWSTR filename, LPWSTR cmd_line, LPVOID env, LPCWSTR cur_dir,
2510 LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES tsa,
2511 BOOL inherit, DWORD flags, LPSTARTUPINFOW startup,
2512 LPPROCESS_INFORMATION info )
2515 static const WCHAR comspecW[] = {'C','O','M','S','P','E','C',0};
2516 static const WCHAR cmdW[] = {'\\','c','m','d','.','e','x','e',0};
2517 static const WCHAR slashscW[] = {' ','/','s','/','c',' ',0};
2518 static const WCHAR quotW[] = {'"',0};
2519 WCHAR comspec[MAX_PATH];
2520 WCHAR *newcmdline;
2521 BOOL ret;
2523 if (!GetEnvironmentVariableW( comspecW, comspec, ARRAY_SIZE( comspec )))
2525 GetSystemDirectoryW( comspec, (sizeof(comspec) - sizeof(cmdW))/sizeof(WCHAR) );
2526 strcatW( comspec, cmdW );
2528 if (!(newcmdline = HeapAlloc( GetProcessHeap(), 0,
2529 (strlenW(comspec) + 7 + strlenW(cmd_line) + 2) * sizeof(WCHAR))))
2530 return FALSE;
2532 strcpyW( newcmdline, comspec );
2533 strcatW( newcmdline, slashscW );
2534 strcatW( newcmdline, quotW );
2535 strcatW( newcmdline, cmd_line );
2536 strcatW( newcmdline, quotW );
2537 ret = CreateProcessW( comspec, newcmdline, psa, tsa, inherit,
2538 flags, env, cur_dir, startup, info );
2539 HeapFree( GetProcessHeap(), 0, newcmdline );
2540 return ret;
2544 /*************************************************************************
2545 * get_file_name
2547 * Helper for CreateProcess: retrieve the file name to load from the
2548 * app name and command line. Store the file name in buffer, and
2549 * return a possibly modified command line.
2550 * Also returns a handle to the opened file if it's a Windows binary.
2552 static LPWSTR get_file_name( LPCWSTR appname, LPWSTR cmdline, LPWSTR buffer,
2553 int buflen, HANDLE *handle, struct binary_info *binary_info )
2555 static const WCHAR quotesW[] = {'"','%','s','"',0};
2557 WCHAR *name, *pos, *first_space, *ret = NULL;
2558 const WCHAR *p;
2560 /* if we have an app name, everything is easy */
2562 if (appname)
2564 /* use the unmodified app name as file name */
2565 lstrcpynW( buffer, appname, buflen );
2566 *handle = open_exe_file( buffer, binary_info );
2567 if (!(ret = cmdline) || !cmdline[0])
2569 /* no command-line, create one */
2570 if ((ret = HeapAlloc( GetProcessHeap(), 0, (strlenW(appname) + 3) * sizeof(WCHAR) )))
2571 sprintfW( ret, quotesW, appname );
2573 return ret;
2576 /* first check for a quoted file name */
2578 if ((cmdline[0] == '"') && ((p = strchrW( cmdline + 1, '"' ))))
2580 int len = p - cmdline - 1;
2581 /* extract the quoted portion as file name */
2582 if (!(name = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return NULL;
2583 memcpy( name, cmdline + 1, len * sizeof(WCHAR) );
2584 name[len] = 0;
2586 if (!find_exe_file( name, buffer, buflen, handle, binary_info )) goto done;
2587 ret = cmdline; /* no change necessary */
2588 goto done;
2591 /* now try the command-line word by word */
2593 if (!(name = HeapAlloc( GetProcessHeap(), 0, (strlenW(cmdline) + 1) * sizeof(WCHAR) )))
2594 return NULL;
2595 pos = name;
2596 p = cmdline;
2597 first_space = NULL;
2599 for (;;)
2601 while (*p && *p != ' ' && *p != '\t') *pos++ = *p++;
2602 *pos = 0;
2603 if (find_exe_file( name, buffer, buflen, handle, binary_info ))
2605 ret = cmdline;
2606 break;
2608 if (!first_space) first_space = pos;
2609 if (!(*pos++ = *p++)) break;
2612 if (!ret)
2614 SetLastError( ERROR_FILE_NOT_FOUND );
2616 else if (first_space) /* build a new command-line with quotes */
2618 if (!(ret = HeapAlloc( GetProcessHeap(), 0, (strlenW(cmdline) + 3) * sizeof(WCHAR) )))
2619 goto done;
2620 sprintfW( ret, quotesW, name );
2621 strcatW( ret, p );
2624 done:
2625 HeapFree( GetProcessHeap(), 0, name );
2626 return ret;
2630 /* Steam hotpatches CreateProcessA and W, so to prevent it from crashing use an internal function */
2631 static BOOL create_process_impl( LPCWSTR app_name, LPWSTR cmd_line, LPSECURITY_ATTRIBUTES process_attr,
2632 LPSECURITY_ATTRIBUTES thread_attr, BOOL inherit, DWORD flags,
2633 LPVOID env, LPCWSTR cur_dir, LPSTARTUPINFOW startup_info,
2634 LPPROCESS_INFORMATION info )
2636 BOOL retv = FALSE;
2637 HANDLE hFile = 0;
2638 char *unixdir = NULL;
2639 WCHAR name[MAX_PATH];
2640 WCHAR *tidy_cmdline, *p, *envW = env;
2641 struct binary_info binary_info;
2643 /* Process the AppName and/or CmdLine to get module name and path */
2645 TRACE("app %s cmdline %s\n", debugstr_w(app_name), debugstr_w(cmd_line) );
2647 if (!(tidy_cmdline = get_file_name( app_name, cmd_line, name, ARRAY_SIZE( name ),
2648 &hFile, &binary_info )))
2649 return FALSE;
2650 if (hFile == INVALID_HANDLE_VALUE) goto done;
2652 /* Warn if unsupported features are used */
2654 if (flags & (IDLE_PRIORITY_CLASS | HIGH_PRIORITY_CLASS | REALTIME_PRIORITY_CLASS |
2655 CREATE_NEW_PROCESS_GROUP | CREATE_SEPARATE_WOW_VDM | CREATE_SHARED_WOW_VDM |
2656 CREATE_DEFAULT_ERROR_MODE | CREATE_NO_WINDOW |
2657 PROFILE_USER | PROFILE_KERNEL | PROFILE_SERVER))
2658 WARN("(%s,...): ignoring some flags in %x\n", debugstr_w(name), flags);
2660 if (cur_dir)
2662 if (!(unixdir = wine_get_unix_file_name( cur_dir )))
2664 SetLastError(ERROR_DIRECTORY);
2665 goto done;
2668 else
2670 WCHAR buf[MAX_PATH];
2671 if (GetCurrentDirectoryW(MAX_PATH, buf)) unixdir = wine_get_unix_file_name( buf );
2674 if (env && !(flags & CREATE_UNICODE_ENVIRONMENT)) /* convert environment to unicode */
2676 char *e = env;
2677 DWORD lenW;
2679 while (*e) e += strlen(e) + 1;
2680 e++; /* final null */
2681 lenW = MultiByteToWideChar( CP_ACP, 0, env, e - (char*)env, NULL, 0 );
2682 envW = HeapAlloc( GetProcessHeap(), 0, lenW * sizeof(WCHAR) );
2683 MultiByteToWideChar( CP_ACP, 0, env, e - (char*)env, envW, lenW );
2684 flags |= CREATE_UNICODE_ENVIRONMENT;
2687 info->hThread = info->hProcess = 0;
2688 info->dwProcessId = info->dwThreadId = 0;
2690 if (binary_info.flags & BINARY_FLAG_DLL)
2692 TRACE( "not starting %s since it is a dll\n", debugstr_w(name) );
2693 SetLastError( ERROR_BAD_EXE_FORMAT );
2695 else switch (binary_info.type)
2697 case BINARY_PE:
2698 TRACE( "starting %s as Win%d binary (%s-%s, arch %04x%s)\n",
2699 debugstr_w(name), (binary_info.flags & BINARY_FLAG_64BIT) ? 64 : 32,
2700 wine_dbgstr_longlong(binary_info.res_start), wine_dbgstr_longlong(binary_info.res_end),
2701 binary_info.arch, (binary_info.flags & BINARY_FLAG_FAKEDLL) ? ", fakedll" : "" );
2702 retv = create_process( hFile, name, tidy_cmdline, envW, cur_dir, process_attr, thread_attr,
2703 inherit, flags, startup_info, info, unixdir, &binary_info, FALSE );
2704 break;
2705 case BINARY_WIN16:
2706 TRACE( "starting %s as Win16/DOS binary\n", debugstr_w(name) );
2707 retv = create_vdm_process( name, tidy_cmdline, envW, cur_dir, process_attr, thread_attr,
2708 inherit, flags, startup_info, info, unixdir, &binary_info, FALSE );
2709 break;
2710 case BINARY_UNIX_LIB:
2711 TRACE( "starting %s as %d-bit Winelib app\n",
2712 debugstr_w(name), (binary_info.flags & BINARY_FLAG_64BIT) ? 64 : 32 );
2713 retv = create_process( hFile, name, tidy_cmdline, envW, cur_dir, process_attr, thread_attr,
2714 inherit, flags, startup_info, info, unixdir, &binary_info, FALSE );
2715 break;
2716 case BINARY_UNKNOWN:
2717 /* check for .com or .bat extension */
2718 if ((p = strrchrW( name, '.' )))
2720 if (!strcmpiW( p, comW ) || !strcmpiW( p, pifW ))
2722 TRACE( "starting %s as DOS binary\n", debugstr_w(name) );
2723 binary_info.type = BINARY_WIN16;
2724 binary_info.arch = IMAGE_FILE_MACHINE_I386;
2725 retv = create_vdm_process( name, tidy_cmdline, envW, cur_dir, process_attr, thread_attr,
2726 inherit, flags, startup_info, info, unixdir,
2727 &binary_info, FALSE );
2728 break;
2730 if (!strcmpiW( p, batW ) || !strcmpiW( p, cmdW ) )
2732 TRACE( "starting %s as batch binary\n", debugstr_w(name) );
2733 retv = create_cmd_process( name, tidy_cmdline, envW, cur_dir, process_attr, thread_attr,
2734 inherit, flags, startup_info, info );
2735 break;
2738 /* fall through */
2739 case BINARY_UNIX_EXE:
2741 /* unknown file, try as unix executable */
2742 char *unix_name;
2744 TRACE( "starting %s as Unix binary\n", debugstr_w(name) );
2746 if ((unix_name = wine_get_unix_file_name( name )))
2748 retv = (fork_and_exec( unix_name, tidy_cmdline, envW, unixdir, flags, startup_info ) != -1);
2749 HeapFree( GetProcessHeap(), 0, unix_name );
2752 break;
2754 if (hFile) CloseHandle( hFile );
2756 done:
2757 if (tidy_cmdline != cmd_line) HeapFree( GetProcessHeap(), 0, tidy_cmdline );
2758 if (envW != env) HeapFree( GetProcessHeap(), 0, envW );
2759 HeapFree( GetProcessHeap(), 0, unixdir );
2760 if (retv)
2761 TRACE( "started process pid %04x tid %04x\n", info->dwProcessId, info->dwThreadId );
2762 return retv;
2766 /**********************************************************************
2767 * CreateProcessA (KERNEL32.@)
2769 BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessA( LPCSTR app_name, LPSTR cmd_line, LPSECURITY_ATTRIBUTES process_attr,
2770 LPSECURITY_ATTRIBUTES thread_attr, BOOL inherit,
2771 DWORD flags, LPVOID env, LPCSTR cur_dir,
2772 LPSTARTUPINFOA startup_info, LPPROCESS_INFORMATION info )
2774 BOOL ret = FALSE;
2775 WCHAR *app_nameW = NULL, *cmd_lineW = NULL, *cur_dirW = NULL;
2776 UNICODE_STRING desktopW, titleW;
2777 STARTUPINFOW infoW;
2779 desktopW.Buffer = NULL;
2780 titleW.Buffer = NULL;
2781 if (app_name && !(app_nameW = FILE_name_AtoW( app_name, TRUE ))) goto done;
2782 if (cmd_line && !(cmd_lineW = FILE_name_AtoW( cmd_line, TRUE ))) goto done;
2783 if (cur_dir && !(cur_dirW = FILE_name_AtoW( cur_dir, TRUE ))) goto done;
2785 if (startup_info->lpDesktop) RtlCreateUnicodeStringFromAsciiz( &desktopW, startup_info->lpDesktop );
2786 if (startup_info->lpTitle) RtlCreateUnicodeStringFromAsciiz( &titleW, startup_info->lpTitle );
2788 memcpy( &infoW, startup_info, sizeof(infoW) );
2789 infoW.lpDesktop = desktopW.Buffer;
2790 infoW.lpTitle = titleW.Buffer;
2792 if (startup_info->lpReserved)
2793 FIXME("StartupInfo.lpReserved is used, please report (%s)\n",
2794 debugstr_a(startup_info->lpReserved));
2796 ret = create_process_impl( app_nameW, cmd_lineW, process_attr, thread_attr,
2797 inherit, flags, env, cur_dirW, &infoW, info );
2798 done:
2799 HeapFree( GetProcessHeap(), 0, app_nameW );
2800 HeapFree( GetProcessHeap(), 0, cmd_lineW );
2801 HeapFree( GetProcessHeap(), 0, cur_dirW );
2802 RtlFreeUnicodeString( &desktopW );
2803 RtlFreeUnicodeString( &titleW );
2804 return ret;
2808 /**********************************************************************
2809 * CreateProcessW (KERNEL32.@)
2811 BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessW( LPCWSTR app_name, LPWSTR cmd_line, LPSECURITY_ATTRIBUTES process_attr,
2812 LPSECURITY_ATTRIBUTES thread_attr, BOOL inherit, DWORD flags,
2813 LPVOID env, LPCWSTR cur_dir, LPSTARTUPINFOW startup_info,
2814 LPPROCESS_INFORMATION info )
2816 return create_process_impl( app_name, cmd_line, process_attr, thread_attr,
2817 inherit, flags, env, cur_dir, startup_info, info);
2821 /**********************************************************************
2822 * exec_process
2824 static void exec_process( LPCWSTR name )
2826 HANDLE hFile;
2827 WCHAR *p;
2828 STARTUPINFOW startup_info;
2829 PROCESS_INFORMATION info;
2830 struct binary_info binary_info;
2832 hFile = open_exe_file( name, &binary_info );
2833 if (!hFile || hFile == INVALID_HANDLE_VALUE) return;
2835 memset( &startup_info, 0, sizeof(startup_info) );
2836 startup_info.cb = sizeof(startup_info);
2838 /* Determine executable type */
2840 if (binary_info.flags & BINARY_FLAG_DLL)
2842 CloseHandle( hFile );
2843 return;
2846 switch (binary_info.type)
2848 case BINARY_PE:
2849 TRACE( "starting %s as Win%d binary (%s-%s, arch %04x)\n",
2850 debugstr_w(name), (binary_info.flags & BINARY_FLAG_64BIT) ? 64 : 32,
2851 wine_dbgstr_longlong(binary_info.res_start), wine_dbgstr_longlong(binary_info.res_end),
2852 binary_info.arch );
2853 create_process( hFile, name, GetCommandLineW(), NULL, NULL, NULL, NULL,
2854 FALSE, 0, &startup_info, &info, NULL, &binary_info, TRUE );
2855 break;
2856 case BINARY_UNIX_LIB:
2857 TRACE( "%s is a Unix library, starting as Winelib app\n", debugstr_w(name) );
2858 create_process( hFile, name, GetCommandLineW(), NULL, NULL, NULL, NULL,
2859 FALSE, 0, &startup_info, &info, NULL, &binary_info, TRUE );
2860 break;
2861 case BINARY_UNKNOWN:
2862 /* check for .com or .pif extension */
2863 if (!(p = strrchrW( name, '.' ))) break;
2864 if (strcmpiW( p, comW ) && strcmpiW( p, pifW )) break;
2865 binary_info.type = BINARY_WIN16;
2866 binary_info.arch = IMAGE_FILE_MACHINE_I386;
2867 /* fall through */
2868 case BINARY_WIN16:
2869 TRACE( "starting %s as Win16/DOS binary\n", debugstr_w(name) );
2870 create_vdm_process( name, GetCommandLineW(), NULL, NULL, NULL, NULL,
2871 FALSE, 0, &startup_info, &info, NULL, &binary_info, TRUE );
2872 break;
2873 default:
2874 break;
2876 CloseHandle( hFile );
2880 /***********************************************************************
2881 * wait_input_idle
2883 * Wrapper to call WaitForInputIdle USER function
2885 typedef DWORD (WINAPI *WaitForInputIdle_ptr)( HANDLE hProcess, DWORD dwTimeOut );
2887 static DWORD wait_input_idle( HANDLE process, DWORD timeout )
2889 HMODULE mod = GetModuleHandleA( "user32.dll" );
2890 if (mod)
2892 WaitForInputIdle_ptr ptr = (WaitForInputIdle_ptr)GetProcAddress( mod, "WaitForInputIdle" );
2893 if (ptr) return ptr( process, timeout );
2895 return 0;
2899 /***********************************************************************
2900 * WinExec (KERNEL32.@)
2902 UINT WINAPI DECLSPEC_HOTPATCH WinExec( LPCSTR lpCmdLine, UINT nCmdShow )
2904 PROCESS_INFORMATION info;
2905 STARTUPINFOA startup;
2906 char *cmdline;
2907 UINT ret;
2909 memset( &startup, 0, sizeof(startup) );
2910 startup.cb = sizeof(startup);
2911 startup.dwFlags = STARTF_USESHOWWINDOW;
2912 startup.wShowWindow = nCmdShow;
2914 /* cmdline needs to be writable for CreateProcess */
2915 if (!(cmdline = HeapAlloc( GetProcessHeap(), 0, strlen(lpCmdLine)+1 ))) return 0;
2916 strcpy( cmdline, lpCmdLine );
2918 if (CreateProcessA( NULL, cmdline, NULL, NULL, FALSE,
2919 0, NULL, NULL, &startup, &info ))
2921 /* Give 30 seconds to the app to come up */
2922 if (wait_input_idle( info.hProcess, 30000 ) == WAIT_FAILED)
2923 WARN("WaitForInputIdle failed: Error %d\n", GetLastError() );
2924 ret = 33;
2925 /* Close off the handles */
2926 CloseHandle( info.hThread );
2927 CloseHandle( info.hProcess );
2929 else if ((ret = GetLastError()) >= 32)
2931 FIXME("Strange error set by CreateProcess: %d\n", ret );
2932 ret = 11;
2934 HeapFree( GetProcessHeap(), 0, cmdline );
2935 return ret;
2939 /**********************************************************************
2940 * LoadModule (KERNEL32.@)
2942 DWORD WINAPI LoadModule( LPCSTR name, LPVOID paramBlock )
2944 LOADPARMS32 *params = paramBlock;
2945 PROCESS_INFORMATION info;
2946 STARTUPINFOA startup;
2947 DWORD ret;
2948 LPSTR cmdline, p;
2949 char filename[MAX_PATH];
2950 BYTE len;
2952 if (!name) return ERROR_FILE_NOT_FOUND;
2954 if (!SearchPathA( NULL, name, ".exe", sizeof(filename), filename, NULL ) &&
2955 !SearchPathA( NULL, name, NULL, sizeof(filename), filename, NULL ))
2956 return GetLastError();
2958 len = (BYTE)params->lpCmdLine[0];
2959 if (!(cmdline = HeapAlloc( GetProcessHeap(), 0, strlen(filename) + len + 2 )))
2960 return ERROR_NOT_ENOUGH_MEMORY;
2962 strcpy( cmdline, filename );
2963 p = cmdline + strlen(cmdline);
2964 *p++ = ' ';
2965 memcpy( p, params->lpCmdLine + 1, len );
2966 p[len] = 0;
2968 memset( &startup, 0, sizeof(startup) );
2969 startup.cb = sizeof(startup);
2970 if (params->lpCmdShow)
2972 startup.dwFlags = STARTF_USESHOWWINDOW;
2973 startup.wShowWindow = ((WORD *)params->lpCmdShow)[1];
2976 if (CreateProcessA( filename, cmdline, NULL, NULL, FALSE, 0,
2977 params->lpEnvAddress, NULL, &startup, &info ))
2979 /* Give 30 seconds to the app to come up */
2980 if (wait_input_idle( info.hProcess, 30000 ) == WAIT_FAILED)
2981 WARN("WaitForInputIdle failed: Error %d\n", GetLastError() );
2982 ret = 33;
2983 /* Close off the handles */
2984 CloseHandle( info.hThread );
2985 CloseHandle( info.hProcess );
2987 else if ((ret = GetLastError()) >= 32)
2989 FIXME("Strange error set by CreateProcess: %u\n", ret );
2990 ret = 11;
2993 HeapFree( GetProcessHeap(), 0, cmdline );
2994 return ret;
2998 /******************************************************************************
2999 * TerminateProcess (KERNEL32.@)
3001 * Terminates a process.
3003 * PARAMS
3004 * handle [I] Process to terminate.
3005 * exit_code [I] Exit code.
3007 * RETURNS
3008 * Success: TRUE.
3009 * Failure: FALSE, check GetLastError().
3011 BOOL WINAPI TerminateProcess( HANDLE handle, DWORD exit_code )
3013 NTSTATUS status;
3015 if (!handle)
3017 SetLastError( ERROR_INVALID_HANDLE );
3018 return FALSE;
3021 status = NtTerminateProcess( handle, exit_code );
3022 if (status) SetLastError( RtlNtStatusToDosError(status) );
3023 return !status;
3026 /***********************************************************************
3027 * ExitProcess (KERNEL32.@)
3029 * Exits the current process.
3031 * PARAMS
3032 * status [I] Status code to exit with.
3034 * RETURNS
3035 * Nothing.
3037 #ifdef __i386__
3038 __ASM_STDCALL_FUNC( ExitProcess, 4, /* Shrinker depend on this particular ExitProcess implementation */
3039 "pushl %ebp\n\t"
3040 ".byte 0x8B, 0xEC\n\t" /* movl %esp, %ebp */
3041 ".byte 0x6A, 0x00\n\t" /* pushl $0 */
3042 ".byte 0x68, 0x00, 0x00, 0x00, 0x00\n\t" /* pushl $0 - 4 bytes immediate */
3043 "pushl 8(%ebp)\n\t"
3044 "call " __ASM_NAME("RtlExitUserProcess") __ASM_STDCALL(4) "\n\t"
3045 "leave\n\t"
3046 "ret $4" )
3047 #else
3049 void WINAPI ExitProcess( DWORD status )
3051 RtlExitUserProcess( status );
3054 #endif
3056 /***********************************************************************
3057 * GetExitCodeProcess [KERNEL32.@]
3059 * Gets termination status of specified process.
3061 * PARAMS
3062 * hProcess [in] Handle to the process.
3063 * lpExitCode [out] Address to receive termination status.
3065 * RETURNS
3066 * Success: TRUE
3067 * Failure: FALSE
3069 BOOL WINAPI GetExitCodeProcess( HANDLE hProcess, LPDWORD lpExitCode )
3071 NTSTATUS status;
3072 PROCESS_BASIC_INFORMATION pbi;
3074 status = NtQueryInformationProcess(hProcess, ProcessBasicInformation, &pbi,
3075 sizeof(pbi), NULL);
3076 if (status == STATUS_SUCCESS)
3078 if (lpExitCode) *lpExitCode = pbi.ExitStatus;
3079 return TRUE;
3081 SetLastError( RtlNtStatusToDosError(status) );
3082 return FALSE;
3086 /***********************************************************************
3087 * SetErrorMode (KERNEL32.@)
3089 UINT WINAPI SetErrorMode( UINT mode )
3091 UINT old;
3093 NtQueryInformationProcess( GetCurrentProcess(), ProcessDefaultHardErrorMode,
3094 &old, sizeof(old), NULL );
3095 NtSetInformationProcess( GetCurrentProcess(), ProcessDefaultHardErrorMode,
3096 &mode, sizeof(mode) );
3097 return old;
3100 /***********************************************************************
3101 * GetErrorMode (KERNEL32.@)
3103 UINT WINAPI GetErrorMode( void )
3105 UINT mode;
3107 NtQueryInformationProcess( GetCurrentProcess(), ProcessDefaultHardErrorMode,
3108 &mode, sizeof(mode), NULL );
3109 return mode;
3112 /**********************************************************************
3113 * TlsAlloc [KERNEL32.@]
3115 * Allocates a thread local storage index.
3117 * RETURNS
3118 * Success: TLS index.
3119 * Failure: 0xFFFFFFFF
3121 DWORD WINAPI TlsAlloc( void )
3123 DWORD index;
3124 PEB * const peb = NtCurrentTeb()->Peb;
3126 RtlAcquirePebLock();
3127 index = RtlFindClearBitsAndSet( peb->TlsBitmap, 1, 1 );
3128 if (index != ~0U) NtCurrentTeb()->TlsSlots[index] = 0; /* clear the value */
3129 else
3131 index = RtlFindClearBitsAndSet( peb->TlsExpansionBitmap, 1, 0 );
3132 if (index != ~0U)
3134 if (!NtCurrentTeb()->TlsExpansionSlots &&
3135 !(NtCurrentTeb()->TlsExpansionSlots = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
3136 8 * sizeof(peb->TlsExpansionBitmapBits) * sizeof(void*) )))
3138 RtlClearBits( peb->TlsExpansionBitmap, index, 1 );
3139 index = ~0U;
3140 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
3142 else
3144 NtCurrentTeb()->TlsExpansionSlots[index] = 0; /* clear the value */
3145 index += TLS_MINIMUM_AVAILABLE;
3148 else SetLastError( ERROR_NO_MORE_ITEMS );
3150 RtlReleasePebLock();
3151 return index;
3155 /**********************************************************************
3156 * TlsFree [KERNEL32.@]
3158 * Releases a thread local storage index, making it available for reuse.
3160 * PARAMS
3161 * index [in] TLS index to free.
3163 * RETURNS
3164 * Success: TRUE
3165 * Failure: FALSE
3167 BOOL WINAPI TlsFree( DWORD index )
3169 BOOL ret;
3171 RtlAcquirePebLock();
3172 if (index >= TLS_MINIMUM_AVAILABLE)
3174 ret = RtlAreBitsSet( NtCurrentTeb()->Peb->TlsExpansionBitmap, index - TLS_MINIMUM_AVAILABLE, 1 );
3175 if (ret) RtlClearBits( NtCurrentTeb()->Peb->TlsExpansionBitmap, index - TLS_MINIMUM_AVAILABLE, 1 );
3177 else
3179 ret = RtlAreBitsSet( NtCurrentTeb()->Peb->TlsBitmap, index, 1 );
3180 if (ret) RtlClearBits( NtCurrentTeb()->Peb->TlsBitmap, index, 1 );
3182 if (ret) NtSetInformationThread( GetCurrentThread(), ThreadZeroTlsCell, &index, sizeof(index) );
3183 else SetLastError( ERROR_INVALID_PARAMETER );
3184 RtlReleasePebLock();
3185 return ret;
3189 /**********************************************************************
3190 * TlsGetValue [KERNEL32.@]
3192 * Gets value in a thread's TLS slot.
3194 * PARAMS
3195 * index [in] TLS index to retrieve value for.
3197 * RETURNS
3198 * Success: Value stored in calling thread's TLS slot for index.
3199 * Failure: 0 and GetLastError() returns NO_ERROR.
3201 LPVOID WINAPI TlsGetValue( DWORD index )
3203 LPVOID ret;
3205 if (index < TLS_MINIMUM_AVAILABLE)
3207 ret = NtCurrentTeb()->TlsSlots[index];
3209 else
3211 index -= TLS_MINIMUM_AVAILABLE;
3212 if (index >= 8 * sizeof(NtCurrentTeb()->Peb->TlsExpansionBitmapBits))
3214 SetLastError( ERROR_INVALID_PARAMETER );
3215 return NULL;
3217 if (!NtCurrentTeb()->TlsExpansionSlots) ret = NULL;
3218 else ret = NtCurrentTeb()->TlsExpansionSlots[index];
3220 SetLastError( ERROR_SUCCESS );
3221 return ret;
3225 /**********************************************************************
3226 * TlsSetValue [KERNEL32.@]
3228 * Stores a value in the thread's TLS slot.
3230 * PARAMS
3231 * index [in] TLS index to set value for.
3232 * value [in] Value to be stored.
3234 * RETURNS
3235 * Success: TRUE
3236 * Failure: FALSE
3238 BOOL WINAPI TlsSetValue( DWORD index, LPVOID value )
3240 if (index < TLS_MINIMUM_AVAILABLE)
3242 NtCurrentTeb()->TlsSlots[index] = value;
3244 else
3246 index -= TLS_MINIMUM_AVAILABLE;
3247 if (index >= 8 * sizeof(NtCurrentTeb()->Peb->TlsExpansionBitmapBits))
3249 SetLastError( ERROR_INVALID_PARAMETER );
3250 return FALSE;
3252 if (!NtCurrentTeb()->TlsExpansionSlots &&
3253 !(NtCurrentTeb()->TlsExpansionSlots = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
3254 8 * sizeof(NtCurrentTeb()->Peb->TlsExpansionBitmapBits) * sizeof(void*) )))
3256 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
3257 return FALSE;
3259 NtCurrentTeb()->TlsExpansionSlots[index] = value;
3261 return TRUE;
3265 /***********************************************************************
3266 * GetProcessFlags (KERNEL32.@)
3268 DWORD WINAPI GetProcessFlags( DWORD processid )
3270 IMAGE_NT_HEADERS *nt;
3271 DWORD flags = 0;
3273 if (processid && processid != GetCurrentProcessId()) return 0;
3275 if ((nt = RtlImageNtHeader( NtCurrentTeb()->Peb->ImageBaseAddress )))
3277 if (nt->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI)
3278 flags |= PDB32_CONSOLE_PROC;
3280 if (!AreFileApisANSI()) flags |= PDB32_FILE_APIS_OEM;
3281 if (IsDebuggerPresent()) flags |= PDB32_DEBUGGED;
3282 return flags;
3286 /*********************************************************************
3287 * OpenProcess (KERNEL32.@)
3289 * Opens a handle to a process.
3291 * PARAMS
3292 * access [I] Desired access rights assigned to the returned handle.
3293 * inherit [I] Determines whether or not child processes will inherit the handle.
3294 * id [I] Process identifier of the process to get a handle to.
3296 * RETURNS
3297 * Success: Valid handle to the specified process.
3298 * Failure: NULL, check GetLastError().
3300 HANDLE WINAPI OpenProcess( DWORD access, BOOL inherit, DWORD id )
3302 NTSTATUS status;
3303 HANDLE handle;
3304 OBJECT_ATTRIBUTES attr;
3305 CLIENT_ID cid;
3307 cid.UniqueProcess = ULongToHandle(id);
3308 cid.UniqueThread = 0; /* FIXME ? */
3310 attr.Length = sizeof(OBJECT_ATTRIBUTES);
3311 attr.RootDirectory = NULL;
3312 attr.Attributes = inherit ? OBJ_INHERIT : 0;
3313 attr.SecurityDescriptor = NULL;
3314 attr.SecurityQualityOfService = NULL;
3315 attr.ObjectName = NULL;
3317 if (GetVersion() & 0x80000000) access = PROCESS_ALL_ACCESS;
3319 status = NtOpenProcess(&handle, access, &attr, &cid);
3320 if (status != STATUS_SUCCESS)
3322 SetLastError( RtlNtStatusToDosError(status) );
3323 return NULL;
3325 return handle;
3329 /*********************************************************************
3330 * GetProcessId (KERNEL32.@)
3332 * Gets the a unique identifier of a process.
3334 * PARAMS
3335 * hProcess [I] Handle to the process.
3337 * RETURNS
3338 * Success: TRUE.
3339 * Failure: FALSE, check GetLastError().
3341 * NOTES
3343 * The identifier is unique only on the machine and only until the process
3344 * exits (including system shutdown).
3346 DWORD WINAPI GetProcessId( HANDLE hProcess )
3348 NTSTATUS status;
3349 PROCESS_BASIC_INFORMATION pbi;
3351 status = NtQueryInformationProcess(hProcess, ProcessBasicInformation, &pbi,
3352 sizeof(pbi), NULL);
3353 if (status == STATUS_SUCCESS) return pbi.UniqueProcessId;
3354 SetLastError( RtlNtStatusToDosError(status) );
3355 return 0;
3359 /*********************************************************************
3360 * CloseHandle (KERNEL32.@)
3362 * Closes a handle.
3364 * PARAMS
3365 * handle [I] Handle to close.
3367 * RETURNS
3368 * Success: TRUE.
3369 * Failure: FALSE, check GetLastError().
3371 BOOL WINAPI CloseHandle( HANDLE handle )
3373 NTSTATUS status;
3375 /* stdio handles need special treatment */
3376 if (handle == (HANDLE)STD_INPUT_HANDLE)
3377 handle = InterlockedExchangePointer( &NtCurrentTeb()->Peb->ProcessParameters->hStdInput, 0 );
3378 else if (handle == (HANDLE)STD_OUTPUT_HANDLE)
3379 handle = InterlockedExchangePointer( &NtCurrentTeb()->Peb->ProcessParameters->hStdOutput, 0 );
3380 else if (handle == (HANDLE)STD_ERROR_HANDLE)
3381 handle = InterlockedExchangePointer( &NtCurrentTeb()->Peb->ProcessParameters->hStdError, 0 );
3383 if (is_console_handle(handle))
3384 return CloseConsoleHandle(handle);
3386 status = NtClose( handle );
3387 if (status) SetLastError( RtlNtStatusToDosError(status) );
3388 return !status;
3392 /*********************************************************************
3393 * GetHandleInformation (KERNEL32.@)
3395 BOOL WINAPI GetHandleInformation( HANDLE handle, LPDWORD flags )
3397 OBJECT_DATA_INFORMATION info;
3398 NTSTATUS status = NtQueryObject( handle, ObjectDataInformation, &info, sizeof(info), NULL );
3400 if (status) SetLastError( RtlNtStatusToDosError(status) );
3401 else if (flags)
3403 *flags = 0;
3404 if (info.InheritHandle) *flags |= HANDLE_FLAG_INHERIT;
3405 if (info.ProtectFromClose) *flags |= HANDLE_FLAG_PROTECT_FROM_CLOSE;
3407 return !status;
3411 /*********************************************************************
3412 * SetHandleInformation (KERNEL32.@)
3414 BOOL WINAPI SetHandleInformation( HANDLE handle, DWORD mask, DWORD flags )
3416 OBJECT_DATA_INFORMATION info;
3417 NTSTATUS status;
3419 /* if not setting both fields, retrieve current value first */
3420 if ((mask & (HANDLE_FLAG_INHERIT | HANDLE_FLAG_PROTECT_FROM_CLOSE)) !=
3421 (HANDLE_FLAG_INHERIT | HANDLE_FLAG_PROTECT_FROM_CLOSE))
3423 if ((status = NtQueryObject( handle, ObjectDataInformation, &info, sizeof(info), NULL )))
3425 SetLastError( RtlNtStatusToDosError(status) );
3426 return FALSE;
3429 if (mask & HANDLE_FLAG_INHERIT)
3430 info.InheritHandle = (flags & HANDLE_FLAG_INHERIT) != 0;
3431 if (mask & HANDLE_FLAG_PROTECT_FROM_CLOSE)
3432 info.ProtectFromClose = (flags & HANDLE_FLAG_PROTECT_FROM_CLOSE) != 0;
3434 status = NtSetInformationObject( handle, ObjectDataInformation, &info, sizeof(info) );
3435 if (status) SetLastError( RtlNtStatusToDosError(status) );
3436 return !status;
3440 /*********************************************************************
3441 * DuplicateHandle (KERNEL32.@)
3443 BOOL WINAPI DuplicateHandle( HANDLE source_process, HANDLE source,
3444 HANDLE dest_process, HANDLE *dest,
3445 DWORD access, BOOL inherit, DWORD options )
3447 NTSTATUS status;
3449 if (is_console_handle(source))
3451 /* FIXME: this test is not sufficient, we need to test process ids, not handles */
3452 if (source_process != dest_process ||
3453 source_process != GetCurrentProcess())
3455 SetLastError(ERROR_INVALID_PARAMETER);
3456 return FALSE;
3458 *dest = DuplicateConsoleHandle( source, access, inherit, options );
3459 return (*dest != INVALID_HANDLE_VALUE);
3461 status = NtDuplicateObject( source_process, source, dest_process, dest,
3462 access, inherit ? OBJ_INHERIT : 0, options );
3463 if (status) SetLastError( RtlNtStatusToDosError(status) );
3464 return !status;
3468 /***********************************************************************
3469 * ConvertToGlobalHandle (KERNEL32.@)
3471 HANDLE WINAPI ConvertToGlobalHandle(HANDLE hSrc)
3473 HANDLE ret = INVALID_HANDLE_VALUE;
3474 DuplicateHandle( GetCurrentProcess(), hSrc, GetCurrentProcess(), &ret, 0, FALSE,
3475 DUP_HANDLE_MAKE_GLOBAL | DUP_HANDLE_SAME_ACCESS | DUP_HANDLE_CLOSE_SOURCE );
3476 return ret;
3480 /***********************************************************************
3481 * SetHandleContext (KERNEL32.@)
3483 BOOL WINAPI SetHandleContext(HANDLE hnd,DWORD context)
3485 FIXME("(%p,%d), stub. In case this got called by WSOCK32/WS2_32: "
3486 "the external WINSOCK DLLs won't work with WINE, don't use them.\n",hnd,context);
3487 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3488 return FALSE;
3492 /***********************************************************************
3493 * GetHandleContext (KERNEL32.@)
3495 DWORD WINAPI GetHandleContext(HANDLE hnd)
3497 FIXME("(%p), stub. In case this got called by WSOCK32/WS2_32: "
3498 "the external WINSOCK DLLs won't work with WINE, don't use them.\n",hnd);
3499 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3500 return 0;
3504 /***********************************************************************
3505 * CreateSocketHandle (KERNEL32.@)
3507 HANDLE WINAPI CreateSocketHandle(void)
3509 FIXME("(), stub. In case this got called by WSOCK32/WS2_32: "
3510 "the external WINSOCK DLLs won't work with WINE, don't use them.\n");
3511 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3512 return INVALID_HANDLE_VALUE;
3516 /***********************************************************************
3517 * SetPriorityClass (KERNEL32.@)
3519 BOOL WINAPI SetPriorityClass( HANDLE hprocess, DWORD priorityclass )
3521 NTSTATUS status;
3522 PROCESS_PRIORITY_CLASS ppc;
3524 ppc.Foreground = FALSE;
3525 switch (priorityclass)
3527 case IDLE_PRIORITY_CLASS:
3528 ppc.PriorityClass = PROCESS_PRIOCLASS_IDLE; break;
3529 case BELOW_NORMAL_PRIORITY_CLASS:
3530 ppc.PriorityClass = PROCESS_PRIOCLASS_BELOW_NORMAL; break;
3531 case NORMAL_PRIORITY_CLASS:
3532 ppc.PriorityClass = PROCESS_PRIOCLASS_NORMAL; break;
3533 case ABOVE_NORMAL_PRIORITY_CLASS:
3534 ppc.PriorityClass = PROCESS_PRIOCLASS_ABOVE_NORMAL; break;
3535 case HIGH_PRIORITY_CLASS:
3536 ppc.PriorityClass = PROCESS_PRIOCLASS_HIGH; break;
3537 case REALTIME_PRIORITY_CLASS:
3538 ppc.PriorityClass = PROCESS_PRIOCLASS_REALTIME; break;
3539 default:
3540 SetLastError(ERROR_INVALID_PARAMETER);
3541 return FALSE;
3544 status = NtSetInformationProcess(hprocess, ProcessPriorityClass,
3545 &ppc, sizeof(ppc));
3547 if (status != STATUS_SUCCESS)
3549 SetLastError( RtlNtStatusToDosError(status) );
3550 return FALSE;
3552 return TRUE;
3556 /***********************************************************************
3557 * GetPriorityClass (KERNEL32.@)
3559 DWORD WINAPI GetPriorityClass(HANDLE hProcess)
3561 NTSTATUS status;
3562 PROCESS_BASIC_INFORMATION pbi;
3564 status = NtQueryInformationProcess(hProcess, ProcessBasicInformation, &pbi,
3565 sizeof(pbi), NULL);
3566 if (status != STATUS_SUCCESS)
3568 SetLastError( RtlNtStatusToDosError(status) );
3569 return 0;
3571 switch (pbi.BasePriority)
3573 case PROCESS_PRIOCLASS_IDLE: return IDLE_PRIORITY_CLASS;
3574 case PROCESS_PRIOCLASS_BELOW_NORMAL: return BELOW_NORMAL_PRIORITY_CLASS;
3575 case PROCESS_PRIOCLASS_NORMAL: return NORMAL_PRIORITY_CLASS;
3576 case PROCESS_PRIOCLASS_ABOVE_NORMAL: return ABOVE_NORMAL_PRIORITY_CLASS;
3577 case PROCESS_PRIOCLASS_HIGH: return HIGH_PRIORITY_CLASS;
3578 case PROCESS_PRIOCLASS_REALTIME: return REALTIME_PRIORITY_CLASS;
3580 SetLastError( ERROR_INVALID_PARAMETER );
3581 return 0;
3585 /***********************************************************************
3586 * SetProcessAffinityMask (KERNEL32.@)
3588 BOOL WINAPI SetProcessAffinityMask( HANDLE hProcess, DWORD_PTR affmask )
3590 NTSTATUS status;
3592 status = NtSetInformationProcess(hProcess, ProcessAffinityMask,
3593 &affmask, sizeof(DWORD_PTR));
3594 if (status)
3596 SetLastError( RtlNtStatusToDosError(status) );
3597 return FALSE;
3599 return TRUE;
3603 /**********************************************************************
3604 * GetProcessAffinityMask (KERNEL32.@)
3606 BOOL WINAPI GetProcessAffinityMask( HANDLE hProcess, PDWORD_PTR process_mask, PDWORD_PTR system_mask )
3608 NTSTATUS status = STATUS_SUCCESS;
3610 if (process_mask)
3612 if ((status = NtQueryInformationProcess( hProcess, ProcessAffinityMask,
3613 process_mask, sizeof(*process_mask), NULL )))
3614 SetLastError( RtlNtStatusToDosError(status) );
3616 if (system_mask && status == STATUS_SUCCESS)
3618 SYSTEM_BASIC_INFORMATION info;
3620 if ((status = NtQuerySystemInformation( SystemBasicInformation, &info, sizeof(info), NULL )))
3621 SetLastError( RtlNtStatusToDosError(status) );
3622 else
3623 *system_mask = info.ActiveProcessorsAffinityMask;
3625 return !status;
3629 /***********************************************************************
3630 * SetProcessAffinityUpdateMode (KERNEL32.@)
3632 BOOL WINAPI SetProcessAffinityUpdateMode( HANDLE process, DWORD flags )
3634 FIXME("(%p,0x%08x): stub\n", process, flags);
3635 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
3636 return FALSE;
3640 /***********************************************************************
3641 * GetProcessVersion (KERNEL32.@)
3643 DWORD WINAPI GetProcessVersion( DWORD pid )
3645 HANDLE process;
3646 NTSTATUS status;
3647 PROCESS_BASIC_INFORMATION pbi;
3648 SIZE_T count;
3649 PEB peb;
3650 IMAGE_DOS_HEADER dos;
3651 IMAGE_NT_HEADERS nt;
3652 DWORD ver = 0;
3654 if (!pid || pid == GetCurrentProcessId())
3656 IMAGE_NT_HEADERS *pnt;
3658 if ((pnt = RtlImageNtHeader( NtCurrentTeb()->Peb->ImageBaseAddress )))
3659 return ((pnt->OptionalHeader.MajorSubsystemVersion << 16) |
3660 pnt->OptionalHeader.MinorSubsystemVersion);
3661 return 0;
3664 process = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, pid);
3665 if (!process) return 0;
3667 status = NtQueryInformationProcess(process, ProcessBasicInformation, &pbi, sizeof(pbi), NULL);
3668 if (status) goto err;
3670 status = NtReadVirtualMemory(process, pbi.PebBaseAddress, &peb, sizeof(peb), &count);
3671 if (status || count != sizeof(peb)) goto err;
3673 memset(&dos, 0, sizeof(dos));
3674 status = NtReadVirtualMemory(process, peb.ImageBaseAddress, &dos, sizeof(dos), &count);
3675 if (status || count != sizeof(dos)) goto err;
3676 if (dos.e_magic != IMAGE_DOS_SIGNATURE) goto err;
3678 memset(&nt, 0, sizeof(nt));
3679 status = NtReadVirtualMemory(process, (char *)peb.ImageBaseAddress + dos.e_lfanew, &nt, sizeof(nt), &count);
3680 if (status || count != sizeof(nt)) goto err;
3681 if (nt.Signature != IMAGE_NT_SIGNATURE) goto err;
3683 ver = MAKELONG(nt.OptionalHeader.MinorSubsystemVersion, nt.OptionalHeader.MajorSubsystemVersion);
3685 err:
3686 CloseHandle(process);
3688 if (status != STATUS_SUCCESS)
3689 SetLastError(RtlNtStatusToDosError(status));
3691 return ver;
3695 /***********************************************************************
3696 * SetProcessWorkingSetSizeEx [KERNEL32.@]
3697 * Sets the min/max working set sizes for a specified process.
3699 * PARAMS
3700 * process [I] Handle to the process of interest
3701 * minset [I] Specifies minimum working set size
3702 * maxset [I] Specifies maximum working set size
3703 * flags [I] Flags to enforce working set sizes
3705 * RETURNS
3706 * Success: TRUE
3707 * Failure: FALSE
3709 BOOL WINAPI SetProcessWorkingSetSizeEx(HANDLE process, SIZE_T minset, SIZE_T maxset, DWORD flags)
3711 WARN("(%p,%ld,%ld,%x): stub - harmless\n", process, minset, maxset, flags);
3712 if(( minset == (SIZE_T)-1) && (maxset == (SIZE_T)-1)) {
3713 /* Trim the working set to zero */
3714 /* Swap the process out of physical RAM */
3716 return TRUE;
3719 /***********************************************************************
3720 * SetProcessWorkingSetSize [KERNEL32.@]
3721 * Sets the min/max working set sizes for a specified process.
3723 * PARAMS
3724 * process [I] Handle to the process of interest
3725 * minset [I] Specifies minimum working set size
3726 * maxset [I] Specifies maximum working set size
3728 * RETURNS
3729 * Success: TRUE
3730 * Failure: FALSE
3732 BOOL WINAPI SetProcessWorkingSetSize(HANDLE process, SIZE_T minset, SIZE_T maxset)
3734 return SetProcessWorkingSetSizeEx(process, minset, maxset, 0);
3737 /***********************************************************************
3738 * K32EmptyWorkingSet (KERNEL32.@)
3740 BOOL WINAPI K32EmptyWorkingSet(HANDLE hProcess)
3742 return SetProcessWorkingSetSize(hProcess, (SIZE_T)-1, (SIZE_T)-1);
3746 /***********************************************************************
3747 * GetProcessWorkingSetSizeEx (KERNEL32.@)
3749 BOOL WINAPI GetProcessWorkingSetSizeEx(HANDLE process, SIZE_T *minset,
3750 SIZE_T *maxset, DWORD *flags)
3752 FIXME("(%p,%p,%p,%p): stub\n", process, minset, maxset, flags);
3753 /* 32 MB working set size */
3754 if (minset) *minset = 32*1024*1024;
3755 if (maxset) *maxset = 32*1024*1024;
3756 if (flags) *flags = QUOTA_LIMITS_HARDWS_MIN_DISABLE |
3757 QUOTA_LIMITS_HARDWS_MAX_DISABLE;
3758 return TRUE;
3762 /***********************************************************************
3763 * GetProcessWorkingSetSize (KERNEL32.@)
3765 BOOL WINAPI GetProcessWorkingSetSize(HANDLE process, SIZE_T *minset, SIZE_T *maxset)
3767 return GetProcessWorkingSetSizeEx(process, minset, maxset, NULL);
3771 /***********************************************************************
3772 * SetProcessShutdownParameters (KERNEL32.@)
3774 BOOL WINAPI SetProcessShutdownParameters(DWORD level, DWORD flags)
3776 FIXME("(%08x, %08x): partial stub.\n", level, flags);
3777 shutdown_flags = flags;
3778 shutdown_priority = level;
3779 return TRUE;
3783 /***********************************************************************
3784 * GetProcessShutdownParameters (KERNEL32.@)
3787 BOOL WINAPI GetProcessShutdownParameters( LPDWORD lpdwLevel, LPDWORD lpdwFlags )
3789 *lpdwLevel = shutdown_priority;
3790 *lpdwFlags = shutdown_flags;
3791 return TRUE;
3795 /***********************************************************************
3796 * GetProcessPriorityBoost (KERNEL32.@)
3798 BOOL WINAPI GetProcessPriorityBoost(HANDLE hprocess,PBOOL pDisablePriorityBoost)
3800 FIXME("(%p,%p): semi-stub\n", hprocess, pDisablePriorityBoost);
3802 /* Report that no boost is present.. */
3803 *pDisablePriorityBoost = FALSE;
3805 return TRUE;
3808 /***********************************************************************
3809 * SetProcessPriorityBoost (KERNEL32.@)
3811 BOOL WINAPI SetProcessPriorityBoost(HANDLE hprocess,BOOL disableboost)
3813 FIXME("(%p,%d): stub\n",hprocess,disableboost);
3814 /* Say we can do it. I doubt the program will notice that we don't. */
3815 return TRUE;
3819 /***********************************************************************
3820 * ReadProcessMemory (KERNEL32.@)
3822 BOOL WINAPI ReadProcessMemory( HANDLE process, LPCVOID addr, LPVOID buffer, SIZE_T size,
3823 SIZE_T *bytes_read )
3825 NTSTATUS status = NtReadVirtualMemory( process, addr, buffer, size, bytes_read );
3826 if (status) SetLastError( RtlNtStatusToDosError(status) );
3827 return !status;
3831 /***********************************************************************
3832 * WriteProcessMemory (KERNEL32.@)
3834 BOOL WINAPI WriteProcessMemory( HANDLE process, LPVOID addr, LPCVOID buffer, SIZE_T size,
3835 SIZE_T *bytes_written )
3837 NTSTATUS status = NtWriteVirtualMemory( process, addr, buffer, size, bytes_written );
3838 if (status) SetLastError( RtlNtStatusToDosError(status) );
3839 return !status;
3843 /****************************************************************************
3844 * FlushInstructionCache (KERNEL32.@)
3846 BOOL WINAPI FlushInstructionCache(HANDLE hProcess, LPCVOID lpBaseAddress, SIZE_T dwSize)
3848 NTSTATUS status;
3849 status = NtFlushInstructionCache( hProcess, lpBaseAddress, dwSize );
3850 if (status) SetLastError( RtlNtStatusToDosError(status) );
3851 return !status;
3855 /******************************************************************
3856 * GetProcessIoCounters (KERNEL32.@)
3858 BOOL WINAPI GetProcessIoCounters(HANDLE hProcess, PIO_COUNTERS ioc)
3860 NTSTATUS status;
3862 status = NtQueryInformationProcess(hProcess, ProcessIoCounters,
3863 ioc, sizeof(*ioc), NULL);
3864 if (status) SetLastError( RtlNtStatusToDosError(status) );
3865 return !status;
3868 /******************************************************************
3869 * GetProcessHandleCount (KERNEL32.@)
3871 BOOL WINAPI GetProcessHandleCount(HANDLE hProcess, DWORD *cnt)
3873 NTSTATUS status;
3875 status = NtQueryInformationProcess(hProcess, ProcessHandleCount,
3876 cnt, sizeof(*cnt), NULL);
3877 if (status) SetLastError( RtlNtStatusToDosError(status) );
3878 return !status;
3881 /******************************************************************
3882 * QueryFullProcessImageNameA (KERNEL32.@)
3884 BOOL WINAPI QueryFullProcessImageNameA(HANDLE hProcess, DWORD dwFlags, LPSTR lpExeName, PDWORD pdwSize)
3886 BOOL retval;
3887 DWORD pdwSizeW = *pdwSize;
3888 LPWSTR lpExeNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *pdwSize * sizeof(WCHAR));
3890 retval = QueryFullProcessImageNameW(hProcess, dwFlags, lpExeNameW, &pdwSizeW);
3892 if(retval)
3893 retval = (0 != WideCharToMultiByte(CP_ACP, 0, lpExeNameW, -1,
3894 lpExeName, *pdwSize, NULL, NULL));
3895 if(retval)
3896 *pdwSize = strlen(lpExeName);
3898 HeapFree(GetProcessHeap(), 0, lpExeNameW);
3899 return retval;
3902 /******************************************************************
3903 * QueryFullProcessImageNameW (KERNEL32.@)
3905 BOOL WINAPI QueryFullProcessImageNameW(HANDLE hProcess, DWORD dwFlags, LPWSTR lpExeName, PDWORD pdwSize)
3907 BYTE buffer[sizeof(UNICODE_STRING) + MAX_PATH*sizeof(WCHAR)]; /* this buffer should be enough */
3908 UNICODE_STRING *dynamic_buffer = NULL;
3909 UNICODE_STRING *result = NULL;
3910 NTSTATUS status;
3911 DWORD needed;
3913 /* FIXME: On Windows, ProcessImageFileName return an NT path. In Wine it
3914 * is a DOS path and we depend on this. */
3915 status = NtQueryInformationProcess(hProcess, ProcessImageFileName, buffer,
3916 sizeof(buffer) - sizeof(WCHAR), &needed);
3917 if (status == STATUS_INFO_LENGTH_MISMATCH)
3919 dynamic_buffer = HeapAlloc(GetProcessHeap(), 0, needed + sizeof(WCHAR));
3920 status = NtQueryInformationProcess(hProcess, ProcessImageFileName, (LPBYTE)dynamic_buffer, needed, &needed);
3921 result = dynamic_buffer;
3923 else
3924 result = (PUNICODE_STRING)buffer;
3926 if (status) goto cleanup;
3928 if (dwFlags & PROCESS_NAME_NATIVE)
3930 WCHAR drive[3];
3931 WCHAR device[1024];
3932 DWORD ntlen, devlen;
3934 if (result->Buffer[1] != ':' || result->Buffer[0] < 'A' || result->Buffer[0] > 'Z')
3936 /* We cannot convert it to an NT device path so fail */
3937 status = STATUS_NO_SUCH_DEVICE;
3938 goto cleanup;
3941 /* Find this drive's NT device path */
3942 drive[0] = result->Buffer[0];
3943 drive[1] = ':';
3944 drive[2] = 0;
3945 if (!QueryDosDeviceW(drive, device, ARRAY_SIZE(device)))
3947 status = STATUS_NO_SUCH_DEVICE;
3948 goto cleanup;
3951 devlen = lstrlenW(device);
3952 ntlen = devlen + (result->Length/sizeof(WCHAR) - 2);
3953 if (ntlen + 1 > *pdwSize)
3955 status = STATUS_BUFFER_TOO_SMALL;
3956 goto cleanup;
3958 *pdwSize = ntlen;
3960 memcpy(lpExeName, device, devlen * sizeof(*device));
3961 memcpy(lpExeName + devlen, result->Buffer + 2, result->Length - 2 * sizeof(WCHAR));
3962 lpExeName[*pdwSize] = 0;
3963 TRACE("NT path: %s\n", debugstr_w(lpExeName));
3965 else
3967 if (result->Length/sizeof(WCHAR) + 1 > *pdwSize)
3969 status = STATUS_BUFFER_TOO_SMALL;
3970 goto cleanup;
3973 *pdwSize = result->Length/sizeof(WCHAR);
3974 memcpy( lpExeName, result->Buffer, result->Length );
3975 lpExeName[*pdwSize] = 0;
3978 cleanup:
3979 HeapFree(GetProcessHeap(), 0, dynamic_buffer);
3980 if (status) SetLastError( RtlNtStatusToDosError(status) );
3981 return !status;
3984 /***********************************************************************
3985 * K32GetProcessImageFileNameA (KERNEL32.@)
3987 DWORD WINAPI K32GetProcessImageFileNameA( HANDLE process, LPSTR file, DWORD size )
3989 return QueryFullProcessImageNameA(process, PROCESS_NAME_NATIVE, file, &size) ? size : 0;
3992 /***********************************************************************
3993 * K32GetProcessImageFileNameW (KERNEL32.@)
3995 DWORD WINAPI K32GetProcessImageFileNameW( HANDLE process, LPWSTR file, DWORD size )
3997 return QueryFullProcessImageNameW(process, PROCESS_NAME_NATIVE, file, &size) ? size : 0;
4000 /***********************************************************************
4001 * K32EnumProcesses (KERNEL32.@)
4003 BOOL WINAPI K32EnumProcesses(DWORD *lpdwProcessIDs, DWORD cb, DWORD *lpcbUsed)
4005 SYSTEM_PROCESS_INFORMATION *spi;
4006 ULONG size = 0x4000;
4007 void *buf = NULL;
4008 NTSTATUS status;
4010 do {
4011 size *= 2;
4012 HeapFree(GetProcessHeap(), 0, buf);
4013 buf = HeapAlloc(GetProcessHeap(), 0, size);
4014 if (!buf)
4015 return FALSE;
4017 status = NtQuerySystemInformation(SystemProcessInformation, buf, size, NULL);
4018 } while(status == STATUS_INFO_LENGTH_MISMATCH);
4020 if (status != STATUS_SUCCESS)
4022 HeapFree(GetProcessHeap(), 0, buf);
4023 SetLastError(RtlNtStatusToDosError(status));
4024 return FALSE;
4027 spi = buf;
4029 for (*lpcbUsed = 0; cb >= sizeof(DWORD); cb -= sizeof(DWORD))
4031 *lpdwProcessIDs++ = HandleToUlong(spi->UniqueProcessId);
4032 *lpcbUsed += sizeof(DWORD);
4034 if (spi->NextEntryOffset == 0)
4035 break;
4037 spi = (SYSTEM_PROCESS_INFORMATION *)(((PCHAR)spi) + spi->NextEntryOffset);
4040 HeapFree(GetProcessHeap(), 0, buf);
4041 return TRUE;
4044 /***********************************************************************
4045 * K32QueryWorkingSet (KERNEL32.@)
4047 BOOL WINAPI K32QueryWorkingSet( HANDLE process, LPVOID buffer, DWORD size )
4049 NTSTATUS status;
4051 TRACE( "(%p, %p, %d)\n", process, buffer, size );
4053 status = NtQueryVirtualMemory( process, NULL, MemoryWorkingSetList, buffer, size, NULL );
4055 if (status)
4057 SetLastError( RtlNtStatusToDosError( status ) );
4058 return FALSE;
4060 return TRUE;
4063 /***********************************************************************
4064 * K32QueryWorkingSetEx (KERNEL32.@)
4066 BOOL WINAPI K32QueryWorkingSetEx( HANDLE process, LPVOID buffer, DWORD size )
4068 NTSTATUS status;
4070 TRACE( "(%p, %p, %d)\n", process, buffer, size );
4072 status = NtQueryVirtualMemory( process, NULL, MemoryWorkingSetList, buffer, size, NULL );
4074 if (status)
4076 SetLastError( RtlNtStatusToDosError( status ) );
4077 return FALSE;
4079 return TRUE;
4082 /***********************************************************************
4083 * K32GetProcessMemoryInfo (KERNEL32.@)
4085 * Retrieve memory usage information for a given process
4088 BOOL WINAPI K32GetProcessMemoryInfo(HANDLE process,
4089 PPROCESS_MEMORY_COUNTERS pmc, DWORD cb)
4091 NTSTATUS status;
4092 VM_COUNTERS vmc;
4094 if (cb < sizeof(PROCESS_MEMORY_COUNTERS))
4096 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4097 return FALSE;
4100 status = NtQueryInformationProcess(process, ProcessVmCounters,
4101 &vmc, sizeof(vmc), NULL);
4103 if (status)
4105 SetLastError(RtlNtStatusToDosError(status));
4106 return FALSE;
4109 pmc->cb = sizeof(PROCESS_MEMORY_COUNTERS);
4110 pmc->PageFaultCount = vmc.PageFaultCount;
4111 pmc->PeakWorkingSetSize = vmc.PeakWorkingSetSize;
4112 pmc->WorkingSetSize = vmc.WorkingSetSize;
4113 pmc->QuotaPeakPagedPoolUsage = vmc.QuotaPeakPagedPoolUsage;
4114 pmc->QuotaPagedPoolUsage = vmc.QuotaPagedPoolUsage;
4115 pmc->QuotaPeakNonPagedPoolUsage = vmc.QuotaPeakNonPagedPoolUsage;
4116 pmc->QuotaNonPagedPoolUsage = vmc.QuotaNonPagedPoolUsage;
4117 pmc->PagefileUsage = vmc.PagefileUsage;
4118 pmc->PeakPagefileUsage = vmc.PeakPagefileUsage;
4120 return TRUE;
4123 /***********************************************************************
4124 * ProcessIdToSessionId (KERNEL32.@)
4125 * This function is available on Terminal Server 4SP4 and Windows 2000
4127 BOOL WINAPI ProcessIdToSessionId( DWORD procid, DWORD *sessionid_ptr )
4129 if (procid != GetCurrentProcessId())
4130 FIXME("Unsupported for other processes.\n");
4132 *sessionid_ptr = NtCurrentTeb()->Peb->SessionId;
4133 return TRUE;
4137 /***********************************************************************
4138 * RegisterServiceProcess (KERNEL32.@)
4140 * A service process calls this function to ensure that it continues to run
4141 * even after a user logged off.
4143 DWORD WINAPI RegisterServiceProcess(DWORD dwProcessId, DWORD dwType)
4145 /* I don't think that Wine needs to do anything in this function */
4146 return 1; /* success */
4150 /**********************************************************************
4151 * IsWow64Process (KERNEL32.@)
4153 BOOL WINAPI IsWow64Process(HANDLE hProcess, PBOOL Wow64Process)
4155 ULONG_PTR pbi;
4156 NTSTATUS status;
4158 status = NtQueryInformationProcess( hProcess, ProcessWow64Information, &pbi, sizeof(pbi), NULL );
4160 if (status != STATUS_SUCCESS)
4162 SetLastError( RtlNtStatusToDosError( status ) );
4163 return FALSE;
4165 *Wow64Process = (pbi != 0);
4166 return TRUE;
4170 /***********************************************************************
4171 * GetCurrentProcess (KERNEL32.@)
4173 * Get a handle to the current process.
4175 * PARAMS
4176 * None.
4178 * RETURNS
4179 * A handle representing the current process.
4181 #undef GetCurrentProcess
4182 HANDLE WINAPI GetCurrentProcess(void)
4184 return (HANDLE)~(ULONG_PTR)0;
4187 /***********************************************************************
4188 * GetLogicalProcessorInformation (KERNEL32.@)
4190 BOOL WINAPI GetLogicalProcessorInformation(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION buffer, PDWORD pBufLen)
4192 NTSTATUS status;
4194 TRACE("(%p,%p)\n", buffer, pBufLen);
4196 if(!pBufLen)
4198 SetLastError(ERROR_INVALID_PARAMETER);
4199 return FALSE;
4202 status = NtQuerySystemInformation( SystemLogicalProcessorInformation, buffer, *pBufLen, pBufLen);
4204 if (status == STATUS_INFO_LENGTH_MISMATCH)
4206 SetLastError( ERROR_INSUFFICIENT_BUFFER );
4207 return FALSE;
4209 if (status != STATUS_SUCCESS)
4211 SetLastError( RtlNtStatusToDosError( status ) );
4212 return FALSE;
4214 return TRUE;
4217 /***********************************************************************
4218 * GetLogicalProcessorInformationEx (KERNEL32.@)
4220 BOOL WINAPI GetLogicalProcessorInformationEx(LOGICAL_PROCESSOR_RELATIONSHIP relationship, SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *buffer, DWORD *len)
4222 NTSTATUS status;
4224 TRACE("(%u,%p,%p)\n", relationship, buffer, len);
4226 if (!len)
4228 SetLastError( ERROR_INVALID_PARAMETER );
4229 return FALSE;
4232 status = NtQuerySystemInformationEx( SystemLogicalProcessorInformationEx, &relationship, sizeof(relationship),
4233 buffer, *len, len );
4234 if (status == STATUS_INFO_LENGTH_MISMATCH)
4236 SetLastError( ERROR_INSUFFICIENT_BUFFER );
4237 return FALSE;
4239 if (status != STATUS_SUCCESS)
4241 SetLastError( RtlNtStatusToDosError( status ) );
4242 return FALSE;
4244 return TRUE;
4247 /***********************************************************************
4248 * CmdBatNotification (KERNEL32.@)
4250 * Notifies the system that a batch file has started or finished.
4252 * PARAMS
4253 * bBatchRunning [I] TRUE if a batch file has started or
4254 * FALSE if a batch file has finished executing.
4256 * RETURNS
4257 * Unknown.
4259 BOOL WINAPI CmdBatNotification( BOOL bBatchRunning )
4261 FIXME("%d\n", bBatchRunning);
4262 return FALSE;
4265 /***********************************************************************
4266 * RegisterApplicationRestart (KERNEL32.@)
4268 HRESULT WINAPI RegisterApplicationRestart(PCWSTR pwzCommandLine, DWORD dwFlags)
4270 FIXME("(%s,%d)\n", debugstr_w(pwzCommandLine), dwFlags);
4272 return S_OK;
4275 /**********************************************************************
4276 * WTSGetActiveConsoleSessionId (KERNEL32.@)
4278 DWORD WINAPI WTSGetActiveConsoleSessionId(void)
4280 static int once;
4281 if (!once++) FIXME("stub\n");
4282 /* Return current session id. */
4283 return NtCurrentTeb()->Peb->SessionId;
4286 /**********************************************************************
4287 * GetSystemDEPPolicy (KERNEL32.@)
4289 DEP_SYSTEM_POLICY_TYPE WINAPI GetSystemDEPPolicy(void)
4291 FIXME("stub\n");
4292 return OptIn;
4295 /**********************************************************************
4296 * SetProcessDEPPolicy (KERNEL32.@)
4298 BOOL WINAPI SetProcessDEPPolicy(DWORD newDEP)
4300 FIXME("(%d): stub\n", newDEP);
4301 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4302 return FALSE;
4305 /**********************************************************************
4306 * ApplicationRecoveryFinished (KERNEL32.@)
4308 VOID WINAPI ApplicationRecoveryFinished(BOOL success)
4310 FIXME(": stub\n");
4311 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4314 /**********************************************************************
4315 * ApplicationRecoveryInProgress (KERNEL32.@)
4317 HRESULT WINAPI ApplicationRecoveryInProgress(PBOOL canceled)
4319 FIXME(":%p stub\n", canceled);
4320 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4321 return E_FAIL;
4324 /**********************************************************************
4325 * RegisterApplicationRecoveryCallback (KERNEL32.@)
4327 HRESULT WINAPI RegisterApplicationRecoveryCallback(APPLICATION_RECOVERY_CALLBACK callback, PVOID param, DWORD pingint, DWORD flags)
4329 FIXME("%p, %p, %d, %d: stub\n", callback, param, pingint, flags);
4330 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4331 return E_FAIL;
4334 /***********************************************************************
4335 * GetApplicationRestartSettings (KERNEL32.@)
4337 HRESULT WINAPI GetApplicationRestartSettings(HANDLE process, WCHAR *cmdline, DWORD *size, DWORD *flags)
4339 FIXME("%p, %p, %p, %p)\n", process, cmdline, size, flags);
4340 return E_NOTIMPL;
4343 /**********************************************************************
4344 * GetNumaHighestNodeNumber (KERNEL32.@)
4346 BOOL WINAPI GetNumaHighestNodeNumber(PULONG highestnode)
4348 *highestnode = 0;
4349 FIXME("(%p): semi-stub\n", highestnode);
4350 return TRUE;
4353 /**********************************************************************
4354 * GetNumaNodeProcessorMask (KERNEL32.@)
4356 BOOL WINAPI GetNumaNodeProcessorMask(UCHAR node, PULONGLONG mask)
4358 FIXME("(%c %p): stub\n", node, mask);
4359 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4360 return FALSE;
4363 /**********************************************************************
4364 * GetNumaNodeProcessorMaskEx (KERNEL32.@)
4366 BOOL WINAPI GetNumaNodeProcessorMaskEx(USHORT node, PGROUP_AFFINITY mask)
4368 FIXME("(%hu %p): stub\n", node, mask);
4369 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4370 return FALSE;
4373 /**********************************************************************
4374 * GetNumaAvailableMemoryNode (KERNEL32.@)
4376 BOOL WINAPI GetNumaAvailableMemoryNode(UCHAR node, PULONGLONG available_bytes)
4378 FIXME("(%c %p): stub\n", node, available_bytes);
4379 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4380 return FALSE;
4383 /***********************************************************************
4384 * GetNumaProcessorNode (KERNEL32.@)
4386 BOOL WINAPI GetNumaProcessorNode(UCHAR processor, PUCHAR node)
4388 SYSTEM_INFO si;
4390 TRACE("(%d, %p)\n", processor, node);
4392 GetSystemInfo( &si );
4393 if (processor < si.dwNumberOfProcessors)
4395 *node = 0;
4396 return TRUE;
4399 *node = 0xFF;
4400 SetLastError(ERROR_INVALID_PARAMETER);
4401 return FALSE;
4404 /**********************************************************************
4405 * GetProcessDEPPolicy (KERNEL32.@)
4407 BOOL WINAPI GetProcessDEPPolicy(HANDLE process, LPDWORD flags, PBOOL permanent)
4409 NTSTATUS status;
4410 ULONG dep_flags;
4412 TRACE("(%p %p %p)\n", process, flags, permanent);
4414 status = NtQueryInformationProcess( GetCurrentProcess(), ProcessExecuteFlags,
4415 &dep_flags, sizeof(dep_flags), NULL );
4416 if (!status)
4419 if (flags)
4421 *flags = 0;
4422 if (dep_flags & MEM_EXECUTE_OPTION_DISABLE)
4423 *flags |= PROCESS_DEP_ENABLE;
4424 if (dep_flags & MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION)
4425 *flags |= PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION;
4428 if (permanent)
4429 *permanent = (dep_flags & MEM_EXECUTE_OPTION_PERMANENT) != 0;
4432 if (status) SetLastError( RtlNtStatusToDosError(status) );
4433 return !status;
4436 /**********************************************************************
4437 * FlushProcessWriteBuffers (KERNEL32.@)
4439 VOID WINAPI FlushProcessWriteBuffers(void)
4441 static int once = 0;
4443 if (!once++)
4444 FIXME(": stub\n");
4447 /***********************************************************************
4448 * UnregisterApplicationRestart (KERNEL32.@)
4450 HRESULT WINAPI UnregisterApplicationRestart(void)
4452 FIXME(": stub\n");
4453 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4454 return S_OK;
4457 struct proc_thread_attr
4459 DWORD_PTR attr;
4460 SIZE_T size;
4461 void *value;
4464 struct _PROC_THREAD_ATTRIBUTE_LIST
4466 DWORD mask; /* bitmask of items in list */
4467 DWORD size; /* max number of items in list */
4468 DWORD count; /* number of items in list */
4469 DWORD pad;
4470 DWORD_PTR unk;
4471 struct proc_thread_attr attrs[1];
4474 /***********************************************************************
4475 * InitializeProcThreadAttributeList (KERNEL32.@)
4477 BOOL WINAPI InitializeProcThreadAttributeList(struct _PROC_THREAD_ATTRIBUTE_LIST *list,
4478 DWORD count, DWORD flags, SIZE_T *size)
4480 SIZE_T needed;
4481 BOOL ret = FALSE;
4483 TRACE("(%p %d %x %p)\n", list, count, flags, size);
4485 needed = FIELD_OFFSET(struct _PROC_THREAD_ATTRIBUTE_LIST, attrs[count]);
4486 if (list && *size >= needed)
4488 list->mask = 0;
4489 list->size = count;
4490 list->count = 0;
4491 list->unk = 0;
4492 ret = TRUE;
4494 else
4495 SetLastError(ERROR_INSUFFICIENT_BUFFER);
4497 *size = needed;
4498 return ret;
4501 /***********************************************************************
4502 * UpdateProcThreadAttribute (KERNEL32.@)
4504 BOOL WINAPI UpdateProcThreadAttribute(struct _PROC_THREAD_ATTRIBUTE_LIST *list,
4505 DWORD flags, DWORD_PTR attr, void *value, SIZE_T size,
4506 void *prev_ret, SIZE_T *size_ret)
4508 DWORD mask;
4509 struct proc_thread_attr *entry;
4511 TRACE("(%p %x %08lx %p %ld %p %p)\n", list, flags, attr, value, size, prev_ret, size_ret);
4513 if (list->count >= list->size)
4515 SetLastError(ERROR_GEN_FAILURE);
4516 return FALSE;
4519 switch (attr)
4521 case PROC_THREAD_ATTRIBUTE_PARENT_PROCESS:
4522 if (size != sizeof(HANDLE))
4524 SetLastError(ERROR_BAD_LENGTH);
4525 return FALSE;
4527 break;
4529 case PROC_THREAD_ATTRIBUTE_HANDLE_LIST:
4530 if ((size / sizeof(HANDLE)) * sizeof(HANDLE) != size)
4532 SetLastError(ERROR_BAD_LENGTH);
4533 return FALSE;
4535 break;
4537 case PROC_THREAD_ATTRIBUTE_IDEAL_PROCESSOR:
4538 if (size != sizeof(PROCESSOR_NUMBER))
4540 SetLastError(ERROR_BAD_LENGTH);
4541 return FALSE;
4543 break;
4545 case PROC_THREAD_ATTRIBUTE_CHILD_PROCESS_POLICY:
4546 if (size != sizeof(DWORD) && size != sizeof(DWORD64))
4548 SetLastError(ERROR_BAD_LENGTH);
4549 return FALSE;
4551 break;
4553 case PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY:
4554 if (size != sizeof(DWORD) && size != sizeof(DWORD64) && size != sizeof(DWORD64) * 2)
4556 SetLastError(ERROR_BAD_LENGTH);
4557 return FALSE;
4559 break;
4561 default:
4562 SetLastError(ERROR_NOT_SUPPORTED);
4563 FIXME("Unhandled attribute number %lu\n", attr & PROC_THREAD_ATTRIBUTE_NUMBER);
4564 return FALSE;
4567 mask = 1 << (attr & PROC_THREAD_ATTRIBUTE_NUMBER);
4569 if (list->mask & mask)
4571 SetLastError(ERROR_OBJECT_NAME_EXISTS);
4572 return FALSE;
4575 list->mask |= mask;
4577 entry = list->attrs + list->count;
4578 entry->attr = attr;
4579 entry->size = size;
4580 entry->value = value;
4581 list->count++;
4583 return TRUE;
4586 /***********************************************************************
4587 * CreateUmsCompletionList (KERNEL32.@)
4589 BOOL WINAPI CreateUmsCompletionList(PUMS_COMPLETION_LIST *list)
4591 FIXME( "%p: stub\n", list );
4592 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
4593 return FALSE;
4596 /***********************************************************************
4597 * CreateUmsThreadContext (KERNEL32.@)
4599 BOOL WINAPI CreateUmsThreadContext(PUMS_CONTEXT *ctx)
4601 FIXME( "%p: stub\n", ctx );
4602 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
4603 return FALSE;
4606 /***********************************************************************
4607 * DeleteProcThreadAttributeList (KERNEL32.@)
4609 void WINAPI DeleteProcThreadAttributeList(struct _PROC_THREAD_ATTRIBUTE_LIST *list)
4611 return;
4614 /***********************************************************************
4615 * DeleteUmsCompletionList (KERNEL32.@)
4617 BOOL WINAPI DeleteUmsCompletionList(PUMS_COMPLETION_LIST list)
4619 FIXME( "%p: stub\n", list );
4620 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
4621 return FALSE;
4624 /***********************************************************************
4625 * DeleteUmsThreadContext (KERNEL32.@)
4627 BOOL WINAPI DeleteUmsThreadContext(PUMS_CONTEXT ctx)
4629 FIXME( "%p: stub\n", ctx );
4630 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
4631 return FALSE;
4634 /***********************************************************************
4635 * DequeueUmsCompletionListItems (KERNEL32.@)
4637 BOOL WINAPI DequeueUmsCompletionListItems(void *list, DWORD timeout, PUMS_CONTEXT *ctx)
4639 FIXME( "%p,%08x,%p: stub\n", list, timeout, ctx );
4640 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
4641 return FALSE;
4644 /***********************************************************************
4645 * EnterUmsSchedulingMode (KERNEL32.@)
4647 BOOL WINAPI EnterUmsSchedulingMode(UMS_SCHEDULER_STARTUP_INFO *info)
4649 FIXME( "%p: stub\n", info );
4650 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
4651 return FALSE;
4654 /***********************************************************************
4655 * ExecuteUmsThread (KERNEL32.@)
4657 BOOL WINAPI ExecuteUmsThread(PUMS_CONTEXT ctx)
4659 FIXME( "%p: stub\n", ctx );
4660 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
4661 return FALSE;
4664 /***********************************************************************
4665 * GetCurrentUmsThread (KERNEL32.@)
4667 PUMS_CONTEXT WINAPI GetCurrentUmsThread(void)
4669 FIXME( "stub\n" );
4670 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
4671 return FALSE;
4674 /***********************************************************************
4675 * GetNextUmsListItem (KERNEL32.@)
4677 PUMS_CONTEXT WINAPI GetNextUmsListItem(PUMS_CONTEXT ctx)
4679 FIXME( "%p: stub\n", ctx );
4680 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
4681 return NULL;
4684 /***********************************************************************
4685 * GetUmsCompletionListEvent (KERNEL32.@)
4687 BOOL WINAPI GetUmsCompletionListEvent(PUMS_COMPLETION_LIST list, HANDLE *event)
4689 FIXME( "%p,%p: stub\n", list, event );
4690 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
4691 return FALSE;
4694 /***********************************************************************
4695 * QueryUmsThreadInformation (KERNEL32.@)
4697 BOOL WINAPI QueryUmsThreadInformation(PUMS_CONTEXT ctx, UMS_THREAD_INFO_CLASS class,
4698 void *buf, ULONG length, ULONG *ret_length)
4700 FIXME( "%p,%08x,%p,%08x,%p: stub\n", ctx, class, buf, length, ret_length );
4701 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
4702 return FALSE;
4705 /***********************************************************************
4706 * SetUmsThreadInformation (KERNEL32.@)
4708 BOOL WINAPI SetUmsThreadInformation(PUMS_CONTEXT ctx, UMS_THREAD_INFO_CLASS class,
4709 void *buf, ULONG length)
4711 FIXME( "%p,%08x,%p,%08x: stub\n", ctx, class, buf, length );
4712 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
4713 return FALSE;
4716 /***********************************************************************
4717 * UmsThreadYield (KERNEL32.@)
4719 BOOL WINAPI UmsThreadYield(void *param)
4721 FIXME( "%p: stub\n", param );
4722 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
4723 return FALSE;
4726 /**********************************************************************
4727 * BaseFlushAppcompatCache (KERNEL32.@)
4729 BOOL WINAPI BaseFlushAppcompatCache(void)
4731 FIXME(": stub\n");
4732 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
4733 return FALSE;
4736 /**********************************************************************
4737 * SetProcessMitigationPolicy (KERNEL32.@)
4739 BOOL WINAPI SetProcessMitigationPolicy(PROCESS_MITIGATION_POLICY policy, void *buffer, SIZE_T length)
4741 FIXME("(%d, %p, %lu): stub\n", policy, buffer, length);
4743 return TRUE;