Fix refreshing display information in wxMSW in some special cases

Passing screen HDC to EnumDisplayMonitors() doesn't work if we do it
while a UAC prompt is shown or during log-off process, so change the
code enumerating the displays to use monitor-appropriate HDC instead.

This fixes the problem with losing display information entirely if
WM_SETTINGSCHANGE was generated when showing UAC prompt, as it happens
when "automatic background color" option is set under Windows 10.
This commit is contained in:
dasimx
2019-03-31 13:18:41 +02:00
committed by Vadim Zeitlin
parent 8927d7b092
commit f3c5923e1a

View File

@@ -594,10 +594,10 @@ void wxDisplayFactoryMSW::DoRefreshMonitors()
{
m_displays.clear();
// We need to pass a valid HDC here in order to get valid hdcMonitor in our
// callback.
ScreenHDC dc;
if ( !::EnumDisplayMonitors(dc, NULL, MultimonEnumProc, (LPARAM)this) )
// Note that we pass NULL as first parameter here because using screen HDC
// doesn't work reliably: notably, it doesn't enumerate any displays if
// this code is executed while a UAC prompt is shown or during log-off.
if ( !::EnumDisplayMonitors(NULL, NULL, MultimonEnumProc, (LPARAM)this) )
{
wxLogLastError(wxT("EnumDisplayMonitors"));
}
@@ -607,13 +607,24 @@ void wxDisplayFactoryMSW::DoRefreshMonitors()
BOOL CALLBACK
wxDisplayFactoryMSW::MultimonEnumProc(
HMONITOR hMonitor, // handle to display monitor
HDC hdcMonitor, // handle to monitor-appropriate device context
HDC /* hdcMonitor */, // handle to monitor-appropriate device context:
// not set due to our use of EnumDisplayMonitors(NULL, ...)
LPRECT WXUNUSED(lprcMonitor), // pointer to monitor intersection rectangle
LPARAM dwData) // data passed from EnumDisplayMonitors (this)
{
wxDisplayFactoryMSW *const self = (wxDisplayFactoryMSW *)dwData;
self->m_displays.push_back(wxDisplayInfo(hMonitor, wxGetHDCDepth(hdcMonitor)));
WinStruct<MONITORINFOEX> monInfo;
if ( !::GetMonitorInfo(hMonitor, &monInfo) )
{
wxLogLastError(wxT("GetMonitorInfo"));
}
HDC hdcMonitor = ::CreateDC(NULL, monInfo.szDevice, NULL, NULL);
const int hdcDepth = wxGetHDCDepth(hdcMonitor);
::DeleteDC(hdcMonitor);
self->m_displays.push_back(wxDisplayInfo(hMonitor, hdcDepth));
// continue the enumeration
return TRUE;