调试时使用Win32.MoveWindow调整大小的Windows应用程序缩放错误125%



我使用2560x1440显示器,在Windows上的比例为10到125%。我在Visual Studio 2019中编写了一个C#单元测试用例,它调用DLL来1(找到各种应用程序(记事本、写字板等(的窗口句柄,2(将它们调整为监视器大小的100%以下。我用Win32.MoveWindow来移动,就像这样:

//    MoveWindow(hWnd, left, top, width, height)
Win32.MoveWindow(hWnd, 0, 0, 2500, 1400, true);

问题是,在单元测试中进行调试时,Windows10将2500和1400像素数放大125%,并将窗口移动到更大的大小。然后,窗口挂在屏幕的底部和右侧边缘。

相比之下,当我从框架Windows窗体应用程序运行相同的DLL代码时(在不调试的情况下(,代码运行良好,Windows可以正确调整记事本和写字板应用程序窗口的大小。

在这两种情况下,我都将相同的数字传递给Win32.MoveWindow

如果重要的话,对于DLL代码,我已经为调用Win32.MoveWindow的DLL代码尝试了app.config和app.manifest设置的无休止组合,但没有成功。

对于骨架表单应用程序,我尝试了4.6.1和4.7.2,在app.config中没有DPI设置,并且在app.manifest中启用了"dpiAware=true">

唯一有区别的是我是否在调试。当我执行MoveWindow操作时,我本以为我可以使用操作系统屏幕边界的正常屏幕像素,但在调试时效果不佳。

使用Win32.MoveWindow调整其他应用程序大小的正确方法是什么?我的应用程序是否应该确定当前的缩放因子,然后缩小我传递给Win32.MoveWindow的数字?(例如,对于125%的缩放,我会将2500/1.25=2000传递给Win32.MoveWindow。(

调试器是否应该像这样干扰缩放和大小调整?这是已知的问题吗?

@selbie的评论完全正确。他甚至好心地在我的一句关键语句中加粗了一行,以引起我的注意。@selbie让我很容易解决这个问题。我在下面包含了我的测试代码片段。

Windows行为

正如@selbie所指出的,如果在辅助功能设置中启用125%的缩放以使一切变得更大,Windows会向有意识和无意识的进程报告不同的屏幕大小。

对于DPI感知进程,Windows将报告2560x1440,因为他们应该缩小思维规模,以便Windows可以将其放大125%,以生成清晰的文本等。

对于不支持DPI的进程,Windows将向调用方报告2048x1152,因此调用方认为屏幕比实际屏幕小。Windows将调用方的订单放大125%,以使调用方的大小适合硬件屏幕大小(2560x1440(。

问题

我遇到的问题是,我的单元测试代码(DPI不知道(使用的是DLL代码中的硬件大小(2560x1440(,该代码是从数据库而非操作系统获得的,所以当Windows放大它时,我重新定位的窗口比硬件屏幕大。

当在DPI感知的Forms应用程序中使用相同的DLL时,Windows允许一切(不产生网络扩展(,并且重新定位的窗口适合硬件屏幕。

解决方案

第一个解决方案是让您的呼叫进程DPI感知,这样您就可以在代码中使用硬件屏幕大小。通过在NET 4.6及更高版本中调用Win32 API来完成此操作。这是我在单元测试中用来使其正常工作的方法。

[STAThread]
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern bool SetProcessDPIAware();
static void Main() {
if (Environment.OSVersion.Version.Major >= 6) SetProcessDPIAware();
... either ConsoleApp code or Windows.Forms code here
}

第二种解决方案是在EXEapp.manifest文件中启用DPI感知。只需取消注释Visual Studio中AddNew生成的默认app.manifest文件中的默认XML代码。

APP.MANIFEST FILE
<application xmlns = "urn:schemas-microsoft-com:asm.v3" >
<windowsSettings >
<dpiAware xmlns = "http://schemas.microsoft.com/SMI/2005/WindowsSettings" >
true </dpiAware >
</windowsSettings >
</application >

在NET 4.7及更高版本中,您还可以在app.config文件中使用新的PerMonitorV2DPI设置,而不是"app.manifest"文件。这显然可以让您对不同的显示器使用不同的DPI感知。(我还没有尝试过,但为了完整起见,我在这里提到了它。(

<configuration>
<!--requires NET 4.7, and the default is false />
<System.Windows.Forms.ApplicationConfigurationSection>
<add key="DpiAwareness" value="PerMonitorV2" />
<add key="EnableWindowsFormsHighDpiAutoResizing" value="false" />
</System.Windows.Forms.ApplicationConfigurationSection>
</configuration>

最新更新