I posted earlier that you shouldn’t call SetProcessDPIAware – and if you shouldn’t call it, why have it? I’ve had some interest in this post, and looking at it again, I didn’t do a great job of explaining it.
- Programmers don’t expect DPI to change.
- This creates bugs when the DPI changes.
- SetProcessDPIAware causes the DPI to change.
Generally, you need to reboot to have the DPI change. But now, there are two scenarios where it can change right out from underneath you. SetProcessDPIAware is one of them – the other is when the aero glass/DWM encounters performance problems due to a misbehaving app and decides to bail. You don’t have much control over the second one (which should also be very rare), but you do have control over SetProcessDPIAware (which happens every time you launch).
So this is a problem, of course – one that you’re choosing to embrace if you call SetProcessDPIAware. The correct solution is to keep a cache of the DPI (like you’ve always done), and also cache what GetProcessDPIAware and DwmIsCompositionEnabled return. When either of these are different from when you built your DPI cache, refresh your cache. But programmers just aren’t doing this. Even some of the basic MSFT dlls aren’t doing this right yet – we’re fixing these issues, of course. But perhaps someone you call won’t. It’s important to do this before creating other UI, but who knows when you’ve managed to do it early enough? Perhaps some accessibility application is hooking your process and it’s not doing it right and then performs incorrect physical to logical DPI conversions. Point being, why ask for more trouble when you don’t need to call SetProcessDPIAware?
You can achieve the important bit that you get from calling SetProcessDPIAware by putting an entry in your manifest. This allows the flag to be set so early on that nothing has cached the DPI yet. Whew. Well, then I guess I can just stop worrying about DPI changes for everything outside my code. Cool. So why would I call SetProcessDPIAware again? The best remaining answer I can see would be "because you don’t control the executable that would need to have the dpiAware manifest entry." Whoa – why would that be? Perhaps because you’re being loaded via extensibility points – then don’t mess with the process! Who knows if it (and other extensions) are high DPI aware? So just use the manifest entry instead.
So when does it make sense to call (or even have) SetProcessDPIAware? Perhaps because you’re being run by rundll32? Personally, I would write my own loader code and put in the manifest. Are we really exposing this function just for rundll32-type scenarios? There’s a real cost to creating, documenting and supporting APIs – maybe this one just shouldn’t exist.