Reactos
1/*
2 * Win32 processes
3 *
4 * Copyright 1996, 1998 Alexandre Julliard
5 *
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.
10 *
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.
15 *
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
19 */
20
21#include <stdarg.h>
22#include <string.h>
23
24#include "ntstatus.h"
25#define WIN32_NO_STATUS
26#include "windef.h"
27#include "winbase.h"
28#include "winnls.h"
29#include "wincontypes.h"
30#include "winternl.h"
31
32#include "kernelbase.h"
33#include "wine/debug.h"
34#include "wine/condrv.h"
35
36WINE_DEFAULT_DEBUG_CHANNEL(process);
37
38static DWORD shutdown_flags = 0;
39static DWORD shutdown_priority = 0x280;
40
41/***********************************************************************
42 * Processes
43 ***********************************************************************/
44
45
46/***********************************************************************
47 * find_exe_file
48 */
49static BOOL find_exe_file( const WCHAR *name, WCHAR *buffer, DWORD buflen )
50{
51 WCHAR *load_path;
52 BOOL ret;
53
54 if (!set_ntstatus( RtlGetExePath( name, &load_path ))) return FALSE;
55
56 TRACE( "looking for %s in %s\n", debugstr_w(name), debugstr_w(load_path) );
57
58 ret = (SearchPathW( load_path, name, L".exe", buflen, buffer, NULL ) ||
59 /* not found, try without extension in case it is a Unix app */
60 SearchPathW( load_path, name, NULL, buflen, buffer, NULL ));
61
62 if (ret) /* make sure it can be opened, SearchPathW also returns directories */
63 {
64 HANDLE handle = CreateFileW( buffer, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_DELETE,
65 NULL, OPEN_EXISTING, 0, 0 );
66 if ((ret = (handle != INVALID_HANDLE_VALUE))) CloseHandle( handle );
67 }
68 RtlReleasePath( load_path );
69 return ret;
70}
71
72
73/*************************************************************************
74 * get_file_name
75 *
76 * Helper for CreateProcess: retrieve the file name to load from the
77 * app name and command line. Store the file name in buffer, and
78 * return a possibly modified command line.
79 */
80static WCHAR *get_file_name( WCHAR *cmdline, WCHAR *buffer, DWORD buflen )
81{
82 WCHAR *name, *pos, *first_space, *ret = NULL;
83 const WCHAR *p;
84
85 /* first check for a quoted file name */
86
87 if (cmdline[0] == '"' && (p = wcschr( cmdline + 1, '"' )))
88 {
89 int len = p - cmdline - 1;
90 /* extract the quoted portion as file name */
91 if (!(name = RtlAllocateHeap( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return NULL;
92 memcpy( name, cmdline + 1, len * sizeof(WCHAR) );
93 name[len] = 0;
94
95 if (!find_exe_file( name, buffer, buflen )) goto done;
96 ret = cmdline; /* no change necessary */
97 goto done;
98 }
99
100 /* now try the command-line word by word */
101
102 if (!(name = RtlAllocateHeap( GetProcessHeap(), 0, (lstrlenW(cmdline) + 1) * sizeof(WCHAR) )))
103 return NULL;
104 pos = name;
105 p = cmdline;
106 first_space = NULL;
107
108 for (;;)
109 {
110 while (*p && *p != ' ' && *p != '\t') *pos++ = *p++;
111 *pos = 0;
112 if (find_exe_file( name, buffer, buflen ))
113 {
114 ret = cmdline;
115 break;
116 }
117 if (!first_space) first_space = pos;
118 if (!(*pos++ = *p++)) break;
119 }
120
121 if (!ret)
122 {
123 SetLastError( ERROR_FILE_NOT_FOUND );
124 }
125 else if (first_space) /* build a new command-line with quotes */
126 {
127 if (!(ret = HeapAlloc( GetProcessHeap(), 0, (lstrlenW(cmdline) + 3) * sizeof(WCHAR) )))
128 goto done;
129 swprintf( ret, lstrlenW(cmdline) + 3, L"\"%s\"%s", name, p );
130 }
131
132 done:
133 RtlFreeHeap( GetProcessHeap(), 0, name );
134 return ret;
135}
136
137
138/***********************************************************************
139 * create_process_params
140 */
141static RTL_USER_PROCESS_PARAMETERS *create_process_params( const WCHAR *filename, const WCHAR *cmdline,
142 const WCHAR *cur_dir, void *env, DWORD flags,
143 const STARTUPINFOW *startup )
144{
145 RTL_USER_PROCESS_PARAMETERS *params;
146 UNICODE_STRING imageW, curdirW, cmdlineW, titleW, desktopW, runtimeW, newdirW;
147 WCHAR imagepath[MAX_PATH];
148 WCHAR *envW = env;
149
150 if (!GetLongPathNameW( filename, imagepath, MAX_PATH )) lstrcpynW( imagepath, filename, MAX_PATH );
151 if (!GetFullPathNameW( imagepath, MAX_PATH, imagepath, NULL )) lstrcpynW( imagepath, filename, MAX_PATH );
152
153 if (env && !(flags & CREATE_UNICODE_ENVIRONMENT)) /* convert environment to unicode */
154 {
155 char *e = env;
156 DWORD lenW;
157
158 while (*e) e += strlen(e) + 1;
159 e++; /* final null */
160 lenW = MultiByteToWideChar( CP_ACP, 0, env, e - (char *)env, NULL, 0 );
161 if ((envW = RtlAllocateHeap( GetProcessHeap(), 0, lenW * sizeof(WCHAR) )))
162 MultiByteToWideChar( CP_ACP, 0, env, e - (char *)env, envW, lenW );
163 }
164
165 newdirW.Buffer = NULL;
166 if (cur_dir)
167 {
168 if (RtlDosPathNameToNtPathName_U( cur_dir, &newdirW, NULL, NULL ))
169 cur_dir = newdirW.Buffer + 4; /* skip \??\ prefix */
170 else
171 cur_dir = NULL;
172 }
173 RtlInitUnicodeString( &imageW, imagepath );
174 RtlInitUnicodeString( &curdirW, cur_dir );
175 RtlInitUnicodeString( &cmdlineW, cmdline );
176 RtlInitUnicodeString( &titleW, startup->lpTitle ? startup->lpTitle : imagepath );
177 RtlInitUnicodeString( &desktopW, startup->lpDesktop );
178 runtimeW.Buffer = (WCHAR *)startup->lpReserved2;
179 runtimeW.Length = runtimeW.MaximumLength = startup->cbReserved2;
180 if (RtlCreateProcessParametersEx( ¶ms, &imageW, NULL, cur_dir ? &curdirW : NULL,
181 &cmdlineW, envW, &titleW, &desktopW,
182 NULL, &runtimeW, PROCESS_PARAMS_FLAG_NORMALIZED ))
183 {
184 RtlFreeUnicodeString( &newdirW );
185 if (envW != env) RtlFreeHeap( GetProcessHeap(), 0, envW );
186 return NULL;
187 }
188 RtlFreeUnicodeString( &newdirW );
189
190 if (!(flags & CREATE_NEW_PROCESS_GROUP))
191 params->ProcessGroupId = NtCurrentTeb()->Peb->ProcessParameters->ProcessGroupId;
192 else if (!(flags & CREATE_NEW_CONSOLE))
193 params->ConsoleFlags = 1;
194
195 if (flags & CREATE_NEW_CONSOLE) params->ConsoleHandle = CONSOLE_HANDLE_ALLOC;
196 else if (!(flags & DETACHED_PROCESS))
197 {
198 if (flags & CREATE_NO_WINDOW) params->ConsoleHandle = CONSOLE_HANDLE_ALLOC_NO_WINDOW;
199 else
200 {
201 params->ConsoleHandle = NtCurrentTeb()->Peb->ProcessParameters->ConsoleHandle;
202 if (!params->ConsoleHandle) params->ConsoleHandle = CONSOLE_HANDLE_ALLOC;
203 }
204 }
205
206 if (startup->dwFlags & STARTF_USESTDHANDLES)
207 {
208 params->hStdInput = startup->hStdInput;
209 params->hStdOutput = startup->hStdOutput;
210 params->hStdError = startup->hStdError;
211 }
212 else if (!(flags & (DETACHED_PROCESS | CREATE_NEW_CONSOLE)))
213 {
214 params->hStdInput = NtCurrentTeb()->Peb->ProcessParameters->hStdInput;
215 params->hStdOutput = NtCurrentTeb()->Peb->ProcessParameters->hStdOutput;
216 params->hStdError = NtCurrentTeb()->Peb->ProcessParameters->hStdError;
217 }
218
219 if (params->hStdInput == INVALID_HANDLE_VALUE) params->hStdInput = NULL;
220 if (params->hStdOutput == INVALID_HANDLE_VALUE) params->hStdOutput = NULL;
221 if (params->hStdError == INVALID_HANDLE_VALUE) params->hStdError = NULL;
222
223 params->dwX = startup->dwX;
224 params->dwY = startup->dwY;
225 params->dwXSize = startup->dwXSize;
226 params->dwYSize = startup->dwYSize;
227 params->dwXCountChars = startup->dwXCountChars;
228 params->dwYCountChars = startup->dwYCountChars;
229 params->dwFillAttribute = startup->dwFillAttribute;
230 params->dwFlags = startup->dwFlags;
231 params->wShowWindow = startup->wShowWindow;
232
233 if (envW != env) RtlFreeHeap( GetProcessHeap(), 0, envW );
234 return params;
235}
236
237struct proc_thread_attr
238{
239 DWORD_PTR attr;
240 SIZE_T size;
241 void *value;
242};
243
244struct _PROC_THREAD_ATTRIBUTE_LIST
245{
246 DWORD mask; /* bitmask of items in list */
247 DWORD size; /* max number of items in list */
248 DWORD count; /* number of items in list */
249 DWORD pad;
250 DWORD_PTR unk;
251 struct proc_thread_attr attrs[1];
252};
253
254/***********************************************************************
255 * create_nt_process
256 */
257static NTSTATUS create_nt_process( HANDLE token, HANDLE debug, SECURITY_ATTRIBUTES *psa,
258 SECURITY_ATTRIBUTES *tsa, DWORD process_flags,
259 RTL_USER_PROCESS_PARAMETERS *params,
260 RTL_USER_PROCESS_INFORMATION *info,
261 HANDLE parent, USHORT machine,
262 const struct proc_thread_attr *handle_list,
263 const struct proc_thread_attr *job_list)
264{
265 OBJECT_ATTRIBUTES process_attr, thread_attr;
266 PS_CREATE_INFO create_info;
267 ULONG_PTR buffer[offsetof( PS_ATTRIBUTE_LIST, Attributes[9] ) / sizeof(ULONG_PTR)];
268 PS_ATTRIBUTE_LIST *attr = (PS_ATTRIBUTE_LIST *)buffer;
269 UNICODE_STRING nameW;
270 NTSTATUS status;
271 UINT pos = 0;
272
273 if (!params->ImagePathName.Buffer[0]) return STATUS_OBJECT_PATH_NOT_FOUND;
274 status = RtlDosPathNameToNtPathName_U_WithStatus( params->ImagePathName.Buffer, &nameW, NULL, NULL );
275 if (!status)
276 {
277 RtlNormalizeProcessParams( params );
278
279 attr->Attributes[pos].Attribute = PS_ATTRIBUTE_IMAGE_NAME;
280 attr->Attributes[pos].Size = nameW.Length;
281 attr->Attributes[pos].ValuePtr = nameW.Buffer;
282 attr->Attributes[pos].ReturnLength = NULL;
283 pos++;
284 attr->Attributes[pos].Attribute = PS_ATTRIBUTE_CLIENT_ID;
285 attr->Attributes[pos].Size = sizeof(info->ClientId);
286 attr->Attributes[pos].ValuePtr = &info->ClientId;
287 attr->Attributes[pos].ReturnLength = NULL;
288 pos++;
289 attr->Attributes[pos].Attribute = PS_ATTRIBUTE_IMAGE_INFO;
290 attr->Attributes[pos].Size = sizeof(info->ImageInformation);
291 attr->Attributes[pos].ValuePtr = &info->ImageInformation;
292 attr->Attributes[pos].ReturnLength = NULL;
293 pos++;
294 if (parent)
295 {
296 attr->Attributes[pos].Attribute = PS_ATTRIBUTE_PARENT_PROCESS;
297 attr->Attributes[pos].Size = sizeof(parent);
298 attr->Attributes[pos].ValuePtr = parent;
299 attr->Attributes[pos].ReturnLength = NULL;
300 pos++;
301 }
302 if ((process_flags & PROCESS_CREATE_FLAGS_INHERIT_HANDLES) && handle_list)
303 {
304 attr->Attributes[pos].Attribute = PS_ATTRIBUTE_HANDLE_LIST;
305 attr->Attributes[pos].Size = handle_list->size;
306 attr->Attributes[pos].ValuePtr = handle_list->value;
307 attr->Attributes[pos].ReturnLength = NULL;
308 pos++;
309 }
310 if (token)
311 {
312 attr->Attributes[pos].Attribute = PS_ATTRIBUTE_TOKEN;
313 attr->Attributes[pos].Size = sizeof(token);
314 attr->Attributes[pos].ValuePtr = token;
315 attr->Attributes[pos].ReturnLength = NULL;
316 pos++;
317 }
318 if (debug)
319 {
320 attr->Attributes[pos].Attribute = PS_ATTRIBUTE_DEBUG_PORT;
321 attr->Attributes[pos].Size = sizeof(debug);
322 attr->Attributes[pos].ValuePtr = debug;
323 attr->Attributes[pos].ReturnLength = NULL;
324 pos++;
325 }
326 if (job_list)
327 {
328 attr->Attributes[pos].Attribute = PS_ATTRIBUTE_JOB_LIST;
329 attr->Attributes[pos].Size = job_list->size;
330 attr->Attributes[pos].ValuePtr = job_list->value;
331 attr->Attributes[pos].ReturnLength = NULL;
332 pos++;
333 }
334 if (machine)
335 {
336 attr->Attributes[pos].Attribute = PS_ATTRIBUTE_MACHINE_TYPE;
337 attr->Attributes[pos].Size = sizeof(machine);
338 attr->Attributes[pos].Value = machine;
339 attr->Attributes[pos].ReturnLength = NULL;
340 pos++;
341 }
342 attr->TotalLength = offsetof( PS_ATTRIBUTE_LIST, Attributes[pos] );
343
344 InitializeObjectAttributes( &process_attr, NULL, 0, NULL, psa ? psa->lpSecurityDescriptor : NULL );
345 InitializeObjectAttributes( &thread_attr, NULL, 0, NULL, tsa ? tsa->lpSecurityDescriptor : NULL );
346
347 status = NtCreateUserProcess( &info->Process, &info->Thread, PROCESS_ALL_ACCESS, THREAD_ALL_ACCESS,
348 &process_attr, &thread_attr, process_flags,
349 THREAD_CREATE_FLAGS_CREATE_SUSPENDED, params,
350 &create_info, attr );
351
352 RtlFreeUnicodeString( &nameW );
353 }
354 return status;
355}
356
357
358/***********************************************************************
359 * create_vdm_process
360 */
361static NTSTATUS create_vdm_process( HANDLE token, HANDLE debug, SECURITY_ATTRIBUTES *psa,
362 SECURITY_ATTRIBUTES *tsa, DWORD flags,
363 RTL_USER_PROCESS_PARAMETERS *params,
364 RTL_USER_PROCESS_INFORMATION *info )
365{
366 const WCHAR *winevdm = (is_win64 || is_wow64 ?
367 L"C:\\windows\\syswow64\\winevdm.exe" :
368 L"C:\\windows\\system32\\winevdm.exe");
369 WCHAR *newcmdline;
370 NTSTATUS status;
371 UINT len;
372
373 len = (lstrlenW(params->ImagePathName.Buffer) + lstrlenW(params->CommandLine.Buffer) +
374 lstrlenW(winevdm) + 16);
375
376 if (!(newcmdline = RtlAllocateHeap( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
377 return STATUS_NO_MEMORY;
378
379 swprintf( newcmdline, len, L"%s --app-name \"%s\" %s",
380 winevdm, params->ImagePathName.Buffer, params->CommandLine.Buffer );
381 RtlInitUnicodeString( ¶ms->ImagePathName, winevdm );
382 RtlInitUnicodeString( ¶ms->CommandLine, newcmdline );
383 status = create_nt_process( token, debug, psa, tsa, flags, params, info, 0, 0, NULL, NULL );
384 HeapFree( GetProcessHeap(), 0, newcmdline );
385 return status;
386}
387
388
389/***********************************************************************
390 * create_cmd_process
391 */
392static NTSTATUS create_cmd_process( HANDLE token, HANDLE debug, SECURITY_ATTRIBUTES *psa,
393 SECURITY_ATTRIBUTES *tsa, DWORD flags,
394 RTL_USER_PROCESS_PARAMETERS *params,
395 RTL_USER_PROCESS_INFORMATION *info )
396{
397 WCHAR comspec[MAX_PATH];
398 WCHAR *newcmdline;
399 NTSTATUS status;
400 UINT len;
401
402 if (!GetEnvironmentVariableW( L"COMSPEC", comspec, ARRAY_SIZE( comspec )))
403 lstrcpyW( comspec, L"C:\\windows\\system32\\cmd.exe" );
404
405 len = lstrlenW(comspec) + 7 + lstrlenW(params->CommandLine.Buffer) + 2;
406 if (!(newcmdline = RtlAllocateHeap( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
407 return STATUS_NO_MEMORY;
408
409 swprintf( newcmdline, len, L"%s /s/c \"%s\"", comspec, params->CommandLine.Buffer );
410 RtlInitUnicodeString( ¶ms->ImagePathName, comspec );
411 RtlInitUnicodeString( ¶ms->CommandLine, newcmdline );
412 status = create_nt_process( token, debug, psa, tsa, flags, params, info, 0, 0, NULL, NULL );
413 RtlFreeHeap( GetProcessHeap(), 0, newcmdline );
414 return status;
415}
416
417
418/*********************************************************************
419 * CloseHandle (kernelbase.@)
420 */
421BOOL WINAPI DECLSPEC_HOTPATCH CloseHandle( HANDLE handle )
422{
423 if (handle == (HANDLE)STD_INPUT_HANDLE)
424 handle = InterlockedExchangePointer( &NtCurrentTeb()->Peb->ProcessParameters->hStdInput, 0 );
425 else if (handle == (HANDLE)STD_OUTPUT_HANDLE)
426 handle = InterlockedExchangePointer( &NtCurrentTeb()->Peb->ProcessParameters->hStdOutput, 0 );
427 else if (handle == (HANDLE)STD_ERROR_HANDLE)
428 handle = InterlockedExchangePointer( &NtCurrentTeb()->Peb->ProcessParameters->hStdError, 0 );
429
430 return set_ntstatus( NtClose( handle ));
431}
432
433
434/**********************************************************************
435 * CreateProcessAsUserA (kernelbase.@)
436 */
437BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessAsUserA( HANDLE token, const char *app_name, char *cmd_line,
438 SECURITY_ATTRIBUTES *process_attr,
439 SECURITY_ATTRIBUTES *thread_attr,
440 BOOL inherit, DWORD flags, void *env,
441 const char *cur_dir, STARTUPINFOA *startup_info,
442 PROCESS_INFORMATION *info )
443{
444 return CreateProcessInternalA( token, app_name, cmd_line, process_attr, thread_attr,
445 inherit, flags, env, cur_dir, startup_info, info, NULL );
446}
447
448
449/**********************************************************************
450 * CreateProcessAsUserW (kernelbase.@)
451 */
452BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessAsUserW( HANDLE token, const WCHAR *app_name, WCHAR *cmd_line,
453 SECURITY_ATTRIBUTES *process_attr,
454 SECURITY_ATTRIBUTES *thread_attr,
455 BOOL inherit, DWORD flags, void *env,
456 const WCHAR *cur_dir, STARTUPINFOW *startup_info,
457 PROCESS_INFORMATION *info )
458{
459 return CreateProcessInternalW( token, app_name, cmd_line, process_attr, thread_attr,
460 inherit, flags, env, cur_dir, startup_info, info, NULL );
461}
462
463/**********************************************************************
464 * CreateProcessInternalA (kernelbase.@)
465 */
466BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessInternalA( HANDLE token, const char *app_name, char *cmd_line,
467 SECURITY_ATTRIBUTES *process_attr,
468 SECURITY_ATTRIBUTES *thread_attr,
469 BOOL inherit, DWORD flags, void *env,
470 const char *cur_dir, STARTUPINFOA *startup_info,
471 PROCESS_INFORMATION *info, HANDLE *new_token )
472{
473 BOOL ret = FALSE;
474 WCHAR *app_nameW = NULL, *cmd_lineW = NULL, *cur_dirW = NULL;
475 UNICODE_STRING desktopW, titleW;
476 STARTUPINFOEXW infoW;
477
478 desktopW.Buffer = NULL;
479 titleW.Buffer = NULL;
480 if (app_name && !(app_nameW = file_name_AtoW( app_name, TRUE ))) goto done;
481 if (cmd_line && !(cmd_lineW = file_name_AtoW( cmd_line, TRUE ))) goto done;
482 if (cur_dir && !(cur_dirW = file_name_AtoW( cur_dir, TRUE ))) goto done;
483
484 if (startup_info->lpDesktop) RtlCreateUnicodeStringFromAsciiz( &desktopW, startup_info->lpDesktop );
485 if (startup_info->lpTitle) RtlCreateUnicodeStringFromAsciiz( &titleW, startup_info->lpTitle );
486
487 memcpy( &infoW.StartupInfo, startup_info, sizeof(infoW.StartupInfo) );
488 infoW.StartupInfo.lpDesktop = desktopW.Buffer;
489 infoW.StartupInfo.lpTitle = titleW.Buffer;
490
491 if (flags & EXTENDED_STARTUPINFO_PRESENT)
492 infoW.lpAttributeList = ((STARTUPINFOEXW *)startup_info)->lpAttributeList;
493
494 ret = CreateProcessInternalW( token, app_nameW, cmd_lineW, process_attr, thread_attr,
495 inherit, flags, env, cur_dirW, (STARTUPINFOW *)&infoW, info, new_token );
496done:
497 RtlFreeHeap( GetProcessHeap(), 0, app_nameW );
498 RtlFreeHeap( GetProcessHeap(), 0, cmd_lineW );
499 RtlFreeHeap( GetProcessHeap(), 0, cur_dirW );
500 RtlFreeUnicodeString( &desktopW );
501 RtlFreeUnicodeString( &titleW );
502 return ret;
503}
504
505/**********************************************************************
506 * CreateProcessInternalW (kernelbase.@)
507 */
508BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessInternalW( HANDLE token, const WCHAR *app_name, WCHAR *cmd_line,
509 SECURITY_ATTRIBUTES *process_attr,
510 SECURITY_ATTRIBUTES *thread_attr,
511 BOOL inherit, DWORD flags, void *env,
512 const WCHAR *cur_dir, STARTUPINFOW *startup_info,
513 PROCESS_INFORMATION *info, HANDLE *new_token )
514{
515 const struct proc_thread_attr *handle_list = NULL, *job_list = NULL;
516 WCHAR name[MAX_PATH];
517 WCHAR *p, *tidy_cmdline = cmd_line;
518 RTL_USER_PROCESS_PARAMETERS *params = NULL;
519 RTL_USER_PROCESS_INFORMATION rtl_info;
520 HANDLE parent = 0, debug = 0;
521 ULONG nt_flags = 0;
522 USHORT machine = 0;
523 NTSTATUS status;
524
525 /* Process the AppName and/or CmdLine to get module name and path */
526
527 TRACE( "app %s cmdline %s\n", debugstr_w(app_name), debugstr_w(cmd_line) );
528
529 if (new_token) FIXME( "No support for returning created process token\n" );
530
531 if (app_name)
532 {
533 if (!cmd_line || !cmd_line[0]) /* no command-line, create one */
534 {
535 if (!(tidy_cmdline = RtlAllocateHeap( GetProcessHeap(), 0, (lstrlenW(app_name)+3) * sizeof(WCHAR) )))
536 return FALSE;
537 swprintf( tidy_cmdline, lstrlenW(app_name) + 3, L"\"%s\"", app_name );
538 }
539 }
540 else
541 {
542 if (!(tidy_cmdline = get_file_name( cmd_line, name, ARRAY_SIZE(name) ))) return FALSE;
543 app_name = name;
544 }
545
546 /* Warn if unsupported features are used */
547
548 if (flags & (IDLE_PRIORITY_CLASS | HIGH_PRIORITY_CLASS | REALTIME_PRIORITY_CLASS |
549 CREATE_DEFAULT_ERROR_MODE | PROFILE_USER | PROFILE_KERNEL | PROFILE_SERVER))
550 WARN( "(%s,...): ignoring some flags in %lx\n", debugstr_w(app_name), flags );
551
552 if (cur_dir)
553 {
554 DWORD attr = GetFileAttributesW( cur_dir );
555 if (attr == INVALID_FILE_ATTRIBUTES || !(attr & FILE_ATTRIBUTE_DIRECTORY))
556 {
557 status = STATUS_NOT_A_DIRECTORY;
558 goto done;
559 }
560 }
561
562 info->hThread = info->hProcess = 0;
563 info->dwProcessId = info->dwThreadId = 0;
564
565 if (!(params = create_process_params( app_name, tidy_cmdline, cur_dir, env, flags, startup_info )))
566 {
567 status = STATUS_NO_MEMORY;
568 goto done;
569 }
570
571 if (flags & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS))
572 {
573 if ((status = DbgUiConnectToDbg())) goto done;
574 debug = DbgUiGetThreadDebugObject();
575 }
576
577 if (flags & EXTENDED_STARTUPINFO_PRESENT)
578 {
579 struct _PROC_THREAD_ATTRIBUTE_LIST *attrs =
580 (struct _PROC_THREAD_ATTRIBUTE_LIST *)((STARTUPINFOEXW *)startup_info)->lpAttributeList;
581 unsigned int i;
582
583 if (attrs)
584 {
585 for (i = 0; i < attrs->count; ++i)
586 {
587 switch(attrs->attrs[i].attr)
588 {
589 case PROC_THREAD_ATTRIBUTE_PARENT_PROCESS:
590 parent = *(HANDLE *)attrs->attrs[i].value;
591 TRACE("PROC_THREAD_ATTRIBUTE_PARENT_PROCESS parent %p.\n", parent);
592 if (!parent)
593 {
594 status = STATUS_INVALID_HANDLE;
595 goto done;
596 }
597 break;
598 case PROC_THREAD_ATTRIBUTE_EXTENDED_FLAGS:
599 FIXME("PROC_THREAD_ATTRIBUTE_EXTENDED_FLAGS %lx.\n", *(ULONG *)attrs->attrs[i].value);
600 break;
601 case PROC_THREAD_ATTRIBUTE_HANDLE_LIST:
602 handle_list = &attrs->attrs[i];
603 TRACE("PROC_THREAD_ATTRIBUTE_HANDLE_LIST handle count %Iu.\n", attrs->attrs[i].size / sizeof(HANDLE));
604 break;
605 case PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE:
606 {
607 struct pseudo_console *console = attrs->attrs[i].value;
608 TRACE( "PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE %p reference %p\n",
609 console, console->reference );
610 params->ConsoleHandle = console->reference;
611 break;
612 }
613 case PROC_THREAD_ATTRIBUTE_JOB_LIST:
614 job_list = &attrs->attrs[i];
615 TRACE( "PROC_THREAD_ATTRIBUTE_JOB_LIST handle count %Iu.\n",
616 attrs->attrs[i].size / sizeof(HANDLE) );
617 break;
618 case PROC_THREAD_ATTRIBUTE_MACHINE_TYPE:
619 machine = *(USHORT *)attrs->attrs[i].value;
620 TRACE( "PROC_THREAD_ATTRIBUTE_MACHINE %x.\n", machine );
621 break;
622 default:
623 FIXME("Unsupported attribute %#Ix.\n", attrs->attrs[i].attr);
624 break;
625 }
626 }
627 }
628 }
629
630 if (inherit) nt_flags |= PROCESS_CREATE_FLAGS_INHERIT_HANDLES;
631 if (flags & DEBUG_ONLY_THIS_PROCESS) nt_flags |= PROCESS_CREATE_FLAGS_NO_DEBUG_INHERIT;
632 if (flags & CREATE_BREAKAWAY_FROM_JOB) nt_flags |= PROCESS_CREATE_FLAGS_BREAKAWAY;
633 if (flags & CREATE_SUSPENDED) nt_flags |= PROCESS_CREATE_FLAGS_SUSPENDED;
634
635 status = create_nt_process( token, debug, process_attr, thread_attr,
636 nt_flags, params, &rtl_info, parent, machine, handle_list, job_list );
637 switch (status)
638 {
639 case STATUS_SUCCESS:
640 break;
641 case STATUS_INVALID_IMAGE_WIN_16:
642 case STATUS_INVALID_IMAGE_NE_FORMAT:
643 case STATUS_INVALID_IMAGE_PROTECT:
644 TRACE( "starting %s as Win16/DOS binary\n", debugstr_w(app_name) );
645 status = create_vdm_process( token, debug, process_attr, thread_attr,
646 nt_flags, params, &rtl_info );
647 break;
648 case STATUS_INVALID_IMAGE_NOT_MZ:
649 /* check for .com or .bat extension */
650 if (!(p = wcsrchr( app_name, '.' ))) break;
651 if (!wcsicmp( p, L".com" ) || !wcsicmp( p, L".pif" ))
652 {
653 TRACE( "starting %s as DOS binary\n", debugstr_w(app_name) );
654 status = create_vdm_process( token, debug, process_attr, thread_attr,
655 nt_flags, params, &rtl_info );
656 }
657 else if (!wcsicmp( p, L".bat" ) || !wcsicmp( p, L".cmd" ))
658 {
659 TRACE( "starting %s as batch binary\n", debugstr_w(app_name) );
660 status = create_cmd_process( token, debug, process_attr, thread_attr,
661 nt_flags, params, &rtl_info );
662 }
663 break;
664 }
665
666 if (!status)
667 {
668 info->hProcess = rtl_info.Process;
669 info->hThread = rtl_info.Thread;
670 info->dwProcessId = HandleToUlong( rtl_info.ClientId.UniqueProcess );
671 info->dwThreadId = HandleToUlong( rtl_info.ClientId.UniqueThread );
672 if (!(flags & CREATE_SUSPENDED)) NtResumeThread( rtl_info.Thread, NULL );
673 TRACE( "started process pid %04lx tid %04lx\n", info->dwProcessId, info->dwThreadId );
674 }
675
676 done:
677 RtlDestroyProcessParameters( params );
678 if (tidy_cmdline != cmd_line) HeapFree( GetProcessHeap(), 0, tidy_cmdline );
679 return set_ntstatus( status );
680}
681
682
683/**********************************************************************
684 * CreateProcessA (kernelbase.@)
685 */
686BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessA( const char *app_name, char *cmd_line,
687 SECURITY_ATTRIBUTES *process_attr,
688 SECURITY_ATTRIBUTES *thread_attr, BOOL inherit,
689 DWORD flags, void *env, const char *cur_dir,
690 STARTUPINFOA *startup_info, PROCESS_INFORMATION *info )
691{
692 return CreateProcessInternalA( NULL, app_name, cmd_line, process_attr, thread_attr,
693 inherit, flags, env, cur_dir, startup_info, info, NULL );
694}
695
696
697/**********************************************************************
698 * CreateProcessW (kernelbase.@)
699 */
700BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessW( const WCHAR *app_name, WCHAR *cmd_line,
701 SECURITY_ATTRIBUTES *process_attr,
702 SECURITY_ATTRIBUTES *thread_attr, BOOL inherit, DWORD flags,
703 void *env, const WCHAR *cur_dir, STARTUPINFOW *startup_info,
704 PROCESS_INFORMATION *info )
705{
706 return CreateProcessInternalW( NULL, app_name, cmd_line, process_attr, thread_attr,
707 inherit, flags, env, cur_dir, startup_info, info, NULL );
708}
709
710
711/**********************************************************************
712 * SetProcessInformation (kernelbase.@)
713 */
714BOOL WINAPI SetProcessInformation( HANDLE process, PROCESS_INFORMATION_CLASS info_class, void *info, DWORD size )
715{
716 switch (info_class)
717 {
718 case ProcessMemoryPriority:
719 return set_ntstatus( NtSetInformationProcess( process, ProcessPagePriority, info, size ));
720 case ProcessPowerThrottling:
721 return set_ntstatus( NtSetInformationProcess( process, ProcessPowerThrottlingState, info, size ));
722 case ProcessLeapSecondInfo:
723 return set_ntstatus( NtSetInformationProcess( process, ProcessLeapSecondInformation, info, size ));
724 default:
725 FIXME("Unrecognized information class %d.\n", info_class);
726 return FALSE;
727 }
728}
729
730
731/*********************************************************************
732 * DuplicateHandle (kernelbase.@)
733 */
734BOOL WINAPI DECLSPEC_HOTPATCH DuplicateHandle( HANDLE source_process, HANDLE source,
735 HANDLE dest_process, HANDLE *dest,
736 DWORD access, BOOL inherit, DWORD options )
737{
738 return set_ntstatus( NtDuplicateObject( source_process, source, dest_process, dest,
739 access, inherit ? OBJ_INHERIT : 0, options ));
740}
741
742
743/***********************************************************************
744 * GetApplicationRestartSettings (kernelbase.@)
745 */
746HRESULT WINAPI /* DECLSPEC_HOTPATCH */ GetApplicationRestartSettings( HANDLE process, WCHAR *cmdline,
747 DWORD *size, DWORD *flags )
748{
749 FIXME( "%p, %p, %p, %p)\n", process, cmdline, size, flags );
750 return E_NOTIMPL;
751}
752
753
754/***********************************************************************
755 * GetCurrentProcess (kernelbase.@)
756 */
757HANDLE WINAPI kernelbase_GetCurrentProcess(void)
758{
759 return (HANDLE)~(ULONG_PTR)0;
760}
761
762
763/***********************************************************************
764 * GetCurrentProcessId (kernelbase.@)
765 */
766DWORD WINAPI kernelbase_GetCurrentProcessId(void)
767{
768 return HandleToULong( NtCurrentTeb()->ClientId.UniqueProcess );
769}
770
771
772/***********************************************************************
773 * GetErrorMode (kernelbase.@)
774 */
775UINT WINAPI DECLSPEC_HOTPATCH GetErrorMode(void)
776{
777 UINT mode;
778
779 NtQueryInformationProcess( GetCurrentProcess(), ProcessDefaultHardErrorMode,
780 &mode, sizeof(mode), NULL );
781 return mode;
782}
783
784
785/***********************************************************************
786 * GetExitCodeProcess (kernelbase.@)
787 */
788BOOL WINAPI DECLSPEC_HOTPATCH GetExitCodeProcess( HANDLE process, LPDWORD exit_code )
789{
790 NTSTATUS status;
791 PROCESS_BASIC_INFORMATION pbi;
792
793 status = NtQueryInformationProcess( process, ProcessBasicInformation, &pbi, sizeof(pbi), NULL );
794 if (!status && exit_code) *exit_code = pbi.ExitStatus;
795 return set_ntstatus( status );
796}
797
798
799/*********************************************************************
800 * GetHandleInformation (kernelbase.@)
801 */
802BOOL WINAPI DECLSPEC_HOTPATCH GetHandleInformation( HANDLE handle, DWORD *flags )
803{
804 OBJECT_HANDLE_FLAG_INFORMATION info;
805
806 if (!set_ntstatus( NtQueryObject( handle, ObjectHandleFlagInformation, &info, sizeof(info), NULL )))
807 return FALSE;
808
809 if (flags)
810 {
811 *flags = 0;
812 if (info.Inherit) *flags |= HANDLE_FLAG_INHERIT;
813 if (info.ProtectFromClose) *flags |= HANDLE_FLAG_PROTECT_FROM_CLOSE;
814 }
815 return TRUE;
816}
817
818
819/***********************************************************************
820 * GetPriorityClass (kernelbase.@)
821 */
822DWORD WINAPI DECLSPEC_HOTPATCH GetPriorityClass( HANDLE process )
823{
824 PROCESS_BASIC_INFORMATION pbi;
825
826 if (!set_ntstatus( NtQueryInformationProcess( process, ProcessBasicInformation,
827 &pbi, sizeof(pbi), NULL )))
828 return 0;
829
830 switch (pbi.BasePriority)
831 {
832 case PROCESS_PRIOCLASS_IDLE: return IDLE_PRIORITY_CLASS;
833 case PROCESS_PRIOCLASS_BELOW_NORMAL: return BELOW_NORMAL_PRIORITY_CLASS;
834 case PROCESS_PRIOCLASS_NORMAL: return NORMAL_PRIORITY_CLASS;
835 case PROCESS_PRIOCLASS_ABOVE_NORMAL: return ABOVE_NORMAL_PRIORITY_CLASS;
836 case PROCESS_PRIOCLASS_HIGH: return HIGH_PRIORITY_CLASS;
837 case PROCESS_PRIOCLASS_REALTIME: return REALTIME_PRIORITY_CLASS;
838 default: return 0;
839 }
840}
841
842
843/***********************************************************************
844 * GetProcessGroupAffinity (kernelbase.@)
845 */
846BOOL WINAPI DECLSPEC_HOTPATCH GetProcessGroupAffinity( HANDLE process, USHORT *count, USHORT *array )
847{
848 FIXME( "(%p,%p,%p): stub\n", process, count, array );
849 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
850 return FALSE;
851}
852
853
854/******************************************************************
855 * GetProcessHandleCount (kernelbase.@)
856 */
857BOOL WINAPI DECLSPEC_HOTPATCH GetProcessHandleCount( HANDLE process, DWORD *count )
858{
859 return set_ntstatus( NtQueryInformationProcess( process, ProcessHandleCount,
860 count, sizeof(*count), NULL ));
861}
862
863
864/***********************************************************************
865 * GetProcessHeap (kernelbase.@)
866 */
867HANDLE WINAPI kernelbase_GetProcessHeap(void)
868{
869 return NtCurrentTeb()->Peb->ProcessHeap;
870}
871
872
873/*********************************************************************
874 * GetProcessId (kernelbase.@)
875 */
876DWORD WINAPI DECLSPEC_HOTPATCH GetProcessId( HANDLE process )
877{
878 PROCESS_BASIC_INFORMATION pbi;
879
880 if (!set_ntstatus( NtQueryInformationProcess( process, ProcessBasicInformation,
881 &pbi, sizeof(pbi), NULL )))
882 return 0;
883 return pbi.UniqueProcessId;
884}
885
886
887/**********************************************************************
888 * GetProcessMitigationPolicy (kernelbase.@)
889 */
890BOOL WINAPI /* DECLSPEC_HOTPATCH */ GetProcessMitigationPolicy( HANDLE process, PROCESS_MITIGATION_POLICY policy,
891 void *buffer, SIZE_T length )
892{
893 FIXME( "(%p, %u, %p, %Iu): stub\n", process, policy, buffer, length );
894 return TRUE;
895}
896
897
898/***********************************************************************
899 * GetProcessPriorityBoost (kernelbase.@)
900 */
901BOOL WINAPI DECLSPEC_HOTPATCH GetProcessPriorityBoost( HANDLE process, PBOOL disable )
902{
903 FIXME( "(%p,%p): semi-stub\n", process, disable );
904 *disable = FALSE; /* report that no boost is present */
905 return TRUE;
906}
907
908
909/***********************************************************************
910 * GetProcessShutdownParameters (kernelbase.@)
911 */
912BOOL WINAPI DECLSPEC_HOTPATCH GetProcessShutdownParameters( LPDWORD level, LPDWORD flags )
913{
914 *level = shutdown_priority;
915 *flags = shutdown_flags;
916 return TRUE;
917}
918
919
920/*********************************************************************
921 * GetProcessTimes (kernelbase.@)
922 */
923BOOL WINAPI DECLSPEC_HOTPATCH GetProcessTimes( HANDLE process, FILETIME *create, FILETIME *exit,
924 FILETIME *kernel, FILETIME *user )
925{
926 KERNEL_USER_TIMES time;
927
928 if (!set_ntstatus( NtQueryInformationProcess( process, ProcessTimes, &time, sizeof(time), NULL )))
929 return FALSE;
930
931 create->dwLowDateTime = time.CreateTime.u.LowPart;
932 create->dwHighDateTime = time.CreateTime.u.HighPart;
933 exit->dwLowDateTime = time.ExitTime.u.LowPart;
934 exit->dwHighDateTime = time.ExitTime.u.HighPart;
935 kernel->dwLowDateTime = time.KernelTime.u.LowPart;
936 kernel->dwHighDateTime = time.KernelTime.u.HighPart;
937 user->dwLowDateTime = time.UserTime.u.LowPart;
938 user->dwHighDateTime = time.UserTime.u.HighPart;
939 return TRUE;
940}
941
942
943/***********************************************************************
944 * GetProcessVersion (kernelbase.@)
945 */
946DWORD WINAPI DECLSPEC_HOTPATCH GetProcessVersion( DWORD pid )
947{
948 SECTION_IMAGE_INFORMATION info;
949 NTSTATUS status;
950 HANDLE process;
951
952 if (pid && pid != GetCurrentProcessId())
953 {
954 if (!(process = OpenProcess( PROCESS_QUERY_INFORMATION, FALSE, pid ))) return 0;
955 status = NtQueryInformationProcess( process, ProcessImageInformation, &info, sizeof(info), NULL );
956 CloseHandle( process );
957 }
958 else status = NtQueryInformationProcess( GetCurrentProcess(), ProcessImageInformation,
959 &info, sizeof(info), NULL );
960
961 if (!set_ntstatus( status )) return 0;
962 return MAKELONG( info.MinorSubsystemVersion, info.MajorSubsystemVersion );
963}
964
965
966/***********************************************************************
967 * GetProcessWorkingSetSizeEx (kernelbase.@)
968 */
969BOOL WINAPI DECLSPEC_HOTPATCH GetProcessWorkingSetSizeEx( HANDLE process, SIZE_T *minset,
970 SIZE_T *maxset, DWORD *flags)
971{
972 FIXME( "(%p,%p,%p,%p): stub\n", process, minset, maxset, flags );
973 /* 32 MB working set size */
974 if (minset) *minset = 32*1024*1024;
975 if (maxset) *maxset = 32*1024*1024;
976 if (flags) *flags = QUOTA_LIMITS_HARDWS_MIN_DISABLE | QUOTA_LIMITS_HARDWS_MAX_DISABLE;
977 return TRUE;
978}
979
980
981/******************************************************************************
982 * IsProcessInJob (kernelbase.@)
983 */
984BOOL WINAPI DECLSPEC_HOTPATCH IsProcessInJob( HANDLE process, HANDLE job, BOOL *result )
985{
986 NTSTATUS status = NtIsProcessInJob( process, job );
987
988 switch (status)
989 {
990 case STATUS_PROCESS_IN_JOB:
991 *result = TRUE;
992 return TRUE;
993 case STATUS_PROCESS_NOT_IN_JOB:
994 *result = FALSE;
995 return TRUE;
996 default:
997 return set_ntstatus( status );
998 }
999}
1000
1001
1002/***********************************************************************
1003 * IsProcessorFeaturePresent (kernelbase.@)
1004 */
1005BOOL WINAPI DECLSPEC_HOTPATCH IsProcessorFeaturePresent ( DWORD feature )
1006{
1007 return RtlIsProcessorFeaturePresent( feature );
1008}
1009
1010
1011/**********************************************************************
1012 * IsWow64Process2 (kernelbase.@)
1013 */
1014BOOL WINAPI DECLSPEC_HOTPATCH IsWow64Process2( HANDLE process, USHORT *machine, USHORT *native_machine )
1015{
1016 return set_ntstatus( RtlWow64GetProcessMachines( process, machine, native_machine ));
1017}
1018
1019
1020/**********************************************************************
1021 * IsWow64Process (kernelbase.@)
1022 */
1023BOOL WINAPI DECLSPEC_HOTPATCH IsWow64Process( HANDLE process, PBOOL wow64 )
1024{
1025 ULONG_PTR pbi;
1026 NTSTATUS status;
1027
1028 status = NtQueryInformationProcess( process, ProcessWow64Information, &pbi, sizeof(pbi), NULL );
1029 if (!status) *wow64 = !!pbi;
1030 return set_ntstatus( status );
1031}
1032
1033/*********************************************************************
1034 * GetProcessInformation (kernelbase.@)
1035 */
1036BOOL WINAPI GetProcessInformation( HANDLE process, PROCESS_INFORMATION_CLASS info_class, void *data, DWORD size )
1037{
1038 switch (info_class)
1039 {
1040 case ProcessMachineTypeInfo:
1041 {
1042 PROCESS_MACHINE_INFORMATION *mi = data;
1043 SYSTEM_SUPPORTED_PROCESSOR_ARCHITECTURES_INFORMATION machines[8];
1044 NTSTATUS status;
1045 ULONG i;
1046
1047 if (size != sizeof(*mi))
1048 {
1049 SetLastError(ERROR_BAD_LENGTH);
1050 return FALSE;
1051 }
1052
1053 status = NtQuerySystemInformationEx( SystemSupportedProcessorArchitectures, &process, sizeof(process),
1054 machines, sizeof(machines), NULL );
1055 if (status) return set_ntstatus( status );
1056
1057 for (i = 0; machines[i].Machine; i++)
1058 {
1059 if (machines[i].Process)
1060 {
1061 mi->ProcessMachine = machines[i].Machine;
1062 mi->Res0 = 0;
1063 mi->MachineAttributes = 0;
1064 if (machines[i].KernelMode)
1065 mi->MachineAttributes |= KernelEnabled;
1066 if (machines[i].UserMode)
1067 mi->MachineAttributes |= UserEnabled;
1068 if (machines[i].WoW64Container)
1069 mi->MachineAttributes |= Wow64Container;
1070
1071 return TRUE;
1072 }
1073 }
1074
1075 break;
1076 }
1077 default:
1078 FIXME("Unsupported information class %d.\n", info_class);
1079 }
1080
1081 return FALSE;
1082}
1083
1084
1085/*********************************************************************
1086 * OpenProcess (kernelbase.@)
1087 */
1088HANDLE WINAPI DECLSPEC_HOTPATCH OpenProcess( DWORD access, BOOL inherit, DWORD id )
1089{
1090 HANDLE handle;
1091 OBJECT_ATTRIBUTES attr;
1092 CLIENT_ID cid;
1093
1094 if (GetVersion() & 0x80000000) access = PROCESS_ALL_ACCESS;
1095
1096 attr.Length = sizeof(OBJECT_ATTRIBUTES);
1097 attr.RootDirectory = 0;
1098 attr.Attributes = inherit ? OBJ_INHERIT : 0;
1099 attr.ObjectName = NULL;
1100 attr.SecurityDescriptor = NULL;
1101 attr.SecurityQualityOfService = NULL;
1102
1103 cid.UniqueProcess = ULongToHandle(id);
1104 cid.UniqueThread = 0;
1105
1106 if (!set_ntstatus( NtOpenProcess( &handle, access, &attr, &cid ))) return NULL;
1107 return handle;
1108}
1109
1110
1111/***********************************************************************
1112 * ProcessIdToSessionId (kernelbase.@)
1113 */
1114BOOL WINAPI DECLSPEC_HOTPATCH ProcessIdToSessionId( DWORD pid, DWORD *id )
1115{
1116 HANDLE process;
1117 NTSTATUS status;
1118
1119 if (pid == GetCurrentProcessId())
1120 {
1121 *id = NtCurrentTeb()->Peb->SessionId;
1122 return TRUE;
1123 }
1124 if (!(process = OpenProcess( PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid ))) return FALSE;
1125 status = NtQueryInformationProcess( process, ProcessSessionInformation, id, sizeof(*id), NULL );
1126 CloseHandle( process );
1127 return set_ntstatus( status );
1128}
1129
1130
1131/***********************************************************************
1132 * QueryProcessCycleTime (kernelbase.@)
1133 */
1134BOOL WINAPI DECLSPEC_HOTPATCH QueryProcessCycleTime( HANDLE process, ULONG64 *cycle )
1135{
1136 PROCESS_CYCLE_TIME_INFORMATION time;
1137
1138 if (!set_ntstatus( NtQueryInformationProcess( process, ProcessCycleTime, &time, sizeof(time), NULL ) ))
1139 return FALSE;
1140
1141 *cycle = time.AccumulatedCycles;
1142 return TRUE;
1143}
1144
1145
1146/***********************************************************************
1147 * SetErrorMode (kernelbase.@)
1148 */
1149UINT WINAPI DECLSPEC_HOTPATCH SetErrorMode( UINT mode )
1150{
1151 UINT old = GetErrorMode();
1152
1153 NtSetInformationProcess( GetCurrentProcess(), ProcessDefaultHardErrorMode,
1154 &mode, sizeof(mode) );
1155 return old;
1156}
1157
1158
1159/*************************************************************************
1160 * SetHandleCount (kernelbase.@)
1161 */
1162UINT WINAPI DECLSPEC_HOTPATCH SetHandleCount( UINT count )
1163{
1164 return count;
1165}
1166
1167
1168/*********************************************************************
1169 * SetHandleInformation (kernelbase.@)
1170 */
1171BOOL WINAPI DECLSPEC_HOTPATCH SetHandleInformation( HANDLE handle, DWORD mask, DWORD flags )
1172{
1173 OBJECT_HANDLE_FLAG_INFORMATION info;
1174
1175 /* if not setting both fields, retrieve current value first */
1176 if ((mask & (HANDLE_FLAG_INHERIT | HANDLE_FLAG_PROTECT_FROM_CLOSE)) !=
1177 (HANDLE_FLAG_INHERIT | HANDLE_FLAG_PROTECT_FROM_CLOSE))
1178 {
1179 if (!set_ntstatus( NtQueryObject( handle, ObjectHandleFlagInformation, &info, sizeof(info), NULL )))
1180 return FALSE;
1181 }
1182 if (mask & HANDLE_FLAG_INHERIT)
1183 info.Inherit = (flags & HANDLE_FLAG_INHERIT) != 0;
1184 if (mask & HANDLE_FLAG_PROTECT_FROM_CLOSE)
1185 info.ProtectFromClose = (flags & HANDLE_FLAG_PROTECT_FROM_CLOSE) != 0;
1186
1187 return set_ntstatus( NtSetInformationObject( handle, ObjectHandleFlagInformation, &info, sizeof(info) ));
1188}
1189
1190
1191/***********************************************************************
1192 * SetPriorityClass (kernelbase.@)
1193 */
1194BOOL WINAPI DECLSPEC_HOTPATCH SetPriorityClass( HANDLE process, DWORD class )
1195{
1196 PROCESS_PRIORITY_CLASS ppc;
1197
1198 ppc.Foreground = FALSE;
1199 switch (class)
1200 {
1201 case IDLE_PRIORITY_CLASS: ppc.PriorityClass = PROCESS_PRIOCLASS_IDLE; break;
1202 case BELOW_NORMAL_PRIORITY_CLASS: ppc.PriorityClass = PROCESS_PRIOCLASS_BELOW_NORMAL; break;
1203 case NORMAL_PRIORITY_CLASS: ppc.PriorityClass = PROCESS_PRIOCLASS_NORMAL; break;
1204 case ABOVE_NORMAL_PRIORITY_CLASS: ppc.PriorityClass = PROCESS_PRIOCLASS_ABOVE_NORMAL; break;
1205 case HIGH_PRIORITY_CLASS: ppc.PriorityClass = PROCESS_PRIOCLASS_HIGH; break;
1206 case REALTIME_PRIORITY_CLASS: ppc.PriorityClass = PROCESS_PRIOCLASS_REALTIME; break;
1207 default:
1208 SetLastError( ERROR_INVALID_PARAMETER );
1209 return FALSE;
1210 }
1211 return set_ntstatus( NtSetInformationProcess( process, ProcessPriorityClass, &ppc, sizeof(ppc) ));
1212}
1213
1214
1215/***********************************************************************
1216 * SetProcessAffinityUpdateMode (kernelbase.@)
1217 */
1218BOOL WINAPI DECLSPEC_HOTPATCH SetProcessAffinityUpdateMode( HANDLE process, DWORD flags )
1219{
1220 FIXME( "(%p,0x%08lx): stub\n", process, flags );
1221 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
1222 return FALSE;
1223}
1224
1225
1226/***********************************************************************
1227 * SetProcessGroupAffinity (kernelbase.@)
1228 */
1229BOOL WINAPI DECLSPEC_HOTPATCH SetProcessGroupAffinity( HANDLE process, const GROUP_AFFINITY *new,
1230 GROUP_AFFINITY *old )
1231{
1232 FIXME( "(%p,%p,%p): stub\n", process, new, old );
1233 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
1234 return FALSE;
1235}
1236
1237
1238/**********************************************************************
1239 * SetProcessMitigationPolicy (kernelbase.@)
1240 */
1241BOOL WINAPI /* DECLSPEC_HOTPATCH */ SetProcessMitigationPolicy( PROCESS_MITIGATION_POLICY policy,
1242 void *buffer, SIZE_T length )
1243{
1244 FIXME( "(%d, %p, %Iu): stub\n", policy, buffer, length );
1245 return TRUE;
1246}
1247
1248
1249/***********************************************************************
1250 * SetProcessPriorityBoost (kernelbase.@)
1251 */
1252BOOL WINAPI /* DECLSPEC_HOTPATCH */ SetProcessPriorityBoost( HANDLE process, BOOL disable )
1253{
1254 FIXME( "(%p,%d): stub\n", process, disable );
1255 return TRUE;
1256}
1257
1258
1259/***********************************************************************
1260 * SetProcessShutdownParameters (kernelbase.@)
1261 */
1262BOOL WINAPI DECLSPEC_HOTPATCH SetProcessShutdownParameters( DWORD level, DWORD flags )
1263{
1264 FIXME( "(%08lx, %08lx): partial stub.\n", level, flags );
1265 shutdown_flags = flags;
1266 shutdown_priority = level;
1267 return TRUE;
1268}
1269
1270
1271/***********************************************************************
1272 * SetProcessWorkingSetSizeEx (kernelbase.@)
1273 */
1274BOOL WINAPI DECLSPEC_HOTPATCH SetProcessWorkingSetSizeEx( HANDLE process, SIZE_T minset,
1275 SIZE_T maxset, DWORD flags )
1276{
1277 return TRUE;
1278}
1279
1280
1281/******************************************************************************
1282 * TerminateProcess (kernelbase.@)
1283 */
1284BOOL WINAPI DECLSPEC_HOTPATCH TerminateProcess( HANDLE handle, DWORD exit_code )
1285{
1286 if (!handle)
1287 {
1288 SetLastError( ERROR_INVALID_HANDLE );
1289 return FALSE;
1290 }
1291 return set_ntstatus( NtTerminateProcess( handle, exit_code ));
1292}
1293
1294
1295/***********************************************************************
1296 * Process startup information
1297 ***********************************************************************/
1298
1299
1300static char *command_lineA;
1301static WCHAR *command_lineW;
1302
1303/******************************************************************
1304 * init_startup_info
1305 */
1306void init_startup_info( RTL_USER_PROCESS_PARAMETERS *params )
1307{
1308 ANSI_STRING ansi;
1309
1310 command_lineW = params->CommandLine.Buffer;
1311 if (!RtlUnicodeStringToAnsiString( &ansi, ¶ms->CommandLine, TRUE )) command_lineA = ansi.Buffer;
1312}
1313
1314
1315/**********************************************************************
1316 * BaseFlushAppcompatCache (kernelbase.@)
1317 */
1318BOOL WINAPI BaseFlushAppcompatCache(void)
1319{
1320 FIXME( "stub\n" );
1321 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
1322 return FALSE;
1323}
1324
1325
1326/***********************************************************************
1327 * GetCommandLineA (kernelbase.@)
1328 */
1329LPSTR WINAPI GetCommandLineA(void)
1330{
1331 return command_lineA;
1332}
1333
1334
1335/***********************************************************************
1336 * GetCommandLineW (kernelbase.@)
1337 */
1338LPWSTR WINAPI GetCommandLineW(void)
1339{
1340 return command_lineW;
1341}
1342
1343
1344/***********************************************************************
1345 * GetStartupInfoW (kernelbase.@)
1346 */
1347void WINAPI DECLSPEC_HOTPATCH GetStartupInfoW( STARTUPINFOW *info )
1348{
1349 RTL_USER_PROCESS_PARAMETERS *params;
1350
1351 RtlAcquirePebLock();
1352
1353 params = RtlGetCurrentPeb()->ProcessParameters;
1354
1355 info->cb = sizeof(*info);
1356 info->lpReserved = NULL;
1357 info->lpDesktop = params->Desktop.Buffer;
1358 info->lpTitle = params->WindowTitle.Buffer;
1359 info->dwX = params->dwX;
1360 info->dwY = params->dwY;
1361 info->dwXSize = params->dwXSize;
1362 info->dwYSize = params->dwYSize;
1363 info->dwXCountChars = params->dwXCountChars;
1364 info->dwYCountChars = params->dwYCountChars;
1365 info->dwFillAttribute = params->dwFillAttribute;
1366 info->dwFlags = params->dwFlags;
1367 info->wShowWindow = params->wShowWindow;
1368 info->cbReserved2 = params->RuntimeInfo.MaximumLength;
1369 info->lpReserved2 = params->RuntimeInfo.MaximumLength ? (void *)params->RuntimeInfo.Buffer : NULL;
1370 if (params->dwFlags & STARTF_USESTDHANDLES)
1371 {
1372 info->hStdInput = params->hStdInput;
1373 info->hStdOutput = params->hStdOutput;
1374 info->hStdError = params->hStdError;
1375 }
1376 RtlReleasePebLock();
1377}
1378
1379
1380/***********************************************************************
1381 * GetStdHandle (kernelbase.@)
1382 */
1383HANDLE WINAPI DECLSPEC_HOTPATCH GetStdHandle( DWORD std_handle )
1384{
1385 switch (std_handle)
1386 {
1387 case STD_INPUT_HANDLE: return NtCurrentTeb()->Peb->ProcessParameters->hStdInput;
1388 case STD_OUTPUT_HANDLE: return NtCurrentTeb()->Peb->ProcessParameters->hStdOutput;
1389 case STD_ERROR_HANDLE: return NtCurrentTeb()->Peb->ProcessParameters->hStdError;
1390 }
1391 SetLastError( ERROR_INVALID_HANDLE );
1392 return INVALID_HANDLE_VALUE;
1393}
1394
1395
1396/***********************************************************************
1397 * SetStdHandle (kernelbase.@)
1398 */
1399BOOL WINAPI DECLSPEC_HOTPATCH SetStdHandle( DWORD std_handle, HANDLE handle )
1400{
1401 switch (std_handle)
1402 {
1403 case STD_INPUT_HANDLE: NtCurrentTeb()->Peb->ProcessParameters->hStdInput = handle; return TRUE;
1404 case STD_OUTPUT_HANDLE: NtCurrentTeb()->Peb->ProcessParameters->hStdOutput = handle; return TRUE;
1405 case STD_ERROR_HANDLE: NtCurrentTeb()->Peb->ProcessParameters->hStdError = handle; return TRUE;
1406 }
1407 SetLastError( ERROR_INVALID_HANDLE );
1408 return FALSE;
1409}
1410
1411
1412/***********************************************************************
1413 * SetStdHandleEx (kernelbase.@)
1414 */
1415BOOL WINAPI DECLSPEC_HOTPATCH SetStdHandleEx( DWORD std_handle, HANDLE handle, HANDLE *prev )
1416{
1417 HANDLE *ptr;
1418
1419 switch (std_handle)
1420 {
1421 case STD_INPUT_HANDLE: ptr = &NtCurrentTeb()->Peb->ProcessParameters->hStdInput; break;
1422 case STD_OUTPUT_HANDLE: ptr = &NtCurrentTeb()->Peb->ProcessParameters->hStdOutput; break;
1423 case STD_ERROR_HANDLE: ptr = &NtCurrentTeb()->Peb->ProcessParameters->hStdError; break;
1424 default:
1425 SetLastError( ERROR_INVALID_HANDLE );
1426 return FALSE;
1427 }
1428 if (prev) *prev = *ptr;
1429 *ptr = handle;
1430 return TRUE;
1431}
1432
1433
1434/***********************************************************************
1435 * Process environment
1436 ***********************************************************************/
1437
1438
1439static inline SIZE_T get_env_length( const WCHAR *env )
1440{
1441 const WCHAR *end = env;
1442 while (*end) end += lstrlenW(end) + 1;
1443 return end + 1 - env;
1444}
1445
1446/***********************************************************************
1447 * ExpandEnvironmentStringsA (kernelbase.@)
1448 */
1449DWORD WINAPI DECLSPEC_HOTPATCH ExpandEnvironmentStringsA( LPCSTR src, LPSTR dst, DWORD count )
1450{
1451 UNICODE_STRING us_src;
1452 PWSTR dstW = NULL;
1453 DWORD count_neededW;
1454 DWORD count_neededA = 0;
1455
1456 RtlCreateUnicodeStringFromAsciiz( &us_src, src );
1457
1458 /* We always need to call ExpandEnvironmentStringsW, since we need the result to calculate the needed buffer size */
1459 count_neededW = ExpandEnvironmentStringsW( us_src.Buffer, NULL, 0 );
1460 if (!(dstW = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, count_neededW * sizeof(WCHAR) ))) goto cleanup;
1461 count_neededW = ExpandEnvironmentStringsW( us_src.Buffer, dstW, count_neededW );
1462
1463 /* Calculate needed buffer */
1464 count_neededA = WideCharToMultiByte( CP_ACP, 0, dstW, count_neededW, NULL, 0, NULL, NULL );
1465
1466 /* If provided buffer is enough, do actual conversion */
1467 if (count > count_neededA)
1468 count_neededA = WideCharToMultiByte( CP_ACP, 0, dstW, count_neededW, dst, count, NULL, NULL );
1469 else if(dst)
1470 *dst = 0;
1471
1472cleanup:
1473 RtlFreeUnicodeString( &us_src );
1474 HeapFree( GetProcessHeap(), 0, dstW );
1475
1476 if (count_neededA >= count) /* When the buffer is too small, native over-reports by one byte */
1477 return count_neededA + 1;
1478 return count_neededA;
1479}
1480
1481
1482/***********************************************************************
1483 * ExpandEnvironmentStringsW (kernelbase.@)
1484 */
1485DWORD WINAPI DECLSPEC_HOTPATCH ExpandEnvironmentStringsW( LPCWSTR src, LPWSTR dst, DWORD len )
1486{
1487 UNICODE_STRING us_src, us_dst;
1488 NTSTATUS status;
1489 DWORD res;
1490
1491 TRACE( "(%s %p %lu)\n", debugstr_w(src), dst, len );
1492
1493 RtlInitUnicodeString( &us_src, src );
1494
1495 /* make sure we don't overflow the maximum UNICODE_STRING size */
1496 len = min( len, UNICODE_STRING_MAX_CHARS );
1497
1498 us_dst.Length = 0;
1499 us_dst.MaximumLength = len * sizeof(WCHAR);
1500 us_dst.Buffer = dst;
1501
1502 res = 0;
1503 status = RtlExpandEnvironmentStrings_U( NULL, &us_src, &us_dst, &res );
1504 res /= sizeof(WCHAR);
1505 if (status != STATUS_BUFFER_TOO_SMALL)
1506 {
1507 if(!set_ntstatus( status ))
1508 return 0;
1509 }
1510 return res;
1511}
1512
1513
1514/***********************************************************************
1515 * GetEnvironmentStrings (kernelbase.@)
1516 * GetEnvironmentStringsA (kernelbase.@)
1517 */
1518LPSTR WINAPI DECLSPEC_HOTPATCH GetEnvironmentStringsA(void)
1519{
1520 LPWSTR env;
1521 LPSTR ret;
1522 SIZE_T lenA, lenW;
1523
1524 RtlAcquirePebLock();
1525 env = NtCurrentTeb()->Peb->ProcessParameters->Environment;
1526 lenW = get_env_length( env );
1527 lenA = WideCharToMultiByte( CP_ACP, 0, env, lenW, NULL, 0, NULL, NULL );
1528 if ((ret = HeapAlloc( GetProcessHeap(), 0, lenA )))
1529 WideCharToMultiByte( CP_ACP, 0, env, lenW, ret, lenA, NULL, NULL );
1530 RtlReleasePebLock();
1531 return ret;
1532}
1533
1534
1535/***********************************************************************
1536 * GetEnvironmentStringsW (kernelbase.@)
1537 */
1538LPWSTR WINAPI DECLSPEC_HOTPATCH GetEnvironmentStringsW(void)
1539{
1540 LPWSTR ret;
1541 SIZE_T len;
1542
1543 RtlAcquirePebLock();
1544 len = get_env_length( NtCurrentTeb()->Peb->ProcessParameters->Environment ) * sizeof(WCHAR);
1545 if ((ret = HeapAlloc( GetProcessHeap(), 0, len )))
1546 memcpy( ret, NtCurrentTeb()->Peb->ProcessParameters->Environment, len );
1547 RtlReleasePebLock();
1548 return ret;
1549}
1550
1551
1552/***********************************************************************
1553 * SetEnvironmentStringsA (kernelbase.@)
1554 */
1555BOOL WINAPI DECLSPEC_HOTPATCH SetEnvironmentStringsA( char *env )
1556{
1557 WCHAR *envW;
1558 const char *p = env;
1559 DWORD len;
1560 BOOL ret;
1561
1562 for (p = env; *p; p += strlen( p ) + 1);
1563
1564 len = MultiByteToWideChar( CP_ACP, 0, env, p - env, NULL, 0 );
1565 if (!(envW = HeapAlloc( GetProcessHeap(), 0, len )))
1566 {
1567 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1568 return FALSE;
1569 }
1570 MultiByteToWideChar( CP_ACP, 0, env, p - env, envW, len );
1571 ret = SetEnvironmentStringsW( envW );
1572 HeapFree( GetProcessHeap(), 0, envW );
1573 return ret;
1574}
1575
1576
1577/***********************************************************************
1578 * SetEnvironmentStringsW (kernelbase.@)
1579 */
1580BOOL WINAPI DECLSPEC_HOTPATCH SetEnvironmentStringsW( WCHAR *env )
1581{
1582 WCHAR *p;
1583 WCHAR *new_env;
1584 NTSTATUS status;
1585
1586 for (p = env; *p; p += wcslen( p ) + 1)
1587 {
1588 const WCHAR *eq = wcschr( p, '=' );
1589 if (!eq || eq == p)
1590 {
1591 SetLastError( ERROR_INVALID_PARAMETER );
1592 return FALSE;
1593 }
1594 }
1595
1596 if ((status = RtlCreateEnvironment( FALSE, &new_env )))
1597 return set_ntstatus( status );
1598
1599 for (p = env; *p; p += wcslen( p ) + 1)
1600 {
1601 const WCHAR *eq = wcschr( p, '=' );
1602 UNICODE_STRING var, value;
1603 var.Buffer = p;
1604 var.Length = (eq - p) * sizeof(WCHAR);
1605 RtlInitUnicodeString( &value, eq + 1 );
1606 if ((status = RtlSetEnvironmentVariable( &new_env, &var, &value )))
1607 {
1608 RtlDestroyEnvironment( new_env );
1609 return set_ntstatus( status );
1610 }
1611 }
1612
1613 RtlSetCurrentEnvironment( new_env, NULL );
1614 return TRUE;
1615}
1616
1617
1618/***********************************************************************
1619 * GetEnvironmentVariableA (kernelbase.@)
1620 */
1621DWORD WINAPI DECLSPEC_HOTPATCH GetEnvironmentVariableA( LPCSTR name, LPSTR value, DWORD size )
1622{
1623 UNICODE_STRING us_name, us_value;
1624 PWSTR valueW;
1625 NTSTATUS status;
1626 DWORD len, ret;
1627
1628 /* limit the size to sane values */
1629 size = min( size, 32767 );
1630 if (!(valueW = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) return 0;
1631
1632 RtlCreateUnicodeStringFromAsciiz( &us_name, name );
1633 us_value.Length = 0;
1634 us_value.MaximumLength = (size ? size - 1 : 0) * sizeof(WCHAR);
1635 us_value.Buffer = valueW;
1636
1637 status = RtlQueryEnvironmentVariable_U( NULL, &us_name, &us_value );
1638 len = us_value.Length / sizeof(WCHAR);
1639 if (status == STATUS_BUFFER_TOO_SMALL) ret = len + 1;
1640 else if (!set_ntstatus( status )) ret = 0;
1641 else if (!size) ret = len + 1;
1642 else
1643 {
1644 if (len) WideCharToMultiByte( CP_ACP, 0, valueW, len + 1, value, size, NULL, NULL );
1645 value[len] = 0;
1646 ret = len;
1647 }
1648
1649 RtlFreeUnicodeString( &us_name );
1650 HeapFree( GetProcessHeap(), 0, valueW );
1651 return ret;
1652}
1653
1654
1655/***********************************************************************
1656 * GetEnvironmentVariableW (kernelbase.@)
1657 */
1658DWORD WINAPI DECLSPEC_HOTPATCH GetEnvironmentVariableW( LPCWSTR name, LPWSTR val, DWORD size )
1659{
1660 UNICODE_STRING us_name, us_value;
1661 NTSTATUS status;
1662 DWORD len;
1663
1664 TRACE( "(%s %p %lu)\n", debugstr_w(name), val, size );
1665
1666 RtlInitUnicodeString( &us_name, name );
1667 us_value.Length = 0;
1668 us_value.MaximumLength = (size ? size - 1 : 0) * sizeof(WCHAR);
1669 us_value.Buffer = val;
1670
1671 status = RtlQueryEnvironmentVariable_U( NULL, &us_name, &us_value );
1672 len = us_value.Length / sizeof(WCHAR);
1673 if (status == STATUS_BUFFER_TOO_SMALL) return len + 1;
1674 if (!set_ntstatus( status )) return 0;
1675 if (!size) return len + 1;
1676 val[len] = 0;
1677 return len;
1678}
1679
1680
1681/***********************************************************************
1682 * FreeEnvironmentStringsA (kernelbase.@)
1683 * FreeEnvironmentStringsW (kernelbase.@)
1684 */
1685BOOL WINAPI DECLSPEC_HOTPATCH FreeEnvironmentStringsW( LPWSTR ptr )
1686{
1687 return HeapFree( GetProcessHeap(), 0, ptr );
1688}
1689
1690
1691/***********************************************************************
1692 * SetEnvironmentVariableA (kernelbase.@)
1693 */
1694BOOL WINAPI DECLSPEC_HOTPATCH SetEnvironmentVariableA( LPCSTR name, LPCSTR value )
1695{
1696 UNICODE_STRING us_name, us_value;
1697 BOOL ret;
1698
1699 if (!name)
1700 {
1701 SetLastError( ERROR_ENVVAR_NOT_FOUND );
1702 return FALSE;
1703 }
1704
1705 RtlCreateUnicodeStringFromAsciiz( &us_name, name );
1706 if (value)
1707 {
1708 RtlCreateUnicodeStringFromAsciiz( &us_value, value );
1709 ret = SetEnvironmentVariableW( us_name.Buffer, us_value.Buffer );
1710 RtlFreeUnicodeString( &us_value );
1711 }
1712 else ret = SetEnvironmentVariableW( us_name.Buffer, NULL );
1713 RtlFreeUnicodeString( &us_name );
1714 return ret;
1715}
1716
1717
1718/***********************************************************************
1719 * SetEnvironmentVariableW (kernelbase.@)
1720 */
1721BOOL WINAPI DECLSPEC_HOTPATCH SetEnvironmentVariableW( LPCWSTR name, LPCWSTR value )
1722{
1723 UNICODE_STRING us_name, us_value;
1724 NTSTATUS status;
1725
1726 TRACE( "(%s %s)\n", debugstr_w(name), debugstr_w(value) );
1727
1728 if (!name)
1729 {
1730 SetLastError( ERROR_ENVVAR_NOT_FOUND );
1731 return FALSE;
1732 }
1733
1734 RtlInitUnicodeString( &us_name, name );
1735 if (value)
1736 {
1737 RtlInitUnicodeString( &us_value, value );
1738 status = RtlSetEnvironmentVariable( NULL, &us_name, &us_value );
1739 }
1740 else status = RtlSetEnvironmentVariable( NULL, &us_name, NULL );
1741
1742 return set_ntstatus( status );
1743}
1744
1745
1746/***********************************************************************
1747 * Process/thread attribute lists
1748 ***********************************************************************/
1749
1750/***********************************************************************
1751 * InitializeProcThreadAttributeList (kernelbase.@)
1752 */
1753BOOL WINAPI DECLSPEC_HOTPATCH InitializeProcThreadAttributeList( struct _PROC_THREAD_ATTRIBUTE_LIST *list,
1754 DWORD count, DWORD flags, SIZE_T *size )
1755{
1756 SIZE_T needed;
1757 BOOL ret = FALSE;
1758
1759 TRACE( "(%p %ld %lx %p)\n", list, count, flags, size );
1760
1761 needed = FIELD_OFFSET( struct _PROC_THREAD_ATTRIBUTE_LIST, attrs[count] );
1762 if (list && *size >= needed)
1763 {
1764 list->mask = 0;
1765 list->size = count;
1766 list->count = 0;
1767 list->unk = 0;
1768 ret = TRUE;
1769 }
1770 else SetLastError( ERROR_INSUFFICIENT_BUFFER );
1771
1772 *size = needed;
1773 return ret;
1774}
1775
1776
1777static inline DWORD validate_proc_thread_attribute( DWORD_PTR attr, SIZE_T size )
1778{
1779 switch (attr)
1780 {
1781 case PROC_THREAD_ATTRIBUTE_PARENT_PROCESS:
1782 if (size != sizeof(HANDLE)) return ERROR_BAD_LENGTH;
1783 break;
1784 case PROC_THREAD_ATTRIBUTE_EXTENDED_FLAGS:
1785 if (size != sizeof(ULONG)) return ERROR_BAD_LENGTH;
1786 break;
1787 case PROC_THREAD_ATTRIBUTE_HANDLE_LIST:
1788 if ((size / sizeof(HANDLE)) * sizeof(HANDLE) != size) return ERROR_BAD_LENGTH;
1789 break;
1790 case PROC_THREAD_ATTRIBUTE_IDEAL_PROCESSOR:
1791 if (size != sizeof(PROCESSOR_NUMBER)) return ERROR_BAD_LENGTH;
1792 break;
1793 case PROC_THREAD_ATTRIBUTE_CHILD_PROCESS_POLICY:
1794 if (size != sizeof(DWORD) && size != sizeof(DWORD64)) return ERROR_BAD_LENGTH;
1795 break;
1796 case PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY:
1797 if (size != sizeof(DWORD) && size != sizeof(DWORD64) && size != sizeof(DWORD64) * 2)
1798 return ERROR_BAD_LENGTH;
1799 break;
1800 case PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE:
1801 if (size != sizeof(HPCON)) return ERROR_BAD_LENGTH;
1802 break;
1803 case PROC_THREAD_ATTRIBUTE_JOB_LIST:
1804 if ((size / sizeof(HANDLE)) * sizeof(HANDLE) != size) return ERROR_BAD_LENGTH;
1805 break;
1806 case PROC_THREAD_ATTRIBUTE_MACHINE_TYPE:
1807 if (size != sizeof(USHORT)) return ERROR_BAD_LENGTH;
1808 break;
1809 default:
1810 FIXME( "Unhandled attribute %Iu\n", attr & PROC_THREAD_ATTRIBUTE_NUMBER );
1811 return ERROR_NOT_SUPPORTED;
1812 }
1813 return 0;
1814}
1815
1816
1817/***********************************************************************
1818 * UpdateProcThreadAttribute (kernelbase.@)
1819 */
1820BOOL WINAPI DECLSPEC_HOTPATCH UpdateProcThreadAttribute( struct _PROC_THREAD_ATTRIBUTE_LIST *list,
1821 DWORD flags, DWORD_PTR attr, void *value,
1822 SIZE_T size, void *prev_ret, SIZE_T *size_ret )
1823{
1824 DWORD mask, err;
1825 struct proc_thread_attr *entry;
1826
1827 TRACE( "(%p %lx %08Ix %p %Id %p %p)\n", list, flags, attr, value, size, prev_ret, size_ret );
1828
1829 if (list->count >= list->size)
1830 {
1831 SetLastError( ERROR_GEN_FAILURE );
1832 return FALSE;
1833 }
1834 if ((err = validate_proc_thread_attribute( attr, size )))
1835 {
1836 SetLastError( err );
1837 return FALSE;
1838 }
1839
1840 mask = 1 << (attr & PROC_THREAD_ATTRIBUTE_NUMBER);
1841 if (list->mask & mask)
1842 {
1843 SetLastError( ERROR_OBJECT_NAME_EXISTS );
1844 return FALSE;
1845 }
1846 list->mask |= mask;
1847
1848 entry = list->attrs + list->count;
1849 entry->attr = attr;
1850 entry->size = size;
1851 entry->value = value;
1852 list->count++;
1853 return TRUE;
1854}
1855
1856
1857/***********************************************************************
1858 * DeleteProcThreadAttributeList (kernelbase.@)
1859 */
1860void WINAPI DECLSPEC_HOTPATCH DeleteProcThreadAttributeList( struct _PROC_THREAD_ATTRIBUTE_LIST *list )
1861{
1862 return;
1863}
1864
1865
1866/***********************************************************************
1867 * CompareObjectHandles (kernelbase.@)
1868 */
1869BOOL WINAPI DECLSPEC_HOTPATCH CompareObjectHandles( HANDLE first, HANDLE second )
1870{
1871 return set_ntstatus( NtCompareObjects( first, second ));
1872}