Index: tclWin32Dll.c =================================================================== RCS file: /cvsroot/tcl/tcl/win/tclWin32Dll.c,v retrieving revision 1.11 diff -c -r1.11 tclWin32Dll.c *** tclWin32Dll.c 2001/11/19 17:45:12 1.11 --- tclWin32Dll.c 2002/01/15 01:45:24 *************** *** 64,70 **** (DWORD (WINAPI *)(CONST TCHAR *, DWORD nBufferLength, WCHAR *, TCHAR **)) GetFullPathNameA, (DWORD (WINAPI *)(HMODULE, WCHAR *, int)) GetModuleFileNameA, ! (DWORD (WINAPI *)(CONST TCHAR *, WCHAR *, DWORD)) GetShortPathNameA, (UINT (WINAPI *)(CONST TCHAR *, CONST TCHAR *, UINT uUnique, WCHAR *)) GetTempFileNameA, (DWORD (WINAPI *)(DWORD, WCHAR *)) GetTempPathA, --- 64,70 ---- (DWORD (WINAPI *)(CONST TCHAR *, DWORD nBufferLength, WCHAR *, TCHAR **)) GetFullPathNameA, (DWORD (WINAPI *)(HMODULE, WCHAR *, int)) GetModuleFileNameA, ! (DWORD (WINAPI *)(CONST TCHAR *, TCHAR *, DWORD)) GetShortPathNameA, (UINT (WINAPI *)(CONST TCHAR *, CONST TCHAR *, UINT uUnique, WCHAR *)) GetTempFileNameA, (DWORD (WINAPI *)(DWORD, WCHAR *)) GetTempPathA, *************** *** 75,81 **** (BOOL (WINAPI *)(CONST TCHAR *, CONST TCHAR *)) MoveFileA, (BOOL (WINAPI *)(CONST TCHAR *)) RemoveDirectoryA, (DWORD (WINAPI *)(CONST TCHAR *, CONST TCHAR *, CONST TCHAR *, DWORD, ! WCHAR *, TCHAR **)) SearchPathA, (BOOL (WINAPI *)(CONST TCHAR *)) SetCurrentDirectoryA, (BOOL (WINAPI *)(CONST TCHAR *, DWORD)) SetFileAttributesA, NULL, --- 75,81 ---- (BOOL (WINAPI *)(CONST TCHAR *, CONST TCHAR *)) MoveFileA, (BOOL (WINAPI *)(CONST TCHAR *)) RemoveDirectoryA, (DWORD (WINAPI *)(CONST TCHAR *, CONST TCHAR *, CONST TCHAR *, DWORD, ! TCHAR *, TCHAR **)) SearchPathA, (BOOL (WINAPI *)(CONST TCHAR *)) SetCurrentDirectoryA, (BOOL (WINAPI *)(CONST TCHAR *, DWORD)) SetFileAttributesA, NULL, *************** *** 102,108 **** (DWORD (WINAPI *)(CONST TCHAR *, DWORD nBufferLength, WCHAR *, TCHAR **)) GetFullPathNameW, (DWORD (WINAPI *)(HMODULE, WCHAR *, int)) GetModuleFileNameW, ! (DWORD (WINAPI *)(CONST TCHAR *, WCHAR *, DWORD)) GetShortPathNameW, (UINT (WINAPI *)(CONST TCHAR *, CONST TCHAR *, UINT uUnique, WCHAR *)) GetTempFileNameW, (DWORD (WINAPI *)(DWORD, WCHAR *)) GetTempPathW, --- 102,108 ---- (DWORD (WINAPI *)(CONST TCHAR *, DWORD nBufferLength, WCHAR *, TCHAR **)) GetFullPathNameW, (DWORD (WINAPI *)(HMODULE, WCHAR *, int)) GetModuleFileNameW, ! (DWORD (WINAPI *)(CONST TCHAR *, TCHAR *, DWORD)) GetShortPathNameW, (UINT (WINAPI *)(CONST TCHAR *, CONST TCHAR *, UINT uUnique, WCHAR *)) GetTempFileNameW, (DWORD (WINAPI *)(DWORD, WCHAR *)) GetTempPathW, *************** *** 113,119 **** (BOOL (WINAPI *)(CONST TCHAR *, CONST TCHAR *)) MoveFileW, (BOOL (WINAPI *)(CONST TCHAR *)) RemoveDirectoryW, (DWORD (WINAPI *)(CONST TCHAR *, CONST TCHAR *, CONST TCHAR *, DWORD, ! WCHAR *, TCHAR **)) SearchPathW, (BOOL (WINAPI *)(CONST TCHAR *)) SetCurrentDirectoryW, (BOOL (WINAPI *)(CONST TCHAR *, DWORD)) SetFileAttributesW, NULL, --- 113,119 ---- (BOOL (WINAPI *)(CONST TCHAR *, CONST TCHAR *)) MoveFileW, (BOOL (WINAPI *)(CONST TCHAR *)) RemoveDirectoryW, (DWORD (WINAPI *)(CONST TCHAR *, CONST TCHAR *, CONST TCHAR *, DWORD, ! TCHAR *, TCHAR **)) SearchPathW, (BOOL (WINAPI *)(CONST TCHAR *)) SetCurrentDirectoryW, (BOOL (WINAPI *)(CONST TCHAR *, DWORD)) SetFileAttributesW, NULL, Index: tclWinInt.h =================================================================== RCS file: /cvsroot/tcl/tcl/win/tclWinInt.h,v retrieving revision 1.12 diff -c -r1.12 tclWinInt.h *** tclWinInt.h 2001/10/29 15:02:44 1.12 --- tclWinInt.h 2002/01/15 01:45:24 *************** *** 75,81 **** DWORD (WINAPI *getFullPathNameProc)(CONST TCHAR *, DWORD nBufferLength, WCHAR *, TCHAR **); DWORD (WINAPI *getModuleFileNameProc)(HMODULE, WCHAR *, int); ! DWORD (WINAPI *getShortPathNameProc)(CONST TCHAR *, WCHAR *, DWORD); UINT (WINAPI *getTempFileNameProc)(CONST TCHAR *, CONST TCHAR *, UINT, WCHAR *); DWORD (WINAPI *getTempPathProc)(DWORD, WCHAR *); --- 75,81 ---- DWORD (WINAPI *getFullPathNameProc)(CONST TCHAR *, DWORD nBufferLength, WCHAR *, TCHAR **); DWORD (WINAPI *getModuleFileNameProc)(HMODULE, WCHAR *, int); ! DWORD (WINAPI *getShortPathNameProc)(CONST TCHAR *, TCHAR *, DWORD); UINT (WINAPI *getTempFileNameProc)(CONST TCHAR *, CONST TCHAR *, UINT, WCHAR *); DWORD (WINAPI *getTempPathProc)(DWORD, WCHAR *); *************** *** 86,92 **** BOOL (WINAPI *moveFileProc)(CONST TCHAR *, CONST TCHAR *); BOOL (WINAPI *removeDirectoryProc)(CONST TCHAR *); DWORD (WINAPI *searchPathProc)(CONST TCHAR *, CONST TCHAR *, ! CONST TCHAR *, DWORD, WCHAR *, TCHAR **); BOOL (WINAPI *setCurrentDirectoryProc)(CONST TCHAR *); BOOL (WINAPI *setFileAttributesProc)(CONST TCHAR *, DWORD); BOOL (WINAPI *getFileAttributesExProc)(CONST TCHAR *, --- 86,92 ---- BOOL (WINAPI *moveFileProc)(CONST TCHAR *, CONST TCHAR *); BOOL (WINAPI *removeDirectoryProc)(CONST TCHAR *); DWORD (WINAPI *searchPathProc)(CONST TCHAR *, CONST TCHAR *, ! CONST TCHAR *, DWORD, TCHAR *, TCHAR **); BOOL (WINAPI *setCurrentDirectoryProc)(CONST TCHAR *); BOOL (WINAPI *setFileAttributesProc)(CONST TCHAR *, DWORD); BOOL (WINAPI *getFileAttributesExProc)(CONST TCHAR *, 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 2002/01/15 01:45:30 *************** *** 18,23 **** --- 18,32 ---- #include #include + + /* + * The Platform SDK headers have this, but the stock headers don't. + */ + #ifndef INVALID_SET_FILE_POINTER + #define INVALID_SET_FILE_POINTER ((DWORD)-1) + #endif + + /* * The following variable is used to tell whether this module has been * initialized. *************** *** 39,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 --- 48,67 ---- */ #define APPL_NONE 0 ! #define APPL_BATCH 1 ! #define APPL_DOS16 2 ! #define APPL_OS2 3 ! #define APPL_OS2DRV 4 ! #define APPL_WIN16 5 ! #define APPL_WIN16DRV 6 ! #define APPL_WIN32CUI 7 ! #define APPL_WIN32GUI 8 ! #define APPL_WIN32DLL 9 ! #define APPL_WIN32DRV 10 ! #define APPL_WIN64CUI 11 ! #define APPL_WIN64GUI 12 ! #define APPL_WIN64DLL 13 ! #define APPL_WIN64DRV 14 /* * The following constants and structures are used to encapsulate the state *************** *** 177,184 **** * Declarations for functions used only in this file. */ ! static int ApplicationType(Tcl_Interp *interp, ! const char *fileName, char *fullName); static void BuildCommandLine(const char *executable, int argc, char **argv, Tcl_DString *linePtr); static BOOL HasConsole(void); --- 197,204 ---- * Declarations for functions used only in this file. */ ! static int ApplicationType(CONST char *originalName, ! Tcl_DString *fullName); static void BuildCommandLine(const char *executable, int argc, char **argv, Tcl_DString *linePtr); static BOOL HasConsole(void); *************** *** 978,997 **** PROCESS_INFORMATION procInfo; SECURITY_ATTRIBUTES secAtts; HANDLE hProcess, h, inputHandle, outputHandle, errorHandle; ! char execPath[MAX_PATH * TCL_UTF_MAX]; WinFile *filePtr; PipeInit(); - applType = ApplicationType(interp, argv[0], execPath); - if (applType == APPL_NONE) { - return TCL_ERROR; - } - - result = TCL_ERROR; - Tcl_DStringInit(&cmdLine); - hProcess = GetCurrentProcess(); - /* * STARTF_USESTDHANDLES must be used to pass handles to child process. * Using SetStdHandle() and/or dup2() only works when a console mode --- 998,1008 ---- PROCESS_INFORMATION procInfo; SECURITY_ATTRIBUTES secAtts; HANDLE hProcess, h, inputHandle, outputHandle, errorHandle; ! Tcl_DString exeFullPathUTF; WinFile *filePtr; PipeInit(); /* * STARTF_USESTDHANDLES must be used to pass handles to child process. * Using SetStdHandle() and/or dup2() only works when a console mode *************** *** 1005,1010 **** --- 1016,1036 ---- startInfo.hStdOutput= INVALID_HANDLE_VALUE; startInfo.hStdError = INVALID_HANDLE_VALUE; + Tcl_DStringInit(&exeFullPathUTF); + Tcl_DStringInit(&cmdLine); + result = TCL_ERROR; + + applType = ApplicationType(argv[0], &exeFullPathUTF); + if (applType == APPL_NONE) { + TclWinConvertError(GetLastError()); + Tcl_AppendResult(interp, "couldn't execute \"", + Tcl_DStringValue(&exeFullPathUTF), "\": ", + Tcl_PosixError(interp), (char *) NULL); + goto end; + } + + hProcess = GetCurrentProcess(); + secAtts.nLength = sizeof(SECURITY_ATTRIBUTES); secAtts.lpSecurityDescriptor = NULL; secAtts.bInheritHandle = TRUE; *************** *** 1087,1093 **** */ if ((TclWinGetPlatformId() == VER_PLATFORM_WIN32_WINDOWS) ! && (applType == APPL_DOS)) { if (CreatePipe(&h, &startInfo.hStdOutput, &secAtts, 0) != FALSE) { CloseHandle(h); } --- 1113,1119 ---- */ if ((TclWinGetPlatformId() == VER_PLATFORM_WIN32_WINDOWS) ! && (applType == APPL_DOS16 || applType == APPL_BATCH)) { if (CreatePipe(&h, &startInfo.hStdOutput, &secAtts, 0) != FALSE) { CloseHandle(h); } *************** *** 1141,1148 **** if (TclWinGetPlatformId() == VER_PLATFORM_WIN32_NT) { if (HasConsole()) { ! createFlags = 0; ! } else if (applType == APPL_DOS) { /* * Under NT, 16-bit DOS applications will not run unless they * can be attached to a console. If we are running without a --- 1167,1178 ---- if (TclWinGetPlatformId() == VER_PLATFORM_WIN32_NT) { if (HasConsole()) { ! if (applType == APPL_DOS16) { ! createFlags = CREATE_SEPARATE_WOW_VDM; ! } else { ! createFlags = 0; ! } ! } else if (applType == APPL_DOS16 || applType == APPL_BATCH) { /* * Under NT, 16-bit DOS applications will not run unless they * can be attached to a console. If we are running without a *************** *** 1165,1171 **** createFlags = DETACHED_PROCESS; } ! if (applType == APPL_DOS) { /* * Under Windows 95, 16-bit DOS applications do not work well * with pipes: --- 1195,1201 ---- createFlags = DETACHED_PROCESS; } ! if (applType == APPL_DOS16 || applType == APPL_BATCH) { /* * Under Windows 95, 16-bit DOS applications do not work well * with pipes: *************** *** 1223,1229 **** * using ab~1.def instead of "a b.default"). */ ! BuildCommandLine(execPath, argc, argv, &cmdLine); if ((*tclWinProcs->createProcessProc)(NULL, (TCHAR *) Tcl_DStringValue(&cmdLine), NULL, NULL, TRUE, --- 1253,1259 ---- * using ab~1.def instead of "a b.default"). */ ! BuildCommandLine(Tcl_DStringValue(&exeFullPathUTF), argc, argv, &cmdLine); if ((*tclWinProcs->createProcessProc)(NULL, (TCHAR *) Tcl_DStringValue(&cmdLine), NULL, NULL, TRUE, *************** *** 1239,1245 **** * process. */ ! if (applType == APPL_DOS) { WaitForSingleObject(procInfo.hProcess, 50); } --- 1269,1275 ---- * process. */ ! if (applType == APPL_DOS16 || applType == APPL_BATCH) { WaitForSingleObject(procInfo.hProcess, 50); } *************** *** 1261,1267 **** } result = TCL_OK; ! end: Tcl_DStringFree(&cmdLine); if (startInfo.hStdInput != INVALID_HANDLE_VALUE) { CloseHandle(startInfo.hStdInput); --- 1291,1298 ---- } result = TCL_OK; ! end: ! Tcl_DStringFree(&exeFullPathUTF); Tcl_DStringFree(&cmdLine); if (startInfo.hStdInput != INVALID_HANDLE_VALUE) { CloseHandle(startInfo.hStdInput); *************** *** 1346,1368 **** */ static int ! ApplicationType(interp, originalName, fullName) ! Tcl_Interp *interp; /* Interp, for error message. */ ! const char *originalName; /* Name of the application to find. */ ! char fullName[]; /* Filled with complete path to ! * application. */ { ! int applType, i, nameLen, found; 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 --- 1377,1404 ---- */ static int ! ApplicationType(originalName, fullName) ! CONST char *originalName; /* Name of the application to find. (in UTF-8) */ ! Tcl_DString *fullName; /* Buffer space filled with complete path to ! * application. (in UTF-8) */ { ! int applType, i, nameLen, nativeNameLen; 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, nativeNameBuff, ds; TCHAR *nativeName; ! WCHAR nativeShortPath[MAX_PATH]; /* needed for unicode space */ ! static char extensions[][5] = {"", ".com", ".exe", ".bat", ".cmd"}; ! int offset64; /* 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 *************** *** 1380,1427 **** applType = APPL_NONE; Tcl_DStringInit(&nameBuf); Tcl_DStringAppend(&nameBuf, originalName, -1); nameLen = Tcl_DStringLength(&nameBuf); ! for (i = 0; i < (int) (sizeof(extensions) / sizeof(extensions[0])); i++) { Tcl_DStringSetLength(&nameBuf, nameLen); Tcl_DStringAppend(&nameBuf, extensions[i], -1); nativeName = Tcl_WinUtfToTChar(Tcl_DStringValue(&nameBuf), Tcl_DStringLength(&nameBuf), &ds); ! found = (*tclWinProcs->searchPathProc)(NULL, nativeName, NULL, ! MAX_PATH, nativeFullPath, &rest); ! Tcl_DStringFree(&ds); ! if (found == 0) { continue; } /* ! * Ignore matches on directories or data files, return if identified ! * a known type. */ ! attr = (*tclWinProcs->getFileAttributesProc)((TCHAR *) nativeFullPath); ! if ((attr == 0xffffffff) || (attr & FILE_ATTRIBUTE_DIRECTORY)) { continue; } ! strcpy(fullName, Tcl_WinTCharToUtf((TCHAR *) nativeFullPath, -1, &ds)); ! Tcl_DStringFree(&ds); ! ext = strrchr(fullName, '.'); ! if ((ext != NULL) && (stricmp(ext, ".bat") == 0)) { ! applType = APPL_DOS; break; } ! hFile = (*tclWinProcs->createFileProc)((TCHAR *) nativeFullPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { ! 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. --- 1416,1482 ---- applType = APPL_NONE; Tcl_DStringInit(&nameBuf); Tcl_DStringAppend(&nameBuf, originalName, -1); + Tcl_DStringAppend(fullName, originalName, -1); nameLen = Tcl_DStringLength(&nameBuf); ! for (i = 0; i < (sizeof(extensions) / sizeof(extensions[0])); i++) { Tcl_DStringSetLength(&nameBuf, nameLen); Tcl_DStringAppend(&nameBuf, extensions[i], -1); nativeName = Tcl_WinUtfToTChar(Tcl_DStringValue(&nameBuf), Tcl_DStringLength(&nameBuf), &ds); ! ! /* Just get the size of the buffer needed, when found. */ ! nativeNameLen = (*tclWinProcs->searchPathProc)(NULL, nativeName, ! NULL, 0, NULL, &rest); ! ! if (nativeNameLen == 0) { ! /* not found. */ ! Tcl_DStringFree(&ds); continue; } + /* Set the buffer needed. */ + Tcl_DStringInit(&nativeNameBuff); + Tcl_DStringSetLength(&nativeNameBuff, + (tclWinProcs->useWide ? nativeNameLen*2 : nativeNameLen)); + + (*tclWinProcs->searchPathProc)(NULL, nativeName, NULL, + Tcl_DStringLength(&nativeNameBuff), + (TCHAR *) Tcl_DStringValue(&nativeNameBuff), &rest); + Tcl_DStringFree(&ds); + /* ! * Ignore matches on directories, keep falling through ! * when identified as something else. */ ! attr = (*tclWinProcs->getFileAttributesProc)( ! (TCHAR *) Tcl_DStringValue(&nativeNameBuff)); ! if ((attr == -1) || (attr & FILE_ATTRIBUTE_DIRECTORY)) { continue; } ! Tcl_WinTCharToUtf((TCHAR *) Tcl_DStringValue(&nativeNameBuff), ! -1, fullName); ! ext = strrchr(Tcl_DStringValue(fullName), '.'); ! if ((ext != NULL) && (stricmp(ext, ".bat") == 0 || ! stricmp(ext, ".cmd") == 0)) { ! applType = APPL_BATCH; break; } ! hFile = (*tclWinProcs->createFileProc)( ! (TCHAR *) Tcl_DStringValue(&nativeNameBuff), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { ! applType = APPL_NONE; ! break; } ! 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,1506 **** * magic numbers and everything. */ CloseHandle(hFile); if ((ext != NULL) && (strcmp(ext, ".com") == 0)) { ! applType = APPL_DOS; break; } ! 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); ! applType = APPL_DOS; break; } /* ! * 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; } break; } - Tcl_DStringFree(&nameBuf); ! if (applType == APPL_NONE) { ! TclWinConvertError(GetLastError()); ! Tcl_AppendResult(interp, "couldn't execute \"", originalName, ! "\": ", Tcl_PosixError(interp), (char *) NULL); ! return APPL_NONE; ! } ! ! if ((applType == APPL_DOS) || (applType == APPL_WIN3X)) { /* ! * Replace long path name of executable with short path name for * 16-bit applications. Otherwise the application may not be able ! * to correctly parse its own command line to separate off the * application name from the arguments. */ ! (*tclWinProcs->getShortPathNameProc)((TCHAR *) nativeFullPath, ! nativeFullPath, MAX_PATH); ! strcpy(fullName, Tcl_WinTCharToUtf((TCHAR *) nativeFullPath, -1, &ds)); ! Tcl_DStringFree(&ds); } return applType; } ! /* *---------------------------------------------------------------------- * * BuildCommandLine -- --- 1485,1685 ---- * 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_DOS16; break; } ! SetLastError(ERROR_INVALID_EXE_SIGNATURE); ! applType = APPL_NONE; ! break; } ! if (p236.e_lfarlc < 0x40 || p236.e_lfanew == 0 /* reserved */) { /* ! * Old-style header only. Can't be more than a DOS16 executable. */ CloseHandle(hFile); ! applType = APPL_DOS16; break; } /* ! * The LONG at p236.e_lfanew points to the real exe header only ! * when p236.e_lfarlc is set to 40h (or greater). */ ! ! if (SetFilePointer(hFile, p236.e_lfanew, NULL, FILE_BEGIN) ! == INVALID_SET_FILE_POINTER) { ! /* Bogus PE header pointer. */ ! CloseHandle(hFile); ! SetLastError(ERROR_BAD_EXE_FORMAT); ! applType = APPL_NONE; ! break; ! } ! 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). ! * 'W4' Variant of above. ! */ ! ! if (header.pe.Signature == IMAGE_NT_SIGNATURE) { ! if (!(header.pe.FileHeader.Characteristics & ! IMAGE_FILE_EXECUTABLE_IMAGE)) { ! /* Not an executable. */ ! SetLastError(ERROR_BAD_EXE_FORMAT); ! applType = APPL_NONE; ! break; ! } ! ! if (header.pe.OptionalHeader.Magic == ! IMAGE_NT_OPTIONAL_HDR32_MAGIC) { ! /* Win32 executable */ ! offset64 = 0; ! } else if (header.pe.OptionalHeader.Magic == ! IMAGE_NT_OPTIONAL_HDR64_MAGIC) { ! /* Win64 executable */ ! offset64 = 4; ! } else { ! /* Unknown magic number */ ! SetLastError(ERROR_INVALID_MODULETYPE); ! applType = APPL_NONE; ! break; ! } ! ! if (header.pe.FileHeader.Characteristics & IMAGE_FILE_DLL) { ! /* ! * DLLs are executable, but indirectly. We shouldn't return ! * APPL_NONE or the subsystem that its said to run under ! * as it's not the complete truth, so return a new type and ! * let the user decide what to do. ! */ ! ! applType = APPL_WIN32DLL + offset64; ! break; ! } ! ! switch (header.pe.OptionalHeader.Subsystem) { ! case IMAGE_SUBSYSTEM_WINDOWS_CUI: ! case IMAGE_SUBSYSTEM_OS2_CUI: ! case IMAGE_SUBSYSTEM_POSIX_CUI: ! /* Runs in the CUI subsystem */ ! applType = APPL_WIN32CUI + offset64; ! break; ! ! case IMAGE_SUBSYSTEM_WINDOWS_GUI: ! case IMAGE_SUBSYSTEM_WINDOWS_CE_GUI: ! /* Runs in the GUI subsystem */ ! applType = APPL_WIN32GUI + offset64; ! break; ! ! case IMAGE_SUBSYSTEM_UNKNOWN: ! case IMAGE_SUBSYSTEM_NATIVE: ! case IMAGE_SUBSYSTEM_NATIVE_WINDOWS: ! /* Special Driver */ ! applType = APPL_WIN32DRV + offset64; ! break; ! } ! ! #define IMAGE_NE_FLAG_DRIVER 0x8000 ! #define IMAGE_NE_EXETYP_OS2 0x1 ! #define IMAGE_NE_EXETYP_WIN 0x2 ! #define IMAGE_NE_EXETYP_DOS4X 0x3 ! #define IMAGE_NE_EXETYP_WIN386 0x4 ! ! } else if (header.ne.ne_magic == IMAGE_OS2_SIGNATURE) { ! switch (header.ne.ne_exetyp) { ! case IMAGE_NE_EXETYP_OS2: /* Microsoft/IBM OS/2 1.x */ ! if (header.ne.ne_flags & IMAGE_NE_FLAG_DRIVER) { ! applType = APPL_OS2DRV; ! } else { ! applType = APPL_OS2; ! } ! break; ! ! case IMAGE_NE_EXETYP_WIN: /* Microsoft Windows */ ! case IMAGE_NE_EXETYP_WIN386: /* Same, but Protected mode */ ! if (header.ne.ne_flags & IMAGE_NE_FLAG_DRIVER) { ! applType = APPL_WIN16DRV; ! } else { ! applType = APPL_WIN16; ! } ! break; ! case IMAGE_NE_EXETYP_DOS4X: /* Microsoft MS-DOS 4.x */ ! applType = APPL_DOS16; ! break; ! ! default: ! /* Unidentified */ ! SetLastError(ERROR_INVALID_MODULETYPE); ! applType = APPL_NONE; ! } ! } else if ( ! header.le.e32_magic == IMAGE_OS2_SIGNATURE_LE /* 'LE' */ || ! header.le.e32_magic == 0x584C /* 'LX' */ || ! header.le.e32_magic == 0x3357 /* 'W3' */ || ! header.le.e32_magic == 0x3457 /* 'W4' */ ! ){ ! /* Virtual device drivers are not executables, per se. */ ! applType = APPL_WIN16DRV; ! } else { ! /* The loader will barf anyway, so barf now. */ ! SetLastError(ERROR_INVALID_EXE_SIGNATURE); ! applType = APPL_NONE; } break; } ! if (applType == APPL_DOS16 || applType == APPL_WIN16 || ! applType == APPL_WIN16DRV || applType == APPL_OS2 || ! applType == APPL_OS2DRV) { /* ! * Replace long path name of executable with short path name for * 16-bit applications. Otherwise the application may not be able ! * to correctly parse its own command line to separate off the * application name from the arguments. */ ! (*tclWinProcs->getShortPathNameProc)( ! (TCHAR *) Tcl_DStringValue(&nativeNameBuff), ! (TCHAR *) nativeShortPath, MAX_PATH); ! Tcl_WinTCharToUtf((TCHAR *) nativeShortPath, -1, fullName); } + Tcl_DStringFree(&nativeNameBuff); + Tcl_DStringFree(&nameBuf); return applType; } ! /* *---------------------------------------------------------------------- * * BuildCommandLine --