Results 1 to 14 of 14

Thread: Question about GetSystemMetrics and VIRTUALSCREEN

  1. #1

    Thread Starter
    PowerPoster
    Join Date
    Jun 2012
    Posts
    2,374

    Question about GetSystemMetrics and VIRTUALSCREEN

    Hello,

    I need the virtual screen (physical, not logical) to make an adjustment so to pass it on ClipCursor. (screen rectangle)

    In below sample there are two approaches.
    1. Using GetSystemMetrics
    2. Using GetClipBox on hDCScreen

    I tested them with 2 monitors. Both ways return correctly (possible) negative values etc. and it seems to work also with what ClipCursor expects.

    However, I read that GetSystemMetrics don't work if the calling thread is per monitor aware and also some posts in the wild that SM_CXVIRTUALSCREEN returns 'bad' values for large screens etc.
    I did the test with a manifest and also messed with the DPI settings either way on the two monitors and the sizes keeps being correct. (?)

    Thanks

    Code:
    Option Explicit
    Private Type RECT
    Left As Long
    Top As Long
    Right As Long
    Bottom As Long
    End Type
    Private Declare Function GetDC Lib "user32" (ByVal hWnd As Long) As Long
    Private Declare Function ReleaseDC Lib "user32" (ByVal hWnd As Long, ByVal hDC As Long) As Long
    Private Declare Function GetClipBox Lib "gdi32" (ByVal hDC As Long, ByRef lpRect As RECT) As Long
    Private Declare Function GetSystemMetrics Lib "user32" (ByVal nIndex As Long) As Long
    Private Const SM_XVIRTUALSCREEN As Long = 76
    Private Const SM_YVIRTUALSCREEN As Long = 77
    Private Const SM_CXVIRTUALSCREEN As Long = 78
    Private Const SM_CYVIRTUALSCREEN As Long = 79
    
    Private Sub Command1_Click()
    Test1
    Test2
    End Sub
    
    Private Sub Test1()
    ' Get virtual screen from GetSystemMetrics.
    ' Any DPI issues ? It seems to be physical always and not logical.
    
    Debug.Print "1", "Left: " & GetSystemMetrics(SM_XVIRTUALSCREEN), "Right: " & (GetSystemMetrics(SM_XVIRTUALSCREEN) + GetSystemMetrics(SM_CXVIRTUALSCREEN))
    Debug.Print "1", "Top: " & GetSystemMetrics(SM_YVIRTUALSCREEN), "Bottom: " & (GetSystemMetrics(SM_YVIRTUALSCREEN) + GetSystemMetrics(SM_CYVIRTUALSCREEN))
    
    End Sub
    
    Private Sub Test2()
    ' This seems to be an easy approach. Better than enumerating all the monitors and get physical pixel sizes ?
    ' Is this 'safe' ?
    
    Dim hDCScreen As Long
    hDCScreen = GetDC(0)
    If hDCScreen <> 0 Then
        Dim RC As RECT
        GetClipBox hDCScreen, RC
        
        Debug.Print "2", "Left: " & RC.Left, "Right: " & RC.Right
        Debug.Print "2", "Top: " & RC.Top, "Bottom: " & RC.Bottom
        
        ReleaseDC 0, hDCScreen
        
    End If
    End Sub
    Last edited by Krool; Nov 24th, 2021 at 02:52 PM. Reason: Thank you Elroy

  2. #2
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,853

    Re: Question about GetSystemMetrics and VIRTUALSCREEN

    Enumerating all the monitors and getting their physical pixel sizes would be difficult for several reasons. First, I wouldn't even begin to know how the monitors were actually physically arranged within Display Settings, and how to actually "get" that information. They may be horizontally arranged, vertically arranged, or a combination of the two:

    Name:  Monitors.png
Views: 445
Size:  3.0 KB

    I've never played around with what you're trying to do, but I'll take your code and try it with different DPI settings and see what it does.

    CORRECTION: I was making a call to SetProcessDpiAwarenessContext(Context_PerMonitorAwareV2) in an IDE add-in that I had forgotten about.
    Last edited by Elroy; Nov 26th, 2021 at 12:45 PM.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  3. #3
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,853

    Re: Question about GetSystemMetrics and VIRTUALSCREEN

    Ok, I typically have my monitors arranged like this:

    Name:  Monitors2.png
Views: 433
Size:  2.6 KB

    Monitor #1 is disabled.
    Monitor #2 is a 3440 x 1440 monitor, but set at 150% scale.
    Monitor #3 is a 1920 x 1080 monitor, set at 100% scale.

    Just out-of-the-box, your code reports the following:

    Code:
    Test: 1       Left: 0        Right: 5360
    Test: 1       Top: 0         Bottom: 1440
    Test: 2       Left: 0        Right: 5360
    Test: 2       Top: 0         Bottom: 1080
    I'm not sure I know how to make sense of that. It looks like test#1 is reporting "physical" across both monitors' width and the height for the larger monitor. Test#2 is reporting the correct width, but the height for the smaller monitor.

    EDIT: The more I think about it, maybe test#1 is reporting the "full" virtual screen, and test#2 is reporting the "viewable" virtual screen. I'll play around more with that idea.

    CORRECTION: I was making a call to SetProcessDpiAwarenessContext(Context_PerMonitorAwareV2) in an IDE add-in that I had forgotten about.
    Last edited by Elroy; Nov 26th, 2021 at 12:45 PM.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  4. #4
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,853

    Re: Question about GetSystemMetrics and VIRTUALSCREEN

    Hmmm, it's not easy to make sense of this stuff. It doesn't seem that width and height are being handled the same way.

    The next configuration I tested was:

    Name:  Monitors3.png
Views: 423
Size:  2.8 KB

    And got this:

    Code:
    Test: 1       Left: 0        Right: 4874
    Test: 1       Top: 0         Bottom: 2520
    Test: 2       Left: 0        Right: 4874
    Test: 2       Top: 0         Bottom: 2520
    My best guess right now is that width is always the total, but height is viewable for test#2.

    CORRECTION: I was making a call to SetProcessDpiAwarenessContext(Context_PerMonitorAwareV2) in an IDE add-in that I had forgotten about.
    Last edited by Elroy; Nov 26th, 2021 at 12:45 PM.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  5. #5
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,853

    Re: Question about GetSystemMetrics and VIRTUALSCREEN

    Ok, this is weird. I put my configuration back to this:

    Name:  Monitors2.png
Views: 414
Size:  2.6 KB

    With monitor #2 still at 150% scaling.

    And I also compiled things. The first (left) one is in the IDE and the second (right) one is compiled:

    Name:  Virtual.jpg
Views: 429
Size:  21.0 KB

    And just an FYI, nothing is manifested.
    CORRECTION: I was making a call to SetProcessDpiAwarenessContext(Context_PerMonitorAwareV2) in an IDE add-in that I had forgotten about.

    I've attached your "modified" project to this post, just modified to report in the form, rather than the Immediate window.
    Attached Files Attached Files
    Last edited by Elroy; Nov 26th, 2021 at 12:46 PM.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  6. #6
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,853

    Re: Question about GetSystemMetrics and VIRTUALSCREEN

    Say Krool, also, you declared ReleaseDC in your project, but you didn't call it. I just spotted that. It's NOT fixed in the project attached to post #5 either, so beware.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  7. #7
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    5,120

    Re: Question about GetSystemMetrics and VIRTUALSCREEN

    Code:
    1             Left: -1920   Right: 2560
    1             Top: 0        Bottom: 1440
    2             Left: -1920   Right: 2560
    2             Top: 0        Bottom: 1440
    An HD monitor next to a QHD monitor, primary is the second one and that's why the negative Left above I guess.

    DPI is 125% system-wide (both monitors) but this seems not to matter in this test.

    cheers,
    </wqw>

  8. #8
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    9,853

    Re: Question about GetSystemMetrics and VIRTUALSCREEN

    Quote Originally Posted by wqweto View Post
    Code:
    1             Left: -1920   Right: 2560
    1             Top: 0        Bottom: 1440
    2             Left: -1920   Right: 2560
    2             Top: 0        Bottom: 1440
    An HD monitor next to a QHD monitor, primary is the second one and that's why the negative Left above I guess.

    DPI is 125% system-wide (both monitors) but this seems not to matter in this test.

    cheers,
    </wqw>
    Weird about the negative value. I guess because my #1 monitor is disabled and my #2 monitor is on the left, I didn't get negative numbers. I can easily test that though.

    Yep, that's totally it (this test just in IDE):

    Name:  Monitors5.png
Views: 422
Size:  2.6 KB
    Name:  Monitors4.png
Views: 423
Size:  8.8 KB

    CORRECTION: I was making a call to SetProcessDpiAwarenessContext(Context_PerMonitorAwareV2) in an IDE add-in that I had forgotten about.
    Last edited by Elroy; Nov 26th, 2021 at 12:46 PM.
    Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.

  9. #9
    PowerPoster
    Join Date
    Feb 2017
    Posts
    4,995

    Re: Question about GetSystemMetrics and VIRTUALSCREEN

    Both reported the right physical(*) pixels values for me.

    I have the IDE manifested for DPI aware per monitor V2 (but that does not seem to come into play).

    Name:  Monitors.png
Views: 405
Size:  2.7 KB

    Monitor 1: 1920x1080, 125% DPI
    Monitor 2: 3840x2160, 300% DPI

    Result:

    Code:
    1             Left: 0       Right: 5760
    1             Top: 0        Bottom: 2160
    2             Left: 0       Right: 5760
    2             Top: 0        Bottom: 2160
    1920+3840 = 5760

    (*) "Physical" are not truly physical but what is selected by the user as the resolution of the monitor.
    I changed the second monitor setting to 1920x1024 and the result changed to:

    Code:
    1             Left: 0       Right: 3840
    1             Top: 0        Bottom: 1080
    2             Left: 0       Right: 3840
    2             Top: 0        Bottom: 1080
    Name:  Monitors2.jpg
Views: 404
Size:  5.3 KB

    Quote Originally Posted by Krool View Post
    I need the virtual screen (physical, not logical) to make an adjustment so to pass it on ClipCursor. (screen rectangle)

    [...]

    However, I read that GetSystemMetrics don't work if the calling thread is per monitor aware and also some posts in the wild that SM_CXVIRTUALSCREEN returns 'bad' values for large screens etc.
    I did the test with a manifest and also messed with the DPI settings either way on the two monitors and the sizes keeps being correct. (?)
    Anyway, I don't understand why you need to explicitly confine the mouse to the virtual screen... isn't supposed that the mouse is already confined by Windows to the virtual screen and cannot got beyond its bounds?
    (Or perhaps you want to leave some space at the sides?)

  10. #10

    Thread Starter
    PowerPoster
    Join Date
    Jun 2012
    Posts
    2,374

    Re: Question about GetSystemMetrics and VIRTUALSCREEN

    Quote Originally Posted by Eduardo- View Post
    (Or perhaps you want to leave some space at the sides?)
    Yes. Thanks all so far.

    However, as you all I get the "true" resolution sizes (physical) and this is what ClipCursor expects. (In my tests at least?)

    EDIT:
    And GetClipCursor also returns always "physical".
    I am really distracted..
    Last edited by Krool; Nov 25th, 2021 at 02:19 AM.

  11. #11
    Lively Member vbLewis's Avatar
    Join Date
    Feb 2009
    Location
    USA
    Posts
    126

    Re: Question about GetSystemMetrics and VIRTUALSCREEN

    Ive recently had a project where i had to dive deep into displays and monitors. heres some things i learned.

    The virtual screen is always the height of the tallest monitor + the width of all monitors combined.
    The SM_XVIRTUALSCREEN and SM_YVIRTUALSCREEN are the upper left X-Y coords of the virtual screen and are used for navigating
    the virtual screen only, they should not be used in calculating the size of the virtual screen.
    Your code only works because those values return 0, if they had a negative value it would skew your numbers heavily.
    The reason those values arent always 0 is because the primary monitor's X-Y are 0 and if the user has a monitor
    to the left of the primary monitor the values will be negative.

    I have a module with all my screen code that may be useful to you, I only coded what I needed and more could be added.

    I made a small example program of how you can use the code. This is my monitor setup shown below. Keep in mind some users can have a monitor
    in portrait mode also.

    Name:  ss.jpg
Views: 383
Size:  20.4 KB


    here is the example code with the module included.


    EDIT: Fixed the taskbar exclusion error, and added VirtualScreenLeft and VirtualScreenTop, and fixed a bug in drawing the virtual screen...
    Attached Files Attached Files
    Last edited by vbLewis; Nov 25th, 2021 at 08:57 PM.

  12. #12
    Lively Member vbLewis's Avatar
    Join Date
    Feb 2009
    Location
    USA
    Posts
    126

    Re: Question about GetSystemMetrics and VIRTUALSCREEN

    I just noticed all the Height values are 40 pixels short, not sure why that is...


    EDIT: the code above excludes the taskbar which is what i needed for my purposes, to be correct it should include the task bar.
    To make that code correct for the whole screen you should change the height, width, left, top to use rcMonitor and not rcWork
    in the EnumMonitorCallback function.

    Code:
                    .Left = .mi.rcWork.Left * .TwipsX
                    .Top = .mi.rcWork.Top * .TwipsY
                    .Width = (.mi.rcWork.Right - .mi.rcWork.Left) * .TwipsX
                    .Height = (.mi.rcWork.Bottom - .mi.rcWork.Top) * .TwipsY
    change to this
    Code:
                    .Left = .mi.rcMonitor.Left * .TwipsX
                    .Top = .mi.rcMonitor.Top * .TwipsY
                    .Width = (.mi.rcMonitor.Right - .mi.rcMonitor.Left) * .TwipsX
                    .Height = (.mi.rcMonitor.Bottom - .mi.rcMonitor.Top) * .TwipsY
    Last edited by vbLewis; Nov 25th, 2021 at 01:41 PM.

  13. #13

    Thread Starter
    PowerPoster
    Join Date
    Jun 2012
    Posts
    2,374

    Re: Question about GetSystemMetrics and VIRTUALSCREEN

    Quote Originally Posted by vbLewis View Post
    Your code only works because those values return 0, if they had a negative value it would skew your numbers heavily.
    The reason those values arent always 0 is because the primary monitor's X-Y are 0 and if the user has a monitor
    to the left of the primary monitor the values will be negative.
    I want a RECT structure.
    For the Right member I use currently below value, which is correct also for negative values. Or what you mean ?

    Code:
    GetSystemMetrics(SM_XVIRTUALSCREEN) + GetSystemMetrics(SM_CXVIRTUALSCREEN)

  14. #14
    Lively Member vbLewis's Avatar
    Join Date
    Feb 2009
    Location
    USA
    Posts
    126

    Re: Question about GetSystemMetrics and VIRTUALSCREEN

    oh ok, my bad, i thought you were just trying to get the correct size.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width