windows-nt/Source/XPSP1/NT/base/cmd/cext.c

1855 lines
59 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1988-1999 Microsoft Corporation
Module Name:
cext.c
Abstract:
External command support
--*/
#include "cmd.h"
#define DBENV 0x0080
#define DBENVSCAN 0x0010
HANDLE hChildProcess;
unsigned start_type ; /* D64 */
extern UINT CurrentCP;
extern TCHAR Fmt16[] ; /* @@5h */
extern unsigned DosErr ;
extern BOOL CtrlCSeen;
extern TCHAR CurDrvDir[] ;
extern TCHAR CmdExt[], BatExt[], PathStr[] ;
extern TCHAR PathExtStr[], PathExtDefaultStr[];
extern TCHAR ComSpec[] ; /* M033 - Use ComSpec for SM memory */
extern TCHAR ComSpecStr[] ; /* M033 - Use ComSpec for SM memory */
extern void tokshrink(TCHAR*);
extern TCHAR PathChar ;
extern TCHAR SwitChar ;
extern PTCHAR pszTitleCur;
extern BOOLEAN fTitleChanged;
extern int LastRetCode ;
extern HANDLE PipePid ; /* M024 - Store PID from piped cmd */
extern struct envdata CmdEnv ; // Holds info to manipulate Cmd's environment
extern int glBatType; // to distinguish OS/2 vs DOS errorlevel behavior depending on a script file name
TCHAR szNameEqExitCodeEnvVar[] = TEXT ("=ExitCode");
TCHAR szNameEqExitCodeAsciiEnvVar[] = TEXT ("=ExitCodeAscii");
WORD
GetProcessSubsystemType(
HANDLE hProcess
);
/*** ExtCom - controls the execution of external programs
*
* Purpose:
* Synchronously execute an external command. Call ECWork with the
* appropriate values to have this done.
*
* ExtCom(struct cmdnode *n)
*
* Args:
* Parse tree node containing the command to be executed.
*
* Returns:
* Whatever ECWork returns.
*
* Notes:
* During batch processing, labels are ignored. Empty commands are
* also ignored.
*
*/
int ExtCom(n)
struct cmdnode *n ;
{
if (CurrentBatchFile && *n->cmdline == COLON)
return(SUCCESS) ;
if (n && n->cmdline && mystrlen(n->cmdline)) {
return(ECWork(n, AI_SYNC, CW_W_YES)) ; /* M024 */
} ;
return(SUCCESS) ;
}
/********************* START OF SPECIFICATION **************************/
/* */
/* SUBROUTINE NAME: ECWork */
/* */
/* DESCRIPTIVE NAME: Execute External Commands Worker */
/* */
/* FUNCTION: Execute External Commands */
/* This routine calls SearchForExecutable routine to search */
/* for the executable command. If the command ( .EXE, .COM, */
/* or .CMD file ) is found, the command is executed. */
/* */
/* ENTRY POINT: ECWork */
/* LINKAGE: NEAR */
/* */
/* INPUT: n - the parse tree node containing the command to be executed*/
/* */
/* ai - the asynchronous indicator */
/* - 0 = Exec synchronous with parent */
/* - 1 = Exec asynchronous and discard child return code */
/* - 2 = Exec asynchronous and save child return code */
/* */
/* wf - the wait flag */
/* - 0 = Wait for process completion */
/* - 1 = Return immediately (Pipes) */
/* */
/* OUTPUT: None. */
/* */
/* EXIT-NORMAL: */
/* If synchronous execution, the return code of the command is */
/* returned. */
/* */
/* If asynchronous execution, the return code of the exec call */
/* is returned. */
/* */
/* EXIT-ERROR: */
/* Return FAILURE to the caller. */
/* */
/* */
/********************** END OF SPECIFICATION **************************/
/*** ECWork - begins the execution of external commands
*
* Purpose:
* To search for and execute an external command. Update LastRetCode
* if an external program was executed.
*
* int ECWork(struct cmdnode *n, unsigned ai, unsigned wf)
*
* Args:
* n - the parse tree node containing the command to be executed
* ai - the asynchronous indicator
* - 0 = Exec synchronous with parent
* - 1 = Exec asynchronous and discard child return code
* - 2 = Exec asynchronous and save child return code
* wf - the wait flag
* - 0 = Wait for process completion
* - 1 = Return immediately (Pipes)
*
* Returns:
* If syncronous execution, the return code of the command is returned.
* If asyncronous execution, the return code of the exec call is returned.
*
* Notes:
* The pid of a program that will be waited on is placed in the global
* variable Retcds.ptcod so that WaitProc can use it and so SigHand()
* can kill it if necessary (only during SYNC exec's).
* M024 - Added wait flag parm so pipes can get immediate return while
* still doing an AI_KEEP async exec.
* - Considerable revisions to structure.
*/
int ECWork(n, ai, wf)
struct cmdnode *n ;
unsigned ai ;
unsigned wf ;
{
TCHAR *fnptr, /* Ptr to filename */
*argptr, /* Command Line String */
*tptr; /* M034 - Temps */
int i ; /* Work variable */
TCHAR * onb ; /* M035 - Obj name buffer */
ULONG rc;
if (!(fnptr = mkstr(MAX_PATH*sizeof(TCHAR)+sizeof(TCHAR)))) /* Loc/nam of file to exec */
return(FAILURE) ;
argptr = GetTitle( n );
tptr = argptr;
if (argptr == NULL) {
return( FAILURE );
}
i = SearchForExecutable(n, fnptr) ;
if (i == SFE_ISEXECOM) { /* Found .com or .exe file */
if (!(onb = (TCHAR *)mkstr(MAX_PATH*sizeof(TCHAR)+sizeof(TCHAR)))) /* M035 */
{
return(FAILURE) ;
}
SetConTitle( tptr );
rc = ExecPgm( n, onb, ai, wf, argptr, fnptr, tptr);
ResetConTitle( pszTitleCur );
return( rc );
} ;
if (i == SFE_ISBAT) { /* Found .cmd file, call BatProc */
SetConTitle(tptr);
rc = BatProc(n, fnptr, BT_CHN) ;
ResetConTitle( pszTitleCur );
return(rc) ;
} ;
if (i == SFE_ISDIR) {
return ChangeDir2(fnptr, TRUE);
}
LastRetCode = DosErr;
if (i == SFE_FAIL) { /* Out of Memory Error */
return(FAILURE) ;
} ;
if (DosErr == MSG_DIR_BAD_COMMAND_OR_FILE) {
PutStdErr(DosErr, ONEARG, n->cmdline);
}
else {
PutStdErr(DosErr, NOARGS);
}
return(FAILURE) ;
}
#ifndef WIN95_CMD
VOID
RestoreCurrentDirectories( VOID )
/* this routine sets the current process's current directories to
those of the child if the child was the VDM to fix DOS batch files.
*/
{
ULONG cchCurDirs;
UINT PreviousErrorMode;
PTCHAR pCurDirs,pCurCurDir;
BOOL CurDrive=TRUE;
#ifdef UNICODE
PCHAR pT;
#endif
cchCurDirs = GetVDMCurrentDirectories( 0,
NULL
);
if (cchCurDirs == 0)
return;
pCurDirs = gmkstr(cchCurDirs*sizeof(TCHAR));
#ifdef UNICODE
pT = gmkstr(cchCurDirs);
#endif
GetVDMCurrentDirectories( cchCurDirs,
#ifdef UNICODE
pT
#else
pCurDirs
#endif
);
#ifdef UNICODE
MultiByteToWideChar(CurrentCP, MB_PRECOMPOSED, pT, -1, pCurDirs, cchCurDirs);
#endif
// set error mode so we don't get popup if trying to set curdir
// on empty floppy drive
PreviousErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
for (pCurCurDir=pCurDirs;*pCurCurDir!=NULLC;pCurCurDir+=(_tcslen(pCurCurDir)+1)) {
ChangeDir2(pCurCurDir,CurDrive);
CurDrive=FALSE;
}
SetErrorMode(PreviousErrorMode);
//free(pCurDirs);
#ifdef UNICODE
FreeStr((PTCHAR)pT);
#endif
}
#endif // WIN95_CMD
/********************* START OF SPECIFICATION **************************/
/* */
/* SUBROUTINE NAME: ExecPgm */
/* */
/* DESCRIPTIVE NAME: Call DosExecPgm to execute External Command */
/* */
/* FUNCTION: Execute External Commands with DosExecPgm */
/* This routine calls DosExecPgm to execute the command. */
/* */
/* */
/* NOTES: This is a new routine added for OS/2 1.1 release. */
/* */
/* */
/* ENTRY POINT: ExecPgm */
/* LINKAGE: NEAR */
/* */
/* INPUT: n - the parse tree node containing the command to be executed*/
/* */
/* ai - the asynchronous indicator */
/* - 0 = Exec synchronous with parent */
/* - 1 = Exec asynchronous and discard child return code */
/* - 2 = Exec asynchronous and save child return code */
/* */
/* wf - the wait flag */
/* - 0 = Wait for process completion */
/* - 1 = Return immediately (Pipes) */
/* */
/* OUTPUT: None. */
/* */
/* EXIT-NORMAL: */
/* If synchronous execution, the return code of the command is */
/* returned. */
/* */
/* If asynchronous execution, the return code of the exec call */
/* is returned. */
/* */
/* EXIT-ERROR: */
/* Return FAILURE to the caller. */
/* */
/* EFFECTS: */
/* */
/* INTERNAL REFERENCES: */
/* ROUTINES: */
/* ExecError - Handles execution error */
/* PutStdErr - Print an error message */
/* WaitProc - wait for the termination of the specified process, */
/* its child process, and related pipelined */
/* processes. */
/* */
/* */
/* EXTERNAL REFERENCES: */
/* ROUTINES: */
/* DOSEXECPGM - Execute the specified program */
/* DOSSMSETTITLE - Set title for the presentation manager */
/* */
/********************** END OF SPECIFICATION **************************/
int
ExecPgm(
IN struct cmdnode *n,
IN TCHAR *onb,
IN unsigned int ai,
IN unsigned int wf,
IN TCHAR * argptr,
IN TCHAR * fnptr,
IN TCHAR * tptr
)
{
int i ; /* Work variable */
BOOL b;
BOOL VdmProcess = FALSE;
BOOL WowProcess = FALSE;
BOOL GuiProcess = FALSE;
LPTSTR CopyCmdValue;
HDESK hdesk;
LPTSTR lpDesktop;
DWORD cbDesktop = 0;
HWINSTA hwinsta;
LPTSTR p;
DWORD cbWinsta = 0;
TCHAR szValEqExitCodeEnvVar [20];
TCHAR szValEqExitCodeAsciiEnvVar [12];
STARTUPINFO StartupInfo;
PROCESS_INFORMATION ChildProcessInfo;
memset( &StartupInfo, 0, sizeof( StartupInfo ) );
StartupInfo.cb = sizeof( StartupInfo );
StartupInfo.lpTitle = tptr;
StartupInfo.dwX = 0;
StartupInfo.dwY = 1;
StartupInfo.dwXSize = 100;
StartupInfo.dwYSize = 100;
StartupInfo.dwFlags = 0;//STARTF_SHELLOVERRIDE;
StartupInfo.wShowWindow = SW_SHOWNORMAL;
// Pass current Desktop to a new process.
hwinsta = GetProcessWindowStation();
GetUserObjectInformation( hwinsta, UOI_NAME, NULL, 0, &cbWinsta );
hdesk = GetThreadDesktop ( GetCurrentThreadId() );
GetUserObjectInformation (hdesk, UOI_NAME, NULL, 0, &cbDesktop);
if ((lpDesktop = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, cbDesktop + cbWinsta + 32) ) != NULL ) {
p = lpDesktop;
if ( GetUserObjectInformation (hwinsta, UOI_NAME, p, cbWinsta, &cbWinsta) ) {
if (cbWinsta > 0) {
p += ((cbWinsta/sizeof(TCHAR))-1);
*p++ = L'\\';
}
if ( GetUserObjectInformation (hdesk, UOI_NAME, p, cbDesktop, &cbDesktop) ) {
StartupInfo.lpDesktop = lpDesktop;
}
}
}
//
// Incredibly ugly hack for Win95 compatibility.
//
// XCOPY in Win95 reaches up into it's parent process to see if it was
// invoked in a batch file. If so, then XCOPY pretends COPYCMD=/Y
//
// There is no way we can do this for NT. The best that can be done is
// to detect if we're in a batch file starting XCOPY and then temporarily
// change COPYCMD=/Y.
//
{
const TCHAR *p = MyGetEnvVarPtr( TEXT( "COPYCMD" ));
if (p == NULL) {
p = TEXT( "" );
}
CopyCmdValue = malloc( (mystrlen( p ) + 1) * sizeof( TCHAR ));
if (CopyCmdValue == NULL) {
PutStdErr( MSG_NO_MEMORY, NOARGS );
return FAILURE;
}
mystrcpy( CopyCmdValue, p );
if ((SingleBatchInvocation
|| SingleCommandInvocation
|| CurrentBatchFile )
&& (p = mystrrchr( fnptr, TEXT( '\\' ))) != NULL
&& !lstrcmp( p, TEXT( "\\XCOPY.EXE" ))
) {
SetEnvVar( TEXT( "COPYCMD" ), TEXT( "/Y" ), NULL );
}
}
//
// If the restricted token exists then create the process with the
// restricted token.
// Else create the process without any restrictions.
//
if ((CurrentBatchFile != NULL) && (CurrentBatchFile->hRestrictedToken != NULL)) {
b = CreateProcessAsUser( CurrentBatchFile->hRestrictedToken,
fnptr,
argptr,
(LPSECURITY_ATTRIBUTES) NULL,
(LPSECURITY_ATTRIBUTES) NULL,
TRUE,
0,
NULL,
CurDrvDir,
&StartupInfo,
&ChildProcessInfo
);
} else {
b = CreateProcess( fnptr,
argptr,
(LPSECURITY_ATTRIBUTES) NULL,
(LPSECURITY_ATTRIBUTES) NULL,
TRUE,
0,
NULL,
CurDrvDir,
&StartupInfo,
&ChildProcessInfo
);
}
if (!b) {
DosErr = i = GetLastError();
} else {
hChildProcess = ChildProcessInfo.hProcess;
#if !defined( WIN95_CMD ) && DBG
if (hChildProcess == NULL) {
DbgBreakPoint( );
}
#endif
CloseHandle(ChildProcessInfo.hThread);
}
//
// Undo ugly hack
//
SetEnvVar( TEXT( "COPYCMD" ), CopyCmdValue, NULL );
free( CopyCmdValue );
HeapFree (GetProcessHeap(), 0, lpDesktop);
if (!b) {
if (fEnableExtensions && DosErr == ERROR_BAD_EXE_FORMAT) {
SHELLEXECUTEINFO sei;
memset(&sei, 0, sizeof(sei));
//
// Use the DDEWAIT flag so apps can finish their DDE conversation
// before ShellExecuteEx returns. Otherwise, apps like Word will
// complain when they try to exit, confusing the user.
//
sei.cbSize = sizeof(sei);
sei.fMask = SEE_MASK_HASTITLE |
SEE_MASK_NO_CONSOLE |
SEE_MASK_FLAG_DDEWAIT |
SEE_MASK_NOCLOSEPROCESS;
sei.lpFile = fnptr;
sei.lpParameters = n->argptr;
sei.lpDirectory = CurDrvDir;
sei.nShow = StartupInfo.wShowWindow;
try {
b = ShellExecuteEx( &sei );
if (b) {
hChildProcess = sei.hProcess;
leave;
}
if (sei.hInstApp == NULL) {
DosErr = ERROR_NOT_ENOUGH_MEMORY;
} else if ((DWORD_PTR)sei.hInstApp == HINSTANCE_ERROR) {
DosErr = ERROR_FILE_NOT_FOUND;
} else {
DosErr = HandleToUlong(sei.hInstApp);
}
} except( DosErr = GetExceptionCode( ), EXCEPTION_EXECUTE_HANDLER ) {
b = FALSE;
}
}
if (!b) {
mystrcpy( onb, fnptr );
ExecError( onb ) ;
return (FAILURE) ;
}
}
#ifndef WIN95_CMD
VdmProcess = ((UINT_PTR)(hChildProcess) & 1) ? TRUE : FALSE;
WowProcess = ((UINT_PTR)(hChildProcess) & 2) ? TRUE : FALSE;
#endif // WIN95_CMD
if (hChildProcess == NULL
|| (fEnableExtensions
&& CurrentBatchFile == 0
&& !SingleBatchInvocation
&& !SingleCommandInvocation
&& ai == AI_SYNC
&& (WowProcess
|| GetProcessSubsystemType(hChildProcess) == IMAGE_SUBSYSTEM_WINDOWS_GUI
)
)
) {
//
// If extensions enabled and doing a synchronous exec of a GUI
// application, then change it into an asynchronous exec, with the
// return code discarded, ala Win 3.x and Win 95 COMMAND.COM
//
ai = AI_DSCD;
GuiProcess = TRUE;
}
i = SUCCESS;
start_type = EXECPGM;
if (ai == AI_SYNC) { /* Async exec... */
LastRetCode = WaitProc( hChildProcess );
i = LastRetCode ;
//
// this is added initially to support new network batch scripts
// but it can be used by any process.
//
// always set "=ExitCode" env. variable as string of 8 hex digits
// representing LastRetCode
_stprintf (szValEqExitCodeEnvVar, TEXT("%08X"), i);
SetEnvVar(szNameEqExitCodeEnvVar, szValEqExitCodeEnvVar, &CmdEnv);
// IF LastRetCode printable
// THEN set "=ExitCodeAscii" env. variable equal LastRetCode
// ELSE remove "=ExitCodeAscii" env. variable
if ( (i >= 0x20) && (i <= 0x7e) ) { // isprint
_stprintf (szValEqExitCodeAsciiEnvVar, TEXT("%01C"), i);
SetEnvVar(szNameEqExitCodeAsciiEnvVar, szValEqExitCodeAsciiEnvVar, &CmdEnv);
} else
SetEnvVar(szNameEqExitCodeAsciiEnvVar, TEXT("\0"), &CmdEnv);
#ifndef WIN95_CMD
if (VdmProcess) {
RestoreCurrentDirectories();
}
#endif // WIN95_CMD
}
/* If real async (discarding retcode), just print PID and return. If
* piped process (keeping retcode but not waiting) just store PID for
* ePipe and return SUCCESS from exec. Else, wait around for the return
* code before going back.
*/
if (ai == AI_DSCD) { /* DETach only */
if (!GuiProcess)
PutStdErr(MSG_PID_IS, ONEARG, argstr1(TEXT("%u"), HandleToUlong(hChildProcess)));
if (hChildProcess != NULL) {
CloseHandle( hChildProcess );
hChildProcess = NULL;
}
} else if (ai == AI_KEEP) { /* Async exec... */
if (wf == CW_W_YES) { /* ...normal type */
LastRetCode = WaitProc(hChildProcess);
i = LastRetCode ;
} else { /* Async exec... */
PipePid = hChildProcess ; /* M035 */
}
} else {
}
return (i) ; /* i == return from DOSEXECPGM */
}
/********************* START OF SPECIFICATION **************************/
/* */
/* SUBROUTINE NAME: SearchForExecutable */
/* */
/* DESCRIPTIVE NAME: Search for Executable File */
/* */
/* FUNCTION: This routine searches the specified executable file. */
/* If the file extension is specified, */
/* CMD.EXE searches for the file with the file extension */
/* to execute. If the specified file with the extension */
/* is not found, CMD.EXE will display an error message to */
/* indicate that the file is not found. */
/* If the file extension is not specified, */
/* CMD.EXE searches for the file with the order of these */
/* file extensions, .COM, .EXE, .CMD, and .BAT. */
/* The file which is found first will be executed. */
/* */
/* NOTES: 1) If a path is given, only the specified directory is */
/* searched. */
/* 2) If no path is given, the current directory of the */
/* drive specified is searched followed by the */
/* directories in the PATH environment variable. */
/* 3) If no executable file is found, an error message is */
/* printed. */
/* */
/* ENTRY POINT: SearchForExecutable */
/* LINKAGE: NEAR */
/* */
/* INPUT: */
/* n - parse tree node containing the command to be searched for */
/* loc - the string in which the location of the command is to be */
/* placed */
/* */
/* OUTPUT: None. */
/* */
/* EXIT-NORMAL: */
/* Returns: */
/* SFE_EXECOM, if a .EXE or .COM file is found. */
/* SFE_ISBAT, if a .CMD file is found. */
/* SFE_ISDIR, if a directory is found. */
/* SFE_NOTFND, if no executable file is found. */
/* */
/* EXIT-ERROR: */
/* Return FAILURE or */
/* SFE_FAIL, if out of memory. */
/* */
/* EFFECTS: None. */
/* */
/* INTERNAL REFERENCES: */
/* ROUTINES: */
/* DoFind - Find the specified file. */
/* GetEnvVar - Get full path. */
/* FullPath - build a full path name. */
/* TokStr - tokenize argument strings. */
/* mkstr - allocate space for a string. */
/* */
/* EXTERNAL REFERENCES: */
/* ROUTINES: */
/* None */
/* */
/********************** END OF SPECIFICATION **************************/
SearchForExecutable(n, loc)
struct cmdnode *n ;
TCHAR *loc ;
{
TCHAR *tokpath ;
TCHAR *extPath ;
TCHAR *extPathWrk ;
TCHAR *fname;
TCHAR *p1;
TCHAR *tmps01;
TCHAR *tmps02 = NULL;
TCHAR pcstr[3];
LONG BinaryType;
size_t cName; // number of characters in file name.
int tplen; // Length of the current tokpath token
int dotloc; // loc offset where extension is appended
int pcloc; // M014 - Flag. True=user had partial path
int addpchar; // True - append PathChar to string @@5g
TCHAR *j ;
TCHAR wrkcmdline[MAX_PATH] ;
unsigned tokpathlen;
//
// Test for name too long first. If it is, we avoid wasting time
//
p1 = StripQuotes( n->cmdline );
if ((cName = mystrlen(p1)) >= MAX_PATH) {
DosErr = MSG_LINES_TOO_LONG;
return(SFE_NOTFND) ;
}
//
// If cmd extensions enable, then treat CMD without an extension
// or path as a reference to COMSPEC variable. Guarantees we dont
// get a random copy of CMD.EXE
//
if (fEnableExtensions && (p1 == NULL || !_tcsnicmp( p1, TEXT( "cmd " ), 4))) {
p1 = GetEnvVar( ComSpecStr );
if (p1 == NULL) {
DosErr = MSG_INVALID_COMSPEC;
return SFE_NOTFND;
}
}
mytcsnset(wrkcmdline, NULLC, MAX_PATH);
mystrcpy(wrkcmdline, p1);
FixPChar( wrkcmdline, SwitChar );
//
// Create the path character string, this will be search string
//
pcstr[0] = PathChar;
pcstr[1] = COLON;
pcstr[2] = NULLC;
//
// The variable pcloc is used as a flag to indicate whether the user
// did or didn't specify a drive or a partial path in his original
// input. It will be NZ if drive or path was specified.
//
pcloc = ((mystrcspn(wrkcmdline,pcstr)) < cName) ;
pcstr[1] = NULLC ; // Fixup pathchar string
//
// handle the case of the user typing in a file name of
// ".", "..", or ending in "\"
// pcloc true say string has to have either a pathchar or colon
//
if ( pcloc ) {
if (!(p1 = mystrrchr( wrkcmdline, PathChar ))) {
p1 = mystrchr( wrkcmdline, COLON );
}
p1++; // move to terminator if hanging ":" or "\"
} else {
p1 = wrkcmdline;
}
//
// p1 is guaranteed to be non-zero
//
if ( !(*p1) || !_tcscmp( p1, TEXT(".") ) || !_tcscmp( p1, TEXT("..") ) ) {
//
// If CMD.EXE extensions enable, see if name matches
// subdirectory name.
//
if (fEnableExtensions) {
DWORD dwFileAttributes;
dwFileAttributes = GetFileAttributes( loc );
if (dwFileAttributes != 0xFFFFFFFF &&
(dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0
) {
return(SFE_ISDIR);
}
}
DosErr = MSG_DIR_BAD_COMMAND_OR_FILE;
return(SFE_NOTFND) ;
}
if (!(tmps01 = mkstr(2*sizeof(TCHAR)*MAX_PATH))) {
DosErr = ERROR_NOT_ENOUGH_MEMORY;
return(SFE_FAIL) ;
}
//
// Handle the case of file..ext on a fat drive
//
mystrcpy( loc, wrkcmdline );
loc[ &p1[0] - &wrkcmdline[0] ] = 0;
mystrcat( loc, TEXT(".") );
//
// Check for a malformed name
//
if (FullPath(tmps01, loc,MAX_PATH*2)) {
//
// If CMD.EXE extensions enable, see if name matches
// subdirectory name.
//
if (fEnableExtensions) {
DWORD dwFileAttributes;
dwFileAttributes = GetFileAttributes( loc );
if (dwFileAttributes != 0xFFFFFFFF &&
(dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0
) {
return(SFE_ISDIR);
}
}
DosErr = MSG_DIR_BAD_COMMAND_OR_FILE;
return(SFE_NOTFND);
}
if ( *lastc(tmps01) != PathChar ) {
mystrcat( tmps01, TEXT("\\") );
}
//
// tmps01 contains full path + file name
//
mystrcat( tmps01, p1 );
tmps01 = resize(tmps01, (mystrlen(tmps01)+1)*sizeof(TCHAR)) ;
if (tmps01 == NULL) {
DosErr = ERROR_NOT_ENOUGH_MEMORY;
return( SFE_FAIL ) ;
}
//
// fname will point to last '\'
// tmps01 is to be path and fname is to be name
//
fname = mystrrchr(tmps01,PathChar) ;
*fname++ = NULLC ;
DEBUG((DBENV, DBENVSCAN, "SearchForExecutable: Command:%ws",fname));
//
// If only fname type in get path string
//
if (!pcloc) {
tmps02 = GetEnvVar(PathStr) ;
}
DEBUG((DBENV, DBENVSCAN, "SearchForExecutable: PATH:%ws",tmps02));
//
// tmps02 is PATH environment variable
// compute enough for PATH environment plus file default path
//
tokpath = mkstr( (2 + mystrlen(tmps01) + mystrlen(tmps02) + 2)*sizeof(TCHAR)) ;
if ( ! tokpath ) {
DosErr = ERROR_NOT_ENOUGH_MEMORY;
return( SFE_FAIL ) ;
}
//
// Copy default path
//
mystrcat(tokpath,TEXT("\""));
mystrcat(tokpath,tmps01) ;
mystrcat(tokpath,TEXT("\""));
//
// If only name type in get also delim and path string
//
if (!pcloc) {
mystrcat(tokpath, TEXT(";")) ;
mystrcat(tokpath,tmps02) ;
}
//
// Shift left string at ';;'
//
tokshrink(tokpath);
tokpath = TokStr(tokpath, TEXT(";"), TS_WSPACE) ;
cName = mystrlen(fname) + 1 ; // file spec. length
//
// Build up the list of extensions we are going to search
// for. If extensions are enabled, get the list from the PATHEXT
// variable, otherwise use the hard coded default.
//
extPath = NULL;
if (fEnableExtensions)
extPath = GetEnvVar(PathExtStr);
if (extPath == NULL)
extPath = PathExtDefaultStr;
tokshrink(extPath);
extPath = TokStr(extPath, TEXT(";"), TS_WSPACE) ;
//
// Everything is now set up. Var tokpath contains a sequential series
// of asciz strings terminated by an extra null. If the user specified
// a drive or partial path, it contains only that one converted to full
// root-based form. If the user typed only a filename (pcloc = 0) it
// begins with the current directory and contains each directory that
// was contained in the PATH variable. This loop will search each of
// the tokpath elements once for each possible executable extention.
// Note that 'i' is used as a constant to test for excessive string
// length prior to performing the string copies.
//
for ( ; ; ) {
//
// Length of current path
//
tplen = mystrlen(tokpath) ;
mystrcpy( tokpath, StripQuotes( tokpath ) );
tokpathlen = mystrlen(tokpath);
if (*lastc(tokpath) != PathChar) {
addpchar = TRUE;
tplen++;
tokpathlen++;
} else {
addpchar = FALSE;
}
/* path + name too long */
//
// Check if path + name is too long
//
if (*tokpath && (tokpathlen + cName) > MAX_PATH) {
tokpath += addpchar ? tplen : tplen+1; // get next path
continue;
}
//
// If no more paths to search return descriptive error
//
if (*(tokpath) == NULLC) {
if (pcloc) {
if (DosErr == 0 || DosErr == ERROR_FILE_NOT_FOUND)
DosErr = MSG_DIR_BAD_COMMAND_OR_FILE;
} else { /* return generic message */
DosErr = MSG_DIR_BAD_COMMAND_OR_FILE;
}
return(SFE_NOTFND) ;
}
//
// Install this path and setup for next one
//
mystrcpy(loc, tokpath) ;
tokpath += addpchar ? tplen : tplen+1;
if (addpchar) {
mystrcat(loc, pcstr) ;
}
mystrcat(loc, fname) ;
mystrcpy(loc, StripQuotes(loc) );
dotloc = mystrlen(loc) ;
DEBUG((DBENV, DBENVSCAN, "SearchForExecutable: PATH:%ws",loc));
//
// Check drive in each path to insure it is valid before searching
//
if (*(loc+1) == COLON) {
if (!IsValidDrv(*loc))
continue ;
};
//
// If fname has ext & ext > "." look for given filename
// this says that all executable files must have an extension
//
j = mystrrchr( fname, DOT );
if ( j && j[1] ) {
//
// If access was denied and the user included a path,
// then say we found it. This handles the case where
// we don't have permission to do the findfirst and so we
// can't see the binary, but it actually exists -- if we
// have execute permission, CreateProcess will work
// just fine.
//
if (exists_ex(loc,TRUE) || (pcloc && (DosErr == ERROR_ACCESS_DENIED))) {
//
// Recompute j as exists_ex trims trailing spaces
//
j = mystrrchr( loc, DOT );
if (j != NULL) {
if ( !_tcsicmp(j,CmdExt) ) {
return(SFE_ISBAT) ;
} else if ( !_tcsicmp(j,BatExt) ) {
return(SFE_ISBAT) ;
} else {
return(SFE_ISEXECOM) ;
}
}
}
if ((DosErr != ERROR_FILE_NOT_FOUND) && DosErr)
continue; // Try next path
}
if (mystrchr( fname, STAR ) || mystrchr( fname, QMARK ) ) {
DosErr = MSG_DIR_BAD_COMMAND_OR_FILE;
return(SFE_NOTFND);
}
//
// Search for each type of extension
//
extPathWrk = extPath;
if (DoFind(loc, dotloc, TEXT(".*"), FALSE)) // Found anything?
while (*extPathWrk) {
//
// if name + path + ext is less then max path length
//
if ( (cName + tokpathlen + mystrlen(extPathWrk)) <= MAX_PATH) {
//
// See if this extension is a match.
//
if (DoFind(loc, dotloc, extPathWrk, TRUE)) {
if (!_tcsicmp(extPathWrk, BatExt) || !_tcsicmp(extPathWrk, CmdExt))
return(SFE_ISBAT) ; // found .bat or .cmd
else
return(SFE_ISEXECOM) ; // found executable
} else {
//
// Any kind of error other than file not found, bail from
// search and try next element in path
//
if ((DosErr != ERROR_FILE_NOT_FOUND) && DosErr)
break;
}
}
//
// Not this extension, try next.
while (*extPathWrk++)
;
}
//
// If we get here, then no match with list of extensions.
// If no wierd errors, deal with NUll extension case.
//
if (DosErr == NO_ERROR || DosErr == ERROR_FILE_NOT_FOUND) {
if (DoFind(loc, dotloc, TEXT("\0"), TRUE)) {
if (GetBinaryType(loc,&BinaryType) &&
BinaryType == SCS_POSIX_BINARY) { // Found .
return(SFE_ISEXECOM) ;
}
}
}
} // end for
return(SFE_NOTFND);
}
/*** DoFind - does indiviual findfirsts during searching
*
* Purpose:
* Add the extension to loc and do the find first for
* SearchForExecutable().
*
* DoFind(TCHAR *loc, int dotloc, TCHAR *ext)
*
* Args:
* loc - the string in which the location of the command is to be placed
* dotloc - the location loc at which the extension is to be appended
* ext - the extension to append to loc
*
* Returns:
* 1 if the file is found.
* 0 if the file isn't found.
*
*/
int DoFind(loc, dotloc, ext, metas)
TCHAR *loc ;
int dotloc ;
TCHAR *ext ;
BOOL metas;
{
*(loc+dotloc) = NULLC ;
mystrcat(loc, ext) ;
DEBUG((DBENV, DBENVSCAN, "DoFind: exists_ex(%ws)",loc));
return(exists_ex(loc,metas)) ; /*@@4*/
}
/*** ExecError - handles exec errors
*
* Purpose:
* Print the exec error message corresponding to the error number in the
* global variable DosErr.
* @@ lots of error codes added.
* ExecError()
*
*/
void ExecError( onb )
TCHAR *onb;
{
unsigned int errmsg;
unsigned int count;
count = ONEARG;
switch (DosErr) {
case ERROR_BAD_DEVICE:
errmsg = MSG_DIR_BAD_COMMAND_OR_FILE;
count = NOARGS;
break;
case ERROR_LOCK_VIOLATION:
errmsg = ERROR_SHARING_VIOLATION;
break ;
case ERROR_NO_PROC_SLOTS:
errmsg = ERROR_NO_PROC_SLOTS;
count = NOARGS;
break ;
case ERROR_NOT_DOS_DISK:
errmsg = ERROR_NOT_DOS_DISK;
break ;
case ERROR_NOT_ENOUGH_MEMORY:
errmsg = ERROR_NOT_ENOUGH_MEMORY;
count = NOARGS;
break ;
case ERROR_PATH_NOT_FOUND:
errmsg = MSG_CMD_FILE_NOT_FOUND;
break ;
case ERROR_FILE_NOT_FOUND:
errmsg = MSG_CMD_FILE_NOT_FOUND;
break ;
case ERROR_ACCESS_DENIED:
errmsg = ERROR_ACCESS_DENIED;
break ;
case ERROR_EXE_MACHINE_TYPE_MISMATCH:
errmsg = ERROR_EXE_MACHINE_TYPE_MISMATCH;
break;
case ERROR_DRIVE_LOCKED:
errmsg = ERROR_DRIVE_LOCKED;
break ;
case ERROR_INVALID_STARTING_CODESEG:
errmsg = ERROR_INVALID_STARTING_CODESEG;
break ;
case ERROR_INVALID_STACKSEG:
errmsg = ERROR_INVALID_STACKSEG;
break ;
case ERROR_INVALID_MODULETYPE:
errmsg = ERROR_INVALID_MODULETYPE;
break ;
case ERROR_INVALID_EXE_SIGNATURE:
errmsg = ERROR_INVALID_EXE_SIGNATURE;
break ;
case ERROR_EXE_MARKED_INVALID:
errmsg = ERROR_EXE_MARKED_INVALID;
break ;
case ERROR_BAD_EXE_FORMAT:
errmsg = ERROR_BAD_EXE_FORMAT;
break ;
case ERROR_INVALID_MINALLOCSIZE:
errmsg = ERROR_INVALID_MINALLOCSIZE;
break ;
case ERROR_SHARING_VIOLATION:
errmsg = ERROR_SHARING_VIOLATION;
break ;
case ERROR_BAD_ENVIRONMENT:
errmsg = ERROR_INFLOOP_IN_RELOC_CHAIN;
count = NOARGS;
break ;
case ERROR_INVALID_ORDINAL:
errmsg = ERROR_INVALID_ORDINAL;
break ;
case ERROR_CHILD_NOT_COMPLETE:
errmsg = ERROR_CHILD_NOT_COMPLETE;
break ;
case ERROR_DIRECTORY:
errmsg = MSG_BAD_CURDIR;
count = NOARGS;
break;
case ERROR_NOT_ENOUGH_QUOTA:
errmsg = ERROR_NOT_ENOUGH_QUOTA;
count = NOARGS;
break;
case MSG_REAL_MODE_ONLY:
errmsg = MSG_REAL_MODE_ONLY;
count = NOARGS;
break ;
default:
// printf( "Exec failed code %x\n", DosErr );
count = NOARGS;
errmsg = MSG_EXEC_FAILURE ; /* M031 */
}
LastRetCode = errmsg;
PutStdErr(errmsg, count, onb );
}
/*
* tokshrink @@4
*
* remove duplicate ';' in a path
*/
void tokshrink( tokpath )
TCHAR *tokpath;
{
int i, j;
i = 0;
do {
if ( tokpath[i] == QUOTE ) {
do {
i++;
} while ( tokpath[i] && tokpath[i] != QUOTE );
}
if ( tokpath[i] && tokpath[i] != TEXT(';') ) {
i++;
}
if ( tokpath[i] == TEXT(';') ) {
j = i;
while ( tokpath[j+1] == TEXT(';') ) {
j++;
}
if ( j > i ) {
mystrcpy( &tokpath[i], &tokpath[j] );
}
i++;
}
} while ( tokpath[i] );
}
/*** eAssoc - execute an Assoc command
*
* Purpose:
* To set/modify the file associations stored in the registry under the
* HKEY_LOCAL_MACHINE\Software\Classes key
*
* int eAssoc(struct cmdnode *n)
*
* Args:
* n - the parse tree node containing the set command
*
* Returns:
* If setting and the command is syntactically correct, whatever SetAssoc()
* returns. Otherwise, FAILURE.
*
* If displaying, SUCCESS is always returned.
*
*/
int eAssoc(n)
struct cmdnode *n ;
{
if (glBatType != CMD_TYPE) {
// if set command is executed from .bat file OR entered at command prompt
return( SetLastRetCodeIfError(AssocWork( n )));
}
else {
return( LastRetCode = AssocWork( n ) );
}
}
int AssocWork(n)
struct cmdnode *n ;
{
HKEY hKeyClasses;
TCHAR *tas ; /* Tokenized argument string */
TCHAR *wptr ; /* Work pointer */
int i ; /* Work variable */
int rc ;
rc = RegOpenKey(HKEY_LOCAL_MACHINE, TEXT("Software\\Classes"), &hKeyClasses);
if (rc) {
return rc;
}
tas = TokStr(n->argptr, ONEQSTR, TS_WSPACE|TS_SDTOKENS) ;
if (!*tas)
rc = DisplayAssoc(hKeyClasses, NULL) ;
else {
for (wptr = tas, i = 0 ; *wptr ; wptr += mystrlen(wptr)+1, i++)
;
/* If too many parameters were given, the second parameter */
/* wasn't an equal sign, or they didn't specify a string */
/* return an error message. */
if ( i > 3 || *(wptr = tas+mystrlen(tas)+1) != EQ ||
!mystrlen(mystrcpy(tas, StripQuotes(tas))) ) {
if (i==1) {
rc =DisplayAssoc(hKeyClasses, tas);
} else {
PutStdErr(MSG_BAD_SYNTAX, NOARGS);
rc = FAILURE ;
}
} else {
rc = SetAssoc(hKeyClasses, tas, wptr+2) ;
}
} ;
RegCloseKey(hKeyClasses) ;
return rc;
}
/*** DisplayAssoc - display a specific file association or all
*
* Purpose:
* To display a specific file association or all
*
* int DisplayAssoc( hKeyClasses, tas )
*
* Returns:
* SUCCESS if all goes well
* FAILURE if it runs out of memory or cannot lock the env. segment
*/
int DisplayAssoc(hKeyClasses, tas)
HKEY hKeyClasses;
TCHAR *tas;
{
int i;
int rc = SUCCESS;
TCHAR NameBuffer[MAX_PATH];
TCHAR ValueBuffer[MAX_PATH];
TCHAR *vstr ;
DWORD cb;
if (tas == NULL) {
for (i=0 ; rc == SUCCESS ; i++) {
rc =RegEnumKey(hKeyClasses, i, NameBuffer, sizeof( NameBuffer ) / sizeof( TCHAR ));
if (rc != 0) {
if (rc==ERROR_NO_MORE_ITEMS)
rc = SUCCESS;
break;
} else
if (NameBuffer[0] == DOT) {
cb = sizeof(ValueBuffer);
rc = RegQueryValue(hKeyClasses, NameBuffer, ValueBuffer, &cb);
if (rc != 0) {
break;
}
rc = cmd_printf(Fmt16, NameBuffer, ValueBuffer);
}
if (CtrlCSeen) {
return(FAILURE);
}
}
}
else {
tas = EatWS(tas, NULL);
if ((vstr = mystrrchr(tas, ' ')) != NULL)
*vstr = NULLC;
cb = sizeof(ValueBuffer);
rc = RegQueryValue(hKeyClasses, tas, ValueBuffer, &cb);
if (rc == 0)
rc = cmd_printf(Fmt16, tas, ValueBuffer);
else
PutStdErr(MSG_ASSOC_NOT_FOUND, ONEARG, tas);
}
return(rc);
}
/*** SetAssoc - controls adding/changing a file association
*
* Purpose:
* Add/replace a file association
*
* int SetAssoc(HKEY hKeyClasses, TCHAR *fileext, TCHAR *filetype)
*
* Args:
* hKeyClasses - handle to HKEY_LOCAL_MACHINE\Software\Classes key
* fileext - file extension string to associate
* filetype - file type associate
*
* Returns:
* SUCCESS if the association could be added/replaced.
* FAILURE otherwise.
*
*/
int SetAssoc(hKeyClasses, fileext, filetype)
HKEY hKeyClasses;
TCHAR *fileext ;
TCHAR *filetype ;
{
int rc;
int i;
DWORD cb;
if (filetype==NULL || *filetype==NULLC) {
rc = RegDeleteKey(hKeyClasses, fileext);
if (rc != 0)
PutStdErr(MSG_ASSOC_NOT_FOUND, ONEARG, fileext);
}
else {
rc = RegSetValue(hKeyClasses, fileext, REG_SZ, filetype, _tcslen(filetype));
if (rc == 0) {
try {
SHChangeNotify( SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL );
cmd_printf( Fmt16, fileext, filetype );
} except (DosErr = GetExceptionCode( ), EXCEPTION_EXECUTE_HANDLER) {
}
}
else
PutStdErr(MSG_ERR_PROC_ARG, ONEARG, fileext);
}
return rc;
}
/*** eFType - execute an FType command
*
* Purpose:
* To set/modify the file types stored in the registry under the
* HKEY_LOCAL_MACHINE\Software\Classes key
*
* int eFType(struct cmdnode *n)
*
* Args:
* n - the parse tree node containing the set command
*
* Returns:
* If setting and the command is syntactically correct, whatever SetFType()
* returns. Otherwise, FAILURE.
*
* If displaying, SUCCESS is always returned.
*
*/
int eFType(n)
struct cmdnode *n ;
{
if (glBatType != CMD_TYPE) {
// if set command is executed from .bat file OR entered at command prompt
return( SetLastRetCodeIfError(FTypeWork( n )));
}
else {
return( LastRetCode = FTypeWork( n ) );
}
}
int FTypeWork(n)
struct cmdnode *n ;
{
HKEY hKeyClasses;
TCHAR *tas ; /* Tokenized argument string */
TCHAR *wptr ; /* Work pointer */
int i ; /* Work variable */
int rc ;
rc = RegOpenKey(HKEY_LOCAL_MACHINE, TEXT("Software\\Classes"), &hKeyClasses);
if (rc) {
return rc;
}
tas = TokStr(n->argptr, ONEQSTR, TS_WSPACE|TS_SDTOKENS) ;
if (!*tas)
rc = DisplayFType(hKeyClasses, NULL) ;
else {
for (wptr = tas, i = 0 ; *wptr ; wptr += mystrlen(wptr)+1, i++)
;
/* If too many parameters were given, the second parameter */
/* wasn't an equal sign, or they didn't specify a string */
/* return an error message. */
if ( i > 3 || *(wptr = tas+mystrlen(tas)+1) != EQ ||
!mystrlen(mystrcpy(tas, StripQuotes(tas))) ) {
if (i==1) {
rc =DisplayFType(hKeyClasses, tas);
} else {
PutStdErr(MSG_BAD_SYNTAX, NOARGS);
rc = FAILURE ;
}
} else {
rc = SetFType(hKeyClasses, tas, wptr+2) ;
}
} ;
RegCloseKey(hKeyClasses) ;
return rc;
}
/*** DisplayFType - display a specific file type or all
*
* Purpose:
* To display a specific file type or all
*
* int DisplayFType( hKeyClasses, tas )
*
* Returns:
* SUCCESS if all goes well
* FAILURE if it runs out of memory or cannot lock the env. segment
*/
int DisplayFType(hKeyClasses, tas)
HKEY hKeyClasses;
TCHAR *tas;
{
int i;
int rc;
HKEY hKeyOpenCmd;
TCHAR NameBuffer[MAX_PATH];
TCHAR ValueBuffer[MAX_PATH];
TCHAR *vstr ;
DWORD cb, j, Type;
if (tas == NULL) {
for (i=0;;i++) {
rc =RegEnumKey(hKeyClasses, i, NameBuffer, sizeof( NameBuffer ) / sizeof( TCHAR ));
if (rc != 0) {
if (rc==ERROR_NO_MORE_ITEMS)
rc = SUCCESS;
break;
} else
if (NameBuffer[0] != DOT) {
j = _tcslen(NameBuffer);
_tcscat(NameBuffer, TEXT("\\Shell\\Open\\Command"));
_tcscpy(ValueBuffer,TEXT("*** no open command defined ***"));
rc = RegOpenKey(hKeyClasses, NameBuffer, &hKeyOpenCmd);
if (!rc) {
NameBuffer[j] = TEXT('\0');
cb = sizeof(ValueBuffer);
rc = RegQueryValueEx(hKeyOpenCmd, TEXT(""), NULL, &Type, (LPBYTE)ValueBuffer, &cb);
RegCloseKey(hKeyOpenCmd);
}
if (!rc) {
cmd_printf(Fmt16, NameBuffer, ValueBuffer);
}
}
if (CtrlCSeen) {
return(FAILURE);
}
}
}
else {
if (*tas == DOT) {
PutStdErr(MSG_FTYPE_NOT_FOUND, ONEARG, tas);
return ERROR_INVALID_NAME;
}
tas = EatWS(tas, NULL);
if ((vstr = mystrrchr(tas, ' ')) != NULL)
*vstr = NULLC;
_sntprintf(NameBuffer, MAX_PATH, TEXT("%s\\Shell\\Open\\Command"), tas);
rc = RegOpenKey(hKeyClasses, NameBuffer, &hKeyOpenCmd);
if (rc) {
PutStdErr(MSG_FTYPE_NOT_FOUND, ONEARG, tas);
return rc;
}
cb = sizeof(ValueBuffer);
rc = RegQueryValueEx(hKeyOpenCmd, TEXT(""), NULL, &Type, (LPBYTE)ValueBuffer, &cb);
if (rc == 0) {
ValueBuffer[ (cb / sizeof( TCHAR )) - 1 ];
cmd_printf(Fmt16, tas, ValueBuffer);
}
else
PutStdErr(MSG_FTYPE_NOT_FOUND, ONEARG, tas);
}
return(rc);
}
/*** SetFType - controls adding/changing the open command associated with a file type
*
* Purpose:
* Add/replace an open command string associated with a file type
*
* int SetFType(HKEY hKeyOpenCmd, TCHAR *filetype TCHAR *opencmd)
*
* Args:
* hKeyClasses - handle to HKEY_LOCAL_MACHINE\Software\Classes
* filetype - file type name
* opencmd - open command string
*
* Returns:
* SUCCESS if the file type could be added/replaced.
* FAILURE otherwise.
*
*/
int SetFType(hKeyClasses, filetype, opencmd)
HKEY hKeyClasses;
TCHAR *filetype ;
TCHAR *opencmd ;
{
HKEY hKeyOpenCmd;
TCHAR NameBuffer[MAX_PATH];
TCHAR c, *s;
DWORD Disposition;
int rc;
int i;
DWORD cb;
_sntprintf(NameBuffer, MAX_PATH, TEXT("%s\\Shell\\Open\\Command"), filetype);
rc = RegOpenKey(hKeyClasses, NameBuffer, &hKeyOpenCmd);
if (rc) {
if (opencmd==NULL || *opencmd==NULLC) {
PutStdErr(MSG_FTYPE_NOT_FOUND, ONEARG, filetype);
return rc;
}
s = NameBuffer;
while (TRUE) {
while (*s && *s != TEXT('\\')) {
s += 1;
}
c = *s;
*s = TEXT('\0');
rc = RegCreateKeyEx(hKeyClasses,
NameBuffer,
0,
NULL,
0,
(REGSAM)MAXIMUM_ALLOWED,
NULL,
&hKeyOpenCmd,
&Disposition
);
if (rc) {
PutStdErr(MSG_FTYPE_NOT_FOUND, ONEARG, filetype);
return rc;
}
if (c == TEXT('\0')) {
break;
}
*s++ = c;
RegCloseKey(hKeyOpenCmd);
}
}
if (opencmd==NULL || *opencmd==NULLC) {
rc = RegDeleteKey(hKeyOpenCmd, NULL);
if (rc != 0)
PutStdErr(MSG_FTYPE_NOT_FOUND, ONEARG, filetype);
}
else {
rc = RegSetValueEx(hKeyOpenCmd, TEXT(""), 0, REG_EXPAND_SZ, (LPBYTE)opencmd, (_tcslen(opencmd)+1)*sizeof(TCHAR));
if (rc == 0)
cmd_printf(Fmt16, filetype, opencmd);
else
PutStdErr(MSG_ERR_PROC_ARG, ONEARG, filetype);
}
RegCloseKey(hKeyOpenCmd);
return rc;
}
typedef
NTSTATUS
(NTAPI *PNTQUERYINFORMATIONPROCESS)(
IN HANDLE ProcessHandle,
IN PROCESSINFOCLASS ProcessInformationClass,
OUT PVOID ProcessInformation,
IN ULONG ProcessInformationLength,
OUT PULONG ReturnLength OPTIONAL
);
HMODULE hNtDllModule;
PNTQUERYINFORMATIONPROCESS lpNtQueryInformationProcess;
WORD
GetProcessSubsystemType(
HANDLE hProcess
)
{
PIMAGE_NT_HEADERS NtHeader;
PPEB PebAddress;
PEB Peb;
SIZE_T SizeOfPeb;
NTSTATUS Status;
PROCESS_BASIC_INFORMATION ProcessInfo;
BOOL b;
PVOID ImageBaseAddress;
LONG e_lfanew;
WORD Subsystem;
Subsystem = IMAGE_SUBSYSTEM_UNKNOWN;
if (hNtDllModule == NULL) {
hNtDllModule = LoadLibrary( TEXT("NTDLL.DLL") );
if (hNtDllModule != NULL) {
lpNtQueryInformationProcess = (PNTQUERYINFORMATIONPROCESS)
GetProcAddress( hNtDllModule,
"NtQueryInformationProcess"
);
}
else {
hNtDllModule = INVALID_HANDLE_VALUE;
}
}
if (lpNtQueryInformationProcess != NULL) {
//
// Get the Peb address
//
Status = (*lpNtQueryInformationProcess)( hProcess,
ProcessBasicInformation,
&ProcessInfo,
sizeof( ProcessInfo ),
NULL
);
if (NT_SUCCESS( Status )) {
PebAddress = ProcessInfo.PebBaseAddress;
//
// Read the subsystem type from the Peb
//
if (ReadProcessMemory( hProcess,
PebAddress,
&Peb,
sizeof( Peb ),
&SizeOfPeb
)
) {
//
// See if we are running on a system that has the image subsystem
// type captured in the PEB. If so use it. Otherwise go the slow
// way and try to get it from the image header.
//
if (SizeOfPeb >= FIELD_OFFSET( PEB, ImageSubsystem ) &&
((UINT_PTR)Peb.ProcessHeaps - (UINT_PTR)PebAddress) > FIELD_OFFSET( PEB, ImageSubsystem )
) {
Subsystem = (WORD)Peb.ImageSubsystem;
}
else {
//
// read e_lfanew from imageheader
//
if (ReadProcessMemory( hProcess,
&((PIMAGE_DOS_HEADER)Peb.ImageBaseAddress)->e_lfanew,
&e_lfanew,
sizeof( e_lfanew ),
NULL
)
) {
//
// Read subsystem version info
//
NtHeader = (PIMAGE_NT_HEADERS)((PUCHAR)Peb.ImageBaseAddress + e_lfanew);
if (ReadProcessMemory( hProcess,
&NtHeader->OptionalHeader.Subsystem,
&Subsystem,
sizeof( Subsystem ),
NULL
)
) {
}
}
}
}
}
}
return Subsystem;
}