/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: 2019-02-04 01:01:24 UTC
  • mto: This revision was merged to the branch mainline in revision 7268.
  • Revision ID: jelmer@jelmer.uk-20190204010124-ni0i4qc6f5tnbvux
Fix source tests.

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
 
        ret = ctypes.windll.psapi.GetProcessMemoryInfo(cur_process,
128
 
            ctypes.byref(mem_struct),
129
 
            ctypes.sizeof(mem_struct))
 
109
        ret = ctypes.windll.psapi.GetProcessMemoryInfo(
 
110
            cur_process, ctypes.byref(mem_struct), ctypes.sizeof(mem_struct))
130
111
        if not ret:
131
 
            trace.note('Failed to GetProcessMemoryInfo()')
 
112
            trace.note(gettext('Failed to GetProcessMemoryInfo()'))
132
113
            return
133
114
        info = {'PageFaultCount': mem_struct.PageFaultCount,
134
115
                'PeakWorkingSetSize': mem_struct.PeakWorkingSetSize,
141
122
                'PagefileUsage': mem_struct.PagefileUsage,
142
123
                'PeakPagefileUsage': mem_struct.PeakPagefileUsage,
143
124
                'PrivateUsage': mem_struct.PrivateUsage,
144
 
               }
 
125
                }
145
126
    elif has_win32api:
146
127
        import win32process
147
128
        # win32process does not return PrivateUsage, because it doesn't use
149
130
        proc = win32process.GetCurrentProcess()
150
131
        info = win32process.GetProcessMemoryInfo(proc)
151
132
    else:
152
 
        trace.note('Cannot debug memory on win32 without ctypes'
153
 
                   ' or win32process')
 
133
        trace.note(gettext('Cannot debug memory on win32 without ctypes'
 
134
                           ' or win32process'))
154
135
        return
155
136
    if short:
156
137
        # using base-2 units (see HACKING.txt).
157
 
        trace.note('WorkingSize %7dKiB'
158
 
                   '\tPeakWorking %7dKiB\t%s',
 
138
        trace.note(gettext('WorkingSize {0:>7}KiB'
 
139
                           '\tPeakWorking {1:>7}KiB\t{2}').format(
159
140
                   info['WorkingSetSize'] / 1024,
160
141
                   info['PeakWorkingSetSize'] / 1024,
161
 
                   message)
 
142
                   message))
162
143
        return
163
144
    if message:
164
145
        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',
 
146
    trace.note(gettext('WorkingSize       %8d KiB'),
 
147
               info['WorkingSetSize'] / 1024)
 
148
    trace.note(gettext('PeakWorking       %8d KiB'),
 
149
               info['PeakWorkingSetSize'] / 1024)
 
150
    trace.note(gettext('PagefileUsage     %8d KiB'),
 
151
               info.get('PagefileUsage', 0) / 1024)
 
152
    trace.note(gettext('PeakPagefileUsage %8d KiB'),
169
153
               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))
 
154
    trace.note(gettext('PrivateUsage      %8d KiB'),
 
155
               info.get('PrivateUsage', 0) / 1024)
 
156
    trace.note(gettext('PageFaultCount    %8d'), info.get('PageFaultCount', 0))
172
157
 
173
158
 
174
159
def get_console_size(defaultx=80, defaulty=25):
190
175
 
191
176
    if res:
192
177
        (bufx, bufy, curx, cury, wattr,
193
 
        left, top, right, bottom, maxx, maxy) = struct.unpack(
 
178
         left, top, right, bottom, maxx, maxy) = struct.unpack(
194
179
            "hhhhHhhhhhh", csbi.raw)
195
180
        sizex = right - left + 1
196
181
        sizey = bottom - top + 1
212
197
            pass
213
198
        else:
214
199
            buf = ctypes.create_unicode_buffer(MAX_PATH)
215
 
            if SHGetSpecialFolderPath(None,buf,csidl,0):
 
200
            if SHGetSpecialFolderPath(None, buf, csidl, 0):
216
201
                return buf.value
217
202
 
218
203
    global has_win32com_shell
242
227
    one that moves with the user as they logon to different machines, and
243
228
    a 'local' one that stays local to the machine.  This returns the 'roaming'
244
229
    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
230
    """
251
231
    appdata = _get_sh_special_folder_path(CSIDL_APPDATA)
252
232
    if appdata:
253
233
        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
 
234
    # Use APPDATA if defined, will return None if not
 
235
    return get_environ_unicode('APPDATA')
267
236
 
268
237
 
269
238
def get_local_appdata_location():
275
244
    a 'local' one that stays local to the machine.  This returns the 'local'
276
245
    directory, and thus is suitable for caches, temp files and other things
277
246
    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
247
    """
284
248
    local = _get_sh_special_folder_path(CSIDL_LOCAL_APPDATA)
285
249
    if local:
286
250
        return local
287
251
    # Vista supplies LOCALAPPDATA, but XP and earlier do not.
288
 
    local = os.environ.get('LOCALAPPDATA')
 
252
    local = get_environ_unicode('LOCALAPPDATA')
289
253
    if local:
290
254
        return local
291
255
    return get_appdata_location()
296
260
    Assume on win32 it's the <My Documents> folder.
297
261
    If location cannot be obtained return system drive root,
298
262
    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
263
    """
304
264
    home = _get_sh_special_folder_path(CSIDL_PERSONAL)
305
265
    if home:
306
266
        return home
307
 
    # try for HOME env variable
308
 
    home = os.path.expanduser('~')
309
 
    if home != '~':
 
267
    home = get_environ_unicode('HOME')
 
268
    if home is not None:
310
269
        return home
 
270
    homepath = get_environ_unicode('HOMEPATH')
 
271
    if homepath is not None:
 
272
        return os.path.join(get_environ_unicode('HOMEDIR', ''), home)
311
273
    # at least return windows root directory
312
 
    windir = os.environ.get('windir')
 
274
    windir = get_environ_unicode('WINDIR')
313
275
    if windir:
314
276
        return os.path.splitdrive(windir)[0] + '/'
315
277
    # otherwise C:\ is good enough for 98% users
316
 
    return 'C:/'
 
278
    return u'C:/'
317
279
 
318
280
 
319
281
def get_user_name():
320
282
    """Return user name as login name.
321
283
    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
284
    """
327
285
    if has_ctypes:
328
286
        try:
329
287
            advapi32 = ctypes.windll.advapi32
330
 
            GetUserName = getattr(advapi32, 'GetUserName'+suffix)
 
288
            GetUserName = getattr(advapi32, 'GetUserName' + suffix)
331
289
        except AttributeError:
332
290
            pass
333
291
        else:
334
 
            buf = create_buffer(UNLEN+1)
335
 
            n = ctypes.c_int(UNLEN+1)
 
292
            buf = create_buffer(UNLEN + 1)
 
293
            n = ctypes.c_int(UNLEN + 1)
336
294
            if GetUserName(buf, ctypes.byref(n)):
337
 
                return buf.value
 
295
                return extract_buffer(buf)
338
296
    # otherwise try env variables
339
 
    return os.environ.get('USERNAME', None)
 
297
    return get_environ_unicode('USERNAME')
340
298
 
341
299
 
342
300
# 1 == ComputerNameDnsHostname, which returns "The DNS host name of the local
343
301
# computer or the cluster associated with the local computer."
344
302
_WIN32_ComputerNameDnsHostname = 1
345
303
 
 
304
 
346
305
def get_host_name():
347
306
    """Return host machine name.
348
307
    If name cannot be obtained return None.
349
308
 
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.
 
309
    :return: A unicode string representing the host name.
352
310
    """
353
311
    if has_win32api:
354
312
        try:
360
318
        try:
361
319
            kernel32 = ctypes.windll.kernel32
362
320
        except AttributeError:
363
 
            pass # Missing the module we need
 
321
            pass  # Missing the module we need
364
322
        else:
365
 
            buf = create_buffer(MAX_COMPUTERNAME_LENGTH+1)
366
 
            n = ctypes.c_int(MAX_COMPUTERNAME_LENGTH+1)
 
323
            buf = create_buffer(MAX_COMPUTERNAME_LENGTH + 1)
 
324
            n = ctypes.c_int(MAX_COMPUTERNAME_LENGTH + 1)
367
325
 
368
326
            # Try GetComputerNameEx which gives a proper Unicode hostname
369
 
            GetComputerNameEx = getattr(kernel32, 'GetComputerNameEx'+suffix,
 
327
            GetComputerNameEx = getattr(kernel32, 'GetComputerNameEx' + suffix,
370
328
                                        None)
371
329
            if (GetComputerNameEx is not None
372
330
                and GetComputerNameEx(_WIN32_ComputerNameDnsHostname,
373
331
                                      buf, ctypes.byref(n))):
374
 
                return buf.value
 
332
                return extract_buffer(buf)
375
333
 
376
334
            # Try GetComputerName in case GetComputerNameEx wasn't found
377
335
            # It returns the NETBIOS name, which isn't as good, but still ok.
378
336
            # 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,
 
337
            n = ctypes.c_int(MAX_COMPUTERNAME_LENGTH + 1)
 
338
            GetComputerName = getattr(kernel32, 'GetComputerName' + suffix,
381
339
                                      None)
382
340
            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())
 
341
                    and GetComputerName(buf, ctypes.byref(n))):
 
342
                return extract_buffer(buf)
 
343
    return get_environ_unicode('COMPUTERNAME')
414
344
 
415
345
 
416
346
def _ensure_with_dir(path):
417
347
    if (not os.path.split(path)[0] or path.startswith(u'*')
418
 
        or path.startswith(u'?')):
 
348
            or path.startswith(u'?')):
419
349
        return u'./' + path, True
420
350
    else:
421
351
        return path, False
422
352
 
 
353
 
423
354
def _undo_ensure_with_dir(path, corrected):
424
355
    if corrected:
425
356
        return path[2:]
427
358
        return path
428
359
 
429
360
 
430
 
 
431
361
def glob_one(possible_glob):
432
362
    """Same as glob.glob().
433
363
 
457
387
    :param file_list: A list of filenames which may include shell globs.
458
388
    :return: An expanded list of filenames.
459
389
 
460
 
    Introduced in bzrlib 0.18.
 
390
    Introduced in breezy 0.18.
461
391
    """
462
392
    if not file_list:
463
393
        return []
468
398
 
469
399
 
470
400
def get_app_path(appname):
471
 
    """Look up in Windows registry for full path to application executable.
 
401
    r"""Look up in Windows registry for full path to application executable.
472
402
    Typically, applications create subkey with their basename
473
403
    in HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\
474
404
 
485
415
 
486
416
    try:
487
417
        hkey = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,
488
 
            'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\' +
489
 
            basename)
 
418
                               'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\' +
 
419
                               basename)
490
420
    except EnvironmentError:
491
421
        return appname
492
422
 
511
441
def set_file_attr_hidden(path):
512
442
    """Set file attributes to hidden if possible"""
513
443
    if has_win32file:
514
 
        if winver != 'Windows 98':
515
 
            SetFileAttributes = win32file.SetFileAttributesW
516
 
        else:
517
 
            SetFileAttributes = win32file.SetFileAttributes
 
444
        SetFileAttributes = win32file.SetFileAttributesW
518
445
        try:
519
446
            SetFileAttributes(path, win32file.FILE_ATTRIBUTE_HIDDEN)
520
 
        except pywintypes.error, e:
521
 
            from bzrlib import trace
 
447
        except pywintypes.error as e:
 
448
            from . import trace
522
449
            trace.mutter('Unable to set hidden attribute on %r: %s', path, e)
523
450
 
524
451
 
525
 
def _command_line_to_argv(command_line, single_quotes_allowed=False):
 
452
def _command_line_to_argv(command_line, argv, single_quotes_allowed=False):
526
453
    """Convert a Unicode command line into a list of argv arguments.
527
454
 
528
455
    It performs wildcard expansion to make wildcards act closer to how they
535
462
                                  default.
536
463
    :return: A list of unicode strings.
537
464
    """
538
 
    s = cmdline.Splitter(command_line, single_quotes_allowed=single_quotes_allowed)
539
 
    # Now that we've split the content, expand globs if necessary
 
465
    # First, split the command line
 
466
    s = cmdline.Splitter(
 
467
        command_line, single_quotes_allowed=single_quotes_allowed)
 
468
 
 
469
    # Bug #587868 Now make sure that the length of s agrees with sys.argv
 
470
    # we do this by simply counting the number of arguments in each. The counts should
 
471
    # agree no matter what encoding sys.argv is in (AFAIK)
 
472
    # len(arguments) < len(sys.argv) should be an impossibility since python gets
 
473
    # args from the very same PEB as does GetCommandLineW
 
474
    arguments = list(s)
 
475
 
 
476
    # Now shorten the command line we get from GetCommandLineW to match sys.argv
 
477
    if len(arguments) < len(argv):
 
478
        raise AssertionError("Split command line can't be shorter than argv")
 
479
    arguments = arguments[len(arguments) - len(argv):]
 
480
 
 
481
    # Carry on to process globs (metachars) in the command line
 
482
    # expand globs if necessary
540
483
    # TODO: Use 'globbing' instead of 'glob.glob', this gives us stuff like
541
484
    #       '**/' style globs
542
485
    args = []
543
 
    for is_quoted, arg in s:
 
486
    for is_quoted, arg in arguments:
544
487
        if is_quoted or not glob.has_magic(arg):
545
488
            args.append(arg)
546
489
        else:
548
491
    return args
549
492
 
550
493
 
551
 
if has_ctypes and winver != 'Windows 98':
 
494
if has_ctypes:
552
495
    def get_unicode_argv():
553
496
        prototype = ctypes.WINFUNCTYPE(ctypes.c_wchar_p)
554
497
        GetCommandLineW = prototype(("GetCommandLineW",
557
500
        if command_line is None:
558
501
            raise ctypes.WinError()
559
502
        # 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:]
 
503
        argv = _command_line_to_argv(command_line, sys.argv)[1:]
571
504
        return argv
572
 
else:
573
 
    get_unicode_argv = None
 
505
 
 
506
    def get_environ_unicode(key, default=None):
 
507
        """Get `key` from environment as unicode or `default` if unset
 
508
 
 
509
        The environment is natively unicode on modern windows versions but
 
510
        Python 2 only accesses it through the legacy bytestring api.
 
511
 
 
512
        Environmental variable names are case insenstive on Windows.
 
513
 
 
514
        A large enough buffer will be allocated to retrieve the value, though
 
515
        it may take two calls to the underlying library function.
 
516
 
 
517
        This needs ctypes because pywin32 does not expose the wide version.
 
518
        """
 
519
        cfunc = getattr(get_environ_unicode, "_c_function", None)
 
520
        if cfunc is None:
 
521
            from ctypes.wintypes import DWORD, LPCWSTR, LPWSTR
 
522
            cfunc = ctypes.WINFUNCTYPE(DWORD, LPCWSTR, LPWSTR, DWORD)(
 
523
                ("GetEnvironmentVariableW", ctypes.windll.kernel32))
 
524
            get_environ_unicode._c_function = cfunc
 
525
        buffer_size = 256  # heuristic, 256 characters often enough
 
526
        while True:
 
527
            buffer = ctypes.create_unicode_buffer(buffer_size)
 
528
            length = cfunc(key, buffer, buffer_size)
 
529
            if not length:
 
530
                code = ctypes.GetLastError()
 
531
                if code == 203:  # ERROR_ENVVAR_NOT_FOUND
 
532
                    return default
 
533
                raise ctypes.WinError(code)
 
534
            if buffer_size > length:
 
535
                return buffer[:length]
 
536
            buffer_size = length
 
537
 
 
538
 
 
539
if has_win32api:
 
540
    def _pywin32_is_local_pid_dead(pid):
 
541
        """True if pid doesn't correspond to live process on this machine"""
 
542
        try:
 
543
            handle = win32api.OpenProcess(1, False, pid)  # PROCESS_TERMINATE
 
544
        except pywintypes.error as e:
 
545
            if e[0] == 5:  # ERROR_ACCESS_DENIED
 
546
                # Probably something alive we're not allowed to kill
 
547
                return False
 
548
            elif e[0] == 87:  # ERROR_INVALID_PARAMETER
 
549
                return True
 
550
            raise
 
551
        handle.close()
 
552
        return False
 
553
    is_local_pid_dead = _pywin32_is_local_pid_dead
 
554
elif has_ctypes and sys.platform == 'win32':
 
555
    from ctypes.wintypes import BOOL, DWORD, HANDLE
 
556
    _kernel32 = ctypes.windll.kernel32
 
557
    _CloseHandle = ctypes.WINFUNCTYPE(BOOL, HANDLE)(
 
558
        ("CloseHandle", _kernel32))
 
559
    _OpenProcess = ctypes.WINFUNCTYPE(HANDLE, DWORD, BOOL, DWORD)(
 
560
        ("OpenProcess", _kernel32))
 
561
 
 
562
    def _ctypes_is_local_pid_dead(pid):
 
563
        """True if pid doesn't correspond to live process on this machine"""
 
564
        handle = _OpenProcess(1, False, pid)  # PROCESS_TERMINATE
 
565
        if not handle:
 
566
            errorcode = ctypes.GetLastError()
 
567
            if errorcode == 5:  # ERROR_ACCESS_DENIED
 
568
                # Probably something alive we're not allowed to kill
 
569
                return False
 
570
            elif errorcode == 87:  # ERROR_INVALID_PARAMETER
 
571
                return True
 
572
            raise ctypes.WinError(errorcode)
 
573
        _CloseHandle(handle)
 
574
        return False
 
575
    is_local_pid_dead = _ctypes_is_local_pid_dead
 
576
 
 
577
 
 
578
def _is_pywintypes_error(evalue):
 
579
    """True if exception instance is an error from pywin32"""
 
580
    if has_pywintypes and isinstance(evalue, pywintypes.error):
 
581
        return True
 
582
    return False