/* * stub16.c * * A helper program used for running 16-bit DOS applications under * Windows 95. * * Copyright (c) 1996 by Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * RCS: @(#) $Id: stub16.c,v 1.4 1999/04/21 21:50:34 rjohnson Exp $ */ #define STRICT #include #include static HANDLE CreateTempFile(void); /* *--------------------------------------------------------------------------- * * main * * Entry point for the 32-bit console mode app used by Windows 95 to * help run the 16-bit program specified on the command line. * * 1. EOF on a pipe that connects a detached 16-bit process and a * 32-bit process is never seen. So, this process runs the 16-bit * process _attached_, and then it is run detached from the calling * 32-bit process. * * 2. If a 16-bit process blocks reading from or writing to a pipe, * it never wakes up, and eventually brings the whole system down * with it if you try to kill the process. This app simulates * pipes. If any of the stdio handles is a pipe, this program * accumulates information into temp files and forwards it to or * from the DOS application as appropriate. This means that this * program must receive EOF from a stdin pipe before it will actually * start the DOS app, and the DOS app must finish generating stdout * or stderr before the data will be sent to the next stage of the * pipe. If the stdio handles are not pipes, no accumulation occurs * and the data is passed straight through to and from the DOS * application. * * Results: * None. * * Side effects: * The child process is created and this process waits for it to * complete. * *--------------------------------------------------------------------------- */ int main() { DWORD dwRead, dwWrite; char *cmdLine; HANDLE hStdInput, hStdOutput, hStdError; HANDLE hFileInput, hFileOutput, hFileError; STARTUPINFO si; PROCESS_INFORMATION pi; char buf[8192]; DWORD result; hFileInput = INVALID_HANDLE_VALUE; hFileOutput = INVALID_HANDLE_VALUE; hFileError = INVALID_HANDLE_VALUE; result = 1; /* * Don't get command line from argc, argv, because the command line * tokenizer will have stripped off all the escape sequences needed * for quotes and backslashes, and then we'd have to put them all * back in again. Get the raw command line and parse off what we * want ourselves. The command line should be of the form: * * stub16.exe program arg1 arg2 ... */ cmdLine = strchr(GetCommandLine(), ' '); if (cmdLine == NULL) { return 1; } cmdLine++; hStdInput = GetStdHandle(STD_INPUT_HANDLE); hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); hStdError = GetStdHandle(STD_ERROR_HANDLE); if (GetFileType(hStdInput) == FILE_TYPE_PIPE) { hFileInput = CreateTempFile(); if (hFileInput == INVALID_HANDLE_VALUE) { goto cleanup; } while (ReadFile(hStdInput, buf, sizeof(buf), &dwRead, NULL) != FALSE) { if (dwRead == 0) { break; } if (WriteFile(hFileInput, buf, dwRead, &dwWrite, NULL) == FALSE) { goto cleanup; } } SetFilePointer(hFileInput, 0, 0, FILE_BEGIN); SetStdHandle(STD_INPUT_HANDLE, hFileInput); } if (GetFileType(hStdOutput) == FILE_TYPE_PIPE) { hFileOutput = CreateTempFile(); if (hFileOutput == INVALID_HANDLE_VALUE) { goto cleanup; } SetStdHandle(STD_OUTPUT_HANDLE, hFileOutput); } if (GetFileType(hStdError) == FILE_TYPE_PIPE) { hFileError = CreateTempFile(); if (hFileError == INVALID_HANDLE_VALUE) { goto cleanup; } SetStdHandle(STD_ERROR_HANDLE, hFileError); } ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); if (CreateProcess(NULL, cmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi) == FALSE) { goto cleanup; } WaitForInputIdle(pi.hProcess, 5000); WaitForSingleObject(pi.hProcess, INFINITE); GetExitCodeProcess(pi.hProcess, &result); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); if (hFileOutput != INVALID_HANDLE_VALUE) { SetFilePointer(hFileOutput, 0, 0, FILE_BEGIN); while (ReadFile(hFileOutput, buf, sizeof(buf), &dwRead, NULL) != FALSE) { if (dwRead == 0) { break; } if (WriteFile(hStdOutput, buf, dwRead, &dwWrite, NULL) == FALSE) { break; } } } if (hFileError != INVALID_HANDLE_VALUE) { SetFilePointer(hFileError, 0, 0, FILE_BEGIN); while (ReadFile(hFileError, buf, sizeof(buf), &dwRead, NULL) != FALSE) { if (dwRead == 0) { break; } if (WriteFile(hStdError, buf, dwRead, &dwWrite, NULL) == FALSE) { break; } } } cleanup: if (hFileInput != INVALID_HANDLE_VALUE) { CloseHandle(hFileInput); } if (hFileOutput != INVALID_HANDLE_VALUE) { CloseHandle(hFileOutput); } if (hFileError != INVALID_HANDLE_VALUE) { CloseHandle(hFileError); } CloseHandle(hStdInput); CloseHandle(hStdOutput); CloseHandle(hStdError); ExitProcess(result); return 1; } static HANDLE CreateTempFile() { char name[MAX_PATH]; SECURITY_ATTRIBUTES sa; if (GetTempPath(sizeof(name), name) == 0) { return INVALID_HANDLE_VALUE; } if (GetTempFileName(name, "tcl", 0, name) == 0) { return INVALID_HANDLE_VALUE; } sa.nLength = sizeof(sa); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE; return CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, &sa, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, NULL); }