Office COM add-ins and DPI awareness: research and analysis
In the first blog of this series, I showed issues related to using several monitors with different DPIs. An Add-in Express pane, an Office custom task pane (CTP) and a modal form show different behavior when you move the pane’s parent window or the form to another monitor with different DPI.
To get an explanation of these results, let’s check resources available on the web.
When reading about multi-DPI environment and .NET, pay attention to the context: they invariably talk about an application, not class library. While an Office COM add-in is a class library, not application.
With this note in mind, the best introductory-level article about DPI and related APIs is at www.telerik.com. It describes many DPI-related details hyperlinking them to their sources. I strongly recommend reading section General Tips for Designing Scalable WinForms on that page. From that article, I use these details:
- Applications may set their DPI Awareness modes in several ways. Of these, an Office add-in developer shouldn’t rely on defining the DPI Awareness mode in the manifest or config file. This is because an Office application may handle these ways differently than a .NET application.
- Applications designed with WPF natively support DPI scaling. This is great. But you’ll understand this after you find all the issues that you need to solve when using Windows Forms.
- You must set the DPI mode before your window (HWND) has been created.
- The API SetThreadDpiAwarenessContext (description) allows specifying different DPI scaling modes when creating a window.
Another great article is about Office solutions, not .NET-based applications. From this article, I’ve chosen the description of the DPI Awareness modes available in Windows 10; you will need these modes often (if you go with Windows Forms controls):
- DPI unaware – Application always renders as if it is on a display with a DPI value of 96. When the DPI changes, application is bitmap stretched to the expected size on the primary and secondary displays.
- System DPI aware – Application detects the DPI of the primary connected monitor at Windows login but cannot respond to DPI changes. Application is bitmap stretched when moved to a new display with a different DPI.
- Per Monitor DPI aware – Application can redraw itself correctly when the DPI changes. Windows will send DPI notifications to top-level windows in the application so that it can redraw when the DPI changes.
- Per Monitor v2 – Application can redraw itself correctly when the DPI changes. Windows will send DPI notifications to both top-level and child windows so that the application can redraw when the DPI changes.
Also, that page reveals that Office does not support Per Monitor v2!
This explains the issues with custom task panes: being child windows, they cannot receive required events. The test add-in (see the previous blog) shows they are created as System DPI aware; accordingly, Windows scales them using bitmap stretching (see above) and whence the blurring. Since the CTP technology doesn’t provide a way for you to deal with DPI changes, you may choose to switch the host application’s Display Settings to Optimize for compatibility; this makes the whole application to be bitmap-stretched and your CTP doesn’t create the spotlight effect.
In the next blog I’ll look into why Windows forms (Windows.Forms.Form) and Add-in Express panes behave the way they behave.