-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
Importing pyautogui breaks monitor DPI detection with ctypes #663
Comments
Here's something related: """
QtWarningMsg:
setProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) failed:
COM error 0x5 (Access is denied.)
"""
import pyautogui # noqa # pylint:disable=unused-import
from PySide6.QtWidgets import QApplication
QApplication() It outputs the warning
According to MS docs,
https://learn.microsoft.com/th-th/windows/win32/api/winuser/nf-winuser-setprocessdpiawarenesscontext So it seems pyautogui/pyautogui/_pyautogui_win.py Lines 14 to 18 in ad7609c
I am considering monkey-patching |
Here's a workaround: """Workaround."""
import ctypes
import pytest
from PySide6.QtWidgets import QApplication
with pytest.MonkeyPatch.context() as mp:
mp.setattr(ctypes.windll.user32, "SetProcessDPIAware", lambda: None)
import pyautogui # noqa # pylint:disable=unused-import
QApplication() |
Much nicer workaround with the standard library: """Workaround."""
from unittest.mock import patch
from PySide6.QtWidgets import QApplication
with patch("ctypes.windll.user32.SetProcessDPIAware", autospec=True):
import pyautogui # noqa # pylint:disable=unused-import
QApplication() |
Importantly, that Qt warning message will go away: This will solve my issue (and make my patch pointless), but it will not solve @GeorgeWashingtonABCDEFG's issue (for which my patch may still be useful). In the end, |
Related: 9cd04d3 |
asweigart/pyautogui#663 Better patch for pyautogui DPI
The unittest workaround significantly increases build time, boot time and build size with PyInstaller. So I went with some sort of postinstall powershell script that patches all offending libraries, and uninstalls those I don't actually need. # Prevent pyautogui and pywinctl from setting Process DPI Awareness, which Qt tries to do then throws warnings about it.
# The unittest workaround significantly increases build time, boot time and build size with PyInstaller.
# https://github.com/asweigart/pyautogui/issues/663#issuecomment-1296719464
$libPath = python -c 'import pyautogui as _; print(_.__path__[0])'
(Get-Content "$libPath/_pyautogui_win.py").replace('ctypes.windll.user32.SetProcessDPIAware()', 'pass') |
Set-Content "$libPath/_pyautogui_win.py"
$libPath = python -c 'import pymonctl as _; print(_.__path__[0])'
(Get-Content "$libPath/_pymonctl_win.py").replace('ctypes.windll.shcore.SetProcessDpiAwareness', 'pass # ') |
Set-Content "$libPath/_pymonctl_win.py"
$libPath = python -c 'import pywinbox as _; print(_.__path__[0])'
(Get-Content "$libPath/_pywinbox_win.py").replace('ctypes.windll.shcore.SetProcessDpiAwareness', 'pass # ') |
Set-Content "$libPath/_pywinbox_win.py"
# Uninstall optional dependencies that PyInstaller picks up
python -m pip uninstall pyscreeze mouseinfo pyperclip -y To find where it's called in the first place, I simply added the following at the top of my main/entrypoint module: # flake8: noqa
def find_culprit(*_):
raise Exception
import ctypes
ctypes.windll.shcore.SetProcessDpiAwareness = find_culprit
ctypes.windll.user32.SetProcessDPIAware = find_culprit |
I think I found an even better workaround. This is what I'm using now. If you did need import sys
# Prevent PyAutoGUI and pywinctl from setting Process DPI Awareness, which Qt tries to do then throws warnings about it.
# The unittest workaround significantly increases build time, boot time and build size with PyInstaller.
# https://github.com/asweigart/pyautogui/issues/663#issuecomment-1296719464
# QT doesn't call those from Python/ctypes, meaning we can stop other programs from setting it.
if sys.platform == "win32":
import ctypes
# pyautogui._pyautogui_win.py
ctypes.windll.user32.SetProcessDPIAware = lambda: None # pyright: ignore[reportAttributeAccessIssue]
# pymonctl._pymonctl_win.py
# pywinbox._pywinbox_win.py
ctypes.windll.shcore.SetProcessDpiAwareness = ( # pyright: ignore[reportAttributeAccessIssue]
lambda _: None # pyright: ignore[reportUnknownLambdaType]
) |
The text was updated successfully, but these errors were encountered: