32
33
from breezy.i18n import gettext
34
has_ctypes_win32 = False
35
if sys.platform == 'win32':
39
has_ctypes_win32 = False
35
# We can cope without it; use a separate variable to help pyflakes
42
create_buffer = ctypes.create_unicode_buffer
43
extract_buffer = operator.attrgetter("value")
49
has_pywintypes = has_win32file = has_win32api = False
62
# pulling in win32com.shell is a bit of overhead, and normally we don't need
63
# it as ctypes is preferred and common. lazy_imports and "optional"
64
# modules don't work well, so we do our own lazy thing...
65
has_win32com_shell = None # Set to True or False once we know for sure...
42
67
# Special Win32 API constants
43
68
# Handles of std streams
78
102
('PagefileUsage', ctypes.c_size_t),
79
103
('PeakPagefileUsage', ctypes.c_size_t),
80
104
('PrivateUsage', ctypes.c_size_t),
82
106
cur_process = ctypes.windll.kernel32.GetCurrentProcess()
83
107
mem_struct = PROCESS_MEMORY_COUNTERS_EX()
84
ret = ctypes.windll.psapi.GetProcessMemoryInfo(
85
cur_process, ctypes.byref(mem_struct), ctypes.sizeof(mem_struct))
108
ret = ctypes.windll.psapi.GetProcessMemoryInfo(cur_process,
109
ctypes.byref(mem_struct),
110
ctypes.sizeof(mem_struct))
87
112
trace.note(gettext('Failed to GetProcessMemoryInfo()'))
97
122
'PagefileUsage': mem_struct.PagefileUsage,
98
123
'PeakPagefileUsage': mem_struct.PeakPagefileUsage,
99
124
'PrivateUsage': mem_struct.PrivateUsage,
128
# win32process does not return PrivateUsage, because it doesn't use
129
# PROCESS_MEMORY_COUNTERS_EX (it uses the one without _EX).
130
proc = win32process.GetCurrentProcess()
131
info = win32process.GetProcessMemoryInfo(proc)
102
133
trace.note(gettext('Cannot debug memory on win32 without ctypes'
106
137
# using base-2 units (see HACKING.txt).
107
138
trace.note(gettext('WorkingSize {0:>7}KiB'
108
'\tPeakWorking {1:>7}KiB\t{2}').format(
139
'\tPeakWorking {1:>7}KiB\t{2}').format(
109
140
info['WorkingSetSize'] / 1024,
110
141
info['PeakWorkingSetSize'] / 1024,
114
145
trace.note('%s', message)
115
trace.note(gettext('WorkingSize %8d KiB'),
116
info['WorkingSetSize'] / 1024)
117
trace.note(gettext('PeakWorking %8d KiB'),
118
info['PeakWorkingSetSize'] / 1024)
119
trace.note(gettext('PagefileUsage %8d KiB'),
120
info.get('PagefileUsage', 0) / 1024)
146
trace.note(gettext('WorkingSize %8d KiB'), info['WorkingSetSize'] / 1024)
147
trace.note(gettext('PeakWorking %8d KiB'), info['PeakWorkingSetSize'] / 1024)
148
trace.note(gettext('PagefileUsage %8d KiB'), info.get('PagefileUsage', 0) / 1024)
121
149
trace.note(gettext('PeakPagefileUsage %8d KiB'),
122
150
info.get('PeakPagefileUsage', 0) / 1024)
123
trace.note(gettext('PrivateUsage %8d KiB'),
124
info.get('PrivateUsage', 0) / 1024)
151
trace.note(gettext('PrivateUsage %8d KiB'), info.get('PrivateUsage', 0) / 1024)
125
152
trace.note(gettext('PageFaultCount %8d'), info.get('PageFaultCount', 0))
146
173
(bufx, bufy, curx, cury, wattr,
147
left, top, right, bottom, maxx, maxy) = struct.unpack(
174
left, top, right, bottom, maxx, maxy) = struct.unpack(
148
175
"hhhhHhhhhhh", csbi.raw)
149
176
sizex = right - left + 1
150
177
sizey = bottom - top + 1
168
195
buf = ctypes.create_unicode_buffer(MAX_PATH)
169
196
if SHGetSpecialFolderPath(None, buf, csidl, 0):
199
global has_win32com_shell
200
if has_win32com_shell is None:
202
from win32com.shell import shell
203
has_win32com_shell = True
205
has_win32com_shell = False
206
if has_win32com_shell:
207
# still need to bind the name locally, but this is fast.
208
from win32com.shell import shell
210
return shell.SHGetSpecialFolderPath(0, csidl, 0)
212
# possibly E_NOTIMPL meaning we can't load the function pointer,
213
# or E_FAIL meaning the function failed - regardless, just ignore it
234
278
"""Return user name as login name.
235
279
If name cannot be obtained return None.
239
283
advapi32 = ctypes.windll.advapi32
240
GetUserName = getattr(advapi32, 'GetUserNameW')
284
GetUserName = getattr(advapi32, 'GetUserName'+suffix)
241
285
except AttributeError:
244
buf = ctypes.create_unicode_buffer(UNLEN + 1)
245
n = ctypes.c_int(UNLEN + 1)
288
buf = create_buffer(UNLEN+1)
289
n = ctypes.c_int(UNLEN+1)
246
290
if GetUserName(buf, ctypes.byref(n)):
291
return extract_buffer(buf)
248
292
# otherwise try env variables
249
293
return get_environ_unicode('USERNAME')
253
297
# computer or the cluster associated with the local computer."
254
298
_WIN32_ComputerNameDnsHostname = 1
257
300
def get_host_name():
258
301
"""Return host machine name.
259
302
If name cannot be obtained return None.
261
304
:return: A unicode string representing the host name.
308
return win32api.GetComputerNameEx(_WIN32_ComputerNameDnsHostname)
309
except (NotImplementedError, win32api.error):
310
# NotImplemented will happen on win9x...
265
314
kernel32 = ctypes.windll.kernel32
266
315
except AttributeError:
267
pass # Missing the module we need
316
pass # Missing the module we need
269
buf = ctypes.create_unicode_buffer(MAX_COMPUTERNAME_LENGTH + 1)
270
n = ctypes.c_int(MAX_COMPUTERNAME_LENGTH + 1)
318
buf = create_buffer(MAX_COMPUTERNAME_LENGTH+1)
319
n = ctypes.c_int(MAX_COMPUTERNAME_LENGTH+1)
272
321
# Try GetComputerNameEx which gives a proper Unicode hostname
273
GetComputerNameEx = getattr(kernel32, 'GetComputerNameExW', None)
322
GetComputerNameEx = getattr(kernel32, 'GetComputerNameEx'+suffix,
274
324
if (GetComputerNameEx is not None
275
325
and GetComputerNameEx(_WIN32_ComputerNameDnsHostname,
276
326
buf, ctypes.byref(n))):
327
return extract_buffer(buf)
329
# Try GetComputerName in case GetComputerNameEx wasn't found
330
# It returns the NETBIOS name, which isn't as good, but still ok.
331
# The first GetComputerNameEx might have changed 'n', so reset it
332
n = ctypes.c_int(MAX_COMPUTERNAME_LENGTH+1)
333
GetComputerName = getattr(kernel32, 'GetComputerName'+suffix,
335
if (GetComputerName is not None
336
and GetComputerName(buf, ctypes.byref(n))):
337
return extract_buffer(buf)
278
338
return get_environ_unicode('COMPUTERNAME')
281
341
def _ensure_with_dir(path):
282
342
if (not os.path.split(path)[0] or path.startswith(u'*')
283
or path.startswith(u'?')):
343
or path.startswith(u'?')):
284
344
return u'./' + path, True
286
346
return path, False
289
348
def _undo_ensure_with_dir(path, corrected):
376
435
def set_file_attr_hidden(path):
377
436
"""Set file attributes to hidden if possible"""
378
if not has_ctypes_win32:
380
from ctypes.wintypes import BOOL, DWORD, LPCWSTR
381
_kernel32 = ctypes.windll.kernel32
382
# <https://docs.microsoft.com/windows/desktop/api/fileapi/nf-fileapi-setfileattributesw>
383
_SetFileAttributesW = ctypes.WINFUNCTYPE(BOOL, LPCWSTR, DWORD)(
384
("SetFileAttributesW", _kernel32))
385
FILE_ATTRIBUTE_HIDDEN = 2
386
if not SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN):
387
e = ctypes.WinError()
389
trace.mutter('Unable to set hidden attribute on %r: %s', path, e)
438
SetFileAttributes = win32file.SetFileAttributesW
440
SetFileAttributes(path, win32file.FILE_ATTRIBUTE_HIDDEN)
441
except pywintypes.error as e:
443
trace.mutter('Unable to set hidden attribute on %r: %s', path, e)
392
446
def _command_line_to_argv(command_line, argv, single_quotes_allowed=False):
403
457
:return: A list of unicode strings.
405
459
# First, split the command line
406
s = cmdline.Splitter(
407
command_line, single_quotes_allowed=single_quotes_allowed)
409
# Bug #587868 Now make sure that the length of s agrees with sys.argv
410
# we do this by simply counting the number of arguments in each. The counts should
411
# agree no matter what encoding sys.argv is in (AFAIK)
412
# len(arguments) < len(sys.argv) should be an impossibility since python gets
460
s = cmdline.Splitter(command_line, single_quotes_allowed=single_quotes_allowed)
462
# Bug #587868 Now make sure that the length of s agrees with sys.argv
463
# we do this by simply counting the number of arguments in each. The counts should
464
# agree no matter what encoding sys.argv is in (AFAIK)
465
# len(arguments) < len(sys.argv) should be an impossibility since python gets
413
466
# args from the very same PEB as does GetCommandLineW
414
467
arguments = list(s)
416
469
# Now shorten the command line we get from GetCommandLineW to match sys.argv
417
470
if len(arguments) < len(argv):
418
471
raise AssertionError("Split command line can't be shorter than argv")
419
472
arguments = arguments[len(arguments) - len(argv):]
421
474
# Carry on to process globs (metachars) in the command line
422
475
# expand globs if necessary
423
476
# TODO: Use 'globbing' instead of 'glob.glob', this gives us stuff like
460
516
cfunc = ctypes.WINFUNCTYPE(DWORD, LPCWSTR, LPWSTR, DWORD)(
461
517
("GetEnvironmentVariableW", ctypes.windll.kernel32))
462
518
get_environ_unicode._c_function = cfunc
463
buffer_size = 256 # heuristic, 256 characters often enough
519
buffer_size = 256 # heuristic, 256 characters often enough
465
buf = ctypes.create_unicode_buffer(buffer_size)
466
length = cfunc(key, buf, buffer_size)
521
buffer = ctypes.create_unicode_buffer(buffer_size)
522
length = cfunc(key, buffer, buffer_size)
468
524
code = ctypes.GetLastError()
469
if code == 203: # ERROR_ENVVAR_NOT_FOUND
525
if code == 203: # ERROR_ENVVAR_NOT_FOUND
471
527
raise ctypes.WinError(code)
472
528
if buffer_size > length:
529
return buffer[:length]
474
530
buffer_size = length
534
def _pywin32_is_local_pid_dead(pid):
535
"""True if pid doesn't correspond to live process on this machine"""
537
handle = win32api.OpenProcess(1, False, pid) # PROCESS_TERMINATE
538
except pywintypes.error as e:
539
if e[0] == 5: # ERROR_ACCESS_DENIED
540
# Probably something alive we're not allowed to kill
542
elif e[0] == 87: # ERROR_INVALID_PARAMETER
547
is_local_pid_dead = _pywin32_is_local_pid_dead
548
elif has_ctypes and sys.platform == 'win32':
478
549
from ctypes.wintypes import BOOL, DWORD, HANDLE
479
550
_kernel32 = ctypes.windll.kernel32
480
551
_CloseHandle = ctypes.WINFUNCTYPE(BOOL, HANDLE)(
481
552
("CloseHandle", _kernel32))
482
553
_OpenProcess = ctypes.WINFUNCTYPE(HANDLE, DWORD, BOOL, DWORD)(
483
554
("OpenProcess", _kernel32))
485
555
def _ctypes_is_local_pid_dead(pid):
486
556
"""True if pid doesn't correspond to live process on this machine"""
487
handle = _OpenProcess(1, False, pid) # PROCESS_TERMINATE
557
handle = _OpenProcess(1, False, pid) # PROCESS_TERMINATE
489
559
errorcode = ctypes.GetLastError()
490
if errorcode == 5: # ERROR_ACCESS_DENIED
560
if errorcode == 5: # ERROR_ACCESS_DENIED
491
561
# Probably something alive we're not allowed to kill
493
elif errorcode == 87: # ERROR_INVALID_PARAMETER
563
elif errorcode == 87: # ERROR_INVALID_PARAMETER
495
565
raise ctypes.WinError(errorcode)
496
566
_CloseHandle(handle)
499
568
is_local_pid_dead = _ctypes_is_local_pid_dead
571
def _is_pywintypes_error(evalue):
572
"""True if exception instance is an error from pywin32"""
573
if has_pywintypes and isinstance(evalue, pywintypes.error):