GetDpiForMonitor does not work properly. Because PB does not support DPI scaling per monitor.
For example, if the main monitor is 100% and the second monitor is 125%, GetDpiForMonitor always returns 100%.
To use GetDpiForMonitor, you must turn off DPI awareness in the compiler settings and force the process to set DPI scaling per monitor.
The code below seems to work well on Windows 10. It's not tested on other versions of Windows.
Turn off DPI awareness in compiler settings and run.
Code: Select all
#PROCESS_DPI_UNAWARE = 0
#PROCESS_SYSTEM_DPI_AWARE = 1
#PROCESS_PER_MONITOR_DPI_AWARE = 2
#DPI_AWARENESS_CONTEXT = 0
#DPI_AWARENESS_CONTEXT_UNAWARE = #DPI_AWARENESS_CONTEXT - 1
#DPI_AWARENESS_CONTEXT_SYSTEM_AWARE = #DPI_AWARENESS_CONTEXT - 2
#DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE = #DPI_AWARENESS_CONTEXT - 3
#DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 = #DPI_AWARENESS_CONTEXT - 4
;Return value: 1507, 1511, 1607, 1703, 1709, 1803, 1809, 1903, 1909, 2004, 2009(20H2) etc.
Procedure.s GetWindowReleaseID()
Protected Buffer.s{16}, Type = #REG_SZ, Size = 15
If OSVersion() >= #PB_OS_Windows_10
If SHGetValue_(#HKEY_LOCAL_MACHINE, "SOFTWARE\Microsoft\Windows NT\CurrentVersion", "ReleaseID", @Type, @Buffer, @Size) = #ERROR_SUCCESS
ProcedureReturn Buffer
EndIf
EndIf
ProcedureReturn ""
EndProcedure
Procedure MonitorEnumProc(hMonitor, hDC, *Rect, lParam)
Protected DpiX, DpiY
Protected LibShcore = OpenLibrary(#PB_Any, "Shcore.dll")
If LibShcore
If hMonitor
If CallFunction(LibShcore, "GetDpiForMonitor", hMonitor, #MDT_EFFECTIVE_DPI, @DpiX, @DpiY) = #S_OK
Debug "DPI: x= " + DpiX + " , y= " + DpiY
Debug "Scaling factor: x= " + StrD(DpiX/96) + " , y= " + StrD(DpiY/96)
Debug "-------------------------------------------"
EndIf
EndIf
CloseLibrary(LibShcore)
EndIf
ProcedureReturn #True
EndProcedure
Procedure GetDPImonitors()
Protected LibShcore = OpenLibrary(#PB_Any, "Shcore.dll")
Protected LibUser32 = OpenLibrary(#PB_Any, "User32.dll")
Protected hDC, Awareness, Result, OS = OSVersion()
Protected rlsid = Val(Left(GetWindowReleaseID(), 2))
If OS >= #PB_OS_Windows_8_1
If CallFunction(LibShcore, "GetProcessDpiAwareness", GetCurrentProcess_(), @Awareness) = #S_OK
If Awareness = #PROCESS_DPI_UNAWARE
If (OS = #PB_OS_Windows_10 And rlsid >= 17) Or OS = #PB_OS_Windows_Future ; OS >= #PB_OS_Windows_11
If CallFunction(LibUser32, "SetProcessDpiAwarenessContext", #DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2)
Debug "Windows 10 1703+"
EnumDisplayMonitors_(0, 0, @MonitorEnumProc(), 0)
CallFunction(LibUser32, "SetProcessDpiAwarenessContext", #DPI_AWARENESS_CONTEXT_UNAWARE)
Result = 1
;Else
; If GetLastError_() = #ERROR_ACCESS_DENIED
; Debug "System DPI awareness is applied. Cannot change."
; EndIf
EndIf
Else
; If OS = #PB_OS_Windows_10 And rlsid = 16
; CallFunction(LibUser32, "SetProcessDpiAwarenessContext", #DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE)
; ......
; CallFunction(LibUser32, "SetProcessDpiAwarenessContext", #DPI_AWARENESS_CONTEXT_UNAWARE)
; If OS < #PB_OS_Windows_10 Or (OS = #PB_OS_Windows_10 And rlsid < 16)
If CallFunction(LibShcore, "SetProcessDpiAwareness", #PROCESS_PER_MONITOR_DPI_AWARE) = #S_OK
EnumDisplayMonitors_(0, 0, @MonitorEnumProc(), 0)
CallFunction(LibShcore, "SetProcessDpiAwareness", #PROCESS_DPI_UNAWARE)
Result = 1
;Else
; Debug "System DPI awareness is applied. Cannot change."
EndIf
EndIf
Else ;PB System DPI awareness.
EnumDisplayMonitors_(0, 0, @MonitorEnumProc(), 0)
Result = 1
EndIf
EndIf
EndIf
If Result = 0
hDC = GetDC_(0)
If hDC
Debug GetDeviceCaps_(hDC, #LOGPIXELSX) / 96.0
Debug GetDeviceCaps_(hDC, #LOGPIXELSY) / 96.0
ReleaseDC_(0, hDC)
EndIf
EndIf
If LibShcore : CloseLibrary(LibShcore) : EndIf
If LibUser32 : CloseLibrary(LibUser32) : EndIf
EndProcedure
GetDPImonitors()
Windows 10 1703+
DPI: x= 96 , y= 96
Scaling factor: x= 1 , y= 1
-------------------------------------------
DPI: x= 120 , y= 120
Scaling factor: x= 1.25 , y= 1.25
-------------------------------------------