Files
clang-p2996/cross-project-tests/debuginfo-tests/dexter/dex/debugger/visualstudio/windows/ComInterface.py
Tobias Hieta f98ee40f4b [NFC][Py Reformat] Reformat python files in the rest of the dirs
This is an ongoing series of commits that are reformatting our
Python code. This catches the last of the python files to
reformat. Since they where so few I bunched them together.

Reformatting is done with `black`.

If you end up having problems merging this commit because you
have made changes to a python file, the best way to handle that
is to run git checkout --ours <yourfile> and then reformat it
with black.

If you run into any problems, post to discourse about it and
we will try to help.

RFC Thread below:

https://discourse.llvm.org/t/rfc-document-and-standardize-python-code-style

Reviewed By: jhenderson, #libc, Mordante, sivachandra

Differential Revision: https://reviews.llvm.org/D150784
2023-05-25 11:17:05 +02:00

124 lines
3.7 KiB
Python

# DExTer : Debugging Experience Tester
# ~~~~~~ ~ ~~ ~ ~~
#
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
# See https://llvm.org/LICENSE.txt for license information.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
"""Communication via the Windows COM interface."""
import inspect
import time
import sys
# pylint: disable=import-error
import win32com.client as com
import win32api
# pylint: enable=import-error
from dex.utils.Exceptions import LoadDebuggerException
_com_error = com.pywintypes.com_error # pylint: disable=no-member
def get_file_version(file_):
try:
info = win32api.GetFileVersionInfo(file_, "\\")
ms = info["FileVersionMS"]
ls = info["FileVersionLS"]
return ".".join(
str(s)
for s in [
win32api.HIWORD(ms),
win32api.LOWORD(ms),
win32api.HIWORD(ls),
win32api.LOWORD(ls),
]
)
except com.pywintypes.error: # pylint: disable=no-member
return "no versioninfo present"
def _handle_com_error(e):
exc = sys.exc_info()
msg = win32api.FormatMessage(e.hresult)
try:
msg = msg.decode("CP1251")
except AttributeError:
pass
msg = msg.strip()
return msg, exc
class ComObject(object):
"""Wrap a raw Windows COM object in a class that implements auto-retry of
failed calls.
"""
def __init__(self, raw):
assert not isinstance(raw, ComObject), raw
self.__dict__["raw"] = raw
def __str__(self):
return self._call(self.raw.__str__)
def __getattr__(self, key):
if key in self.__dict__:
return self.__dict__[key]
return self._call(self.raw.__getattr__, key)
def __setattr__(self, key, val):
if key in self.__dict__:
self.__dict__[key] = val
self._call(self.raw.__setattr__, key, val)
def __getitem__(self, key):
return self._call(self.raw.__getitem__, key)
def __setitem__(self, key, val):
self._call(self.raw.__setitem__, key, val)
def __call__(self, *args):
return self._call(self.raw, *args)
@classmethod
def _call(cls, fn, *args):
"""COM calls tend to randomly fail due to thread sync issues.
The Microsoft recommended solution is to set up a message filter object
to automatically retry failed calls, but this seems prohibitively hard
from python, so this is a custom solution to do the same thing.
All COM accesses should go through this function.
"""
ex = AssertionError("this should never be raised!")
assert (
inspect.isfunction(fn) or inspect.ismethod(fn) or inspect.isbuiltin(fn)
), (fn, type(fn))
retries = ([0] * 50) + ([1] * 5)
for r in retries:
try:
try:
result = fn(*args)
if inspect.ismethod(result) or "win32com" in str(result.__class__):
result = ComObject(result)
return result
except _com_error as e:
msg, _ = _handle_com_error(e)
e = WindowsError(msg) # pylint: disable=undefined-variable
raise e
except (AttributeError, TypeError, OSError) as e:
ex = e
time.sleep(r)
raise ex
class DTE(ComObject):
def __init__(self, class_string):
try:
super(DTE, self).__init__(com.DispatchEx(class_string))
except _com_error as e:
msg, exc = _handle_com_error(e)
raise LoadDebuggerException(
"{} [{}]".format(msg, class_string), orig_exception=exc
)