/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/win32utils.py

  • Committer: Jelmer Vernooij
  • Date: 2018-11-11 04:08:32 UTC
  • mto: (7143.16.20 even-more-cleanups)
  • mto: This revision was merged to the branch mainline in revision 7175.
  • Revision ID: jelmer@jelmer.uk-20181111040832-nsljjynzzwmznf3h
Run autopep8.

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
Only one dependency: ctypes should be installed.
20
20
"""
21
21
 
 
22
from __future__ import absolute_import
 
23
 
22
24
import glob
 
25
import operator
23
26
import os
24
27
import struct
25
28
import sys
26
29
 
27
 
from bzrlib import cmdline
28
 
 
29
 
# Windows version
30
 
if sys.platform == 'win32':
31
 
    _major,_minor,_build,_platform,_text = sys.getwindowsversion()
32
 
    # from MSDN:
33
 
    # dwPlatformId
34
 
    #   The operating system platform.
35
 
    #   This member can be one of the following values.
36
 
    #   ==========================  ======================================
37
 
    #   Value                       Meaning
38
 
    #   --------------------------  --------------------------------------
39
 
    #   VER_PLATFORM_WIN32_NT       The operating system is Windows Vista,
40
 
    #   2                           Windows Server "Longhorn",
41
 
    #                               Windows Server 2003, Windows XP,
42
 
    #                               Windows 2000, or Windows NT.
43
 
    #
44
 
    #   VER_PLATFORM_WIN32_WINDOWS  The operating system is Windows Me,
45
 
    #   1                           Windows 98, or Windows 95.
46
 
    #   ==========================  ======================================
47
 
    if _platform == 2:
48
 
        winver = 'Windows NT'
49
 
    else:
50
 
        # don't care about real Windows name, just to force safe operations
51
 
        winver = 'Windows 98'
52
 
else:
53
 
    winver = None
54
 
 
 
30
from breezy import (
 
31
    cmdline,
 
32
    )
 
33
from breezy.i18n import gettext
55
34
 
56
35
# We can cope without it; use a separate variable to help pyflakes
57
36
try:
60
39
except ImportError:
61
40
    has_ctypes = False
62
41
else:
63
 
    if winver == 'Windows 98':
64
 
        create_buffer = ctypes.create_string_buffer
65
 
        suffix = 'A'
66
 
    else:
67
 
        create_buffer = ctypes.create_unicode_buffer
68
 
        suffix = 'W'
 
42
    create_buffer = ctypes.create_unicode_buffer
 
43
    extract_buffer = operator.attrgetter("value")
 
44
    suffix = 'W'
69
45
try:
70
 
    import win32file
71
46
    import pywintypes
72
 
    has_win32file = True
73
 
except ImportError:
74
 
    has_win32file = False
75
 
try:
76
 
    import win32api
77
 
    has_win32api = True
78
 
except ImportError:
79
 
    has_win32api = False
 
47
    has_pywintypes = True
 
48
except ImportError:
 
49
    has_pywintypes = has_win32file = has_win32api = False
 
50
else:
 
51
    try:
 
52
        import win32file
 
53
        has_win32file = True
 
54
    except ImportError:
 
55
        has_win32file = False
 
56
    try:
 
57
        import win32api
 
58
        has_win32api = True
 
59
    except ImportError:
 
60
        has_win32api = False
80
61
 
81
62
# pulling in win32com.shell is a bit of overhead, and normally we don't need
82
63
# it as ctypes is preferred and common.  lazy_imports and "optional"
83
64
# modules don't work well, so we do our own lazy thing...
84
 
has_win32com_shell = None # Set to True or False once we know for sure...
 
65
has_win32com_shell = None  # Set to True or False once we know for sure...
85
66
 
86
67
# Special Win32 API constants
87
68
# Handles of std streams
91
72
 
92
73
# CSIDL constants (from MSDN 2003)
93
74
CSIDL_APPDATA = 0x001A      # Application Data folder
94
 
CSIDL_LOCAL_APPDATA = 0x001c# <user name>\Local Settings\Application Data (non roaming)
 
75
# <user name>\Local Settings\Application Data (non roaming)
 
76
CSIDL_LOCAL_APPDATA = 0x001c
95
77
CSIDL_PERSONAL = 0x0005     # My Documents folder
96
78
 
97
79
# from winapi C headers
106
88
 
107
89
def debug_memory_win32api(message='', short=True):
108
90
    """Use trace.note() to dump the running memory info."""
109
 
    from bzrlib import trace
 
91
    from breezy import trace
110
92
    if has_ctypes:
111
93
        class PROCESS_MEMORY_COUNTERS_EX(ctypes.Structure):
112
94
            """Used by GetProcessMemoryInfo"""
121
103
                        ('PagefileUsage', ctypes.c_size_t),
122
104
                        ('PeakPagefileUsage', ctypes.c_size_t),
123
105
                        ('PrivateUsage', ctypes.c_size_t),
124
 
                       ]
 
106
                        ]
125
107
        cur_process = ctypes.windll.kernel32.GetCurrentProcess()
126
108
        mem_struct = PROCESS_MEMORY_COUNTERS_EX()
127
109
        ret = ctypes.windll.psapi.GetProcessMemoryInfo(cur_process,
128
 
            ctypes.byref(mem_struct),
129
 
            ctypes.sizeof(mem_struct))
 
110
                                                       ctypes.byref(
 
111
                                                           mem_struct),
 
112
                                                       ctypes.sizeof(mem_struct))
130
113
        if not ret:
131
 
            trace.note('Failed to GetProcessMemoryInfo()')
 
114
            trace.note(gettext('Failed to GetProcessMemoryInfo()'))
132
115
            return
133
116
        info = {'PageFaultCount': mem_struct.PageFaultCount,
134
117
                'PeakWorkingSetSize': mem_struct.PeakWorkingSetSize,
141
124
                'PagefileUsage': mem_struct.PagefileUsage,
142
125
                'PeakPagefileUsage': mem_struct.PeakPagefileUsage,
143
126
                'PrivateUsage': mem_struct.PrivateUsage,
144
 
               }
 
127
                }
145
128
    elif has_win32api:
146
129
        import win32process
147
130
        # win32process does not return PrivateUsage, because it doesn't use
149
132
        proc = win32process.GetCurrentProcess()
150
133
        info = win32process.GetProcessMemoryInfo(proc)
151
134
    else:
152
 
        trace.note('Cannot debug memory on win32 without ctypes'
153
 
                   ' or win32process')
 
135
        trace.note(gettext('Cannot debug memory on win32 without ctypes'
 
136
                           ' or win32process'))
154
137
        return
155
138
    if short:
156
139
        # using base-2 units (see HACKING.txt).
157
 
        trace.note('WorkingSize %7dKiB'
158
 
                   '\tPeakWorking %7dKiB\t%s',
 
140
        trace.note(gettext('WorkingSize {0:>7}KiB'
 
141
                           '\tPeakWorking {1:>7}KiB\t{2}').format(
159
142
                   info['WorkingSetSize'] / 1024,
160
143
                   info['PeakWorkingSetSize'] / 1024,
161
 
                   message)
 
144
                   message))
162
145
        return
163
146
    if message:
164
147
        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',
 
148
    trace.note(gettext('WorkingSize       %8d KiB'),
 
149
               info['WorkingSetSize'] / 1024)
 
150
    trace.note(gettext('PeakWorking       %8d KiB'),
 
151
               info['PeakWorkingSetSize'] / 1024)
 
152
    trace.note(gettext('PagefileUsage     %8d KiB'),
 
153
               info.get('PagefileUsage', 0) / 1024)
 
154
    trace.note(gettext('PeakPagefileUsage %8d KiB'),
169
155
               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))
 
156
    trace.note(gettext('PrivateUsage      %8d KiB'),
 
157
               info.get('PrivateUsage', 0) / 1024)
 
158
    trace.note(gettext('PageFaultCount    %8d'), info.get('PageFaultCount', 0))
172
159
 
173
160
 
174
161
def get_console_size(defaultx=80, defaulty=25):
190
177
 
191
178
    if res:
192
179
        (bufx, bufy, curx, cury, wattr,
193
 
        left, top, right, bottom, maxx, maxy) = struct.unpack(
 
180
         left, top, right, bottom, maxx, maxy) = struct.unpack(
194
181
            "hhhhHhhhhhh", csbi.raw)
195
182
        sizex = right - left + 1
196
183
        sizey = bottom - top + 1
212
199
            pass
213
200
        else:
214
201
            buf = ctypes.create_unicode_buffer(MAX_PATH)
215
 
            if SHGetSpecialFolderPath(None,buf,csidl,0):
 
202
            if SHGetSpecialFolderPath(None, buf, csidl, 0):
216
203
                return buf.value
217
204
 
218
205
    global has_win32com_shell
242
229
    one that moves with the user as they logon to different machines, and
243
230
    a 'local' one that stays local to the machine.  This returns the 'roaming'
244
231
    directory, and thus is suitable for storing user-preferences, etc.
245
 
 
246
 
    Returned value can be unicode or plain string.
247
 
    To convert plain string to unicode use
248
 
    s.decode(osutils.get_user_encoding())
249
 
    (XXX - but see bug 262874, which asserts the correct encoding is 'mbcs')
250
232
    """
251
233
    appdata = _get_sh_special_folder_path(CSIDL_APPDATA)
252
234
    if appdata:
253
235
        return appdata
254
 
    # from env variable
255
 
    appdata = os.environ.get('APPDATA')
256
 
    if appdata:
257
 
        return appdata
258
 
    # if we fall to this point we on win98
259
 
    # at least try C:/WINDOWS/Application Data
260
 
    windir = os.environ.get('windir')
261
 
    if windir:
262
 
        appdata = os.path.join(windir, 'Application Data')
263
 
        if os.path.isdir(appdata):
264
 
            return appdata
265
 
    # did not find anything
266
 
    return None
 
236
    # Use APPDATA if defined, will return None if not
 
237
    return get_environ_unicode('APPDATA')
267
238
 
268
239
 
269
240
def get_local_appdata_location():
275
246
    a 'local' one that stays local to the machine.  This returns the 'local'
276
247
    directory, and thus is suitable for caches, temp files and other things
277
248
    which don't need to move with the user.
278
 
 
279
 
    Returned value can be unicode or plain string.
280
 
    To convert plain string to unicode use
281
 
    s.decode(osutils.get_user_encoding())
282
 
    (XXX - but see bug 262874, which asserts the correct encoding is 'mbcs')
283
249
    """
284
250
    local = _get_sh_special_folder_path(CSIDL_LOCAL_APPDATA)
285
251
    if local:
286
252
        return local
287
253
    # Vista supplies LOCALAPPDATA, but XP and earlier do not.
288
 
    local = os.environ.get('LOCALAPPDATA')
 
254
    local = get_environ_unicode('LOCALAPPDATA')
289
255
    if local:
290
256
        return local
291
257
    return get_appdata_location()
296
262
    Assume on win32 it's the <My Documents> folder.
297
263
    If location cannot be obtained return system drive root,
298
264
    i.e. C:\
299
 
 
300
 
    Returned value can be unicode or plain string.
301
 
    To convert plain string to unicode use
302
 
    s.decode(osutils.get_user_encoding())
303
265
    """
304
266
    home = _get_sh_special_folder_path(CSIDL_PERSONAL)
305
267
    if home:
306
268
        return home
307
 
    # try for HOME env variable
308
 
    home = os.path.expanduser('~')
309
 
    if home != '~':
 
269
    home = get_environ_unicode('HOME')
 
270
    if home is not None:
310
271
        return home
 
272
    homepath = get_environ_unicode('HOMEPATH')
 
273
    if homepath is not None:
 
274
        return os.path.join(get_environ_unicode('HOMEDIR', ''), home)
311
275
    # at least return windows root directory
312
 
    windir = os.environ.get('windir')
 
276
    windir = get_environ_unicode('WINDIR')
313
277
    if windir:
314
278
        return os.path.splitdrive(windir)[0] + '/'
315
279
    # otherwise C:\ is good enough for 98% users
316
 
    return 'C:/'
 
280
    return u'C:/'
317
281
 
318
282
 
319
283
def get_user_name():
320
284
    """Return user name as login name.
321
285
    If name cannot be obtained return None.
322
 
 
323
 
    Returned value can be unicode or plain string.
324
 
    To convert plain string to unicode use
325
 
    s.decode(osutils.get_user_encoding())
326
286
    """
327
287
    if has_ctypes:
328
288
        try:
329
289
            advapi32 = ctypes.windll.advapi32
330
 
            GetUserName = getattr(advapi32, 'GetUserName'+suffix)
 
290
            GetUserName = getattr(advapi32, 'GetUserName' + suffix)
331
291
        except AttributeError:
332
292
            pass
333
293
        else:
334
 
            buf = create_buffer(UNLEN+1)
335
 
            n = ctypes.c_int(UNLEN+1)
 
294
            buf = create_buffer(UNLEN + 1)
 
295
            n = ctypes.c_int(UNLEN + 1)
336
296
            if GetUserName(buf, ctypes.byref(n)):
337
 
                return buf.value
 
297
                return extract_buffer(buf)
338
298
    # otherwise try env variables
339
 
    return os.environ.get('USERNAME', None)
 
299
    return get_environ_unicode('USERNAME')
340
300
 
341
301
 
342
302
# 1 == ComputerNameDnsHostname, which returns "The DNS host name of the local
343
303
# computer or the cluster associated with the local computer."
344
304
_WIN32_ComputerNameDnsHostname = 1
345
305
 
 
306
 
346
307
def get_host_name():
347
308
    """Return host machine name.
348
309
    If name cannot be obtained return None.
349
310
 
350
 
    :return: A unicode string representing the host name. On win98, this may be
351
 
        a plain string as win32 api doesn't support unicode.
 
311
    :return: A unicode string representing the host name.
352
312
    """
353
313
    if has_win32api:
354
314
        try:
360
320
        try:
361
321
            kernel32 = ctypes.windll.kernel32
362
322
        except AttributeError:
363
 
            pass # Missing the module we need
 
323
            pass  # Missing the module we need
364
324
        else:
365
 
            buf = create_buffer(MAX_COMPUTERNAME_LENGTH+1)
366
 
            n = ctypes.c_int(MAX_COMPUTERNAME_LENGTH+1)
 
325
            buf = create_buffer(MAX_COMPUTERNAME_LENGTH + 1)
 
326
            n = ctypes.c_int(MAX_COMPUTERNAME_LENGTH + 1)
367
327
 
368
328
            # Try GetComputerNameEx which gives a proper Unicode hostname
369
 
            GetComputerNameEx = getattr(kernel32, 'GetComputerNameEx'+suffix,
 
329
            GetComputerNameEx = getattr(kernel32, 'GetComputerNameEx' + suffix,
370
330
                                        None)
371
331
            if (GetComputerNameEx is not None
372
332
                and GetComputerNameEx(_WIN32_ComputerNameDnsHostname,
373
 
                                      buf, ctypes.byref(n))):
374
 
                return buf.value
 
333
                                  buf, ctypes.byref(n))):
 
334
                return extract_buffer(buf)
375
335
 
376
336
            # Try GetComputerName in case GetComputerNameEx wasn't found
377
337
            # It returns the NETBIOS name, which isn't as good, but still ok.
378
338
            # The first GetComputerNameEx might have changed 'n', so reset it
379
 
            n = ctypes.c_int(MAX_COMPUTERNAME_LENGTH+1)
380
 
            GetComputerName = getattr(kernel32, 'GetComputerName'+suffix,
 
339
            n = ctypes.c_int(MAX_COMPUTERNAME_LENGTH + 1)
 
340
            GetComputerName = getattr(kernel32, 'GetComputerName' + suffix,
381
341
                                      None)
382
342
            if (GetComputerName is not None
383
 
                and GetComputerName(buf, ctypes.byref(n))):
384
 
                return buf.value
385
 
    # otherwise try env variables, which will be 'mbcs' encoded
386
 
    # on Windows (Python doesn't expose the native win32 unicode environment)
387
 
    # According to this:
388
 
    # http://msdn.microsoft.com/en-us/library/aa246807.aspx
389
 
    # environment variables should always be encoded in 'mbcs'.
390
 
    try:
391
 
        return os.environ['COMPUTERNAME'].decode("mbcs")
392
 
    except KeyError:
393
 
        return None
394
 
 
395
 
 
396
 
def _ensure_unicode(s):
397
 
    if s and type(s) != unicode:
398
 
        from bzrlib import osutils
399
 
        s = s.decode(osutils.get_user_encoding())
400
 
    return s
401
 
 
402
 
 
403
 
def get_appdata_location_unicode():
404
 
    return _ensure_unicode(get_appdata_location())
405
 
 
406
 
def get_home_location_unicode():
407
 
    return _ensure_unicode(get_home_location())
408
 
 
409
 
def get_user_name_unicode():
410
 
    return _ensure_unicode(get_user_name())
411
 
 
412
 
def get_host_name_unicode():
413
 
    return _ensure_unicode(get_host_name())
 
343
                    and GetComputerName(buf, ctypes.byref(n))):
 
344
                return extract_buffer(buf)
 
345
    return get_environ_unicode('COMPUTERNAME')
414
346
 
415
347
 
416
348
def _ensure_with_dir(path):
417
349
    if (not os.path.split(path)[0] or path.startswith(u'*')
418
 
        or path.startswith(u'?')):
 
350
            or path.startswith(u'?')):
419
351
        return u'./' + path, True
420
352
    else:
421
353
        return path, False
422
354
 
 
355
 
423
356
def _undo_ensure_with_dir(path, corrected):
424
357
    if corrected:
425
358
        return path[2:]
427
360
        return path
428
361
 
429
362
 
430
 
 
431
363
def glob_one(possible_glob):
432
364
    """Same as glob.glob().
433
365
 
457
389
    :param file_list: A list of filenames which may include shell globs.
458
390
    :return: An expanded list of filenames.
459
391
 
460
 
    Introduced in bzrlib 0.18.
 
392
    Introduced in breezy 0.18.
461
393
    """
462
394
    if not file_list:
463
395
        return []
468
400
 
469
401
 
470
402
def get_app_path(appname):
471
 
    """Look up in Windows registry for full path to application executable.
 
403
    r"""Look up in Windows registry for full path to application executable.
472
404
    Typically, applications create subkey with their basename
473
405
    in HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\
474
406
 
485
417
 
486
418
    try:
487
419
        hkey = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,
488
 
            'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\' +
489
 
            basename)
 
420
                               'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\' +
 
421
                               basename)
490
422
    except EnvironmentError:
491
423
        return appname
492
424
 
511
443
def set_file_attr_hidden(path):
512
444
    """Set file attributes to hidden if possible"""
513
445
    if has_win32file:
514
 
        if winver != 'Windows 98':
515
 
            SetFileAttributes = win32file.SetFileAttributesW
516
 
        else:
517
 
            SetFileAttributes = win32file.SetFileAttributes
 
446
        SetFileAttributes = win32file.SetFileAttributesW
518
447
        try:
519
448
            SetFileAttributes(path, win32file.FILE_ATTRIBUTE_HIDDEN)
520
 
        except pywintypes.error, e:
521
 
            from bzrlib import trace
 
449
        except pywintypes.error as e:
 
450
            from . import trace
522
451
            trace.mutter('Unable to set hidden attribute on %r: %s', path, e)
523
452
 
524
453
 
525
 
def _command_line_to_argv(command_line, single_quotes_allowed=False):
 
454
def _command_line_to_argv(command_line, argv, single_quotes_allowed=False):
526
455
    """Convert a Unicode command line into a list of argv arguments.
527
456
 
528
457
    It performs wildcard expansion to make wildcards act closer to how they
535
464
                                  default.
536
465
    :return: A list of unicode strings.
537
466
    """
538
 
    s = cmdline.Splitter(command_line, single_quotes_allowed=single_quotes_allowed)
539
 
    # Now that we've split the content, expand globs if necessary
 
467
    # First, split the command line
 
468
    s = cmdline.Splitter(
 
469
        command_line, single_quotes_allowed=single_quotes_allowed)
 
470
 
 
471
    # Bug #587868 Now make sure that the length of s agrees with sys.argv
 
472
    # we do this by simply counting the number of arguments in each. The counts should
 
473
    # agree no matter what encoding sys.argv is in (AFAIK)
 
474
    # len(arguments) < len(sys.argv) should be an impossibility since python gets
 
475
    # args from the very same PEB as does GetCommandLineW
 
476
    arguments = list(s)
 
477
 
 
478
    # Now shorten the command line we get from GetCommandLineW to match sys.argv
 
479
    if len(arguments) < len(argv):
 
480
        raise AssertionError("Split command line can't be shorter than argv")
 
481
    arguments = arguments[len(arguments) - len(argv):]
 
482
 
 
483
    # Carry on to process globs (metachars) in the command line
 
484
    # expand globs if necessary
540
485
    # TODO: Use 'globbing' instead of 'glob.glob', this gives us stuff like
541
486
    #       '**/' style globs
542
487
    args = []
543
 
    for is_quoted, arg in s:
 
488
    for is_quoted, arg in arguments:
544
489
        if is_quoted or not glob.has_magic(arg):
545
490
            args.append(arg)
546
491
        else:
548
493
    return args
549
494
 
550
495
 
551
 
if has_ctypes and winver != 'Windows 98':
 
496
if has_ctypes:
552
497
    def get_unicode_argv():
553
498
        prototype = ctypes.WINFUNCTYPE(ctypes.c_wchar_p)
554
499
        GetCommandLineW = prototype(("GetCommandLineW",
557
502
        if command_line is None:
558
503
            raise ctypes.WinError()
559
504
        # 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] != '-':
569
 
                    break
570
 
            argv = argv[idx+1:]
 
505
        argv = _command_line_to_argv(command_line, sys.argv)[1:]
571
506
        return argv
572
 
else:
573
 
    get_unicode_argv = None
 
507
 
 
508
    def get_environ_unicode(key, default=None):
 
509
        """Get `key` from environment as unicode or `default` if unset
 
510
 
 
511
        The environment is natively unicode on modern windows versions but
 
512
        Python 2 only accesses it through the legacy bytestring api.
 
513
 
 
514
        Environmental variable names are case insenstive on Windows.
 
515
 
 
516
        A large enough buffer will be allocated to retrieve the value, though
 
517
        it may take two calls to the underlying library function.
 
518
 
 
519
        This needs ctypes because pywin32 does not expose the wide version.
 
520
        """
 
521
        cfunc = getattr(get_environ_unicode, "_c_function", None)
 
522
        if cfunc is None:
 
523
            from ctypes.wintypes import DWORD, LPCWSTR, LPWSTR
 
524
            cfunc = ctypes.WINFUNCTYPE(DWORD, LPCWSTR, LPWSTR, DWORD)(
 
525
                ("GetEnvironmentVariableW", ctypes.windll.kernel32))
 
526
            get_environ_unicode._c_function = cfunc
 
527
        buffer_size = 256  # heuristic, 256 characters often enough
 
528
        while True:
 
529
            buffer = ctypes.create_unicode_buffer(buffer_size)
 
530
            length = cfunc(key, buffer, buffer_size)
 
531
            if not length:
 
532
                code = ctypes.GetLastError()
 
533
                if code == 203:  # ERROR_ENVVAR_NOT_FOUND
 
534
                    return default
 
535
                raise ctypes.WinError(code)
 
536
            if buffer_size > length:
 
537
                return buffer[:length]
 
538
            buffer_size = length
 
539
 
 
540
 
 
541
if has_win32api:
 
542
    def _pywin32_is_local_pid_dead(pid):
 
543
        """True if pid doesn't correspond to live process on this machine"""
 
544
        try:
 
545
            handle = win32api.OpenProcess(1, False, pid)  # PROCESS_TERMINATE
 
546
        except pywintypes.error as e:
 
547
            if e[0] == 5:  # ERROR_ACCESS_DENIED
 
548
                # Probably something alive we're not allowed to kill
 
549
                return False
 
550
            elif e[0] == 87:  # ERROR_INVALID_PARAMETER
 
551
                return True
 
552
            raise
 
553
        handle.close()
 
554
        return False
 
555
    is_local_pid_dead = _pywin32_is_local_pid_dead
 
556
elif has_ctypes and sys.platform == 'win32':
 
557
    from ctypes.wintypes import BOOL, DWORD, HANDLE
 
558
    _kernel32 = ctypes.windll.kernel32
 
559
    _CloseHandle = ctypes.WINFUNCTYPE(BOOL, HANDLE)(
 
560
        ("CloseHandle", _kernel32))
 
561
    _OpenProcess = ctypes.WINFUNCTYPE(HANDLE, DWORD, BOOL, DWORD)(
 
562
        ("OpenProcess", _kernel32))
 
563
 
 
564
    def _ctypes_is_local_pid_dead(pid):
 
565
        """True if pid doesn't correspond to live process on this machine"""
 
566
        handle = _OpenProcess(1, False, pid)  # PROCESS_TERMINATE
 
567
        if not handle:
 
568
            errorcode = ctypes.GetLastError()
 
569
            if errorcode == 5:  # ERROR_ACCESS_DENIED
 
570
                # Probably something alive we're not allowed to kill
 
571
                return False
 
572
            elif errorcode == 87:  # ERROR_INVALID_PARAMETER
 
573
                return True
 
574
            raise ctypes.WinError(errorcode)
 
575
        _CloseHandle(handle)
 
576
        return False
 
577
    is_local_pid_dead = _ctypes_is_local_pid_dead
 
578
 
 
579
 
 
580
def _is_pywintypes_error(evalue):
 
581
    """True if exception instance is an error from pywin32"""
 
582
    if has_pywintypes and isinstance(evalue, pywintypes.error):
 
583
        return True
 
584
    return False