Moved the functionality of starting Win16 and DOS programs from the

common process startup into a separate winevdm application.
This commit is contained in:
Alexandre Julliard 2003-04-27 00:47:58 +00:00
parent 8f6727c57d
commit fedc411743
17 changed files with 337 additions and 156 deletions

3
configure vendored

File diff suppressed because one or more lines are too long

View File

@ -1523,6 +1523,7 @@ programs/winedbg/Makefile
programs/winefile/Makefile
programs/winemine/Makefile
programs/winepath/Makefile
programs/winevdm/Makefile
programs/winhelp/Makefile
programs/winver/Makefile
server/Makefile

View File

@ -105,7 +105,7 @@ static WORD init_cs,init_ip,init_ss,init_sp;
static HANDLE dosvm_thread, loop_thread;
static DWORD dosvm_tid, loop_tid;
static void MZ_Launch(void);
static void MZ_Launch( LPCSTR cmdline );
static BOOL MZ_InitTask(void);
static void MZ_CreatePSP( LPVOID lpPSP, WORD env, WORD par )
@ -124,7 +124,7 @@ static void MZ_CreatePSP( LPVOID lpPSP, WORD env, WORD par )
/* FIXME: more PSP stuff */
}
static void MZ_FillPSP( LPVOID lpPSP, LPBYTE cmdline, int length )
static void MZ_FillPSP( LPVOID lpPSP, LPCSTR cmdline, int length )
{
PDB16 *psp = lpPSP;
@ -346,15 +346,18 @@ load_error:
}
/***********************************************************************
* LoadDosExe (WINEDOS.@)
* wine_load_dos_exe (WINEDOS.@)
*
* Called from Wine loader when a new real-mode DOS process is started.
* Called from WineVDM when a new real-mode DOS process is started.
* Loads DOS program into memory and executes the program.
*/
void WINAPI MZ_LoadImage( LPCSTR filename, HANDLE hFile )
void WINAPI wine_load_dos_exe( LPCSTR filename, LPCSTR cmdline )
{
HANDLE hFile = CreateFileA( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
if (hFile == INVALID_HANDLE_VALUE) return;
DOSVM_isdosexe = TRUE;
if (MZ_DoLoadImage( hFile, filename, NULL )) MZ_Launch();
if (MZ_DoLoadImage( hFile, filename, NULL )) MZ_Launch( cmdline );
}
/***********************************************************************
@ -557,11 +560,10 @@ static BOOL MZ_InitTask(void)
return TRUE;
}
static void MZ_Launch(void)
static void MZ_Launch( LPCSTR cmdline )
{
TDB *pTask = GlobalLock16( GetCurrentTask() );
BYTE *psp_start = PTR_REAL_TO_LIN( DOSVM_psp, 0 );
LPSTR cmdline = GetCommandLineA();
DWORD rv;
SYSLEVEL *lock;

View File

@ -1,4 +1,5 @@
@ stdcall LoadDosExe(str long) MZ_LoadImage
@ stdcall wine_load_dos_exe(str str)
@ stdcall EmulateInterruptPM(ptr long) DOSVM_EmulateInterruptPM
@ stdcall CallBuiltinHandler(ptr long) DOSVM_CallBuiltinHandler

View File

@ -25,7 +25,6 @@
#include "winnt.h"
typedef struct {
void (WINAPI *LoadDosExe)( LPCSTR filename, HANDLE hFile );
void (WINAPI *EmulateInterruptPM)( CONTEXT86 *context, BYTE intnum );
void (WINAPI *CallBuiltinHandler)( CONTEXT86 *context, BYTE intnum );

View File

@ -414,6 +414,21 @@ void *wine_dll_load_main_exe( const char *name, char *error, int errorsize, int
}
/***********************************************************************
* wine_init
*
* Main Wine initialisation.
*/
void wine_init( int argc, char *argv[], char *error, int error_size )
{
void *ntdll;
void (*init_func)(int, char **);
if (!(ntdll = dlopen_dll( "ntdll.dll", error, error_size, 0 ))) return;
if (!(init_func = wine_dlsym( ntdll, "__wine_process_init", error, error_size ))) return;
init_func( argc, argv );
}
#if defined(__svr4__) || defined(__NetBSD__)
/***********************************************************************

View File

@ -1107,44 +1107,6 @@ HINSTANCE16 WINAPI LoadModule16( LPCSTR name, LPVOID paramBlock )
}
/**********************************************************************
* NE_StartMain
*
* Start the main NE task.
*/
HINSTANCE16 NE_StartMain( LPCSTR name, HANDLE file )
{
STARTUPINFOA info;
HMODULE16 hModule;
NE_MODULE *pModule;
INT len;
LPSTR pCmdLine, cmdline = GetCommandLineA();
if ((hModule = NE_LoadExeHeader( file, name )) < 32) return hModule;
if (!(pModule = NE_GetPtr( hModule ))) return (HINSTANCE16)11;
if (pModule->flags & NE_FFLAGS_LIBMODULE)
{
MESSAGE( "%s is not a valid Win16 executable\n", name );
ExitProcess( ERROR_BAD_EXE_FORMAT );
}
while (*cmdline && *cmdline != ' ') cmdline++;
if (*cmdline) cmdline++;
len = strlen(cmdline);
pCmdLine = HeapAlloc(GetProcessHeap(), 0, len+2);
if (pCmdLine)
{
strcpy(pCmdLine+1, cmdline);
*pCmdLine = len;
}
GetStartupInfoA( &info );
if (!(info.dwFlags & STARTF_USESHOWWINDOW)) info.wShowWindow = 1;
return NE_CreateThread( pModule, info.wShowWindow, pCmdLine );
}
/**********************************************************************
* NE_StartTask
*

View File

@ -720,15 +720,9 @@ void WINAPI DirectedYield16( HTASK16 hTask )
{
TDB *pCurTask = TASK_GetCurrent();
if (!pCurTask) OldYield16();
if (!pCurTask || (pCurTask->flags & TDBF_WIN32)) OldYield16();
else
{
if (pCurTask->flags & TDBF_WIN32)
{
FIXME("called for Win32 thread (%04x)!\n", NtCurrentTeb()->teb_sel);
return;
}
TRACE("%04x: DirectedYield(%04x)\n", pCurTask->hSelf, hTask );
pCurTask->hYieldTo = hTask;
OldYield16();

View File

@ -1,3 +1,2 @@
Makefile
wine
wine.spec.c

View File

@ -3,8 +3,6 @@ TOPOBJDIR = ..
SRCDIR = @srcdir@
VPATH = @srcdir@
MODULE = wine
IMPORTS = ntdll
LDIMPORTS = ntdll.dll
C_SRCS = \
main.c
@ -13,14 +11,10 @@ all: $(MODULE)
@MAKE_RULES@
ALL_OBJS = $(MODULE).spec.o $(OBJS)
LDEXECFLAGS = @LDEXECFLAGS@
$(MODULE): $(ALL_OBJS)
$(CC) -o $@ $(LDEXECFLAGS) $(ALL_OBJS) -L$(DLLDIR) $(LDIMPORTS:%=-l%) $(LIBWINE) $(LIBUNICODE) $(LIBPORT) $(LIBS) $(LDFLAGS)
$(MODULE).spec.c: $(WINEBUILD)
$(WINEBUILD) $(DEFS) -o $@ --exe $(MODULE) --exe-mode gui --entry wine_initial_task -L$(DLLDIR) $(IMPORTS:%=-l%)
$(MODULE): $(OBJS)
$(CC) -o $@ $(LDEXECFLAGS) $(OBJS) $(LIBWINE) $(LIBPORT) $(LDFLAGS)
install:: $(MODULE)
$(MKINSTALLDIRS) $(bindir)

View File

@ -18,87 +18,18 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "winbase.h"
#include "wine/winbase16.h"
#include "wingdi.h"
#include "winuser.h"
#include "miscemu.h"
#include "callback.h"
#include "options.h"
#include "wine/debug.h"
static char main_exe_name[MAX_PATH];
static HANDLE main_exe_file;
static BOOL (WINAPI *pGetMessageA)(LPMSG,HWND,UINT,UINT);
static BOOL (WINAPI *pTranslateMessage)(const MSG*);
static LONG (WINAPI *pDispatchMessageA)(const MSG*);
extern void DECLSPEC_NORETURN PROCESS_InitWine(
int argc, char *argv[], LPSTR win16_exe_name,
HANDLE *win16_exe_file );
extern HINSTANCE16 NE_StartMain( LPCSTR name, HANDLE file );
/***********************************************************************
* Main loop of initial task
*/
int WINAPI wine_initial_task( HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, INT show )
{
MSG msg;
HINSTANCE16 instance;
HMODULE user32;
/* some programs assume mmsystem is always present */
LoadLibrary16( "mmsystem.dll" );
if ((instance = NE_StartMain( main_exe_name, main_exe_file )) < 32)
{
if (instance == 11) /* try DOS format */
{
if (DPMI_LoadDosSystem())
Dosvm.LoadDosExe( main_exe_name, main_exe_file );
/* if we get back here it failed */
instance = GetLastError();
}
WINE_MESSAGE( "%s: can't exec '%s': ", argv0, GetCommandLineA() );
switch (instance)
{
case 2: WINE_MESSAGE("file not found\n" ); break;
case 11: WINE_MESSAGE("invalid exe file\n" ); break;
default: WINE_MESSAGE("error=%d\n", instance ); break;
}
ExitProcess(instance);
}
CloseHandle( main_exe_file ); /* avoid file sharing problems */
/* Start message loop for desktop window */
if (!(user32 = LoadLibraryA( "user32.dll" )))
{
WINE_MESSAGE( "Cannot load user32.dll\n" );
ExitProcess( GetLastError() );
}
pGetMessageA = (void *)GetProcAddress( user32, "GetMessageA" );
pTranslateMessage = (void *)GetProcAddress( user32, "TranslateMessage" );
pDispatchMessageA = (void *)GetProcAddress( user32, "DispatchMessageA" );
while ( GetNumTasks16() > 1 && pGetMessageA( &msg, 0, 0, 0 ) )
{
pTranslateMessage( &msg );
pDispatchMessageA( &msg );
}
ExitProcess( 0 );
}
#include <stdio.h>
extern void wine_init( int argc, char *argv[], char *error, int error_size );
/**********************************************************************
* main
*/
int main( int argc, char *argv[] )
{
PROCESS_InitWine( argc, argv, main_exe_name, &main_exe_file );
return 1; /* not reached */
char error[1024];
wine_init( argc, argv, error, sizeof(error) );
fprintf( stderr, "wine: failed to initialize: %s\n", error );
exit(1);
}

View File

@ -45,7 +45,6 @@ BOOL DPMI_LoadDosSystem(void)
}
#define GET_ADDR(func) Dosvm.func = (void *)GetProcAddress(DosModule, #func);
GET_ADDR(LoadDosExe);
GET_ADDR(SetTimer);
GET_ADDR(GetTimer);
GET_ADDR(inport);

View File

@ -30,6 +30,7 @@ SUBDIRS = \
winefile \
winemine \
winepath \
winevdm \
winhelp \
winver
@ -82,6 +83,7 @@ SYMLINKS = \
wcmd.exe \
wineconsole.exe \
winedbg.exe \
winevdm.exe \
winhelp.exe
@MAKE_RULES@
@ -139,12 +141,16 @@ wineconsole.exe$(DLLEXT): wineconsole/wineconsole.exe$(DLLEXT)
winedbg.exe$(DLLEXT): winedbg/winedbg.exe$(DLLEXT)
$(RM) $@ && $(LN_S) winedbg/winedbg.exe$(DLLEXT) $@
winevdm.exe$(DLLEXT): winevdm/winevdm.exe$(DLLEXT)
$(RM) $@ && $(LN_S) winevdm/winevdm.exe$(DLLEXT) $@
winhelp.exe$(DLLEXT): winhelp/winhelp.exe$(DLLEXT)
$(RM) $@ && $(LN_S) winhelp/winhelp.exe$(DLLEXT) $@
wcmd/wcmd.exe$(DLLEXT): wcmd
wineconsole/wineconsole.exe$(DLLEXT): wineconsole
winedbg/winedbg.exe$(DLLEXT): winedbg
winevdm/winevdm.exe$(DLLEXT): winevdm
winhelp/winhelp.exe$(DLLEXT): winhelp
### Dependencies:

View File

@ -0,0 +1,3 @@
Makefile
winevdm.exe.dbg.c
winevdm.exe.spec.c

View File

@ -0,0 +1,14 @@
TOPSRCDIR = @top_srcdir@
TOPOBJDIR = ../..
SRCDIR = @srcdir@
VPATH = @srcdir@
MODULE = winevdm.exe
APPMODE = cui
IMPORTS = winedos kernel32
C_SRCS = \
winevdm.c
@MAKE_PROG_RULES@
### Dependencies:

229
programs/winevdm/winevdm.c Normal file
View File

@ -0,0 +1,229 @@
/*
* Wine virtual DOS machine
*
* Copyright 2003 Alexandre Julliard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "winbase.h"
#include "wine/winbase16.h"
#include "winuser.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(winevdm);
extern void WINAPI wine_load_dos_exe( LPCSTR filename, LPCSTR cmdline );
/***********************************************************************
* build_command_line
*
* Build the command line of a process from the argv array.
* Copied from ENV_BuildCommandLine.
*/
static char *build_command_line( char **argv )
{
int len;
char *p, **arg, *cmd_line;
len = 0;
for (arg = argv; *arg; arg++)
{
int has_space,bcount;
char* a;
has_space=0;
bcount=0;
a=*arg;
while (*a!='\0') {
if (*a=='\\') {
bcount++;
} else {
if (*a==' ' || *a=='\t') {
has_space=1;
} else if (*a=='"') {
/* doubling of '\' preceeding a '"',
* plus escaping of said '"'
*/
len+=2*bcount+1;
}
bcount=0;
}
a++;
}
len+=(a-*arg)+1 /* for the separating space */;
if (has_space)
len+=2; /* for the quotes */
}
if (!(cmd_line = HeapAlloc( GetProcessHeap(), 0, len + 1 ))) return NULL;
p = cmd_line;
*p++ = len;
for (arg = argv; *arg; arg++)
{
int has_space,has_quote;
char* a;
/* Check for quotes and spaces in this argument */
has_space=has_quote=0;
a=*arg;
while (*a!='\0') {
if (*a==' ' || *a=='\t') {
has_space=1;
if (has_quote)
break;
} else if (*a=='"') {
has_quote=1;
if (has_space)
break;
}
a++;
}
/* Now transfer it to the command line */
if (has_space)
*p++='"';
if (has_quote) {
int bcount;
char* a;
bcount=0;
a=*arg;
while (*a!='\0') {
if (*a=='\\') {
*p++=*a;
bcount++;
} else {
if (*a=='"') {
int i;
/* Double all the '\\' preceeding this '"', plus one */
for (i=0;i<=bcount;i++)
*p++='\\';
*p++='"';
} else {
*p++=*a;
}
bcount=0;
}
a++;
}
} else {
strcpy(p,*arg);
p+=strlen(*arg);
}
if (has_space)
*p++='"';
*p++=' ';
}
if (p > cmd_line) p--; /* remove last space */
*p = '\0';
return cmd_line;
}
/***********************************************************************
* usage
*/
static void usage(void)
{
WINE_MESSAGE( "Usage: winevdm.exe [--app-name app.exe] command line\n\n" );
ExitProcess(1);
}
/***********************************************************************
* main
*/
int main( int argc, char *argv[] )
{
DWORD count;
HINSTANCE16 instance;
LOADPARAMS16 params;
WORD showCmd[2];
char buffer[MAX_PATH];
STARTUPINFOA info;
char *cmdline, *appname, **first_arg;
if (!argv[1]) usage();
if (!strcmp( argv[1], "--app-name" ))
{
if (!(appname = argv[2])) usage();
first_arg = argv + 3;
}
else
{
if (!SearchPathA( NULL, argv[1], ".exe", sizeof(buffer), buffer, NULL ))
{
WINE_MESSAGE( "winevdm: can't exec '%s': file not found\n", argv[1] );
ExitProcess(1);
}
appname = buffer;
first_arg = argv + 1;
}
if (*first_arg) first_arg++; /* skip program name */
cmdline = build_command_line( first_arg );
if (WINE_TRACE_ON(winevdm))
{
int i;
WINE_TRACE( "GetCommandLine = '%s'\n", GetCommandLineA() );
WINE_TRACE( "appname = '%s'\n", appname );
WINE_TRACE( "cmdline = '%.*s'\n", cmdline[0], cmdline+1 );
for (i = 0; argv[i]; i++) WINE_TRACE( "argv[%d]: '%s'\n", i, argv[i] );
}
GetStartupInfoA( &info );
showCmd[0] = 2;
showCmd[1] = (info.dwFlags & STARTF_USESHOWWINDOW) ? info.wShowWindow : SW_SHOWNORMAL;
params.hEnvironment = 0;
params.cmdLine = MapLS( cmdline );
params.showCmd = MapLS( showCmd );
params.reserved = 0;
RestoreThunkLock(1); /* grab the Win16 lock */
/* some programs assume mmsystem is always present */
LoadLibrary16( "mmsystem.dll" );
if ((instance = LoadModule16( appname, &params )) < 32)
{
if (instance == 11) /* try DOS format */
{
wine_load_dos_exe( appname, cmdline );
/* if we get back here it failed */
instance = GetLastError();
}
WINE_MESSAGE( "winevdm: can't exec '%s': ", appname );
switch (instance)
{
case 2: WINE_MESSAGE("file not found\n" ); break;
case 11: WINE_MESSAGE("invalid exe file\n" ); break;
default: WINE_MESSAGE("error=%d\n", instance ); break;
}
ExitProcess(instance);
}
/* wait forever; the process will be killed when the last task exits */
ReleaseThunkLock( &count );
Sleep( INFINITE );
return 0;
}

View File

@ -572,11 +572,11 @@ static void start_process(void)
/***********************************************************************
* PROCESS_InitWine
* __wine_process_init
*
* Wine initialisation: load and start the main exe file.
*/
void PROCESS_InitWine( int argc, char *argv[], LPSTR win16_exe_name, HANDLE *win16_exe_file )
void __wine_process_init( int argc, char *argv[] )
{
char error[1024], *p;
DWORD stack_size = 0;
@ -636,14 +636,15 @@ void PROCESS_InitWine( int argc, char *argv[], LPSTR win16_exe_name, HANDLE *win
case BINARY_WIN16:
case BINARY_DOS:
TRACE( "starting Win16/DOS binary %s\n", debugstr_a(main_exe_name) );
NtCurrentTeb()->tibflags &= ~TEBF_WIN32;
current_process.flags |= PDB32_WIN16_PROC;
strcpy( win16_exe_name, main_exe_name );
main_exe_name[0] = 0;
*win16_exe_file = main_exe_file;
CloseHandle( main_exe_file );
main_exe_file = 0;
_EnterWin16Lock();
goto found;
argv--;
argv[0] = "winevdm.exe";
if (open_builtin_exe_file( "winevdm.exe", error, sizeof(error), 0 ))
goto found;
MESSAGE( "%s: trying to run '%s', cannot open builtin library for 'winevdm.exe': %s\n",
argv0, main_exe_name, error );
ExitProcess(1);
case BINARY_OS216:
MESSAGE( "%s: '%s' is an OS/2 binary, not supported\n", argv0, main_exe_name );
ExitProcess(1);
@ -1132,6 +1133,32 @@ static BOOL create_process( HANDLE hFile, LPCSTR filename, LPSTR cmd_line, LPCST
}
/***********************************************************************
* create_vdm_process
*
* Create a new VDM process for a 16-bit or DOS application.
*/
static BOOL create_vdm_process( LPCSTR filename, LPSTR cmd_line, LPCSTR env,
LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES tsa,
BOOL inherit, DWORD flags, LPSTARTUPINFOA startup,
LPPROCESS_INFORMATION info, LPCSTR unixdir )
{
BOOL ret;
LPSTR new_cmd_line = HeapAlloc( GetProcessHeap(), 0, strlen(filename) + strlen(cmd_line) + 30 );
if (!new_cmd_line)
{
SetLastError( ERROR_OUTOFMEMORY );
return FALSE;
}
sprintf( new_cmd_line, "winevdm.exe --app-name \"%s\" %s", filename, cmd_line );
ret = create_process( 0, "winevdm.exe", new_cmd_line, env, psa, tsa, inherit,
flags, startup, info, unixdir );
HeapFree( GetProcessHeap(), 0, new_cmd_line );
return ret;
}
/*************************************************************************
* get_file_name
*
@ -1310,12 +1337,16 @@ BOOL WINAPI CreateProcessA( LPCSTR app_name, LPSTR cmd_line, LPSECURITY_ATTRIBUT
switch( MODULE_GetBinaryType( hFile ))
{
case BINARY_PE_EXE:
case BINARY_WIN16:
case BINARY_DOS:
TRACE( "starting %s as Windows binary\n", debugstr_a(name) );
TRACE( "starting %s as Win32 binary\n", debugstr_a(name) );
retv = create_process( hFile, name, tidy_cmdline, env, process_attr, thread_attr,
inherit, flags, startup_info, info, unixdir );
break;
case BINARY_WIN16:
case BINARY_DOS:
TRACE( "starting %s as Win16/DOS binary\n", debugstr_a(name) );
retv = create_vdm_process( name, tidy_cmdline, env, process_attr, thread_attr,
inherit, flags, startup_info, info, unixdir );
break;
case BINARY_OS216:
FIXME( "%s is OS/2 binary, not supported\n", debugstr_a(name) );
SetLastError( ERROR_BAD_EXE_FORMAT );
@ -1336,8 +1367,8 @@ BOOL WINAPI CreateProcessA( LPCSTR app_name, LPSTR cmd_line, LPSECURITY_ATTRIBUT
if (!FILE_strcasecmp( p, ".com" ))
{
TRACE( "starting %s as DOS binary\n", debugstr_a(name) );
retv = create_process( hFile, name, tidy_cmdline, env, process_attr, thread_attr,
inherit, flags, startup_info, info, unixdir );
retv = create_vdm_process( name, tidy_cmdline, env, process_attr, thread_attr,
inherit, flags, startup_info, info, unixdir );
break;
}
if (!FILE_strcasecmp( p, ".bat" ))