17

Trying to my Delphi 2010 application more user freindly in high DPI modes in Windows 7 I have been trying several methods to retrive PixelsPerInch and compare to 96. Alas, no matter what I tried I always get 96. My questions are:

  1. What is the best practice to get custom DPI mode?
  2. Is the fact I am getting a constant 96 no matter what I what the percebtage is means I missing somthing?

Here is what I had tried

dpiX := Form1.PixelsPerInch

and

dpiX := Screen.PixelsPerInch

and finally:

D2DFactoryOptions.DebugLevel := D2D1_DEBUG_LEVEL_NONE;
pD2DFactoryOptions := @D2DFactoryOptions;
if D2D1CreateFactory(
    D2D1_FACTORY_TYPE_SINGLE_THREADED,
    IID_ID2D1Factory,
    PD2DFactoryOptions,
    D2DFactory
    ) <> S_OK then exit;
D2DFactory.GetDesktopDpi(dpiX, dpiY)

Care to guess? that's right dpiX is a constant 96 in 100%, 125% and 150%

Please advice.

asafadd
  • 265
  • 1
  • 3
  • 15

7 Answers7

12

I think you need to mark your application as being high DPI aware by including this in your application manifest:

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

Details on declaring DPI awareness are given here.

It seems like you are currently falling back to what is called DPI Virtualization.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • Thanks @david-heffernan, I totally agree. The thing is, being DPI aware means that I have to handle all the customization by myself and that is a whole lot of work... Is there a cheaper way? – asafadd Aug 08 '11 at 19:00
  • if you set Scaled to be True on every form then the VCL framework will scale your GUI. That's what I do. – David Heffernan Aug 08 '11 at 19:10
  • Thanks, the pages are scaled, but I need to know that I am in high DPI state so that I customized controls. – asafadd Aug 08 '11 at 19:22
  • Once you mark your application as DPI aware then `Screen.PixelsPerInch` will return 120, 144 etc. – David Heffernan Aug 08 '11 at 19:23
  • I'm doomed if I do (see @warren-p answer) and dommed if I don't. Isn't there a way to claw my way out of this virtualization? – asafadd Aug 09 '11 at 01:05
  • warren is unduly pessemistic in my view. I had none of the troubles he describes. – David Heffernan Aug 09 '11 at 06:19
  • I had integrated your xml with a schema I found in http://delphi.about.com/library/bluc/text/uc111601a.htm and it worked like magic. I have tons of customized controls and they all fell into place like a dream. – asafadd Aug 10 '11 at 18:03
  • The approch breaks application with High DPI (for example, 191 dpi for Retina) - so it's not a sollution totally. – Dmitry Feb 06 '13 at 20:43
  • @Altaveron No it does not. My app looks great at that DPI. You just need to know how to do it right. Read this if you want to learn: http://stackoverflow.com/questions/8296784/how-do-i-make-my-gui-behave-well-when-windows-font-scaling-is-greater-than-100/8296833#8296833 – David Heffernan Feb 06 '13 at 20:44
  • @Altaveron I cannot possibly imagine why you downvoted this answer to this question. It is the correct answer to this question. The fact that you don't know how to write a high DPI app does not make this the wrong answer. – David Heffernan Feb 06 '13 at 20:46
  • It's a million of problems instead a correct reading of 1 system setting! – Dmitry Feb 06 '13 at 20:46
  • David, I don't want to add high DPI support - I only want to detect system DPI setting. That's all. Really. – Dmitry Feb 06 '13 at 20:47
  • 1
    @Altaveron So why are you downvoting my answer to a different question? And it's perfectly easy to write an app that works well at very high DPI. Your one doesn't. But mine does. So, why attack this answer? I could help you if you would let me. – David Heffernan Feb 06 '13 at 20:49
5

You could have a look at the Registry value AppliedDPI at

HKEY_CURRENT_USER\Control Panel\Desktop\WindowMetrics\AppliedDPI

Thanks to Andreas Rejbrand.

Dmitry
  • 14,306
  • 23
  • 105
  • 189
4

Is your application DPI aware? If not, declare it so.

Edit:

If you really just want to detect the current setting, but don't want to enable DPI awareness for your whole application then maybe the best approach is to write a small (dpi aware) app whose sole job is to do this detection. Run it and transfer the result over to your main app. Or provide a launcher which detects and then runs the main app providing the setting as command line param. This of course only if there is no other API or "secret" call your application can make to determine the setting even when running DPI virtualized.

Heinrich Ulbricht
  • 10,064
  • 4
  • 54
  • 85
  • Hello Heinrich, calling SetProcessDPIAware did enable D2DFactory to get the right DPI. Screen.PixelPerInch remained at 96, alas. – asafadd Aug 08 '11 at 19:24
  • 2
    @asafadd You probably can't call `SetProcessDPIAware` early enough. You may need it to run before VCL initiazation. You could achieve that by putting it in an initialization section of a unit that uses no other units (and I mean that) and make it first in your .dpr file. But the manifest approach is a lot better. Sadly, the app manifest that Delphi generates cannot be customised. I always link my own and then I can get what I want. – David Heffernan Aug 08 '11 at 19:53
  • @asafadd David has a point here - try calling `SetProcessDPIAware` earlier. Put it in some unit in the initialization section, right-click your project, click View Source, put this very unit at first place. This should guarantee earliest possible initialization. – Heinrich Ulbricht Aug 09 '11 at 07:30
  • Integrated it into my manifest and it solved all my problems. Thanks a lot! – asafadd Aug 10 '11 at 18:09
2

Because Delphi's IDE doesn't even provide a way to mark your application DPI-aware as David has shown you you need to make your own manifest and add stuff to it, and because going into DPI Aware mode means you will have to handle a lot of work yourself, you might find that it's just not worth it. I certainly abandoned the attempt after about 100 fruitless hours of work.

If your app used 100% Common Controls, and you didn't mind reworking all the others until they worked fine for you, then go for it.

Even Common-controls based controls like the Page control don't seem to work (at least their VCL wrappers don't work) well in a high-dpi environment once DPI virtualization is turned off.

Short version: Best practice these days is don't bother at all in VCL apps unless you absolutely must, and then, you may as well set aside time for rewriting and fixing every control in the VCL and every third party control, to work around the glitches.

Warren P
  • 65,725
  • 40
  • 181
  • 316
  • 1
    Let me see if I got it straight: Don't use Delphi because it lacks good support for high DPI? – asafadd Aug 09 '11 at 02:42
  • I don't agree my app uses plain Vcl controls and works fine at 200% dpi. The only extra work I needed to do was to make sure my app wide image list loaded appropriately sized icon resources. – David Heffernan Aug 09 '11 at 06:18
  • Well your UI controls must be simpler than mine. :-) All I'm saying is "I had lots of trouble, and you might too". Image sizes were so far down the list of layout problems that I never got far enough to even care about using small images on buttons. – Warren P Aug 09 '11 at 12:52
  • @asafadd: Delphi isn't alone there. Most frameworks (other than WPF) have a lot of trouble with windows High DPI mode. My opinion is that it's Windows that is badly designed, not Delphi. – Warren P Aug 09 '11 at 13:31
  • @Warren Don't blame your tools! Of course you need to have different images for different DPI modes. Put your images in icons linked as resources and load the best size into an image list at runtime. My solution involves a single application wide image list that is centrally managed at a low level. I could give you a nice screen shot at 200% DPI is you like! – David Heffernan Aug 10 '11 at 09:46
  • What? I'm not blaming my tools (Delphi), but I am blaming the irregular implementation in Windows which is not consistent between GDI and GDI+ and Direct2D. The issue is more complex than the sizes of images. Maybe I need to repeat that more times? An image list won't begin to help with the issues I am talking about. – Warren P Aug 10 '11 at 12:51
2

Don't respond to the user's DPI setting.

Respond the user's font preference.

If you only respond to the user's DPI setting, then your form will not get bigger if the user uses a larger font than you used at design time, e.g.

  • you designed with 8pt MS Sans Serif or Tahoma
  • the user is running Windows Vista or Windows 7 (9pt Segoe UI)
  • you're running on my computer (14pt Segoe UI)

By responding to font size (in pixels), you get high-DPI support for free (and you're being a good developer!):

  • 8pt Tahoma @96dpi: 13px Windows 2000/XP (what you designed with)
  • 8pt Tahoma @131dpi: 15px (scale your designed form by 115%)
  • 9pt Segue UI @96dpi: 15px Windows Vista/7 (scale your designed form by 115%)
  • 9pt Segoe UI@131dp: 16px my home machine (scale your form by 123%)
  • 12pt Tahoma @96dpi: 16px my work machine (scale your designed form by 123%)

You want to turn all your form's Scaled property off; so they don't try to respond to dpi settings. You want the .NET WinForms equivalent of AutoScaleMode.Font.


And yes, once you've paid your taxes, and can handle different DPI settings, declare your application highDpi aware using a manifest - as other answers have given.

Don't use SetProcessDPIAware, as it may be too late for DLLs that you depend on who already read the current DPI:

Note SetProcessDPIAware is subject to a possible race condition if a DLL caches dpi settings during initialization. For this reason, it is recommended that dpi-aware be set through the application (.exe) manifest rather than by calling SetProcessDPIAware.

Ian Boyd
  • 246,734
  • 253
  • 869
  • 1,219
  • And although you're using DirectX rather than `DFM` forms, the concepts are still valid. They concepts are also valid for Windows dialogs, .NET WinForms, WPF, and Direct2D. – Ian Boyd Aug 15 '11 at 14:38
1

In case it helps someone, I have noticed that Screen->PrimaryMonitor->PixelsPerInch DOES change according to the display scaling.

Stephane
  • 21
  • 2
1

i set out to fix this delphi program which had DPI troubles in Windows 10, fine in Windows 7 Virtual Magnifying Glass, after landing here and troubleshooting, i ended up saving alot of time by just right clicking properties of the exe and fiddling with Compatibility settings, there's a "Change high DPI settings" button, at the bottom of that dialog turned on "Override high DPI scaling" and app is now working fine.

So if it's just personal use or w/e this will be much less of a headache!

colin lamarre
  • 1,714
  • 1
  • 18
  • 25