Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/276.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 检测是否已扩展/虚拟化了不支持DPI的应用程序_C#_.net_Windows_Dpi - Fatal编程技术网

C# 检测是否已扩展/虚拟化了不支持DPI的应用程序

C# 检测是否已扩展/虚拟化了不支持DPI的应用程序,c#,.net,windows,dpi,C#,.net,Windows,Dpi,我试图在WinForms应用程序中检测它是否由于操作系统具有高DPI而以缩放/虚拟化模式启动。目前,在以3840x2400运行且缩放率为200%的系统中,应用程序将分辨率视为1920x1200,DPI视为96,缩放因子为1 我们正在使应用程序的DPI意识到,但在此之前,我们需要一个“快速修复”,使我们能够检测是否缩放。原因是它破坏了应用程序中截图的功能。我们在Graphics.CopyFromScreen中使用缩放尺寸,因为它需要非缩放尺寸,所以截图的尺寸错误 我知道DPI感知设置,但目前,我们

我试图在WinForms应用程序中检测它是否由于操作系统具有高DPI而以缩放/虚拟化模式启动。目前,在以3840x2400运行且缩放率为200%的系统中,应用程序将分辨率视为1920x1200,DPI视为96,缩放因子为1

我们正在使应用程序的DPI意识到,但在此之前,我们需要一个“快速修复”,使我们能够检测是否缩放。原因是它破坏了应用程序中截图的功能。我们在Graphics.CopyFromScreen中使用缩放尺寸,因为它需要非缩放尺寸,所以截图的尺寸错误


我知道DPI感知设置,但目前,我们仍希望应用程序能够缩放,但能够检测到我们已缩放并获得非缩放尺寸,如果可能。

系统将向未明确标记为高DPI感知的应用程序撒谎,并告知有96 DPI,比例因子为100%。为了获得真正的DPI设置,并避免DWM自动虚拟化,您需要在应用程序清单中包含
True/PM
。可获得更多信息

在您的情况下,听起来您正在寻找和对函数。正如链接文档所解释的,默认情况下,系统将根据调用者的DPI感知返回有关其他窗口的信息。因此,如果一个非DPI感知的应用程序尝试获取一个高DPI感知进程的窗口边界,它将获得已转换为其自身的非DPI感知坐标空间的边界。用这些函数的方言来说,这就是“逻辑”坐标。您可以将这些坐标转换为“物理”坐标,即操作系统(和其他具有高DPI意识的进程)实际使用的坐标

不过,为了回答您的实际问题:如果您确实需要在一个不了解DPI的过程中突破操作系统的谎言,我可以想出两种方法:

  • 调用该函数。如果生成的
    设备比例系数
    值不是
    比例100%
    ,则您将被缩放。如果您的应用程序不支持DPI,则您正在被虚拟化

    这是一个快速而肮脏的解决方案,因为从WinForms应用程序调用它只需要一个简单的p/Invoke定义。但是,您不应该只依赖于布尔“we we scaled/virtualized?”指示器的结果。换句话说,不要相信它返回的比例因子

    在Windows 10系统上,系统DPI为96,且高DPI监视器的DPI为144(150%缩放),
    getScaleFactorFormMonitor
    函数在预期返回
    SCALE\u 150%
    (144/96==1.5)时返回
    SCALE\u 140%
    。我真的不明白为什么会这样。我唯一能弄明白的是,它是为Windows 8.1上的Metro/Modern/UWP应用程序设计的,其中150%不是有效的比例因子,但140%是。此后,缩放因子一直保持不变,但此函数似乎尚未更新,并且仍然会为桌面应用程序返回不可靠的结果

  • 根据显示器的逻辑和物理宽度,自己计算比例因子。

    当然,首先,您需要获得一个
    HMONITOR
    (特定物理监视器的句柄)。您可以通过调用、向WinForms窗口传递句柄并指定
    MONITOR\u DEFAULTTONEAREST
    来完成此操作。这将使您获得显示感兴趣窗口的监视器的句柄

    然后,您将使用此监视器句柄通过调用函数获取该监视器的逻辑宽度。它填充一个包含作为其成员之一的
    RECT
    结构(
    rcMonitor
    )的,该结构包含该监视器的虚拟屏幕坐标。(请记住,与.NET不同,Windows API以矩形的左、上、右和下范围表示矩形。宽度是右范围减去左范围,而高度是底部范围减去顶部范围。)

    GetMonitorInfo
    填写的
    MonitorInfo
    结构也将为您提供该监视器的名称(
    szDevice
    成员)。然后,您可以使用该名称调用函数,该函数将在
    DEVMODE
    结构中填充有关该监视器的物理显示模式的一组信息。您感兴趣的成员是
    dmPelsWidth
    dmpelshigh
    ,它们分别为您提供每宽和每高的物理像素数

    然后可以将逻辑宽度除以物理宽度,以确定宽度的比例因子。高度也是一样(除了我知道的所有监视器都有正方形像素,所以垂直比例因子等于水平比例因子)

    示例代码,在Windows 10中测试和工作(用C++编写,因为这是我所能使用的;抱歉,您必须对.NET进行自己的翻译):


  • 将截屏代码移到另一个应用程序dpiaware中。@HansPassant这是一个很好的建议,但我们通过远程桌面服务将此应用程序作为远程应用程序提供,这确实使此方法复杂化。感谢您的详细回复!这正是我要找的!请注意,根本不应使用“GetScaleFactorFormMonitor”方法,即使只是用于检查是否应用了缩放。根据我在Windows 10上的测试(仅未检查周年纪念),比例因子为100%或125%,此函数仍然返回100%的比例,对于回答中提到的较高数字,会返回异常值。这绝对是一个Windows错误。枚举v
    // Get the monitor that the window is currently displayed on
    // (where hWnd is a handle to the window of interest).
    HMONITOR hMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);
    
    // Get the logical width and height of the monitor.
    MONITORINFOEX miex;
    miex.cbSize = sizeof(miex);
    GetMonitorInfo(hMonitor, &miex);
    int cxLogical = (miex.rcMonitor.right  - miex.rcMonitor.left);
    int cyLogical = (miex.rcMonitor.bottom - miex.rcMonitor.top);
    
    // Get the physical width and height of the monitor.
    DEVMODE dm;
    dm.dmSize        = sizeof(dm);
    dm.dmDriverExtra = 0;
    EnumDisplaySettings(miex.szDevice, ENUM_CURRENT_SETTINGS, &dm);
    int cxPhysical = dm.dmPelsWidth;
    int cyPhysical = dm.dmPelsHeight;
    
    // Calculate the scaling factor.
    double horzScale = ((double)cxPhysical / (double)cxLogical);
    double vertScale = ((double)cyPhysical / (double)cyLogical);
    ASSERT(horzScale == vertScale);