Backends: Win32: Rework to handle certains Windows 8.1/10 features without a manifest. (#4200, #4191)

This commit is contained in:
ocornut 2021-06-08 18:35:35 +02:00
parent 020d1ced1d
commit b66529fe3e
2 changed files with 48 additions and 32 deletions

View File

@ -22,7 +22,7 @@
#include <dwmapi.h> #include <dwmapi.h>
// Configuration flags to add in your imconfig.h file: // Configuration flags to add in your imconfig.h file:
//#define IMGUI_IMPL_WIN32_DISABLE_GAMEPAD // Disable gamepad support (this used to be meaningful before <1.81) but we know load XInput dynamically so the option is less relevant now. //#define IMGUI_IMPL_WIN32_DISABLE_GAMEPAD // Disable gamepad support. This was meaningful before <1.81 but we now load XInput dynamically so the option is now less relevant.
// Using XInput for gamepad (will load DLL dynamically) // Using XInput for gamepad (will load DLL dynamically)
#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
@ -33,6 +33,7 @@ typedef DWORD (WINAPI *PFN_XInputGetState)(DWORD, XINPUT_STATE*);
// CHANGELOG // CHANGELOG
// (minor and older changes stripped away, please see git history for details) // (minor and older changes stripped away, please see git history for details)
// 2021-06-08: Fix ImGui_ImplWin32_EnableDpiAwareness() and ImGui_ImplWin32_GetDpiScaleForMonitor() to handle Windows 8.1/10 features without a manifest (per-monitor DPI, and properly calls SetProcessDpiAwareness() on 8.1).
// 2021-03-23: Inputs: Clearing keyboard down array when losing focus (WM_KILLFOCUS). // 2021-03-23: Inputs: Clearing keyboard down array when losing focus (WM_KILLFOCUS).
// 2021-02-18: Added ImGui_ImplWin32_EnableAlphaCompositing(). Non Visual Studio users will need to link with dwmapi.lib (MinGW/gcc: use -ldwmapi). // 2021-02-18: Added ImGui_ImplWin32_EnableAlphaCompositing(). Non Visual Studio users will need to link with dwmapi.lib (MinGW/gcc: use -ldwmapi).
// 2021-02-17: Fixed ImGui_ImplWin32_EnableDpiAwareness() attempting to get SetProcessDpiAwareness from shcore.dll on Windows 8 whereas it is only supported on Windows 8.1. // 2021-02-17: Fixed ImGui_ImplWin32_EnableDpiAwareness() attempting to get SetProcessDpiAwareness from shcore.dll on Windows 8 whereas it is only supported on Windows 8.1.
@ -410,21 +411,30 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA
// If you are trying to implement your own backend for your own engine, you may ignore that noise. // If you are trying to implement your own backend for your own engine, you may ignore that noise.
//--------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------
// Implement some of the functions and types normally declared in recent Windows SDK. // Perform our own check with RtlVerifyVersionInfo() instead of using functions from <VersionHelpers.h> as they
#if !defined(_versionhelpers_H_INCLUDED_) && !defined(_INC_VERSIONHELPERS) // require a manifest to be functional for checks above 8.1. See https://github.com/ocornut/imgui/issues/4200
static BOOL IsWindowsVersionOrGreater(WORD major, WORD minor, WORD sp) static BOOL _IsWindowsVersionOrGreater(WORD major, WORD minor, WORD)
{ {
OSVERSIONINFOEXW osvi = { sizeof(osvi), major, minor, 0, 0, { 0 }, sp, 0, 0, 0, 0 }; typedef LONG(WINAPI* PFN_RtlVerifyVersionInfo)(OSVERSIONINFOEXW*, ULONG, ULONGLONG);
DWORD mask = VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR; static PFN_RtlVerifyVersionInfo RtlVerifyVersionInfoFn = NULL;
ULONGLONG cond = ::VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL); if (RtlVerifyVersionInfoFn == NULL)
cond = ::VerSetConditionMask(cond, VER_MINORVERSION, VER_GREATER_EQUAL); if (HMODULE ntdllModule = ::GetModuleHandleA("ntdll.dll"))
cond = ::VerSetConditionMask(cond, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); RtlVerifyVersionInfoFn = (PFN_RtlVerifyVersionInfo)GetProcAddress(ntdllModule, "RtlVerifyVersionInfo");
return ::VerifyVersionInfoW(&osvi, mask, cond);
RTL_OSVERSIONINFOEXW versionInfo = { };
ULONGLONG conditionMask = 0;
versionInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);
versionInfo.dwMajorVersion = major;
versionInfo.dwMinorVersion = minor;
VER_SET_CONDITION(conditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL);
VER_SET_CONDITION(conditionMask, VER_MINORVERSION, VER_GREATER_EQUAL);
return (RtlVerifyVersionInfoFn(&versionInfo, VER_MAJORVERSION | VER_MINORVERSION, conditionMask) == 0) ? TRUE : FALSE;
} }
#define IsWindowsVistaOrGreater() IsWindowsVersionOrGreater(HIBYTE(0x0600), LOBYTE(0x0600), 0) // _WIN32_WINNT_VISTA
#define IsWindows8OrGreater() IsWindowsVersionOrGreater(HIBYTE(0x0602), LOBYTE(0x0602), 0) // _WIN32_WINNT_WIN8 #define _IsWindowsVistaOrGreater() _IsWindowsVersionOrGreater(HIBYTE(0x0600), LOBYTE(0x0600), 0) // _WIN32_WINNT_VISTA
#define IsWindows8Point1OrGreater() IsWindowsVersionOrGreater(HIBYTE(0x0603), LOBYTE(0x0603), 0) // _WIN32_WINNT_WINBLUE #define _IsWindows8OrGreater() _IsWindowsVersionOrGreater(HIBYTE(0x0602), LOBYTE(0x0602), 0) // _WIN32_WINNT_WIN8
#endif #define _IsWindows8Point1OrGreater() _IsWindowsVersionOrGreater(HIBYTE(0x0603), LOBYTE(0x0603), 0) // _WIN32_WINNT_WINBLUE
#define _IsWindows10OrGreater() _IsWindowsVersionOrGreater(HIBYTE(0x0A00), LOBYTE(0x0A00), 0) // _WIN32_WINNT_WINTHRESHOLD / _WIN32_WINNT_WIN10
#ifndef DPI_ENUMS_DECLARED #ifndef DPI_ENUMS_DECLARED
typedef enum { PROCESS_DPI_UNAWARE = 0, PROCESS_SYSTEM_DPI_AWARE = 1, PROCESS_PER_MONITOR_DPI_AWARE = 2 } PROCESS_DPI_AWARENESS; typedef enum { PROCESS_DPI_UNAWARE = 0, PROCESS_SYSTEM_DPI_AWARE = 1, PROCESS_PER_MONITOR_DPI_AWARE = 2 } PROCESS_DPI_AWARENESS;
@ -444,7 +454,7 @@ typedef DPI_AWARENESS_CONTEXT(WINAPI* PFN_SetThreadDpiAwarenessContext)(DPI_AWAR
// Helper function to enable DPI awareness without setting up a manifest // Helper function to enable DPI awareness without setting up a manifest
void ImGui_ImplWin32_EnableDpiAwareness() void ImGui_ImplWin32_EnableDpiAwareness()
{ {
// if (IsWindows10OrGreater()) // This needs a manifest to succeed. Instead we try to grab the function pointer! if (_IsWindows10OrGreater())
{ {
static HINSTANCE user32_dll = ::LoadLibraryA("user32.dll"); // Reference counted per-process static HINSTANCE user32_dll = ::LoadLibraryA("user32.dll"); // Reference counted per-process
if (PFN_SetThreadDpiAwarenessContext SetThreadDpiAwarenessContextFn = (PFN_SetThreadDpiAwarenessContext)::GetProcAddress(user32_dll, "SetThreadDpiAwarenessContext")) if (PFN_SetThreadDpiAwarenessContext SetThreadDpiAwarenessContextFn = (PFN_SetThreadDpiAwarenessContext)::GetProcAddress(user32_dll, "SetThreadDpiAwarenessContext"))
@ -453,7 +463,7 @@ void ImGui_ImplWin32_EnableDpiAwareness()
return; return;
} }
} }
if (IsWindows8Point1OrGreater()) if (_IsWindows8Point1OrGreater())
{ {
static HINSTANCE shcore_dll = ::LoadLibraryA("shcore.dll"); // Reference counted per-process static HINSTANCE shcore_dll = ::LoadLibraryA("shcore.dll"); // Reference counted per-process
if (PFN_SetProcessDpiAwareness SetProcessDpiAwarenessFn = (PFN_SetProcessDpiAwareness)::GetProcAddress(shcore_dll, "SetProcessDpiAwareness")) if (PFN_SetProcessDpiAwareness SetProcessDpiAwarenessFn = (PFN_SetProcessDpiAwareness)::GetProcAddress(shcore_dll, "SetProcessDpiAwareness"))
@ -474,23 +484,26 @@ void ImGui_ImplWin32_EnableDpiAwareness()
float ImGui_ImplWin32_GetDpiScaleForMonitor(void* monitor) float ImGui_ImplWin32_GetDpiScaleForMonitor(void* monitor)
{ {
UINT xdpi = 96, ydpi = 96; UINT xdpi = 96, ydpi = 96;
static BOOL bIsWindows8Point1OrGreater = IsWindows8Point1OrGreater(); if (_IsWindows8Point1OrGreater())
if (bIsWindows8Point1OrGreater)
{ {
static HINSTANCE shcore_dll = ::LoadLibraryA("shcore.dll"); // Reference counted per-process static HINSTANCE shcore_dll = ::LoadLibraryA("shcore.dll"); // Reference counted per-process
if (PFN_GetDpiForMonitor GetDpiForMonitorFn = (PFN_GetDpiForMonitor)::GetProcAddress(shcore_dll, "GetDpiForMonitor")) static PFN_GetDpiForMonitor GetDpiForMonitorFn = NULL;
if (GetDpiForMonitorFn == NULL && shcore_dll != NULL)
GetDpiForMonitorFn = (PFN_GetDpiForMonitor)::GetProcAddress(shcore_dll, "GetDpiForMonitor");
if (GetDpiForMonitorFn != NULL)
{
GetDpiForMonitorFn((HMONITOR)monitor, MDT_EFFECTIVE_DPI, &xdpi, &ydpi); GetDpiForMonitorFn((HMONITOR)monitor, MDT_EFFECTIVE_DPI, &xdpi, &ydpi);
IM_ASSERT(xdpi == ydpi); // Please contact me if you hit this assert!
return xdpi / 96.0f;
}
} }
#ifndef NOGDI #ifndef NOGDI
else
{
const HDC dc = ::GetDC(NULL); const HDC dc = ::GetDC(NULL);
xdpi = ::GetDeviceCaps(dc, LOGPIXELSX); xdpi = ::GetDeviceCaps(dc, LOGPIXELSX);
ydpi = ::GetDeviceCaps(dc, LOGPIXELSY); ydpi = ::GetDeviceCaps(dc, LOGPIXELSY);
::ReleaseDC(NULL, dc);
}
#endif
IM_ASSERT(xdpi == ydpi); // Please contact me if you hit this assert! IM_ASSERT(xdpi == ydpi); // Please contact me if you hit this assert!
::ReleaseDC(NULL, dc);
#endif
return xdpi / 96.0f; return xdpi / 96.0f;
} }
@ -513,7 +526,7 @@ float ImGui_ImplWin32_GetDpiScaleForHwnd(void* hwnd)
// (the Dwm* functions are Vista era functions but we are borrowing logic from GLFW) // (the Dwm* functions are Vista era functions but we are borrowing logic from GLFW)
void ImGui_ImplWin32_EnableAlphaCompositing(void* hwnd) void ImGui_ImplWin32_EnableAlphaCompositing(void* hwnd)
{ {
if (!IsWindowsVistaOrGreater()) if (!_IsWindowsVistaOrGreater())
return; return;
BOOL composition; BOOL composition;
@ -522,7 +535,7 @@ void ImGui_ImplWin32_EnableAlphaCompositing(void* hwnd)
BOOL opaque; BOOL opaque;
DWORD color; DWORD color;
if (IsWindows8OrGreater() || (SUCCEEDED(::DwmGetColorizationColor(&color, &opaque)) && !opaque)) if (_IsWindows8OrGreater() || (SUCCEEDED(::DwmGetColorizationColor(&color, &opaque)) && !opaque))
{ {
HRGN region = ::CreateRectRgn(0, 0, -1, -1); HRGN region = ::CreateRectRgn(0, 0, -1, -1);
DWM_BLURBEHIND bb = {}; DWM_BLURBEHIND bb = {};

View File

@ -47,6 +47,9 @@ Other Changes:
- Demo: Fixed requirement in 1.83 to link with imgui_demo.cpp if IMGUI_DISABLE_METRICS_WINDOW is not set. (#4171) - Demo: Fixed requirement in 1.83 to link with imgui_demo.cpp if IMGUI_DISABLE_METRICS_WINDOW is not set. (#4171)
Normally the right way to disable compiling the demo is to set IMGUI_DISABLE_DEMO_WINDOWS, but we want to avoid Normally the right way to disable compiling the demo is to set IMGUI_DISABLE_DEMO_WINDOWS, but we want to avoid
implying that the file is required. implying that the file is required.
- Backends: Win32: Rework to handle certains Windows 8.1/10 features without a manifest. (#4200, #4191)
- ImGui_ImplWin32_GetDpiScaleForMonitor() will handle per-monitor DPI on Windows 10 without a manifest.
- ImGui_ImplWin32_EnableDpiAwareness() will call SetProcessDpiAwareness() fallback on Windows 8.1 without a manifest.
- Backends: OpenGL3: Handle GL_CLIP_ORIGIN on <4.5 contexts if "GL_ARB_clip_control" extension is detected. (#4170, #3998) - Backends: OpenGL3: Handle GL_CLIP_ORIGIN on <4.5 contexts if "GL_ARB_clip_control" extension is detected. (#4170, #3998)
- Examples: Updated all .vcxproj to VS2015 (toolset v140) to facilitate usage with vcpkg. - Examples: Updated all .vcxproj to VS2015 (toolset v140) to facilitate usage with vcpkg.
- Examples: SDL2: Accomodate for vcpkg install having headers in SDL2/SDL.h vs SDL.h. - Examples: SDL2: Accomodate for vcpkg install having headers in SDL2/SDL.h vs SDL.h.