Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Methods to bridge the gap between Integer error codes and HRESULT values represented as signed 32-bit hexadecimal #665

Open
junkmd opened this issue Nov 16, 2024 · 0 comments
Labels
enhancement New feature or request shared_info use cases, tips and troubleshoots

Comments

@junkmd
Copy link
Collaborator

junkmd commented Nov 16, 2024

New users of this package may find themselves deeply confused when encountering a COMError.

COMError is an exception defined in the ctypes internal implementation, _ctypes, and is part of the Python standard library. However, it remained undocumented for many years. To address this, I opened an issue and submitted a pull request to add documentation for this error to the official Python documentation.

Another problem with COMError is that most COM references typically represent error codes as signed 32-bit hexadecimal values, like the ones below, while the error code assigned to its hresult attribute is an int, making them less 'googlable'.

Additionally, converting between signed 32-bit hexadecimal strings and integer values requires some extra effort.
For instance, when I was less familiar with HRESULT, I mistakenly tried to derive the integer value for E_NOINTERFACE using int("0x80004002", 16).

To handle these conversions properly, a utility function like the following is necessary:

def signed32bithex_to_int(value: str, /) -> int:
    """
    Examples:

        >>> from comtypes import hresult as hr
        >>> signed32bithex_to_int('0x00000000') == hr.S_OK
        True
        >>> signed32bithex_to_int('0x00000001') == hr.S_FALSE
        True
        >>> signed32bithex_to_int('0x8000FFFF') == hr.E_UNEXPECTED
        True
    """
    val = int(value, 16)
    if val < 0x80000000:
        return val
    return val - 0x100000000


def int_to_signed32bithex(value: int, /) -> str:
    """
    Examples:

        >>> import comtypes.hresult as hr
        >>> int_to_signed32bithex(hr.S_OK)
        '0x00000000'
        >>> int_to_signed32bithex(hr.S_FALSE)
        '0x00000001'
        >>> int_to_signed32bithex(hr.E_UNEXPECTED)
        '0x8000FFFF'

        >>> from comtypes import CoCreateInstance
        >>> from comtypes import shelllink, automation
        >>> CLSID_ShellLink = shelllink.ShellLink().IPersist_GetClassID()
        >>> p = CoCreateInstance(CLSID_ShellLink)
        >>> p.QueryInterface(shelllink.IShellLinkA)  # doctest: +ELLIPSIS
        <POINTER(IShellLinkA) ptr=0x... at ...>
        >>> p.QueryInterface(automation.IDispatch)  # doctest: +ELLIPSIS
        Traceback (most recent call last):
            ...
        _ctypes.COMError: (-2147467262, ..., (None, None, None, 0, None))
        >>> int_to_signed32bithex(-2147467262)  # E_NOINTERFACE
        '0x80004002'
    """
    # it is simpler than using `hex(value & 0xFFFFFFFF)`
    return f"0x{value & 0xFFFFFFFF:08X}"

For example, let’s consider the case where you encounter an COMError: (-2146233083, ..., ...).
Searching for -2146233083 alone will primarily return information about COR_E_TIMEOUT, which is related to .NET.
However, searching for "0x80131505", which can be derived using int_to_signed32bithex(-2146233083), makes it easier to find information about UIA_E_TIMEOUT, which is related to UIAutomation.

I am considering adding such a function to comtypes/hresult.py with appropriate docstrings.
Doing so will likely reduce the number of inquiries related to error handling in the future, preventing burnout among the community and maintainers.

@junkmd junkmd added enhancement New feature or request shared_info use cases, tips and troubleshoots labels Nov 16, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request shared_info use cases, tips and troubleshoots
Projects
None yet
Development

No branches or pull requests

1 participant