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