kernel32: Separate the exec process functionality.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
bff3255703
commit
7e96514029
|
@ -2033,11 +2033,11 @@ static BOOL terminate_main_thread(void)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* exec_loader
|
* spawn_loader
|
||||||
*/
|
*/
|
||||||
static pid_t exec_loader( const RTL_USER_PROCESS_PARAMETERS *params, unsigned int flags, int socketfd,
|
static pid_t spawn_loader( const RTL_USER_PROCESS_PARAMETERS *params, unsigned int flags, int socketfd,
|
||||||
int stdin_fd, int stdout_fd, const char *unixdir, char *winedebug,
|
int stdin_fd, int stdout_fd, const char *unixdir, char *winedebug,
|
||||||
const pe_image_info_t *pe_info, int exec_only )
|
const pe_image_info_t *pe_info )
|
||||||
{
|
{
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
char *wineloader = NULL;
|
char *wineloader = NULL;
|
||||||
|
@ -2049,9 +2049,9 @@ static pid_t exec_loader( const RTL_USER_PROCESS_PARAMETERS *params, unsigned in
|
||||||
if (!is_win64 ^ !is_64bit_arch( pe_info->cpu ))
|
if (!is_win64 ^ !is_64bit_arch( pe_info->cpu ))
|
||||||
loader = get_alternate_loader( &wineloader );
|
loader = get_alternate_loader( &wineloader );
|
||||||
|
|
||||||
if (exec_only || !(pid = fork())) /* child */
|
if (!(pid = fork())) /* child */
|
||||||
{
|
{
|
||||||
if (exec_only || !(pid = fork())) /* grandchild */
|
if (!(pid = fork())) /* grandchild */
|
||||||
{
|
{
|
||||||
char preloader_reserve[64], socket_env[64];
|
char preloader_reserve[64], socket_env[64];
|
||||||
ULONGLONG res_start = pe_info->base;
|
ULONGLONG res_start = pe_info->base;
|
||||||
|
@ -2091,18 +2091,7 @@ static pid_t exec_loader( const RTL_USER_PROCESS_PARAMETERS *params, unsigned in
|
||||||
if (wineloader) putenv( wineloader );
|
if (wineloader) putenv( wineloader );
|
||||||
if (unixdir) chdir(unixdir);
|
if (unixdir) chdir(unixdir);
|
||||||
|
|
||||||
if (argv)
|
if (argv) wine_exec_wine_binary( loader, argv, getenv("WINELOADER") );
|
||||||
{
|
|
||||||
do
|
|
||||||
{
|
|
||||||
wine_exec_wine_binary( loader, argv, getenv("WINELOADER") );
|
|
||||||
}
|
|
||||||
#ifdef __APPLE__
|
|
||||||
while (errno == ENOTSUP && exec_only && terminate_main_thread());
|
|
||||||
#else
|
|
||||||
while (0);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
_exit(1);
|
_exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2123,6 +2112,50 @@ static pid_t exec_loader( const RTL_USER_PROCESS_PARAMETERS *params, unsigned in
|
||||||
return pid;
|
return pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* exec_loader
|
||||||
|
*/
|
||||||
|
static NTSTATUS exec_loader( const RTL_USER_PROCESS_PARAMETERS *params, int socketfd,
|
||||||
|
const pe_image_info_t *pe_info )
|
||||||
|
{
|
||||||
|
char *wineloader = NULL;
|
||||||
|
const char *loader = NULL;
|
||||||
|
char **argv;
|
||||||
|
char preloader_reserve[64], socket_env[64];
|
||||||
|
ULONGLONG res_start = pe_info->base;
|
||||||
|
ULONGLONG res_end = pe_info->base + pe_info->map_size;
|
||||||
|
|
||||||
|
if (!(argv = build_argv( params->CommandLine.Buffer, 1 ))) return STATUS_NO_MEMORY;
|
||||||
|
|
||||||
|
if (!is_win64 ^ !is_64bit_arch( pe_info->cpu ))
|
||||||
|
loader = get_alternate_loader( &wineloader );
|
||||||
|
|
||||||
|
/* Reset signals that we previously set to SIG_IGN */
|
||||||
|
signal( SIGPIPE, SIG_DFL );
|
||||||
|
|
||||||
|
sprintf( socket_env, "WINESERVERSOCKET=%u", socketfd );
|
||||||
|
sprintf( preloader_reserve, "WINEPRELOADRESERVE=%x%08x-%x%08x",
|
||||||
|
(ULONG)(res_start >> 32), (ULONG)res_start, (ULONG)(res_end >> 32), (ULONG)res_end );
|
||||||
|
|
||||||
|
putenv( preloader_reserve );
|
||||||
|
putenv( socket_env );
|
||||||
|
if (wineloader) putenv( wineloader );
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
wine_exec_wine_binary( loader, argv, getenv("WINELOADER") );
|
||||||
|
}
|
||||||
|
#ifdef __APPLE__
|
||||||
|
while (errno == ENOTSUP && exec_only && terminate_main_thread());
|
||||||
|
#else
|
||||||
|
while (0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
HeapFree( GetProcessHeap(), 0, wineloader );
|
||||||
|
HeapFree( GetProcessHeap(), 0, argv );
|
||||||
|
return STATUS_INVALID_IMAGE_FORMAT;
|
||||||
|
}
|
||||||
|
|
||||||
/* creates a struct security_descriptor and contained information in one contiguous piece of memory */
|
/* creates a struct security_descriptor and contained information in one contiguous piece of memory */
|
||||||
static NTSTATUS alloc_object_attributes( const SECURITY_ATTRIBUTES *attr, struct object_attributes **ret,
|
static NTSTATUS alloc_object_attributes( const SECURITY_ATTRIBUTES *attr, struct object_attributes **ret,
|
||||||
data_size_t *ret_len )
|
data_size_t *ret_len )
|
||||||
|
@ -2185,6 +2218,61 @@ static NTSTATUS alloc_object_attributes( const SECURITY_ATTRIBUTES *attr, struct
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* replace_process
|
||||||
|
*
|
||||||
|
* Replace the existing process by exec'ing a new one.
|
||||||
|
*/
|
||||||
|
static BOOL replace_process( HANDLE handle, const RTL_USER_PROCESS_PARAMETERS *params,
|
||||||
|
const pe_image_info_t *pe_info )
|
||||||
|
{
|
||||||
|
NTSTATUS status;
|
||||||
|
int socketfd[2];
|
||||||
|
|
||||||
|
if (socketpair( PF_UNIX, SOCK_STREAM, 0, socketfd ) == -1)
|
||||||
|
{
|
||||||
|
SetLastError( ERROR_TOO_MANY_OPEN_FILES );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
#ifdef SO_PASSCRED
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int enable = 1;
|
||||||
|
setsockopt( socketfd[0], SOL_SOCKET, SO_PASSCRED, &enable, sizeof(enable) );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
wine_server_send_fd( socketfd[1] );
|
||||||
|
close( socketfd[1] );
|
||||||
|
|
||||||
|
SERVER_START_REQ( exec_process )
|
||||||
|
{
|
||||||
|
req->socket_fd = socketfd[1];
|
||||||
|
req->exe_file = wine_server_obj_handle( handle );
|
||||||
|
req->cpu = pe_info->cpu;
|
||||||
|
status = wine_server_call( req );
|
||||||
|
}
|
||||||
|
SERVER_END_REQ;
|
||||||
|
|
||||||
|
switch (status)
|
||||||
|
{
|
||||||
|
case STATUS_INVALID_IMAGE_WIN_64:
|
||||||
|
ERR( "64-bit application %s not supported in 32-bit prefix\n",
|
||||||
|
debugstr_w( params->ImagePathName.Buffer ));
|
||||||
|
break;
|
||||||
|
case STATUS_INVALID_IMAGE_FORMAT:
|
||||||
|
ERR( "%s not supported on this installation (%s binary)\n",
|
||||||
|
debugstr_w( params->ImagePathName.Buffer ), cpu_names[pe_info->cpu] );
|
||||||
|
break;
|
||||||
|
case STATUS_SUCCESS:
|
||||||
|
status = exec_loader( params, socketfd[0], pe_info );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
close( socketfd[0] );
|
||||||
|
SetLastError( RtlNtStatusToDosError( status ));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* create_process
|
* create_process
|
||||||
*
|
*
|
||||||
|
@ -2193,8 +2281,7 @@ static NTSTATUS alloc_object_attributes( const SECURITY_ATTRIBUTES *attr, struct
|
||||||
*/
|
*/
|
||||||
static BOOL create_process( HANDLE hFile, LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES tsa,
|
static BOOL create_process( HANDLE hFile, LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES tsa,
|
||||||
BOOL inherit, DWORD flags, const RTL_USER_PROCESS_PARAMETERS *params,
|
BOOL inherit, DWORD flags, const RTL_USER_PROCESS_PARAMETERS *params,
|
||||||
LPPROCESS_INFORMATION info, LPCSTR unixdir,
|
LPPROCESS_INFORMATION info, LPCSTR unixdir, const pe_image_info_t *pe_info )
|
||||||
const pe_image_info_t *pe_info, int exec_only )
|
|
||||||
{
|
{
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
BOOL success = FALSE;
|
BOOL success = FALSE;
|
||||||
|
@ -2224,38 +2311,6 @@ static BOOL create_process( HANDLE hFile, LPSECURITY_ATTRIBUTES psa, LPSECURITY_
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (exec_only) /* things are much simpler in this case */
|
|
||||||
{
|
|
||||||
wine_server_send_fd( socketfd[1] );
|
|
||||||
close( socketfd[1] );
|
|
||||||
SERVER_START_REQ( exec_process )
|
|
||||||
{
|
|
||||||
req->socket_fd = socketfd[1];
|
|
||||||
req->exe_file = wine_server_obj_handle( hFile );
|
|
||||||
req->cpu = pe_info->cpu;
|
|
||||||
status = wine_server_call( req );
|
|
||||||
}
|
|
||||||
SERVER_END_REQ;
|
|
||||||
|
|
||||||
switch (status)
|
|
||||||
{
|
|
||||||
case STATUS_INVALID_IMAGE_WIN_64:
|
|
||||||
ERR( "64-bit application %s not supported in 32-bit prefix\n",
|
|
||||||
debugstr_w( params->ImagePathName.Buffer ));
|
|
||||||
break;
|
|
||||||
case STATUS_INVALID_IMAGE_FORMAT:
|
|
||||||
ERR( "%s not supported on this installation (%s binary)\n",
|
|
||||||
debugstr_w( params->ImagePathName.Buffer ), cpu_names[pe_info->cpu] );
|
|
||||||
break;
|
|
||||||
case STATUS_SUCCESS:
|
|
||||||
exec_loader( params, flags, socketfd[0], stdin_fd, stdout_fd, unixdir,
|
|
||||||
winedebug, pe_info, TRUE );
|
|
||||||
}
|
|
||||||
close( socketfd[0] );
|
|
||||||
SetLastError( RtlNtStatusToDosError( status ));
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(startup_info = create_startup_info( params, &startup_info_size )))
|
if (!(startup_info = create_startup_info( params, &startup_info_size )))
|
||||||
{
|
{
|
||||||
close( socketfd[0] );
|
close( socketfd[0] );
|
||||||
|
@ -2359,8 +2414,7 @@ static BOOL create_process( HANDLE hFile, LPSECURITY_ATTRIBUTES psa, LPSECURITY_
|
||||||
|
|
||||||
/* create the child process */
|
/* create the child process */
|
||||||
|
|
||||||
pid = exec_loader( params, flags, socketfd[0], stdin_fd, stdout_fd, unixdir,
|
pid = spawn_loader( params, flags, socketfd[0], stdin_fd, stdout_fd, unixdir, winedebug, pe_info );
|
||||||
winedebug, pe_info, FALSE );
|
|
||||||
|
|
||||||
if (stdin_fd != -1) close( stdin_fd );
|
if (stdin_fd != -1) close( stdin_fd );
|
||||||
if (stdout_fd != -1) close( stdout_fd );
|
if (stdout_fd != -1) close( stdout_fd );
|
||||||
|
@ -2403,19 +2457,16 @@ error:
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* create_vdm_process
|
* get_vdm_params
|
||||||
*
|
*
|
||||||
* Create a new VDM process for a 16-bit or DOS application.
|
* Build the parameters needed to launch a new VDM process.
|
||||||
*/
|
*/
|
||||||
static BOOL create_vdm_process( LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES tsa,
|
static RTL_USER_PROCESS_PARAMETERS *get_vdm_params( const RTL_USER_PROCESS_PARAMETERS *params,
|
||||||
BOOL inherit, DWORD flags, const RTL_USER_PROCESS_PARAMETERS *params,
|
pe_image_info_t *pe_info )
|
||||||
LPPROCESS_INFORMATION info, LPCSTR unixdir, int exec_only )
|
|
||||||
{
|
{
|
||||||
static const WCHAR argsW[] = {'%','s',' ','-','-','a','p','p','-','n','a','m','e',' ','"','%','s','"',' ','%','s',0};
|
static const WCHAR argsW[] = {'%','s',' ','-','-','a','p','p','-','n','a','m','e',' ','"','%','s','"',' ','%','s',0};
|
||||||
|
|
||||||
BOOL ret;
|
WCHAR *new_cmd_line;
|
||||||
LPWSTR new_cmd_line;
|
|
||||||
pe_image_info_t pe_info;
|
|
||||||
RTL_USER_PROCESS_PARAMETERS *new_params;
|
RTL_USER_PROCESS_PARAMETERS *new_params;
|
||||||
UNICODE_STRING imageW, cmdlineW;
|
UNICODE_STRING imageW, cmdlineW;
|
||||||
|
|
||||||
|
@ -2426,7 +2477,7 @@ static BOOL create_vdm_process( LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES
|
||||||
if (!new_cmd_line)
|
if (!new_cmd_line)
|
||||||
{
|
{
|
||||||
SetLastError( ERROR_OUTOFMEMORY );
|
SetLastError( ERROR_OUTOFMEMORY );
|
||||||
return FALSE;
|
return NULL;
|
||||||
}
|
}
|
||||||
sprintfW( new_cmd_line, argsW, winevdm, params->ImagePathName.Buffer, params->CommandLine.Buffer );
|
sprintfW( new_cmd_line, argsW, winevdm, params->ImagePathName.Buffer, params->CommandLine.Buffer );
|
||||||
RtlInitUnicodeString( &imageW, winevdm );
|
RtlInitUnicodeString( &imageW, winevdm );
|
||||||
|
@ -2454,11 +2505,29 @@ static BOOL create_vdm_process( LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES
|
||||||
new_params->dwFlags = params->dwFlags;
|
new_params->dwFlags = params->dwFlags;
|
||||||
new_params->wShowWindow = params->wShowWindow;
|
new_params->wShowWindow = params->wShowWindow;
|
||||||
|
|
||||||
memset( &pe_info, 0, sizeof(pe_info) );
|
memset( pe_info, 0, sizeof(*pe_info) );
|
||||||
pe_info.cpu = CPU_x86;
|
pe_info->cpu = CPU_x86;
|
||||||
ret = create_process( 0, psa, tsa, inherit, flags, new_params, info, unixdir, &pe_info, exec_only );
|
return new_params;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* create_vdm_process
|
||||||
|
*
|
||||||
|
* Create a new VDM process for a 16-bit or DOS application.
|
||||||
|
*/
|
||||||
|
static BOOL create_vdm_process( LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES tsa,
|
||||||
|
BOOL inherit, DWORD flags, const RTL_USER_PROCESS_PARAMETERS *params,
|
||||||
|
LPPROCESS_INFORMATION info, LPCSTR unixdir )
|
||||||
|
{
|
||||||
|
BOOL ret;
|
||||||
|
pe_image_info_t pe_info;
|
||||||
|
RTL_USER_PROCESS_PARAMETERS *new_params;
|
||||||
|
|
||||||
|
if (!(new_params = get_vdm_params( params, &pe_info ))) return FALSE;
|
||||||
|
|
||||||
|
ret = create_process( 0, psa, tsa, inherit, flags, new_params, info, unixdir, &pe_info );
|
||||||
RtlDestroyProcessParameters( new_params );
|
RtlDestroyProcessParameters( new_params );
|
||||||
HeapFree( GetProcessHeap(), 0, new_cmd_line );
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2678,18 +2747,17 @@ static BOOL create_process_impl( LPCWSTR app_name, LPWSTR cmd_line, LPSECURITY_A
|
||||||
wine_dbgstr_longlong(pe_info.base), wine_dbgstr_longlong(pe_info.base + pe_info.map_size),
|
wine_dbgstr_longlong(pe_info.base), wine_dbgstr_longlong(pe_info.base + pe_info.map_size),
|
||||||
cpu_names[pe_info.cpu] );
|
cpu_names[pe_info.cpu] );
|
||||||
retv = create_process( hFile, process_attr, thread_attr,
|
retv = create_process( hFile, process_attr, thread_attr,
|
||||||
inherit, flags, params, info, unixdir, &pe_info, FALSE );
|
inherit, flags, params, info, unixdir, &pe_info );
|
||||||
break;
|
break;
|
||||||
case BINARY_WIN16:
|
case BINARY_WIN16:
|
||||||
TRACE( "starting %s as Win16/DOS binary\n", debugstr_w(name) );
|
TRACE( "starting %s as Win16/DOS binary\n", debugstr_w(name) );
|
||||||
retv = create_vdm_process( process_attr, thread_attr,
|
retv = create_vdm_process( process_attr, thread_attr, inherit, flags, params, info, unixdir );
|
||||||
inherit, flags, params, info, unixdir, FALSE );
|
|
||||||
break;
|
break;
|
||||||
case BINARY_UNIX_LIB:
|
case BINARY_UNIX_LIB:
|
||||||
TRACE( "starting %s as %d-bit Winelib app\n",
|
TRACE( "starting %s as %d-bit Winelib app\n",
|
||||||
debugstr_w(name), is_64bit_arch(pe_info.cpu) ? 64 : 32 );
|
debugstr_w(name), is_64bit_arch(pe_info.cpu) ? 64 : 32 );
|
||||||
retv = create_process( hFile, process_attr, thread_attr,
|
retv = create_process( hFile, process_attr, thread_attr,
|
||||||
inherit, flags, params, info, unixdir, &pe_info, FALSE );
|
inherit, flags, params, info, unixdir, &pe_info );
|
||||||
break;
|
break;
|
||||||
case BINARY_UNKNOWN:
|
case BINARY_UNKNOWN:
|
||||||
/* check for .com or .bat extension */
|
/* check for .com or .bat extension */
|
||||||
|
@ -2699,7 +2767,7 @@ static BOOL create_process_impl( LPCWSTR app_name, LPWSTR cmd_line, LPSECURITY_A
|
||||||
{
|
{
|
||||||
TRACE( "starting %s as DOS binary\n", debugstr_w(name) );
|
TRACE( "starting %s as DOS binary\n", debugstr_w(name) );
|
||||||
retv = create_vdm_process( process_attr, thread_attr,
|
retv = create_vdm_process( process_attr, thread_attr,
|
||||||
inherit, flags, params, info, unixdir, FALSE );
|
inherit, flags, params, info, unixdir );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!strcmpiW( p, batW ) || !strcmpiW( p, cmdW ) )
|
if (!strcmpiW( p, batW ) || !strcmpiW( p, cmdW ) )
|
||||||
|
@ -2792,8 +2860,7 @@ static void exec_process( LPCWSTR name )
|
||||||
HANDLE hFile;
|
HANDLE hFile;
|
||||||
WCHAR *p;
|
WCHAR *p;
|
||||||
STARTUPINFOW startup_info = { sizeof(startup_info) };
|
STARTUPINFOW startup_info = { sizeof(startup_info) };
|
||||||
RTL_USER_PROCESS_PARAMETERS *params;
|
RTL_USER_PROCESS_PARAMETERS *params, *new_params;
|
||||||
PROCESS_INFORMATION info;
|
|
||||||
pe_image_info_t pe_info;
|
pe_image_info_t pe_info;
|
||||||
BOOL is_64bit;
|
BOOL is_64bit;
|
||||||
|
|
||||||
|
@ -2813,11 +2880,11 @@ static void exec_process( LPCWSTR name )
|
||||||
debugstr_w(name), is_64bit_arch(pe_info.cpu) ? 64 : 32,
|
debugstr_w(name), is_64bit_arch(pe_info.cpu) ? 64 : 32,
|
||||||
wine_dbgstr_longlong(pe_info.base), wine_dbgstr_longlong(pe_info.base + pe_info.map_size),
|
wine_dbgstr_longlong(pe_info.base), wine_dbgstr_longlong(pe_info.base + pe_info.map_size),
|
||||||
cpu_names[pe_info.cpu] );
|
cpu_names[pe_info.cpu] );
|
||||||
create_process( hFile, NULL, NULL, FALSE, 0, params, &info, NULL, &pe_info, TRUE );
|
replace_process( hFile, params, &pe_info );
|
||||||
break;
|
break;
|
||||||
case BINARY_UNIX_LIB:
|
case BINARY_UNIX_LIB:
|
||||||
TRACE( "%s is a Unix library, starting as Winelib app\n", debugstr_w(name) );
|
TRACE( "%s is a Unix library, starting as Winelib app\n", debugstr_w(name) );
|
||||||
create_process( hFile, NULL, NULL, FALSE, 0, params, &info, NULL, &pe_info, TRUE );
|
replace_process( hFile, params, &pe_info );
|
||||||
break;
|
break;
|
||||||
case BINARY_UNKNOWN:
|
case BINARY_UNKNOWN:
|
||||||
/* check for .com or .pif extension */
|
/* check for .com or .pif extension */
|
||||||
|
@ -2826,12 +2893,15 @@ static void exec_process( LPCWSTR name )
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case BINARY_WIN16:
|
case BINARY_WIN16:
|
||||||
TRACE( "starting %s as Win16/DOS binary\n", debugstr_w(name) );
|
TRACE( "starting %s as Win16/DOS binary\n", debugstr_w(name) );
|
||||||
create_vdm_process( NULL, NULL, FALSE, 0, params, &info, NULL, TRUE );
|
if (!(new_params = get_vdm_params( params, &pe_info ))) break;
|
||||||
|
replace_process( 0, new_params, &pe_info );
|
||||||
|
RtlDestroyProcessParameters( new_params );
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
CloseHandle( hFile );
|
CloseHandle( hFile );
|
||||||
|
RtlDestroyProcessParameters( params );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue