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