##// END OF EJS Templates
Make process execution work under windows.
gvaroquaux -
Show More
@@ -0,0 +1,264 b''
1 # A module to expose various thread/process/job related structures and
2 # methods from kernel32
3 #
4 # The MIT License
5 #
6 # Copyright (c) 2006 the Mozilla Foundation <http://www.mozilla.org>
7 #
8 # Permission is hereby granted, free of charge, to any person obtaining a
9 # copy of this software and associated documentation files (the "Software"),
10 # to deal in the Software without restriction, including without limitation
11 # the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 # and/or sell copies of the Software, and to permit persons to whom the
13 # Software is furnished to do so, subject to the following conditions:
14 #
15 # The above copyright notice and this permission notice shall be included in
16 # all copies or substantial portions of the Software.
17 #
18 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 # DEALINGS IN THE SOFTWARE.
25
26 from ctypes import c_void_p, POINTER, sizeof, Structure, windll, WinError, WINFUNCTYPE
27 from ctypes.wintypes import BOOL, BYTE, DWORD, HANDLE, LPCWSTR, LPWSTR, UINT, WORD
28
29 LPVOID = c_void_p
30 LPBYTE = POINTER(BYTE)
31 LPDWORD = POINTER(DWORD)
32
33 SW_HIDE = 0
34
35 def ErrCheckBool(result, func, args):
36 """errcheck function for Windows functions that return a BOOL True
37 on success"""
38 if not result:
39 raise WinError()
40 return args
41
42 # CloseHandle()
43
44 CloseHandleProto = WINFUNCTYPE(BOOL, HANDLE)
45 CloseHandle = CloseHandleProto(("CloseHandle", windll.kernel32))
46 CloseHandle.errcheck = ErrCheckBool
47
48 # AutoHANDLE
49
50 class AutoHANDLE(HANDLE):
51 """Subclass of HANDLE which will call CloseHandle() on deletion."""
52 def Close(self):
53 if self.value:
54 CloseHandle(self)
55 self.value = 0
56
57 def __del__(self):
58 self.Close()
59
60 def __int__(self):
61 return self.value
62
63 def ErrCheckHandle(result, func, args):
64 """errcheck function for Windows functions that return a HANDLE."""
65 if not result:
66 raise WinError()
67 return AutoHANDLE(result)
68
69 # PROCESS_INFORMATION structure
70
71 class PROCESS_INFORMATION(Structure):
72 _fields_ = [("hProcess", HANDLE),
73 ("hThread", HANDLE),
74 ("dwProcessID", DWORD),
75 ("dwThreadID", DWORD)]
76
77 def __init__(self):
78 Structure.__init__(self)
79
80 self.cb = sizeof(self)
81
82 LPPROCESS_INFORMATION = POINTER(PROCESS_INFORMATION)
83
84 # STARTUPINFO structure
85
86 class STARTUPINFO(Structure):
87 _fields_ = [("cb", DWORD),
88 ("lpReserved", LPWSTR),
89 ("lpDesktop", LPWSTR),
90 ("lpTitle", LPWSTR),
91 ("dwX", DWORD),
92 ("dwY", DWORD),
93 ("dwXSize", DWORD),
94 ("dwYSize", DWORD),
95 ("dwXCountChars", DWORD),
96 ("dwYCountChars", DWORD),
97 ("dwFillAttribute", DWORD),
98 ("dwFlags", DWORD),
99 ("wShowWindow", WORD),
100 ("cbReserved2", WORD),
101 ("lpReserved2", LPBYTE),
102 ("hStdInput", HANDLE),
103 ("hStdOutput", HANDLE),
104 ("hStdError", HANDLE)
105 ]
106 LPSTARTUPINFO = POINTER(STARTUPINFO)
107
108 STARTF_USESHOWWINDOW = 0x01
109 STARTF_USESIZE = 0x02
110 STARTF_USEPOSITION = 0x04
111 STARTF_USECOUNTCHARS = 0x08
112 STARTF_USEFILLATTRIBUTE = 0x10
113 STARTF_RUNFULLSCREEN = 0x20
114 STARTF_FORCEONFEEDBACK = 0x40
115 STARTF_FORCEOFFFEEDBACK = 0x80
116 STARTF_USESTDHANDLES = 0x100
117
118 # EnvironmentBlock
119
120 class EnvironmentBlock:
121 """An object which can be passed as the lpEnv parameter of CreateProcess.
122 It is initialized with a dictionary."""
123
124 def __init__(self, dict):
125 if not dict:
126 self._as_parameter_ = None
127 else:
128 values = ["%s=%s" % (key, value)
129 for (key, value) in dict.iteritems()]
130 values.append("")
131 self._as_parameter_ = LPCWSTR("\0".join(values))
132
133 # CreateProcess()
134
135 CreateProcessProto = WINFUNCTYPE(BOOL, # Return type
136 LPCWSTR, # lpApplicationName
137 LPWSTR, # lpCommandLine
138 LPVOID, # lpProcessAttributes
139 LPVOID, # lpThreadAttributes
140 BOOL, # bInheritHandles
141 DWORD, # dwCreationFlags
142 LPVOID, # lpEnvironment
143 LPCWSTR, # lpCurrentDirectory
144 LPSTARTUPINFO, # lpStartupInfo
145 LPPROCESS_INFORMATION # lpProcessInformation
146 )
147
148 CreateProcessFlags = ((1, "lpApplicationName", None),
149 (1, "lpCommandLine"),
150 (1, "lpProcessAttributes", None),
151 (1, "lpThreadAttributes", None),
152 (1, "bInheritHandles", True),
153 (1, "dwCreationFlags", 0),
154 (1, "lpEnvironment", None),
155 (1, "lpCurrentDirectory", None),
156 (1, "lpStartupInfo"),
157 (2, "lpProcessInformation"))
158
159 def ErrCheckCreateProcess(result, func, args):
160 ErrCheckBool(result, func, args)
161 # return a tuple (hProcess, hThread, dwProcessID, dwThreadID)
162 pi = args[9]
163 return AutoHANDLE(pi.hProcess), AutoHANDLE(pi.hThread), pi.dwProcessID, pi.dwThreadID
164
165 CreateProcess = CreateProcessProto(("CreateProcessW", windll.kernel32),
166 CreateProcessFlags)
167 CreateProcess.errcheck = ErrCheckCreateProcess
168
169 CREATE_BREAKAWAY_FROM_JOB = 0x01000000
170 CREATE_DEFAULT_ERROR_MODE = 0x04000000
171 CREATE_NEW_CONSOLE = 0x00000010
172 CREATE_NEW_PROCESS_GROUP = 0x00000200
173 CREATE_NO_WINDOW = 0x08000000
174 CREATE_SUSPENDED = 0x00000004
175 CREATE_UNICODE_ENVIRONMENT = 0x00000400
176 DEBUG_ONLY_THIS_PROCESS = 0x00000002
177 DEBUG_PROCESS = 0x00000001
178 DETACHED_PROCESS = 0x00000008
179
180 # CreateJobObject()
181
182 CreateJobObjectProto = WINFUNCTYPE(HANDLE, # Return type
183 LPVOID, # lpJobAttributes
184 LPCWSTR # lpName
185 )
186
187 CreateJobObjectFlags = ((1, "lpJobAttributes", None),
188 (1, "lpName", None))
189
190 CreateJobObject = CreateJobObjectProto(("CreateJobObjectW", windll.kernel32),
191 CreateJobObjectFlags)
192 CreateJobObject.errcheck = ErrCheckHandle
193
194 # AssignProcessToJobObject()
195
196 AssignProcessToJobObjectProto = WINFUNCTYPE(BOOL, # Return type
197 HANDLE, # hJob
198 HANDLE # hProcess
199 )
200 AssignProcessToJobObjectFlags = ((1, "hJob"),
201 (1, "hProcess"))
202 AssignProcessToJobObject = AssignProcessToJobObjectProto(
203 ("AssignProcessToJobObject", windll.kernel32),
204 AssignProcessToJobObjectFlags)
205 AssignProcessToJobObject.errcheck = ErrCheckBool
206
207 # ResumeThread()
208
209 def ErrCheckResumeThread(result, func, args):
210 if result == -1:
211 raise WinError()
212
213 return args
214
215 ResumeThreadProto = WINFUNCTYPE(DWORD, # Return type
216 HANDLE # hThread
217 )
218 ResumeThreadFlags = ((1, "hThread"),)
219 ResumeThread = ResumeThreadProto(("ResumeThread", windll.kernel32),
220 ResumeThreadFlags)
221 ResumeThread.errcheck = ErrCheckResumeThread
222
223 # TerminateJobObject()
224
225 TerminateJobObjectProto = WINFUNCTYPE(BOOL, # Return type
226 HANDLE, # hJob
227 UINT # uExitCode
228 )
229 TerminateJobObjectFlags = ((1, "hJob"),
230 (1, "uExitCode", 127))
231 TerminateJobObject = TerminateJobObjectProto(
232 ("TerminateJobObject", windll.kernel32),
233 TerminateJobObjectFlags)
234 TerminateJobObject.errcheck = ErrCheckBool
235
236 # WaitForSingleObject()
237
238 WaitForSingleObjectProto = WINFUNCTYPE(DWORD, # Return type
239 HANDLE, # hHandle
240 DWORD, # dwMilliseconds
241 )
242 WaitForSingleObjectFlags = ((1, "hHandle"),
243 (1, "dwMilliseconds", -1))
244 WaitForSingleObject = WaitForSingleObjectProto(
245 ("WaitForSingleObject", windll.kernel32),
246 WaitForSingleObjectFlags)
247
248 INFINITE = -1
249 WAIT_TIMEOUT = 0x0102
250 WAIT_OBJECT_0 = 0x0
251 WAIT_ABANDONED = 0x0080
252
253 # GetExitCodeProcess()
254
255 GetExitCodeProcessProto = WINFUNCTYPE(BOOL, # Return type
256 HANDLE, # hProcess
257 LPDWORD, # lpExitCode
258 )
259 GetExitCodeProcessFlags = ((1, "hProcess"),
260 (2, "lpExitCode"))
261 GetExitCodeProcess = GetExitCodeProcessProto(
262 ("GetExitCodeProcess", windll.kernel32),
263 GetExitCodeProcessFlags)
264 GetExitCodeProcess.errcheck = ErrCheckBool
@@ -107,7 +107,7 b' class Popen(subprocess.Popen):'
107
107
108 if startupinfo is None:
108 if startupinfo is None:
109 startupinfo = winprocess.STARTUPINFO()
109 startupinfo = winprocess.STARTUPINFO()
110
110
111 if None not in (p2cread, c2pwrite, errwrite):
111 if None not in (p2cread, c2pwrite, errwrite):
112 startupinfo.dwFlags |= winprocess.STARTF_USESTDHANDLES
112 startupinfo.dwFlags |= winprocess.STARTF_USESTDHANDLES
113
113
@@ -194,7 +194,7 b' class ConsoleWidget(editwindow.EditWindow):'
194 self.StyleSetSpec(stc.STC_P_COMMENTBLOCK, p['comment'])
194 self.StyleSetSpec(stc.STC_P_COMMENTBLOCK, p['comment'])
195
195
196
196
197 def write(self, text):
197 def write(self, text, refresh=True):
198 """ Write given text to buffer, while translating the ansi escape
198 """ Write given text to buffer, while translating the ansi escape
199 sequences.
199 sequences.
200 """
200 """
@@ -227,7 +227,8 b' class ConsoleWidget(editwindow.EditWindow):'
227 self.SetStyling(len(text), style)
227 self.SetStyling(len(text), style)
228
228
229 self.GotoPos(self.GetLength())
229 self.GotoPos(self.GetLength())
230 wx.Yield()
230 if refresh:
231 wx.Yield()
231
232
232
233
233 def new_prompt(self, prompt):
234 def new_prompt(self, prompt):
@@ -21,7 +21,7 b' class IPythonXController(WxController):'
21 # Intercept Ctrl-D to quit
21 # Intercept Ctrl-D to quit
22 if event.KeyCode == ord('D') and event.ControlDown() and \
22 if event.KeyCode == ord('D') and event.ControlDown() and \
23 self.get_current_edit_buffer()=='' and \
23 self.get_current_edit_buffer()=='' and \
24 not self.raw_input == __builtin__.raw_input:
24 self._input_state == 'readline':
25 wx.CallAfter(self.ask_exit)
25 wx.CallAfter(self.ask_exit)
26 else:
26 else:
27 WxController._on_key_down(self, event, skip=skip)
27 WxController._on_key_down(self, event, skip=skip)
@@ -257,7 +257,7 b' class WxController(PrefilterFrontEnd, ConsoleWidget):'
257 self._out_buffer.append(text)
257 self._out_buffer.append(text)
258 self._out_buffer_lock.release()
258 self._out_buffer_lock.release()
259 if not self._buffer_flush_timer.IsRunning():
259 if not self._buffer_flush_timer.IsRunning():
260 self._buffer_flush_timer.Start(100) # milliseconds
260 wx.CallAfter(self._buffer_flush_timer.Start, 100) # milliseconds
261
261
262
262
263 def show_traceback(self):
263 def show_traceback(self):
@@ -297,6 +297,7 b' class WxController(PrefilterFrontEnd, ConsoleWidget):'
297 if self.debug:
297 if self.debug:
298 print >>sys.__stderr__, chr(event.KeyCode)
298 print >>sys.__stderr__, chr(event.KeyCode)
299 self._running_process.process.stdin.write(chr(event.KeyCode))
299 self._running_process.process.stdin.write(chr(event.KeyCode))
300 self._running_process.process.stdin.flush()
300 elif event.KeyCode in (ord('('), 57):
301 elif event.KeyCode in (ord('('), 57):
301 # Calltips
302 # Calltips
302 event.Skip()
303 event.Skip()
@@ -372,7 +373,7 b' class WxController(PrefilterFrontEnd, ConsoleWidget):'
372 _out_buffer = self._out_buffer
373 _out_buffer = self._out_buffer
373 self._out_buffer = []
374 self._out_buffer = []
374 self._out_buffer_lock.release()
375 self._out_buffer_lock.release()
375 self.write(''.join(_out_buffer))
376 self.write(''.join(_out_buffer), refresh=False)
376 self._buffer_flush_timer.Stop()
377 self._buffer_flush_timer.Stop()
377
378
378
379
General Comments 0
You need to be logged in to leave comments. Login now