kernel: Added support for exec'ing a new Win32 process.

Use it to restart execution if the main binary can't be loaded because
of address space conflicts, and also for Win16/DOS support.
This commit is contained in:
Alexandre Julliard 2006-07-19 14:12:58 +02:00
parent c316f0e47f
commit 2cb0f43224
2 changed files with 82 additions and 51 deletions

View File

@ -93,6 +93,8 @@ static const WCHAR batW[] = {'.','b','a','t',0};
static const WCHAR pifW[] = {'.','p','i','f',0};
static const WCHAR winevdmW[] = {'w','i','n','e','v','d','m','.','e','x','e',0};
static void exec_process( LPCWSTR name );
extern void SHELL_LoadRegistry(void);
@ -880,16 +882,14 @@ void __wine_kernel_init(void)
{
static const WCHAR dotW[] = {'.',0};
static const WCHAR exeW[] = {'.','e','x','e',0};
static char winevdm[] = "winevdm.exe";
WCHAR *p, main_exe_name[MAX_PATH];
HMODULE module;
DWORD type, error = 0;
WCHAR *p, main_exe_name[MAX_PATH+1];
PEB *peb = NtCurrentTeb()->Peb;
char *new_argv0 = NULL;
/* Initialize everything */
if (!process_init()) exit(1);
set_process_name( &__wine_main_argc, __wine_main_argv, NULL );
set_library_wargv( __wine_main_argv );
if (peb->ProcessParameters->ImagePathName.Buffer)
{
@ -897,15 +897,13 @@ void __wine_kernel_init(void)
}
else
{
WCHAR exe_nameW[MAX_PATH];
MultiByteToWideChar( CP_UNIXCP, 0, __wine_main_argv[1], -1, exe_nameW, MAX_PATH );
if (!SearchPathW( NULL, exe_nameW, exeW, MAX_PATH, main_exe_name, NULL ) &&
!get_builtin_path( exe_nameW, exeW, main_exe_name, MAX_PATH ))
if (!SearchPathW( NULL, __wine_main_wargv[0], exeW, MAX_PATH, main_exe_name, NULL ) &&
!get_builtin_path( __wine_main_wargv[0], exeW, main_exe_name, MAX_PATH ))
{
MESSAGE( "wine: cannot find '%s'\n", __wine_main_argv[1] );
MESSAGE( "wine: cannot find '%s'\n", __wine_main_argv[0] );
ExitProcess( GetLastError() );
}
if (!build_command_line( __wine_main_wargv )) goto error;
}
/* if there's no extension, append a dot to prevent LoadLibrary from appending .dll */
@ -913,42 +911,28 @@ void __wine_kernel_init(void)
if (!p || strchrW( p, '/' ) || strchrW( p, '\\' )) strcatW( main_exe_name, dotW );
TRACE( "starting process name=%s argv[0]=%s\n",
debugstr_w(main_exe_name), debugstr_a(__wine_main_argv[1]) );
debugstr_w(main_exe_name), debugstr_w(__wine_main_wargv[0]) );
RtlInitUnicodeString( &NtCurrentTeb()->Peb->ProcessParameters->DllPath,
MODULE_get_dll_load_path(main_exe_name) );
if (!(module = LoadLibraryExW( main_exe_name, 0, DONT_RESOLVE_DLL_REFERENCES )))
{
error = GetLastError();
/* check for a DOS binary and start winevdm if needed */
if (error == ERROR_BAD_EXE_FORMAT && GetBinaryTypeW( main_exe_name, &type ))
{
if (type == SCS_WOW_BINARY || type == SCS_DOS_BINARY ||
type == SCS_OS216_BINARY || type == SCS_PIF_BINARY)
{
new_argv0 = winevdm;
module = LoadLibraryExW( winevdmW, 0, DONT_RESOLVE_DLL_REFERENCES );
}
}
}
if (!module)
if (!(peb->ImageBaseAddress = LoadLibraryExW( main_exe_name, 0, DONT_RESOLVE_DLL_REFERENCES )))
{
char msg[1024];
DWORD error = GetLastError();
/* if Win16/DOS format, or unavailable address, exec a new process with the proper setup */
if (error == ERROR_BAD_EXE_FORMAT || error == ERROR_INVALID_ADDRESS)
{
if (!getenv("WINEPRELOADRESERVE")) exec_process( main_exe_name );
/* if we get back here, it failed */
}
FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, msg, sizeof(msg), NULL );
MESSAGE( "wine: could not load %s: %s", debugstr_w(main_exe_name), msg );
ExitProcess( error );
}
set_process_name( &__wine_main_argc, __wine_main_argv, new_argv0 );
peb->ImageBaseAddress = module;
/* build command line */
set_library_wargv( __wine_main_argv );
if (!build_command_line( __wine_main_wargv )) goto error;
/* switch to the new stack */
wine_switch_to_stack( start_process, NULL, init_stack() );
@ -1252,7 +1236,7 @@ static BOOL create_process( HANDLE hFile, LPCWSTR filename, LPWSTR cmd_line, LPW
LPCWSTR cur_dir, LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES tsa,
BOOL inherit, DWORD flags, LPSTARTUPINFOW startup,
LPPROCESS_INFORMATION info, LPCSTR unixdir,
void *res_start, void *res_end )
void *res_start, void *res_end, int exec_only )
{
BOOL ret, success = FALSE;
HANDLE process_info;
@ -1351,7 +1335,7 @@ static BOOL create_process( HANDLE hFile, LPCWSTR filename, LPWSTR cmd_line, LPW
/* create the child process */
if (!(pid = fork())) /* child */
if (exec_only || !(pid = fork())) /* child */
{
char preloader_reserve[64], socket_env[64];
char **argv = build_argv( cmd_line, 1 );
@ -1423,7 +1407,7 @@ error:
static BOOL create_vdm_process( LPCWSTR filename, LPWSTR cmd_line, LPWSTR env, LPCWSTR cur_dir,
LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES tsa,
BOOL inherit, DWORD flags, LPSTARTUPINFOW startup,
LPPROCESS_INFORMATION info, LPCSTR unixdir )
LPPROCESS_INFORMATION info, LPCSTR unixdir, int exec_only )
{
static const WCHAR argsW[] = {'%','s',' ','-','-','a','p','p','-','n','a','m','e',' ','"','%','s','"',' ','%','s',0};
@ -1438,7 +1422,7 @@ static BOOL create_vdm_process( LPCWSTR filename, LPWSTR cmd_line, LPWSTR env, L
}
sprintfW( new_cmd_line, argsW, winevdmW, filename, cmd_line );
ret = create_process( 0, winevdmW, new_cmd_line, env, cur_dir, psa, tsa, inherit,
flags, startup, info, unixdir, NULL, NULL );
flags, startup, info, unixdir, NULL, NULL, exec_only );
HeapFree( GetProcessHeap(), 0, new_cmd_line );
return ret;
}
@ -1674,7 +1658,7 @@ BOOL WINAPI CreateProcessW( LPCWSTR app_name, LPWSTR cmd_line, LPSECURITY_ATTRIB
{
TRACE( "starting %s as Winelib app\n", debugstr_w(name) );
retv = create_process( 0, name, tidy_cmdline, envW, cur_dir, process_attr, thread_attr,
inherit, flags, startup_info, info, unixdir, NULL, NULL );
inherit, flags, startup_info, info, unixdir, NULL, NULL, FALSE );
goto done;
}
@ -1683,14 +1667,14 @@ BOOL WINAPI CreateProcessW( LPCWSTR app_name, LPWSTR cmd_line, LPSECURITY_ATTRIB
case BINARY_PE_EXE:
TRACE( "starting %s as Win32 binary (%p-%p)\n", debugstr_w(name), res_start, res_end );
retv = create_process( hFile, name, tidy_cmdline, envW, cur_dir, process_attr, thread_attr,
inherit, flags, startup_info, info, unixdir, res_start, res_end );
inherit, flags, startup_info, info, unixdir, res_start, res_end, FALSE );
break;
case BINARY_OS216:
case BINARY_WIN16:
case BINARY_DOS:
TRACE( "starting %s as Win16/DOS binary\n", debugstr_w(name) );
retv = create_vdm_process( name, tidy_cmdline, envW, cur_dir, process_attr, thread_attr,
inherit, flags, startup_info, info, unixdir );
inherit, flags, startup_info, info, unixdir, FALSE );
break;
case BINARY_PE_DLL:
TRACE( "not starting %s since it is a dll\n", debugstr_w(name) );
@ -1699,7 +1683,7 @@ BOOL WINAPI CreateProcessW( LPCWSTR app_name, LPWSTR cmd_line, LPSECURITY_ATTRIB
case BINARY_UNIX_LIB:
TRACE( "%s is a Unix library, starting as Winelib app\n", debugstr_w(name) );
retv = create_process( hFile, name, tidy_cmdline, envW, cur_dir, process_attr, thread_attr,
inherit, flags, startup_info, info, unixdir, NULL, NULL );
inherit, flags, startup_info, info, unixdir, NULL, NULL, FALSE );
break;
case BINARY_UNKNOWN:
/* check for .com or .bat extension */
@ -1709,7 +1693,7 @@ BOOL WINAPI CreateProcessW( LPCWSTR app_name, LPWSTR cmd_line, LPSECURITY_ATTRIB
{
TRACE( "starting %s as DOS binary\n", debugstr_w(name) );
retv = create_vdm_process( name, tidy_cmdline, envW, cur_dir, process_attr, thread_attr,
inherit, flags, startup_info, info, unixdir );
inherit, flags, startup_info, info, unixdir, FALSE );
break;
}
if (!strcmpiW( p, batW ))
@ -1746,6 +1730,56 @@ BOOL WINAPI CreateProcessW( LPCWSTR app_name, LPWSTR cmd_line, LPSECURITY_ATTRIB
}
/**********************************************************************
* exec_process
*/
static void exec_process( LPCWSTR name )
{
HANDLE hFile;
WCHAR *p;
void *res_start, *res_end;
STARTUPINFOW startup_info;
PROCESS_INFORMATION info;
hFile = open_exe_file( name );
if (!hFile || hFile == INVALID_HANDLE_VALUE) return;
memset( &startup_info, 0, sizeof(startup_info) );
startup_info.cb = sizeof(startup_info);
/* Determine executable type */
switch( MODULE_GetBinaryType( hFile, &res_start, &res_end ))
{
case BINARY_PE_EXE:
TRACE( "starting %s as Win32 binary (%p-%p)\n", debugstr_w(name), res_start, res_end );
create_process( hFile, name, GetCommandLineW(), NULL, NULL, NULL, NULL,
FALSE, 0, &startup_info, &info, NULL, res_start, res_end, TRUE );
break;
case BINARY_UNIX_LIB:
TRACE( "%s is a Unix library, starting as Winelib app\n", debugstr_w(name) );
create_process( hFile, name, GetCommandLineW(), NULL, NULL, NULL, NULL,
FALSE, 0, &startup_info, &info, NULL, NULL, NULL, TRUE );
break;
case BINARY_UNKNOWN:
/* check for .com or .pif extension */
if (!(p = strrchrW( name, '.' ))) break;
if (strcmpiW( p, comW ) && strcmpiW( p, pifW )) break;
/* fall through */
case BINARY_OS216:
case BINARY_WIN16:
case BINARY_DOS:
TRACE( "starting %s as Win16/DOS binary\n", debugstr_w(name) );
create_vdm_process( name, GetCommandLineW(), NULL, NULL, NULL, NULL,
FALSE, 0, &startup_info, &info, NULL, TRUE );
break;
default:
break;
}
CloseHandle( hFile );
}
/***********************************************************************
* wait_input_idle
*

View File

@ -1053,12 +1053,9 @@ static NTSTATUS map_image( HANDLE hmapping, int fd, char *base, SIZE_T total_siz
relocs = &nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
if (nt->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
{
if (nt->OptionalHeader.ImageBase == 0x400000) {
ERR("Image was mapped at %p: standard load address for a Win32 program (0x00400000) not available\n", ptr);
ERR("Do you have exec-shield or prelink active?\n");
} else
ERR( "FATAL: Need to relocate module from addr %lx, but there are no relocation records\n",
nt->OptionalHeader.ImageBase );
WARN( "Need to relocate module from addr %lx, but there are no relocation records\n",
nt->OptionalHeader.ImageBase );
status = STATUS_CONFLICTING_ADDRESSES;
goto error;
}