Skip to content

Commit a0e5037

Browse files
Make sure HANDLE on Windows has correct size
Previously, the type of various HANDLEs are native Python integer types. The ctypes library will treat them as 4-byte integer when used in function arguments. On 64-bit Windows, HANDLE is 8-byte and usually a small integer. Depending on whether the extra 4 bytes are zero-ed out or not, things can happen to work, or break. This patch adds explicit type casts so ctypes uses 8-byte integers for HANDLEs on 64-bit Windows. Thanks to @quark-zju for providing this patch to the 1.0 branch. This patch contains similar changes for the the 2.0 branch.
1 parent 2eb19a1 commit a0e5037

File tree

5 files changed

+33
-33
lines changed

5 files changed

+33
-33
lines changed

prompt_toolkit/eventloop/asyncio_win32.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ def __init__(self, loop=None):
3030
self.closed = False
3131

3232
# Maps win32 handles to their callbacks.
33-
self._handle_callbacks = {}
33+
self._handle_callbacks = {} # HANDLE fd to callback.
3434

3535
def close(self):
3636
# Note: we should not close the asyncio loop itself, because that one
@@ -90,7 +90,7 @@ def default_exception_handler(self, context):
9090
def add_win32_handle(self, handle, callback):
9191
" Add a Win32 handle to the event loop. "
9292
callback = wrap_in_current_context(callback)
93-
self._handle_callbacks[handle] = callback
93+
self._handle_callbacks[handle.value] = callback
9494

9595
# Add reader.
9696
def ready():
@@ -104,7 +104,7 @@ def ready():
104104
# (Use an executor for this, the Windows asyncio event loop doesn't
105105
# allow us to wait for handles like stdin.)
106106
def wait():
107-
if self._handle_callbacks.get(handle) != callback:
107+
if self._handle_callbacks.get(handle.value) != callback:
108108
return
109109

110110
wait_for_handles([handle])
@@ -114,5 +114,5 @@ def wait():
114114

115115
def remove_win32_handle(self, handle):
116116
" Remove a Win32 handle from the event loop. "
117-
if handle in self._handle_callbacks:
118-
del self._handle_callbacks[handle]
117+
if handle.value in self._handle_callbacks:
118+
del self._handle_callbacks[handle.value]

prompt_toolkit/eventloop/win32.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ def __init__(self, recognize_paste=True):
4141
self._running = False
4242

4343
# Additional readers.
44-
self._read_fds = {} # Maps fd to handler.
44+
self._read_fds = {} # Maps HANDLE value to handler.
4545

4646
# Create inputhook context.
4747
self._inputhook_context = None
@@ -86,9 +86,9 @@ def ready(wait):
8686
self._inputhook_context.call_inputhook(ready, inputhook)
8787

8888
# Wait for the next event.
89-
handle = self._ready_for_reading(INFINITE)
89+
handle = self._ready_for_reading(INFINITE).value
9090

91-
if handle == self._event:
91+
if handle == self._event.value:
9292
# When the Windows Event has been trigger, process the messages in the queue.
9393
windll.kernel32.ResetEvent(self._event)
9494
self._process_queued_calls_from_executor()
@@ -110,7 +110,7 @@ def _ready_for_reading(self, timeout=INFINITE):
110110
Return the handle that is ready for reading or `None` on timeout.
111111
"""
112112
handles = [self._event]
113-
handles.extend(self._read_fds.keys())
113+
handles.extend(HANDLE(fd) for fd in self._read_fds.keys())
114114
return wait_for_handles(handles, timeout)
115115

116116
def close(self):
@@ -161,23 +161,23 @@ def add_reader(self, fd, callback):
161161
" Start watching the file descriptor for read availability. "
162162
callback = wrap_in_current_context(callback)
163163

164-
h = msvcrt.get_osfhandle(fd)
164+
h = HANDLE(msvcrt.get_osfhandle(fd))
165165
self.add_win32_handle(h, callback)
166166

167167
def remove_reader(self, fd):
168168
" Stop watching the file descriptor for read availability. "
169-
h = msvcrt.get_osfhandle(fd)
169+
h = HANDLE(msvcrt.get_osfhandle(fd))
170170
self.remove_win32_handle(h)
171171

172172
def add_win32_handle(self, handle, callback):
173173
" Add a Win32 handle to the event loop. "
174174
callback = wrap_in_current_context(callback)
175-
self._read_fds[handle] = callback
175+
self._read_fds[handle.value] = callback
176176

177177
def remove_win32_handle(self, handle):
178178
" Remove a Win32 handle from the event loop. "
179-
if handle in self._read_fds:
180-
del self._read_fds[handle]
179+
if handle.value in self._read_fds:
180+
del self._read_fds[handle.value]
181181

182182

183183
def wait_for_handles(handles, timeout=INFINITE):
@@ -187,7 +187,7 @@ def wait_for_handles(handles, timeout=INFINITE):
187187
188188
http://msdn.microsoft.com/en-us/library/windows/desktop/ms687025(v=vs.85).aspx
189189
"""
190-
assert isinstance(handles, list)
190+
assert isinstance(handles, list) # List of `HANDLE` objects.
191191
assert isinstance(timeout, int)
192192

193193
arrtype = HANDLE * len(handles)
@@ -200,7 +200,7 @@ def wait_for_handles(handles, timeout=INFINITE):
200200
return None
201201
else:
202202
h = handle_array[ret]
203-
return h
203+
return HANDLE(h)
204204

205205

206206
def create_win32_event():
@@ -209,9 +209,9 @@ def create_win32_event():
209209
210210
http://msdn.microsoft.com/en-us/library/windows/desktop/ms682396(v=vs.85).aspx
211211
"""
212-
return windll.kernel32.CreateEventA(
212+
return HANDLE(windll.kernel32.CreateEventA(
213213
pointer(SECURITY_ATTRIBUTES()),
214214
BOOL(True), # Manual reset event.
215215
BOOL(False), # Initial state.
216216
None # Unnamed event object.
217-
)
217+
))

prompt_toolkit/input/win32.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import sys
66
from contextlib import contextmanager
77
from ctypes import pointer, windll
8-
from ctypes.wintypes import DWORD
8+
from ctypes.wintypes import DWORD, HANDLE
99

1010
import six
1111
from six.moves import range
@@ -181,10 +181,10 @@ def __init__(self, recognize_paste=True):
181181
# When stdin is a tty, use that handle, otherwise, create a handle from
182182
# CONIN$.
183183
if sys.stdin.isatty():
184-
self.handle = windll.kernel32.GetStdHandle(STD_INPUT_HANDLE)
184+
self.handle = HANDLE(windll.kernel32.GetStdHandle(STD_INPUT_HANDLE))
185185
else:
186186
self._fdcon = os.open('CONIN$', os.O_RDWR | os.O_BINARY)
187-
self.handle = msvcrt.get_osfhandle(self._fdcon)
187+
self.handle = HANDLE(msvcrt.get_osfhandle(self._fdcon))
188188

189189
def close(self):
190190
" Close fdcon. "
@@ -465,7 +465,7 @@ class raw_mode(object):
465465
`raw_input` method of `.vt100_input`.
466466
"""
467467
def __init__(self, fileno=None):
468-
self.handle = windll.kernel32.GetStdHandle(STD_INPUT_HANDLE)
468+
self.handle = HANDLE(windll.kernel32.GetStdHandle(STD_INPUT_HANDLE))
469469

470470
def __enter__(self):
471471
# Remember original mode.

prompt_toolkit/output/win32.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
pointer,
1212
windll,
1313
)
14-
from ctypes.wintypes import DWORD
14+
from ctypes.wintypes import DWORD, HANDLE
1515

1616
import six
1717

@@ -88,7 +88,7 @@ def __init__(self, stdout, use_complete_width=False):
8888

8989
self._buffer = []
9090
self.stdout = stdout
91-
self.hconsole = windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE)
91+
self.hconsole = HANDLE(windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE))
9292

9393
self._in_alternate_screen = False
9494
self._hidden = False
@@ -370,8 +370,8 @@ def enter_alternate_screen(self):
370370
GENERIC_WRITE = 0x40000000
371371

372372
# Create a new console buffer and activate that one.
373-
handle = self._winapi(windll.kernel32.CreateConsoleScreenBuffer, GENERIC_READ|GENERIC_WRITE,
374-
DWORD(0), None, DWORD(1), None)
373+
handle = HANDLE(self._winapi(windll.kernel32.CreateConsoleScreenBuffer, GENERIC_READ|GENERIC_WRITE,
374+
DWORD(0), None, DWORD(1), None))
375375

376376
self._winapi(windll.kernel32.SetConsoleActiveScreenBuffer, handle)
377377
self.hconsole = handle
@@ -382,23 +382,23 @@ def quit_alternate_screen(self):
382382
Make stdout again the active buffer.
383383
"""
384384
if self._in_alternate_screen:
385-
stdout = self._winapi(windll.kernel32.GetStdHandle, STD_OUTPUT_HANDLE)
385+
stdout = HANDLE(self._winapi(windll.kernel32.GetStdHandle, STD_OUTPUT_HANDLE))
386386
self._winapi(windll.kernel32.SetConsoleActiveScreenBuffer, stdout)
387387
self._winapi(windll.kernel32.CloseHandle, self.hconsole)
388388
self.hconsole = stdout
389389
self._in_alternate_screen = False
390390

391391
def enable_mouse_support(self):
392392
ENABLE_MOUSE_INPUT = 0x10
393-
handle = windll.kernel32.GetStdHandle(STD_INPUT_HANDLE)
393+
handle = HANDLE(windll.kernel32.GetStdHandle(STD_INPUT_HANDLE))
394394

395395
original_mode = DWORD()
396396
self._winapi(windll.kernel32.GetConsoleMode, handle, pointer(original_mode))
397397
self._winapi(windll.kernel32.SetConsoleMode, handle, original_mode.value | ENABLE_MOUSE_INPUT)
398398

399399
def disable_mouse_support(self):
400400
ENABLE_MOUSE_INPUT = 0x10
401-
handle = windll.kernel32.GetStdHandle(STD_INPUT_HANDLE)
401+
handle = HANDLE(windll.kernel32.GetStdHandle(STD_INPUT_HANDLE))
402402

403403
original_mode = DWORD()
404404
self._winapi(windll.kernel32.GetConsoleMode, handle, pointer(original_mode))
@@ -420,7 +420,7 @@ def win32_refresh_window(cls):
420420
to a bug in the Windows Console. Sending a repaint request solves it.
421421
"""
422422
# Get console handle
423-
handle = windll.kernel32.GetConsoleWindow()
423+
handle = HANDLE(windll.kernel32.GetConsoleWindow())
424424

425425
RDW_INVALIDATE = 0x0001
426426
windll.user32.RedrawWindow(handle, None, None, c_uint(RDW_INVALIDATE))

prompt_toolkit/output/windows10.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from __future__ import unicode_literals
22

33
from ctypes import byref, windll
4-
from ctypes.wintypes import DWORD
4+
from ctypes.wintypes import DWORD, HANDLE
55

66
from prompt_toolkit.renderer import Output
77
from prompt_toolkit.utils import is_windows
@@ -26,7 +26,7 @@ class Windows10_Output(object):
2626
def __init__(self, stdout):
2727
self.win32_output = Win32Output(stdout)
2828
self.vt100_output = Vt100_Output(stdout, lambda: None)
29-
self._hconsole = windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE)
29+
self._hconsole = HANDLE(windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE))
3030

3131
def flush(self):
3232
"""
@@ -68,7 +68,7 @@ def is_win_vt100_enabled():
6868
if not is_windows():
6969
return False
7070

71-
hconsole = windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE)
71+
hconsole = HANDLE(windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE))
7272

7373
# Get original console mode.
7474
original_mode = DWORD(0)

0 commit comments

Comments
 (0)