Tcl Source Code

Artifact [1b59f49daf]
Login

Artifact 1b59f49dafa5a190c778b03592030414be228c15:

Attachment "noGUIexec.txt" to ticket [469618ffff] added by davygrvy 2001-10-10 10:52:31.
Index: tclWinPipe.c
===================================================================
RCS file: /cvsroot/tcl/tcl/win/tclWinPipe.c,v
retrieving revision 1.20
diff -c -r1.20 tclWinPipe.c
*** tclWinPipe.c	2001/09/06 01:38:02	1.20
--- tclWinPipe.c	2001/10/10 03:48:37
***************
*** 41,47 ****
  #define APPL_NONE	0
  #define APPL_DOS	1
  #define APPL_WIN3X	2
! #define APPL_WIN32	3
  
  /*
   * The following constants and structures are used to encapsulate the state
--- 41,48 ----
  #define APPL_NONE	0
  #define APPL_DOS	1
  #define APPL_WIN3X	2
! #define APPL_WIN32CUI	3
! #define APPL_WIN32GUI	4
  
  /*
   * The following constants and structures are used to encapsulate the state
***************
*** 927,934 ****
   *
   *	The complete Windows search path is searched to find the specified 
   *	executable.  If an executable by the given name is not found, 
!  *	automatically tries appending ".com", ".exe", and ".bat" to the 
!  *	executable name.
   *
   * Results:
   *	The return value is TCL_ERROR and an error message is left in
--- 928,935 ----
   *
   *	The complete Windows search path is searched to find the specified 
   *	executable.  If an executable by the given name is not found, 
!  *	automatically tries appending ".com", ".exe", ".bat", and ".cmd" 
!  *	to the executable name.
   *
   * Results:
   *	The return value is TCL_ERROR and an error message is left in
***************
*** 986,991 ****
--- 987,998 ----
      applType = ApplicationType(interp, argv[0], execPath);
      if (applType == APPL_NONE) {
  	return TCL_ERROR;
+     } else if (applType == APPL_WIN32GUI) {
+ 	TclWinConvertError(ERROR_BAD_PIPE);
+ 	Tcl_AppendResult(interp, execPath,
+ 		" is a GUI application that doesn't support pipes: ",
+ 		Tcl_PosixError(interp), (char *) NULL);
+ 	return TCL_ERROR;
      }
  
      result = TCL_ERROR;
***************
*** 1356,1368 ****
      HANDLE hFile;
      TCHAR *rest;
      char *ext;
-     char buf[2];
      DWORD attr, read;
!     IMAGE_DOS_HEADER header;
      Tcl_DString nameBuf, ds;
      TCHAR *nativeName;
      WCHAR nativeFullPath[MAX_PATH];
!     static char extensions[][5] = {"", ".com", ".exe", ".bat"};
  
      /* Look for the program as an external program.  First try the name
       * as it is, then try adding .com, .exe, and .bat, in that order, to
--- 1363,1380 ----
      HANDLE hFile;
      TCHAR *rest;
      char *ext;
      DWORD attr, read;
!     IMAGE_DOS_HEADER p236;  /* p236, DOS (old-style) executable-file header */
!     union {
! 	BYTE buf[200];
! 	IMAGE_NT_HEADERS pe;
! 	IMAGE_OS2_HEADER ne;
! 	IMAGE_VXD_HEADER le;
!     } header;
      Tcl_DString nameBuf, ds;
      TCHAR *nativeName;
      WCHAR nativeFullPath[MAX_PATH];
!     static char extensions[][5] = {"", ".com", ".exe", ".bat", ".cmd"};
  
      /* Look for the program as an external program.  First try the name
       * as it is, then try adding .com, .exe, and .bat, in that order, to
***************
*** 1407,1413 ****
  	Tcl_DStringFree(&ds);
  
  	ext = strrchr(fullName, '.');
! 	if ((ext != NULL) && (stricmp(ext, ".bat") == 0)) {
  	    applType = APPL_DOS;
  	    break;
  	}
--- 1419,1426 ----
  	Tcl_DStringFree(&ds);
  
  	ext = strrchr(fullName, '.');
! 	if ((ext != NULL) && (stricmp(ext, ".bat") == 0 ||
! 		stricmp(ext, ".cmd") == 0)) {
  	    applType = APPL_DOS;
  	    break;
  	}
***************
*** 1419,1427 ****
  	    continue;
  	}
  
! 	header.e_magic = 0;
! 	ReadFile(hFile, (void *) &header, sizeof(header), &read, NULL);
! 	if (header.e_magic != IMAGE_DOS_SIGNATURE) {
  	    /* 
  	     * Doesn't have the magic number for relocatable executables.  If 
  	     * filename ends with .com, assume it's a DOS application anyhow.
--- 1432,1440 ----
  	    continue;
  	}
  
! 	p236.e_magic = 0;
! 	ReadFile(hFile, &p236, sizeof(IMAGE_DOS_HEADER), &read, NULL);
! 	if (p236.e_magic != IMAGE_DOS_SIGNATURE) {
  	    /* 
  	     * Doesn't have the magic number for relocatable executables.  If 
  	     * filename ends with .com, assume it's a DOS application anyhow.
***************
*** 1430,1435 ****
--- 1443,1467 ----
  	     * magic numbers and everything.  
  	     */
  
+ 	    /*
+ 	     * Additional notes from Ralf Brown's interupt list:
+ 	     *
+ 	     * The COM files are raw binary executables and are a leftover
+ 	     * from the old CP/M machines with 64K RAM.  A COM program can
+ 	     * only have a size of less than one segment (64K), including code
+ 	     * and static data since no fixups for segment relocation or
+ 	     * anything else is included. One method to check for a COM file
+ 	     * is to check if the first byte in the file could be a valid jump
+ 	     * or call opcode, but this is a very weak test since a COM file
+ 	     * is not required to start with a jump or a call. In principle,
+ 	     * a COM file is just loaded at offset 100h in the segment and
+ 	     * then executed.
+ 	     *
+ 	     * OFFSET              Count TYPE   Description
+ 	     * 0000h                   1 byte   ID=0E9h
+ 	     *                                  ID=0EBh
+ 	     */
+ 
  	    CloseHandle(hFile);
  	    if ((ext != NULL) && (strcmp(ext, ".com") == 0)) {
  		applType = APPL_DOS;
***************
*** 1437,1447 ****
  	    }
  	    continue;
  	}
! 	if (header.e_lfarlc != sizeof(header)) {
  	    /* 
! 	     * All Windows 3.X and Win32 and some DOS programs have this value
! 	     * set here.  If it doesn't, assume that since it already had the 
! 	     * other magic number it was a DOS application.
  	     */
  
  	    CloseHandle(hFile);
--- 1469,1477 ----
  	    }
  	    continue;
  	}
! 	if (p236.e_lfarlc < 0x40 || p236.e_lfanew == 0 /* reserved */) {
  	    /* 
! 	     * Old-style header only.  Can't be more than a DOS executable.
  	     */
  
  	    CloseHandle(hFile);
***************
*** 1450,1474 ****
  	}
  
  	/* 
! 	 * The DWORD at header.e_lfanew points to yet another magic number.
  	 */
! 
! 	buf[0] = '\0';
! 	SetFilePointer(hFile, header.e_lfanew, NULL, FILE_BEGIN);
! 	ReadFile(hFile, (void *) buf, 2, &read, NULL);
  	CloseHandle(hFile);
  
! 	if ((buf[0] == 'N') && (buf[1] == 'E')) {
! 	    applType = APPL_WIN3X;
! 	} else if ((buf[0] == 'P') && (buf[1] == 'E')) {
! 	    applType = APPL_WIN32;
  	} else {
  	    /*
! 	     * Strictly speaking, there should be a test that there
! 	     * is an 'L' and 'E' at buf[0..1], to identify the type as 
! 	     * DOS, but of course we ran into a DOS executable that 
! 	     * _doesn't_ have the magic number -- specifically, one
! 	     * compiled using the Lahey Fortran90 compiler.
  	     */
  
  	    applType = APPL_DOS;
--- 1480,1565 ----
  	}
  
  	/* 
! 	 * The LONG at p236.e_lfanew points to the real exe header only
! 	 * when p236.e_lfarlc is set to 40h (or greater).
  	 */
! 	
! 	SetFilePointer(hFile, p236.e_lfanew, NULL, FILE_BEGIN);
! 	ReadFile(hFile, header.buf, 200, &read, NULL);
  	CloseHandle(hFile);
+ 
+ 	/*
+ 	 * Check the sigs against the following list:
+ 	 *  'PE\0\0'  Win32 (Windows NT and Win32s) portable executable based
+ 	 *	    on Unix COFF.
+ 	 *  'NE'  Windows or OS/2 1.x segmented ("new") executable.
+ 	 *  'LE'  Windows virtual device driver (VxD) linear executable.
+ 	 *  'LX'  variant of LE used in OS/2 2.x
+ 	 *  'W3'  Windows WIN386.EXE file; a collection of LE files
+ 	 *	    (protected mode windows).
+ 	 *  'MZ'  old-style p236 DOS executable.
+ 	 */
+ 
+ 	if (header.pe.Signature == IMAGE_NT_SIGNATURE) {
+ 	    /*
+ 	     * Win32, "PE\0\0" which is short for "Portable Executable".
+ 	     */
+ 
+ 	    if (header.pe.OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC
+ 		    || !(header.pe.FileHeader.Characteristics &
+ 		    IMAGE_FILE_EXECUTABLE_IMAGE)) {
+ 		/*
+ 		 * Not an executable. Might be a dll or a COMDAT library.
+ 		 */
+ 
+ 		applType = APPL_NONE;
+ 		break;
+ 	    }
+ 
+ 	    switch (header.pe.OptionalHeader.Subsystem) {
+ 		case IMAGE_SUBSYSTEM_WINDOWS_CUI:
+ 		case IMAGE_SUBSYSTEM_OS2_CUI:
+ 		case IMAGE_SUBSYSTEM_POSIX_CUI:
+ 		    /* 
+ 		     * image runs in the Windows, OS/2, or Posix character
+ 		     * subsystem.
+ 		     */
+ 
+ 		    applType = APPL_WIN32CUI;
+ 		    break;
+ 
+ 		default:
+ 		    /*
+ 		     * Non-CUI applications are run detached.  Return a flag
+ 		     * that will indicate this error.
+ 		     */
+ 
+ 		    applType = APPL_WIN32GUI;
+ 	    }
+ 	} else if (header.ne.ne_magic == IMAGE_OS2_SIGNATURE) {
+ 	    switch (header.ne.ne_exetyp) {
+ 		case 0x1:  /* Microsoft/IBM OS/2 (default)  */
+ 		case 0x3:  /* Microsoft MS-DOS 4.x */
+ 		    /* Only these might be character-mode. */
+ 		    applType = APPL_DOS;
+ 		    break;
+ 
+ 		default:
+ 		    applType = APPL_NONE;
+ 	    }
+ 
+ 	} else if (header.le.e32_magic == IMAGE_OS2_SIGNATURE_LE ||
+ 		header.le.e32_magic == 'LX' ||
+ 		header.le.e32_magic == 'W3') {
+ 	    /*
+ 	     * Virtual device drivers are not executables, per se.
+ 	     */
  
! 	    applType = APPL_NONE;
  	} else {
  	    /*
! 	     * NOTE: The Lahey Fortran90 compiler might make executables
! 	     * that have a bogus signature and end-up here.
  	     */
  
  	    applType = APPL_DOS;