##// END OF EJS Templates
win32: specify _CREATE_NO_WINDOW on spawndetached()...
Adrian Buehlmann -
r17050:e780fb37 default
parent child Browse files
Show More
@@ -1,396 +1,396
1 # win32.py - utility functions that use win32 API
1 # win32.py - utility functions that use win32 API
2 #
2 #
3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 import ctypes, errno, os, subprocess, random
8 import ctypes, errno, os, subprocess, random
9
9
10 _kernel32 = ctypes.windll.kernel32
10 _kernel32 = ctypes.windll.kernel32
11 _advapi32 = ctypes.windll.advapi32
11 _advapi32 = ctypes.windll.advapi32
12 _user32 = ctypes.windll.user32
12 _user32 = ctypes.windll.user32
13
13
14 _BOOL = ctypes.c_long
14 _BOOL = ctypes.c_long
15 _WORD = ctypes.c_ushort
15 _WORD = ctypes.c_ushort
16 _DWORD = ctypes.c_ulong
16 _DWORD = ctypes.c_ulong
17 _UINT = ctypes.c_uint
17 _UINT = ctypes.c_uint
18 _LONG = ctypes.c_long
18 _LONG = ctypes.c_long
19 _LPCSTR = _LPSTR = ctypes.c_char_p
19 _LPCSTR = _LPSTR = ctypes.c_char_p
20 _HANDLE = ctypes.c_void_p
20 _HANDLE = ctypes.c_void_p
21 _HWND = _HANDLE
21 _HWND = _HANDLE
22
22
23 _INVALID_HANDLE_VALUE = _HANDLE(-1).value
23 _INVALID_HANDLE_VALUE = _HANDLE(-1).value
24
24
25 # GetLastError
25 # GetLastError
26 _ERROR_SUCCESS = 0
26 _ERROR_SUCCESS = 0
27 _ERROR_INVALID_PARAMETER = 87
27 _ERROR_INVALID_PARAMETER = 87
28 _ERROR_INSUFFICIENT_BUFFER = 122
28 _ERROR_INSUFFICIENT_BUFFER = 122
29
29
30 # WPARAM is defined as UINT_PTR (unsigned type)
30 # WPARAM is defined as UINT_PTR (unsigned type)
31 # LPARAM is defined as LONG_PTR (signed type)
31 # LPARAM is defined as LONG_PTR (signed type)
32 if ctypes.sizeof(ctypes.c_long) == ctypes.sizeof(ctypes.c_void_p):
32 if ctypes.sizeof(ctypes.c_long) == ctypes.sizeof(ctypes.c_void_p):
33 _WPARAM = ctypes.c_ulong
33 _WPARAM = ctypes.c_ulong
34 _LPARAM = ctypes.c_long
34 _LPARAM = ctypes.c_long
35 elif ctypes.sizeof(ctypes.c_longlong) == ctypes.sizeof(ctypes.c_void_p):
35 elif ctypes.sizeof(ctypes.c_longlong) == ctypes.sizeof(ctypes.c_void_p):
36 _WPARAM = ctypes.c_ulonglong
36 _WPARAM = ctypes.c_ulonglong
37 _LPARAM = ctypes.c_longlong
37 _LPARAM = ctypes.c_longlong
38
38
39 class _FILETIME(ctypes.Structure):
39 class _FILETIME(ctypes.Structure):
40 _fields_ = [('dwLowDateTime', _DWORD),
40 _fields_ = [('dwLowDateTime', _DWORD),
41 ('dwHighDateTime', _DWORD)]
41 ('dwHighDateTime', _DWORD)]
42
42
43 class _BY_HANDLE_FILE_INFORMATION(ctypes.Structure):
43 class _BY_HANDLE_FILE_INFORMATION(ctypes.Structure):
44 _fields_ = [('dwFileAttributes', _DWORD),
44 _fields_ = [('dwFileAttributes', _DWORD),
45 ('ftCreationTime', _FILETIME),
45 ('ftCreationTime', _FILETIME),
46 ('ftLastAccessTime', _FILETIME),
46 ('ftLastAccessTime', _FILETIME),
47 ('ftLastWriteTime', _FILETIME),
47 ('ftLastWriteTime', _FILETIME),
48 ('dwVolumeSerialNumber', _DWORD),
48 ('dwVolumeSerialNumber', _DWORD),
49 ('nFileSizeHigh', _DWORD),
49 ('nFileSizeHigh', _DWORD),
50 ('nFileSizeLow', _DWORD),
50 ('nFileSizeLow', _DWORD),
51 ('nNumberOfLinks', _DWORD),
51 ('nNumberOfLinks', _DWORD),
52 ('nFileIndexHigh', _DWORD),
52 ('nFileIndexHigh', _DWORD),
53 ('nFileIndexLow', _DWORD)]
53 ('nFileIndexLow', _DWORD)]
54
54
55 # CreateFile
55 # CreateFile
56 _FILE_SHARE_READ = 0x00000001
56 _FILE_SHARE_READ = 0x00000001
57 _FILE_SHARE_WRITE = 0x00000002
57 _FILE_SHARE_WRITE = 0x00000002
58 _FILE_SHARE_DELETE = 0x00000004
58 _FILE_SHARE_DELETE = 0x00000004
59
59
60 _OPEN_EXISTING = 3
60 _OPEN_EXISTING = 3
61
61
62 _FILE_FLAG_BACKUP_SEMANTICS = 0x02000000
62 _FILE_FLAG_BACKUP_SEMANTICS = 0x02000000
63
63
64 # SetFileAttributes
64 # SetFileAttributes
65 _FILE_ATTRIBUTE_NORMAL = 0x80
65 _FILE_ATTRIBUTE_NORMAL = 0x80
66 _FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x2000
66 _FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x2000
67
67
68 # Process Security and Access Rights
68 # Process Security and Access Rights
69 _PROCESS_QUERY_INFORMATION = 0x0400
69 _PROCESS_QUERY_INFORMATION = 0x0400
70
70
71 # GetExitCodeProcess
71 # GetExitCodeProcess
72 _STILL_ACTIVE = 259
72 _STILL_ACTIVE = 259
73
73
74 class _STARTUPINFO(ctypes.Structure):
74 class _STARTUPINFO(ctypes.Structure):
75 _fields_ = [('cb', _DWORD),
75 _fields_ = [('cb', _DWORD),
76 ('lpReserved', _LPSTR),
76 ('lpReserved', _LPSTR),
77 ('lpDesktop', _LPSTR),
77 ('lpDesktop', _LPSTR),
78 ('lpTitle', _LPSTR),
78 ('lpTitle', _LPSTR),
79 ('dwX', _DWORD),
79 ('dwX', _DWORD),
80 ('dwY', _DWORD),
80 ('dwY', _DWORD),
81 ('dwXSize', _DWORD),
81 ('dwXSize', _DWORD),
82 ('dwYSize', _DWORD),
82 ('dwYSize', _DWORD),
83 ('dwXCountChars', _DWORD),
83 ('dwXCountChars', _DWORD),
84 ('dwYCountChars', _DWORD),
84 ('dwYCountChars', _DWORD),
85 ('dwFillAttribute', _DWORD),
85 ('dwFillAttribute', _DWORD),
86 ('dwFlags', _DWORD),
86 ('dwFlags', _DWORD),
87 ('wShowWindow', _WORD),
87 ('wShowWindow', _WORD),
88 ('cbReserved2', _WORD),
88 ('cbReserved2', _WORD),
89 ('lpReserved2', ctypes.c_char_p),
89 ('lpReserved2', ctypes.c_char_p),
90 ('hStdInput', _HANDLE),
90 ('hStdInput', _HANDLE),
91 ('hStdOutput', _HANDLE),
91 ('hStdOutput', _HANDLE),
92 ('hStdError', _HANDLE)]
92 ('hStdError', _HANDLE)]
93
93
94 class _PROCESS_INFORMATION(ctypes.Structure):
94 class _PROCESS_INFORMATION(ctypes.Structure):
95 _fields_ = [('hProcess', _HANDLE),
95 _fields_ = [('hProcess', _HANDLE),
96 ('hThread', _HANDLE),
96 ('hThread', _HANDLE),
97 ('dwProcessId', _DWORD),
97 ('dwProcessId', _DWORD),
98 ('dwThreadId', _DWORD)]
98 ('dwThreadId', _DWORD)]
99
99
100 _DETACHED_PROCESS = 0x00000008
100 _CREATE_NO_WINDOW = 0x08000000
101 _STARTF_USESHOWWINDOW = 0x00000001
101 _STARTF_USESHOWWINDOW = 0x00000001
102 _SW_HIDE = 0
102 _SW_HIDE = 0
103
103
104 class _COORD(ctypes.Structure):
104 class _COORD(ctypes.Structure):
105 _fields_ = [('X', ctypes.c_short),
105 _fields_ = [('X', ctypes.c_short),
106 ('Y', ctypes.c_short)]
106 ('Y', ctypes.c_short)]
107
107
108 class _SMALL_RECT(ctypes.Structure):
108 class _SMALL_RECT(ctypes.Structure):
109 _fields_ = [('Left', ctypes.c_short),
109 _fields_ = [('Left', ctypes.c_short),
110 ('Top', ctypes.c_short),
110 ('Top', ctypes.c_short),
111 ('Right', ctypes.c_short),
111 ('Right', ctypes.c_short),
112 ('Bottom', ctypes.c_short)]
112 ('Bottom', ctypes.c_short)]
113
113
114 class _CONSOLE_SCREEN_BUFFER_INFO(ctypes.Structure):
114 class _CONSOLE_SCREEN_BUFFER_INFO(ctypes.Structure):
115 _fields_ = [('dwSize', _COORD),
115 _fields_ = [('dwSize', _COORD),
116 ('dwCursorPosition', _COORD),
116 ('dwCursorPosition', _COORD),
117 ('wAttributes', _WORD),
117 ('wAttributes', _WORD),
118 ('srWindow', _SMALL_RECT),
118 ('srWindow', _SMALL_RECT),
119 ('dwMaximumWindowSize', _COORD)]
119 ('dwMaximumWindowSize', _COORD)]
120
120
121 _STD_ERROR_HANDLE = _DWORD(-12).value
121 _STD_ERROR_HANDLE = _DWORD(-12).value
122
122
123 # types of parameters of C functions used (required by pypy)
123 # types of parameters of C functions used (required by pypy)
124
124
125 _kernel32.CreateFileA.argtypes = [_LPCSTR, _DWORD, _DWORD, ctypes.c_void_p,
125 _kernel32.CreateFileA.argtypes = [_LPCSTR, _DWORD, _DWORD, ctypes.c_void_p,
126 _DWORD, _DWORD, _HANDLE]
126 _DWORD, _DWORD, _HANDLE]
127 _kernel32.CreateFileA.restype = _HANDLE
127 _kernel32.CreateFileA.restype = _HANDLE
128
128
129 _kernel32.GetFileInformationByHandle.argtypes = [_HANDLE, ctypes.c_void_p]
129 _kernel32.GetFileInformationByHandle.argtypes = [_HANDLE, ctypes.c_void_p]
130 _kernel32.GetFileInformationByHandle.restype = _BOOL
130 _kernel32.GetFileInformationByHandle.restype = _BOOL
131
131
132 _kernel32.CloseHandle.argtypes = [_HANDLE]
132 _kernel32.CloseHandle.argtypes = [_HANDLE]
133 _kernel32.CloseHandle.restype = _BOOL
133 _kernel32.CloseHandle.restype = _BOOL
134
134
135 try:
135 try:
136 _kernel32.CreateHardLinkA.argtypes = [_LPCSTR, _LPCSTR, ctypes.c_void_p]
136 _kernel32.CreateHardLinkA.argtypes = [_LPCSTR, _LPCSTR, ctypes.c_void_p]
137 _kernel32.CreateHardLinkA.restype = _BOOL
137 _kernel32.CreateHardLinkA.restype = _BOOL
138 except AttributeError:
138 except AttributeError:
139 pass
139 pass
140
140
141 _kernel32.SetFileAttributesA.argtypes = [_LPCSTR, _DWORD]
141 _kernel32.SetFileAttributesA.argtypes = [_LPCSTR, _DWORD]
142 _kernel32.SetFileAttributesA.restype = _BOOL
142 _kernel32.SetFileAttributesA.restype = _BOOL
143
143
144 _kernel32.OpenProcess.argtypes = [_DWORD, _BOOL, _DWORD]
144 _kernel32.OpenProcess.argtypes = [_DWORD, _BOOL, _DWORD]
145 _kernel32.OpenProcess.restype = _HANDLE
145 _kernel32.OpenProcess.restype = _HANDLE
146
146
147 _kernel32.GetExitCodeProcess.argtypes = [_HANDLE, ctypes.c_void_p]
147 _kernel32.GetExitCodeProcess.argtypes = [_HANDLE, ctypes.c_void_p]
148 _kernel32.GetExitCodeProcess.restype = _BOOL
148 _kernel32.GetExitCodeProcess.restype = _BOOL
149
149
150 _kernel32.GetLastError.argtypes = []
150 _kernel32.GetLastError.argtypes = []
151 _kernel32.GetLastError.restype = _DWORD
151 _kernel32.GetLastError.restype = _DWORD
152
152
153 _kernel32.GetModuleFileNameA.argtypes = [_HANDLE, ctypes.c_void_p, _DWORD]
153 _kernel32.GetModuleFileNameA.argtypes = [_HANDLE, ctypes.c_void_p, _DWORD]
154 _kernel32.GetModuleFileNameA.restype = _DWORD
154 _kernel32.GetModuleFileNameA.restype = _DWORD
155
155
156 _kernel32.CreateProcessA.argtypes = [_LPCSTR, _LPCSTR, ctypes.c_void_p,
156 _kernel32.CreateProcessA.argtypes = [_LPCSTR, _LPCSTR, ctypes.c_void_p,
157 ctypes.c_void_p, _BOOL, _DWORD, ctypes.c_void_p, _LPCSTR, ctypes.c_void_p,
157 ctypes.c_void_p, _BOOL, _DWORD, ctypes.c_void_p, _LPCSTR, ctypes.c_void_p,
158 ctypes.c_void_p]
158 ctypes.c_void_p]
159 _kernel32.CreateProcessA.restype = _BOOL
159 _kernel32.CreateProcessA.restype = _BOOL
160
160
161 _kernel32.ExitProcess.argtypes = [_UINT]
161 _kernel32.ExitProcess.argtypes = [_UINT]
162 _kernel32.ExitProcess.restype = None
162 _kernel32.ExitProcess.restype = None
163
163
164 _kernel32.GetCurrentProcessId.argtypes = []
164 _kernel32.GetCurrentProcessId.argtypes = []
165 _kernel32.GetCurrentProcessId.restype = _DWORD
165 _kernel32.GetCurrentProcessId.restype = _DWORD
166
166
167 _SIGNAL_HANDLER = ctypes.WINFUNCTYPE(_BOOL, _DWORD)
167 _SIGNAL_HANDLER = ctypes.WINFUNCTYPE(_BOOL, _DWORD)
168 _kernel32.SetConsoleCtrlHandler.argtypes = [_SIGNAL_HANDLER, _BOOL]
168 _kernel32.SetConsoleCtrlHandler.argtypes = [_SIGNAL_HANDLER, _BOOL]
169 _kernel32.SetConsoleCtrlHandler.restype = _BOOL
169 _kernel32.SetConsoleCtrlHandler.restype = _BOOL
170
170
171 _kernel32.GetStdHandle.argtypes = [_DWORD]
171 _kernel32.GetStdHandle.argtypes = [_DWORD]
172 _kernel32.GetStdHandle.restype = _HANDLE
172 _kernel32.GetStdHandle.restype = _HANDLE
173
173
174 _kernel32.GetConsoleScreenBufferInfo.argtypes = [_HANDLE, ctypes.c_void_p]
174 _kernel32.GetConsoleScreenBufferInfo.argtypes = [_HANDLE, ctypes.c_void_p]
175 _kernel32.GetConsoleScreenBufferInfo.restype = _BOOL
175 _kernel32.GetConsoleScreenBufferInfo.restype = _BOOL
176
176
177 _advapi32.GetUserNameA.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
177 _advapi32.GetUserNameA.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
178 _advapi32.GetUserNameA.restype = _BOOL
178 _advapi32.GetUserNameA.restype = _BOOL
179
179
180 _user32.GetWindowThreadProcessId.argtypes = [_HANDLE, ctypes.c_void_p]
180 _user32.GetWindowThreadProcessId.argtypes = [_HANDLE, ctypes.c_void_p]
181 _user32.GetWindowThreadProcessId.restype = _DWORD
181 _user32.GetWindowThreadProcessId.restype = _DWORD
182
182
183 _user32.ShowWindow.argtypes = [_HANDLE, ctypes.c_int]
183 _user32.ShowWindow.argtypes = [_HANDLE, ctypes.c_int]
184 _user32.ShowWindow.restype = _BOOL
184 _user32.ShowWindow.restype = _BOOL
185
185
186 _WNDENUMPROC = ctypes.WINFUNCTYPE(_BOOL, _HWND, _LPARAM)
186 _WNDENUMPROC = ctypes.WINFUNCTYPE(_BOOL, _HWND, _LPARAM)
187 _user32.EnumWindows.argtypes = [_WNDENUMPROC, _LPARAM]
187 _user32.EnumWindows.argtypes = [_WNDENUMPROC, _LPARAM]
188 _user32.EnumWindows.restype = _BOOL
188 _user32.EnumWindows.restype = _BOOL
189
189
190 def _raiseoserror(name):
190 def _raiseoserror(name):
191 err = ctypes.WinError()
191 err = ctypes.WinError()
192 raise OSError(err.errno, '%s: %s' % (name, err.strerror))
192 raise OSError(err.errno, '%s: %s' % (name, err.strerror))
193
193
194 def _getfileinfo(name):
194 def _getfileinfo(name):
195 fh = _kernel32.CreateFileA(name, 0,
195 fh = _kernel32.CreateFileA(name, 0,
196 _FILE_SHARE_READ | _FILE_SHARE_WRITE | _FILE_SHARE_DELETE,
196 _FILE_SHARE_READ | _FILE_SHARE_WRITE | _FILE_SHARE_DELETE,
197 None, _OPEN_EXISTING, _FILE_FLAG_BACKUP_SEMANTICS, None)
197 None, _OPEN_EXISTING, _FILE_FLAG_BACKUP_SEMANTICS, None)
198 if fh == _INVALID_HANDLE_VALUE:
198 if fh == _INVALID_HANDLE_VALUE:
199 _raiseoserror(name)
199 _raiseoserror(name)
200 try:
200 try:
201 fi = _BY_HANDLE_FILE_INFORMATION()
201 fi = _BY_HANDLE_FILE_INFORMATION()
202 if not _kernel32.GetFileInformationByHandle(fh, ctypes.byref(fi)):
202 if not _kernel32.GetFileInformationByHandle(fh, ctypes.byref(fi)):
203 _raiseoserror(name)
203 _raiseoserror(name)
204 return fi
204 return fi
205 finally:
205 finally:
206 _kernel32.CloseHandle(fh)
206 _kernel32.CloseHandle(fh)
207
207
208 def oslink(src, dst):
208 def oslink(src, dst):
209 try:
209 try:
210 if not _kernel32.CreateHardLinkA(dst, src, None):
210 if not _kernel32.CreateHardLinkA(dst, src, None):
211 _raiseoserror(src)
211 _raiseoserror(src)
212 except AttributeError: # Wine doesn't support this function
212 except AttributeError: # Wine doesn't support this function
213 _raiseoserror(src)
213 _raiseoserror(src)
214
214
215 def nlinks(name):
215 def nlinks(name):
216 '''return number of hardlinks for the given file'''
216 '''return number of hardlinks for the given file'''
217 return _getfileinfo(name).nNumberOfLinks
217 return _getfileinfo(name).nNumberOfLinks
218
218
219 def samefile(path1, path2):
219 def samefile(path1, path2):
220 '''Returns whether path1 and path2 refer to the same file or directory.'''
220 '''Returns whether path1 and path2 refer to the same file or directory.'''
221 res1 = _getfileinfo(path1)
221 res1 = _getfileinfo(path1)
222 res2 = _getfileinfo(path2)
222 res2 = _getfileinfo(path2)
223 return (res1.dwVolumeSerialNumber == res2.dwVolumeSerialNumber
223 return (res1.dwVolumeSerialNumber == res2.dwVolumeSerialNumber
224 and res1.nFileIndexHigh == res2.nFileIndexHigh
224 and res1.nFileIndexHigh == res2.nFileIndexHigh
225 and res1.nFileIndexLow == res2.nFileIndexLow)
225 and res1.nFileIndexLow == res2.nFileIndexLow)
226
226
227 def samedevice(path1, path2):
227 def samedevice(path1, path2):
228 '''Returns whether path1 and path2 are on the same device.'''
228 '''Returns whether path1 and path2 are on the same device.'''
229 res1 = _getfileinfo(path1)
229 res1 = _getfileinfo(path1)
230 res2 = _getfileinfo(path2)
230 res2 = _getfileinfo(path2)
231 return res1.dwVolumeSerialNumber == res2.dwVolumeSerialNumber
231 return res1.dwVolumeSerialNumber == res2.dwVolumeSerialNumber
232
232
233 def testpid(pid):
233 def testpid(pid):
234 '''return True if pid is still running or unable to
234 '''return True if pid is still running or unable to
235 determine, False otherwise'''
235 determine, False otherwise'''
236 h = _kernel32.OpenProcess(_PROCESS_QUERY_INFORMATION, False, pid)
236 h = _kernel32.OpenProcess(_PROCESS_QUERY_INFORMATION, False, pid)
237 if h:
237 if h:
238 try:
238 try:
239 status = _DWORD()
239 status = _DWORD()
240 if _kernel32.GetExitCodeProcess(h, ctypes.byref(status)):
240 if _kernel32.GetExitCodeProcess(h, ctypes.byref(status)):
241 return status.value == _STILL_ACTIVE
241 return status.value == _STILL_ACTIVE
242 finally:
242 finally:
243 _kernel32.CloseHandle(h)
243 _kernel32.CloseHandle(h)
244 return _kernel32.GetLastError() != _ERROR_INVALID_PARAMETER
244 return _kernel32.GetLastError() != _ERROR_INVALID_PARAMETER
245
245
246 def executablepath():
246 def executablepath():
247 '''return full path of hg.exe'''
247 '''return full path of hg.exe'''
248 size = 600
248 size = 600
249 buf = ctypes.create_string_buffer(size + 1)
249 buf = ctypes.create_string_buffer(size + 1)
250 len = _kernel32.GetModuleFileNameA(None, ctypes.byref(buf), size)
250 len = _kernel32.GetModuleFileNameA(None, ctypes.byref(buf), size)
251 if len == 0:
251 if len == 0:
252 raise ctypes.WinError
252 raise ctypes.WinError
253 elif len == size:
253 elif len == size:
254 raise ctypes.WinError(_ERROR_INSUFFICIENT_BUFFER)
254 raise ctypes.WinError(_ERROR_INSUFFICIENT_BUFFER)
255 return buf.value
255 return buf.value
256
256
257 def getuser():
257 def getuser():
258 '''return name of current user'''
258 '''return name of current user'''
259 size = _DWORD(300)
259 size = _DWORD(300)
260 buf = ctypes.create_string_buffer(size.value + 1)
260 buf = ctypes.create_string_buffer(size.value + 1)
261 if not _advapi32.GetUserNameA(ctypes.byref(buf), ctypes.byref(size)):
261 if not _advapi32.GetUserNameA(ctypes.byref(buf), ctypes.byref(size)):
262 raise ctypes.WinError
262 raise ctypes.WinError
263 return buf.value
263 return buf.value
264
264
265 _signalhandler = []
265 _signalhandler = []
266
266
267 def setsignalhandler():
267 def setsignalhandler():
268 '''Register a termination handler for console events including
268 '''Register a termination handler for console events including
269 CTRL+C. python signal handlers do not work well with socket
269 CTRL+C. python signal handlers do not work well with socket
270 operations.
270 operations.
271 '''
271 '''
272 def handler(event):
272 def handler(event):
273 _kernel32.ExitProcess(1)
273 _kernel32.ExitProcess(1)
274
274
275 if _signalhandler:
275 if _signalhandler:
276 return # already registered
276 return # already registered
277 h = _SIGNAL_HANDLER(handler)
277 h = _SIGNAL_HANDLER(handler)
278 _signalhandler.append(h) # needed to prevent garbage collection
278 _signalhandler.append(h) # needed to prevent garbage collection
279 if not _kernel32.SetConsoleCtrlHandler(h, True):
279 if not _kernel32.SetConsoleCtrlHandler(h, True):
280 raise ctypes.WinError
280 raise ctypes.WinError
281
281
282 def hidewindow():
282 def hidewindow():
283
283
284 def callback(hwnd, pid):
284 def callback(hwnd, pid):
285 wpid = _DWORD()
285 wpid = _DWORD()
286 _user32.GetWindowThreadProcessId(hwnd, ctypes.byref(wpid))
286 _user32.GetWindowThreadProcessId(hwnd, ctypes.byref(wpid))
287 if pid == wpid.value:
287 if pid == wpid.value:
288 _user32.ShowWindow(hwnd, _SW_HIDE)
288 _user32.ShowWindow(hwnd, _SW_HIDE)
289 return False # stop enumerating windows
289 return False # stop enumerating windows
290 return True
290 return True
291
291
292 pid = _kernel32.GetCurrentProcessId()
292 pid = _kernel32.GetCurrentProcessId()
293 _user32.EnumWindows(_WNDENUMPROC(callback), pid)
293 _user32.EnumWindows(_WNDENUMPROC(callback), pid)
294
294
295 def termwidth():
295 def termwidth():
296 # cmd.exe does not handle CR like a unix console, the CR is
296 # cmd.exe does not handle CR like a unix console, the CR is
297 # counted in the line length. On 80 columns consoles, if 80
297 # counted in the line length. On 80 columns consoles, if 80
298 # characters are written, the following CR won't apply on the
298 # characters are written, the following CR won't apply on the
299 # current line but on the new one. Keep room for it.
299 # current line but on the new one. Keep room for it.
300 width = 79
300 width = 79
301 # Query stderr to avoid problems with redirections
301 # Query stderr to avoid problems with redirections
302 screenbuf = _kernel32.GetStdHandle(
302 screenbuf = _kernel32.GetStdHandle(
303 _STD_ERROR_HANDLE) # don't close the handle returned
303 _STD_ERROR_HANDLE) # don't close the handle returned
304 if screenbuf is None or screenbuf == _INVALID_HANDLE_VALUE:
304 if screenbuf is None or screenbuf == _INVALID_HANDLE_VALUE:
305 return width
305 return width
306 csbi = _CONSOLE_SCREEN_BUFFER_INFO()
306 csbi = _CONSOLE_SCREEN_BUFFER_INFO()
307 if not _kernel32.GetConsoleScreenBufferInfo(
307 if not _kernel32.GetConsoleScreenBufferInfo(
308 screenbuf, ctypes.byref(csbi)):
308 screenbuf, ctypes.byref(csbi)):
309 return width
309 return width
310 width = csbi.srWindow.Right - csbi.srWindow.Left
310 width = csbi.srWindow.Right - csbi.srWindow.Left
311 return width
311 return width
312
312
313 def spawndetached(args):
313 def spawndetached(args):
314 # No standard library function really spawns a fully detached
314 # No standard library function really spawns a fully detached
315 # process under win32 because they allocate pipes or other objects
315 # process under win32 because they allocate pipes or other objects
316 # to handle standard streams communications. Passing these objects
316 # to handle standard streams communications. Passing these objects
317 # to the child process requires handle inheritance to be enabled
317 # to the child process requires handle inheritance to be enabled
318 # which makes really detached processes impossible.
318 # which makes really detached processes impossible.
319 si = _STARTUPINFO()
319 si = _STARTUPINFO()
320 si.cb = ctypes.sizeof(_STARTUPINFO)
320 si.cb = ctypes.sizeof(_STARTUPINFO)
321 si.dwFlags = _STARTF_USESHOWWINDOW
321 si.dwFlags = _STARTF_USESHOWWINDOW
322 si.wShowWindow = _SW_HIDE
322 si.wShowWindow = _SW_HIDE
323
323
324 pi = _PROCESS_INFORMATION()
324 pi = _PROCESS_INFORMATION()
325
325
326 env = ''
326 env = ''
327 for k in os.environ:
327 for k in os.environ:
328 env += "%s=%s\0" % (k, os.environ[k])
328 env += "%s=%s\0" % (k, os.environ[k])
329 if not env:
329 if not env:
330 env = '\0'
330 env = '\0'
331 env += '\0'
331 env += '\0'
332
332
333 args = subprocess.list2cmdline(args)
333 args = subprocess.list2cmdline(args)
334 # Not running the command in shell mode makes python26 hang when
334 # Not running the command in shell mode makes python26 hang when
335 # writing to hgweb output socket.
335 # writing to hgweb output socket.
336 comspec = os.environ.get("COMSPEC", "cmd.exe")
336 comspec = os.environ.get("COMSPEC", "cmd.exe")
337 args = comspec + " /c " + args
337 args = comspec + " /c " + args
338
338
339 res = _kernel32.CreateProcessA(
339 res = _kernel32.CreateProcessA(
340 None, args, None, None, False, _DETACHED_PROCESS,
340 None, args, None, None, False, _CREATE_NO_WINDOW,
341 env, os.getcwd(), ctypes.byref(si), ctypes.byref(pi))
341 env, os.getcwd(), ctypes.byref(si), ctypes.byref(pi))
342 if not res:
342 if not res:
343 raise ctypes.WinError
343 raise ctypes.WinError
344
344
345 return pi.dwProcessId
345 return pi.dwProcessId
346
346
347 def unlink(f):
347 def unlink(f):
348 '''try to implement POSIX' unlink semantics on Windows'''
348 '''try to implement POSIX' unlink semantics on Windows'''
349
349
350 # POSIX allows to unlink and rename open files. Windows has serious
350 # POSIX allows to unlink and rename open files. Windows has serious
351 # problems with doing that:
351 # problems with doing that:
352 # - Calling os.unlink (or os.rename) on a file f fails if f or any
352 # - Calling os.unlink (or os.rename) on a file f fails if f or any
353 # hardlinked copy of f has been opened with Python's open(). There is no
353 # hardlinked copy of f has been opened with Python's open(). There is no
354 # way such a file can be deleted or renamed on Windows (other than
354 # way such a file can be deleted or renamed on Windows (other than
355 # scheduling the delete or rename for the next reboot).
355 # scheduling the delete or rename for the next reboot).
356 # - Calling os.unlink on a file that has been opened with Mercurial's
356 # - Calling os.unlink on a file that has been opened with Mercurial's
357 # posixfile (or comparable methods) will delay the actual deletion of
357 # posixfile (or comparable methods) will delay the actual deletion of
358 # the file for as long as the file is held open. The filename is blocked
358 # the file for as long as the file is held open. The filename is blocked
359 # during that time and cannot be used for recreating a new file under
359 # during that time and cannot be used for recreating a new file under
360 # that same name ("zombie file"). Directories containing such zombie files
360 # that same name ("zombie file"). Directories containing such zombie files
361 # cannot be removed or moved.
361 # cannot be removed or moved.
362 # A file that has been opened with posixfile can be renamed, so we rename
362 # A file that has been opened with posixfile can be renamed, so we rename
363 # f to a random temporary name before calling os.unlink on it. This allows
363 # f to a random temporary name before calling os.unlink on it. This allows
364 # callers to recreate f immediately while having other readers do their
364 # callers to recreate f immediately while having other readers do their
365 # implicit zombie filename blocking on a temporary name.
365 # implicit zombie filename blocking on a temporary name.
366
366
367 for tries in xrange(10):
367 for tries in xrange(10):
368 temp = '%s-%08x' % (f, random.randint(0, 0xffffffff))
368 temp = '%s-%08x' % (f, random.randint(0, 0xffffffff))
369 try:
369 try:
370 os.rename(f, temp) # raises OSError EEXIST if temp exists
370 os.rename(f, temp) # raises OSError EEXIST if temp exists
371 break
371 break
372 except OSError, e:
372 except OSError, e:
373 if e.errno != errno.EEXIST:
373 if e.errno != errno.EEXIST:
374 raise
374 raise
375 else:
375 else:
376 raise IOError, (errno.EEXIST, "No usable temporary filename found")
376 raise IOError, (errno.EEXIST, "No usable temporary filename found")
377
377
378 try:
378 try:
379 os.unlink(temp)
379 os.unlink(temp)
380 except OSError:
380 except OSError:
381 # The unlink might have failed because the READONLY attribute may heave
381 # The unlink might have failed because the READONLY attribute may heave
382 # been set on the original file. Rename works fine with READONLY set,
382 # been set on the original file. Rename works fine with READONLY set,
383 # but not os.unlink. Reset all attributes and try again.
383 # but not os.unlink. Reset all attributes and try again.
384 _kernel32.SetFileAttributesA(temp, _FILE_ATTRIBUTE_NORMAL)
384 _kernel32.SetFileAttributesA(temp, _FILE_ATTRIBUTE_NORMAL)
385 try:
385 try:
386 os.unlink(temp)
386 os.unlink(temp)
387 except OSError:
387 except OSError:
388 # The unlink might have failed due to some very rude AV-Scanners.
388 # The unlink might have failed due to some very rude AV-Scanners.
389 # Leaking a tempfile is the lesser evil than aborting here and
389 # Leaking a tempfile is the lesser evil than aborting here and
390 # leaving some potentially serious inconsistencies.
390 # leaving some potentially serious inconsistencies.
391 pass
391 pass
392
392
393 def makedir(path, notindexed):
393 def makedir(path, notindexed):
394 os.mkdir(path)
394 os.mkdir(path)
395 if notindexed:
395 if notindexed:
396 _kernel32.SetFileAttributesA(path, _FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)
396 _kernel32.SetFileAttributesA(path, _FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)
General Comments 0
You need to be logged in to leave comments. Login now