MadExcept report dialog unusable in high-dpi

delphi package - automated exception handling
obl918
Posts: 23
Joined: Thu Sep 03, 2015 8:33 pm

MadExcept report dialog unusable in high-dpi

Post by obl918 »

I've been working on making my application completely high-dpi aware. On my new Surface Book, which defaults to 192 DPI, the MadExcept exception report dialog is almost completely unusable because it is not scaling itself based on the monitor DPI. 100% scaling is super small on a 3000x2000 monitor that's only 13.5"!

If there is a setting I missed please point it out to me. Otherwise, the forms need to be updated to scale to the DPI of whatever monitor they are on. System DPI scale would be the bare minimum, but it really also needs to scale at runtime when DPI changes (such as the report window being dragged to a monitor with a different DPI).
obl918
Posts: 23
Joined: Thu Sep 03, 2015 8:33 pm

Re: MadExcept report dialog unusable in high-dpi

Post by obl918 »

An easy way to test this is to create a new VCL application and make sure to set it as a high-dpi aware application in the manifest settings (Delphi 10 Seattle). Have a button that throws an exception. Compile, then change your display scaling in Windows 10 to 200% (which is the default on a Surface Book and many other high-end devices now), and run it. The initial form will be properly scaled, but the MadExcept windows won't. Trust me, on one of these retina-class monitors, it's almost impossible to read anything.
madshi
Site Admin
Posts: 10753
Joined: Sun Mar 21, 2004 5:25 pm

Re: MadExcept report dialog unusable in high-dpi

Post by madshi »

Yeah, I'm aware of the problem. madExcept's windows are created by pure win32 APIs, instead of using VCL, because madExcept's windows must be thread safe, which the VCL is not. Making all this high-DPI capable is surely possible, but would cost quite a bit of development time, so I'm not sure how quickly I'll get to that. I've so many things to do atm... :?
obl918
Posts: 23
Joined: Thu Sep 03, 2015 8:33 pm

Re: MadExcept report dialog unusable in high-dpi

Post by obl918 »

madshi wrote:Yeah, I'm aware of the problem. madExcept's windows are created by pure win32 APIs, instead of using VCL, because madExcept's windows must be thread safe, which the VCL is not. Making all this high-DPI capable is surely possible, but would cost quite a bit of development time, so I'm not sure how quickly I'll get to that. I've so many things to do atm... :?
I understand. We all have to prioritize. :-)

For two decades I have treated "large fonts" and more recently high-dpi as a minor issue. However, now there are tons of devices on the market that come out-of-the-box with very high scaling levels set default. My surface book came at 200% scaling. So this is now a pretty big deal, and will only become moreso. And I know it's a lot of work, I have been chasing down DPI-related issues for a month.

DPI awareness is a process-level thing. Perhaps a quick and dirty solution would be to switch off DPI awareness at the process level while all of the application threads are frozen, and then set it back once MadExcept is done doing its thing (assuming the user wanted to continue the application rather than close it). SetProcessDpiAwareness is for that. As long as you build your dialogs and process events (mouse etc) with DPI awareness off, everything will be scaled by Windows automatically. It won't look pretty but will be usable, unlike how it is now. This is just theory on my part though, it's where I would start looking for a quick way to make it functional without committing to full DPI proper support. Obviously this would only be relevant if the system is Windows 8+ (or whatever the min version is).
madshi
Site Admin
Posts: 10753
Joined: Sun Mar 21, 2004 5:25 pm

Re: MadExcept report dialog unusable in high-dpi

Post by madshi »

Maybe you can work around the issue yourself, then you don't have to wait for me? madExcept.pas exports these:

Code: Select all

// do you want to be notified when a madExcept exception box was created/destroyed?
var
  OnExceptBoxCreate  : procedure (exceptBox: HWND; simpleMsgBox: boolean) = nil;
  OnExceptBoxDestroy : procedure = nil;
Using these you should be able to e.g. call SetProcessDpiAwareness yourself. Maybe that would do the job for now?
obl918
Posts: 23
Joined: Thu Sep 03, 2015 8:33 pm

Re: MadExcept report dialog unusable in high-dpi

Post by obl918 »

madshi wrote:Maybe you can work around the issue yourself, then you don't have to wait for me? madExcept.pas exports these:

Code: Select all

// do you want to be notified when a madExcept exception box was created/destroyed?
var
  OnExceptBoxCreate  : procedure (exceptBox: HWND; simpleMsgBox: boolean) = nil;
  OnExceptBoxDestroy : procedure = nil;
Using these you should be able to e.g. call SetProcessDpiAwareness yourself. Maybe that would do the job for now?
I'll give it a try and let you know how it goes.
obl918
Posts: 23
Joined: Thu Sep 03, 2015 8:33 pm

Re: MadExcept report dialog unusable in high-dpi

Post by obl918 »

Well, so much for my idea.

As it turns out, you can't change DPI awareness once it is set. So if the application is DPI aware, you can't temporarily disable it.

The only solution is to factor the DPI into the dialog construction.
madshi
Site Admin
Posts: 10753
Joined: Sun Mar 21, 2004 5:25 pm

Re: MadExcept report dialog unusable in high-dpi

Post by madshi »

Ouch.

Since you already have the experience with doing all these changes, can you sum that up for me? Maybe that will motivate me to look into that soon, although I have SO many other things on my to do list right now. Unfortunately I fear that most of your experience is probably with VCL stuff, while madExcept's windows are all built by using pure win32 APIs. So I'm not sure how much your experience would help me?
obl918
Posts: 23
Joined: Thu Sep 03, 2015 8:33 pm

Re: MadExcept report dialog unusable in high-dpi

Post by obl918 »

I have plenty of experience with win32 API, but it would take looking through the MadExcept code to give you any useful details, and like you my list is too full.

Theoretically this is a simple matter of looking at the current DPI, and then MulDiving all of your coordinates and sizes used when creating the dialog against 96. So basically MyDialogWidth := 100 becomes MyDialogWidth := MulDiv(100, DPI, 96). There is a simple API for getting DPI but it escapes my memory. Also you need to set the font DPI accordingly, or muldiv the height of the fonts as above. That's probably all you really need to worry about, but that's theoretical and you know how that goes.

It gets a lot more complicated if you want to properly support a runtime DPI change (if the user drags the dialog from one monitor to another with a different DPI) but that would not be a critical feature to support.
madshi
Site Admin
Posts: 10753
Joined: Sun Mar 21, 2004 5:25 pm

Re: MadExcept report dialog unusable in high-dpi

Post by madshi »

Ok, doesn't sound too complicated. Maybe I'll give it a try if I find some time...
obl918
Posts: 23
Joined: Thu Sep 03, 2015 8:33 pm

Re: MadExcept report dialog unusable in high-dpi

Post by obl918 »

Resurrecting this thread, because solving this should be really easy now.

With Windows 10 Anniversary Update, there is a new user32 procedure called SetThreadDpiAwarenessContext that should fix this problem, assuming the madExcept reporting dialog is in its own thread:

https://msdn.microsoft.com/en-us/librar ... 85%29.aspx

Basically, when the thread for the reporting dialog is created, you should be able to tell Windows that you don't know how to scale for DPI, and Windows will handle it by itself for you. Obviously you'd need to check for the existence of SetThreadDpiAwarenessContext since most versions of Windows installed out there don't have it...

This issue is a pretty big problem for me, since I have made my entire application per-monitor DPI aware, except for the madExcept dialog. If an exception occurs on a PC running in high dpi (like a Surface Book), the madExcept dialog is totally unusable because it is practically microscopic, since the process is running as DPI aware but the dialog doesn't scale for DPI.

More info from MS here: https://blogs.technet.microsoft.com/ask ... ry-update/

If you can't look into this, please point me to some direction on rebuilding madExcept for myself so that I can add this functionality.
madshi
Site Admin
Posts: 10753
Joined: Sun Mar 21, 2004 5:25 pm

Re: MadExcept report dialog unusable in high-dpi

Post by madshi »

Sounds like a good and easy solution! I'll give it a try. It might take a couple of days, though.

If you want to try for yourself, just copy madExcept.pas and mad.inc into your project folder. Then look for TExceptionBox.Create and add the call to SetThreadDpiAwarenessContext. With a bit of luck it might already work?
obl918
Posts: 23
Joined: Thu Sep 03, 2015 8:33 pm

Re: MadExcept report dialog unusable in high-dpi

Post by obl918 »

Even Berlin update 2 doesn't have the headers for the new dpi calls. :shock: Bah.
obl918
Posts: 23
Joined: Thu Sep 03, 2015 8:33 pm

Re: MadExcept report dialog unusable in high-dpi

Post by obl918 »

This is not pretty, but it works. It should definitely be added in a more orderly fashion.

Add this to TExceptionBox.Create::

Code: Select all

var
  H: HMODULE;
  _SetThreadDpiAwarenessContext: function (dpiContext: THandle): THandle; stdcall;
  DPIAwareOld: THandle;

begin
  {$ifdef log}log('TExceptionBox.Create'); indentLog;{$endif}
  inherited Create;

  // my bolted-on dpi fix for Windows 10 anniversary+
  DPIAwareOld := 0;
  H := LoadLibrary('User32.dll');
  if H > HINSTANCE_ERROR then
  begin
    try
      _SetThreadDpiAwarenessContext := GetProcAddress(H, 'SetThreadDpiAwarenessContext');
      if Assigned(_SetThreadDpiAwarenessContext) then
        DPIAwareOld := _SetThreadDpiAwarenessContext(THandle(-1));
    finally
      FreeLibrary(H);
    end;
  end;
If the call is available, this tells Windows to handle the scaling of any created exception box. Ideally I would restore the previous setting on destroy, but it doesn't really matter, since madExcept's threads won't handle dpi anywhere.

After making this change, on my Surface Book, madExcept is no longer microscopic! Yay! :crazy:

Doesn't help anyone running an older version of Windows, but for them it will behave as before.

Using the exposed before/after exception box is too late -- you need to call SetThreadDpiAwarenessContext before the window is created or it uses the previous setting.
Last edited by obl918 on Wed Jan 18, 2017 9:07 pm, edited 1 time in total.
obl918
Posts: 23
Joined: Thu Sep 03, 2015 8:33 pm

Re: MadExcept report dialog unusable in high-dpi

Post by obl918 »

fixed code in above.
Post Reply