0

I inherited a legacy application that now has to run on Windows 10. During testing, we found that part of the program (which is a child window placed as a toolbar) would only partially draw when the program starts--more than half of the right of the toolbar would draw only black. At runtime, the fix was to resize the whole window, which would resize/redraw the toolbar window. We eventually found that if we set "Disable display scaling" appeared to prevent the bug entirely (tested to a confidence of just beyond 1-in-10,000 so far, which is good enough for me).

The question is:

this bug only occurred with a probability likely between 1/12 and 1/20 (which I determined from video of our automatic tests of the program, which involved 185 opportunities for the bug to occur. No pattern of occurrence has been discerned). I've never had to deal with a bug like this, and so I'm wondering: given the bug's apparent randomness, and the fix, what was happening? A race condition between the bitmap rendering that Windows then upscales for "high DPI" and the functions that lay out the toolbar?

Erin Anne
  • 141
  • 1
  • 6

1 Answers1

1

Windows 10 extended the concept of DPI awareness. Before, DPI awareness was a per-process setting, but now it's a per-thread concept. The MSDN docs wording is now a little hard to decipher, but it sounds like calling SetProcessDPIAwareness (which I expect the legacy app is doing) affects only calling thread (despite "Process" being in the name).

Theory #1: Perhaps your toolbar window is sometimes created on a thread with DPI awareness and sometimes it's created on a different thread.

Theory #2: There is a race between the app calling SetProcessDPIAware and some UI code caching a display metric which is later used to paint the toolbar window. Depending on who wins the race, you might get the incorrect behavior.

The docs suggest that older applications (a.k.a., legacy applications) set DPI awareness for the entire process using the manifest setting. I believe this would ensure that the setting is applied to all threads in the process, and it should happen before any user code runs, so there should be no race. Since disabling scaling seems to solve the problem, and setting the DPI awareness should be roughly equivalent to that (in effect), I'd expect that to solve the problem if either theory is correct.

The documentation for SetProcessDpiAware explains how to set DPI awareness with a manifest.

Adrian McCarthy
  • 45,555
  • 16
  • 123
  • 175
  • I *think* I understand this in your first paragraph, but just to be sure--I'm using the compatibility flags in either the shortcut or for the "properties" of the EXE itself (as get set in the registry) to disable DPI awareness, so you think that SetProcessDPIAwareness gets called because that's set? Manifests will probably come in future versions, but unfortunately the next version is probably going to be a while. – Erin Anne May 19 '17 at 03:34
  • Not quite. Disabling scaling in the properties doesn't cause SetProcessDPIAwareness to be called, but it does have a similar effect. Since it appears to always work when you manually disable scaling, I suspect the code is written to understand high DPI. Since it works sometimes when you don't disable scaling, I think the program attempts to tell the OS that it's DPI aware (by calling SetProcessDPIAware or SetProcessDPIAwareness), but either it's not being applied to all threads (Windows 10 changed that) or there's a race condition (so it sometimes tells the OS a bit too late). – Adrian McCarthy May 19 '17 at 16:29
  • The application's code definitely doesn't understand High DPI (or completely understand it), but all the GUI elements are standard Win32 so I don't know what happens there. We also haven't run it on any of the OSes between Win 7 and Win 10 so I wouldn't be able to pin down what OS versions exhibit the bug (except that 7 doesn't and 10 does). One of the other reasons we considered High DPI being a problem was that the automatic testing started clicking in the wrong place when trying to interact with the menu bar...race condition is seeming more credible now. – Erin Anne May 19 '17 at 17:56