Added PSharedptr class
[pwlib.git] / src / ptlib / msos / pipe.cxx
blob2a24c3f02aec7b8d2d39b44eef0144b5d16eec80
1 /*
2 * pipe.cxx
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
18 * under the License.
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): ______________________________________.
29 * $Log$
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
41 * Initial revision
45 #include <ptlib.h>
46 #include <ptlib/pipechan.h>
48 #include <ctype.h>
50 ///////////////////////////////////////////////////////////////////////////////
51 // PPipeChannel
53 PPipeChannel::PPipeChannel()
55 hToChild = hFromChild = hStandardError = INVALID_HANDLE_VALUE;
59 BOOL PPipeChannel::PlatformOpen(const PString & subProgram,
60 const PStringArray & argumentList,
61 OpenMode mode,
62 BOOL searchPath,
63 BOOL stderrSeparate,
64 const PStringToString * environment)
66 subProgName = subProgram;
68 const char * prog = NULL;
69 PStringStream cmdLine;
70 if (searchPath)
71 cmdLine << subProgram;
72 else
73 prog = subProgram;
75 for (PINDEX i = 0; i < argumentList.GetSize(); i++) {
76 cmdLine << ' ';
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] << '"';
81 else
82 cmdLine << '\'' << argumentList[i] << '\'';
85 PCharArray envBuf;
86 char * envStr = NULL;
87 if (environment != NULL) {
88 PINDEX size = 0;
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);
94 size += len;
96 envStr = envBuf.GetPointer();
100 STARTUPINFO startup;
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;
116 else {
117 HANDLE writeEnd;
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);
131 else {
132 PAssertOS(CreatePipe(&hFromChild, &startup.hStdOutput, &security, 0));
133 if (stderrSeparate)
134 PAssertOS(CreatePipe(&hStandardError, &startup.hStdError, &security, 0));
135 else {
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;
145 else {
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);
164 return IsOpen();
168 PPipeChannel::~PPipeChannel()
170 Close();
174 BOOL PPipeChannel::IsOpen() const
176 return os_handle != -1;
180 int PPipeChannel::GetReturnCode() const
182 DWORD code;
183 if (GetExitCodeProcess(info.hProcess, &code) && (code != STILL_ACTIVE))
184 return code;
186 ((PPipeChannel*)this)->ConvertOSError(-2);
187 return -1;
191 BOOL PPipeChannel::CanReadAndWrite()
193 return TRUE;
196 BOOL PPipeChannel::IsRunning() const
198 DWORD code;
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();
208 ConvertOSError(-2);
209 return -1;
213 int PPipeChannel::WaitForTermination(const PTimeInterval & timeout)
215 if (WaitForSingleObject(info.hProcess, timeout.GetInterval()) == WAIT_OBJECT_0)
216 return GetReturnCode();
218 ConvertOSError(-2);
219 return -1;
223 BOOL PPipeChannel::Kill(int signal)
225 return ConvertOSError(TerminateProcess(info.hProcess, signal) ? 0 : -2);
229 BOOL PPipeChannel::Read(void * buffer, PINDEX len)
231 lastReadCount = 0;
232 DWORD count;
233 if (!ConvertOSError(ReadFile(hFromChild, buffer, len, &count, NULL) ? 0 :-2, LastReadError))
234 return FALSE;
235 lastReadCount = count;
236 return lastReadCount > 0;
240 BOOL PPipeChannel::Write(const void * buffer, PINDEX len)
242 lastWriteCount = 0;
243 DWORD count;
244 if (!ConvertOSError(WriteFile(hToChild, buffer, len, &count, NULL) ? 0 : -2, LastWriteError))
245 return FALSE;
246 lastWriteCount = count;
247 return lastWriteCount >= len;
251 BOOL PPipeChannel::Close()
253 if (IsOpen()) {
254 os_handle = -1;
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))
262 return FALSE;
264 return TRUE;
268 BOOL PPipeChannel::Execute()
270 flush();
271 clear();
272 if (hToChild != INVALID_HANDLE_VALUE)
273 CloseHandle(hToChild);
274 hToChild = INVALID_HANDLE_VALUE;
275 return TRUE;
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);
285 if (available != 0)
286 return ConvertOSError(ReadFile(hStandardError,
287 errors.GetPointer(available+1), available,
288 &bytesRead, NULL) ? 0 : -2, LastReadError);
290 if (wait)
291 return FALSE;
293 char firstByte;
294 if (!ReadFile(hStandardError, &firstByte, 1, &bytesRead, NULL))
295 return ConvertOSError(-2, LastReadError);
297 errors = firstByte;
299 if (!PeekNamedPipe(hStandardError, NULL, 0, NULL, &available, NULL))
300 return ConvertOSError(-2, LastReadError);
302 if (available == 0)
303 return TRUE;
305 return ConvertOSError(ReadFile(hStandardError,
306 errors.GetPointer(available+2)+1, available,
307 &bytesRead, NULL) ? 0 : -2, LastReadError);
311 // End Of File ///////////////////////////////////////////////////////////////