DPI-scaled windows

On Windows Vista and later, in Control Panel -> Display you can make text and other items in all windows bigger (125%, 150%...). Let's call it DPI scaling. When DPI scaling is not 100% and not using XP-style scaling, some windows are stretched and look a little blurry. Let's call these windows DPI-scaled windows.

 

DPI-scaled windows is a problem for automation programs like QM. QM solves most of these problems in its internal functions. This topic is about problems that you may still have with DPI-scaled windows.

 

Windows Vista, 7 and 8.0

On these OS, with DPI-scaled windows Windows API functions use coordinates of non-scaled window, and they are smaller than the window view that you see. These coordinates are called logical. The scaled/stretched view is in physical coordinates.

 

QM 2.3.6 and later with DPI-scaled windows uses physical coordinates (what you see), and it works well. Older QM versions used logical coordinates in most cases, and it did not work well. If in older QM you have created macros that use logical coordinates (x, y, width, height) in DPI-scaled windows, in new QM these macros will not work. Need to replace logical coordinates with physical.

 

If in macros you use Windows API functions, and want to make the macros work well with DPI-scaled windows, replace the API functions with similar QM functions. Note that QM dialogs and other QM windows cannot be DPI-scaled, therefore you can safely use Windows API functions with them.

 

Windows API function QM function
GetCursorPos xm
GetWindowRect, GetClientRect DpiGetWindowRect
ScreenToClient DpiScreenToClient
ClientToScreen DpiClientToScreen
MapWindowPoints DpiMapWindowPoints
MoveWindow, SetWindowPos mov, siz

 

Windows 8.1 and 10

On these OS, most Windows API functions use physical coordinates with all windows. Therefore the above QM functions (DpiGetWindowRect etc) on these OS don't convert physical/logical coordinates. You can still use them to make your code work well on all OS.

 

QM has problems with DPI-scaled windows on these OS:

 

You can disable DPI scaling for a program in its file Properties dialog, Compatibility tab. To disable for all programs, in Control Panel -> Display check "...one scaling..." and choose 125%. On older OS - check XP-style.

 

QM DpiX functions

Added in QM 2.3.6. The functions work with all windows. They use physical coordinates (what you see) with all windows.

 


#DpiIsWindowScaled hwnd ;;if hwnd 1, gets is scaling enabled

 

Returns 1 if window is DPI-scaled, 0 if not.

 

hwnd - window handle. If hwnd is 1, returns 1 if DPI scaling is enabled, 0 if not.

 

Often this function is used like this: if(DpiIsWindowScaled(w)) ... DpiScale(...). You may want to disable such code on Windows 8.1 and later, if related Windows API functions on these OS use physical coordinates. Use code like this: if(_winver<0x603 and DpiIsWindowScaled(w)) ... DpiScale(...). What is _winver and 0x603.

 


#DpiGetWindowRect hwnd RECT*r [flags] ;;flags: 4 client, 8 client in screen

 

Gets window rectangle in screen, or window client area rectangle, or window client area rectangle in screen.

 

hwnd - window handle.

r - address of variable that receives physical rectangle coordinates.

 

Returns 2 if the window is DPI-scaled, 1 if not, 0 if failed.

 


#DpiClientToScreen hwnd POINT*p [flags] ;;flags: 16 window, 0x100 RECT
#DpiScreenToClient hwnd POINT*p [flags] ;;flags: 16 window, 0x100 RECT

 

Converts point coordinates in window client area to coordinates in screen, and vice versa.

If flag 16, converts point coordinates in window to coordinates in screen, and vice versa.

 

hwnd - window handle.

p - address of variable that contains physical point coordinates.

 

Returns 2 if the window is DPI-scaled, 1 if not, 0 if failed.

 


DpiMapWindowPoints hwnd1 hwnd2 POINT*p n [flags]

 

Converts coordinates of n points from client area of one window to client area of another window.

 

hwnd1 - handle of window where coordinates are before calling this function. Screen if 0.

hwnd2 - handle of window where coordinates are after calling this function. Screen if 0.

p - address of one or more POINT or RECT variables that contain physical coordinates.

n - number of points to convert. Must be 1 if p is address of single POINT variable. Must be 2 if p is address of single RECT variable, like +&r.

 


DpiScale POINT*p n ;;n: >0 scale, <0 unscale

 

Converts coordinates of one or more points from logical to physical or vice versa.

 

p - address of one or more POINT or RECT variables that contain coordinates.

n - number of points to convert. Must be 1 if p is address of single POINT variable. Must be 2 if p is address of single RECT variable, like +&r. If n is negative, converts from physical to logical.

 

This function simply multiplies coordinates. For example, if text size is 125% and p.x is 100, the function makes it 125 if n>0, or 80 if n<0. Works always, regardless of system DPI settings and version.

 

On Windows 8.1 and later, multiple monitors can have different DPI. This function uses DPI of the primary monitor.

 


#DpiGetDPI

 

Returns text size in DPI (dots-per-inch). Text size 100% is 96 DPI, 125% is 120 DPI, and so on. Works even if text size is 100% or using XP style scaling.

 

On Windows 8.1 and later, multiple monitors can have different DPI. This function gets DPI of the primary monitor. To get DPI of any monitor, use Windows API GetDpiForMonitor.

 


With all functions that have flags parameter, can be used flag 1 if you know the window is not DPI-scaled, and 2 if DPI-scaled. It makes the function faster.