1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | PC/w9xpopen.c
/* * w9xpopen.c * * Serves as an intermediate stub Win32 console application to * avoid a hanging pipe when redirecting 16-bit console based * programs (including MS-DOS console based programs and batch * files) on Window 95 and Windows 98. * * This program is to be launched with redirected standard * handles. It will launch the command line specified 16-bit * console based application in the same console, forwarding * its own redirected standard handles to the 16-bit child. * AKA solution to the problem described in KB: Q150956. */ #define WIN32_LEAN_AND_MEAN #include <windows.h> #include <stdio.h> #include <stdlib.h> /* for malloc and its friends */ const char *usage = "This program is used by Python's os.popen function\n" "to work around a limitation in Windows 95/98. It is\n" "not designed to be used as a stand-alone program."; int main(int argc, char *argv[]) { BOOL bRet; STARTUPINFO si; PROCESS_INFORMATION pi; DWORD exit_code=0; size_t cmdlen = 0; int i; char *cmdline, *cmdlinefill; if (argc < 2) { if (GetFileType(GetStdHandle(STD_INPUT_HANDLE))==FILE_TYPE_CHAR) /* Attached to a console, and therefore not executed by Python Display a message box for the inquisitive user */ MessageBox(NULL, usage, argv[0], MB_OK); else { /* Eeek - executed by Python, but args are screwed! Write an error message to stdout so there is at least some clue for the end user when it appears in their output. A message box would be hidden and blocks the app. */ fprintf(stdout, "Internal popen error - no args specified\n%s\n", usage); } return 1; } /* Build up the command-line from the args. Args with a space are quoted, existing quotes are escaped. To keep things simple calculating the buffer size, we assume every character is a quote - ie, we allocate double what we need in the worst case. As this is only double the command line passed to us, there is a good chance this is reasonably small, so the total allocation will almost always be < 512 bytes. */ for (i=1;i<argc;i++) cmdlen += strlen(argv[i])*2 + 3; /* one space, maybe 2 quotes */ cmdline = cmdlinefill = (char *)malloc(cmdlen+1); if (cmdline == NULL) return -1; for (i=1;i<argc;i++) { const char *arglook; int bQuote = strchr(argv[i], ' ') != NULL; if (bQuote) *cmdlinefill++ = '"'; /* escape quotes */ for (arglook=argv[i];*arglook;arglook++) { if (*arglook=='"') *cmdlinefill++ = '\\'; *cmdlinefill++ = *arglook; } if (bQuote) *cmdlinefill++ = '"'; *cmdlinefill++ = ' '; } *cmdlinefill = '\0'; /* Make child process use this app's standard files. */ ZeroMemory(&si, sizeof si); si.cb = sizeof si; si.dwFlags = STARTF_USESTDHANDLES; si.hStdInput = GetStdHandle(STD_INPUT_HANDLE); si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); si.hStdError = GetStdHandle(STD_ERROR_HANDLE); bRet = CreateProcess( NULL, cmdline, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi ); free(cmdline); if (bRet) { if (WaitForSingleObject(pi.hProcess, INFINITE) != WAIT_FAILED) { GetExitCodeProcess(pi.hProcess, &exit_code); } CloseHandle(pi.hProcess); CloseHandle(pi.hThread); return exit_code; } return 1; } |