【问题标题】:How can I get the scale factor of all my monitors?如何获得所有显示器的比例因子?
【发布时间】:2020-03-17 04:38:45
【问题描述】:

微软不知道如何帮助我,所以我不得不在这里问。

我有三台显示器...

  • 屏幕 1:3840 x 2160,缩放 150%
  • 屏幕 2:1920 x 1200,缩放 100%
  • 屏幕 3:1920 x 1200,缩放 100%

我需要在VB.netC# 中获取每个监视器的缩放比例。

Microsoft 建议我使用此代码:

Private Declare Function GetDeviceCaps Lib "gdi32.dll" (hdc As IntPtr, nIndex As Integer) As Integer

Public Enum DeviceCap
    VERTRES = 10
    DESKTOPVERTRES = 117
End Enum

Private Sub MainWindow_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
    For Each screen As Forms.Screen In Forms.Screen.AllScreens
        Dim pnt = New System.Drawing.Point(screen.Bounds.Left + 1, screen.Bounds.Top + 1)
        Dim mon = MonitorFromPoint(pnt, 2)
        Dim fac As Single = GetScalingFactor(mon)
        Console.WriteLine($"Factor: {fac}")
    Next
End Sub

Private Function GetScalingFactor(monitorHandle As IntPtr) As Single
    Dim g As Graphics = Graphics.FromHwnd(IntPtr.Zero)
    Dim desktop As IntPtr = g.GetHdc()
    Dim LogicalScreenHeight As Integer = GetDeviceCaps(desktop, CInt(DeviceCap.VERTRES))
    Dim PhysicalScreenHeight As Integer = GetDeviceCaps(desktop, CInt(DeviceCap.DESKTOPVERTRES))
    Dim ScreenScalingFactor As Single = CSng(PhysicalScreenHeight) / CSng(LogicalScreenHeight)
    Return ScreenScalingFactor
End Function

但它为我的所有屏幕返回 1 的比例。

我需要它独立于我的应用是否支持 dpiAware,因此我必须以某种方式从屏幕控制面板读取它。

该解决方案必须适用于 Windows 10 和 Windows Server 2012 R2 远程桌面客户端。

【问题讨论】:

  • This 解决方案对我来说效果很好。
  • @JoãoSilva - 我的注册表中没有 LogPixels 条目。不过还是谢谢。
  • This 似乎以各种方式做到了这一点(尽管在 C# 中,但应该很容易转换)。选择您的选择。
  • @Christian.K ...是的,这也是微软的建议之一,但正如许多 cmets 所说,GetDeviceCaps 总是返回 1 ...所以我们不得不放弃它。
  • 您的代码使用 WPF 样式的事件处理程序。这是一个 WPF 应用程序吗? WPF 应用程序 本质上 是 DpiAware,除非您强制禁用它。为什么不使用PresentationSource.FromVisual(Application.Current.MainWindow).CompositionTarget.TransformToDevice; 返回的矩阵呢?在 WPF 中使用 Graphics.FromHwnd() 没有任何意义。

标签: c# vb.net


【解决方案1】:

我相信您可以在DisplayInformation 类中使用ResolutionScale 属性。这会为您检索一个带有比例因子的枚举,但我不知道它是否独立于 dpiAware。

【讨论】:

    【解决方案2】:

    这可能会对您有所帮助

    通常屏幕显示器的 rawDpi 为 102 点 x 英寸,但如果你有一个 Microsft Surface is logic 你有另一个 rawDpi。 所以在这种情况下,您可以使用真实设备 rawDpi 更改 102(您可以通过 100% 屏幕分辨率下的代码获得)

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    
        For Each screen In System.Windows.Forms.Screen.AllScreens
    
            Dim mRawSreen As SCREENS = Display(screen, DpiType.MDT_RAW_DPI)
    
            Console.WriteLine(" deviceName: " & screen.DeviceName &
                              " ScaleFactorX: " & (102 / mRawSreen.DPI_X * 100).ToString("N2") & "%" &
                              " ScaleFactorY: " & (102 / mRawSreen.DPI_Y * 100).ToString("N2") & "%")
    
        Next
    
    End Sub
    
    Public Enum DpiType
        MDT_EFFECTIVE_DPI = 0
        MDT_ANGULAR_DPI = 1
        MDT_RAW_DPI = 2
    End Enum
    
    Structure SCREENS
        Dim DPI_X As Integer
        Dim DPI_Y As Integer
    End Structure
    
    Private Function Display(screen As Screen, ByVal type As DpiType) As SCREENS
    
        Dim x, y As UInteger
    
        GetDpi(screen, type, x, y)
    
        Dim current As SCREENS = New SCREENS With {
                .DPI_X = x,
                .DPI_Y = y
                }
    
        'Console.WriteLine(" deviceName: " & screen.DeviceName & " typeDpi: " & type.ToString & " : dpiX=" & x & ", dpiY=" & y)
        Return current
    
    End Function
    
    Private Declare Function MonitorFromPoint Lib "User32.dll" (ByVal pt As System.Drawing.Point, ByVal dwFlags As UInteger) As IntPtr
    Private Declare Function GetDpiForMonitor Lib "Shcore.dll" (ByVal hmonitor As IntPtr, ByVal dpiType As DpiType, ByRef dpiX As UInteger, ByRef dpiY As UInteger) As IntPtr
    
    Sub GetDpi(ByVal screen As System.Windows.Forms.Screen, ByVal dpiType As DpiType, ByRef dpiX As UInteger, ByRef dpiY As UInteger)
        Dim pnt = New System.Drawing.Point(screen.Bounds.Left + 5, screen.Bounds.Top + 5)
        Dim mon = MonitorFromPoint(pnt, 2)
        GetDpiForMonitor(mon, dpiType, dpiX, dpiY)
    End Sub
    

    【讨论】:

    • 感谢您在这里帮助我......但我不完全确定,上面的 DPI 代码将如何帮助我获得用户定义的自定义缩放?
    • 原始 DPI 与有效 DPI 不同。有效 DPI 不会在屏幕自定义分辨率上发生变化。相反,原始 DPI 会更改自定义分辨率。因此,此时您可以自行计算百分比(如上面的代码所示,正常原始 DPI / 自定义原始 DPI)要获得初始正常原始 DPI,您也可以通过此代码获得它,您可以保存在注册表或你想在哪里。那就是删除我的静态102。:)
    猜你喜欢
    • 2012-12-10
    • 1970-01-01
    • 1970-01-01
    • 2011-10-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多