Fix argument passing to DOS program from winevdm.

Add support for invoking DOS programs with long command lines.
This commit is contained in:
Jukka Heinonen 2003-05-02 20:11:52 +00:00 committed by Alexandre Julliard
parent 6ac3bee094
commit f93d452d78
2 changed files with 107 additions and 35 deletions

View File

@ -105,7 +105,7 @@ static WORD init_cs,init_ip,init_ss,init_sp;
static HANDLE dosvm_thread, loop_thread; static HANDLE dosvm_thread, loop_thread;
static DWORD dosvm_tid, loop_tid; static DWORD dosvm_tid, loop_tid;
static void MZ_Launch( LPCSTR cmdline ); static void MZ_Launch( LPCSTR cmdtail, int length );
static BOOL MZ_InitTask(void); static BOOL MZ_InitTask(void);
static void MZ_CreatePSP( LPVOID lpPSP, WORD env, WORD par ) static void MZ_CreatePSP( LPVOID lpPSP, WORD env, WORD par )
@ -124,31 +124,29 @@ static void MZ_CreatePSP( LPVOID lpPSP, WORD env, WORD par )
/* FIXME: more PSP stuff */ /* FIXME: more PSP stuff */
} }
static void MZ_FillPSP( LPVOID lpPSP, LPCSTR cmdline, int length ) static void MZ_FillPSP( LPVOID lpPSP, LPCSTR cmdtail, int length )
{ {
PDB16 *psp = lpPSP; PDB16 *psp = lpPSP;
while(length > 0 && *cmdline != ' ') { if(length > 127)
length--; {
cmdline++; WARN( "Command tail truncated! (length %d)\n", length );
}
/* command.com does not skip over multiple spaces */
if(length > 126) {
/*
* FIXME: If length > 126 we should put truncated command line to
* PSP and store the entire command line in the environment
* variable CMDLINE.
*/
FIXME("Command line truncated! (length %d > maximum length 126)\n",
length);
length = 126; length = 126;
} }
psp->cmdLine[0] = length; psp->cmdLine[0] = length;
/*
* Length of exactly 127 bytes means that full command line is
* stored in environment variable CMDLINE and PSP contains
* command tail truncated to 126 bytes.
*/
if(length == 127)
length = 126;
if(length > 0) if(length > 0)
memmove(psp->cmdLine+1, cmdline, length); memmove(psp->cmdLine+1, cmdtail, length);
psp->cmdLine[length+1] = '\r'; psp->cmdLine[length+1] = '\r';
/* FIXME: more PSP stuff */ /* FIXME: more PSP stuff */
@ -353,11 +351,78 @@ load_error:
*/ */
void WINAPI wine_load_dos_exe( LPCSTR filename, LPCSTR cmdline ) void WINAPI wine_load_dos_exe( LPCSTR filename, LPCSTR cmdline )
{ {
HANDLE hFile = CreateFileA( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); char dos_cmdtail[126];
int dos_length = 0;
HANDLE hFile = CreateFileA( filename, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, 0, 0 );
if (hFile == INVALID_HANDLE_VALUE) return; if (hFile == INVALID_HANDLE_VALUE) return;
DOSVM_isdosexe = TRUE; DOSVM_isdosexe = TRUE;
if (MZ_DoLoadImage( hFile, filename, NULL )) MZ_Launch( cmdline );
if(cmdline && *cmdline)
{
dos_length = strlen(cmdline);
memmove( dos_cmdtail + 1, cmdline,
(dos_length < 125) ? dos_length : 125 );
/* Non-empty command tail always starts with at least one space. */
dos_cmdtail[0] = ' ';
dos_length++;
/*
* If command tail is longer than 126 characters,
* set tail length to 127 and fill CMDLINE environment variable
* with full command line (this includes filename).
*/
if (dos_length > 126)
{
char *cmd = HeapAlloc( GetProcessHeap(), 0,
dos_length + strlen(filename) + 4 );
char *ptr = cmd;
if (!cmd)
return;
/*
* Append filename. If path includes spaces, quote the path.
*/
if (strchr(filename, ' '))
{
*ptr++ = '\"';
strcpy( ptr, filename );
ptr += strlen(filename);
*ptr++ = '\"';
}
else
{
strcpy( ptr, filename );
ptr += strlen(filename);
}
/*
* Append command tail.
*/
if (cmdline[0] != ' ')
*ptr++ = ' ';
strcpy( ptr, cmdline );
/*
* Set environment variable. This will be passed to
* new DOS process.
*/
if (!SetEnvironmentVariableA( "CMDLINE", cmd ))
{
HeapFree(GetProcessHeap(), 0, cmd );
return;
}
HeapFree(GetProcessHeap(), 0, cmd );
dos_length = 127;
}
}
if (MZ_DoLoadImage( hFile, filename, NULL ))
MZ_Launch( dos_cmdtail, dos_length );
} }
/*********************************************************************** /***********************************************************************
@ -391,13 +456,18 @@ BOOL WINAPI MZ_Exec( CONTEXT86 *context, LPCSTR filename, BYTE func, LPVOID para
ExecBlock *blk = (ExecBlock *)paramblk; ExecBlock *blk = (ExecBlock *)paramblk;
LPBYTE cmdline = PTR_REAL_TO_LIN(SELECTOROF(blk->cmdline),OFFSETOF(blk->cmdline)); LPBYTE cmdline = PTR_REAL_TO_LIN(SELECTOROF(blk->cmdline),OFFSETOF(blk->cmdline));
LPBYTE envblock = PTR_REAL_TO_LIN(psp->environment, 0); LPBYTE envblock = PTR_REAL_TO_LIN(psp->environment, 0);
BYTE cmdLength = cmdline[0]; int cmdLength = cmdline[0];
/* /*
* FIXME: If cmdLength == 126, PSP may contain truncated version * If cmdLength is 127, command tail is truncated and environment
* of the full command line. In this case environment * variable CMDLINE should contain full command line
* variable CMDLINE contains the entire command line. * (this includes filename).
*/ */
if (cmdLength == 127)
{
FIXME( "CMDLINE argument passing is unimplemented.\n" );
cmdLength = 126; /* FIXME */
}
fullCmdLength = (strlen(filename) + 1) + cmdLength + 1; /* filename + space + cmdline + terminating null character */ fullCmdLength = (strlen(filename) + 1) + cmdLength + 1; /* filename + space + cmdline + terminating null character */
@ -560,14 +630,14 @@ static BOOL MZ_InitTask(void)
return TRUE; return TRUE;
} }
static void MZ_Launch( LPCSTR cmdline ) static void MZ_Launch( LPCSTR cmdtail, int length )
{ {
TDB *pTask = GlobalLock16( GetCurrentTask() ); TDB *pTask = GlobalLock16( GetCurrentTask() );
BYTE *psp_start = PTR_REAL_TO_LIN( DOSVM_psp, 0 ); BYTE *psp_start = PTR_REAL_TO_LIN( DOSVM_psp, 0 );
DWORD rv; DWORD rv;
SYSLEVEL *lock; SYSLEVEL *lock;
MZ_FillPSP(psp_start, cmdline, cmdline ? strlen(cmdline) : 0); MZ_FillPSP(psp_start, cmdtail, length);
pTask->flags |= TDBF_WINOLDAP; pTask->flags |= TDBF_WINOLDAP;
/* DTA is set to PSP:0080h when a program is started. */ /* DTA is set to PSP:0080h when a program is started. */

View File

@ -69,10 +69,11 @@ static char *build_command_line( char **argv )
len+=2; /* for the quotes */ len+=2; /* for the quotes */
} }
if (!(cmd_line = HeapAlloc( GetProcessHeap(), 0, len + 1 ))) return NULL; if (!(cmd_line = HeapAlloc( GetProcessHeap(), 0, len ? len + 1 : 2 )))
return NULL;
p = cmd_line; p = cmd_line;
*p++ = len; *p++ = (len < 256) ? len : 255;
for (arg = argv; *arg; arg++) for (arg = argv; *arg; arg++)
{ {
int has_space,has_quote; int has_space,has_quote;
@ -130,7 +131,7 @@ static char *build_command_line( char **argv )
*p++='"'; *p++='"';
*p++=' '; *p++=' ';
} }
if (p > cmd_line) p--; /* remove last space */ if (len) p--; /* remove last space */
*p = '\0'; *p = '\0';
return cmd_line; return cmd_line;
} }
@ -207,7 +208,8 @@ int main( int argc, char *argv[] )
{ {
if (instance == 11) /* try DOS format */ if (instance == 11) /* try DOS format */
{ {
wine_load_dos_exe( appname, cmdline ); /* loader expects arguments to be regular C strings */
wine_load_dos_exe( appname, cmdline + 1 );
/* if we get back here it failed */ /* if we get back here it failed */
instance = GetLastError(); instance = GetLastError();
} }