mirror of
git://source.winehq.org/git/wine.git
synced 2024-10-14 20:07:17 +00:00
kernel32: Move CreateProcess() functions to kernelbase.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
4405195b3c
commit
712ae337fe
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
*
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.@)
|
||||
*/
|
||||
|
|
Loading…
Reference in a new issue