1from ctypes import pointer
2
3from ..utils import SPHINX_AUTODOC_RUNNING
4
5# Do not import win32-specific stuff when generating documentation.
6# Otherwise RTD would be unable to generate docs for this module.
7if not SPHINX_AUTODOC_RUNNING:
8    from ctypes import windll
9
10from ctypes.wintypes import BOOL, DWORD, HANDLE
11from typing import List, Optional
12
13from prompt_toolkit.win32_types import SECURITY_ATTRIBUTES
14
15__all__ = ["wait_for_handles", "create_win32_event"]
16
17
18WAIT_TIMEOUT = 0x00000102
19INFINITE = -1
20
21
22def wait_for_handles(
23    handles: List[HANDLE], timeout: int = INFINITE
24) -> Optional[HANDLE]:
25    """
26    Waits for multiple handles. (Similar to 'select') Returns the handle which is ready.
27    Returns `None` on timeout.
28    http://msdn.microsoft.com/en-us/library/windows/desktop/ms687025(v=vs.85).aspx
29
30    Note that handles should be a list of `HANDLE` objects, not integers. See
31    this comment in the patch by @quark-zju for the reason why:
32
33        ''' Make sure HANDLE on Windows has a correct size
34
35        Previously, the type of various HANDLEs are native Python integer
36        types. The ctypes library will treat them as 4-byte integer when used
37        in function arguments. On 64-bit Windows, HANDLE is 8-byte and usually
38        a small integer. Depending on whether the extra 4 bytes are zero-ed out
39        or not, things can happen to work, or break. '''
40
41    This function returns either `None` or one of the given `HANDLE` objects.
42    (The return value can be tested with the `is` operator.)
43    """
44    arrtype = HANDLE * len(handles)
45    handle_array = arrtype(*handles)
46
47    ret: int = windll.kernel32.WaitForMultipleObjects(
48        len(handle_array), handle_array, BOOL(False), DWORD(timeout)
49    )
50
51    if ret == WAIT_TIMEOUT:
52        return None
53    else:
54        return handles[ret]
55
56
57def create_win32_event() -> HANDLE:
58    """
59    Creates a Win32 unnamed Event .
60    http://msdn.microsoft.com/en-us/library/windows/desktop/ms682396(v=vs.85).aspx
61    """
62    return HANDLE(
63        windll.kernel32.CreateEventA(
64            pointer(SECURITY_ATTRIBUTES()),
65            BOOL(True),  # Manual reset event.
66            BOOL(False),  # Initial state.
67            None,  # Unnamed event object.
68        )
69    )
70