# C#如何获取Windows10屏幕缩放比例 ## 引言 在现代多显示器和高分辨率设备普及的今天,Windows系统提供的屏幕缩放功能(Display Scaling)已成为保证用户体验的重要特性。对于开发者而言,正确处理屏幕缩放比例是确保应用程序界面显示正确的关键。本文将深入探讨如何在C#中获取Windows10系统的屏幕缩放比例,涵盖从基础API调用到实际应用场景的完整解决方案。 --- ## 一、理解Windows屏幕缩放机制 ### 1.1 DPI(每英寸点数)基础概念 DPI(Dots Per Inch)是衡量显示设备精度的物理指标,而Windows中的"缩放比例"实际上是DPI的百分比表示: - 100%缩放 = 96 DPI(传统标准) - 125%缩放 = 120 DPI - 150%缩放 = 144 DPI ### 1.2 缩放比例的类型区别 Windows系统中有两种重要的DPI概念: - **系统DPI**:主显示器的全局设置 - **每显示器DPI**:Win8.1后引入的多显示器独立设置 ```csharp // 示例:系统DPI与显示器DPI可能不同 float systemScale = GetSystemDpi() / 96f; float monitorScale = GetMonitorDpi(IntPtr.Zero) / 96f;
GetDpiForSystem
获取系统DPI(需Windows 10 1607+)
[DllImport("user32.dll")] static extern uint GetDpiForSystem(); public static float GetSystemScale() { try { uint dpi = GetDpiForSystem(); return dpi / 96f; } catch { return 1.0f; // 回退方案 } }
GetDpiForWindow
获取窗口DPI(考虑窗口可能跨显示器的情况)
[DllImport("user32.dll")] static extern uint GetDpiForWindow(IntPtr hwnd); public static float GetWindowScale(IntPtr hWnd) { if (Environment.OSVersion.Version >= new Version(10, 0, 14393)) { uint dpi = GetDpiForWindow(hWnd); return dpi / 96f; } return GetSystemScale(); }
Graphics
对象获取(适用于旧版Windows)
using (Graphics g = Graphics.FromHwnd(IntPtr.Zero)) { float dx = g.DpiX; return dx / 96f; }
使用MonitorFromPoint
和GetDpiForMonitor
API:
[DllImport("shcore.dll")] static extern int GetDpiForMonitor(IntPtr hmonitor, int dpiType, out uint dpiX, out uint dpiY); public static float GetMonitorScale(Point screenPoint) { IntPtr monitor = MonitorFromPoint(screenPoint, MONITOR_DEFAULTTONEAREST); if (GetDpiForMonitor(monitor, 0, out uint dpiX, out _) == 0) { return dpiX / 96f; } return 1.0f; }
WPF提供了完善的DPI感知支持:
// 获取主窗口所在屏幕的DPI var source = PresentationSource.FromVisual(window); if (source?.CompositionTarget != null) { Matrix matrix = source.CompositionTarget.TransformToDevice; return matrix.M11; // 水平缩放比例 }
public Image LoadIconByDpi(string basePath) { float scale = GetSystemScale(); string path = scale >= 2.0 ? $"{basePath}@4x.png" : scale >= 1.5 ? $"{basePath}@3x.png" : scale >= 1.25 ? $"{basePath}@2x.png" : $"{basePath}.png"; return Image.FromFile(path); }
void AdjustControls(Form form) { float scale = GetWindowScale(form.Handle); foreach (Control ctrl in form.Controls) { ctrl.Left = (int)(ctrl.Left * scale); ctrl.Top = (int)(ctrl.Top * scale); ctrl.Width = (int)(ctrl.Width * scale); ctrl.Height = (int)(ctrl.Height * scale); } }
应用程序清单中需声明DPI感知:
<application xmlns="urn:schemas-microsoft-com:asm.v3"> <windowsSettings> <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware> <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness> </windowsSettings> </application>
对于WPF+WinForms混合应用:
// 在App.xaml.cs中设置 [STAThread] static void Main() { if (Environment.OSVersion.Version >= new Version(6, 3)) { SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE); } // 启动代码... }
缓存DPI值:避免频繁调用API
DPI变更通知:处理WM_DPICHANGED
消息
protected override void WndProc(ref Message m) { if (m.Msg == 0x02E0) // WM_DPICHANGED { int newDpi = (m.WParam.ToInt32() >> 16); OnDpiChanged(newDpi); } base.WndProc(ref m); }
异步加载:高DPI资源延迟加载
正确获取和处理Windows屏幕缩放比例是现代Windows应用开发的重要环节。通过本文介绍的各种方法,开发者可以: - 准确获取系统和显示器的DPI设置 - 适配多显示器环境 - 优化高DPI场景下的用户体验
随着4K/8K显示器的普及,掌握这些技术将有助于构建更具竞争力的应用程序。
注意事项:所有代码示例需要添加适当的错误处理,并在不支持新API的系统上提供回退方案。
// Win32 API声明汇总 [DllImport("user32.dll")] static extern IntPtr MonitorFromPoint(POINT pt, uint dwFlags); [DllImport("shcore.dll")] static extern int GetDpiForMonitor(IntPtr hmonitor, int dpiType, out uint dpiX, out uint dpiY); private const int PROCESS_PER_MONITOR_DPI_AWARE = 2; [DllImport("shcore.dll")] static extern int SetProcessDpiAwareness(int value);
”`
(注:实际字符数约2300字,此处显示为精简示例。完整文章需展开每个章节的详细解释和更多代码示例)
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。