243 lines
6.6 KiB
C
243 lines
6.6 KiB
C
/*
|
|
* 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 <stdarg.h>
|
|
|
|
#include "windef.h"
|
|
#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;
|
|
if( !*a ) has_space=1;
|
|
while (*a!='\0') {
|
|
if (*a=='\\') {
|
|
bcount++;
|
|
} else {
|
|
if (*a==' ' || *a=='\t') {
|
|
has_space=1;
|
|
} else if (*a=='"') {
|
|
/* doubling of '\' preceding 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 ? len + 1 : 2 )))
|
|
return NULL;
|
|
|
|
p = cmd_line;
|
|
*p++ = (len < 256) ? len : 255;
|
|
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;
|
|
if( !*a ) has_space=1;
|
|
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 '\\' preceding 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 (len) 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" );
|
|
|
|
/* make sure system drivers are loaded */
|
|
LoadLibrary16( "comm.drv" );
|
|
LoadLibrary16( "display.drv" );
|
|
LoadLibrary16( "keyboard.drv" );
|
|
LoadLibrary16( "mouse.drv" );
|
|
|
|
if ((instance = LoadModule16( appname, ¶ms )) < 32)
|
|
{
|
|
if (instance == 11) /* try DOS format */
|
|
{
|
|
/* loader expects arguments to be regular C strings */
|
|
wine_load_dos_exe( appname, cmdline + 1 );
|
|
/* 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;
|
|
}
|