diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec index 5769a8b6ce1..cf2f622a77e 100644 --- a/dlls/kernel32/kernel32.spec +++ b/dlls/kernel32/kernel32.spec @@ -309,13 +309,13 @@ @ stdcall -import CreatePipe(ptr ptr ptr long) # @ stub CreatePrivateNamespaceA # @ stub CreatePrivateNamespaceW -@ stdcall CreateProcessA(str str ptr ptr long long ptr str ptr ptr) -@ stdcall CreateProcessAsUserA(long str str ptr ptr long long ptr str ptr ptr) -@ stdcall CreateProcessAsUserW(long wstr wstr ptr ptr long long ptr wstr ptr ptr) -@ stdcall CreateProcessInternalA(long str str ptr ptr long long ptr str ptr ptr ptr) -@ stdcall CreateProcessInternalW(long wstr wstr ptr ptr long long ptr wstr ptr ptr ptr) +@ stdcall -import CreateProcessA(str str ptr ptr long long ptr str ptr ptr) +@ stdcall -import CreateProcessAsUserA(long str str ptr ptr long long ptr str ptr ptr) +@ stdcall -import CreateProcessAsUserW(long wstr wstr ptr ptr long long ptr wstr ptr ptr) +@ stdcall -import CreateProcessInternalA(long str str ptr ptr long long ptr str ptr ptr ptr) +@ stdcall -import CreateProcessInternalW(long wstr wstr ptr ptr long long ptr wstr ptr ptr ptr) # @ stub CreateProcessInternalWSecure -@ stdcall CreateProcessW(wstr wstr ptr ptr long long ptr wstr ptr ptr) +@ stdcall -import CreateProcessW(wstr wstr ptr ptr long long ptr wstr ptr ptr) @ stdcall -import CreateRemoteThread(long ptr long ptr long long ptr) @ stdcall -import CreateRemoteThreadEx(long ptr long ptr ptr long ptr ptr) @ stdcall CreateSemaphoreA(ptr long long str) diff --git a/dlls/kernel32/kernel_private.h b/dlls/kernel32/kernel_private.h index af85bee84df..cd6c63efa34 100644 --- a/dlls/kernel32/kernel_private.h +++ b/dlls/kernel32/kernel_private.h @@ -59,7 +59,6 @@ extern SYSTEM_BASIC_INFORMATION system_info DECLSPEC_HIDDEN; extern const WCHAR DIR_Windows[] DECLSPEC_HIDDEN; extern const WCHAR DIR_System[] DECLSPEC_HIDDEN; -extern const WCHAR *DIR_SysWow64 DECLSPEC_HIDDEN; extern void FILE_SetDosError(void) DECLSPEC_HIDDEN; extern WCHAR *FILE_name_AtoW( LPCSTR name, BOOL alloc ) DECLSPEC_HIDDEN; diff --git a/dlls/kernel32/process.c b/dlls/kernel32/process.c index 5a07174f372..f68193c93dd 100644 --- a/dlls/kernel32/process.c +++ b/dlls/kernel32/process.c @@ -70,16 +70,12 @@ typedef struct DWORD dwReserved; } LOADPARMS32; -static BOOL is_wow64; -static const BOOL is_win64 = (sizeof(void *) > sizeof(int)); - HMODULE kernel32_handle = 0; SYSTEM_BASIC_INFORMATION system_info = { 0 }; const WCHAR DIR_Windows[] = {'C',':','\\','w','i','n','d','o','w','s',0}; const WCHAR DIR_System[] = {'C',':','\\','w','i','n','d','o','w','s', '\\','s','y','s','t','e','m','3','2',0}; -const WCHAR *DIR_SysWow64 = NULL; /* Process flags */ #define PDB32_DEBUGGED 0x0001 /* Process is being debugged */ @@ -89,38 +85,6 @@ const WCHAR *DIR_SysWow64 = NULL; #define PDB32_FILE_APIS_OEM 0x0040 /* File APIs are OEM */ #define PDB32_WIN32S_PROC 0x8000 /* Win32s process */ -static const WCHAR exeW[] = {'.','e','x','e',0}; -static const WCHAR comW[] = {'.','c','o','m',0}; -static const WCHAR batW[] = {'.','b','a','t',0}; -static const WCHAR cmdW[] = {'.','c','m','d',0}; -static const WCHAR pifW[] = {'.','p','i','f',0}; -static WCHAR winevdm[] = {'C',':','\\','w','i','n','d','o','w','s', - '\\','s','y','s','t','e','m','3','2', - '\\','w','i','n','e','v','d','m','.','e','x','e',0}; - - -/*********************************************************************** - * find_exe_file - * - * Open an exe file, and return the full name and file handle. - * Returns FALSE if file could not be found. - */ -static BOOL find_exe_file( const WCHAR *name, WCHAR *buffer, int 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, exeW, 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; -} - /*********************************************************************** * set_library_argv @@ -155,22 +119,6 @@ static void set_library_argv( WCHAR **wargv ) } -/*********************************************************************** - * init_windows_dirs - */ -static void init_windows_dirs(void) -{ - static const WCHAR default_syswow64W[] = {'C',':','\\','w','i','n','d','o','w','s', - '\\','s','y','s','w','o','w','6','4',0}; - - if (is_win64 || is_wow64) /* SysWow64 is always defined on 64-bit */ - { - DIR_SysWow64 = default_syswow64W; - memcpy( winevdm, default_syswow64W, sizeof(default_syswow64W) - sizeof(WCHAR) ); - } -} - - #ifdef __i386__ extern DWORD call_process_entry( PEB *peb, LPTHREAD_START_ROUTINE entry ); __ASM_GLOBAL_FUNC( call_process_entry, @@ -263,11 +211,9 @@ void * CDECL __wine_kernel_init(void) setbuf(stdout,NULL); setbuf(stderr,NULL); kernel32_handle = GetModuleHandleW(kernel32W); - IsWow64Process( GetCurrentProcess(), &is_wow64 ); RtlSetUnhandledExceptionFilter( UnhandledExceptionFilter ); LOCALE_Init(); - init_windows_dirs(); convert_old_config(); set_library_argv( __wine_main_wargv ); @@ -277,474 +223,6 @@ void * CDECL __wine_kernel_init(void) } -/*********************************************************************** - * create_process_params - */ -static RTL_USER_PROCESS_PARAMETERS *create_process_params( LPCWSTR filename, LPCWSTR cmdline, - LPCWSTR 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 = HeapAlloc( 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) HeapFree( GetProcessHeap(), 0, envW ); - return NULL; - } - RtlReleasePath( load_path ); - - if (flags & CREATE_NEW_PROCESS_GROUP) params->ConsoleFlags = 1; - if (flags & CREATE_NEW_CONSOLE) params->ConsoleHandle = 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) HeapFree( GetProcessHeap(), 0, envW ); - return params; -} - -/*********************************************************************** - * create_nt_process - */ -static NTSTATUS create_nt_process( LPSECURITY_ATTRIBUTES psa, LPSECURITY_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 - * - * Create a new VDM process for a 16-bit or DOS application. - */ -static NTSTATUS create_vdm_process( LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES tsa, - BOOL inherit, DWORD flags, RTL_USER_PROCESS_PARAMETERS *params, - RTL_USER_PROCESS_INFORMATION *info ) -{ - static const WCHAR argsW[] = {'%','s',' ','-','-','a','p','p','-','n','a','m','e',' ','"','%','s','"',' ','%','s',0}; - - NTSTATUS status; - WCHAR *new_cmd_line; - - new_cmd_line = HeapAlloc(GetProcessHeap(), 0, - (strlenW(params->ImagePathName.Buffer) + - strlenW(params->CommandLine.Buffer) + - strlenW(winevdm) + 16) * sizeof(WCHAR)); - if (!new_cmd_line) return STATUS_NO_MEMORY; - - sprintfW( new_cmd_line, argsW, winevdm, params->ImagePathName.Buffer, params->CommandLine.Buffer ); - RtlInitUnicodeString( ¶ms->ImagePathName, winevdm ); - RtlInitUnicodeString( ¶ms->CommandLine, new_cmd_line ); - status = create_nt_process( psa, tsa, inherit, flags, params, info ); - HeapFree( GetProcessHeap(), 0, new_cmd_line ); - return status; -} - - -/*********************************************************************** - * create_cmd_process - * - * Create a new cmd shell process for a .BAT file. - */ -static NTSTATUS create_cmd_process( LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES tsa, - BOOL inherit, DWORD flags, RTL_USER_PROCESS_PARAMETERS *params, - RTL_USER_PROCESS_INFORMATION *info ) -{ - static const WCHAR argsW[] = {'%','s',' ','/','s','/','c',' ','"','%','s','"',0}; - static const WCHAR comspecW[] = {'C','O','M','S','P','E','C',0}; - static const WCHAR cmdW[] = {'\\','c','m','d','.','e','x','e',0}; - WCHAR comspec[MAX_PATH]; - WCHAR *newcmdline; - NTSTATUS status; - - if (!GetEnvironmentVariableW( comspecW, comspec, ARRAY_SIZE( comspec ))) - { - GetSystemDirectoryW( comspec, ARRAY_SIZE( comspec ) - ARRAY_SIZE( cmdW )); - strcatW( comspec, cmdW ); - } - if (!(newcmdline = HeapAlloc( GetProcessHeap(), 0, - (strlenW(comspec) + 7 + - strlenW(params->CommandLine.Buffer) + 2) * sizeof(WCHAR)))) - return STATUS_NO_MEMORY; - - sprintfW( newcmdline, argsW, comspec, params->CommandLine.Buffer ); - RtlInitUnicodeString( ¶ms->ImagePathName, comspec ); - RtlInitUnicodeString( ¶ms->CommandLine, newcmdline ); - status = create_nt_process( psa, tsa, inherit, flags, params, info ); - HeapFree( GetProcessHeap(), 0, newcmdline ); - return status; -} - - -/************************************************************************* - * 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 LPWSTR get_file_name( LPWSTR cmdline, LPWSTR buffer, int buflen ) -{ - WCHAR *name, *pos, *first_space, *ret = NULL; - const WCHAR *p; - - /* first check for a quoted file name */ - - if ((cmdline[0] == '"') && ((p = strchrW( cmdline + 1, '"' )))) - { - int len = p - cmdline - 1; - /* extract the quoted portion as file name */ - if (!(name = HeapAlloc( 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 = HeapAlloc( GetProcessHeap(), 0, (strlenW(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 */ - { - static const WCHAR quotesW[] = {'"','%','s','"','%','s',0}; - - if (!(ret = HeapAlloc( GetProcessHeap(), 0, (strlenW(cmdline) + 3) * sizeof(WCHAR) ))) - goto done; - sprintfW( ret, quotesW, name, p ); - } - - done: - HeapFree( GetProcessHeap(), 0, name ); - return ret; -} - -/********************************************************************** - * CreateProcessInternalW (KERNEL32.@) - */ -BOOL WINAPI CreateProcessInternalW( HANDLE token, LPCWSTR app_name, LPWSTR cmd_line, - LPSECURITY_ATTRIBUTES process_attr, LPSECURITY_ATTRIBUTES thread_attr, - BOOL inherit, DWORD flags, LPVOID env, LPCWSTR cur_dir, - LPSTARTUPINFOW startup_info, LPPROCESS_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 */ - { - static const WCHAR quotesW[] = {'"','%','s','"',0}; - if (!(tidy_cmdline = HeapAlloc( GetProcessHeap(), 0, (strlenW(app_name)+3) * sizeof(WCHAR) ))) - return FALSE; - sprintfW( tidy_cmdline, quotesW, 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 = strrchrW( app_name, '.' ))) break; - if (!strcmpiW( p, comW ) || !strcmpiW( p, pifW )) - { - 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 (!strcmpiW( p, batW ) || !strcmpiW( p, cmdW )) - { - 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 ); -} - - -/********************************************************************** - * CreateProcessInternalA (KERNEL32.@) - */ -BOOL WINAPI CreateProcessInternalA( HANDLE token, LPCSTR app_name, LPSTR cmd_line, - LPSECURITY_ATTRIBUTES process_attr, LPSECURITY_ATTRIBUTES thread_attr, - BOOL inherit, DWORD flags, LPVOID env, LPCSTR cur_dir, - LPSTARTUPINFOA startup_info, LPPROCESS_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; - - if (startup_info->lpReserved) - FIXME("StartupInfo.lpReserved is used, please report (%s)\n", - debugstr_a(startup_info->lpReserved)); - - ret = CreateProcessInternalW( token, app_nameW, cmd_lineW, process_attr, thread_attr, - inherit, flags, env, cur_dirW, &infoW, info, new_token ); -done: - HeapFree( GetProcessHeap(), 0, app_nameW ); - HeapFree( GetProcessHeap(), 0, cmd_lineW ); - HeapFree( GetProcessHeap(), 0, cur_dirW ); - RtlFreeUnicodeString( &desktopW ); - RtlFreeUnicodeString( &titleW ); - return ret; -} - - -/********************************************************************** - * CreateProcessA (KERNEL32.@) - */ -BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessA( LPCSTR app_name, LPSTR cmd_line, LPSECURITY_ATTRIBUTES process_attr, - LPSECURITY_ATTRIBUTES thread_attr, BOOL inherit, - DWORD flags, LPVOID env, LPCSTR cur_dir, - LPSTARTUPINFOA startup_info, LPPROCESS_INFORMATION info ) -{ - return CreateProcessInternalA( NULL, app_name, cmd_line, process_attr, thread_attr, - inherit, flags, env, cur_dir, startup_info, info, NULL ); -} - - -/********************************************************************** - * CreateProcessW (KERNEL32.@) - */ -BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessW( LPCWSTR app_name, LPWSTR cmd_line, LPSECURITY_ATTRIBUTES process_attr, - LPSECURITY_ATTRIBUTES thread_attr, BOOL inherit, DWORD flags, - LPVOID env, LPCWSTR cur_dir, LPSTARTUPINFOW startup_info, - LPPROCESS_INFORMATION info ) -{ - return CreateProcessInternalW( NULL, app_name, cmd_line, process_attr, thread_attr, - inherit, flags, env, cur_dir, startup_info, info, NULL ); -} - - -/********************************************************************** - * CreateProcessAsUserA (KERNEL32.@) - */ -BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessAsUserA( HANDLE token, LPCSTR app_name, LPSTR cmd_line, - LPSECURITY_ATTRIBUTES process_attr, - LPSECURITY_ATTRIBUTES thread_attr, - BOOL inherit, DWORD flags, LPVOID env, LPCSTR cur_dir, - LPSTARTUPINFOA startup_info, - LPPROCESS_INFORMATION info ) -{ - return CreateProcessInternalA( token, app_name, cmd_line, process_attr, thread_attr, - inherit, flags, env, cur_dir, startup_info, info, NULL ); -} - - -/********************************************************************** - * CreateProcessAsUserW (KERNEL32.@) - */ -BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessAsUserW( HANDLE token, LPCWSTR app_name, LPWSTR cmd_line, - LPSECURITY_ATTRIBUTES process_attr, - LPSECURITY_ATTRIBUTES thread_attr, - BOOL inherit, DWORD flags, LPVOID env, LPCWSTR cur_dir, - LPSTARTUPINFOW startup_info, - LPPROCESS_INFORMATION info ) -{ - return CreateProcessInternalW( token, app_name, cmd_line, process_attr, thread_attr, - inherit, flags, env, cur_dir, startup_info, info, NULL ); -} - - /*********************************************************************** * wait_input_idle * diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec index a0e90f706be..7c5ae99a790 100644 --- a/dlls/kernelbase/kernelbase.spec +++ b/dlls/kernelbase/kernelbase.spec @@ -205,12 +205,12 @@ @ stdcall CreatePrivateObjectSecurity(ptr ptr ptr long long ptr) @ stdcall CreatePrivateObjectSecurityEx(ptr ptr ptr ptr long long long ptr) @ stdcall CreatePrivateObjectSecurityWithMultipleInheritance(ptr ptr ptr ptr long long long long ptr) -@ stdcall CreateProcessA(str str ptr ptr long long ptr str ptr ptr) kernel32.CreateProcessA -@ stdcall CreateProcessAsUserA(long str str ptr ptr long long ptr str ptr ptr) kernel32.CreateProcessAsUserA -@ stdcall CreateProcessAsUserW(long wstr wstr ptr ptr long long ptr wstr ptr ptr) kernel32.CreateProcessAsUserW -@ stdcall CreateProcessInternalA(long str str ptr ptr long long ptr str ptr ptr ptr) kernel32.CreateProcessInternalA -@ stdcall CreateProcessInternalW(long wstr wstr ptr ptr long long ptr wstr ptr ptr ptr) kernel32.CreateProcessInternalW -@ stdcall CreateProcessW(wstr wstr ptr ptr long long ptr wstr ptr ptr) kernel32.CreateProcessW +@ stdcall CreateProcessA(str str ptr ptr long long ptr str ptr ptr) +@ stdcall CreateProcessAsUserA(long str str ptr ptr long long ptr str ptr ptr) +@ stdcall CreateProcessAsUserW(long wstr wstr ptr ptr long long ptr wstr ptr ptr) +@ stdcall CreateProcessInternalA(long str str ptr ptr long long ptr str ptr ptr ptr) +@ stdcall CreateProcessInternalW(long wstr wstr ptr ptr long long ptr wstr ptr ptr ptr) +@ stdcall CreateProcessW(wstr wstr ptr ptr long long ptr wstr ptr ptr) @ stdcall CreateRemoteThread(long ptr long ptr long long ptr) @ stdcall CreateRemoteThreadEx(long ptr long ptr ptr long ptr ptr) @ stdcall CreateRestrictedToken(long long long ptr long ptr long ptr ptr) diff --git a/dlls/kernelbase/process.c b/dlls/kernelbase/process.c index 11d515d4fb6..51b75470c8f 100644 --- a/dlls/kernelbase/process.c +++ b/dlls/kernelbase/process.c @@ -42,6 +42,279 @@ static DWORD shutdown_priority = 0x280; ***********************************************************************/ +/*********************************************************************** + * 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.@) */ @@ -59,6 +332,212 @@ BOOL WINAPI DECLSPEC_HOTPATCH CloseHandle( HANDLE 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.@) */