Fix Win32 ctypes issues: wintypes aliases, DrawTextW belongs to user32, drop FillRect (use class brush), NULL ptr for EnumDisplayMonitors

Verified on Windows: module imports and enum_monitor_rects() returns correct
device-coordinate monitor rects.
This commit is contained in:
Hermes Agent committed 2026-09-16 16:28:23 +02:00
1 parent 0e88bf62f5
commit d6e83565c1
1 file changed
+27 -30
+27 -30
View File
@@ -104,11 +104,18 @@ if sys.platform == "win32":
TRANSPARENT = 1 TRANSPARENT = 1
DEFAULT_GUI_FONT = 17 DEFAULT_GUI_FONT = 17
WNDPROC = ctypes.WINFUNCTYPE(wt.LRESULT, wt.HWND, wt.UINT, wt.WPARAM, wt.LPARAM) LRESULT = ctypes.c_int64
HMONITOR = ctypes.c_void_p
HHOOK = ctypes.c_void_p
HCURSOR = ctypes.c_void_p
ULONG_PTR = ctypes.c_void_p
UINT_PTR = ctypes.c_void_p
WNDPROC = ctypes.WINFUNCTYPE(LRESULT, wt.HWND, wt.UINT, wt.WPARAM, wt.LPARAM)
MONITORENUMPROC = ctypes.WINFUNCTYPE( MONITORENUMPROC = ctypes.WINFUNCTYPE(
wt.BOOL, wt.HMONITOR, wt.HDC, ctypes.POINTER(wt.RECT), wt.LPARAM wt.BOOL, HMONITOR, wt.HDC, ctypes.POINTER(wt.RECT), wt.LPARAM
) )
HOOKPROC = ctypes.WINFUNCTYPE(wt.LRESULT, ctypes.c_int, wt.WPARAM, wt.LPARAM) HOOKPROC = ctypes.WINFUNCTYPE(LRESULT, ctypes.c_int, wt.WPARAM, wt.LPARAM)
class WNDCLASSEXW(ctypes.Structure): class WNDCLASSEXW(ctypes.Structure):
_fields_ = [ _fields_ = [
@@ -119,7 +126,7 @@ if sys.platform == "win32":
("cbWndExtra", wt.INT), ("cbWndExtra", wt.INT),
("hInstance", wt.HINSTANCE), ("hInstance", wt.HINSTANCE),
("hIcon", wt.HICON), ("hIcon", wt.HICON),
("hCursor", wt.HCURSOR), ("hCursor", HCURSOR),
("hbrBackground", wt.HBRUSH), ("hbrBackground", wt.HBRUSH),
("lpszMenuName", wt.LPCWSTR), ("lpszMenuName", wt.LPCWSTR),
("lpszClassName", wt.LPCWSTR), ("lpszClassName", wt.LPCWSTR),
@@ -142,7 +149,7 @@ if sys.platform == "win32":
("scanCode", wt.DWORD), ("scanCode", wt.DWORD),
("flags", wt.DWORD), ("flags", wt.DWORD),
("time", wt.DWORD), ("time", wt.DWORD),
("dwExtraInfo", wt.ULONG_PTR), ("dwExtraInfo", ULONG_PTR),
] ]
# --- prototypes (64-bit safe) --- # --- prototypes (64-bit safe) ---
@@ -161,9 +168,9 @@ if sys.platform == "win32":
user32.UpdateWindow.restype = wt.BOOL user32.UpdateWindow.restype = wt.BOOL
user32.SetWindowPos.argtypes = [wt.HWND, wt.HWND, wt.INT, wt.INT, wt.INT, wt.INT, wt.UINT] user32.SetWindowPos.argtypes = [wt.HWND, wt.HWND, wt.INT, wt.INT, wt.INT, wt.INT, wt.UINT]
user32.SetWindowPos.restype = wt.BOOL user32.SetWindowPos.restype = wt.BOOL
user32.SetTimer.argtypes = [wt.HWND, wt.UINT_PTR, wt.UINT, ctypes.c_void_p] user32.SetTimer.argtypes = [wt.HWND, UINT_PTR, wt.UINT, ctypes.c_void_p]
user32.SetTimer.restype = wt.UINT_PTR user32.SetTimer.restype = UINT_PTR
user32.KillTimer.argtypes = [wt.HWND, wt.UINT_PTR] user32.KillTimer.argtypes = [wt.HWND, UINT_PTR]
user32.KillTimer.restype = wt.BOOL user32.KillTimer.restype = wt.BOOL
user32.GetClientRect.argtypes = [wt.HWND, ctypes.POINTER(wt.RECT)] user32.GetClientRect.argtypes = [wt.HWND, ctypes.POINTER(wt.RECT)]
user32.GetClientRect.restype = wt.BOOL user32.GetClientRect.restype = wt.BOOL
@@ -182,24 +189,20 @@ if sys.platform == "win32":
user32.DispatchMessageW.argtypes = [ctypes.POINTER(wt.MSG)] user32.DispatchMessageW.argtypes = [ctypes.POINTER(wt.MSG)]
user32.DispatchMessageW.restype = wt.LONG user32.DispatchMessageW.restype = wt.LONG
user32.SetWindowsHookExW.argtypes = [wt.INT, HOOKPROC, wt.HINSTANCE, wt.DWORD] user32.SetWindowsHookExW.argtypes = [wt.INT, HOOKPROC, wt.HINSTANCE, wt.DWORD]
user32.SetWindowsHookExW.restype = wt.HHOOK user32.SetWindowsHookExW.restype = HHOOK
user32.CallNextHookEx.argtypes = [wt.HHOOK, ctypes.c_int, wt.WPARAM, wt.LPARAM] user32.CallNextHookEx.argtypes = [HHOOK, ctypes.c_int, wt.WPARAM, wt.LPARAM]
user32.CallNextHookEx.restype = wt.LRESULT user32.CallNextHookEx.restype = LRESULT
user32.UnhookWindowsHookEx.argtypes = [wt.HHOOK] user32.UnhookWindowsHookEx.argtypes = [HHOOK]
user32.UnhookWindowsHookEx.restype = wt.BOOL user32.UnhookWindowsHookEx.restype = wt.BOOL
user32.DestroyWindow.argtypes = [wt.HWND] user32.DestroyWindow.argtypes = [wt.HWND]
user32.DestroyWindow.restype = wt.BOOL user32.DestroyWindow.restype = wt.BOOL
user32.ShowCursor.argtypes = [wt.BOOL] user32.ShowCursor.argtypes = [wt.BOOL]
user32.ShowCursor.restype = wt.INT user32.ShowCursor.restype = wt.INT
user32.DefWindowProcW.argtypes = [wt.HWND, wt.UINT, wt.WPARAM, wt.LPARAM] user32.DefWindowProcW.argtypes = [wt.HWND, wt.UINT, wt.WPARAM, wt.LPARAM]
user32.DefWindowProcW.restype = wt.LRESULT user32.DefWindowProcW.restype = LRESULT
user32.SetProcessDPIAware.argtypes = [] user32.SetProcessDPIAware.argtypes = []
user32.SetProcessDPIAware.restype = wt.BOOL user32.SetProcessDPIAware.restype = wt.BOOL
gdi32.CreateSolidBrush.argtypes = [wt.COLORREF] gdi32.CreateSolidBrush.argtypes = [wt.COLORREF]
gdi32.CreateSolidBrush.restype = wt.HBRUSH
gdi32.FillRect.argtypes = [wt.HDC, ctypes.POINTER(wt.RECT), wt.HBRUSH]
gdi32.FillRect.restype = wt.INT
gdi32.DeleteObject.argtypes = [wt.HGDIOBJ]
gdi32.DeleteObject.restype = wt.BOOL gdi32.DeleteObject.restype = wt.BOOL
gdi32.SetTextColor.argtypes = [wt.HDC, wt.COLORREF] gdi32.SetTextColor.argtypes = [wt.HDC, wt.COLORREF]
gdi32.SetTextColor.restype = wt.COLORREF gdi32.SetTextColor.restype = wt.COLORREF
@@ -209,8 +212,8 @@ if sys.platform == "win32":
gdi32.GetStockObject.restype = wt.HGDIOBJ gdi32.GetStockObject.restype = wt.HGDIOBJ
gdi32.SelectObject.argtypes = [wt.HDC, wt.HGDIOBJ] gdi32.SelectObject.argtypes = [wt.HDC, wt.HGDIOBJ]
gdi32.SelectObject.restype = wt.HGDIOBJ gdi32.SelectObject.restype = wt.HGDIOBJ
gdi32.DrawTextW.argtypes = [wt.HDC, wt.LPCWSTR, wt.INT, ctypes.POINTER(wt.RECT), wt.UINT] user32.DrawTextW.argtypes = [wt.HDC, wt.LPCWSTR, wt.INT, ctypes.POINTER(wt.RECT), wt.UINT]
gdi32.DrawTextW.restype = wt.INT user32.DrawTextW.restype = wt.INT
kernel32.GetModuleHandleW.argtypes = [wt.LPCWSTR] kernel32.GetModuleHandleW.argtypes = [wt.LPCWSTR]
kernel32.GetModuleHandleW.restype = wt.HINSTANCE kernel32.GetModuleHandleW.restype = wt.HINSTANCE
kernel32.GetLastError.argtypes = [] kernel32.GetLastError.argtypes = []
@@ -229,28 +232,23 @@ if sys.platform == "win32":
rects.append((r.left, r.top, r.right, r.bottom)) rects.append((r.left, r.top, r.right, r.bottom))
return True return True
user32.EnumDisplayMonitors(0, 0, MONITORENUMPROC(cb), 0) user32.EnumDisplayMonitors(None, None, MONITORENUMPROC(cb), 0)
return rects return rects
def _wndproc(hwnd, msg, wparam, lparam): def _wndproc(hwnd, msg, wparam, lparam):
if msg == WM_ERASEBKGND: global _hint_active
return 1
if msg == WM_PAINT: if msg == WM_PAINT:
# Background (black) is erased by DefWindowProc via the class brush.
ps = PAINTSTRUCT() ps = PAINTSTRUCT()
hdc = user32.BeginPaint(hwnd, ctypes.byref(ps)) hdc = user32.BeginPaint(hwnd, ctypes.byref(ps))
rect = wt.RECT()
user32.GetClientRect(hwnd, ctypes.byref(rect))
brush = gdi32.CreateSolidBrush(0x000000)
gdi32.FillRect(hdc, ctypes.byref(rect), brush)
gdi32.DeleteObject(brush)
if _hint_active: if _hint_active:
gdi32.SetTextColor(hdc, 0xFFFFFF) gdi32.SetTextColor(hdc, 0xFFFFFF)
gdi32.SetBkMode(hdc, TRANSPARENT) gdi32.SetBkMode(hdc, TRANSPARENT)
font = gdi32.GetStockObject(DEFAULT_GUI_FONT) font = gdi32.GetStockObject(DEFAULT_GUI_FONT)
old = gdi32.SelectObject(hdc, font) old = gdi32.SelectObject(hdc, font)
buf = ctypes.create_unicode_buffer(_hint_text) buf = ctypes.create_unicode_buffer(_hint_text)
gdi32.DrawTextW( user32.DrawTextW(
hdc, buf, -1, ctypes.byref(rect), hdc, buf, -1, ctypes.byref(ps.rcPaint),
DT_CENTER | DT_VCENTER | DT_SINGLELINE, DT_CENTER | DT_VCENTER | DT_SINGLELINE,
) )
if old: if old:
@@ -258,7 +256,6 @@ if sys.platform == "win32":
user32.EndPaint(hwnd, ctypes.byref(ps)) user32.EndPaint(hwnd, ctypes.byref(ps))
return 0 return 0
if msg == WM_TIMER: if msg == WM_TIMER:
global _hint_active
_hint_active = False _hint_active = False
user32.KillTimer(hwnd, 1) user32.KillTimer(hwnd, 1)
for h in _hwnds: for h in _hwnds: