11#include " stdafx.h"
22#include " ProcessExecute.h"
3+ #include " WcharMbcsConverter.h"
34
45/* The Console Redirection is taken from the TagsView plugin from Vitaliy Dovgan.
56 * My thanks to him for pointing me in the right direction. :)
1112#define PIPE_READBUFSIZE 4096
1213
1314using namespace boost ::python;
15+ using namespace std ;
1416
1517ProcessExecute::ProcessExecute ()
1618{
@@ -29,19 +31,24 @@ bool ProcessExecute::isWindowsNT()
2931 return (osv.dwPlatformId >= VER_PLATFORM_WIN32_NT);
3032}
3133
32- int ProcessExecute::execute (const TCHAR *commandLine, boost::python::object pyStdout, boost::python::object pyStderr, boost::python::object pyStdin)
34+ long ProcessExecute::execute (const TCHAR *commandLine, boost::python::object pyStdout, boost::python::object pyStderr, boost::python::object pyStdin)
3335{
36+ DWORD returnValue = 0 ;
37+
3438 if (pyStdout.is_none ())
35- return 3 ;
39+ throw process_start_exception ( " stdout cannot be None " ) ;
3640 if (pyStderr.is_none ())
37- return 4 ;
41+ throw process_start_exception ( " stderr cannot be None " ) ;
3842
3943 // Create out, err, and in pipes (ignore in, initially)
4044 SECURITY_DESCRIPTOR sd;
4145 SECURITY_ATTRIBUTES sa;
46+ process_start_exception exceptionThrown (" " );
47+ bool thrown = false ;
4248
4349 Py_BEGIN_ALLOW_THREADS
44-
50+ try
51+ {
4552 if (isWindowsNT ())
4653 {
4754 ::InitializeSecurityDescriptor ( &sd, SECURITY_DESCRIPTOR_REVISION );
@@ -57,14 +64,12 @@ int ProcessExecute::execute(const TCHAR *commandLine, boost::python::object pySt
5764
5865 if (!::CreatePipe (&m_hStdOutReadPipe, &m_hStdOutWritePipe, &sa, DEFAULT_PIPE_SIZE))
5966 {
60- // TODO throw exception
61- return -1 ;
67+ throw process_start_exception (" Error creating pipe for stdout" );
6268 }
6369
6470 if (!::CreatePipe (&m_hStdErrReadPipe, &m_hStdErrWritePipe, &sa, DEFAULT_PIPE_SIZE))
6571 {
66- // TODO throw exception
67- return -1 ;
72+ throw process_start_exception (" Error creating pipe for stderr" );
6873 }
6974
7075 HANDLE stopEvent = CreateEvent (NULL , TRUE , FALSE , NULL );
@@ -93,15 +98,14 @@ int ProcessExecute::execute(const TCHAR *commandLine, boost::python::object pySt
9398 (LPVOID) &stdoutReaderArgs, // thread parameter
9499 0 , // not suspended
95100 &dwThreadId); // returns thread ID
96- /*
101+
97102 HANDLE hStderrThread = CreateThread (
98103 NULL , // no security attribute
99104 0 , // default stack size
100105 pipeReader, // thread proc
101106 (LPVOID) &stderrReaderArgs, // thread parameter
102107 0 , // not suspended
103108 &dwThreadId); // returns thread ID
104- */
105109
106110
107111 // start process
@@ -119,12 +123,14 @@ int ProcessExecute::execute(const TCHAR *commandLine, boost::python::object pySt
119123 si.wShowWindow = SW_HIDE;
120124 si.hStdInput = NULL ;
121125 si.hStdOutput = m_hStdOutWritePipe;
122- si.hStdError = m_hStdOutWritePipe ;
126+ si.hStdError = m_hStdErrWritePipe ;
123127
124128 ::ZeroMemory ( &pi, sizeof (PROCESS_INFORMATION) );
129+
125130 int commandLineLength = _tcslen (commandLine) + 1 ;
126131 TCHAR *cmdLine = new TCHAR[commandLineLength];
127132 _tcscpy_s (cmdLine, commandLineLength, commandLine);
133+ bool processStartSuccess;
128134
129135 if ( ::CreateProcess (
130136 NULL ,
@@ -141,18 +147,64 @@ int ProcessExecute::execute(const TCHAR *commandLine, boost::python::object pySt
141147 {
142148 // wait for process to exit
143149 ::WaitForSingleObject (pi.hProcess, INFINITE);
144-
150+ CloseHandle (pi.hThread );
151+
152+ processStartSuccess = true ;
153+
154+ }
155+ else
156+ {
157+ processStartSuccess = false ;
145158 }
146159
147160
148- // Abort / Stop somehow the reader threads
149- SetEvent (stopEvent);
161+
162+ // Stop the reader threads
163+ SetEvent (stopEvent);
164+ // Wait for the pipe reader threads to complete
150165 HANDLE handles[] = { stdoutReaderArgs.completedEvent , stderrReaderArgs.completedEvent };
166+ WaitForMultipleObjects (2 , handles, TRUE , INFINITE);
167+ CloseHandle (stdoutReaderArgs.completedEvent );
168+ CloseHandle (stderrReaderArgs.completedEvent );
169+ CloseHandle (hStdoutThread);
170+ CloseHandle (hStderrThread);
171+ CloseHandle (stopEvent);
172+
173+ if (processStartSuccess)
174+ {
175+ GetExitCodeProcess (pi.hProcess , &returnValue);
176+ CloseHandle (pi.hProcess );
177+ }
178+ else
179+ {
180+ DWORD errorNo = ::GetLastError ();
181+ TCHAR *buffer;
182+
183+ ::FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL , errorNo, 0 , reinterpret_cast <LPTSTR>(&buffer), 0, NULL);
184+
185+ shared_ptr<char > message = WcharMbcsConverter::tchar2char (buffer);
186+ process_start_exception ex (message.get ());
187+
188+ ::LocalFree (buffer);
189+ throw ex;
190+
191+ }
192+ }
193+ catch (process_start_exception& ex)
194+ {
195+ exceptionThrown = ex;
196+ thrown = true ;
197+ }
198+
151199
152- // WaitForMultipleObjects(2, handles, TRUE, INFINITE);
153- int returnedIndex = WaitForSingleObject (stdoutReaderArgs.completedEvent , INFINITE);
154200 Py_END_ALLOW_THREADS
155- return 0 ;
201+
202+ if (thrown)
203+ {
204+ throw exceptionThrown;
205+ }
206+
207+ return returnValue;
156208}
157209
158210
0 commit comments