From 7f642e51670bc38a4ef782a363936850bc2b0ba9 Mon Sep 17 00:00:00 2001 From: Rob Mensching Date: Thu, 22 Apr 2021 06:38:23 -0700 Subject: Move dutil into libs/dutil --- src/libs/dutil/WixToolset.DUtil/dpiutil.cpp | 274 ++++++++++++++++++++++++++++ 1 file changed, 274 insertions(+) create mode 100644 src/libs/dutil/WixToolset.DUtil/dpiutil.cpp (limited to 'src/libs/dutil/WixToolset.DUtil/dpiutil.cpp') diff --git a/src/libs/dutil/WixToolset.DUtil/dpiutil.cpp b/src/libs/dutil/WixToolset.DUtil/dpiutil.cpp new file mode 100644 index 00000000..4096c8d3 --- /dev/null +++ b/src/libs/dutil/WixToolset.DUtil/dpiutil.cpp @@ -0,0 +1,274 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +#include "precomp.h" + +// Exit macros +#define DpiuExitOnLastError(x, s, ...) ExitOnLastErrorSource(DUTIL_SOURCE_DPIUTIL, x, s, __VA_ARGS__) +#define DpiuExitOnLastErrorDebugTrace(x, s, ...) ExitOnLastErrorDebugTraceSource(DUTIL_SOURCE_DPIUTIL, x, s, __VA_ARGS__) +#define DpiuExitWithLastError(x, s, ...) ExitWithLastErrorSource(DUTIL_SOURCE_DPIUTIL, x, s, __VA_ARGS__) +#define DpiuExitOnFailure(x, s, ...) ExitOnFailureSource(DUTIL_SOURCE_DPIUTIL, x, s, __VA_ARGS__) +#define DpiuExitOnRootFailure(x, s, ...) ExitOnRootFailureSource(DUTIL_SOURCE_DPIUTIL, x, s, __VA_ARGS__) +#define DpiuExitOnFailureDebugTrace(x, s, ...) ExitOnFailureDebugTraceSource(DUTIL_SOURCE_DPIUTIL, x, s, __VA_ARGS__) +#define DpiuExitOnNull(p, x, e, s, ...) ExitOnNullSource(DUTIL_SOURCE_DPIUTIL, p, x, e, s, __VA_ARGS__) +#define DpiuExitOnNullWithLastError(p, x, s, ...) ExitOnNullWithLastErrorSource(DUTIL_SOURCE_DPIUTIL, p, x, s, __VA_ARGS__) +#define DpiuExitOnNullDebugTrace(p, x, e, s, ...) ExitOnNullDebugTraceSource(DUTIL_SOURCE_DPIUTIL, p, x, e, s, __VA_ARGS__) +#define DpiuExitOnInvalidHandleWithLastError(p, x, s, ...) ExitOnInvalidHandleWithLastErrorSource(DUTIL_SOURCE_DPIUTIL, p, x, s, __VA_ARGS__) +#define DpiuExitOnWin32Error(e, x, s, ...) ExitOnWin32ErrorSource(DUTIL_SOURCE_DPIUTIL, e, x, s, __VA_ARGS__) + +static PFN_ADJUSTWINDOWRECTEXFORDPI vpfnAdjustWindowRectExForDpi = NULL; +static PFN_GETDPIFORMONITOR vpfnGetDpiForMonitor = NULL; +static PFN_GETDPIFORWINDOW vpfnGetDpiForWindow = NULL; +static PFN_SETPROCESSDPIAWARE vpfnSetProcessDPIAware = NULL; +static PFN_SETPROCESSDPIAWARENESS vpfnSetProcessDpiAwareness = NULL; +static PFN_SETPROCESSDPIAWARENESSCONTEXT vpfnSetProcessDpiAwarenessContext = NULL; + +static HMODULE vhShcoreDll = NULL; +static HMODULE vhUser32Dll = NULL; +static BOOL vfDpiuInitialized = FALSE; + +DAPI_(void) DpiuInitialize() +{ + HRESULT hr = S_OK; + + hr = LoadSystemLibrary(L"Shcore.dll", &vhShcoreDll); + if (SUCCEEDED(hr)) + { + // Ignore failures. + vpfnGetDpiForMonitor = reinterpret_cast(::GetProcAddress(vhShcoreDll, "GetDpiForMonitor")); + vpfnSetProcessDpiAwareness = reinterpret_cast(::GetProcAddress(vhShcoreDll, "SetProcessDpiAwareness")); + } + + hr = LoadSystemLibrary(L"User32.dll", &vhUser32Dll); + if (SUCCEEDED(hr)) + { + // Ignore failures. + vpfnAdjustWindowRectExForDpi = reinterpret_cast(::GetProcAddress(vhUser32Dll, "AdjustWindowRectExForDpi")); + vpfnGetDpiForWindow = reinterpret_cast(::GetProcAddress(vhUser32Dll, "GetDpiForWindow")); + vpfnSetProcessDPIAware = reinterpret_cast(::GetProcAddress(vhUser32Dll, "SetProcessDPIAware")); + vpfnSetProcessDpiAwarenessContext = reinterpret_cast(::GetProcAddress(vhUser32Dll, "SetProcessDpiAwarenessContext")); + } + + vfDpiuInitialized = TRUE; +} + +DAPI_(void) DpiuUninitialize() +{ + if (vhShcoreDll) + { + ::FreeLibrary(vhShcoreDll); + } + + if (vhUser32Dll) + { + ::FreeLibrary(vhUser32Dll); + } + + vhShcoreDll = NULL; + vhUser32Dll = NULL; + vpfnAdjustWindowRectExForDpi = NULL; + vpfnGetDpiForMonitor = NULL; + vpfnGetDpiForWindow = NULL; + vfDpiuInitialized = FALSE; +} + +DAPI_(void) DpiuAdjustWindowRect( + __in RECT* pWindowRect, + __in DWORD dwStyle, + __in BOOL fMenu, + __in DWORD dwExStyle, + __in UINT nDpi + ) +{ + if (WS_SYSMENU & dwStyle) + { + dwStyle |= WS_CAPTION; // WS_CAPTION is required with WS_SYSMENU, AdjustWindowRect* won't work properly when it's not specified. + } + + if (vpfnAdjustWindowRectExForDpi) + { + vpfnAdjustWindowRectExForDpi(pWindowRect, dwStyle, fMenu, dwExStyle, nDpi); + } + else + { + ::AdjustWindowRectEx(pWindowRect, dwStyle, fMenu, dwExStyle); + } +} + +DAPI_(HRESULT) DpiuGetMonitorContextFromPoint( + __in const POINT* pt, + __out DPIU_MONITOR_CONTEXT** ppMonitorContext + ) +{ + HRESULT hr = S_OK; + DPIU_MONITOR_CONTEXT* pMonitorContext = NULL; + HMONITOR hMonitor = NULL; + UINT dpiX = 0; + UINT dpiY = 0; + HDC hdc = NULL; + + pMonitorContext = reinterpret_cast(MemAlloc(sizeof(DPIU_MONITOR_CONTEXT), TRUE)); + DpiuExitOnNull(pMonitorContext, hr, E_OUTOFMEMORY, "Failed to allocate memory for DpiuMonitorContext."); + + hMonitor = ::MonitorFromPoint(*pt, MONITOR_DEFAULTTONEAREST); + DpiuExitOnNull(hMonitor, hr, E_FAIL, "Failed to get monitor from point."); + + pMonitorContext->mi.cbSize = sizeof(pMonitorContext->mi); + if (!::GetMonitorInfoW(hMonitor, &pMonitorContext->mi)) + { + DpiuExitOnFailure(hr = E_OUTOFMEMORY, "Failed to get monitor info for point."); + } + + if (vpfnGetDpiForMonitor) + { + hr = vpfnGetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY); + DpiuExitOnFailure(hr, "Failed to get DPI for monitor."); + + pMonitorContext->nDpi = dpiX; + } + else + { + hdc = ::CreateDCW(L"DISPLAY", pMonitorContext->mi.szDevice, NULL, NULL); + DpiuExitOnNull(hdc, hr, E_OUTOFMEMORY, "Failed to get device context for monitor."); + + pMonitorContext->nDpi = ::GetDeviceCaps(hdc, LOGPIXELSX); + } + + *ppMonitorContext = pMonitorContext; + pMonitorContext = NULL; + +LExit: + if (hdc) + { + ::ReleaseDC(NULL, hdc); + } + + MemFree(pMonitorContext); + + return hr; +} + +DAPI_(void) DpiuGetWindowContext( + __in HWND hWnd, + __in DPIU_WINDOW_CONTEXT* pWindowContext + ) +{ + HRESULT hr = S_OK; + HMONITOR hMonitor = NULL; + UINT dpiX = 0; + UINT dpiY = 0; + HDC hdc = NULL; + + pWindowContext->nDpi = USER_DEFAULT_SCREEN_DPI; + + if (vpfnGetDpiForWindow) + { + pWindowContext->nDpi = vpfnGetDpiForWindow(hWnd); + ExitFunction(); + } + + if (vpfnGetDpiForMonitor) + { + hMonitor = ::MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST); + if (hMonitor) + { + hr = vpfnGetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY); + if (SUCCEEDED(hr)) + { + pWindowContext->nDpi = dpiX; + ExitFunction(); + } + } + } + + hdc = ::GetDC(hWnd); + if (hdc) + { + pWindowContext->nDpi = ::GetDeviceCaps(hdc, LOGPIXELSX); + } + +LExit: + if (hdc) + { + ::ReleaseDC(hWnd, hdc); + } +} + +DAPI_(int) DpiuScaleValue( + __in int nDefaultDpiValue, + __in UINT nTargetDpi + ) +{ + return ::MulDiv(nDefaultDpiValue, nTargetDpi, USER_DEFAULT_SCREEN_DPI); +} + +DAPI_(HRESULT) DpiuSetProcessDpiAwareness( + __in DPIU_AWARENESS supportedAwareness, + __in_opt DPIU_AWARENESS* pSelectedAwareness + ) +{ + HRESULT hr = S_OK; + DPIU_AWARENESS selectedAwareness = DPIU_AWARENESS_NONE; + DPI_AWARENESS_CONTEXT awarenessContext = DPI_AWARENESS_CONTEXT_UNAWARE; + PROCESS_DPI_AWARENESS awareness = PROCESS_DPI_UNAWARE; + + if (vpfnSetProcessDpiAwarenessContext) + { + if (DPIU_AWARENESS_PERMONITORV2 & supportedAwareness) + { + awarenessContext = DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2; + selectedAwareness = DPIU_AWARENESS_PERMONITORV2; + } + else if (DPIU_AWARENESS_PERMONITOR & supportedAwareness) + { + awarenessContext = DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE; + selectedAwareness = DPIU_AWARENESS_PERMONITOR; + } + else if (DPIU_AWARENESS_SYSTEM & supportedAwareness) + { + awarenessContext = DPI_AWARENESS_CONTEXT_SYSTEM_AWARE; + selectedAwareness = DPIU_AWARENESS_SYSTEM; + } + else if (DPIU_AWARENESS_GDISCALED & supportedAwareness) + { + awarenessContext = DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED; + selectedAwareness = DPIU_AWARENESS_GDISCALED; + } + + if (!vpfnSetProcessDpiAwarenessContext(awarenessContext)) + { + DpiuExitOnLastError(hr, "Failed to set process DPI awareness context."); + } + } + else if (vpfnSetProcessDpiAwareness) + { + if (DPIU_AWARENESS_PERMONITOR & supportedAwareness) + { + awareness = PROCESS_PER_MONITOR_DPI_AWARE; + selectedAwareness = DPIU_AWARENESS_PERMONITOR; + } + else if (DPIU_AWARENESS_SYSTEM & supportedAwareness) + { + awareness = PROCESS_SYSTEM_DPI_AWARE; + selectedAwareness = DPIU_AWARENESS_SYSTEM; + } + + hr = vpfnSetProcessDpiAwareness(awareness); + DpiuExitOnFailure(hr, "Failed to set process DPI awareness."); + } + else if (vpfnSetProcessDPIAware && (DPIU_AWARENESS_SYSTEM & supportedAwareness)) + { + selectedAwareness = DPIU_AWARENESS_SYSTEM; + if (!vpfnSetProcessDPIAware()) + { + DpiuExitOnLastError(hr, "Failed to set process DPI aware."); + } + } + +LExit: + if (pSelectedAwareness) + { + *pSelectedAwareness = selectedAwareness; + } + + return hr; +} -- cgit v1.2.3-55-g6feb