如何跟踪 WPF 中 WM_DPICHANGED 发送的最后一个 DPI?

问题描述 投票:0回答:1

我想根据可用的屏幕 DPI 缩放我的 WPF 应用程序。我知道每个显示器 DPI 感知可用,但这与我想要实现的目标完全不同。我想禁用我的 WPF 应用程序的缩放,即使 Windows 在每个监视器或系统范围内具有一定的缩放比例。我知道如果系统缩放被禁用,那么 Windows 决定使用什么缩放因子是我的主要目标。

要在启动时根据初始 DPI 缩放 WPF 应用程序,我需要获取当前 DPI。并且窗口的当前 DPI 始终等于 WM_DPICHANGED 发送的最后一个 DPI。

这是我的代码:

 public partial class MainWindow : Window
    {
        private HwndSource hwndSource;   
        public MainWindow()
        {
           InitializeComponent();
        }
        protected override void OnSourceInitialized(EventArgs e)
        {    
            hwndSource = PresentationSource.FromVisual((Visual) sender) as HwndSource;
            hwndSource.AddHook(new HwndSourceHook(WndProc));
        }
        private const int WM_DPICHANGED = 0x02E0;
        private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            if (msg == WM_DPICHANGED)
            {
                handled = true;
            }
            return IntPtr.Zero;
        }
    }

看看这个代码。这就是我禁用系统缩放的方法。但不利因素是,当我以不同的屏幕分辨率 (DPI) 重新启动应用程序时,未检测到初始 DPI。它在启动时没有接收到 WM_DPICHANGED,并且对初始渲染没有影响。

我只需要找到 WM_DPICHANGED 发送的最后一个 DPI 即可。如果我以某种方式跟踪它,那么我可以根据它轻松扩展我的应用程序。所以,不存在初始 DPI 问题。

我知道,我说了很多,整个问题很混乱。因此,我在这里总结一下这个问题以及我想要的答案。我把它分成两部分 -

  1. 如何追踪WM_DPICHANGED发送的Last DPI?

  2. 获取最后一个 WM_DPICHANGED 后,想要将其应用到我的 WPF 界面缩放中,以便检测到初始 DPI,并且我的应用程序自行缩放,而不是由系统/操作系统缩放。

Stack Overflow 中提供了很多基于 C# 的解决方案,但它们都不起作用,而且相当旧的解决方案在当前的 Windows 11 环境中不起作用。请尝试添加/修改我给定的基于 Win32 的代码。如果每个步骤描述正确,也欢迎其他基于纯 C# 的代码解决方案。

c# wpf winapi scaling dpi
1个回答
0
投票

尝试与 WPF 争夺 DPI 控制权,您将进入一个痛苦的世界。 我建议 您遇到 X-Y 问题并且需要发布有关您实际问题的问题,或者使用正常的 WPF 支持高 DPI。

无论如何,过滤

WM_DPICHANGED
(设置
handled = true
以阻止 WPF 处理消息)不会禁用系统缩放,它会阻止 WPF 侦听 DPI 信息。 系统缩放 清单
<dpiAware>
元素或通过
Set*DpiAwareness*
函数(WPF 可能正在调用)的影响。 详细信息取决于您的应用程序的清单以及 WPF/.Net/dotnet 的版本以及您正在使用的 Windows。

WM_DPICHANGED
提供新的 DPI 作为参数。 具体来说,就是 wParam 的低位字。

        private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            if (msg == WM_DPICHANGED)
            {
                handled = true;
                var dpi = unchecked((int)(wParam & 0xffff));
                Console.WriteLine($"New DPI: {dpi}");
            }
            return IntPtr.Zero;
        }
© www.soinside.com 2019 - 2024. All rights reserved.