I have written an application in python 3.6 and would like to run a command to see what the current scaling for a monitor is in Windows 10 or 8 - something like how the following returns screen resolution:
user32 = ctypes.windll.user32
screensize_l = user32.GetSystemMetrics(0)
screensize_w = user32.GetSystemMetrics(1)
I understand that the easiest way to do this may be to make my application DPI aware, but doing so causes lots of additional problems in my application - so I would like to avoid this option.
I have looked in the windows documentation and thought "GetDpiForMonitor" or "GetScaleFactorForMonitor" may be what I am looking for, but don't know how to implement these commands.
I already use both win32api and ctypes so anything relying on either of these would be fine - any help would be greatly appreciated!
On Windows 10, the following code (you need pywin32
):
import ctypes
import win32api
PROCESS_PER_MONITOR_DPI_AWARE = 2
MDT_EFFECTIVE_DPI = 0
def print_dpi():
shcore = ctypes.windll.shcore
monitors = win32api.EnumDisplayMonitors()
hresult = shcore.SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE)
assert hresult == 0
dpiX = ctypes.c_uint()
dpiY = ctypes.c_uint()
for i, monitor in enumerate(monitors):
shcore.GetDpiForMonitor(
monitor[0].handle,
MDT_EFFECTIVE_DPI,
ctypes.byref(dpiX),
ctypes.byref(dpiY)
)
print(
f"Monitor {i} (hmonitor: {monitor[0]}) = dpiX: {dpiX.value}, dpiY: {dpiY.value}"
)
if __name__ == "__main__":
print_dpi()
gives the following output on my machine with 3 monitors and 1 scaled to 125%:
Monitor 0 (hmonitor: <PyHANDLE:65539>) = dpiX: 96, dpiY: 96
Monitor 1 (hmonitor: <PyHANDLE:65537>) = dpiX: 120, dpiY: 120
Monitor 2 (hmonitor: <PyHANDLE:65541>) = dpiX: 96, dpiY: 96
If you do not want to set your own application as a dpi-aware per monitor, you could try launching some variant of the above code in another process using the multiprocessing
module and retrieve the results.
hope this helps.