33
30
from breezy.i18n import gettext
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
32
has_ctypes_win32 = False
33
if sys.platform == 'win32':
37
has_ctypes_win32 = 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...
67
40
# Special Win32 API constants
68
41
# Handles of std streams
102
76
('PagefileUsage', ctypes.c_size_t),
103
77
('PeakPagefileUsage', ctypes.c_size_t),
104
78
('PrivateUsage', ctypes.c_size_t),
106
80
cur_process = ctypes.windll.kernel32.GetCurrentProcess()
107
81
mem_struct = PROCESS_MEMORY_COUNTERS_EX()
108
ret = ctypes.windll.psapi.GetProcessMemoryInfo(cur_process,
109
ctypes.byref(mem_struct),
110
ctypes.sizeof(mem_struct))
82
ret = ctypes.windll.psapi.GetProcessMemoryInfo(
83
cur_process, ctypes.byref(mem_struct), ctypes.sizeof(mem_struct))
112
85
trace.note(gettext('Failed to GetProcessMemoryInfo()'))
122
95
'PagefileUsage': mem_struct.PagefileUsage,
123
96
'PeakPagefileUsage': mem_struct.PeakPagefileUsage,
124
97
'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)
133
100
trace.note(gettext('Cannot debug memory on win32 without ctypes'
137
104
# using base-2 units (see HACKING.txt).
138
105
trace.note(gettext('WorkingSize {0:>7}KiB'
139
'\tPeakWorking {1:>7}KiB\t{2}').format(
106
'\tPeakWorking {1:>7}KiB\t{2}').format(
140
107
info['WorkingSetSize'] / 1024,
141
108
info['PeakWorkingSetSize'] / 1024,
145
112
trace.note('%s', message)
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)
113
trace.note(gettext('WorkingSize %8d KiB'),
114
info['WorkingSetSize'] / 1024)
115
trace.note(gettext('PeakWorking %8d KiB'),
116
info['PeakWorkingSetSize'] / 1024)
117
trace.note(gettext('PagefileUsage %8d KiB'),
118
info.get('PagefileUsage', 0) / 1024)
149
119
trace.note(gettext('PeakPagefileUsage %8d KiB'),
150
120
info.get('PeakPagefileUsage', 0) / 1024)
151
trace.note(gettext('PrivateUsage %8d KiB'), info.get('PrivateUsage', 0) / 1024)
121
trace.note(gettext('PrivateUsage %8d KiB'),
122
info.get('PrivateUsage', 0) / 1024)
152
123
trace.note(gettext('PageFaultCount %8d'), info.get('PageFaultCount', 0))
173
144
(bufx, bufy, curx, cury, wattr,
174
left, top, right, bottom, maxx, maxy) = struct.unpack(
145
left, top, right, bottom, maxx, maxy) = struct.unpack(
175
146
"hhhhHhhhhhh", csbi.raw)
176
147
sizex = right - left + 1
177
148
sizey = bottom - top + 1
195
166
buf = ctypes.create_unicode_buffer(MAX_PATH)
196
167
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
272
226
return os.path.splitdrive(windir)[0] + '/'
273
227
# otherwise C:\ is good enough for 98% users
274
return unicode('C:/')
277
231
def get_user_name():
278
232
"""Return user name as login name.
279
233
If name cannot be obtained return None.
283
237
advapi32 = ctypes.windll.advapi32
284
GetUserName = getattr(advapi32, 'GetUserName'+suffix)
238
GetUserName = getattr(advapi32, 'GetUserNameW')
285
239
except AttributeError:
288
buf = create_buffer(UNLEN+1)
289
n = ctypes.c_int(UNLEN+1)
242
buf = ctypes.create_unicode_buffer(UNLEN + 1)
243
n = ctypes.c_int(UNLEN + 1)
290
244
if GetUserName(buf, ctypes.byref(n)):
291
return extract_buffer(buf)
292
246
# otherwise try env variables
293
247
return get_environ_unicode('USERNAME')
297
251
# computer or the cluster associated with the local computer."
298
252
_WIN32_ComputerNameDnsHostname = 1
300
255
def get_host_name():
301
256
"""Return host machine name.
302
257
If name cannot be obtained return None.
304
259
: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...
314
263
kernel32 = ctypes.windll.kernel32
315
264
except AttributeError:
316
pass # Missing the module we need
265
pass # Missing the module we need
318
buf = create_buffer(MAX_COMPUTERNAME_LENGTH+1)
319
n = ctypes.c_int(MAX_COMPUTERNAME_LENGTH+1)
267
buf = ctypes.create_unicode_buffer(MAX_COMPUTERNAME_LENGTH + 1)
268
n = ctypes.c_int(MAX_COMPUTERNAME_LENGTH + 1)
321
270
# Try GetComputerNameEx which gives a proper Unicode hostname
322
GetComputerNameEx = getattr(kernel32, 'GetComputerNameEx'+suffix,
271
GetComputerNameEx = getattr(kernel32, 'GetComputerNameExW', None)
324
272
if (GetComputerNameEx is not None
325
273
and GetComputerNameEx(_WIN32_ComputerNameDnsHostname,
326
274
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)
338
276
return get_environ_unicode('COMPUTERNAME')
341
279
def _ensure_with_dir(path):
342
280
if (not os.path.split(path)[0] or path.startswith(u'*')
343
or path.startswith(u'?')):
281
or path.startswith(u'?')):
344
282
return u'./' + path, True
346
284
return path, False
348
287
def _undo_ensure_with_dir(path, corrected):
435
374
def set_file_attr_hidden(path):
436
375
"""Set file attributes to hidden if possible"""
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)
376
if not has_ctypes_win32:
378
from ctypes.wintypes import BOOL, DWORD, LPCWSTR
379
_kernel32 = ctypes.windll.kernel32
380
# <https://docs.microsoft.com/windows/desktop/api/fileapi/nf-fileapi-setfileattributesw>
381
_SetFileAttributesW = ctypes.WINFUNCTYPE(BOOL, LPCWSTR, DWORD)(
382
("SetFileAttributesW", _kernel32))
383
FILE_ATTRIBUTE_HIDDEN = 2
384
if not SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN):
385
e = ctypes.WinError()
387
trace.mutter('Unable to set hidden attribute on %r: %s', path, e)
446
390
def _command_line_to_argv(command_line, argv, single_quotes_allowed=False):
457
401
:return: A list of unicode strings.
459
403
# First, split the command line
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
404
s = cmdline.Splitter(
405
command_line, single_quotes_allowed=single_quotes_allowed)
407
# Bug #587868 Now make sure that the length of s agrees with sys.argv
408
# we do this by simply counting the number of arguments in each. The counts should
409
# agree no matter what encoding sys.argv is in (AFAIK)
410
# len(arguments) < len(sys.argv) should be an impossibility since python gets
466
411
# args from the very same PEB as does GetCommandLineW
467
412
arguments = list(s)
469
414
# Now shorten the command line we get from GetCommandLineW to match sys.argv
470
415
if len(arguments) < len(argv):
471
416
raise AssertionError("Split command line can't be shorter than argv")
472
417
arguments = arguments[len(arguments) - len(argv):]
474
419
# Carry on to process globs (metachars) in the command line
475
420
# expand globs if necessary
476
421
# TODO: Use 'globbing' instead of 'glob.glob', this gives us stuff like
516
458
cfunc = ctypes.WINFUNCTYPE(DWORD, LPCWSTR, LPWSTR, DWORD)(
517
459
("GetEnvironmentVariableW", ctypes.windll.kernel32))
518
460
get_environ_unicode._c_function = cfunc
519
buffer_size = 256 # heuristic, 256 characters often enough
461
buffer_size = 256 # heuristic, 256 characters often enough
521
buffer = ctypes.create_unicode_buffer(buffer_size)
522
length = cfunc(key, buffer, buffer_size)
463
buf = ctypes.create_unicode_buffer(buffer_size)
464
length = cfunc(key, buf, buffer_size)
524
466
code = ctypes.GetLastError()
525
if code == 203: # ERROR_ENVVAR_NOT_FOUND
467
if code == 203: # ERROR_ENVVAR_NOT_FOUND
527
469
raise ctypes.WinError(code)
528
470
if buffer_size > length:
529
return buffer[:length]
530
472
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':
549
476
from ctypes.wintypes import BOOL, DWORD, HANDLE
550
477
_kernel32 = ctypes.windll.kernel32
551
478
_CloseHandle = ctypes.WINFUNCTYPE(BOOL, HANDLE)(
552
479
("CloseHandle", _kernel32))
553
480
_OpenProcess = ctypes.WINFUNCTYPE(HANDLE, DWORD, BOOL, DWORD)(
554
481
("OpenProcess", _kernel32))
555
483
def _ctypes_is_local_pid_dead(pid):
556
484
"""True if pid doesn't correspond to live process on this machine"""
557
handle = _OpenProcess(1, False, pid) # PROCESS_TERMINATE
485
handle = _OpenProcess(1, False, pid) # PROCESS_TERMINATE
559
487
errorcode = ctypes.GetLastError()
560
if errorcode == 5: # ERROR_ACCESS_DENIED
488
if errorcode == 5: # ERROR_ACCESS_DENIED
561
489
# Probably something alive we're not allowed to kill
563
elif errorcode == 87: # ERROR_INVALID_PARAMETER
491
elif errorcode == 87: # ERROR_INVALID_PARAMETER
565
493
raise ctypes.WinError(errorcode)
566
494
_CloseHandle(handle)
568
497
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):