/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: 2017-06-08 23:30:31 UTC
  • mto: This revision was merged to the branch mainline in revision 6690.
  • Revision ID: jelmer@jelmer.uk-20170608233031-3qavls2o7a1pqllj
Update imports.

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
29
32
    )
30
33
from breezy.i18n import gettext
31
34
 
 
35
# We can cope without it; use a separate variable to help pyflakes
 
36
try:
 
37
    import ctypes
 
38
    has_ctypes = True
 
39
except ImportError:
 
40
    has_ctypes = False
 
41
else:
 
42
    create_buffer = ctypes.create_unicode_buffer
 
43
    extract_buffer = operator.attrgetter("value")
 
44
    suffix = 'W'
 
45
try:
 
46
    import pywintypes
 
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
 
61
 
 
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...
32
66
 
33
67
# Special Win32 API constants
34
68
# Handles of std streams
38
72
 
39
73
# CSIDL constants (from MSDN 2003)
40
74
CSIDL_APPDATA = 0x001A      # Application Data folder
41
 
# <user name>\Local Settings\Application Data (non roaming)
42
 
CSIDL_LOCAL_APPDATA = 0x001c
 
75
CSIDL_LOCAL_APPDATA = 0x001c# <user name>\Local Settings\Application Data (non roaming)
43
76
CSIDL_PERSONAL = 0x0005     # My Documents folder
44
77
 
45
78
# from winapi C headers
54
87
 
55
88
def debug_memory_win32api(message='', short=True):
56
89
    """Use trace.note() to dump the running memory info."""
57
 
    import ctypes
58
90
    from breezy import trace
59
 
    class PROCESS_MEMORY_COUNTERS_EX(ctypes.Structure):
60
 
        """Used by GetProcessMemoryInfo"""
61
 
        _fields_ = [('cb', ctypes.c_ulong),
62
 
                    ('PageFaultCount', ctypes.c_ulong),
63
 
                    ('PeakWorkingSetSize', ctypes.c_size_t),
64
 
                    ('WorkingSetSize', ctypes.c_size_t),
65
 
                    ('QuotaPeakPagedPoolUsage', ctypes.c_size_t),
66
 
                    ('QuotaPagedPoolUsage', ctypes.c_size_t),
67
 
                    ('QuotaPeakNonPagedPoolUsage', ctypes.c_size_t),
68
 
                    ('QuotaNonPagedPoolUsage', ctypes.c_size_t),
69
 
                    ('PagefileUsage', ctypes.c_size_t),
70
 
                    ('PeakPagefileUsage', ctypes.c_size_t),
71
 
                    ('PrivateUsage', ctypes.c_size_t),
72
 
                    ]
73
 
    cur_process = ctypes.windll.kernel32.GetCurrentProcess()
74
 
    mem_struct = PROCESS_MEMORY_COUNTERS_EX()
75
 
    ret = ctypes.windll.psapi.GetProcessMemoryInfo(
76
 
        cur_process, ctypes.byref(mem_struct), ctypes.sizeof(mem_struct))
77
 
    if not ret:
78
 
        trace.note(gettext('Failed to GetProcessMemoryInfo()'))
 
91
    if has_ctypes:
 
92
        class PROCESS_MEMORY_COUNTERS_EX(ctypes.Structure):
 
93
            """Used by GetProcessMemoryInfo"""
 
94
            _fields_ = [('cb', ctypes.c_ulong),
 
95
                        ('PageFaultCount', ctypes.c_ulong),
 
96
                        ('PeakWorkingSetSize', ctypes.c_size_t),
 
97
                        ('WorkingSetSize', ctypes.c_size_t),
 
98
                        ('QuotaPeakPagedPoolUsage', ctypes.c_size_t),
 
99
                        ('QuotaPagedPoolUsage', ctypes.c_size_t),
 
100
                        ('QuotaPeakNonPagedPoolUsage', ctypes.c_size_t),
 
101
                        ('QuotaNonPagedPoolUsage', ctypes.c_size_t),
 
102
                        ('PagefileUsage', ctypes.c_size_t),
 
103
                        ('PeakPagefileUsage', ctypes.c_size_t),
 
104
                        ('PrivateUsage', ctypes.c_size_t),
 
105
                       ]
 
106
        cur_process = ctypes.windll.kernel32.GetCurrentProcess()
 
107
        mem_struct = PROCESS_MEMORY_COUNTERS_EX()
 
108
        ret = ctypes.windll.psapi.GetProcessMemoryInfo(cur_process,
 
109
            ctypes.byref(mem_struct),
 
110
            ctypes.sizeof(mem_struct))
 
111
        if not ret:
 
112
            trace.note(gettext('Failed to GetProcessMemoryInfo()'))
 
113
            return
 
114
        info = {'PageFaultCount': mem_struct.PageFaultCount,
 
115
                'PeakWorkingSetSize': mem_struct.PeakWorkingSetSize,
 
116
                'WorkingSetSize': mem_struct.WorkingSetSize,
 
117
                'QuotaPeakPagedPoolUsage': mem_struct.QuotaPeakPagedPoolUsage,
 
118
                'QuotaPagedPoolUsage': mem_struct.QuotaPagedPoolUsage,
 
119
                'QuotaPeakNonPagedPoolUsage':
 
120
                    mem_struct.QuotaPeakNonPagedPoolUsage,
 
121
                'QuotaNonPagedPoolUsage': mem_struct.QuotaNonPagedPoolUsage,
 
122
                'PagefileUsage': mem_struct.PagefileUsage,
 
123
                'PeakPagefileUsage': mem_struct.PeakPagefileUsage,
 
124
                'PrivateUsage': mem_struct.PrivateUsage,
 
125
               }
 
126
    elif has_win32api:
 
127
        import win32process
 
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)
 
132
    else:
 
133
        trace.note(gettext('Cannot debug memory on win32 without ctypes'
 
134
                   ' or win32process'))
79
135
        return
80
 
    info = {'PageFaultCount': mem_struct.PageFaultCount,
81
 
            'PeakWorkingSetSize': mem_struct.PeakWorkingSetSize,
82
 
            'WorkingSetSize': mem_struct.WorkingSetSize,
83
 
            'QuotaPeakPagedPoolUsage': mem_struct.QuotaPeakPagedPoolUsage,
84
 
            'QuotaPagedPoolUsage': mem_struct.QuotaPagedPoolUsage,
85
 
            'QuotaPeakNonPagedPoolUsage':
86
 
                mem_struct.QuotaPeakNonPagedPoolUsage,
87
 
            'QuotaNonPagedPoolUsage': mem_struct.QuotaNonPagedPoolUsage,
88
 
            'PagefileUsage': mem_struct.PagefileUsage,
89
 
            'PeakPagefileUsage': mem_struct.PeakPagefileUsage,
90
 
            'PrivateUsage': mem_struct.PrivateUsage,
91
 
            }
92
136
    if short:
93
137
        # using base-2 units (see HACKING.txt).
94
138
        trace.note(gettext('WorkingSize {0:>7}KiB'
95
 
                           '\tPeakWorking {1:>7}KiB\t{2}').format(
 
139
                   '\tPeakWorking {1:>7}KiB\t{2}').format(
96
140
                   info['WorkingSetSize'] / 1024,
97
141
                   info['PeakWorkingSetSize'] / 1024,
98
142
                   message))
99
143
        return
100
144
    if message:
101
145
        trace.note('%s', message)
102
 
    trace.note(gettext('WorkingSize       %8d KiB'),
103
 
               info['WorkingSetSize'] / 1024)
104
 
    trace.note(gettext('PeakWorking       %8d KiB'),
105
 
               info['PeakWorkingSetSize'] / 1024)
106
 
    trace.note(gettext('PagefileUsage     %8d KiB'),
107
 
               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)
108
149
    trace.note(gettext('PeakPagefileUsage %8d KiB'),
109
150
               info.get('PeakPagefileUsage', 0) / 1024)
110
 
    trace.note(gettext('PrivateUsage      %8d KiB'),
111
 
               info.get('PrivateUsage', 0) / 1024)
 
151
    trace.note(gettext('PrivateUsage      %8d KiB'), info.get('PrivateUsage', 0) / 1024)
112
152
    trace.note(gettext('PageFaultCount    %8d'), info.get('PageFaultCount', 0))
113
153
 
114
154
 
119
159
    console window and return tuple (sizex, sizey) if success,
120
160
    or default size (defaultx, defaulty) otherwise.
121
161
    """
122
 
    import ctypes
 
162
    if not has_ctypes:
 
163
        # no ctypes is found
 
164
        return (defaultx, defaulty)
 
165
 
123
166
    # To avoid problem with redirecting output via pipe
124
167
    # we need to use stderr instead of stdout
125
168
    h = ctypes.windll.kernel32.GetStdHandle(WIN32_STDERR_HANDLE)
128
171
 
129
172
    if res:
130
173
        (bufx, bufy, curx, cury, wattr,
131
 
         left, top, right, bottom, maxx, maxy) = struct.unpack(
 
174
        left, top, right, bottom, maxx, maxy) = struct.unpack(
132
175
            "hhhhHhhhhhh", csbi.raw)
133
176
        sizex = right - left + 1
134
177
        sizey = bottom - top + 1
142
185
 
143
186
    Result is always unicode (or None).
144
187
    """
145
 
    import ctypes
146
 
    try:
147
 
        SHGetSpecialFolderPath = \
148
 
            ctypes.windll.shell32.SHGetSpecialFolderPathW
149
 
    except AttributeError:
150
 
        pass
151
 
    else:
152
 
        buf = ctypes.create_unicode_buffer(MAX_PATH)
153
 
        if SHGetSpecialFolderPath(None, buf, csidl, 0):
154
 
            return buf.value
 
188
    if has_ctypes:
 
189
        try:
 
190
            SHGetSpecialFolderPath = \
 
191
                ctypes.windll.shell32.SHGetSpecialFolderPathW
 
192
        except AttributeError:
 
193
            pass
 
194
        else:
 
195
            buf = ctypes.create_unicode_buffer(MAX_PATH)
 
196
            if SHGetSpecialFolderPath(None,buf,csidl,0):
 
197
                return buf.value
 
198
 
 
199
    global has_win32com_shell
 
200
    if has_win32com_shell is None:
 
201
        try:
 
202
            from win32com.shell import shell
 
203
            has_win32com_shell = True
 
204
        except ImportError:
 
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
 
209
        try:
 
210
            return shell.SHGetSpecialFolderPath(0, csidl, 0)
 
211
        except shell.error:
 
212
            # possibly E_NOTIMPL meaning we can't load the function pointer,
 
213
            # or E_FAIL meaning the function failed - regardless, just ignore it
 
214
            pass
 
215
    return None
155
216
 
156
217
 
157
218
def get_appdata_location():
167
228
    if appdata:
168
229
        return appdata
169
230
    # Use APPDATA if defined, will return None if not
170
 
    return os.environ.get('APPDATA')
 
231
    return get_environ_unicode('APPDATA')
171
232
 
172
233
 
173
234
def get_local_appdata_location():
184
245
    if local:
185
246
        return local
186
247
    # Vista supplies LOCALAPPDATA, but XP and earlier do not.
187
 
    local = os.environ.get('LOCALAPPDATA')
 
248
    local = get_environ_unicode('LOCALAPPDATA')
188
249
    if local:
189
250
        return local
190
251
    return get_appdata_location()
199
260
    home = _get_sh_special_folder_path(CSIDL_PERSONAL)
200
261
    if home:
201
262
        return home
202
 
    home = os.environ.get('HOME')
 
263
    home = get_environ_unicode('HOME')
203
264
    if home is not None:
204
265
        return home
205
 
    homepath = os.environ.get('HOMEPATH')
 
266
    homepath = get_environ_unicode('HOMEPATH')
206
267
    if homepath is not None:
207
 
        return os.path.join(os.environ.get('HOMEDIR', ''), home)
 
268
        return os.path.join(get_environ_unicode('HOMEDIR', ''), home)
208
269
    # at least return windows root directory
209
 
    windir = os.environ.get('WINDIR')
 
270
    windir = get_environ_unicode('WINDIR')
210
271
    if windir:
211
272
        return os.path.splitdrive(windir)[0] + '/'
212
273
    # otherwise C:\ is good enough for 98% users
213
 
    return u'C:/'
 
274
    return unicode('C:/')
214
275
 
215
276
 
216
277
def get_user_name():
217
278
    """Return user name as login name.
218
279
    If name cannot be obtained return None.
219
280
    """
220
 
    try:
221
 
        advapi32 = ctypes.windll.advapi32
222
 
        GetUserName = getattr(advapi32, 'GetUserNameW')
223
 
    except AttributeError:
224
 
        pass
225
 
    else:
226
 
        buf = ctypes.create_unicode_buffer(UNLEN + 1)
227
 
        n = ctypes.c_int(UNLEN + 1)
228
 
        if GetUserName(buf, ctypes.byref(n)):
229
 
            return buf.value
 
281
    if has_ctypes:
 
282
        try:
 
283
            advapi32 = ctypes.windll.advapi32
 
284
            GetUserName = getattr(advapi32, 'GetUserName'+suffix)
 
285
        except AttributeError:
 
286
            pass
 
287
        else:
 
288
            buf = create_buffer(UNLEN+1)
 
289
            n = ctypes.c_int(UNLEN+1)
 
290
            if GetUserName(buf, ctypes.byref(n)):
 
291
                return extract_buffer(buf)
230
292
    # otherwise try env variables
231
 
    return os.environ.get('USERNAME')
 
293
    return get_environ_unicode('USERNAME')
232
294
 
233
295
 
234
296
# 1 == ComputerNameDnsHostname, which returns "The DNS host name of the local
235
297
# computer or the cluster associated with the local computer."
236
298
_WIN32_ComputerNameDnsHostname = 1
237
299
 
238
 
 
239
300
def get_host_name():
240
301
    """Return host machine name.
241
302
    If name cannot be obtained return None.
242
303
 
243
304
    :return: A unicode string representing the host name.
244
305
    """
245
 
    import ctypes
246
 
    buf = ctypes.create_unicode_buffer(MAX_COMPUTERNAME_LENGTH + 1)
247
 
    n = ctypes.c_int(MAX_COMPUTERNAME_LENGTH + 1)
248
 
 
249
 
    # Try GetComputerNameEx which gives a proper Unicode hostname
250
 
    GetComputerNameEx = getattr(
251
 
        ctypes.windll.kernel32, 'GetComputerNameExW', None)
252
 
    if (GetComputerNameEx is not None
253
 
        and GetComputerNameEx(_WIN32_ComputerNameDnsHostname,
254
 
                              buf, ctypes.byref(n))):
255
 
        return buf.value
256
 
    return os.environ.get('COMPUTERNAME')
 
306
    if has_win32api:
 
307
        try:
 
308
            return win32api.GetComputerNameEx(_WIN32_ComputerNameDnsHostname)
 
309
        except (NotImplementedError, win32api.error):
 
310
            # NotImplemented will happen on win9x...
 
311
            pass
 
312
    if has_ctypes:
 
313
        try:
 
314
            kernel32 = ctypes.windll.kernel32
 
315
        except AttributeError:
 
316
            pass # Missing the module we need
 
317
        else:
 
318
            buf = create_buffer(MAX_COMPUTERNAME_LENGTH+1)
 
319
            n = ctypes.c_int(MAX_COMPUTERNAME_LENGTH+1)
 
320
 
 
321
            # Try GetComputerNameEx which gives a proper Unicode hostname
 
322
            GetComputerNameEx = getattr(kernel32, 'GetComputerNameEx'+suffix,
 
323
                                        None)
 
324
            if (GetComputerNameEx is not None
 
325
                and GetComputerNameEx(_WIN32_ComputerNameDnsHostname,
 
326
                                      buf, ctypes.byref(n))):
 
327
                return extract_buffer(buf)
 
328
 
 
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,
 
334
                                      None)
 
335
            if (GetComputerName is not None
 
336
                and GetComputerName(buf, ctypes.byref(n))):
 
337
                return extract_buffer(buf)
 
338
    return get_environ_unicode('COMPUTERNAME')
257
339
 
258
340
 
259
341
def _ensure_with_dir(path):
260
342
    if (not os.path.split(path)[0] or path.startswith(u'*')
261
 
            or path.startswith(u'?')):
 
343
        or path.startswith(u'?')):
262
344
        return u'./' + path, True
263
345
    else:
264
346
        return path, False
265
347
 
266
 
 
267
348
def _undo_ensure_with_dir(path, corrected):
268
349
    if corrected:
269
350
        return path[2:]
328
409
 
329
410
    try:
330
411
        hkey = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,
331
 
                               'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\' +
332
 
                               basename)
 
412
            'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\' +
 
413
            basename)
333
414
    except EnvironmentError:
334
415
        return appname
335
416
 
343
424
 
344
425
    if type_id == REG_SZ:
345
426
        return path
 
427
    if type_id == REG_EXPAND_SZ and has_win32api:
 
428
        fullpath = win32api.ExpandEnvironmentStrings(path)
 
429
        if len(fullpath) > 1 and fullpath[0] == '"' and fullpath[-1] == '"':
 
430
            fullpath = fullpath[1:-1]   # remove quotes around value
 
431
        return fullpath
346
432
    return appname
347
433
 
348
434
 
349
435
def set_file_attr_hidden(path):
350
436
    """Set file attributes to hidden if possible"""
351
 
    from ctypes.wintypes import BOOL, DWORD, LPWSTR
352
 
    import ctypes
353
 
    # <https://docs.microsoft.com/windows/desktop/api/fileapi/nf-fileapi-setfileattributesw>
354
 
    SetFileAttributes = ctypes.windll.kernel32.SetFileAttributesW
355
 
    SetFileAttributes.argtypes = LPWSTR, DWORD
356
 
    SetFileAttributes.restype = BOOL
357
 
    FILE_ATTRIBUTE_HIDDEN = 2
358
 
    if not SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN):
359
 
        e = ctypes.WinError()
360
 
        from . import trace
361
 
        trace.mutter('Unable to set hidden attribute on %r: %s', path, e)
 
437
    if has_win32file:
 
438
        SetFileAttributes = win32file.SetFileAttributesW
 
439
        try:
 
440
            SetFileAttributes(path, win32file.FILE_ATTRIBUTE_HIDDEN)
 
441
        except pywintypes.error as e:
 
442
            from . import trace
 
443
            trace.mutter('Unable to set hidden attribute on %r: %s', path, e)
362
444
 
363
445
 
364
446
def _command_line_to_argv(command_line, argv, single_quotes_allowed=False):
375
457
    :return: A list of unicode strings.
376
458
    """
377
459
    # First, split the command line
378
 
    s = cmdline.Splitter(
379
 
        command_line, single_quotes_allowed=single_quotes_allowed)
380
 
 
381
 
    # Bug #587868 Now make sure that the length of s agrees with sys.argv
382
 
    # we do this by simply counting the number of arguments in each. The counts should
383
 
    # agree no matter what encoding sys.argv is in (AFAIK)
384
 
    # len(arguments) < len(sys.argv) should be an impossibility since python gets
 
460
    s = cmdline.Splitter(command_line, single_quotes_allowed=single_quotes_allowed)
 
461
    
 
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 
385
466
    # args from the very same PEB as does GetCommandLineW
386
467
    arguments = list(s)
387
 
 
 
468
    
388
469
    # Now shorten the command line we get from GetCommandLineW to match sys.argv
389
470
    if len(arguments) < len(argv):
390
471
        raise AssertionError("Split command line can't be shorter than argv")
391
472
    arguments = arguments[len(arguments) - len(argv):]
392
 
 
 
473
    
393
474
    # Carry on to process globs (metachars) in the command line
394
475
    # expand globs if necessary
395
476
    # TODO: Use 'globbing' instead of 'glob.glob', this gives us stuff like
403
484
    return args
404
485
 
405
486
 
406
 
def _ctypes_is_local_pid_dead(pid):
407
 
    import ctypes
408
 
    kernel32 = ctypes.wintypes.windll.kernel32
409
 
    """True if pid doesn't correspond to live process on this machine"""
410
 
    handle = kernel32.OpenProcess(1, False, pid)
411
 
    if not handle:
412
 
        errorcode = ctypes.GetLastError()
413
 
        if errorcode == 5:  # ERROR_ACCESS_DENIED
414
 
            # Probably something alive we're not allowed to kill
415
 
            return False
416
 
        elif errorcode == 87:  # ERROR_INVALID_PARAMETER
417
 
            return True
418
 
        raise ctypes.WinError(errorcode)
419
 
    Kernel32.CloseHandle(handle)
 
487
if has_ctypes:
 
488
    def get_unicode_argv():
 
489
        prototype = ctypes.WINFUNCTYPE(ctypes.c_wchar_p)
 
490
        GetCommandLineW = prototype(("GetCommandLineW",
 
491
                                     ctypes.windll.kernel32))
 
492
        command_line = GetCommandLineW()
 
493
        if command_line is None:
 
494
            raise ctypes.WinError()
 
495
        # Skip the first argument, since we only care about parameters
 
496
        argv = _command_line_to_argv(command_line, sys.argv)[1:]
 
497
        return argv
 
498
 
 
499
 
 
500
    def get_environ_unicode(key, default=None):
 
501
        """Get `key` from environment as unicode or `default` if unset
 
502
 
 
503
        The environment is natively unicode on modern windows versions but
 
504
        Python 2 only accesses it through the legacy bytestring api.
 
505
 
 
506
        Environmental variable names are case insenstive on Windows.
 
507
 
 
508
        A large enough buffer will be allocated to retrieve the value, though
 
509
        it may take two calls to the underlying library function.
 
510
 
 
511
        This needs ctypes because pywin32 does not expose the wide version.
 
512
        """
 
513
        cfunc = getattr(get_environ_unicode, "_c_function", None)
 
514
        if cfunc is None:
 
515
            from ctypes.wintypes import DWORD, LPCWSTR, LPWSTR
 
516
            cfunc = ctypes.WINFUNCTYPE(DWORD, LPCWSTR, LPWSTR, DWORD)(
 
517
                ("GetEnvironmentVariableW", ctypes.windll.kernel32))
 
518
            get_environ_unicode._c_function = cfunc
 
519
        buffer_size = 256 # heuristic, 256 characters often enough
 
520
        while True:
 
521
            buffer = ctypes.create_unicode_buffer(buffer_size)
 
522
            length = cfunc(key, buffer, buffer_size)
 
523
            if not length:
 
524
                code = ctypes.GetLastError()
 
525
                if code == 203: # ERROR_ENVVAR_NOT_FOUND
 
526
                    return default
 
527
                raise ctypes.WinError(code)
 
528
            if buffer_size > length:
 
529
                return buffer[:length]
 
530
            buffer_size = length
 
531
 
 
532
 
 
533
if has_win32api:
 
534
    def _pywin32_is_local_pid_dead(pid):
 
535
        """True if pid doesn't correspond to live process on this machine"""
 
536
        try:
 
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
 
541
                return False
 
542
            elif e[0] == 87: # ERROR_INVALID_PARAMETER
 
543
                return True
 
544
            raise
 
545
        handle.close()
 
546
        return False
 
547
    is_local_pid_dead = _pywin32_is_local_pid_dead
 
548
elif has_ctypes and sys.platform == 'win32':
 
549
    from ctypes.wintypes import BOOL, DWORD, HANDLE
 
550
    _kernel32 = ctypes.windll.kernel32
 
551
    _CloseHandle = ctypes.WINFUNCTYPE(BOOL, HANDLE)(
 
552
        ("CloseHandle", _kernel32))
 
553
    _OpenProcess = ctypes.WINFUNCTYPE(HANDLE, DWORD, BOOL, DWORD)(
 
554
        ("OpenProcess", _kernel32))
 
555
    def _ctypes_is_local_pid_dead(pid):
 
556
        """True if pid doesn't correspond to live process on this machine"""
 
557
        handle = _OpenProcess(1, False, pid) # PROCESS_TERMINATE
 
558
        if not handle:
 
559
            errorcode = ctypes.GetLastError()
 
560
            if errorcode == 5: # ERROR_ACCESS_DENIED
 
561
                # Probably something alive we're not allowed to kill
 
562
                return False
 
563
            elif errorcode == 87: # ERROR_INVALID_PARAMETER
 
564
                return True
 
565
            raise ctypes.WinError(errorcode)
 
566
        _CloseHandle(handle)
 
567
        return False
 
568
    is_local_pid_dead = _ctypes_is_local_pid_dead
 
569
 
 
570
 
 
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):
 
574
        return True
420
575
    return False
421
 
 
422
 
is_local_pid_dead = _ctypes_is_local_pid_dead