4 * Sub-process communicating with pipe I/O channel class
6 * Portable Windows Library
8 * Copyright (c) 1993-1998 Equivalence Pty. Ltd.
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17 * the License for the specific language governing rights and limitations
20 * The Original Code is Portable Windows Library.
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24 * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
25 * All Rights Reserved.
27 * Contributor(s): ______________________________________.
30 * Revision 1.4 2004/04/03 06:54:30 rjongbloed
31 * Many and various changes to support new Visual C++ 2003
33 * Revision 1.3 2001/09/10 02:51:23 robertj
34 * Major change to fix problem with error codes being corrupted in a
35 * PChannel when have simultaneous reads and writes in threads.
37 * Revision 1.2 1998/11/30 07:37:56 robertj
38 * Fixed (previous bug) of incorrect handle values.
40 * Revision 1.1 1998/11/30 04:57:42 robertj
46 #include <ptlib/pipechan.h>
50 ///////////////////////////////////////////////////////////////////////////////
53 PPipeChannel::PPipeChannel()
55 hToChild
= hFromChild
= hStandardError
= INVALID_HANDLE_VALUE
;
59 BOOL
PPipeChannel::PlatformOpen(const PString
& subProgram
,
60 const PStringArray
& argumentList
,
64 const PStringToString
* environment
)
66 subProgName
= subProgram
;
68 const char * prog
= NULL
;
69 PStringStream cmdLine
;
71 cmdLine
<< subProgram
;
75 for (PINDEX i
= 0; i
< argumentList
.GetSize(); i
++) {
77 if (argumentList
[i
].Find(' ') == P_MAX_INDEX
)
78 cmdLine
<< argumentList
[i
];
79 else if (argumentList
[i
].Find('"') == P_MAX_INDEX
)
80 cmdLine
<< '"' << argumentList
[i
] << '"';
82 cmdLine
<< '\'' << argumentList
[i
] << '\'';
87 if (environment
!= NULL
) {
89 for (PINDEX e
= 0; e
< environment
->GetSize(); e
++) {
90 PString str
= environment
->GetKeyAt(e
) + '=' + environment
->GetDataAt(e
);
91 PINDEX len
= str
.GetLength() + 1;
92 envBuf
.SetSize(size
+ len
);
93 memcpy(envBuf
.GetPointer()+size
, (const char *)str
, len
);
96 envStr
= envBuf
.GetPointer();
101 memset(&startup
, 0, sizeof(startup
));
102 startup
.cb
= sizeof(startup
);
103 startup
.dwFlags
= STARTF_USESHOWWINDOW
|STARTF_USESTDHANDLES
;
104 startup
.wShowWindow
= SW_HIDE
;
105 startup
.hStdInput
= INVALID_HANDLE_VALUE
;
106 startup
.hStdOutput
= INVALID_HANDLE_VALUE
;
107 startup
.hStdError
= INVALID_HANDLE_VALUE
;
109 SECURITY_ATTRIBUTES security
;
110 security
.nLength
= sizeof(security
);
111 security
.lpSecurityDescriptor
= NULL
;
112 security
.bInheritHandle
= TRUE
;
114 if (mode
== ReadOnly
)
115 hToChild
= INVALID_HANDLE_VALUE
;
118 PAssertOS(CreatePipe(&startup
.hStdInput
, &writeEnd
, &security
, 0));
119 PAssertOS(DuplicateHandle(GetCurrentProcess(), writeEnd
,
120 GetCurrentProcess(), &hToChild
, 0, FALSE
,
121 DUPLICATE_CLOSE_SOURCE
|DUPLICATE_SAME_ACCESS
));
124 if (mode
== WriteOnly
)
125 hFromChild
= INVALID_HANDLE_VALUE
;
126 else if (mode
== ReadWriteStd
) {
127 hFromChild
= INVALID_HANDLE_VALUE
;
128 startup
.hStdOutput
= GetStdHandle(STD_OUTPUT_HANDLE
);
129 startup
.hStdError
= GetStdHandle(STD_ERROR_HANDLE
);
132 PAssertOS(CreatePipe(&hFromChild
, &startup
.hStdOutput
, &security
, 0));
134 PAssertOS(CreatePipe(&hStandardError
, &startup
.hStdError
, &security
, 0));
136 startup
.hStdError
= startup
.hStdOutput
;
137 hStandardError
= INVALID_HANDLE_VALUE
;
141 if (ConvertOSError(CreateProcess(prog
, cmdLine
.GetPointer(),
142 NULL
, NULL
, TRUE
, 0, envStr
,
143 NULL
, &startup
, &info
) ? 0 : -2))
144 os_handle
= info
.dwProcessId
;
146 if (hToChild
!= INVALID_HANDLE_VALUE
)
147 CloseHandle(hToChild
);
148 if (hFromChild
!= INVALID_HANDLE_VALUE
)
149 CloseHandle(hFromChild
);
150 if (hStandardError
!= INVALID_HANDLE_VALUE
)
151 CloseHandle(hStandardError
);
154 if (startup
.hStdInput
!= INVALID_HANDLE_VALUE
)
155 CloseHandle(startup
.hStdInput
);
157 if (mode
!= ReadWriteStd
) {
158 if (startup
.hStdOutput
!= INVALID_HANDLE_VALUE
)
159 CloseHandle(startup
.hStdOutput
);
160 if (startup
.hStdOutput
!= startup
.hStdError
)
161 CloseHandle(startup
.hStdError
);
168 PPipeChannel::~PPipeChannel()
174 BOOL
PPipeChannel::IsOpen() const
176 return os_handle
!= -1;
180 int PPipeChannel::GetReturnCode() const
183 if (GetExitCodeProcess(info
.hProcess
, &code
) && (code
!= STILL_ACTIVE
))
186 ((PPipeChannel
*)this)->ConvertOSError(-2);
191 BOOL
PPipeChannel::CanReadAndWrite()
196 BOOL
PPipeChannel::IsRunning() const
199 return GetExitCodeProcess(info
.hProcess
, &code
) && (code
== STILL_ACTIVE
);
203 int PPipeChannel::WaitForTermination()
205 if (WaitForSingleObject(info
.hProcess
, INFINITE
) == WAIT_OBJECT_0
)
206 return GetReturnCode();
213 int PPipeChannel::WaitForTermination(const PTimeInterval
& timeout
)
215 if (WaitForSingleObject(info
.hProcess
, timeout
.GetInterval()) == WAIT_OBJECT_0
)
216 return GetReturnCode();
223 BOOL
PPipeChannel::Kill(int signal
)
225 return ConvertOSError(TerminateProcess(info
.hProcess
, signal
) ? 0 : -2);
229 BOOL
PPipeChannel::Read(void * buffer
, PINDEX len
)
233 if (!ConvertOSError(ReadFile(hFromChild
, buffer
, len
, &count
, NULL
) ? 0 :-2, LastReadError
))
235 lastReadCount
= count
;
236 return lastReadCount
> 0;
240 BOOL
PPipeChannel::Write(const void * buffer
, PINDEX len
)
244 if (!ConvertOSError(WriteFile(hToChild
, buffer
, len
, &count
, NULL
) ? 0 : -2, LastWriteError
))
246 lastWriteCount
= count
;
247 return lastWriteCount
>= len
;
251 BOOL
PPipeChannel::Close()
255 if (hToChild
!= INVALID_HANDLE_VALUE
)
256 CloseHandle(hToChild
);
257 if (hFromChild
!= INVALID_HANDLE_VALUE
)
258 CloseHandle(hFromChild
);
259 if (hStandardError
!= INVALID_HANDLE_VALUE
)
260 CloseHandle(hStandardError
);
261 if (!TerminateProcess(info
.hProcess
, 1))
268 BOOL
PPipeChannel::Execute()
272 if (hToChild
!= INVALID_HANDLE_VALUE
)
273 CloseHandle(hToChild
);
274 hToChild
= INVALID_HANDLE_VALUE
;
279 BOOL
PPipeChannel::ReadStandardError(PString
& errors
, BOOL wait
)
281 DWORD available
, bytesRead
;
282 if (!PeekNamedPipe(hStandardError
, NULL
, 0, NULL
, &available
, NULL
))
283 return ConvertOSError(-2, LastReadError
);
286 return ConvertOSError(ReadFile(hStandardError
,
287 errors
.GetPointer(available
+1), available
,
288 &bytesRead
, NULL
) ? 0 : -2, LastReadError
);
294 if (!ReadFile(hStandardError
, &firstByte
, 1, &bytesRead
, NULL
))
295 return ConvertOSError(-2, LastReadError
);
299 if (!PeekNamedPipe(hStandardError
, NULL
, 0, NULL
, &available
, NULL
))
300 return ConvertOSError(-2, LastReadError
);
305 return ConvertOSError(ReadFile(hStandardError
,
306 errors
.GetPointer(available
+2)+1, available
,
307 &bytesRead
, NULL
) ? 0 : -2, LastReadError
);
311 // End Of File ///////////////////////////////////////////////////////////////