Page 1 of 1
[Solved] DPI issue when app can't use DPI awareness
Posted: Sun Apr 20, 2025 10:04 am
by BarryG
[Edit] Solved - See new post below (
https://www.purebasic.fr/english/viewto ... 22#p639722).
Hi all. I am using the following code to copy an image of my 1920x1080 desktop and show it in a window over my real desktop, and it works great at 100% DPI:
Code: Select all
Global w,h
Procedure ScreenshotDesktop()
ExamineDesktops()
w=DesktopWidth(0)
h=DesktopHeight(0)
hImage=CreateImage(#PB_Any,w,h)
If hImage
hDC=StartDrawing(ImageOutput(hImage))
If hDC
dt=GetDesktopWindow_()
dc=GetDC_(dt)
If dc
If BitBlt_(hDC,0,0,w,h,dc,0,0,#SRCCOPY)
ssdesktop=hImage
EndIf
ReleaseDC_(dt,dc)
EndIf
StopDrawing()
EndIf
EndIf
ProcedureReturn ssdesktop
EndProcedure
ss=ScreenshotDesktop()
StartDrawing(ImageOutput(ss))
DrawText(5,5," This is the captured image ("+Str(ImageWidth(ss))+"x"+Str(ImageHeight(ss))+" / Esc to close) ",#Yellow)
StopDrawing()
OpenWindow(0,0,0,w,h,"",#PB_Window_BorderLess)
ImageGadget(0,0,0,w,h,ImageID(ss))
Repeat : WaitWindowEvent() : Until GetAsyncKeyState_(#VK_ESCAPE)
Now, the problem is when my 1920x1080 desktop is set to 125% DPI or higher. The window that gets overlayed on my desktop doesn't show the full captured image, because the right and bottom sides get cropped. This is despite the image and window being 1920x1080 like my desktop. Here's an example image of it at 125% DPI:
See how the desktop's Start button, taskbar, and system tray items (clock, etc) aren't visible?
I know I can turn on DPI-awareness to fix this, but let's pretend that I can't for any given reason. Is there a way to make this image scale properly and not be cropped when DPI awareness is off? As I said, the image is the correct desktop size, but just isn't showing all of itself.

Re: DPI issue when app can't use DPI awareness
Posted: Sun Apr 20, 2025 11:30 am
by Michael Vogel
If you are using Windows, it's not very difficult. Examples are seen in some of my codes here, like
this (have a look at ScaleUp and ScaleDown).
Re: DPI issue when app can't use DPI awareness
Posted: Mon Apr 21, 2025 12:00 am
by BarryG
Thanks, Michael. I'm too dumb to understand what you did, but I found a hacky "fix" by simply resizing the image (below). Not the best method but it'll be okay for now. I really have to convert my app to be DPI-aware but it's going to take so much work.
Code: Select all
Global w,h
Procedure ScreenshotDesktop()
ExamineDesktops()
w=DesktopWidth(0)
h=DesktopHeight(0)
hImage=CreateImage(#PB_Any,w,h)
If hImage
hDC=StartDrawing(ImageOutput(hImage))
If hDC
dt=GetDesktopWindow_()
dc=GetDC_(dt)
If dc
If BitBlt_(hDC,0,0,w,h,dc,0,0,#SRCCOPY)
ssdesktop=hImage
EndIf
ReleaseDC_(dt,dc)
EndIf
StopDrawing()
EndIf
EndIf
ResizeImage(ssdesktop,GetSystemMetrics_(#SM_CXSCREEN),GetSystemMetrics_(#SM_CYSCREEN)) ; The hacky "fix".
ProcedureReturn ssdesktop
EndProcedure
ss=ScreenshotDesktop()
StartDrawing(ImageOutput(ss))
DrawText(5,5," This is the captured image ("+Str(ImageWidth(ss))+"x"+Str(ImageHeight(ss))+" / Esc to close) ",#Yellow)
StopDrawing()
OpenWindow(0,0,0,w,h,"",#PB_Window_BorderLess)
ImageGadget(0,0,0,w,h,ImageID(ss))
Repeat : WaitWindowEvent() : Until GetAsyncKeyState_(#VK_ESCAPE)
Re: [Solved] DPI issue when app can't use DPI awareness
Posted: Mon Apr 21, 2025 8:04 am
by Fred
I don't think it's that much work, we did the IDE very quickly.
Re: [Solved] DPI issue when app can't use DPI awareness
Posted: Mon Apr 21, 2025 9:49 am
by BarryG
Literally 99% of my app's display and functions get broken when I turn DPI on.

Gadgets appear too small or large, images aren't the right size, opening a window to the edge of the desktop never works (they go off the edge similar to my first post above), etc. It's a massive re-write to fix it, which is why I haven't done it, and at this stage probably never will.
I started this app years ago before DPI was a thing, which is why it's all broken and incompatible now if I turn DPI on. There's over 65,000 lines of code to go through.

To anyone writing a new app: turn DPI on and code with it on, so you don't suffer my fate.
Re: [Solved] DPI issue when app can't use DPI awareness
Posted: Mon Apr 21, 2025 10:31 am
by fluent
BarryG wrote: Mon Apr 21, 2025 9:49 am
Literally 99% of my app's display and functions get broken when I turn DPI on.

Gadgets appear too small or large, images aren't the right size, opening a window to the edge of the desktop never works (they go off the edge similar to my first post above), etc. It's a massive re-write to fix it, which is why I haven't done it, and at this stage probably never will.
I started this app years ago before DPI was a thing, which is why it's all broken and incompatible now if I turn DPI on. There's over 65,000 lines of code to go through.

To anyone writing a new app: turn DPI on and code with it on, so you don't suffer my fate.
Is there an easy tutorial available to adapt an old program to DPI?
Or maybe ChatGPT can help? (just asking.)
Re: [Solved] DPI issue when app can't use DPI awareness
Posted: Tue Apr 22, 2025 9:04 am
by PBJim
BarryG wrote: Mon Apr 21, 2025 9:49 am
To anyone writing a new app: turn DPI on and code with it on, so you don't suffer my fate.
I can sympathise with the work involved. As far as I'm aware though, isn't it enabled by default? Or are you referring to changing the Windows scaling factor?
In my experience, PB automatically handles the majority of gadgets when scaling is increased and it still works — for our systems at least — even when the DPI setting in Compiler Options is disabled. The PB manual offers a little on this, although limited background :
Enable DPI Aware Executable (Windows only)
This option enable DPI awareness when creating an executable. That means than [that a] GUI created in
PureBasic will scale automatically if the DPI of the screen is above 100%. Most of the process is
seemless, but some case needs to be worked out, like pixel based gadgets (ImageGadget, CanvasGadget etc.).
One can take from this, there are some gadgets for which scaling is not performed automatically, but for those exceptions we have the functions DesktopResolutionX() and DesktopResolutionY(), therefore a question of compensating for their size.
Re: [Solved] DPI issue when app can't use DPI awareness
Posted: Tue Apr 22, 2025 1:03 pm
by BarryG
PBJim wrote: Tue Apr 22, 2025 9:04 amisn't it enabled by default?
No. And turning it on means you need to change screen coordinates for a lot of stuff. Take the example below. Run it as a compiled exe on a 100% DPI desktop, and the mouse correctly goes over the window's icon. Now turn DPI on for the exe and recompile, and then change your desktop to 125% DPI and run it. The mouse is now way off the window and not where it should be. This is what I mean by turning DPI on breaks my app in major ways.
Code: Select all
x=300
y=300
OpenWindow(0,x,y,320,120,"test",#PB_Window_SystemMenu)
SetCursorPos_(x+10,y+10) ; Put the mouse over the window icon.
Repeat : Until WaitWindowEvent()=#PB_Event_CloseWindow
Yes, this can be "fixed" by using DesktopScaledX() and DesktopScaledY() like below, but that's a hell of a lot of additional coding and typing just to make it work with API commands. PureBasic is requiring us to scale everything with wrappers like this? This is not good.
Code: Select all
x=300
y=300
OpenWindow(0,x,y,320,120,"test",#PB_Window_SystemMenu)
SetCursorPos_(DesktopScaledX(x+10),DesktopScaledY(y+10)) ; To make it work on all DPI scales. :(
Repeat : Until WaitWindowEvent()=#PB_Event_CloseWindow
I know what you're probably going to say: just use the official PureBasic commands. That's not possible for me because using API calls are a big part of my app for commands that don't exist in PureBasic, such as creating window thumbnails at X/Y/W/H positions, or custom balloon tips at specific X/Y positions. These break with DPI turned on unless I wrap them like above.

Re: [Solved] DPI issue when app can't use DPI awareness
Posted: Tue Apr 22, 2025 1:55 pm
by Fred
It's not PureBasic which requires that, but Windows. For example on MacOS you have almost nothing to do for HiDPI screen as the OS takes care of all that. So yes If you use API here and here you need to adjust the coordinates with the desktop commands and your app will work with and without the DPI flags. It's some work but it shouldn't be that big IMHO.
Re: [Solved] DPI issue when app can't use DPI awareness
Posted: Tue Apr 22, 2025 3:49 pm
by PBJim
No, I accept what you say, with regard to external APIs. I don't think there's any easy way Barry mate, with a sizable application that's been developed over a long period, there's sometimes going to be tasks like this, as part of its lifecycle. I'm sure it's a task that becomes easier as you work through it.
I suspect that on my system, the graphics card is doing the scaling, because the mouse position is spot-on at the icon every time, as marked with the arrow below. This would account for everything being consistently upscaled to 125% — regardless of the compiler option "DPI aware".

Re: [Solved] DPI issue when app can't use DPI awareness
Posted: Tue Apr 22, 2025 9:54 pm
by BarryG
Fred wrote: Tue Apr 22, 2025 1:55 pmIf you use API here and here you need to adjust the coordinates with the desktop commands and your app will work with and without the DPI flags. It's some work but it shouldn't be that big IMHO.
You underestimate how many API commands that use screen coords that my app has.
@PBJim: You're lucky. Every PC that I try it on, gives the wrong coords when DPI is on for the built exe.
Re: [Solved] DPI issue when app can't use DPI awareness
Posted: Wed Apr 23, 2025 12:50 am
by kenmo
Rather than change hundreds of lines of your code, you can use Macro wrappers to scale each API function "once"...
Example...
Code: Select all
CompilerIf (#PB_Compiler_DPIAware)
Procedure SetCursorPos_DPI_(X, Y)
SetCursorPos_(DesktopScaledX(X), DesktopScaledY(Y))
EndProcedure
Macro SetCursorPos_(X, Y)
SetCursorPos_DPI_((X), (Y))
EndMacro
CompilerEndIf
SetCursorPos_(100, 100)
Re: [Solved] DPI issue when app can't use DPI awareness
Posted: Wed Apr 23, 2025 8:26 am
by BarryG
Thanks, Kenmo. I totally forgot about wrapping with macros. That should definitely make things a LOT easier!

Re: [Solved] DPI issue when app can't use DPI awareness
Posted: Thu Apr 24, 2025 12:07 pm
by BarryG
DPI TRULY SOLVED!
I just found out I can write a Registry setting to make my non-DPI exe work perfectly scaled on any DPI system setting!
I just added a string entry to my exe's location like this, with the data value shown:
Here's the Registry section for easy copying:
Code: Select all
Computer\HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers
So I just made my app check on start if that entry exists, and if not, it writes it and then restarts itself. Works perfect! Now there's no need for me to change anything in my app to make everything scale and look good on any DPI setting! It also solves all issues with SetCursorPos_() and so on, and I don't need to wrap macros with DesktopScaledX() and such. So happy.

Sometimes Microsoft
does do things right!
How it works: What this Registry setting does is simply changes the DPI setting of the exe to the below. The user could do this manually by right-clicking the exe and going into the Compatibility properties page, but making the exe do it is more user-friendly. Hope this info helps someone in future.

Re: [Solved] DPI issue when app can't use DPI awareness
Posted: Fri Apr 25, 2025 4:06 pm
by PBJim
What you've actually shown there, Barry, is a newish DPI function in Windows. On all our systems, we have the below Compatibility tab — which is different from your example.
If I select the disable option, it creates the same registry value and data as you've shown — ~ HIGHDPIAWARE — but it doesn't behave the same way as yours, if that option isn't ticked. Our Windows systems, which are a mix of Server and Windows 10, scale everything regardless even when PureBasic's DPI compiler option isn't chosen, whereas you've found your application was broken by the setting in the compiler, combined with scaling at 125%.
The appearance is not satisfactory though, as shown below left, with original on right. It affects drawing clarity and I would think that coding it properly is better, because you're then retaining the fine resolution of the GUI drawing, without distorting it, but you adjust the size of certain graphical objects to compensate for variation in monitor size.
