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