| /* | |
| * 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; | |
| } |