Important tip: getting the desktop resolution
Important tip: getting the desktop resolution
Just discovered this weird issue (bug?) with the GetSystemMetrics_() API on Windows.
My PC's desktop is 1280 x 1024 pixels. I normally use GetSystemMetrics_() to get the width and height of it, and it normally correctly returns 1280 and 1024 accordingly; however today I switched to Large fonts (150%) and noted the results were now incorrect. So a tip / heads-up to anyone using GetSystemMetrics_(): drop it!
[Edit] I advocated using ExamineDesktops() instead, but discovered today for myself that it's totally unreliable; so see my new post further below which works reliably instead. For me, anyway.
My PC's desktop is 1280 x 1024 pixels. I normally use GetSystemMetrics_() to get the width and height of it, and it normally correctly returns 1280 and 1024 accordingly; however today I switched to Large fonts (150%) and noted the results were now incorrect. So a tip / heads-up to anyone using GetSystemMetrics_(): drop it!
[Edit] I advocated using ExamineDesktops() instead, but discovered today for myself that it's totally unreliable; so see my new post further below which works reliably instead. For me, anyway.
Last edited by Dude on Wed May 31, 2017 12:14 pm, edited 2 times in total.
Re: Important tip: getting the desktop resolution
Yup. But even then output isn't always consistent.
http://www.ninelizards.com/purebasic/pu ... 17.htm#top
Once you start messing with DPI settings even DesktopWidth() can give you the wrong number...
http://www.ninelizards.com/purebasic/pu ... 17.htm#top
Once you start messing with DPI settings even DesktopWidth() can give you the wrong number...
( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB)
( The path to enlightenment and the PureBasic Survival Guide right here... )
( The path to enlightenment and the PureBasic Survival Guide right here... )
Re: Important tip: getting the desktop resolution
So how can we 100% reliably get the desktop size? Take a screenshot and check the image w/h? That works, but it's damn overkill...blueznl wrote:Once you start messing with DPI settings even DesktopWidth() can give you the wrong number...
Re: Important tip: getting the desktop resolution
DunnoDude wrote:So how can we 100% reliably get the desktop size? Take a screenshot and check the image w/h? That works, but it's damn overkill...blueznl wrote:Once you start messing with DPI settings even DesktopWidth() can give you the wrong number...
There's probably a good way to do it, but if there is not one way would be to create an invisible window and make it maximised, then get its size, that would probably work regardless of settings.
You'd still have to accommodate for font size versus DPI issues, I guess. It's a mess, this whole DPI thing on Windows. I haven't worked out the changes in Windows 10 yet, have been very busy with all sorts of (shock!) non-purebasic things
( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB)
( The path to enlightenment and the PureBasic Survival Guide right here... )
( The path to enlightenment and the PureBasic Survival Guide right here... )
Re: Important tip: getting the desktop resolution
[Deleted as was pointless]
Last edited by Dude on Sun Sep 24, 2017 8:01 am, edited 1 time in total.
Re: Important tip: getting the desktop resolution
The important thing here is, you MUST build your program DPI-Aware! GetSystemMetrics_(), GetDeviceCaps_(), ... return wrong values if you don't.I normally use GetSystemMetrics_() to get the width and height of it, and it normally correctly returns 1280 and 1024 accordingly; however today I switched to Large fonts (150%) and noted the results were now incorrect.
Just check following sample and comment/uncomment the OpenLibrary part:
Code: Select all
Global txt$
Procedure _IsProcessDPIAware() : EndProcedure
Prototype _IsProcessDPIAware()
Procedure _SetProcessDPIAware() : EndProcedure
Prototype _SetProcessDPIAware()
Define user32 = OpenLibrary(#PB_Any, "user32.dll")
If user32
Define IsProcessDPIAware__._IsProcessDPIAware = GetFunction(user32, "IsProcessDPIAware")
If IsProcessDPIAware__ = 0 : IsProcessDPIAware__ = @_IsProcessDPIAware() : EndIf
Define SetProcessDPIAware__._SetProcessDPIAware = GetFunction(user32, "SetProcessDPIAware")
If SetProcessDPIAware__ = 0 : SetProcessDPIAware__ = @_SetProcessDPIAware() : EndIf
If IsProcessDPIAware__() = #False
SetProcessDPIAware__()
EndIf
CloseLibrary(user32)
EndIf
Procedure MonitorEnumProc(hMonitor, hdcMonitor, lprcMonitor, dwData)
;Protected mi.MONITORINFOEX\cbSize = SizeOf(MONITORINFOEX)
;GetMonitorInfo_(hMonitor, mi)
;Debug PeekS(@mi\szDevice)
Protected *monRect.RECT = lprcMonitor
txt$ + "hMon: " + Chr(9) + Str(hMonitor) +Chr(10)
txt$ + "left: " + Chr(9) + *monRect\left +Chr(10)
txt$ + "top: " + Chr(9) + *monRect\top +Chr(10)
txt$ + "right: " + Chr(9) + *monRect\right +Chr(10)
txt$ + "bottom: " + Chr(9) + *monRect\bottom +Chr(10) +Chr(10)
ProcedureReturn #True
EndProcedure
;Debug MonitorFromWindow_(66560, #MONITOR_DEFAULTTONEAREST)
txt$ + "DPI: " + Str(GetDeviceCaps_(GetDC_(0), #LOGPIXELSX)) +Chr(10) +Chr(10)
txt$ + "SystemMetrics W: " + Chr(9) + GetSystemMetrics_(0) +Chr(10)
txt$ + "SystemMetrics H: " + Chr(9) + GetSystemMetrics_(1) +Chr(10) +Chr(10)
ExamineDesktops()
txt$ + "DesktopWidth: " + Chr(9) + DesktopWidth(0) +Chr(10)
txt$ + "DesktopHeight: " + Chr(9) + DesktopHeight(0) +Chr(10) +Chr(10)
EnumDisplayMonitors_(#Null, #Null, @MonitorEnumProc(), 0)
MessageRequester("", txt$)
Et cetera is my worst enemy
Re: Important tip: getting the desktop resolution
Here's my bug report about this, and screenshot as proof:Dude wrote:The error said something like "ExamineDesktops() must be called before DesktopWidth()" or such... which is weird because I did it already.
http://www.purebasic.fr/english/viewtop ... =4&t=68632
Re: Important tip: getting the desktop resolution
Do you have the same behavior in ekzaminedesktop?
Returns the width and height is not correct.
if you uncomment the lines then it starts to return correctly.
Returns the width and height is not correct.
if you uncomment the lines then it starts to return correctly.
Code: Select all
; ; Uncomment ExamineDesktops work very good
; Debug "DPI: " + Str(GetDeviceCaps_(GetDC_(#Null), #LOGPIXELSX)) ; 96
; Procedure _IsProcessDPIAware() : EndProcedure
; Prototype _IsProcessDPIAware()
;
; Procedure _SetProcessDPIAware() : EndProcedure
; Prototype _SetProcessDPIAware()
;
; Define user32 = OpenLibrary(#PB_Any, "user32.dll")
; If user32
; Define IsProcessDPIAware__._IsProcessDPIAware = GetFunction(user32, "IsProcessDPIAware")
; If IsProcessDPIAware__ = 0 : IsProcessDPIAware__ = @_IsProcessDPIAware() : EndIf
;
; Define SetProcessDPIAware__._SetProcessDPIAware = GetFunction(user32, "SetProcessDPIAware")
; If SetProcessDPIAware__ = 0 : SetProcessDPIAware__ = @_SetProcessDPIAware() : EndIf
;
; If IsProcessDPIAware__() = #False
; SetProcessDPIAware__()
; EndIf
;
; CloseLibrary(user32)
; EndIf
Debug "DPI: " + Str(GetDeviceCaps_(GetDC_(#Null), #LOGPIXELSX)) ; 96 if uncomment 120
;// Для получения разрешения экрана напишите следующий код:
hDCScreen = GetDC_(#Null);
Horres.i = GetDeviceCaps_(hDCScreen, #HORZRES);
Vertres.i = GetDeviceCaps_(hDCScreen, #VERTRES);
ReleaseDC_(#Null, hDCScreen);
;// в Horres содержится разрешение экрана по горизонтали,
;// в Vertres содержится разрешение экрана по вертикали.
If OpenWindow(0,0,0,500,250,"Window 0")
ButtonGadget(-1, 10,10,80,30,"Button")
ResizeWindow(0, (Horres-WindowWidth(0, #PB_Window_FrameCoordinate))/2, (Vertres-WindowHeight(0, #PB_Window_FrameCoordinate))/2, #PB_Ignore, #PB_Ignore)
EndIf
Horres.i = GetSystemMetrics_(#SM_CXSCREEN)
Vertres.i = GetSystemMetrics_(#SM_CYSCREEN)
If OpenWindow(20,0,0,500,250,"Window 20")
ButtonGadget(-1, 10,10,80,30,"Button")
ResizeWindow(20, (Horres-WindowWidth(20, #PB_Window_FrameCoordinate))/2, (Vertres-WindowHeight(20, #PB_Window_FrameCoordinate))/2, #PB_Ignore, #PB_Ignore)
EndIf
ExamineDesktops()
If OpenWindow(10,0,0,500,250,"Window 10")
ButtonGadget(-1, 10,10,80,30,"Button")
ResizeWindow(10, (DesktopWidth(0)-WindowWidth(10, #PB_Window_FrameCoordinate))/2, (DesktopHeight(0)-WindowHeight(10, #PB_Window_FrameCoordinate))/2, #PB_Ignore, #PB_Ignore)
Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf
Last edited by mestnyi on Sun Sep 24, 2017 6:48 pm, edited 1 time in total.
Re: Important tip: getting the desktop resolution
PureBasic language doesn't do 'natively' DPI-aware applications. chi called it!
Really no reason why PB shouldn't now be supporting it natively.
I've personally observed visual issues making applications with PureBasic which aren't DPI-Aware. To quote from Microsoft page.
"Applications that are not DPI–aware but are running on a high-DPI display setting can suffer from many visual artifacts, including incorrect scaling of UI elements, clipped text, and blurry images. By adding support in your application for DPI awareness, you ensure that the presentation of your application's UI is more predictable, making it more visually appealing to users. This gives the user the best possible experience on any display."
GetSystemMetrics_(), GetDeviceCaps_()... is returning logical vs. physical pixels. And there's no bug with PureBasic or Windows APIs. If your desktop resolution is 1280 x 1024 and your DPI is set to 150%, 1280 would now be 853 and 1024 would now be 682 for Not DPI-Aware application. 853 x 682 is roughly your return using GetSystemMetrics?
If you making system info utilities, then getting the physical information would be important. However you trying to make windows and controls then It is easier to work with the logical rather than the physical returns while making not DPI-Aware PB applications. As anyone can clearly see that PureBasic natively included commands such as DesktopWidth() reports physical and using that in Not DPI-Aware code is mind baffling to people. The help file isn't exactly any help to avoid confusion that is repeatedly shown again and again.
Using DesktopWidth() return to make PB Window with maximum desktop width is no help, and no way to calculate properly to my knowledge without also being able to grab the DPI information. I don't believe PB offers such support yet? Therefore OS specific API calls to determine the DPI and do the calculations.
Really no reason why PB shouldn't now be supporting it natively.
I've personally observed visual issues making applications with PureBasic which aren't DPI-Aware. To quote from Microsoft page.
"Applications that are not DPI–aware but are running on a high-DPI display setting can suffer from many visual artifacts, including incorrect scaling of UI elements, clipped text, and blurry images. By adding support in your application for DPI awareness, you ensure that the presentation of your application's UI is more predictable, making it more visually appealing to users. This gives the user the best possible experience on any display."
GetSystemMetrics_(), GetDeviceCaps_()... is returning logical vs. physical pixels. And there's no bug with PureBasic or Windows APIs. If your desktop resolution is 1280 x 1024 and your DPI is set to 150%, 1280 would now be 853 and 1024 would now be 682 for Not DPI-Aware application. 853 x 682 is roughly your return using GetSystemMetrics?
If you making system info utilities, then getting the physical information would be important. However you trying to make windows and controls then It is easier to work with the logical rather than the physical returns while making not DPI-Aware PB applications. As anyone can clearly see that PureBasic natively included commands such as DesktopWidth() reports physical and using that in Not DPI-Aware code is mind baffling to people. The help file isn't exactly any help to avoid confusion that is repeatedly shown again and again.
Using DesktopWidth() return to make PB Window with maximum desktop width is no help, and no way to calculate properly to my knowledge without also being able to grab the DPI information. I don't believe PB offers such support yet? Therefore OS specific API calls to determine the DPI and do the calculations.
Code: Select all
Procedure CreateWindow(WinID, x, y, iw, ih, backcolor)
OpenWindow(WinID, x, y, iw, ih, "", #PB_Window_BorderLess)
SetWindowColor(WinID, backcolor)
EndProcedure
Result = ExamineDesktops()
DesktopWidth = DesktopWidth(0)
DesktopHeight = DesktopHeight(0)
DesktopWidth2 = GetSystemMetrics_(#SM_CXSCREEN)
DesktopHeight2 = GetSystemMetrics_(#SM_CYSCREEN)
Debug "PB_Native: Desktop: "+ Str(DesktopWidth) + "x" + Str(DesktopHeight)
Debug "Win_API: Desktop: "+ Str(DesktopWidth2) + "x" + Str(DesktopHeight2)
; Top left
CreateWindow(0, 0, 0, 30, 30, RGB(255,0,0))
CreateWindow(1, 0, 40, 30, 30, RGB(0, 92, 253))
; Top right
CreateWindow(2, DesktopWidth-30, 0, 30, 30, RGB(255,0,0))
CreateWindow(3, DesktopWidth2-30, 40, 30, 30, RGB(0, 92, 253))
Debug #LF$+"Red blocks to demonstrate using PB Native DesktopWidth() command."
Debug #LF$+"Blue blocks to demonstrate using Windows GetSystemMetrics_()"
Debug #LF$+"... Goal is to have the blocks attached to the top-left & top-right edge of the screen,"+#LF$+
"With the exception that the blue blocks are lowered by design."
Repeat
Event = WindowEvent()
Until Event = #PB_Event_CloseWindow
ʽʽSuccess is almost totally dependent upon drive and persistence. The extra energy required to make another effort or try another approach is the secret of winning.ʾʾ --Dennis Waitley
Re: Important tip: getting the desktop resolution
I do not know what to happen, but I have an api to determine the wines correctly and there is no purebasik. DesktopWidth (0) then at least must have a flag.
-
- Always Here
- Posts: 6425
- Joined: Fri Oct 23, 2009 2:33 am
- Location: Wales, UK
- Contact:
Re: Important tip: getting the desktop resolution
Has anyone tried using the Vector Lib for this purpose?
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
If it sounds simple, you have not grasped the complexity.
Re: Important tip: getting the desktop resolution
For the function GetDeviceCaps_() not all the possible values appear in the documentation.
You can use #DESKTOPHORZRES and #DESKTOPVERTRES (instead of #HORZRES and #VERTRES) to retrieve the width and height of the Screen.
Try this code with scaling >100%
Hope this helps
Tested on Windows 10 x64 only
TeddyLM
You can use #DESKTOPHORZRES and #DESKTOPVERTRES (instead of #HORZRES and #VERTRES) to retrieve the width and height of the Screen.
Try this code with scaling >100%
Code: Select all
#DESKTOPVERTRES = $75
#DESKTOPHORZRES = $76
hDCScreen.l = GetDC_(#Null)
;Returns the scaled size
Debug GetDeviceCaps_(hDCScreen, #HORZRES)
Debug GetDeviceCaps_(hDCScreen, #VERTRES)
;Returns the physical size
Debug GetDeviceCaps_(hDCScreen, #DESKTOPHORZRES)
Debug GetDeviceCaps_(hDCScreen, #DESKTOPVERTRES))
ReleaseDC_(#Null, hDCScreen)
Tested on Windows 10 x64 only
TeddyLM