How can I get the scale factor of all my monitors?

时光毁灭记忆、已成空白 提交于 2019-12-12 18:34:52

问题


Microsoft can't figure out how to help me, so I have to ask here.

I have three monitors...

  • Screen 1: 3840 x 2160, scaling 150%
  • Screen 2: 1920 x 1200, scaling 100%
  • Screen 3: 1920 x 1200, scaling 100%

I need in VB.net or C# to get the scaling of each monitors.

Microsoft advises me to use this code:

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

But it returns a scale of 1 for all my screens.

I need it to be independent of my app being dpiAware or not, so I have to read it from the screen control panel somehow.

The solution must work on both Windows 10 and Windows Server 2012 R2 Remote Desktop clients.


回答1:


I believe you can use the ResolutionScale property in the DisplayInformation class. This retrieves you an enum with the scale factor, but I do not know if it is dpiAware independent or not.




回答2:


This might help you.

Normally screen monitors have a rawDpi 102 dots x inch but if you have a Microsft Surface is logic you have another rawDpi. So in this case you can change 102 with real device rawDpi (you can get that by code under 100% screen resolution)

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


来源:https://stackoverflow.com/questions/58971670/how-can-i-get-the-scale-factor-of-all-my-monitors

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!