[英]Windows apps resized with Win32.MoveWindow while debugging are scaled incorrectly by 125%
I use 2560x1440 monitors scaled on Windows 10 to 125%.我使用在 Windows 10 到 125% 上缩放的 2560x1440 显示器。 I wrote a C# unit test case in Visual Studio 2019 that calls a DLL to 1) find the window handles of various apps (notepad, wordpad, etc) and 2) resize them to just under 100% of the monitor size.
我在 Visual Studio 2019 中编写了一个 C# 单元测试用例,该用例将 DLL 调用为 1)找到各种应用程序的 window 句柄(记事本、写字板等),并将它们调整为显示器大小的 2%。 I used
Win32.MoveWindow
to do the move, like so:我使用
Win32.MoveWindow
进行移动,如下所示:
// MoveWindow(hWnd, left, top, width, height)
Win32.MoveWindow(hWnd, 0, 0, 2500, 1400, true);
The problem is that while debugging in the unit test, Windows10 scales up the 2500 and 1400 pixel numbers by 125% and moves the windows to that larger size.问题在于,在单元测试中进行调试时,Windows10 将 2500 和 1400 像素数放大了 125%,并将 windows 移动到更大的尺寸。 The windows then hang off the bottom and right edges of the screen.
windows 然后挂在屏幕的底部和右侧边缘。
In contrast, when I run the same DLL code from a skeleton Windows Forms app (and while not debugging), the code works fine, and Windows resizes the Notepad and Wordpad app windows correctly. In contrast, when I run the same DLL code from a skeleton Windows Forms app (and while not debugging), the code works fine, and Windows resizes the Notepad and Wordpad app windows correctly.
I pass in the same numbers to Win32.MoveWindow
in both cases.在这两种情况下,我都将相同的数字传递给
Win32.MoveWindow
。
In case it matters, for the DLL code, I have tried endless combinations of the app.config and app.manifest settings for my DLL code that calls Win32.MoveWindow
(and am targeting NET 4.7.2) but without success.万一这很重要,对于 DLL 代码,我已经尝试了 app.config 和 app.manifest 设置的无限组合,用于调用
Win32.MoveWindow
(并且我的目标是 NET 4.7.2)的 DLL 代码,但没有成功。
For the skeleton Forms app, I have tried 4.6.1 and 4.7.2 with no DPI settings in app.config and the "dpiAware=true" enabled in the app.manifest.对于骨架 Forms 应用程序,我尝试了 4.6.1 和 4.7.2,在 app.config 中没有 DPI 设置,并且在 app.manifest 中启用了“dpiAware=true”。 (Of course, neither the skeleton Forms app nor the DLL are DPI aware. I just tried the setting on and off.)
(当然,骨架 Forms 应用程序和 DLL 都不是 DPI 感知的。我只是尝试打开和关闭设置。)
The only thing that seems to make a difference is whether I am debugging.唯一似乎有所作为的是我是否在调试。 I expected that I could use the normal screen pixels from the OS screen boundaries when I did MoveWindow operations, but that isn't working well when debugging.
我希望在执行 MoveWindow 操作时可以使用来自操作系统屏幕边界的正常屏幕像素,但在调试时效果不佳。
What is the proper way to resize other apps with Win32.MoveWindow
?使用
Win32.MoveWindow
调整其他应用程序大小的正确方法是什么? Should my app determine the current scaling factor and then down-scale the numbers that I pass to Win32.MoveWindow
?我的应用程序是否应该确定当前的比例因子,然后缩小我传递给
Win32.MoveWindow
的数字? (I would pass 2500/1.25 = 2000 to Win32.MoveWindow
, for example, for 125% scaling.) (例如,我会将 2500/1.25 = 2000 传递给
Win32.MoveWindow
以进行 125% 缩放。)
Is the debugger supposed to interfere with scaling and sizing like this?调试器是否应该像这样干扰缩放和调整大小? Is it a known problem?
这是一个已知问题吗?
@selbie was totally correct and exactly on the target with his comment. @selbie 的评论完全正确,并且完全符合目标。 He was even kind enough to bold one of the key statement lines for me to draw my attention to it.
他甚至好心地将其中一条关键语句加粗,以引起我的注意。 @selbie made it easy for me to solve the problem.
@selbie 让我很容易解决问题。 I have included my test code fragments below.
我在下面包含了我的测试代码片段。
Windows Behavior Windows 行为
As @selbie pointed out, if 125% scaling is enabled in the Accessibility Settings to make everything bigger, Windows reports different screen sizes to aware and unaware processes.正如@selbie 指出的那样,如果在“辅助功能设置”中启用了 125% 缩放以使一切都变大,Windows 会向有意识和无意识进程报告不同的屏幕尺寸。
For DPI-aware processes, Windows will report 2560x1440 because they are supposed to down-scale their thinking so that Windows can scale it back up 125% to produce sharp text, etc.对于 DPI 感知进程,Windows 将报告 2560x1440,因为他们应该缩小他们的思维,以便 Windows 可以将其放大 125% 以产生清晰的文本等。
For DPI-unaware processes, Windows will report 2048x1152 to the caller so the caller thinks the screen is smaller than it really is.对于不知道 DPI 的进程,Windows 将向调用者报告 2048x1152,因此调用者认为屏幕比实际小。 Windows scales up the caller's orders by 125% to make the caller's sizes fit the hardware screen size (2560x1440).
Windows 将调用者的订单放大 125% 以使调用者的尺寸适合硬件屏幕尺寸 (2560x1440)。
The Problem问题
The problem I had was that my unit test code (DPI unaware) was using the hardware sizes in my DLL code (2560x1440), obtained from a database and not the OS, so when Windows scaled it up, my relocated windows were bigger than the hardware screen size. The problem I had was that my unit test code (DPI unaware) was using the hardware sizes in my DLL code (2560x1440), obtained from a database and not the OS, so when Windows scaled it up, my relocated windows were bigger than the硬件屏幕尺寸。
When the same DLL was used in a DPI-aware Forms app, Windows allowed for everything (produced no net scaling up) and the relocated windows fit the hardware screens. When the same DLL was used in a DPI-aware Forms app, Windows allowed for everything (produced no net scaling up) and the relocated windows fit the hardware screens.
The Solutions解决方案
The first solution is to make your calling process DPI-aware so that you can use the hardware screen sizes in your code.第一个解决方案是让您的调用进程能够识别 DPI,以便您可以在代码中使用硬件屏幕尺寸。 Do this by calling the Win32 API in NET 4.6 and above.
通过在 NET 4.6 及更高版本中调用 Win32 API 来执行此操作。 This is what I used in my unit test to make it work properly.
这是我在单元测试中使用的,以使其正常工作。
[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
}
The second solution is to enable DPI-awareness in the EXE app.manifest
file.第二种解决方案是在 EXE
app.manifest
文件中启用 DPI 感知。 Just uncomment the default XML code in the default app.manifest
file produced by AddNew in Visual Studio.只需在 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 >
In NET 4.7 and above, you can also use the new PerMonitorV2
DPI settings in the app.config
file, not the `app.manifest' file.在 NET 4.7 及更高版本中,您还可以在
app.config
文件中使用新的PerMonitorV2
DPI 设置,而不是在“app.manifest”文件中。 This apparently lets you use different DPI-awareness for different monitors.这显然可以让您对不同的显示器使用不同的 DPI 感知。 (I have not tried this yet, but I mention it here for completeness.)
(我还没有尝试过,但为了完整起见,我在这里提到它。)
<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>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.