/* * Win32 processes * * Copyright 1996, 1998 Alexandre Julliard * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include "ntstatus.h" #define WIN32_NO_STATUS #define NONAMELESSUNION #include "windef.h" #include "winbase.h" #include "winnls.h" #include "winternl.h" #include "kernelbase.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(process); static DWORD shutdown_flags = 0; static DWORD shutdown_priority = 0x280; /*********************************************************************** * Processes ***********************************************************************/ /*********************************************************************** * find_exe_file */ static BOOL find_exe_file( const WCHAR *name, WCHAR *buffer, DWORD buflen ) { WCHAR *load_path; BOOL ret; if (!set_ntstatus( RtlGetExePath( name, &load_path ))) return FALSE; TRACE( "looking for %s in %s\n", debugstr_w(name), debugstr_w(load_path) ); ret = (SearchPathW( load_path, name, L".exe", buflen, buffer, NULL ) || /* not found, try without extension in case it is a Unix app */ SearchPathW( load_path, name, NULL, buflen, buffer, NULL )); RtlReleasePath( load_path ); return ret; } /************************************************************************* * get_file_name * * Helper for CreateProcess: retrieve the file name to load from the * app name and command line. Store the file name in buffer, and * return a possibly modified command line. */ static WCHAR *get_file_name( WCHAR *cmdline, WCHAR *buffer, DWORD buflen ) { WCHAR *name, *pos, *first_space, *ret = NULL; const WCHAR *p; /* first check for a quoted file name */ if (cmdline[0] == '"' && (p = wcschr( cmdline + 1, '"' ))) { int len = p - cmdline - 1; /* extract the quoted portion as file name */ if (!(name = RtlAllocateHeap( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return NULL; memcpy( name, cmdline + 1, len * sizeof(WCHAR) ); name[len] = 0; if (!find_exe_file( name, buffer, buflen )) goto done; ret = cmdline; /* no change necessary */ goto done; } /* now try the command-line word by word */ if (!(name = RtlAllocateHeap( GetProcessHeap(), 0, (lstrlenW(cmdline) + 1) * sizeof(WCHAR) ))) return NULL; pos = name; p = cmdline; first_space = NULL; for (;;) { while (*p && *p != ' ' && *p != '\t') *pos++ = *p++; *pos = 0; if (find_exe_file( name, buffer, buflen )) { ret = cmdline; break; } if (!first_space) first_space = pos; if (!(*pos++ = *p++)) break; } if (!ret) { SetLastError( ERROR_FILE_NOT_FOUND ); } else if (first_space) /* build a new command-line with quotes */ { if (!(ret = HeapAlloc( GetProcessHeap(), 0, (lstrlenW(cmdline) + 3) * sizeof(WCHAR) ))) goto done; swprintf( ret, lstrlenW(cmdline) + 3, L"\"%s\"%s", name, p ); } done: RtlFreeHeap( GetProcessHeap(), 0, name ); return ret; } /*********************************************************************** * create_process_params */ static RTL_USER_PROCESS_PARAMETERS *create_process_params( const WCHAR *filename, const WCHAR *cmdline, const WCHAR *cur_dir, void *env, DWORD flags, const STARTUPINFOW *startup ) { RTL_USER_PROCESS_PARAMETERS *params; UNICODE_STRING imageW, dllpathW, curdirW, cmdlineW, titleW, desktopW, runtimeW, newdirW; WCHAR imagepath[MAX_PATH]; WCHAR *load_path, *dummy, *envW = env; if (!GetLongPathNameW( filename, imagepath, MAX_PATH )) lstrcpynW( imagepath, filename, MAX_PATH ); if (!GetFullPathNameW( imagepath, MAX_PATH, imagepath, NULL )) lstrcpynW( imagepath, filename, MAX_PATH ); if (env && !(flags & CREATE_UNICODE_ENVIRONMENT)) /* convert environment to unicode */ { char *e = env; DWORD lenW; while (*e) e += strlen(e) + 1; e++; /* final null */ lenW = MultiByteToWideChar( CP_ACP, 0, env, e - (char *)env, NULL, 0 ); if ((envW = RtlAllocateHeap( GetProcessHeap(), 0, lenW * sizeof(WCHAR) ))) MultiByteToWideChar( CP_ACP, 0, env, e - (char *)env, envW, lenW ); } newdirW.Buffer = NULL; if (cur_dir) { if (RtlDosPathNameToNtPathName_U( cur_dir, &newdirW, NULL, NULL )) cur_dir = newdirW.Buffer + 4; /* skip \??\ prefix */ else cur_dir = NULL; } LdrGetDllPath( imagepath, LOAD_WITH_ALTERED_SEARCH_PATH, &load_path, &dummy ); RtlInitUnicodeString( &imageW, imagepath ); RtlInitUnicodeString( &dllpathW, load_path ); RtlInitUnicodeString( &curdirW, cur_dir ); RtlInitUnicodeString( &cmdlineW, cmdline ); RtlInitUnicodeString( &titleW, startup->lpTitle ? startup->lpTitle : imagepath ); RtlInitUnicodeString( &desktopW, startup->lpDesktop ); runtimeW.Buffer = (WCHAR *)startup->lpReserved2; runtimeW.Length = runtimeW.MaximumLength = startup->cbReserved2; if (RtlCreateProcessParametersEx( ¶ms, &imageW, &dllpathW, cur_dir ? &curdirW : NULL, &cmdlineW, envW, &titleW, &desktopW, NULL, &runtimeW, PROCESS_PARAMS_FLAG_NORMALIZED )) { RtlReleasePath( load_path ); if (envW != env) RtlFreeHeap( GetProcessHeap(), 0, envW ); return NULL; } RtlReleasePath( load_path ); if (flags & CREATE_NEW_PROCESS_GROUP) params->ConsoleFlags = 1; if (flags & CREATE_NEW_CONSOLE) params->ConsoleHandle = (HANDLE)1; /* KERNEL32_CONSOLE_ALLOC */ if (startup->dwFlags & STARTF_USESTDHANDLES) { params->hStdInput = startup->hStdInput; params->hStdOutput = startup->hStdOutput; params->hStdError = startup->hStdError; } else if (flags & DETACHED_PROCESS) { params->hStdInput = INVALID_HANDLE_VALUE; params->hStdOutput = INVALID_HANDLE_VALUE; params->hStdError = INVALID_HANDLE_VALUE; } else { params->hStdInput = NtCurrentTeb()->Peb->ProcessParameters->hStdInput; params->hStdOutput = NtCurrentTeb()->Peb->ProcessParameters->hStdOutput; params->hStdError = NtCurrentTeb()->Peb->ProcessParameters->hStdError; } if (flags & CREATE_NEW_CONSOLE) { /* this is temporary (for console handles). We have no way to control that the handle is invalid in child process otherwise */ if (is_console_handle(params->hStdInput)) params->hStdInput = INVALID_HANDLE_VALUE; if (is_console_handle(params->hStdOutput)) params->hStdOutput = INVALID_HANDLE_VALUE; if (is_console_handle(params->hStdError)) params->hStdError = INVALID_HANDLE_VALUE; } else { if (is_console_handle(params->hStdInput)) params->hStdInput = (HANDLE)((UINT_PTR)params->hStdInput & ~3); if (is_console_handle(params->hStdOutput)) params->hStdOutput = (HANDLE)((UINT_PTR)params->hStdOutput & ~3); if (is_console_handle(params->hStdError)) params->hStdError = (HANDLE)((UINT_PTR)params->hStdError & ~3); } params->dwX = startup->dwX; params->dwY = startup->dwY; params->dwXSize = startup->dwXSize; params->dwYSize = startup->dwYSize; params->dwXCountChars = startup->dwXCountChars; params->dwYCountChars = startup->dwYCountChars; params->dwFillAttribute = startup->dwFillAttribute; params->dwFlags = startup->dwFlags; params->wShowWindow = startup->wShowWindow; if (envW != env) RtlFreeHeap( GetProcessHeap(), 0, envW ); return params; } /*********************************************************************** * create_nt_process */ static NTSTATUS create_nt_process( SECURITY_ATTRIBUTES *psa, SECURITY_ATTRIBUTES *tsa, BOOL inherit, DWORD flags, RTL_USER_PROCESS_PARAMETERS *params, RTL_USER_PROCESS_INFORMATION *info ) { NTSTATUS status; UNICODE_STRING nameW; if (!params->ImagePathName.Buffer[0]) return STATUS_OBJECT_PATH_NOT_FOUND; status = RtlDosPathNameToNtPathName_U_WithStatus( params->ImagePathName.Buffer, &nameW, NULL, NULL ); if (!status) { params->DebugFlags = flags; /* hack, cf. RtlCreateUserProcess implementation */ status = RtlCreateUserProcess( &nameW, OBJ_CASE_INSENSITIVE, params, psa ? psa->lpSecurityDescriptor : NULL, tsa ? tsa->lpSecurityDescriptor : NULL, 0, inherit, 0, 0, info ); RtlFreeUnicodeString( &nameW ); } return status; } /*********************************************************************** * create_vdm_process */ static NTSTATUS create_vdm_process( SECURITY_ATTRIBUTES *psa, SECURITY_ATTRIBUTES *tsa, BOOL inherit, DWORD flags, RTL_USER_PROCESS_PARAMETERS *params, RTL_USER_PROCESS_INFORMATION *info ) { const WCHAR *winevdm = (is_win64 || is_wow64 ? L"C:\\windows\\syswow64\\winevdm.exe" : L"C:\\windows\\system32\\winevdm.exe"); WCHAR *newcmdline; NTSTATUS status; UINT len; len = (lstrlenW(params->ImagePathName.Buffer) + lstrlenW(params->CommandLine.Buffer) + lstrlenW(winevdm) + 16); if (!(newcmdline = RtlAllocateHeap( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return STATUS_NO_MEMORY; swprintf( newcmdline, len, L"%s --app-name \"%s\" %s", winevdm, params->ImagePathName.Buffer, params->CommandLine.Buffer ); RtlInitUnicodeString( ¶ms->ImagePathName, winevdm ); RtlInitUnicodeString( ¶ms->CommandLine, newcmdline ); status = create_nt_process( psa, tsa, inherit, flags, params, info ); HeapFree( GetProcessHeap(), 0, newcmdline ); return status; } /*********************************************************************** * create_cmd_process */ static NTSTATUS create_cmd_process( SECURITY_ATTRIBUTES *psa, SECURITY_ATTRIBUTES *tsa, BOOL inherit, DWORD flags, RTL_USER_PROCESS_PARAMETERS *params, RTL_USER_PROCESS_INFORMATION *info ) { WCHAR comspec[MAX_PATH]; WCHAR *newcmdline; NTSTATUS status; UINT len; if (!GetEnvironmentVariableW( L"COMSPEC", comspec, ARRAY_SIZE( comspec ))) lstrcpyW( comspec, L"C:\\windows\\system32\\cmd.exe" ); len = lstrlenW(comspec) + 7 + lstrlenW(params->CommandLine.Buffer) + 2; if (!(newcmdline = RtlAllocateHeap( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return STATUS_NO_MEMORY; swprintf( newcmdline, len, L"%s /s/c \"%s\"", comspec, params->CommandLine.Buffer ); RtlInitUnicodeString( ¶ms->ImagePathName, comspec ); RtlInitUnicodeString( ¶ms->CommandLine, newcmdline ); status = create_nt_process( psa, tsa, inherit, flags, params, info ); RtlFreeHeap( GetProcessHeap(), 0, newcmdline ); return status; } /********************************************************************* * CloseHandle (kernelbase.@) */ BOOL WINAPI DECLSPEC_HOTPATCH CloseHandle( HANDLE handle ) { if (handle == (HANDLE)STD_INPUT_HANDLE) handle = InterlockedExchangePointer( &NtCurrentTeb()->Peb->ProcessParameters->hStdInput, 0 ); else if (handle == (HANDLE)STD_OUTPUT_HANDLE) handle = InterlockedExchangePointer( &NtCurrentTeb()->Peb->ProcessParameters->hStdOutput, 0 ); else if (handle == (HANDLE)STD_ERROR_HANDLE) handle = InterlockedExchangePointer( &NtCurrentTeb()->Peb->ProcessParameters->hStdError, 0 ); if (is_console_handle( handle )) handle = console_handle_map( handle ); return set_ntstatus( NtClose( handle )); } /********************************************************************** * CreateProcessAsUserA (kernelbase.@) */ BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessAsUserA( HANDLE token, const char *app_name, char *cmd_line, SECURITY_ATTRIBUTES *process_attr, SECURITY_ATTRIBUTES *thread_attr, BOOL inherit, DWORD flags, void *env, const char *cur_dir, STARTUPINFOA *startup_info, PROCESS_INFORMATION *info ) { return CreateProcessInternalA( token, app_name, cmd_line, process_attr, thread_attr, inherit, flags, env, cur_dir, startup_info, info, NULL ); } /********************************************************************** * CreateProcessAsUserW (kernelbase.@) */ BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessAsUserW( HANDLE token, const WCHAR *app_name, WCHAR *cmd_line, SECURITY_ATTRIBUTES *process_attr, SECURITY_ATTRIBUTES *thread_attr, BOOL inherit, DWORD flags, void *env, const WCHAR *cur_dir, STARTUPINFOW *startup_info, PROCESS_INFORMATION *info ) { return CreateProcessInternalW( token, app_name, cmd_line, process_attr, thread_attr, inherit, flags, env, cur_dir, startup_info, info, NULL ); } /********************************************************************** * CreateProcessInternalA (kernelbase.@) */ BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessInternalA( HANDLE token, const char *app_name, char *cmd_line, SECURITY_ATTRIBUTES *process_attr, SECURITY_ATTRIBUTES *thread_attr, BOOL inherit, DWORD flags, void *env, const char *cur_dir, STARTUPINFOA *startup_info, PROCESS_INFORMATION *info, HANDLE *new_token ) { BOOL ret = FALSE; WCHAR *app_nameW = NULL, *cmd_lineW = NULL, *cur_dirW = NULL; UNICODE_STRING desktopW, titleW; STARTUPINFOW infoW; desktopW.Buffer = NULL; titleW.Buffer = NULL; if (app_name && !(app_nameW = file_name_AtoW( app_name, TRUE ))) goto done; if (cmd_line && !(cmd_lineW = file_name_AtoW( cmd_line, TRUE ))) goto done; if (cur_dir && !(cur_dirW = file_name_AtoW( cur_dir, TRUE ))) goto done; if (startup_info->lpDesktop) RtlCreateUnicodeStringFromAsciiz( &desktopW, startup_info->lpDesktop ); if (startup_info->lpTitle) RtlCreateUnicodeStringFromAsciiz( &titleW, startup_info->lpTitle ); memcpy( &infoW, startup_info, sizeof(infoW) ); infoW.lpDesktop = desktopW.Buffer; infoW.lpTitle = titleW.Buffer; ret = CreateProcessInternalW( token, app_nameW, cmd_lineW, process_attr, thread_attr, inherit, flags, env, cur_dirW, &infoW, info, new_token ); done: RtlFreeHeap( GetProcessHeap(), 0, app_nameW ); RtlFreeHeap( GetProcessHeap(), 0, cmd_lineW ); RtlFreeHeap( GetProcessHeap(), 0, cur_dirW ); RtlFreeUnicodeString( &desktopW ); RtlFreeUnicodeString( &titleW ); return ret; } /********************************************************************** * CreateProcessInternalW (kernelbase.@) */ BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessInternalW( HANDLE token, const WCHAR *app_name, WCHAR *cmd_line, SECURITY_ATTRIBUTES *process_attr, SECURITY_ATTRIBUTES *thread_attr, BOOL inherit, DWORD flags, void *env, const WCHAR *cur_dir, STARTUPINFOW *startup_info, PROCESS_INFORMATION *info, HANDLE *new_token ) { WCHAR name[MAX_PATH]; WCHAR *p, *tidy_cmdline = cmd_line; RTL_USER_PROCESS_PARAMETERS *params = NULL; RTL_USER_PROCESS_INFORMATION rtl_info; NTSTATUS status; /* Process the AppName and/or CmdLine to get module name and path */ TRACE( "app %s cmdline %s\n", debugstr_w(app_name), debugstr_w(cmd_line) ); if (token) FIXME( "Creating a process with a token is not yet implemented\n" ); if (new_token) FIXME( "No support for returning created process token\n" ); if (app_name) { if (!cmd_line || !cmd_line[0]) /* no command-line, create one */ { if (!(tidy_cmdline = RtlAllocateHeap( GetProcessHeap(), 0, (lstrlenW(app_name)+3) * sizeof(WCHAR) ))) return FALSE; swprintf( tidy_cmdline, lstrlenW(app_name) + 3, L"\"%s\"", app_name ); } } else { if (!(tidy_cmdline = get_file_name( cmd_line, name, ARRAY_SIZE(name) ))) return FALSE; app_name = name; } /* Warn if unsupported features are used */ if (flags & (IDLE_PRIORITY_CLASS | HIGH_PRIORITY_CLASS | REALTIME_PRIORITY_CLASS | CREATE_DEFAULT_ERROR_MODE | CREATE_NO_WINDOW | PROFILE_USER | PROFILE_KERNEL | PROFILE_SERVER)) WARN( "(%s,...): ignoring some flags in %x\n", debugstr_w(app_name), flags ); if (cur_dir) { DWORD attr = GetFileAttributesW( cur_dir ); if (attr == INVALID_FILE_ATTRIBUTES || !(attr & FILE_ATTRIBUTE_DIRECTORY)) { status = STATUS_NOT_A_DIRECTORY; goto done; } } info->hThread = info->hProcess = 0; info->dwProcessId = info->dwThreadId = 0; if (!(params = create_process_params( app_name, tidy_cmdline, cur_dir, env, flags, startup_info ))) { status = STATUS_NO_MEMORY; goto done; } status = create_nt_process( process_attr, thread_attr, inherit, flags, params, &rtl_info ); switch (status) { case STATUS_SUCCESS: break; case STATUS_INVALID_IMAGE_WIN_16: case STATUS_INVALID_IMAGE_NE_FORMAT: case STATUS_INVALID_IMAGE_PROTECT: TRACE( "starting %s as Win16/DOS binary\n", debugstr_w(app_name) ); status = create_vdm_process( process_attr, thread_attr, inherit, flags, params, &rtl_info ); break; case STATUS_INVALID_IMAGE_NOT_MZ: /* check for .com or .bat extension */ if (!(p = wcsrchr( app_name, '.' ))) break; if (!wcsicmp( p, L".com" ) || !wcsicmp( p, L".pif" )) { TRACE( "starting %s as DOS binary\n", debugstr_w(app_name) ); status = create_vdm_process( process_attr, thread_attr, inherit, flags, params, &rtl_info ); } else if (!wcsicmp( p, L".bat" ) || !wcsicmp( p, L".cmd" )) { TRACE( "starting %s as batch binary\n", debugstr_w(app_name) ); status = create_cmd_process( process_attr, thread_attr, inherit, flags, params, &rtl_info ); } break; } if (!status) { info->hProcess = rtl_info.Process; info->hThread = rtl_info.Thread; info->dwProcessId = HandleToUlong( rtl_info.ClientId.UniqueProcess ); info->dwThreadId = HandleToUlong( rtl_info.ClientId.UniqueThread ); if (!(flags & CREATE_SUSPENDED)) NtResumeThread( rtl_info.Thread, NULL ); TRACE( "started process pid %04x tid %04x\n", info->dwProcessId, info->dwThreadId ); } done: RtlDestroyProcessParameters( params ); if (tidy_cmdline != cmd_line) HeapFree( GetProcessHeap(), 0, tidy_cmdline ); return set_ntstatus( status ); } /********************************************************************** * CreateProcessA (kernelbase.@) */ BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessA( const char *app_name, char *cmd_line, SECURITY_ATTRIBUTES *process_attr, SECURITY_ATTRIBUTES *thread_attr, BOOL inherit, DWORD flags, void *env, const char *cur_dir, STARTUPINFOA *startup_info, PROCESS_INFORMATION *info ) { return CreateProcessInternalA( NULL, app_name, cmd_line, process_attr, thread_attr, inherit, flags, env, cur_dir, startup_info, info, NULL ); } /********************************************************************** * CreateProcessW (kernelbase.@) */ BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessW( const WCHAR *app_name, WCHAR *cmd_line, SECURITY_ATTRIBUTES *process_attr, SECURITY_ATTRIBUTES *thread_attr, BOOL inherit, DWORD flags, void *env, const WCHAR *cur_dir, STARTUPINFOW *startup_info, PROCESS_INFORMATION *info ) { return CreateProcessInternalW( NULL, app_name, cmd_line, process_attr, thread_attr, inherit, flags, env, cur_dir, startup_info, info, NULL ); } /********************************************************************* * DuplicateHandle (kernelbase.@) */ BOOL WINAPI DECLSPEC_HOTPATCH DuplicateHandle( HANDLE source_process, HANDLE source, HANDLE dest_process, HANDLE *dest, DWORD access, BOOL inherit, DWORD options ) { if (is_console_handle( source )) { source = console_handle_map( source ); if (!set_ntstatus( NtDuplicateObject( source_process, source, dest_process, dest, access, inherit ? OBJ_INHERIT : 0, options ))) return FALSE; *dest = console_handle_map( *dest ); return TRUE; } return set_ntstatus( NtDuplicateObject( source_process, source, dest_process, dest, access, inherit ? OBJ_INHERIT : 0, options )); } /**************************************************************************** * FlushInstructionCache (kernelbase.@) */ BOOL WINAPI DECLSPEC_HOTPATCH FlushInstructionCache( HANDLE process, LPCVOID addr, SIZE_T size ) { return set_ntstatus( NtFlushInstructionCache( process, addr, size )); } /*********************************************************************** * GetCurrentProcess (kernelbase.@) */ HANDLE WINAPI kernelbase_GetCurrentProcess(void) { return (HANDLE)~(ULONG_PTR)0; } /*********************************************************************** * GetCurrentProcessId (kernelbase.@) */ DWORD WINAPI kernelbase_GetCurrentProcessId(void) { return HandleToULong( NtCurrentTeb()->ClientId.UniqueProcess ); } /*********************************************************************** * GetErrorMode (kernelbase.@) */ UINT WINAPI DECLSPEC_HOTPATCH GetErrorMode(void) { UINT mode; NtQueryInformationProcess( GetCurrentProcess(), ProcessDefaultHardErrorMode, &mode, sizeof(mode), NULL ); return mode; } /*********************************************************************** * GetExitCodeProcess (kernelbase.@) */ BOOL WINAPI DECLSPEC_HOTPATCH GetExitCodeProcess( HANDLE process, LPDWORD exit_code ) { NTSTATUS status; PROCESS_BASIC_INFORMATION pbi; status = NtQueryInformationProcess( process, ProcessBasicInformation, &pbi, sizeof(pbi), NULL ); if (status && exit_code) *exit_code = pbi.ExitStatus; return set_ntstatus( status ); } /********************************************************************* * GetHandleInformation (kernelbase.@) */ BOOL WINAPI DECLSPEC_HOTPATCH GetHandleInformation( HANDLE handle, DWORD *flags ) { OBJECT_DATA_INFORMATION info; if (!set_ntstatus( NtQueryObject( handle, ObjectDataInformation, &info, sizeof(info), NULL ))) return FALSE; if (flags) { *flags = 0; if (info.InheritHandle) *flags |= HANDLE_FLAG_INHERIT; if (info.ProtectFromClose) *flags |= HANDLE_FLAG_PROTECT_FROM_CLOSE; } return TRUE; } /*********************************************************************** * GetPriorityClass (kernelbase.@) */ DWORD WINAPI DECLSPEC_HOTPATCH GetPriorityClass( HANDLE process ) { PROCESS_BASIC_INFORMATION pbi; if (!set_ntstatus( NtQueryInformationProcess( process, ProcessBasicInformation, &pbi, sizeof(pbi), NULL ))) return 0; switch (pbi.BasePriority) { case PROCESS_PRIOCLASS_IDLE: return IDLE_PRIORITY_CLASS; case PROCESS_PRIOCLASS_BELOW_NORMAL: return BELOW_NORMAL_PRIORITY_CLASS; case PROCESS_PRIOCLASS_NORMAL: return NORMAL_PRIORITY_CLASS; case PROCESS_PRIOCLASS_ABOVE_NORMAL: return ABOVE_NORMAL_PRIORITY_CLASS; case PROCESS_PRIOCLASS_HIGH: return HIGH_PRIORITY_CLASS; case PROCESS_PRIOCLASS_REALTIME: return REALTIME_PRIORITY_CLASS; default: return 0; } } /****************************************************************** * GetProcessHandleCount (kernelbase.@) */ BOOL WINAPI DECLSPEC_HOTPATCH GetProcessHandleCount( HANDLE process, DWORD *count ) { return set_ntstatus( NtQueryInformationProcess( process, ProcessHandleCount, count, sizeof(*count), NULL )); } /*********************************************************************** * GetProcessHeap (kernelbase.@) */ HANDLE WINAPI kernelbase_GetProcessHeap(void) { return NtCurrentTeb()->Peb->ProcessHeap; } /********************************************************************* * GetProcessId (kernelbase.@) */ DWORD WINAPI DECLSPEC_HOTPATCH GetProcessId( HANDLE process ) { PROCESS_BASIC_INFORMATION pbi; if (!set_ntstatus( NtQueryInformationProcess( process, ProcessBasicInformation, &pbi, sizeof(pbi), NULL ))) return 0; return pbi.UniqueProcessId; } /********************************************************************** * GetProcessMitigationPolicy (kernelbase.@) */ BOOL WINAPI /* DECLSPEC_HOTPATCH */ GetProcessMitigationPolicy( HANDLE process, PROCESS_MITIGATION_POLICY policy, void *buffer, SIZE_T length ) { FIXME( "(%p, %u, %p, %lu): stub\n", process, policy, buffer, length ); return TRUE; } /*********************************************************************** * GetProcessPriorityBoost (kernelbase.@) */ BOOL WINAPI DECLSPEC_HOTPATCH GetProcessPriorityBoost( HANDLE process, PBOOL disable ) { FIXME( "(%p,%p): semi-stub\n", process, disable ); *disable = FALSE; /* report that no boost is present */ return TRUE; } /*********************************************************************** * GetProcessShutdownParameters (kernelbase.@) */ BOOL WINAPI DECLSPEC_HOTPATCH GetProcessShutdownParameters( LPDWORD level, LPDWORD flags ) { *level = shutdown_priority; *flags = shutdown_flags; return TRUE; } /*********************************************************************** * GetProcessWorkingSetSizeEx (kernelbase.@) */ BOOL WINAPI DECLSPEC_HOTPATCH GetProcessWorkingSetSizeEx( HANDLE process, SIZE_T *minset, SIZE_T *maxset, DWORD *flags) { FIXME( "(%p,%p,%p,%p): stub\n", process, minset, maxset, flags ); /* 32 MB working set size */ if (minset) *minset = 32*1024*1024; if (maxset) *maxset = 32*1024*1024; if (flags) *flags = QUOTA_LIMITS_HARDWS_MIN_DISABLE | QUOTA_LIMITS_HARDWS_MAX_DISABLE; return TRUE; } /****************************************************************************** * IsProcessInJob (kernelbase.@) */ BOOL WINAPI DECLSPEC_HOTPATCH IsProcessInJob( HANDLE process, HANDLE job, BOOL *result ) { NTSTATUS status = NtIsProcessInJob( process, job ); switch (status) { case STATUS_PROCESS_IN_JOB: *result = TRUE; return TRUE; case STATUS_PROCESS_NOT_IN_JOB: *result = FALSE; return TRUE; default: return set_ntstatus( status ); } } /*********************************************************************** * IsProcessorFeaturePresent (kernelbase.@) */ BOOL WINAPI DECLSPEC_HOTPATCH IsProcessorFeaturePresent ( DWORD feature ) { return RtlIsProcessorFeaturePresent( feature ); } /********************************************************************** * IsWow64Process (kernelbase.@) */ BOOL WINAPI DECLSPEC_HOTPATCH IsWow64Process( HANDLE process, PBOOL wow64 ) { ULONG_PTR pbi; NTSTATUS status; status = NtQueryInformationProcess( process, ProcessWow64Information, &pbi, sizeof(pbi), NULL ); if (!status) *wow64 = !!pbi; return set_ntstatus( status ); } /********************************************************************* * OpenProcess (kernelbase.@) */ HANDLE WINAPI DECLSPEC_HOTPATCH OpenProcess( DWORD access, BOOL inherit, DWORD id ) { HANDLE handle; OBJECT_ATTRIBUTES attr; CLIENT_ID cid; if (GetVersion() & 0x80000000) access = PROCESS_ALL_ACCESS; attr.Length = sizeof(OBJECT_ATTRIBUTES); attr.RootDirectory = 0; attr.Attributes = inherit ? OBJ_INHERIT : 0; attr.ObjectName = NULL; attr.SecurityDescriptor = NULL; attr.SecurityQualityOfService = NULL; cid.UniqueProcess = ULongToHandle(id); cid.UniqueThread = 0; if (!set_ntstatus( NtOpenProcess( &handle, access, &attr, &cid ))) return NULL; return handle; } /*********************************************************************** * SetErrorMode (kernelbase.@) */ UINT WINAPI DECLSPEC_HOTPATCH SetErrorMode( UINT mode ) { UINT old = GetErrorMode(); NtSetInformationProcess( GetCurrentProcess(), ProcessDefaultHardErrorMode, &mode, sizeof(mode) ); return old; } /************************************************************************* * SetHandleCount (kernelbase.@) */ UINT WINAPI DECLSPEC_HOTPATCH SetHandleCount( UINT count ) { return count; } /********************************************************************* * SetHandleInformation (kernelbase.@) */ BOOL WINAPI DECLSPEC_HOTPATCH SetHandleInformation( HANDLE handle, DWORD mask, DWORD flags ) { OBJECT_DATA_INFORMATION info; /* if not setting both fields, retrieve current value first */ if ((mask & (HANDLE_FLAG_INHERIT | HANDLE_FLAG_PROTECT_FROM_CLOSE)) != (HANDLE_FLAG_INHERIT | HANDLE_FLAG_PROTECT_FROM_CLOSE)) { if (!set_ntstatus( NtQueryObject( handle, ObjectDataInformation, &info, sizeof(info), NULL ))) return FALSE; } if (mask & HANDLE_FLAG_INHERIT) info.InheritHandle = (flags & HANDLE_FLAG_INHERIT) != 0; if (mask & HANDLE_FLAG_PROTECT_FROM_CLOSE) info.ProtectFromClose = (flags & HANDLE_FLAG_PROTECT_FROM_CLOSE) != 0; return set_ntstatus( NtSetInformationObject( handle, ObjectDataInformation, &info, sizeof(info) )); } /*********************************************************************** * SetPriorityClass (kernelbase.@) */ BOOL WINAPI DECLSPEC_HOTPATCH SetPriorityClass( HANDLE process, DWORD class ) { PROCESS_PRIORITY_CLASS ppc; ppc.Foreground = FALSE; switch (class) { case IDLE_PRIORITY_CLASS: ppc.PriorityClass = PROCESS_PRIOCLASS_IDLE; break; case BELOW_NORMAL_PRIORITY_CLASS: ppc.PriorityClass = PROCESS_PRIOCLASS_BELOW_NORMAL; break; case NORMAL_PRIORITY_CLASS: ppc.PriorityClass = PROCESS_PRIOCLASS_NORMAL; break; case ABOVE_NORMAL_PRIORITY_CLASS: ppc.PriorityClass = PROCESS_PRIOCLASS_ABOVE_NORMAL; break; case HIGH_PRIORITY_CLASS: ppc.PriorityClass = PROCESS_PRIOCLASS_HIGH; break; case REALTIME_PRIORITY_CLASS: ppc.PriorityClass = PROCESS_PRIOCLASS_REALTIME; break; default: SetLastError( ERROR_INVALID_PARAMETER ); return FALSE; } return set_ntstatus( NtSetInformationProcess( process, ProcessPriorityClass, &ppc, sizeof(ppc) )); } /*********************************************************************** * SetProcessAffinityUpdateMode (kernelbase.@) */ BOOL WINAPI DECLSPEC_HOTPATCH SetProcessAffinityUpdateMode( HANDLE process, DWORD flags ) { FIXME( "(%p,0x%08x): stub\n", process, flags ); SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); return FALSE; } /********************************************************************** * SetProcessMitigationPolicy (kernelbase.@) */ BOOL WINAPI /* DECLSPEC_HOTPATCH */ SetProcessMitigationPolicy( PROCESS_MITIGATION_POLICY policy, void *buffer, SIZE_T length ) { FIXME( "(%d, %p, %lu): stub\n", policy, buffer, length ); return TRUE; } /*********************************************************************** * SetProcessPriorityBoost (kernelbase.@) */ BOOL WINAPI /* DECLSPEC_HOTPATCH */ SetProcessPriorityBoost( HANDLE process, BOOL disable ) { FIXME( "(%p,%d): stub\n", process, disable ); return TRUE; } /*********************************************************************** * SetProcessShutdownParameters (kernelbase.@) */ BOOL WINAPI DECLSPEC_HOTPATCH SetProcessShutdownParameters( DWORD level, DWORD flags ) { FIXME( "(%08x, %08x): partial stub.\n", level, flags ); shutdown_flags = flags; shutdown_priority = level; return TRUE; } /*********************************************************************** * SetProcessWorkingSetSizeEx (kernelbase.@) */ BOOL WINAPI DECLSPEC_HOTPATCH SetProcessWorkingSetSizeEx( HANDLE process, SIZE_T minset, SIZE_T maxset, DWORD flags ) { return TRUE; } /****************************************************************************** * TerminateProcess (kernelbase.@) */ BOOL WINAPI DECLSPEC_HOTPATCH TerminateProcess( HANDLE handle, DWORD exit_code ) { if (!handle) { SetLastError( ERROR_INVALID_HANDLE ); return FALSE; } return set_ntstatus( NtTerminateProcess( handle, exit_code )); } /*********************************************************************** * Process startup information ***********************************************************************/ static STARTUPINFOW startup_infoW; static char *command_lineA; static WCHAR *command_lineW; /****************************************************************** * init_startup_info */ void init_startup_info( RTL_USER_PROCESS_PARAMETERS *params ) { ANSI_STRING ansi; startup_infoW.cb = sizeof(startup_infoW); startup_infoW.lpReserved = NULL; startup_infoW.lpDesktop = params->Desktop.Buffer; startup_infoW.lpTitle = params->WindowTitle.Buffer; startup_infoW.dwX = params->dwX; startup_infoW.dwY = params->dwY; startup_infoW.dwXSize = params->dwXSize; startup_infoW.dwYSize = params->dwYSize; startup_infoW.dwXCountChars = params->dwXCountChars; startup_infoW.dwYCountChars = params->dwYCountChars; startup_infoW.dwFillAttribute = params->dwFillAttribute; startup_infoW.dwFlags = params->dwFlags; startup_infoW.wShowWindow = params->wShowWindow; startup_infoW.cbReserved2 = params->RuntimeInfo.MaximumLength; startup_infoW.lpReserved2 = params->RuntimeInfo.MaximumLength ? (void *)params->RuntimeInfo.Buffer : NULL; startup_infoW.hStdInput = params->hStdInput ? params->hStdInput : INVALID_HANDLE_VALUE; startup_infoW.hStdOutput = params->hStdOutput ? params->hStdOutput : INVALID_HANDLE_VALUE; startup_infoW.hStdError = params->hStdError ? params->hStdError : INVALID_HANDLE_VALUE; command_lineW = params->CommandLine.Buffer; if (!RtlUnicodeStringToAnsiString( &ansi, ¶ms->CommandLine, TRUE )) command_lineA = ansi.Buffer; } /*********************************************************************** * GetCommandLineA (kernelbase.@) */ LPSTR WINAPI DECLSPEC_HOTPATCH GetCommandLineA(void) { return command_lineA; } /*********************************************************************** * GetCommandLineW (kernelbase.@) */ LPWSTR WINAPI DECLSPEC_HOTPATCH GetCommandLineW(void) { return NtCurrentTeb()->Peb->ProcessParameters->CommandLine.Buffer; } /*********************************************************************** * GetStartupInfoW (kernelbase.@) */ void WINAPI DECLSPEC_HOTPATCH GetStartupInfoW( STARTUPINFOW *info ) { *info = startup_infoW; } /*********************************************************************** * GetStdHandle (kernelbase.@) */ HANDLE WINAPI DECLSPEC_HOTPATCH GetStdHandle( DWORD std_handle ) { switch (std_handle) { case STD_INPUT_HANDLE: return NtCurrentTeb()->Peb->ProcessParameters->hStdInput; case STD_OUTPUT_HANDLE: return NtCurrentTeb()->Peb->ProcessParameters->hStdOutput; case STD_ERROR_HANDLE: return NtCurrentTeb()->Peb->ProcessParameters->hStdError; } SetLastError( ERROR_INVALID_HANDLE ); return INVALID_HANDLE_VALUE; } /*********************************************************************** * SetStdHandle (kernelbase.@) */ BOOL WINAPI DECLSPEC_HOTPATCH SetStdHandle( DWORD std_handle, HANDLE handle ) { switch (std_handle) { case STD_INPUT_HANDLE: NtCurrentTeb()->Peb->ProcessParameters->hStdInput = handle; return TRUE; case STD_OUTPUT_HANDLE: NtCurrentTeb()->Peb->ProcessParameters->hStdOutput = handle; return TRUE; case STD_ERROR_HANDLE: NtCurrentTeb()->Peb->ProcessParameters->hStdError = handle; return TRUE; } SetLastError( ERROR_INVALID_HANDLE ); return FALSE; } /*********************************************************************** * SetStdHandleEx (kernelbase.@) */ BOOL WINAPI DECLSPEC_HOTPATCH SetStdHandleEx( DWORD std_handle, HANDLE handle, HANDLE *prev ) { HANDLE *ptr; switch (std_handle) { case STD_INPUT_HANDLE: ptr = &NtCurrentTeb()->Peb->ProcessParameters->hStdInput; break; case STD_OUTPUT_HANDLE: ptr = &NtCurrentTeb()->Peb->ProcessParameters->hStdOutput; break; case STD_ERROR_HANDLE: ptr = &NtCurrentTeb()->Peb->ProcessParameters->hStdError; break; default: SetLastError( ERROR_INVALID_HANDLE ); return FALSE; } if (prev) *prev = *ptr; *ptr = handle; return TRUE; } /*********************************************************************** * Process environment ***********************************************************************/ static inline SIZE_T get_env_length( const WCHAR *env ) { const WCHAR *end = env; while (*end) end += lstrlenW(end) + 1; return end + 1 - env; } /*********************************************************************** * ExpandEnvironmentStringsA (kernelbase.@) */ DWORD WINAPI DECLSPEC_HOTPATCH ExpandEnvironmentStringsA( LPCSTR src, LPSTR dst, DWORD count ) { UNICODE_STRING us_src; PWSTR dstW = NULL; DWORD ret; RtlCreateUnicodeStringFromAsciiz( &us_src, src ); if (count) { if (!(dstW = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WCHAR)))) return 0; ret = ExpandEnvironmentStringsW( us_src.Buffer, dstW, count); if (ret) WideCharToMultiByte( CP_ACP, 0, dstW, ret, dst, count, NULL, NULL ); } else ret = ExpandEnvironmentStringsW( us_src.Buffer, NULL, 0 ); RtlFreeUnicodeString( &us_src ); HeapFree( GetProcessHeap(), 0, dstW ); return ret; } /*********************************************************************** * ExpandEnvironmentStringsW (kernelbase.@) */ DWORD WINAPI DECLSPEC_HOTPATCH ExpandEnvironmentStringsW( LPCWSTR src, LPWSTR dst, DWORD len ) { UNICODE_STRING us_src, us_dst; NTSTATUS status; DWORD res; TRACE( "(%s %p %u)\n", debugstr_w(src), dst, len ); RtlInitUnicodeString( &us_src, src ); /* make sure we don't overflow the maximum UNICODE_STRING size */ len = min( len, UNICODE_STRING_MAX_CHARS ); us_dst.Length = 0; us_dst.MaximumLength = len * sizeof(WCHAR); us_dst.Buffer = dst; res = 0; status = RtlExpandEnvironmentStrings_U( NULL, &us_src, &us_dst, &res ); res /= sizeof(WCHAR); if (!set_ntstatus( status )) { if (status != STATUS_BUFFER_TOO_SMALL) return 0; if (len && dst) dst[len - 1] = 0; } return res; } /*********************************************************************** * GetEnvironmentStrings (kernelbase.@) * GetEnvironmentStringsA (kernelbase.@) */ LPSTR WINAPI DECLSPEC_HOTPATCH GetEnvironmentStringsA(void) { LPWSTR env; LPSTR ret; SIZE_T lenA, lenW; RtlAcquirePebLock(); env = NtCurrentTeb()->Peb->ProcessParameters->Environment; lenW = get_env_length( env ); lenA = WideCharToMultiByte( CP_ACP, 0, env, lenW, NULL, 0, NULL, NULL ); if ((ret = HeapAlloc( GetProcessHeap(), 0, lenA ))) WideCharToMultiByte( CP_ACP, 0, env, lenW, ret, lenA, NULL, NULL ); RtlReleasePebLock(); return ret; } /*********************************************************************** * GetEnvironmentStringsW (kernelbase.@) */ LPWSTR WINAPI DECLSPEC_HOTPATCH GetEnvironmentStringsW(void) { LPWSTR ret; SIZE_T len; RtlAcquirePebLock(); len = get_env_length( NtCurrentTeb()->Peb->ProcessParameters->Environment ) * sizeof(WCHAR); if ((ret = HeapAlloc( GetProcessHeap(), 0, len ))) memcpy( ret, NtCurrentTeb()->Peb->ProcessParameters->Environment, len ); RtlReleasePebLock(); return ret; } /*********************************************************************** * GetEnvironmentVariableA (kernelbase.@) */ DWORD WINAPI DECLSPEC_HOTPATCH GetEnvironmentVariableA( LPCSTR name, LPSTR value, DWORD size ) { UNICODE_STRING us_name; PWSTR valueW; DWORD ret; /* limit the size to sane values */ size = min( size, 32767 ); if (!(valueW = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) return 0; RtlCreateUnicodeStringFromAsciiz( &us_name, name ); SetLastError( 0 ); ret = GetEnvironmentVariableW( us_name.Buffer, valueW, size); if (ret && ret < size) WideCharToMultiByte( CP_ACP, 0, valueW, ret + 1, value, size, NULL, NULL ); /* this is needed to tell, with 0 as a return value, the difference between: * - an error (GetLastError() != 0) * - returning an empty string (in this case, we need to update the buffer) */ if (ret == 0 && size && GetLastError() == 0) value[0] = 0; RtlFreeUnicodeString( &us_name ); HeapFree( GetProcessHeap(), 0, valueW ); return ret; } /*********************************************************************** * GetEnvironmentVariableW (kernelbase.@) */ DWORD WINAPI DECLSPEC_HOTPATCH GetEnvironmentVariableW( LPCWSTR name, LPWSTR val, DWORD size ) { UNICODE_STRING us_name, us_value; NTSTATUS status; DWORD len; TRACE( "(%s %p %u)\n", debugstr_w(name), val, size ); RtlInitUnicodeString( &us_name, name ); us_value.Length = 0; us_value.MaximumLength = (size ? size - 1 : 0) * sizeof(WCHAR); us_value.Buffer = val; status = RtlQueryEnvironmentVariable_U( NULL, &us_name, &us_value ); len = us_value.Length / sizeof(WCHAR); if (!set_ntstatus( status )) return (status == STATUS_BUFFER_TOO_SMALL) ? len + 1 : 0; if (size) val[len] = 0; return len; } /*********************************************************************** * FreeEnvironmentStringsA (kernelbase.@) * FreeEnvironmentStringsW (kernelbase.@) */ BOOL WINAPI DECLSPEC_HOTPATCH FreeEnvironmentStringsW( LPWSTR ptr ) { return HeapFree( GetProcessHeap(), 0, ptr ); } /*********************************************************************** * SetEnvironmentVariableA (kernelbase.@) */ BOOL WINAPI DECLSPEC_HOTPATCH SetEnvironmentVariableA( LPCSTR name, LPCSTR value ) { UNICODE_STRING us_name, us_value; BOOL ret; if (!name) { SetLastError( ERROR_ENVVAR_NOT_FOUND ); return FALSE; } RtlCreateUnicodeStringFromAsciiz( &us_name, name ); if (value) { RtlCreateUnicodeStringFromAsciiz( &us_value, value ); ret = SetEnvironmentVariableW( us_name.Buffer, us_value.Buffer ); RtlFreeUnicodeString( &us_value ); } else ret = SetEnvironmentVariableW( us_name.Buffer, NULL ); RtlFreeUnicodeString( &us_name ); return ret; } /*********************************************************************** * SetEnvironmentVariableW (kernelbase.@) */ BOOL WINAPI DECLSPEC_HOTPATCH SetEnvironmentVariableW( LPCWSTR name, LPCWSTR value ) { UNICODE_STRING us_name, us_value; NTSTATUS status; TRACE( "(%s %s)\n", debugstr_w(name), debugstr_w(value) ); if (!name) { SetLastError( ERROR_ENVVAR_NOT_FOUND ); return FALSE; } RtlInitUnicodeString( &us_name, name ); if (value) { RtlInitUnicodeString( &us_value, value ); status = RtlSetEnvironmentVariable( NULL, &us_name, &us_value ); } else status = RtlSetEnvironmentVariable( NULL, &us_name, NULL ); return set_ntstatus( status ); } /*********************************************************************** * Process/thread attribute lists ***********************************************************************/ struct proc_thread_attr { DWORD_PTR attr; SIZE_T size; void *value; }; struct _PROC_THREAD_ATTRIBUTE_LIST { DWORD mask; /* bitmask of items in list */ DWORD size; /* max number of items in list */ DWORD count; /* number of items in list */ DWORD pad; DWORD_PTR unk; struct proc_thread_attr attrs[1]; }; /*********************************************************************** * InitializeProcThreadAttributeList (kernelbase.@) */ BOOL WINAPI DECLSPEC_HOTPATCH InitializeProcThreadAttributeList( struct _PROC_THREAD_ATTRIBUTE_LIST *list, DWORD count, DWORD flags, SIZE_T *size ) { SIZE_T needed; BOOL ret = FALSE; TRACE( "(%p %d %x %p)\n", list, count, flags, size ); needed = FIELD_OFFSET( struct _PROC_THREAD_ATTRIBUTE_LIST, attrs[count] ); if (list && *size >= needed) { list->mask = 0; list->size = count; list->count = 0; list->unk = 0; ret = TRUE; } else SetLastError( ERROR_INSUFFICIENT_BUFFER ); *size = needed; return ret; } /*********************************************************************** * UpdateProcThreadAttribute (kernelbase.@) */ BOOL WINAPI DECLSPEC_HOTPATCH UpdateProcThreadAttribute( struct _PROC_THREAD_ATTRIBUTE_LIST *list, DWORD flags, DWORD_PTR attr, void *value, SIZE_T size, void *prev_ret, SIZE_T *size_ret ) { DWORD mask; struct proc_thread_attr *entry; TRACE( "(%p %x %08lx %p %ld %p %p)\n", list, flags, attr, value, size, prev_ret, size_ret ); if (list->count >= list->size) { SetLastError( ERROR_GEN_FAILURE ); return FALSE; } switch (attr) { case PROC_THREAD_ATTRIBUTE_PARENT_PROCESS: if (size != sizeof(HANDLE)) { SetLastError( ERROR_BAD_LENGTH ); return FALSE; } break; case PROC_THREAD_ATTRIBUTE_HANDLE_LIST: if ((size / sizeof(HANDLE)) * sizeof(HANDLE) != size) { SetLastError( ERROR_BAD_LENGTH ); return FALSE; } break; case PROC_THREAD_ATTRIBUTE_IDEAL_PROCESSOR: if (size != sizeof(PROCESSOR_NUMBER)) { SetLastError( ERROR_BAD_LENGTH ); return FALSE; } break; case PROC_THREAD_ATTRIBUTE_CHILD_PROCESS_POLICY: if (size != sizeof(DWORD) && size != sizeof(DWORD64)) { SetLastError( ERROR_BAD_LENGTH ); return FALSE; } break; case PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY: if (size != sizeof(DWORD) && size != sizeof(DWORD64) && size != sizeof(DWORD64) * 2) { SetLastError( ERROR_BAD_LENGTH ); return FALSE; } break; default: SetLastError( ERROR_NOT_SUPPORTED ); FIXME( "Unhandled attribute %lu\n", attr & PROC_THREAD_ATTRIBUTE_NUMBER ); return FALSE; } mask = 1 << (attr & PROC_THREAD_ATTRIBUTE_NUMBER); if (list->mask & mask) { SetLastError( ERROR_OBJECT_NAME_EXISTS ); return FALSE; } list->mask |= mask; entry = list->attrs + list->count; entry->attr = attr; entry->size = size; entry->value = value; list->count++; return TRUE; } /*********************************************************************** * DeleteProcThreadAttributeList (kernelbase.@) */ void WINAPI DECLSPEC_HOTPATCH DeleteProcThreadAttributeList( struct _PROC_THREAD_ATTRIBUTE_LIST *list ) { return; }