Alaska Software Inc. - Bug in AppDesktop():CurrentSize()
Username: Password:
AuthorTopic: Bug in AppDesktop():CurrentSize()
Itai Ben-ArtziBug in AppDesktop():CurrentSize()
on Tue, 20 Oct 2015 19:15:16 -0700
I’ve setup screen resolution to 1920 x 1200.
AppDesktop():CurrentSize() = {1920,1200}
I’ve changed desktop font size to 150% (screen resolution kept at 1920 X 
1200).
AppDesktop:CurrentSize() = {1280,800}
Can this bug be fixed?
Is there a way to retrieve screen resolution independent of desktop 
font-size?

Many thanks,
-Itai
Andreas Gehrs-Pahl
Re: Bug in AppDesktop():CurrentSize()
on Thu, 22 Oct 2015 01:22:34 -0400
Itai,

>Iʼve setup screen resolution to 1920 x 1200.
>AppDesktop():CurrentSize() = {1920,1200}
>Iʼve changed desktop font size to 150% (screen resolution kept at 1920 X 
>1200).
>AppDesktop:CurrentSize() = {1280,800}
>Can this bug be fixed?

This is called "DPI Virtualization" and is correct behavior, so it doesn't 
need to be fixed. On Windows Vista and higher, Windows APIs report a virtual 
resolution, based on the actual Screen Resolution and the applied scaling 
factor, leaving the (reported) DPI at the default of 96 DPI. That way, the 
entire application dialog is transparently scaled by the OS, not only the 
fonts. This feature allows applications that are "not DPI aware" appear the 
same as if the resolution was changed, even though they might look "blurry", 
as they are scaled by the Desktop Window Manager (DWM). In Windows Vista, 
the text isn't scaled correctly, but in Windows 7 and later the text is also 
scaled.

>Is there a way to retrieve screen resolution independent of desktop 
>font-size?

Yes, to change this behavior (for all applications), select "Control Panel" 
==> "Appearance and Personalization" ==> "Display" and from that dialog the: 
"Set custom text size (DPI)" option on the left (this is for Windows 7, 
other OS versions might be slightly different).

On the popup dialog, select the "Use Windows XP style DPI scaling" check 
box and [Apply] the settings. After Log-off or Restart, the OS will report 
the original resolution (of 1920 x 1200) with an adjusted DPI setting (for 
fonts), which will be 120 DPI (for the "Medium - 125%" setting) or 144 DPI 
(for the "Larger - 150%") setting, instead of the default of 96 DPI (for 
the "Smaller - 100%" setting).

DPI virtualization is by default enabled when a scale factor of greater than 
120 (125 percent) is selected. But it can be disabled (or enabled) with this 
check box for any scale (or DPI) setting.

You can also change this for just a particular application, by selecting the 
Compatibility tab on the Properties dialog, and then select the box labeled 
"Disable display scaling on high DPI settings". Another option to disable 
DPI virtualization for a particular application, is to supply a manifest 
file for the application with the <dpiAware>true</dpiAware> setting. 
Additionally, you can use the SetProcessDPIAware() Windows API function to 
change the setting at runtime, but MS discourages doing this.

To check if the above-mentioned check box has been selected, you can also 
read the "UseDpiScaling" value of the following Registry key: 
HKEY_CURRENT_USER\Software\Microsoft\Windows\DWM. If it is set to 0 (Zero)
(a DWord), then the check box is selected (XP-style scaling is used). If 
it is set to 1, then the check box is not selected (and DPI virtualization 
is used).

You can verify (and experiment with) this using the Windows API functions 
GetClientRect() and GetDeviceCaps(). Here is what I use:

Function GetDeskTopSize()
*************************************************************************
* Used to get the actual, current Desktop Size, as this value is not    
 updated correctly, if the Deskop resolution is changed during program 
 execution, and "AppDektop():CurrentSize() always reports the original 
 settings. See also PDR 109-4244 for details.                          *
*************************************************************************
LOCAL nHWnd   := AppDesktop():GetHWnd()
LOCAL nWidth  := 0
LOCAL nHeight := 0
LOCAL cBuffer := U2Bin(0) + U2Bin(0) + U2Bin(nWidth) + U2Bin(nHeight)
   DllCall("User32.DLL", DLL_STDCALL, "GetClientRect", nHWnd, @cBuffer)
   nWidth     := Bin2U(substr(cBuffer,  9, 4))
   nHeight    := Bin2U(substr(cBuffer, 13, 4))
return ({nWidth, nHeight})

Function GetWindowsFontsDPI(lWidth)
LOCAL lHeight := iif(lWidth == NIL, .t., .not. lWidth)
LOCAL nHeight := iif(lHeight, LOGPIXELSY, LOGPIXELSX)
LOCAL nHWnd   := AppDesktop():GetHWnd()
LOCAL nHDC    := DllCall("User32.DLL", DLL_STDCALL, "GetDC", nHWnd)
LOCAL nLogPix := 96		 default for Small Fonts (100%)
   if nHDC # 0
      nLogPix := DllCall("GDI32.DLL", DLL_STDCALL, "GetDeviceCaps", nHDC, nHeight)
      DllCall("User32.DLL", DLL_STDCALL, "ReleaseDC", nHWnd, nHDC)
   endif
return (nLogPix)

For more information, see also this MS article on "Writing DPI-Aware Desktop 
and Win32 Applications":

https://msdn.microsoft.com/en-us/library/windows/desktop/dn469266(v=vs.85).aspx

Hope this helps,

Andreas

Andreas Gehrs-Pahl
Absolute Software, LLC

phone: (989) 723-9927
email: Andreas.GP@Charter.net
web:   http://www.Aerospace-History.net
Itai Ben-ArtziRe: Bug in AppDesktop():CurrentSize()
on Thu, 22 Oct 2015 20:37:14 -0700
Thank you! Thank you! Thank you, Andreas!!!
This is valuable info well delivered.

One more follow-up question:
Can I set (via manifest or otherwise) the application to 96 DPI (100%) 
regardless of the computer settings?

Many thanks,

-Itai
Andreas Gehrs-Pahl
Re: Bug in AppDesktop():CurrentSize()
on Fri, 23 Oct 2015 02:05:42 -0400
Itai,

>Thank you! Thank you! Thank you, Andreas!!!
>This is valuable info well delivered.

You are welcome.

>One more follow-up question:
>Can I set (via manifest or otherwise) the application to 96 DPI (100%) 
>regardless of the computer settings?

Yes, if you (always) enable DPI virtualization, the DWM will do the scaling 
of your application, and the application will think it is at 96 DPI (100%) 
regardless of the computer's actual settings.

But this is what you didn't like, according to your original post, because 
the OS APIs will report a lower resolution than the one actually set, while 
the DWM will do the scaling for you.

I haven't tried it, but using <dpiAware>false</dpiAware> in your manifest 
file might do exactly that -- enable DPI virtualization at any scale factor.

Follow the link to the MS article about DPI-aware applications at the end of 
my previous post. It explains a lot of this in detail and the differences 
between the various OS versions.

As a general note, the best option would be to actually create a DPI-aware 
application and to size all GUI elements and fonts according to the selected 
scaling factor (DPI setting) and resolution at runtime. This would result in 
a much better resolution (no blurriness) and no GUI rendering issues -- like 
the ones mentioned in the MS article.

Maybe Alaska could add such a feature to their future layout manager/visual 
designer in Xbase++ Version 3.0, allowing for automatic, out-of-the-box, 
DPI-aware GUI elements and behavior. Especially since Windows 8.1 introduced 
dynamic DPI scaling (and the corresponding events).

Andreas

Andreas Gehrs-Pahl
Absolute Software, LLC

phone: (989) 723-9927
email: Andreas.GP@Charter.net
web:   http://www.Aerospace-History.net
Itai Ben-ArtziRe: Bug in AppDesktop():CurrentSize()
on Thu, 22 Oct 2015 23:46:39 -0700
Great! good advice.  I'll simply scale the font as needed.
-Itai
Itai Ben-ArtziRe: Bug in AppDesktop():CurrentSize()
on Thu, 22 Oct 2015 21:20:06 -0700
Andreas,
Including <dpiAware>true</dpiAware> in the manifest yields run-time error. 
Could you please provide a sample how/where to insert this line?
Many thanks,
-Itai
Itai Ben-ArtziRe: Bug in AppDesktop():CurrentSize()
on Thu, 22 Oct 2015 22:06:09 -0700
OK, I've found it:

<asmv3:application>
  <asmv3:windowsSettings 
xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
    <dpiAware>true</dpiAware>
  </asmv3:windowsSettings>
</asmv3:application>