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;