aboutsummaryrefslogtreecommitdiff
path: root/src/libs/dutil/WixToolset.DUtil/dpiutil.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/dutil/WixToolset.DUtil/dpiutil.cpp')
-rw-r--r--src/libs/dutil/WixToolset.DUtil/dpiutil.cpp274
1 files changed, 274 insertions, 0 deletions
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 @@
1// 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.
2
3#include "precomp.h"
4
5// Exit macros
6#define DpiuExitOnLastError(x, s, ...) ExitOnLastErrorSource(DUTIL_SOURCE_DPIUTIL, x, s, __VA_ARGS__)
7#define DpiuExitOnLastErrorDebugTrace(x, s, ...) ExitOnLastErrorDebugTraceSource(DUTIL_SOURCE_DPIUTIL, x, s, __VA_ARGS__)
8#define DpiuExitWithLastError(x, s, ...) ExitWithLastErrorSource(DUTIL_SOURCE_DPIUTIL, x, s, __VA_ARGS__)
9#define DpiuExitOnFailure(x, s, ...) ExitOnFailureSource(DUTIL_SOURCE_DPIUTIL, x, s, __VA_ARGS__)
10#define DpiuExitOnRootFailure(x, s, ...) ExitOnRootFailureSource(DUTIL_SOURCE_DPIUTIL, x, s, __VA_ARGS__)
11#define DpiuExitOnFailureDebugTrace(x, s, ...) ExitOnFailureDebugTraceSource(DUTIL_SOURCE_DPIUTIL, x, s, __VA_ARGS__)
12#define DpiuExitOnNull(p, x, e, s, ...) ExitOnNullSource(DUTIL_SOURCE_DPIUTIL, p, x, e, s, __VA_ARGS__)
13#define DpiuExitOnNullWithLastError(p, x, s, ...) ExitOnNullWithLastErrorSource(DUTIL_SOURCE_DPIUTIL, p, x, s, __VA_ARGS__)
14#define DpiuExitOnNullDebugTrace(p, x, e, s, ...) ExitOnNullDebugTraceSource(DUTIL_SOURCE_DPIUTIL, p, x, e, s, __VA_ARGS__)
15#define DpiuExitOnInvalidHandleWithLastError(p, x, s, ...) ExitOnInvalidHandleWithLastErrorSource(DUTIL_SOURCE_DPIUTIL, p, x, s, __VA_ARGS__)
16#define DpiuExitOnWin32Error(e, x, s, ...) ExitOnWin32ErrorSource(DUTIL_SOURCE_DPIUTIL, e, x, s, __VA_ARGS__)
17
18static PFN_ADJUSTWINDOWRECTEXFORDPI vpfnAdjustWindowRectExForDpi = NULL;
19static PFN_GETDPIFORMONITOR vpfnGetDpiForMonitor = NULL;
20static PFN_GETDPIFORWINDOW vpfnGetDpiForWindow = NULL;
21static PFN_SETPROCESSDPIAWARE vpfnSetProcessDPIAware = NULL;
22static PFN_SETPROCESSDPIAWARENESS vpfnSetProcessDpiAwareness = NULL;
23static PFN_SETPROCESSDPIAWARENESSCONTEXT vpfnSetProcessDpiAwarenessContext = NULL;
24
25static HMODULE vhShcoreDll = NULL;
26static HMODULE vhUser32Dll = NULL;
27static BOOL vfDpiuInitialized = FALSE;
28
29DAPI_(void) DpiuInitialize()
30{
31 HRESULT hr = S_OK;
32
33 hr = LoadSystemLibrary(L"Shcore.dll", &vhShcoreDll);
34 if (SUCCEEDED(hr))
35 {
36 // Ignore failures.
37 vpfnGetDpiForMonitor = reinterpret_cast<PFN_GETDPIFORMONITOR>(::GetProcAddress(vhShcoreDll, "GetDpiForMonitor"));
38 vpfnSetProcessDpiAwareness = reinterpret_cast<PFN_SETPROCESSDPIAWARENESS>(::GetProcAddress(vhShcoreDll, "SetProcessDpiAwareness"));
39 }
40
41 hr = LoadSystemLibrary(L"User32.dll", &vhUser32Dll);
42 if (SUCCEEDED(hr))
43 {
44 // Ignore failures.
45 vpfnAdjustWindowRectExForDpi = reinterpret_cast<PFN_ADJUSTWINDOWRECTEXFORDPI>(::GetProcAddress(vhUser32Dll, "AdjustWindowRectExForDpi"));
46 vpfnGetDpiForWindow = reinterpret_cast<PFN_GETDPIFORWINDOW>(::GetProcAddress(vhUser32Dll, "GetDpiForWindow"));
47 vpfnSetProcessDPIAware = reinterpret_cast<PFN_SETPROCESSDPIAWARE>(::GetProcAddress(vhUser32Dll, "SetProcessDPIAware"));
48 vpfnSetProcessDpiAwarenessContext = reinterpret_cast<PFN_SETPROCESSDPIAWARENESSCONTEXT>(::GetProcAddress(vhUser32Dll, "SetProcessDpiAwarenessContext"));
49 }
50
51 vfDpiuInitialized = TRUE;
52}
53
54DAPI_(void) DpiuUninitialize()
55{
56 if (vhShcoreDll)
57 {
58 ::FreeLibrary(vhShcoreDll);
59 }
60
61 if (vhUser32Dll)
62 {
63 ::FreeLibrary(vhUser32Dll);
64 }
65
66 vhShcoreDll = NULL;
67 vhUser32Dll = NULL;
68 vpfnAdjustWindowRectExForDpi = NULL;
69 vpfnGetDpiForMonitor = NULL;
70 vpfnGetDpiForWindow = NULL;
71 vfDpiuInitialized = FALSE;
72}
73
74DAPI_(void) DpiuAdjustWindowRect(
75 __in RECT* pWindowRect,
76 __in DWORD dwStyle,
77 __in BOOL fMenu,
78 __in DWORD dwExStyle,
79 __in UINT nDpi
80 )
81{
82 if (WS_SYSMENU & dwStyle)
83 {
84 dwStyle |= WS_CAPTION; // WS_CAPTION is required with WS_SYSMENU, AdjustWindowRect* won't work properly when it's not specified.
85 }
86
87 if (vpfnAdjustWindowRectExForDpi)
88 {
89 vpfnAdjustWindowRectExForDpi(pWindowRect, dwStyle, fMenu, dwExStyle, nDpi);
90 }
91 else
92 {
93 ::AdjustWindowRectEx(pWindowRect, dwStyle, fMenu, dwExStyle);
94 }
95}
96
97DAPI_(HRESULT) DpiuGetMonitorContextFromPoint(
98 __in const POINT* pt,
99 __out DPIU_MONITOR_CONTEXT** ppMonitorContext
100 )
101{
102 HRESULT hr = S_OK;
103 DPIU_MONITOR_CONTEXT* pMonitorContext = NULL;
104 HMONITOR hMonitor = NULL;
105 UINT dpiX = 0;
106 UINT dpiY = 0;
107 HDC hdc = NULL;
108
109 pMonitorContext = reinterpret_cast<DPIU_MONITOR_CONTEXT*>(MemAlloc(sizeof(DPIU_MONITOR_CONTEXT), TRUE));
110 DpiuExitOnNull(pMonitorContext, hr, E_OUTOFMEMORY, "Failed to allocate memory for DpiuMonitorContext.");
111
112 hMonitor = ::MonitorFromPoint(*pt, MONITOR_DEFAULTTONEAREST);
113 DpiuExitOnNull(hMonitor, hr, E_FAIL, "Failed to get monitor from point.");
114
115 pMonitorContext->mi.cbSize = sizeof(pMonitorContext->mi);
116 if (!::GetMonitorInfoW(hMonitor, &pMonitorContext->mi))
117 {
118 DpiuExitOnFailure(hr = E_OUTOFMEMORY, "Failed to get monitor info for point.");
119 }
120
121 if (vpfnGetDpiForMonitor)
122 {
123 hr = vpfnGetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY);
124 DpiuExitOnFailure(hr, "Failed to get DPI for monitor.");
125
126 pMonitorContext->nDpi = dpiX;
127 }
128 else
129 {
130 hdc = ::CreateDCW(L"DISPLAY", pMonitorContext->mi.szDevice, NULL, NULL);
131 DpiuExitOnNull(hdc, hr, E_OUTOFMEMORY, "Failed to get device context for monitor.");
132
133 pMonitorContext->nDpi = ::GetDeviceCaps(hdc, LOGPIXELSX);
134 }
135
136 *ppMonitorContext = pMonitorContext;
137 pMonitorContext = NULL;
138
139LExit:
140 if (hdc)
141 {
142 ::ReleaseDC(NULL, hdc);
143 }
144
145 MemFree(pMonitorContext);
146
147 return hr;
148}
149
150DAPI_(void) DpiuGetWindowContext(
151 __in HWND hWnd,
152 __in DPIU_WINDOW_CONTEXT* pWindowContext
153 )
154{
155 HRESULT hr = S_OK;
156 HMONITOR hMonitor = NULL;
157 UINT dpiX = 0;
158 UINT dpiY = 0;
159 HDC hdc = NULL;
160
161 pWindowContext->nDpi = USER_DEFAULT_SCREEN_DPI;
162
163 if (vpfnGetDpiForWindow)
164 {
165 pWindowContext->nDpi = vpfnGetDpiForWindow(hWnd);
166 ExitFunction();
167 }
168
169 if (vpfnGetDpiForMonitor)
170 {
171 hMonitor = ::MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);
172 if (hMonitor)
173 {
174 hr = vpfnGetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY);
175 if (SUCCEEDED(hr))
176 {
177 pWindowContext->nDpi = dpiX;
178 ExitFunction();
179 }
180 }
181 }
182
183 hdc = ::GetDC(hWnd);
184 if (hdc)
185 {
186 pWindowContext->nDpi = ::GetDeviceCaps(hdc, LOGPIXELSX);
187 }
188
189LExit:
190 if (hdc)
191 {
192 ::ReleaseDC(hWnd, hdc);
193 }
194}
195
196DAPI_(int) DpiuScaleValue(
197 __in int nDefaultDpiValue,
198 __in UINT nTargetDpi
199 )
200{
201 return ::MulDiv(nDefaultDpiValue, nTargetDpi, USER_DEFAULT_SCREEN_DPI);
202}
203
204DAPI_(HRESULT) DpiuSetProcessDpiAwareness(
205 __in DPIU_AWARENESS supportedAwareness,
206 __in_opt DPIU_AWARENESS* pSelectedAwareness
207 )
208{
209 HRESULT hr = S_OK;
210 DPIU_AWARENESS selectedAwareness = DPIU_AWARENESS_NONE;
211 DPI_AWARENESS_CONTEXT awarenessContext = DPI_AWARENESS_CONTEXT_UNAWARE;
212 PROCESS_DPI_AWARENESS awareness = PROCESS_DPI_UNAWARE;
213
214 if (vpfnSetProcessDpiAwarenessContext)
215 {
216 if (DPIU_AWARENESS_PERMONITORV2 & supportedAwareness)
217 {
218 awarenessContext = DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2;
219 selectedAwareness = DPIU_AWARENESS_PERMONITORV2;
220 }
221 else if (DPIU_AWARENESS_PERMONITOR & supportedAwareness)
222 {
223 awarenessContext = DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE;
224 selectedAwareness = DPIU_AWARENESS_PERMONITOR;
225 }
226 else if (DPIU_AWARENESS_SYSTEM & supportedAwareness)
227 {
228 awarenessContext = DPI_AWARENESS_CONTEXT_SYSTEM_AWARE;
229 selectedAwareness = DPIU_AWARENESS_SYSTEM;
230 }
231 else if (DPIU_AWARENESS_GDISCALED & supportedAwareness)
232 {
233 awarenessContext = DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED;
234 selectedAwareness = DPIU_AWARENESS_GDISCALED;
235 }
236
237 if (!vpfnSetProcessDpiAwarenessContext(awarenessContext))
238 {
239 DpiuExitOnLastError(hr, "Failed to set process DPI awareness context.");
240 }
241 }
242 else if (vpfnSetProcessDpiAwareness)
243 {
244 if (DPIU_AWARENESS_PERMONITOR & supportedAwareness)
245 {
246 awareness = PROCESS_PER_MONITOR_DPI_AWARE;
247 selectedAwareness = DPIU_AWARENESS_PERMONITOR;
248 }
249 else if (DPIU_AWARENESS_SYSTEM & supportedAwareness)
250 {
251 awareness = PROCESS_SYSTEM_DPI_AWARE;
252 selectedAwareness = DPIU_AWARENESS_SYSTEM;
253 }
254
255 hr = vpfnSetProcessDpiAwareness(awareness);
256 DpiuExitOnFailure(hr, "Failed to set process DPI awareness.");
257 }
258 else if (vpfnSetProcessDPIAware && (DPIU_AWARENESS_SYSTEM & supportedAwareness))
259 {
260 selectedAwareness = DPIU_AWARENESS_SYSTEM;
261 if (!vpfnSetProcessDPIAware())
262 {
263 DpiuExitOnLastError(hr, "Failed to set process DPI aware.");
264 }
265 }
266
267LExit:
268 if (pSelectedAwareness)
269 {
270 *pSelectedAwareness = selectedAwareness;
271 }
272
273 return hr;
274}