13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
17
"""Win32-specific helper functions
19
19
Only one dependency: ctypes should be installed.
27
from bzrlib import cmdline
30
28
if sys.platform == 'win32':
100
97
MAX_COMPUTERNAME_LENGTH = 31
102
# Registry data type ids
107
def debug_memory_win32api(message='', short=True):
108
"""Use trace.note() to dump the running memory info."""
109
from bzrlib import trace
111
class PROCESS_MEMORY_COUNTERS_EX(ctypes.Structure):
112
"""Used by GetProcessMemoryInfo"""
113
_fields_ = [('cb', ctypes.c_ulong),
114
('PageFaultCount', ctypes.c_ulong),
115
('PeakWorkingSetSize', ctypes.c_size_t),
116
('WorkingSetSize', ctypes.c_size_t),
117
('QuotaPeakPagedPoolUsage', ctypes.c_size_t),
118
('QuotaPagedPoolUsage', ctypes.c_size_t),
119
('QuotaPeakNonPagedPoolUsage', ctypes.c_size_t),
120
('QuotaNonPagedPoolUsage', ctypes.c_size_t),
121
('PagefileUsage', ctypes.c_size_t),
122
('PeakPagefileUsage', ctypes.c_size_t),
123
('PrivateUsage', ctypes.c_size_t),
125
cur_process = ctypes.windll.kernel32.GetCurrentProcess()
126
mem_struct = PROCESS_MEMORY_COUNTERS_EX()
127
ret = ctypes.windll.psapi.GetProcessMemoryInfo(cur_process,
128
ctypes.byref(mem_struct),
129
ctypes.sizeof(mem_struct))
131
trace.note('Failed to GetProcessMemoryInfo()')
133
info = {'PageFaultCount': mem_struct.PageFaultCount,
134
'PeakWorkingSetSize': mem_struct.PeakWorkingSetSize,
135
'WorkingSetSize': mem_struct.WorkingSetSize,
136
'QuotaPeakPagedPoolUsage': mem_struct.QuotaPeakPagedPoolUsage,
137
'QuotaPagedPoolUsage': mem_struct.QuotaPagedPoolUsage,
138
'QuotaPeakNonPagedPoolUsage':
139
mem_struct.QuotaPeakNonPagedPoolUsage,
140
'QuotaNonPagedPoolUsage': mem_struct.QuotaNonPagedPoolUsage,
141
'PagefileUsage': mem_struct.PagefileUsage,
142
'PeakPagefileUsage': mem_struct.PeakPagefileUsage,
143
'PrivateUsage': mem_struct.PrivateUsage,
147
# win32process does not return PrivateUsage, because it doesn't use
148
# PROCESS_MEMORY_COUNTERS_EX (it uses the one without _EX).
149
proc = win32process.GetCurrentProcess()
150
info = win32process.GetProcessMemoryInfo(proc)
152
trace.note('Cannot debug memory on win32 without ctypes'
156
# using base-2 units (see HACKING.txt).
157
trace.note('WorkingSize %7dKiB'
158
'\tPeakWorking %7dKiB\t%s',
159
info['WorkingSetSize'] / 1024,
160
info['PeakWorkingSetSize'] / 1024,
164
trace.note('%s', message)
165
trace.note('WorkingSize %8d KiB', info['WorkingSetSize'] / 1024)
166
trace.note('PeakWorking %8d KiB', info['PeakWorkingSetSize'] / 1024)
167
trace.note('PagefileUsage %8d KiB', info.get('PagefileUsage', 0) / 1024)
168
trace.note('PeakPagefileUsage %8d KiB',
169
info.get('PeakPagefileUsage', 0) / 1024)
170
trace.note('PrivateUsage %8d KiB', info.get('PrivateUsage', 0) / 1024)
171
trace.note('PageFaultCount %8d', info.get('PageFaultCount', 0))
174
100
def get_console_size(defaultx=80, defaulty=25):
175
101
"""Return size of current console.
183
109
return (defaultx, defaulty)
185
111
# To avoid problem with redirecting output via pipe
186
# we need to use stderr instead of stdout
112
# need to use stderr instead of stdout
187
113
h = ctypes.windll.kernel32.GetStdHandle(WIN32_STDERR_HANDLE)
188
114
csbi = ctypes.create_string_buffer(22)
189
115
res = ctypes.windll.kernel32.GetConsoleScreenBufferInfo(h, csbi)
192
118
(bufx, bufy, curx, cury, wattr,
193
left, top, right, bottom, maxx, maxy) = struct.unpack(
194
"hhhhHhhhhhh", csbi.raw)
119
left, top, right, bottom, maxx, maxy) = struct.unpack("hhhhHhhhhhh", csbi.raw)
195
120
sizex = right - left + 1
196
121
sizey = bottom - top + 1
197
122
return (sizex, sizey)
431
def glob_one(possible_glob):
432
"""Same as glob.glob().
434
work around bugs in glob.glob()
435
- Python bug #1001604 ("glob doesn't return unicode with ...")
436
- failing expansion for */* with non-iso-8859-* chars
438
corrected_glob, corrected = _ensure_with_dir(possible_glob)
439
glob_files = glob.glob(corrected_glob)
442
# special case to let the normal code path handle
443
# files that do not exist, etc.
444
glob_files = [possible_glob]
446
glob_files = [_undo_ensure_with_dir(elem, corrected)
447
for elem in glob_files]
448
return [elem.replace(u'\\', u'/') for elem in glob_files]
451
354
def glob_expand(file_list):
452
355
"""Replacement for glob expansion by the shell.
462
365
if not file_list:
464
368
expanded_file_list = []
465
369
for possible_glob in file_list:
466
expanded_file_list.extend(glob_one(possible_glob))
467
return expanded_file_list
371
# work around bugs in glob.glob()
372
# - Python bug #1001604 ("glob doesn't return unicode with ...")
373
# - failing expansion for */* with non-iso-8859-* chars
374
possible_glob, corrected = _ensure_with_dir(possible_glob)
375
glob_files = glob.glob(possible_glob)
378
# special case to let the normal code path handle
379
# files that do not exists
380
expanded_file_list.append(
381
_undo_ensure_with_dir(possible_glob, corrected))
383
glob_files = [_undo_ensure_with_dir(elem, corrected) for elem in glob_files]
384
expanded_file_list += glob_files
386
return [elem.replace(u'\\', u'/') for elem in expanded_file_list]
470
389
def get_app_path(appname):
471
390
"""Look up in Windows registry for full path to application executable.
472
Typically, applications create subkey with their basename
391
Typicaly, applications create subkey with their basename
473
392
in HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\
475
394
:param appname: name of application (if no filename extension
478
397
or appname itself if nothing found.
401
hkey = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,
402
r'SOFTWARE\Microsoft\Windows'
403
r'\CurrentVersion\App Paths')
404
except EnvironmentError:
482
407
basename = appname
483
408
if not os.path.splitext(basename)[1]:
484
409
basename = appname + '.exe'
487
hkey = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,
488
'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\' +
490
except EnvironmentError:
495
path, type_id = _winreg.QueryValueEx(hkey, '')
412
fullpath = _winreg.QueryValue(hkey, basename)
496
413
except WindowsError:
499
416
_winreg.CloseKey(hkey)
501
if type_id == REG_SZ:
503
if type_id == REG_EXPAND_SZ and has_win32api:
504
fullpath = win32api.ExpandEnvironmentStrings(path)
505
if len(fullpath) > 1 and fullpath[0] == '"' and fullpath[-1] == '"':
506
fullpath = fullpath[1:-1] # remove quotes around value
511
421
def set_file_attr_hidden(path):
512
422
"""Set file attributes to hidden if possible"""
513
423
if has_win32file:
514
if winver != 'Windows 98':
515
SetFileAttributes = win32file.SetFileAttributesW
517
SetFileAttributes = win32file.SetFileAttributes
519
SetFileAttributes(path, win32file.FILE_ATTRIBUTE_HIDDEN)
520
except pywintypes.error, e:
521
from bzrlib import trace
522
trace.mutter('Unable to set hidden attribute on %r: %s', path, e)
525
def _command_line_to_argv(command_line, single_quotes_allowed=False):
526
"""Convert a Unicode command line into a list of argv arguments.
528
It performs wildcard expansion to make wildcards act closer to how they
529
work in posix shells, versus how they work by default on Windows. Quoted
530
arguments are left untouched.
532
:param command_line: The unicode string to split into an arg list.
533
:param single_quotes_allowed: Whether single quotes are accepted as quoting
534
characters like double quotes. False by
536
:return: A list of unicode strings.
538
s = cmdline.Splitter(command_line, single_quotes_allowed=single_quotes_allowed)
539
# Now that we've split the content, expand globs if necessary
540
# TODO: Use 'globbing' instead of 'glob.glob', this gives us stuff like
543
for is_quoted, arg in s:
544
if is_quoted or not glob.has_magic(arg):
547
args.extend(glob_one(arg))
551
if has_ctypes and winver != 'Windows 98':
552
def get_unicode_argv():
553
prototype = ctypes.WINFUNCTYPE(ctypes.c_wchar_p)
554
GetCommandLineW = prototype(("GetCommandLineW",
555
ctypes.windll.kernel32))
556
command_line = GetCommandLineW()
557
if command_line is None:
558
raise ctypes.WinError()
559
# Skip the first argument, since we only care about parameters
560
argv = _command_line_to_argv(command_line)[1:]
561
if getattr(sys, 'frozen', None) is None:
562
# Invoked via 'python.exe' which takes the form:
563
# python.exe [PYTHON_OPTIONS] C:\Path\bzr [BZR_OPTIONS]
564
# we need to get only BZR_OPTIONS part,
565
# We already removed 'python.exe' so we remove everything up to and
566
# including the first non-option ('-') argument.
567
for idx in xrange(len(argv)):
568
if argv[idx][:1] != '-':
573
get_unicode_argv = None
424
win32file.SetFileAttributes(path, win32file.FILE_ATTRIBUTE_HIDDEN)