kernelbase: Pass the token to NtCreateUserProcess().
[wine.git] / dlls / kernelbase / process.c
blobe7998c00f285fbe20fca712498e1b550d7b5bbff
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 <stdarg.h>
22 #include <string.h>
24 #include "ntstatus.h"
25 #define WIN32_NO_STATUS
26 #define NONAMELESSUNION
27 #define NONAMELESSSTRUCT
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winnls.h"
31 #include "wincontypes.h"
32 #include "winternl.h"
34 #include "kernelbase.h"
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(process);
39 static DWORD shutdown_flags = 0;
40 static DWORD shutdown_priority = 0x280;
42 /***********************************************************************
43 * Processes
44 ***********************************************************************/
47 /***********************************************************************
48 * find_exe_file
50 static BOOL find_exe_file( const WCHAR *name, WCHAR *buffer, DWORD buflen )
52 WCHAR *load_path;
53 BOOL ret;
55 if (!set_ntstatus( RtlGetExePath( name, &load_path ))) return FALSE;
57 TRACE( "looking for %s in %s\n", debugstr_w(name), debugstr_w(load_path) );
59 ret = (SearchPathW( load_path, name, L".exe", buflen, buffer, NULL ) ||
60 /* not found, try without extension in case it is a Unix app */
61 SearchPathW( load_path, name, NULL, buflen, buffer, NULL ));
63 if (ret) /* make sure it can be opened, SearchPathW also returns directories */
65 HANDLE handle = CreateFileW( buffer, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_DELETE,
66 NULL, OPEN_EXISTING, 0, 0 );
67 if ((ret = (handle != INVALID_HANDLE_VALUE))) CloseHandle( handle );
69 RtlReleasePath( load_path );
70 return ret;
74 /*************************************************************************
75 * get_file_name
77 * Helper for CreateProcess: retrieve the file name to load from the
78 * app name and command line. Store the file name in buffer, and
79 * return a possibly modified command line.
81 static WCHAR *get_file_name( WCHAR *cmdline, WCHAR *buffer, DWORD buflen )
83 WCHAR *name, *pos, *first_space, *ret = NULL;
84 const WCHAR *p;
86 /* first check for a quoted file name */
88 if (cmdline[0] == '"' && (p = wcschr( cmdline + 1, '"' )))
90 int len = p - cmdline - 1;
91 /* extract the quoted portion as file name */
92 if (!(name = RtlAllocateHeap( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return NULL;
93 memcpy( name, cmdline + 1, len * sizeof(WCHAR) );
94 name[len] = 0;
96 if (!find_exe_file( name, buffer, buflen )) goto done;
97 ret = cmdline; /* no change necessary */
98 goto done;
101 /* now try the command-line word by word */
103 if (!(name = RtlAllocateHeap( GetProcessHeap(), 0, (lstrlenW(cmdline) + 1) * sizeof(WCHAR) )))
104 return NULL;
105 pos = name;
106 p = cmdline;
107 first_space = NULL;
109 for (;;)
111 while (*p && *p != ' ' && *p != '\t') *pos++ = *p++;
112 *pos = 0;
113 if (find_exe_file( name, buffer, buflen ))
115 ret = cmdline;
116 break;
118 if (!first_space) first_space = pos;
119 if (!(*pos++ = *p++)) break;
122 if (!ret)
124 SetLastError( ERROR_FILE_NOT_FOUND );
126 else if (first_space) /* build a new command-line with quotes */
128 if (!(ret = HeapAlloc( GetProcessHeap(), 0, (lstrlenW(cmdline) + 3) * sizeof(WCHAR) )))
129 goto done;
130 swprintf( ret, lstrlenW(cmdline) + 3, L"\"%s\"%s", name, p );
133 done:
134 RtlFreeHeap( GetProcessHeap(), 0, name );
135 return ret;
139 /***********************************************************************
140 * create_process_params
142 static RTL_USER_PROCESS_PARAMETERS *create_process_params( const WCHAR *filename, const WCHAR *cmdline,
143 const WCHAR *cur_dir, void *env, DWORD flags,
144 const STARTUPINFOW *startup )
146 RTL_USER_PROCESS_PARAMETERS *params;
147 UNICODE_STRING imageW, dllpathW, curdirW, cmdlineW, titleW, desktopW, runtimeW, newdirW;
148 WCHAR imagepath[MAX_PATH];
149 WCHAR *load_path, *dummy, *envW = env;
151 if (!GetLongPathNameW( filename, imagepath, MAX_PATH )) lstrcpynW( imagepath, filename, MAX_PATH );
152 if (!GetFullPathNameW( imagepath, MAX_PATH, imagepath, NULL )) lstrcpynW( imagepath, filename, MAX_PATH );
154 if (env && !(flags & CREATE_UNICODE_ENVIRONMENT)) /* convert environment to unicode */
156 char *e = env;
157 DWORD lenW;
159 while (*e) e += strlen(e) + 1;
160 e++; /* final null */
161 lenW = MultiByteToWideChar( CP_ACP, 0, env, e - (char *)env, NULL, 0 );
162 if ((envW = RtlAllocateHeap( GetProcessHeap(), 0, lenW * sizeof(WCHAR) )))
163 MultiByteToWideChar( CP_ACP, 0, env, e - (char *)env, envW, lenW );
166 newdirW.Buffer = NULL;
167 if (cur_dir)
169 if (RtlDosPathNameToNtPathName_U( cur_dir, &newdirW, NULL, NULL ))
170 cur_dir = newdirW.Buffer + 4; /* skip \??\ prefix */
171 else
172 cur_dir = NULL;
174 LdrGetDllPath( imagepath, LOAD_WITH_ALTERED_SEARCH_PATH, &load_path, &dummy );
175 RtlInitUnicodeString( &imageW, imagepath );
176 RtlInitUnicodeString( &dllpathW, load_path );
177 RtlInitUnicodeString( &curdirW, cur_dir );
178 RtlInitUnicodeString( &cmdlineW, cmdline );
179 RtlInitUnicodeString( &titleW, startup->lpTitle ? startup->lpTitle : imagepath );
180 RtlInitUnicodeString( &desktopW, startup->lpDesktop );
181 runtimeW.Buffer = (WCHAR *)startup->lpReserved2;
182 runtimeW.Length = runtimeW.MaximumLength = startup->cbReserved2;
183 if (RtlCreateProcessParametersEx( &params, &imageW, &dllpathW, cur_dir ? &curdirW : NULL,
184 &cmdlineW, envW, &titleW, &desktopW,
185 NULL, &runtimeW, PROCESS_PARAMS_FLAG_NORMALIZED ))
187 RtlFreeUnicodeString( &newdirW );
188 RtlReleasePath( load_path );
189 if (envW != env) RtlFreeHeap( GetProcessHeap(), 0, envW );
190 return NULL;
192 RtlFreeUnicodeString( &newdirW );
193 RtlReleasePath( load_path );
195 if (flags & CREATE_NEW_PROCESS_GROUP) params->ConsoleFlags = 1;
196 if (flags & CREATE_NEW_CONSOLE) params->ConsoleHandle = (HANDLE)1; /* KERNEL32_CONSOLE_ALLOC */
197 else if (!(flags & DETACHED_PROCESS)) params->ConsoleHandle = NtCurrentTeb()->Peb->ProcessParameters->ConsoleHandle;
199 if (startup->dwFlags & STARTF_USESTDHANDLES)
201 params->hStdInput = startup->hStdInput;
202 params->hStdOutput = startup->hStdOutput;
203 params->hStdError = startup->hStdError;
205 else if (flags & DETACHED_PROCESS)
207 params->hStdInput = INVALID_HANDLE_VALUE;
208 params->hStdOutput = INVALID_HANDLE_VALUE;
209 params->hStdError = INVALID_HANDLE_VALUE;
211 else
213 params->hStdInput = NtCurrentTeb()->Peb->ProcessParameters->hStdInput;
214 params->hStdOutput = NtCurrentTeb()->Peb->ProcessParameters->hStdOutput;
215 params->hStdError = NtCurrentTeb()->Peb->ProcessParameters->hStdError;
218 if (flags & CREATE_NEW_CONSOLE)
220 /* this is temporary (for console handles). We have no way to control that the handle is invalid in child process otherwise */
221 if (is_console_handle(params->hStdInput)) params->hStdInput = INVALID_HANDLE_VALUE;
222 if (is_console_handle(params->hStdOutput)) params->hStdOutput = INVALID_HANDLE_VALUE;
223 if (is_console_handle(params->hStdError)) params->hStdError = INVALID_HANDLE_VALUE;
225 else
227 if (is_console_handle(params->hStdInput)) params->hStdInput = (HANDLE)((UINT_PTR)params->hStdInput & ~3);
228 if (is_console_handle(params->hStdOutput)) params->hStdOutput = (HANDLE)((UINT_PTR)params->hStdOutput & ~3);
229 if (is_console_handle(params->hStdError)) params->hStdError = (HANDLE)((UINT_PTR)params->hStdError & ~3);
232 params->dwX = startup->dwX;
233 params->dwY = startup->dwY;
234 params->dwXSize = startup->dwXSize;
235 params->dwYSize = startup->dwYSize;
236 params->dwXCountChars = startup->dwXCountChars;
237 params->dwYCountChars = startup->dwYCountChars;
238 params->dwFillAttribute = startup->dwFillAttribute;
239 params->dwFlags = startup->dwFlags;
240 params->wShowWindow = startup->wShowWindow;
242 if (envW != env) RtlFreeHeap( GetProcessHeap(), 0, envW );
243 return params;
246 struct proc_thread_attr
248 DWORD_PTR attr;
249 SIZE_T size;
250 void *value;
253 struct _PROC_THREAD_ATTRIBUTE_LIST
255 DWORD mask; /* bitmask of items in list */
256 DWORD size; /* max number of items in list */
257 DWORD count; /* number of items in list */
258 DWORD pad;
259 DWORD_PTR unk;
260 struct proc_thread_attr attrs[1];
263 /***********************************************************************
264 * create_nt_process
266 static NTSTATUS create_nt_process( HANDLE token, SECURITY_ATTRIBUTES *psa, SECURITY_ATTRIBUTES *tsa,
267 BOOL inherit, DWORD flags, RTL_USER_PROCESS_PARAMETERS *params,
268 RTL_USER_PROCESS_INFORMATION *info, HANDLE parent,
269 const struct proc_thread_attr *handle_list )
271 OBJECT_ATTRIBUTES process_attr, thread_attr;
272 PS_CREATE_INFO create_info;
273 ULONG_PTR buffer[offsetof( PS_ATTRIBUTE_LIST, Attributes[6] ) / sizeof(ULONG_PTR)];
274 PS_ATTRIBUTE_LIST *attr = (PS_ATTRIBUTE_LIST *)buffer;
275 UNICODE_STRING nameW;
276 NTSTATUS status;
277 UINT pos = 0;
279 if (!params->ImagePathName.Buffer[0]) return STATUS_OBJECT_PATH_NOT_FOUND;
280 status = RtlDosPathNameToNtPathName_U_WithStatus( params->ImagePathName.Buffer, &nameW, NULL, NULL );
281 if (!status)
283 params->DebugFlags = flags; /* hack, cf. RtlCreateUserProcess implementation */
285 RtlNormalizeProcessParams( params );
287 attr->Attributes[pos].Attribute = PS_ATTRIBUTE_IMAGE_NAME;
288 attr->Attributes[pos].Size = nameW.Length;
289 attr->Attributes[pos].ValuePtr = nameW.Buffer;
290 attr->Attributes[pos].ReturnLength = NULL;
291 pos++;
292 attr->Attributes[pos].Attribute = PS_ATTRIBUTE_CLIENT_ID;
293 attr->Attributes[pos].Size = sizeof(info->ClientId);
294 attr->Attributes[pos].ValuePtr = &info->ClientId;
295 attr->Attributes[pos].ReturnLength = NULL;
296 pos++;
297 attr->Attributes[pos].Attribute = PS_ATTRIBUTE_IMAGE_INFO;
298 attr->Attributes[pos].Size = sizeof(info->ImageInformation);
299 attr->Attributes[pos].ValuePtr = &info->ImageInformation;
300 attr->Attributes[pos].ReturnLength = NULL;
301 pos++;
302 if (parent)
304 attr->Attributes[pos].Attribute = PS_ATTRIBUTE_PARENT_PROCESS;
305 attr->Attributes[pos].Size = sizeof(parent);
306 attr->Attributes[pos].ValuePtr = parent;
307 attr->Attributes[pos].ReturnLength = NULL;
308 pos++;
310 if (inherit && handle_list)
312 attr->Attributes[pos].Attribute = PS_ATTRIBUTE_HANDLE_LIST;
313 attr->Attributes[pos].Size = handle_list->size;
314 attr->Attributes[pos].ValuePtr = handle_list->value;
315 attr->Attributes[pos].ReturnLength = NULL;
316 pos++;
318 if (token)
320 attr->Attributes[pos].Attribute = PS_ATTRIBUTE_TOKEN;
321 attr->Attributes[pos].Size = sizeof(token);
322 attr->Attributes[pos].ValuePtr = token;
323 attr->Attributes[pos].ReturnLength = NULL;
324 pos++;
326 attr->TotalLength = offsetof( PS_ATTRIBUTE_LIST, Attributes[pos] );
328 InitializeObjectAttributes( &process_attr, NULL, 0, NULL, psa ? psa->lpSecurityDescriptor : NULL );
329 InitializeObjectAttributes( &thread_attr, NULL, 0, NULL, tsa ? tsa->lpSecurityDescriptor : NULL );
331 status = NtCreateUserProcess( &info->Process, &info->Thread, PROCESS_ALL_ACCESS, THREAD_ALL_ACCESS,
332 &process_attr, &thread_attr,
333 inherit ? PROCESS_CREATE_FLAGS_INHERIT_HANDLES : 0,
334 THREAD_CREATE_FLAGS_CREATE_SUSPENDED, params,
335 &create_info, attr );
337 RtlFreeUnicodeString( &nameW );
339 return status;
343 /***********************************************************************
344 * create_vdm_process
346 static NTSTATUS create_vdm_process( HANDLE token, SECURITY_ATTRIBUTES *psa, SECURITY_ATTRIBUTES *tsa,
347 BOOL inherit, DWORD flags, RTL_USER_PROCESS_PARAMETERS *params,
348 RTL_USER_PROCESS_INFORMATION *info )
350 const WCHAR *winevdm = (is_win64 || is_wow64 ?
351 L"C:\\windows\\syswow64\\winevdm.exe" :
352 L"C:\\windows\\system32\\winevdm.exe");
353 WCHAR *newcmdline;
354 NTSTATUS status;
355 UINT len;
357 len = (lstrlenW(params->ImagePathName.Buffer) + lstrlenW(params->CommandLine.Buffer) +
358 lstrlenW(winevdm) + 16);
360 if (!(newcmdline = RtlAllocateHeap( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
361 return STATUS_NO_MEMORY;
363 swprintf( newcmdline, len, L"%s --app-name \"%s\" %s",
364 winevdm, params->ImagePathName.Buffer, params->CommandLine.Buffer );
365 RtlInitUnicodeString( &params->ImagePathName, winevdm );
366 RtlInitUnicodeString( &params->CommandLine, newcmdline );
367 status = create_nt_process( token, psa, tsa, inherit, flags, params, info, NULL, NULL );
368 HeapFree( GetProcessHeap(), 0, newcmdline );
369 return status;
373 /***********************************************************************
374 * create_cmd_process
376 static NTSTATUS create_cmd_process( HANDLE token, SECURITY_ATTRIBUTES *psa, SECURITY_ATTRIBUTES *tsa,
377 BOOL inherit, DWORD flags, RTL_USER_PROCESS_PARAMETERS *params,
378 RTL_USER_PROCESS_INFORMATION *info )
380 WCHAR comspec[MAX_PATH];
381 WCHAR *newcmdline;
382 NTSTATUS status;
383 UINT len;
385 if (!GetEnvironmentVariableW( L"COMSPEC", comspec, ARRAY_SIZE( comspec )))
386 lstrcpyW( comspec, L"C:\\windows\\system32\\cmd.exe" );
388 len = lstrlenW(comspec) + 7 + lstrlenW(params->CommandLine.Buffer) + 2;
389 if (!(newcmdline = RtlAllocateHeap( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
390 return STATUS_NO_MEMORY;
392 swprintf( newcmdline, len, L"%s /s/c \"%s\"", comspec, params->CommandLine.Buffer );
393 RtlInitUnicodeString( &params->ImagePathName, comspec );
394 RtlInitUnicodeString( &params->CommandLine, newcmdline );
395 status = create_nt_process( token, psa, tsa, inherit, flags, params, info, NULL, NULL );
396 RtlFreeHeap( GetProcessHeap(), 0, newcmdline );
397 return status;
401 /*********************************************************************
402 * CloseHandle (kernelbase.@)
404 BOOL WINAPI DECLSPEC_HOTPATCH CloseHandle( HANDLE handle )
406 if (handle == (HANDLE)STD_INPUT_HANDLE)
407 handle = InterlockedExchangePointer( &NtCurrentTeb()->Peb->ProcessParameters->hStdInput, 0 );
408 else if (handle == (HANDLE)STD_OUTPUT_HANDLE)
409 handle = InterlockedExchangePointer( &NtCurrentTeb()->Peb->ProcessParameters->hStdOutput, 0 );
410 else if (handle == (HANDLE)STD_ERROR_HANDLE)
411 handle = InterlockedExchangePointer( &NtCurrentTeb()->Peb->ProcessParameters->hStdError, 0 );
413 if (is_console_handle( handle )) handle = console_handle_map( handle );
414 return set_ntstatus( NtClose( handle ));
418 /**********************************************************************
419 * CreateProcessAsUserA (kernelbase.@)
421 BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessAsUserA( HANDLE token, const char *app_name, char *cmd_line,
422 SECURITY_ATTRIBUTES *process_attr,
423 SECURITY_ATTRIBUTES *thread_attr,
424 BOOL inherit, DWORD flags, void *env,
425 const char *cur_dir, STARTUPINFOA *startup_info,
426 PROCESS_INFORMATION *info )
428 return CreateProcessInternalA( token, app_name, cmd_line, process_attr, thread_attr,
429 inherit, flags, env, cur_dir, startup_info, info, NULL );
433 /**********************************************************************
434 * CreateProcessAsUserW (kernelbase.@)
436 BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessAsUserW( HANDLE token, const WCHAR *app_name, WCHAR *cmd_line,
437 SECURITY_ATTRIBUTES *process_attr,
438 SECURITY_ATTRIBUTES *thread_attr,
439 BOOL inherit, DWORD flags, void *env,
440 const WCHAR *cur_dir, STARTUPINFOW *startup_info,
441 PROCESS_INFORMATION *info )
443 return CreateProcessInternalW( token, app_name, cmd_line, process_attr, thread_attr,
444 inherit, flags, env, cur_dir, startup_info, info, NULL );
447 /**********************************************************************
448 * CreateProcessInternalA (kernelbase.@)
450 BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessInternalA( HANDLE token, const char *app_name, char *cmd_line,
451 SECURITY_ATTRIBUTES *process_attr,
452 SECURITY_ATTRIBUTES *thread_attr,
453 BOOL inherit, DWORD flags, void *env,
454 const char *cur_dir, STARTUPINFOA *startup_info,
455 PROCESS_INFORMATION *info, HANDLE *new_token )
457 BOOL ret = FALSE;
458 WCHAR *app_nameW = NULL, *cmd_lineW = NULL, *cur_dirW = NULL;
459 UNICODE_STRING desktopW, titleW;
460 STARTUPINFOEXW infoW;
462 desktopW.Buffer = NULL;
463 titleW.Buffer = NULL;
464 if (app_name && !(app_nameW = file_name_AtoW( app_name, TRUE ))) goto done;
465 if (cmd_line && !(cmd_lineW = file_name_AtoW( cmd_line, TRUE ))) goto done;
466 if (cur_dir && !(cur_dirW = file_name_AtoW( cur_dir, TRUE ))) goto done;
468 if (startup_info->lpDesktop) RtlCreateUnicodeStringFromAsciiz( &desktopW, startup_info->lpDesktop );
469 if (startup_info->lpTitle) RtlCreateUnicodeStringFromAsciiz( &titleW, startup_info->lpTitle );
471 memcpy( &infoW.StartupInfo, startup_info, sizeof(infoW.StartupInfo) );
472 infoW.StartupInfo.lpDesktop = desktopW.Buffer;
473 infoW.StartupInfo.lpTitle = titleW.Buffer;
475 if (flags & EXTENDED_STARTUPINFO_PRESENT)
476 infoW.lpAttributeList = ((STARTUPINFOEXW *)startup_info)->lpAttributeList;
478 ret = CreateProcessInternalW( token, app_nameW, cmd_lineW, process_attr, thread_attr,
479 inherit, flags, env, cur_dirW, (STARTUPINFOW *)&infoW, info, new_token );
480 done:
481 RtlFreeHeap( GetProcessHeap(), 0, app_nameW );
482 RtlFreeHeap( GetProcessHeap(), 0, cmd_lineW );
483 RtlFreeHeap( GetProcessHeap(), 0, cur_dirW );
484 RtlFreeUnicodeString( &desktopW );
485 RtlFreeUnicodeString( &titleW );
486 return ret;
489 /**********************************************************************
490 * CreateProcessInternalW (kernelbase.@)
492 BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessInternalW( HANDLE token, const WCHAR *app_name, WCHAR *cmd_line,
493 SECURITY_ATTRIBUTES *process_attr,
494 SECURITY_ATTRIBUTES *thread_attr,
495 BOOL inherit, DWORD flags, void *env,
496 const WCHAR *cur_dir, STARTUPINFOW *startup_info,
497 PROCESS_INFORMATION *info, HANDLE *new_token )
499 const struct proc_thread_attr *handle_list = NULL;
500 WCHAR name[MAX_PATH];
501 WCHAR *p, *tidy_cmdline = cmd_line;
502 RTL_USER_PROCESS_PARAMETERS *params = NULL;
503 RTL_USER_PROCESS_INFORMATION rtl_info;
504 HANDLE parent = NULL;
505 NTSTATUS status;
507 /* Process the AppName and/or CmdLine to get module name and path */
509 TRACE( "app %s cmdline %s\n", debugstr_w(app_name), debugstr_w(cmd_line) );
511 if (new_token) FIXME( "No support for returning created process token\n" );
513 if (app_name)
515 if (!cmd_line || !cmd_line[0]) /* no command-line, create one */
517 if (!(tidy_cmdline = RtlAllocateHeap( GetProcessHeap(), 0, (lstrlenW(app_name)+3) * sizeof(WCHAR) )))
518 return FALSE;
519 swprintf( tidy_cmdline, lstrlenW(app_name) + 3, L"\"%s\"", app_name );
522 else
524 if (!(tidy_cmdline = get_file_name( cmd_line, name, ARRAY_SIZE(name) ))) return FALSE;
525 app_name = name;
528 /* Warn if unsupported features are used */
530 if (flags & (IDLE_PRIORITY_CLASS | HIGH_PRIORITY_CLASS | REALTIME_PRIORITY_CLASS |
531 CREATE_DEFAULT_ERROR_MODE | CREATE_NO_WINDOW |
532 PROFILE_USER | PROFILE_KERNEL | PROFILE_SERVER))
533 WARN( "(%s,...): ignoring some flags in %x\n", debugstr_w(app_name), flags );
535 if (cur_dir)
537 DWORD attr = GetFileAttributesW( cur_dir );
538 if (attr == INVALID_FILE_ATTRIBUTES || !(attr & FILE_ATTRIBUTE_DIRECTORY))
540 status = STATUS_NOT_A_DIRECTORY;
541 goto done;
545 info->hThread = info->hProcess = 0;
546 info->dwProcessId = info->dwThreadId = 0;
548 if (!(params = create_process_params( app_name, tidy_cmdline, cur_dir, env, flags, startup_info )))
550 status = STATUS_NO_MEMORY;
551 goto done;
554 if (flags & EXTENDED_STARTUPINFO_PRESENT)
556 struct _PROC_THREAD_ATTRIBUTE_LIST *attrs =
557 (struct _PROC_THREAD_ATTRIBUTE_LIST *)((STARTUPINFOEXW *)startup_info)->lpAttributeList;
558 unsigned int i;
560 if (attrs)
562 for (i = 0; i < attrs->count; ++i)
564 switch(attrs->attrs[i].attr)
566 case PROC_THREAD_ATTRIBUTE_PARENT_PROCESS:
567 parent = *(HANDLE *)attrs->attrs[i].value;
568 TRACE("PROC_THREAD_ATTRIBUTE_PARENT_PROCESS parent %p.\n", parent);
569 if (!parent)
571 status = STATUS_INVALID_HANDLE;
572 goto done;
574 break;
575 case PROC_THREAD_ATTRIBUTE_HANDLE_LIST:
576 handle_list = &attrs->attrs[i];
577 TRACE("PROC_THREAD_ATTRIBUTE_HANDLE_LIST handle count %Iu.\n", attrs->attrs[i].size / sizeof(HANDLE));
578 break;
579 case PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE:
581 struct pseudo_console *console = attrs->attrs[i].value;
582 TRACE( "PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE %p reference %p\n",
583 console, console->reference );
584 params->ConsoleHandle = console->reference;
585 break;
587 default:
588 FIXME("Unsupported attribute %#Ix.\n", attrs->attrs[i].attr);
589 break;
595 status = create_nt_process( token, process_attr, thread_attr, inherit,
596 flags, params, &rtl_info, parent, handle_list );
597 switch (status)
599 case STATUS_SUCCESS:
600 break;
601 case STATUS_INVALID_IMAGE_WIN_16:
602 case STATUS_INVALID_IMAGE_NE_FORMAT:
603 case STATUS_INVALID_IMAGE_PROTECT:
604 TRACE( "starting %s as Win16/DOS binary\n", debugstr_w(app_name) );
605 status = create_vdm_process( token, process_attr, thread_attr, inherit, flags, params, &rtl_info );
606 break;
607 case STATUS_INVALID_IMAGE_NOT_MZ:
608 /* check for .com or .bat extension */
609 if (!(p = wcsrchr( app_name, '.' ))) break;
610 if (!wcsicmp( p, L".com" ) || !wcsicmp( p, L".pif" ))
612 TRACE( "starting %s as DOS binary\n", debugstr_w(app_name) );
613 status = create_vdm_process( token, process_attr, thread_attr, inherit, flags, params, &rtl_info );
615 else if (!wcsicmp( p, L".bat" ) || !wcsicmp( p, L".cmd" ))
617 TRACE( "starting %s as batch binary\n", debugstr_w(app_name) );
618 status = create_cmd_process( token, process_attr, thread_attr, inherit, flags, params, &rtl_info );
620 break;
623 if (!status)
625 info->hProcess = rtl_info.Process;
626 info->hThread = rtl_info.Thread;
627 info->dwProcessId = HandleToUlong( rtl_info.ClientId.UniqueProcess );
628 info->dwThreadId = HandleToUlong( rtl_info.ClientId.UniqueThread );
629 if (!(flags & CREATE_SUSPENDED)) NtResumeThread( rtl_info.Thread, NULL );
630 TRACE( "started process pid %04x tid %04x\n", info->dwProcessId, info->dwThreadId );
633 done:
634 RtlDestroyProcessParameters( params );
635 if (tidy_cmdline != cmd_line) HeapFree( GetProcessHeap(), 0, tidy_cmdline );
636 return set_ntstatus( status );
640 /**********************************************************************
641 * CreateProcessA (kernelbase.@)
643 BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessA( const char *app_name, char *cmd_line,
644 SECURITY_ATTRIBUTES *process_attr,
645 SECURITY_ATTRIBUTES *thread_attr, BOOL inherit,
646 DWORD flags, void *env, const char *cur_dir,
647 STARTUPINFOA *startup_info, PROCESS_INFORMATION *info )
649 return CreateProcessInternalA( NULL, app_name, cmd_line, process_attr, thread_attr,
650 inherit, flags, env, cur_dir, startup_info, info, NULL );
654 /**********************************************************************
655 * CreateProcessW (kernelbase.@)
657 BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessW( const WCHAR *app_name, WCHAR *cmd_line,
658 SECURITY_ATTRIBUTES *process_attr,
659 SECURITY_ATTRIBUTES *thread_attr, BOOL inherit, DWORD flags,
660 void *env, const WCHAR *cur_dir, STARTUPINFOW *startup_info,
661 PROCESS_INFORMATION *info )
663 return CreateProcessInternalW( NULL, app_name, cmd_line, process_attr, thread_attr,
664 inherit, flags, env, cur_dir, startup_info, info, NULL );
668 /*********************************************************************
669 * DuplicateHandle (kernelbase.@)
671 BOOL WINAPI DECLSPEC_HOTPATCH DuplicateHandle( HANDLE source_process, HANDLE source,
672 HANDLE dest_process, HANDLE *dest,
673 DWORD access, BOOL inherit, DWORD options )
675 if (is_console_handle( source ))
677 source = console_handle_map( source );
678 if (!set_ntstatus( NtDuplicateObject( source_process, source, dest_process, dest,
679 access, inherit ? OBJ_INHERIT : 0, options )))
680 return FALSE;
681 *dest = console_handle_map( *dest );
682 return TRUE;
684 return set_ntstatus( NtDuplicateObject( source_process, source, dest_process, dest,
685 access, inherit ? OBJ_INHERIT : 0, options ));
689 /****************************************************************************
690 * FlushInstructionCache (kernelbase.@)
692 BOOL WINAPI DECLSPEC_HOTPATCH FlushInstructionCache( HANDLE process, LPCVOID addr, SIZE_T size )
694 return set_ntstatus( NtFlushInstructionCache( process, addr, size ));
698 /***********************************************************************
699 * GetApplicationRestartSettings (kernelbase.@)
701 HRESULT WINAPI /* DECLSPEC_HOTPATCH */ GetApplicationRestartSettings( HANDLE process, WCHAR *cmdline,
702 DWORD *size, DWORD *flags )
704 FIXME( "%p, %p, %p, %p)\n", process, cmdline, size, flags );
705 return E_NOTIMPL;
709 /***********************************************************************
710 * GetCurrentProcess (kernelbase.@)
712 HANDLE WINAPI kernelbase_GetCurrentProcess(void)
714 return (HANDLE)~(ULONG_PTR)0;
718 /***********************************************************************
719 * GetCurrentProcessId (kernelbase.@)
721 DWORD WINAPI kernelbase_GetCurrentProcessId(void)
723 return HandleToULong( NtCurrentTeb()->ClientId.UniqueProcess );
727 /***********************************************************************
728 * GetErrorMode (kernelbase.@)
730 UINT WINAPI DECLSPEC_HOTPATCH GetErrorMode(void)
732 UINT mode;
734 NtQueryInformationProcess( GetCurrentProcess(), ProcessDefaultHardErrorMode,
735 &mode, sizeof(mode), NULL );
736 return mode;
740 /***********************************************************************
741 * GetExitCodeProcess (kernelbase.@)
743 BOOL WINAPI DECLSPEC_HOTPATCH GetExitCodeProcess( HANDLE process, LPDWORD exit_code )
745 NTSTATUS status;
746 PROCESS_BASIC_INFORMATION pbi;
748 status = NtQueryInformationProcess( process, ProcessBasicInformation, &pbi, sizeof(pbi), NULL );
749 if (status && exit_code) *exit_code = pbi.ExitStatus;
750 return set_ntstatus( status );
754 /*********************************************************************
755 * GetHandleInformation (kernelbase.@)
757 BOOL WINAPI DECLSPEC_HOTPATCH GetHandleInformation( HANDLE handle, DWORD *flags )
759 OBJECT_DATA_INFORMATION info;
761 if (!set_ntstatus( NtQueryObject( handle, ObjectDataInformation, &info, sizeof(info), NULL )))
762 return FALSE;
764 if (flags)
766 *flags = 0;
767 if (info.InheritHandle) *flags |= HANDLE_FLAG_INHERIT;
768 if (info.ProtectFromClose) *flags |= HANDLE_FLAG_PROTECT_FROM_CLOSE;
770 return TRUE;
774 /***********************************************************************
775 * GetPriorityClass (kernelbase.@)
777 DWORD WINAPI DECLSPEC_HOTPATCH GetPriorityClass( HANDLE process )
779 PROCESS_BASIC_INFORMATION pbi;
781 if (!set_ntstatus( NtQueryInformationProcess( process, ProcessBasicInformation,
782 &pbi, sizeof(pbi), NULL )))
783 return 0;
785 switch (pbi.BasePriority)
787 case PROCESS_PRIOCLASS_IDLE: return IDLE_PRIORITY_CLASS;
788 case PROCESS_PRIOCLASS_BELOW_NORMAL: return BELOW_NORMAL_PRIORITY_CLASS;
789 case PROCESS_PRIOCLASS_NORMAL: return NORMAL_PRIORITY_CLASS;
790 case PROCESS_PRIOCLASS_ABOVE_NORMAL: return ABOVE_NORMAL_PRIORITY_CLASS;
791 case PROCESS_PRIOCLASS_HIGH: return HIGH_PRIORITY_CLASS;
792 case PROCESS_PRIOCLASS_REALTIME: return REALTIME_PRIORITY_CLASS;
793 default: return 0;
798 /******************************************************************
799 * GetProcessHandleCount (kernelbase.@)
801 BOOL WINAPI DECLSPEC_HOTPATCH GetProcessHandleCount( HANDLE process, DWORD *count )
803 return set_ntstatus( NtQueryInformationProcess( process, ProcessHandleCount,
804 count, sizeof(*count), NULL ));
808 /***********************************************************************
809 * GetProcessHeap (kernelbase.@)
811 HANDLE WINAPI kernelbase_GetProcessHeap(void)
813 return NtCurrentTeb()->Peb->ProcessHeap;
817 /*********************************************************************
818 * GetProcessId (kernelbase.@)
820 DWORD WINAPI DECLSPEC_HOTPATCH GetProcessId( HANDLE process )
822 PROCESS_BASIC_INFORMATION pbi;
824 if (!set_ntstatus( NtQueryInformationProcess( process, ProcessBasicInformation,
825 &pbi, sizeof(pbi), NULL )))
826 return 0;
827 return pbi.UniqueProcessId;
831 /**********************************************************************
832 * GetProcessMitigationPolicy (kernelbase.@)
834 BOOL WINAPI /* DECLSPEC_HOTPATCH */ GetProcessMitigationPolicy( HANDLE process, PROCESS_MITIGATION_POLICY policy,
835 void *buffer, SIZE_T length )
837 FIXME( "(%p, %u, %p, %lu): stub\n", process, policy, buffer, length );
838 return TRUE;
842 /***********************************************************************
843 * GetProcessPriorityBoost (kernelbase.@)
845 BOOL WINAPI DECLSPEC_HOTPATCH GetProcessPriorityBoost( HANDLE process, PBOOL disable )
847 FIXME( "(%p,%p): semi-stub\n", process, disable );
848 *disable = FALSE; /* report that no boost is present */
849 return TRUE;
853 /***********************************************************************
854 * GetProcessShutdownParameters (kernelbase.@)
856 BOOL WINAPI DECLSPEC_HOTPATCH GetProcessShutdownParameters( LPDWORD level, LPDWORD flags )
858 *level = shutdown_priority;
859 *flags = shutdown_flags;
860 return TRUE;
864 /*********************************************************************
865 * GetProcessTimes (kernelbase.@)
867 BOOL WINAPI DECLSPEC_HOTPATCH GetProcessTimes( HANDLE process, FILETIME *create, FILETIME *exit,
868 FILETIME *kernel, FILETIME *user )
870 KERNEL_USER_TIMES time;
872 if (!set_ntstatus( NtQueryInformationProcess( process, ProcessTimes, &time, sizeof(time), NULL )))
873 return FALSE;
875 create->dwLowDateTime = time.CreateTime.u.LowPart;
876 create->dwHighDateTime = time.CreateTime.u.HighPart;
877 exit->dwLowDateTime = time.ExitTime.u.LowPart;
878 exit->dwHighDateTime = time.ExitTime.u.HighPart;
879 kernel->dwLowDateTime = time.KernelTime.u.LowPart;
880 kernel->dwHighDateTime = time.KernelTime.u.HighPart;
881 user->dwLowDateTime = time.UserTime.u.LowPart;
882 user->dwHighDateTime = time.UserTime.u.HighPart;
883 return TRUE;
887 /***********************************************************************
888 * GetProcessVersion (kernelbase.@)
890 DWORD WINAPI DECLSPEC_HOTPATCH GetProcessVersion( DWORD pid )
892 SECTION_IMAGE_INFORMATION info;
893 NTSTATUS status;
894 HANDLE process;
896 if (pid && pid != GetCurrentProcessId())
898 if (!(process = OpenProcess( PROCESS_QUERY_INFORMATION, FALSE, pid ))) return 0;
899 status = NtQueryInformationProcess( process, ProcessImageInformation, &info, sizeof(info), NULL );
900 CloseHandle( process );
902 else status = NtQueryInformationProcess( GetCurrentProcess(), ProcessImageInformation,
903 &info, sizeof(info), NULL );
905 if (!set_ntstatus( status )) return 0;
906 return MAKELONG( info.SubsystemVersionLow, info.SubsystemVersionHigh );
910 /***********************************************************************
911 * GetProcessWorkingSetSizeEx (kernelbase.@)
913 BOOL WINAPI DECLSPEC_HOTPATCH GetProcessWorkingSetSizeEx( HANDLE process, SIZE_T *minset,
914 SIZE_T *maxset, DWORD *flags)
916 FIXME( "(%p,%p,%p,%p): stub\n", process, minset, maxset, flags );
917 /* 32 MB working set size */
918 if (minset) *minset = 32*1024*1024;
919 if (maxset) *maxset = 32*1024*1024;
920 if (flags) *flags = QUOTA_LIMITS_HARDWS_MIN_DISABLE | QUOTA_LIMITS_HARDWS_MAX_DISABLE;
921 return TRUE;
925 /******************************************************************************
926 * IsProcessInJob (kernelbase.@)
928 BOOL WINAPI DECLSPEC_HOTPATCH IsProcessInJob( HANDLE process, HANDLE job, BOOL *result )
930 NTSTATUS status = NtIsProcessInJob( process, job );
932 switch (status)
934 case STATUS_PROCESS_IN_JOB:
935 *result = TRUE;
936 return TRUE;
937 case STATUS_PROCESS_NOT_IN_JOB:
938 *result = FALSE;
939 return TRUE;
940 default:
941 return set_ntstatus( status );
946 /***********************************************************************
947 * IsProcessorFeaturePresent (kernelbase.@)
949 BOOL WINAPI DECLSPEC_HOTPATCH IsProcessorFeaturePresent ( DWORD feature )
951 return RtlIsProcessorFeaturePresent( feature );
955 /**********************************************************************
956 * IsWow64Process2 (kernelbase.@)
958 BOOL WINAPI DECLSPEC_HOTPATCH IsWow64Process2( HANDLE process, USHORT *machine, USHORT *native_machine )
960 BOOL wow64;
961 SYSTEM_INFO si;
963 TRACE( "(%p,%p,%p)\n", process, machine, native_machine );
965 if (!IsWow64Process( process, &wow64 ))
966 return FALSE;
968 if (wow64)
970 if (process != GetCurrentProcess())
972 #if defined(__i386__) || defined(__x86_64__)
973 *machine = IMAGE_FILE_MACHINE_I386;
974 #else
975 FIXME("not implemented for other process\n");
976 *machine = IMAGE_FILE_MACHINE_UNKNOWN;
977 #endif
979 else
981 IMAGE_NT_HEADERS *nt;
982 nt = RtlImageNtHeader( NtCurrentTeb()->Peb->ImageBaseAddress );
983 *machine = nt->FileHeader.Machine;
986 if (!native_machine) return TRUE;
988 GetNativeSystemInfo( &si );
990 else
992 *machine = IMAGE_FILE_MACHINE_UNKNOWN;
994 if (!native_machine) return TRUE;
996 #ifdef _WIN64
997 GetSystemInfo( &si );
998 #else
999 GetNativeSystemInfo( &si );
1000 #endif
1003 switch (si.u.s.wProcessorArchitecture)
1005 case PROCESSOR_ARCHITECTURE_INTEL:
1006 *native_machine = IMAGE_FILE_MACHINE_I386;
1007 break;
1008 case PROCESSOR_ARCHITECTURE_ARM:
1009 *native_machine = IMAGE_FILE_MACHINE_ARM;
1010 break;
1011 case PROCESSOR_ARCHITECTURE_AMD64:
1012 *native_machine = IMAGE_FILE_MACHINE_AMD64;
1013 break;
1014 case PROCESSOR_ARCHITECTURE_ARM64:
1015 *native_machine = IMAGE_FILE_MACHINE_ARM64;
1016 break;
1017 default:
1018 FIXME("unknown architecture %u\n", si.u.s.wProcessorArchitecture);
1019 *native_machine = IMAGE_FILE_MACHINE_UNKNOWN;
1020 break;
1023 return TRUE;
1027 /**********************************************************************
1028 * IsWow64Process (kernelbase.@)
1030 BOOL WINAPI DECLSPEC_HOTPATCH IsWow64Process( HANDLE process, PBOOL wow64 )
1032 ULONG_PTR pbi;
1033 NTSTATUS status;
1035 status = NtQueryInformationProcess( process, ProcessWow64Information, &pbi, sizeof(pbi), NULL );
1036 if (!status) *wow64 = !!pbi;
1037 return set_ntstatus( status );
1041 /*********************************************************************
1042 * OpenProcess (kernelbase.@)
1044 HANDLE WINAPI DECLSPEC_HOTPATCH OpenProcess( DWORD access, BOOL inherit, DWORD id )
1046 HANDLE handle;
1047 OBJECT_ATTRIBUTES attr;
1048 CLIENT_ID cid;
1050 if (GetVersion() & 0x80000000) access = PROCESS_ALL_ACCESS;
1052 attr.Length = sizeof(OBJECT_ATTRIBUTES);
1053 attr.RootDirectory = 0;
1054 attr.Attributes = inherit ? OBJ_INHERIT : 0;
1055 attr.ObjectName = NULL;
1056 attr.SecurityDescriptor = NULL;
1057 attr.SecurityQualityOfService = NULL;
1059 cid.UniqueProcess = ULongToHandle(id);
1060 cid.UniqueThread = 0;
1062 if (!set_ntstatus( NtOpenProcess( &handle, access, &attr, &cid ))) return NULL;
1063 return handle;
1067 /***********************************************************************
1068 * ProcessIdToSessionId (kernelbase.@)
1070 BOOL WINAPI DECLSPEC_HOTPATCH ProcessIdToSessionId( DWORD procid, DWORD *sessionid )
1072 if (procid != GetCurrentProcessId()) FIXME( "Unsupported for other process %x\n", procid );
1073 *sessionid = NtCurrentTeb()->Peb->SessionId;
1074 return TRUE;
1078 /***********************************************************************
1079 * QueryProcessCycleTime (kernelbase.@)
1081 BOOL WINAPI DECLSPEC_HOTPATCH QueryProcessCycleTime( HANDLE process, ULONG64 *cycle )
1083 static int once;
1084 if (!once++) FIXME( "(%p,%p): stub!\n", process, cycle );
1085 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
1086 return FALSE;
1090 /***********************************************************************
1091 * SetErrorMode (kernelbase.@)
1093 UINT WINAPI DECLSPEC_HOTPATCH SetErrorMode( UINT mode )
1095 UINT old = GetErrorMode();
1097 NtSetInformationProcess( GetCurrentProcess(), ProcessDefaultHardErrorMode,
1098 &mode, sizeof(mode) );
1099 return old;
1103 /*************************************************************************
1104 * SetHandleCount (kernelbase.@)
1106 UINT WINAPI DECLSPEC_HOTPATCH SetHandleCount( UINT count )
1108 return count;
1112 /*********************************************************************
1113 * SetHandleInformation (kernelbase.@)
1115 BOOL WINAPI DECLSPEC_HOTPATCH SetHandleInformation( HANDLE handle, DWORD mask, DWORD flags )
1117 OBJECT_DATA_INFORMATION info;
1119 /* if not setting both fields, retrieve current value first */
1120 if ((mask & (HANDLE_FLAG_INHERIT | HANDLE_FLAG_PROTECT_FROM_CLOSE)) !=
1121 (HANDLE_FLAG_INHERIT | HANDLE_FLAG_PROTECT_FROM_CLOSE))
1123 if (!set_ntstatus( NtQueryObject( handle, ObjectDataInformation, &info, sizeof(info), NULL )))
1124 return FALSE;
1126 if (mask & HANDLE_FLAG_INHERIT)
1127 info.InheritHandle = (flags & HANDLE_FLAG_INHERIT) != 0;
1128 if (mask & HANDLE_FLAG_PROTECT_FROM_CLOSE)
1129 info.ProtectFromClose = (flags & HANDLE_FLAG_PROTECT_FROM_CLOSE) != 0;
1131 return set_ntstatus( NtSetInformationObject( handle, ObjectDataInformation, &info, sizeof(info) ));
1135 /***********************************************************************
1136 * SetPriorityClass (kernelbase.@)
1138 BOOL WINAPI DECLSPEC_HOTPATCH SetPriorityClass( HANDLE process, DWORD class )
1140 PROCESS_PRIORITY_CLASS ppc;
1142 ppc.Foreground = FALSE;
1143 switch (class)
1145 case IDLE_PRIORITY_CLASS: ppc.PriorityClass = PROCESS_PRIOCLASS_IDLE; break;
1146 case BELOW_NORMAL_PRIORITY_CLASS: ppc.PriorityClass = PROCESS_PRIOCLASS_BELOW_NORMAL; break;
1147 case NORMAL_PRIORITY_CLASS: ppc.PriorityClass = PROCESS_PRIOCLASS_NORMAL; break;
1148 case ABOVE_NORMAL_PRIORITY_CLASS: ppc.PriorityClass = PROCESS_PRIOCLASS_ABOVE_NORMAL; break;
1149 case HIGH_PRIORITY_CLASS: ppc.PriorityClass = PROCESS_PRIOCLASS_HIGH; break;
1150 case REALTIME_PRIORITY_CLASS: ppc.PriorityClass = PROCESS_PRIOCLASS_REALTIME; break;
1151 default:
1152 SetLastError( ERROR_INVALID_PARAMETER );
1153 return FALSE;
1155 return set_ntstatus( NtSetInformationProcess( process, ProcessPriorityClass, &ppc, sizeof(ppc) ));
1159 /***********************************************************************
1160 * SetProcessAffinityUpdateMode (kernelbase.@)
1162 BOOL WINAPI DECLSPEC_HOTPATCH SetProcessAffinityUpdateMode( HANDLE process, DWORD flags )
1164 FIXME( "(%p,0x%08x): stub\n", process, flags );
1165 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
1166 return FALSE;
1170 /**********************************************************************
1171 * SetProcessMitigationPolicy (kernelbase.@)
1173 BOOL WINAPI /* DECLSPEC_HOTPATCH */ SetProcessMitigationPolicy( PROCESS_MITIGATION_POLICY policy,
1174 void *buffer, SIZE_T length )
1176 FIXME( "(%d, %p, %lu): stub\n", policy, buffer, length );
1177 return TRUE;
1181 /***********************************************************************
1182 * SetProcessPriorityBoost (kernelbase.@)
1184 BOOL WINAPI /* DECLSPEC_HOTPATCH */ SetProcessPriorityBoost( HANDLE process, BOOL disable )
1186 FIXME( "(%p,%d): stub\n", process, disable );
1187 return TRUE;
1191 /***********************************************************************
1192 * SetProcessShutdownParameters (kernelbase.@)
1194 BOOL WINAPI DECLSPEC_HOTPATCH SetProcessShutdownParameters( DWORD level, DWORD flags )
1196 FIXME( "(%08x, %08x): partial stub.\n", level, flags );
1197 shutdown_flags = flags;
1198 shutdown_priority = level;
1199 return TRUE;
1203 /***********************************************************************
1204 * SetProcessWorkingSetSizeEx (kernelbase.@)
1206 BOOL WINAPI DECLSPEC_HOTPATCH SetProcessWorkingSetSizeEx( HANDLE process, SIZE_T minset,
1207 SIZE_T maxset, DWORD flags )
1209 return TRUE;
1213 /******************************************************************************
1214 * TerminateProcess (kernelbase.@)
1216 BOOL WINAPI DECLSPEC_HOTPATCH TerminateProcess( HANDLE handle, DWORD exit_code )
1218 if (!handle)
1220 SetLastError( ERROR_INVALID_HANDLE );
1221 return FALSE;
1223 return set_ntstatus( NtTerminateProcess( handle, exit_code ));
1227 /***********************************************************************
1228 * Process startup information
1229 ***********************************************************************/
1232 static STARTUPINFOW startup_infoW;
1233 static char *command_lineA;
1234 static WCHAR *command_lineW;
1236 /******************************************************************
1237 * init_startup_info
1239 void init_startup_info( RTL_USER_PROCESS_PARAMETERS *params )
1241 ANSI_STRING ansi;
1243 startup_infoW.cb = sizeof(startup_infoW);
1244 startup_infoW.lpReserved = NULL;
1245 startup_infoW.lpDesktop = params->Desktop.Buffer;
1246 startup_infoW.lpTitle = params->WindowTitle.Buffer;
1247 startup_infoW.dwX = params->dwX;
1248 startup_infoW.dwY = params->dwY;
1249 startup_infoW.dwXSize = params->dwXSize;
1250 startup_infoW.dwYSize = params->dwYSize;
1251 startup_infoW.dwXCountChars = params->dwXCountChars;
1252 startup_infoW.dwYCountChars = params->dwYCountChars;
1253 startup_infoW.dwFillAttribute = params->dwFillAttribute;
1254 startup_infoW.dwFlags = params->dwFlags;
1255 startup_infoW.wShowWindow = params->wShowWindow;
1256 startup_infoW.cbReserved2 = params->RuntimeInfo.MaximumLength;
1257 startup_infoW.lpReserved2 = params->RuntimeInfo.MaximumLength ? (void *)params->RuntimeInfo.Buffer : NULL;
1258 startup_infoW.hStdInput = params->hStdInput ? params->hStdInput : INVALID_HANDLE_VALUE;
1259 startup_infoW.hStdOutput = params->hStdOutput ? params->hStdOutput : INVALID_HANDLE_VALUE;
1260 startup_infoW.hStdError = params->hStdError ? params->hStdError : INVALID_HANDLE_VALUE;
1262 command_lineW = params->CommandLine.Buffer;
1263 if (!RtlUnicodeStringToAnsiString( &ansi, &params->CommandLine, TRUE )) command_lineA = ansi.Buffer;
1267 /**********************************************************************
1268 * BaseFlushAppcompatCache (kernelbase.@)
1270 BOOL WINAPI BaseFlushAppcompatCache(void)
1272 FIXME( "stub\n" );
1273 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
1274 return FALSE;
1278 /***********************************************************************
1279 * GetCommandLineA (kernelbase.@)
1281 LPSTR WINAPI DECLSPEC_HOTPATCH GetCommandLineA(void)
1283 return command_lineA;
1287 /***********************************************************************
1288 * GetCommandLineW (kernelbase.@)
1290 LPWSTR WINAPI DECLSPEC_HOTPATCH GetCommandLineW(void)
1292 return NtCurrentTeb()->Peb->ProcessParameters->CommandLine.Buffer;
1296 /***********************************************************************
1297 * GetStartupInfoW (kernelbase.@)
1299 void WINAPI DECLSPEC_HOTPATCH GetStartupInfoW( STARTUPINFOW *info )
1301 *info = startup_infoW;
1305 /***********************************************************************
1306 * GetStdHandle (kernelbase.@)
1308 HANDLE WINAPI DECLSPEC_HOTPATCH GetStdHandle( DWORD std_handle )
1310 switch (std_handle)
1312 case STD_INPUT_HANDLE: return NtCurrentTeb()->Peb->ProcessParameters->hStdInput;
1313 case STD_OUTPUT_HANDLE: return NtCurrentTeb()->Peb->ProcessParameters->hStdOutput;
1314 case STD_ERROR_HANDLE: return NtCurrentTeb()->Peb->ProcessParameters->hStdError;
1316 SetLastError( ERROR_INVALID_HANDLE );
1317 return INVALID_HANDLE_VALUE;
1321 /***********************************************************************
1322 * SetStdHandle (kernelbase.@)
1324 BOOL WINAPI DECLSPEC_HOTPATCH SetStdHandle( DWORD std_handle, HANDLE handle )
1326 switch (std_handle)
1328 case STD_INPUT_HANDLE: NtCurrentTeb()->Peb->ProcessParameters->hStdInput = handle; return TRUE;
1329 case STD_OUTPUT_HANDLE: NtCurrentTeb()->Peb->ProcessParameters->hStdOutput = handle; return TRUE;
1330 case STD_ERROR_HANDLE: NtCurrentTeb()->Peb->ProcessParameters->hStdError = handle; return TRUE;
1332 SetLastError( ERROR_INVALID_HANDLE );
1333 return FALSE;
1337 /***********************************************************************
1338 * SetStdHandleEx (kernelbase.@)
1340 BOOL WINAPI DECLSPEC_HOTPATCH SetStdHandleEx( DWORD std_handle, HANDLE handle, HANDLE *prev )
1342 HANDLE *ptr;
1344 switch (std_handle)
1346 case STD_INPUT_HANDLE: ptr = &NtCurrentTeb()->Peb->ProcessParameters->hStdInput; break;
1347 case STD_OUTPUT_HANDLE: ptr = &NtCurrentTeb()->Peb->ProcessParameters->hStdOutput; break;
1348 case STD_ERROR_HANDLE: ptr = &NtCurrentTeb()->Peb->ProcessParameters->hStdError; break;
1349 default:
1350 SetLastError( ERROR_INVALID_HANDLE );
1351 return FALSE;
1353 if (prev) *prev = *ptr;
1354 *ptr = handle;
1355 return TRUE;
1359 /***********************************************************************
1360 * Process environment
1361 ***********************************************************************/
1364 static inline SIZE_T get_env_length( const WCHAR *env )
1366 const WCHAR *end = env;
1367 while (*end) end += lstrlenW(end) + 1;
1368 return end + 1 - env;
1371 /***********************************************************************
1372 * ExpandEnvironmentStringsA (kernelbase.@)
1374 DWORD WINAPI DECLSPEC_HOTPATCH ExpandEnvironmentStringsA( LPCSTR src, LPSTR dst, DWORD count )
1376 UNICODE_STRING us_src;
1377 PWSTR dstW = NULL;
1378 DWORD ret;
1380 RtlCreateUnicodeStringFromAsciiz( &us_src, src );
1381 if (count)
1383 if (!(dstW = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WCHAR)))) return 0;
1384 ret = ExpandEnvironmentStringsW( us_src.Buffer, dstW, count);
1385 if (ret) WideCharToMultiByte( CP_ACP, 0, dstW, ret, dst, count, NULL, NULL );
1387 else ret = ExpandEnvironmentStringsW( us_src.Buffer, NULL, 0 );
1389 RtlFreeUnicodeString( &us_src );
1390 HeapFree( GetProcessHeap(), 0, dstW );
1391 return ret;
1395 /***********************************************************************
1396 * ExpandEnvironmentStringsW (kernelbase.@)
1398 DWORD WINAPI DECLSPEC_HOTPATCH ExpandEnvironmentStringsW( LPCWSTR src, LPWSTR dst, DWORD len )
1400 UNICODE_STRING us_src, us_dst;
1401 NTSTATUS status;
1402 DWORD res;
1404 TRACE( "(%s %p %u)\n", debugstr_w(src), dst, len );
1406 RtlInitUnicodeString( &us_src, src );
1408 /* make sure we don't overflow the maximum UNICODE_STRING size */
1409 len = min( len, UNICODE_STRING_MAX_CHARS );
1411 us_dst.Length = 0;
1412 us_dst.MaximumLength = len * sizeof(WCHAR);
1413 us_dst.Buffer = dst;
1415 res = 0;
1416 status = RtlExpandEnvironmentStrings_U( NULL, &us_src, &us_dst, &res );
1417 res /= sizeof(WCHAR);
1418 if (!set_ntstatus( status ))
1420 if (status != STATUS_BUFFER_TOO_SMALL) return 0;
1421 if (len && dst) dst[len - 1] = 0;
1423 return res;
1427 /***********************************************************************
1428 * GetEnvironmentStrings (kernelbase.@)
1429 * GetEnvironmentStringsA (kernelbase.@)
1431 LPSTR WINAPI DECLSPEC_HOTPATCH GetEnvironmentStringsA(void)
1433 LPWSTR env;
1434 LPSTR ret;
1435 SIZE_T lenA, lenW;
1437 RtlAcquirePebLock();
1438 env = NtCurrentTeb()->Peb->ProcessParameters->Environment;
1439 lenW = get_env_length( env );
1440 lenA = WideCharToMultiByte( CP_ACP, 0, env, lenW, NULL, 0, NULL, NULL );
1441 if ((ret = HeapAlloc( GetProcessHeap(), 0, lenA )))
1442 WideCharToMultiByte( CP_ACP, 0, env, lenW, ret, lenA, NULL, NULL );
1443 RtlReleasePebLock();
1444 return ret;
1448 /***********************************************************************
1449 * GetEnvironmentStringsW (kernelbase.@)
1451 LPWSTR WINAPI DECLSPEC_HOTPATCH GetEnvironmentStringsW(void)
1453 LPWSTR ret;
1454 SIZE_T len;
1456 RtlAcquirePebLock();
1457 len = get_env_length( NtCurrentTeb()->Peb->ProcessParameters->Environment ) * sizeof(WCHAR);
1458 if ((ret = HeapAlloc( GetProcessHeap(), 0, len )))
1459 memcpy( ret, NtCurrentTeb()->Peb->ProcessParameters->Environment, len );
1460 RtlReleasePebLock();
1461 return ret;
1465 /***********************************************************************
1466 * SetEnvironmentStringsA (kernelbase.@)
1468 BOOL WINAPI DECLSPEC_HOTPATCH SetEnvironmentStringsA( char *env )
1470 WCHAR *envW;
1471 const char *p = env;
1472 DWORD len;
1473 BOOL ret;
1475 for (p = env; *p; p += strlen( p ) + 1);
1477 len = MultiByteToWideChar( CP_ACP, 0, env, p - env, NULL, 0 );
1478 if (!(envW = HeapAlloc( GetProcessHeap(), 0, len )))
1480 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1481 return FALSE;
1483 MultiByteToWideChar( CP_ACP, 0, env, p - env, envW, len );
1484 ret = SetEnvironmentStringsW( envW );
1485 HeapFree( GetProcessHeap(), 0, envW );
1486 return ret;
1490 /***********************************************************************
1491 * SetEnvironmentStringsW (kernelbase.@)
1493 BOOL WINAPI DECLSPEC_HOTPATCH SetEnvironmentStringsW( WCHAR *env )
1495 WCHAR *p;
1496 WCHAR *new_env;
1497 NTSTATUS status;
1499 for (p = env; *p; p += wcslen( p ) + 1)
1501 const WCHAR *eq = wcschr( p, '=' );
1502 if (!eq || eq == p)
1504 SetLastError( ERROR_INVALID_PARAMETER );
1505 return FALSE;
1509 if ((status = RtlCreateEnvironment( FALSE, &new_env )))
1510 return set_ntstatus( status );
1512 for (p = env; *p; p += wcslen( p ) + 1)
1514 const WCHAR *eq = wcschr( p, '=' );
1515 UNICODE_STRING var, value;
1516 var.Buffer = p;
1517 var.Length = (eq - p) * sizeof(WCHAR);
1518 RtlInitUnicodeString( &value, eq + 1 );
1519 if ((status = RtlSetEnvironmentVariable( &new_env, &var, &value )))
1521 RtlDestroyEnvironment( new_env );
1522 return set_ntstatus( status );
1526 RtlSetCurrentEnvironment( new_env, NULL );
1527 return TRUE;
1531 /***********************************************************************
1532 * GetEnvironmentVariableA (kernelbase.@)
1534 DWORD WINAPI DECLSPEC_HOTPATCH GetEnvironmentVariableA( LPCSTR name, LPSTR value, DWORD size )
1536 UNICODE_STRING us_name, us_value;
1537 PWSTR valueW;
1538 NTSTATUS status;
1539 DWORD len, ret;
1541 /* limit the size to sane values */
1542 size = min( size, 32767 );
1543 if (!(valueW = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) return 0;
1545 RtlCreateUnicodeStringFromAsciiz( &us_name, name );
1546 us_value.Length = 0;
1547 us_value.MaximumLength = (size ? size - 1 : 0) * sizeof(WCHAR);
1548 us_value.Buffer = valueW;
1550 status = RtlQueryEnvironmentVariable_U( NULL, &us_name, &us_value );
1551 len = us_value.Length / sizeof(WCHAR);
1552 if (status == STATUS_BUFFER_TOO_SMALL) ret = len + 1;
1553 else if (!set_ntstatus( status )) ret = 0;
1554 else if (!size) ret = len + 1;
1555 else
1557 if (len) WideCharToMultiByte( CP_ACP, 0, valueW, len + 1, value, size, NULL, NULL );
1558 value[len] = 0;
1559 ret = len;
1562 RtlFreeUnicodeString( &us_name );
1563 HeapFree( GetProcessHeap(), 0, valueW );
1564 return ret;
1568 /***********************************************************************
1569 * GetEnvironmentVariableW (kernelbase.@)
1571 DWORD WINAPI DECLSPEC_HOTPATCH GetEnvironmentVariableW( LPCWSTR name, LPWSTR val, DWORD size )
1573 UNICODE_STRING us_name, us_value;
1574 NTSTATUS status;
1575 DWORD len;
1577 TRACE( "(%s %p %u)\n", debugstr_w(name), val, size );
1579 RtlInitUnicodeString( &us_name, name );
1580 us_value.Length = 0;
1581 us_value.MaximumLength = (size ? size - 1 : 0) * sizeof(WCHAR);
1582 us_value.Buffer = val;
1584 status = RtlQueryEnvironmentVariable_U( NULL, &us_name, &us_value );
1585 len = us_value.Length / sizeof(WCHAR);
1586 if (status == STATUS_BUFFER_TOO_SMALL) return len + 1;
1587 if (!set_ntstatus( status )) return 0;
1588 if (!size) return len + 1;
1589 val[len] = 0;
1590 return len;
1594 /***********************************************************************
1595 * FreeEnvironmentStringsA (kernelbase.@)
1596 * FreeEnvironmentStringsW (kernelbase.@)
1598 BOOL WINAPI DECLSPEC_HOTPATCH FreeEnvironmentStringsW( LPWSTR ptr )
1600 return HeapFree( GetProcessHeap(), 0, ptr );
1604 /***********************************************************************
1605 * SetEnvironmentVariableA (kernelbase.@)
1607 BOOL WINAPI DECLSPEC_HOTPATCH SetEnvironmentVariableA( LPCSTR name, LPCSTR value )
1609 UNICODE_STRING us_name, us_value;
1610 BOOL ret;
1612 if (!name)
1614 SetLastError( ERROR_ENVVAR_NOT_FOUND );
1615 return FALSE;
1618 RtlCreateUnicodeStringFromAsciiz( &us_name, name );
1619 if (value)
1621 RtlCreateUnicodeStringFromAsciiz( &us_value, value );
1622 ret = SetEnvironmentVariableW( us_name.Buffer, us_value.Buffer );
1623 RtlFreeUnicodeString( &us_value );
1625 else ret = SetEnvironmentVariableW( us_name.Buffer, NULL );
1626 RtlFreeUnicodeString( &us_name );
1627 return ret;
1631 /***********************************************************************
1632 * SetEnvironmentVariableW (kernelbase.@)
1634 BOOL WINAPI DECLSPEC_HOTPATCH SetEnvironmentVariableW( LPCWSTR name, LPCWSTR value )
1636 UNICODE_STRING us_name, us_value;
1637 NTSTATUS status;
1639 TRACE( "(%s %s)\n", debugstr_w(name), debugstr_w(value) );
1641 if (!name)
1643 SetLastError( ERROR_ENVVAR_NOT_FOUND );
1644 return FALSE;
1647 RtlInitUnicodeString( &us_name, name );
1648 if (value)
1650 RtlInitUnicodeString( &us_value, value );
1651 status = RtlSetEnvironmentVariable( NULL, &us_name, &us_value );
1653 else status = RtlSetEnvironmentVariable( NULL, &us_name, NULL );
1655 return set_ntstatus( status );
1659 /***********************************************************************
1660 * Process/thread attribute lists
1661 ***********************************************************************/
1663 /***********************************************************************
1664 * InitializeProcThreadAttributeList (kernelbase.@)
1666 BOOL WINAPI DECLSPEC_HOTPATCH InitializeProcThreadAttributeList( struct _PROC_THREAD_ATTRIBUTE_LIST *list,
1667 DWORD count, DWORD flags, SIZE_T *size )
1669 SIZE_T needed;
1670 BOOL ret = FALSE;
1672 TRACE( "(%p %d %x %p)\n", list, count, flags, size );
1674 needed = FIELD_OFFSET( struct _PROC_THREAD_ATTRIBUTE_LIST, attrs[count] );
1675 if (list && *size >= needed)
1677 list->mask = 0;
1678 list->size = count;
1679 list->count = 0;
1680 list->unk = 0;
1681 ret = TRUE;
1683 else SetLastError( ERROR_INSUFFICIENT_BUFFER );
1685 *size = needed;
1686 return ret;
1690 /***********************************************************************
1691 * UpdateProcThreadAttribute (kernelbase.@)
1693 BOOL WINAPI DECLSPEC_HOTPATCH UpdateProcThreadAttribute( struct _PROC_THREAD_ATTRIBUTE_LIST *list,
1694 DWORD flags, DWORD_PTR attr, void *value,
1695 SIZE_T size, void *prev_ret, SIZE_T *size_ret )
1697 DWORD mask;
1698 struct proc_thread_attr *entry;
1700 TRACE( "(%p %x %08lx %p %ld %p %p)\n", list, flags, attr, value, size, prev_ret, size_ret );
1702 if (list->count >= list->size)
1704 SetLastError( ERROR_GEN_FAILURE );
1705 return FALSE;
1708 switch (attr)
1710 case PROC_THREAD_ATTRIBUTE_PARENT_PROCESS:
1711 if (size != sizeof(HANDLE))
1713 SetLastError( ERROR_BAD_LENGTH );
1714 return FALSE;
1716 break;
1718 case PROC_THREAD_ATTRIBUTE_HANDLE_LIST:
1719 if ((size / sizeof(HANDLE)) * sizeof(HANDLE) != size)
1721 SetLastError( ERROR_BAD_LENGTH );
1722 return FALSE;
1724 break;
1726 case PROC_THREAD_ATTRIBUTE_IDEAL_PROCESSOR:
1727 if (size != sizeof(PROCESSOR_NUMBER))
1729 SetLastError( ERROR_BAD_LENGTH );
1730 return FALSE;
1732 break;
1734 case PROC_THREAD_ATTRIBUTE_CHILD_PROCESS_POLICY:
1735 if (size != sizeof(DWORD) && size != sizeof(DWORD64))
1737 SetLastError( ERROR_BAD_LENGTH );
1738 return FALSE;
1740 break;
1742 case PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY:
1743 if (size != sizeof(DWORD) && size != sizeof(DWORD64) && size != sizeof(DWORD64) * 2)
1745 SetLastError( ERROR_BAD_LENGTH );
1746 return FALSE;
1748 break;
1750 case PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE:
1751 if (size != sizeof(HPCON))
1753 SetLastError( ERROR_BAD_LENGTH );
1754 return FALSE;
1756 break;
1758 default:
1759 SetLastError( ERROR_NOT_SUPPORTED );
1760 FIXME( "Unhandled attribute %lu\n", attr & PROC_THREAD_ATTRIBUTE_NUMBER );
1761 return FALSE;
1764 mask = 1 << (attr & PROC_THREAD_ATTRIBUTE_NUMBER);
1765 if (list->mask & mask)
1767 SetLastError( ERROR_OBJECT_NAME_EXISTS );
1768 return FALSE;
1770 list->mask |= mask;
1772 entry = list->attrs + list->count;
1773 entry->attr = attr;
1774 entry->size = size;
1775 entry->value = value;
1776 list->count++;
1777 return TRUE;
1781 /***********************************************************************
1782 * DeleteProcThreadAttributeList (kernelbase.@)
1784 void WINAPI DECLSPEC_HOTPATCH DeleteProcThreadAttributeList( struct _PROC_THREAD_ATTRIBUTE_LIST *list )
1786 return;