brintos

brintos / llvm-project-archived public Read only

0
0
Text · 3.7 KiB · 84f4336 Raw
124 lines · python
1# DExTer : Debugging Experience Tester2# ~~~~~~   ~         ~~         ~   ~~3#4# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.5# See https://llvm.org/LICENSE.txt for license information.6# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception7"""Communication via the Windows COM interface."""8 9import inspect10import time11import sys12 13# pylint: disable=import-error14import win32com.client as com15import win32api16 17# pylint: enable=import-error18 19from dex.utils.Exceptions import LoadDebuggerException20 21_com_error = com.pywintypes.com_error  # pylint: disable=no-member22 23 24def get_file_version(file_):25    try:26        info = win32api.GetFileVersionInfo(file_, "\\")27        ms = info["FileVersionMS"]28        ls = info["FileVersionLS"]29        return ".".join(30            str(s)31            for s in [32                win32api.HIWORD(ms),33                win32api.LOWORD(ms),34                win32api.HIWORD(ls),35                win32api.LOWORD(ls),36            ]37        )38    except com.pywintypes.error:  # pylint: disable=no-member39        return "no versioninfo present"40 41 42def _handle_com_error(e):43    exc = sys.exc_info()44    msg = win32api.FormatMessage(e.hresult)45    try:46        msg = msg.decode("CP1251")47    except AttributeError:48        pass49    msg = msg.strip()50    return msg, exc51 52 53class ComObject(object):54    """Wrap a raw Windows COM object in a class that implements auto-retry of55    failed calls.56    """57 58    def __init__(self, raw):59        assert not isinstance(raw, ComObject), raw60        self.__dict__["raw"] = raw61 62    def __str__(self):63        return self._call(self.raw.__str__)64 65    def __getattr__(self, key):66        if key in self.__dict__:67            return self.__dict__[key]68        return self._call(self.raw.__getattr__, key)69 70    def __setattr__(self, key, val):71        if key in self.__dict__:72            self.__dict__[key] = val73        self._call(self.raw.__setattr__, key, val)74 75    def __getitem__(self, key):76        return self._call(self.raw.__getitem__, key)77 78    def __setitem__(self, key, val):79        self._call(self.raw.__setitem__, key, val)80 81    def __call__(self, *args):82        return self._call(self.raw, *args)83 84    @classmethod85    def _call(cls, fn, *args):86        """COM calls tend to randomly fail due to thread sync issues.87        The Microsoft recommended solution is to set up a message filter object88        to automatically retry failed calls, but this seems prohibitively hard89        from python, so this is a custom solution to do the same thing.90        All COM accesses should go through this function.91        """92        ex = AssertionError("this should never be raised!")93 94        assert (95            inspect.isfunction(fn) or inspect.ismethod(fn) or inspect.isbuiltin(fn)96        ), (fn, type(fn))97        retries = ([0] * 50) + ([1] * 5)98        for r in retries:99            try:100                try:101                    result = fn(*args)102                    if inspect.ismethod(result) or "win32com" in str(result.__class__):103                        result = ComObject(result)104                    return result105                except _com_error as e:106                    msg, _ = _handle_com_error(e)107                    e = WindowsError(msg)  # pylint: disable=undefined-variable108                    raise e109            except (AttributeError, TypeError, OSError) as e:110                ex = e111                time.sleep(r)112        raise ex113 114 115class DTE(ComObject):116    def __init__(self, class_string):117        try:118            super(DTE, self).__init__(com.DispatchEx(class_string))119        except _com_error as e:120            msg, exc = _handle_com_error(e)121            raise LoadDebuggerException(122                "{} [{}]".format(msg, class_string), orig_exception=exc123            )124