-
May 20th, 2022, 01:07 PM
#1
Thread Starter
Fanatic Member
Monitor Numbering
I'm finding that the monitor numbering that Windows Displays Settings uses and
and the numbering generated when calling EnumDisplayMonitors are not synched.
Can someone confirm this?
If this is true, is there a way to force them to be the same?
-
May 21st, 2022, 10:55 AM
#2
Re: Monitor Numbering
EnumDisplayMonitors and the Windows Display Settings are only loosely related. The Windows Display Settings could be calling EnumDisplayMonitors, however it can then choose to number the information it reports in whatever way it sees fit.
-
May 21st, 2022, 07:33 PM
#3
Re: Monitor Numbering
Perhaps this is correct:
Give each "monitor" you track (array, Collection, etc.) Index, Number, and Primary properties
Build the list by enumerating monitors, assigning Index from 0 to n as you go, capturing Primary = True for the primary.
Find PrimaryIndex (or assign it when you capture Primary = True).
Assign Mon(Primary Index).Number = 1, assign a MonNumber variable = 1.
Scan the list from I = 0 to n. If Not Mon(I)Primary Then MonNumber = MonNumber + 1:Mon(I).Number = MonNumber
Ok, that's an awkward description. I'm suggesting that perhaps monitor 1 is always the primary and the rest are numbered above 1 in the enumeration sequence. What have you got to lose by trying it?
Note: While your program is running the user can change the primary monitor, so you may need some way to refresh the list from scratch. There might be some broadcast message to tell you when you must refresh, I'm not sure.
-
May 21st, 2022, 08:17 PM
#4
Thread Starter
Fanatic Member
Re: Monitor Numbering
I will give your approach a try.
-
May 22nd, 2022, 03:44 PM
#5
Re: Monitor Numbering
Personally, I've never been able to get this to work (correct numbering) with EnumDisplayMonitors. However, I haven't examined the order in which the monitors are returned by the WMI. Maybe they're correctly ordered (per Windows settings) when listing them that way.
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.
-
May 26th, 2022, 09:57 AM
#6
Thread Starter
Fanatic Member
Re: Monitor Numbering
I guess I have to give up on this, as I am spending way too much time and getting nowhere really.
The only thing I can determine with certainty is that the primary monitor always has top-left coordinates of (0,0)
I can find no way to tie numbering from EnumDisplayMonitors to Windows Settings numbering.
Code for virtual screen requires VB project with
Picture1 on Form1
Picture2 inside Picture1
Label1 inside Picture2
Form1 code
Code:
Option Explicit
'https://docs.microsoft.com/en-us/windows/win32/gdi/the-virtual-screen
Private Sub Form_Load()
Me.ScaleMode = vbPixels
Me.Caption = "Virtual Screen"
Me.BorderStyle = 1
'Picture1 - background
Picture1.ScaleMode = vbPixels
Picture1.Appearance = 0
Picture1.BorderStyle = 1
Picture1.BackColor = vbWhite
'Picture2 - virtual screen
Picture2.ScaleMode = vbPixels
Picture2.Appearance = 0
Picture2.BorderStyle = 1
Picture2.BackColor = &H8000000A
'Label1 - monitors
Label1(0).Appearance = 0
Label1(0).BorderStyle = 1
Label1(0).BackColor = vbCyan
Call DrawVirtualScreen
End Sub
Module1 code
Code:
Option Explicit
Private Declare Function EnumDisplayMonitors Lib "user32" _
(ByVal hdc As Long, lprcClip As Any, ByVal lpfnEnum As Long, dwData As Any) As Long
Private Declare Function UnionRect Lib "user32" _
(lprcDst As RECT, lprcSrc1 As RECT, lprcSrc2 As RECT) As Long
Private Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Dim rectMonitors() As RECT 'coordinates array for all monitors
Dim rectVS As RECT 'coordinates for Virtual Screen
Dim ret As Long
Function DrawVirtualScreen() As Long
Dim i As Long
ret = EnumDisplayMonitors(0, ByVal 0&, AddressOf MonitorEnumProc, i)
'size virtual screen
Form1.Picture2.Width = Round((rectVS.Right - rectVS.Left) * 0.18, 0)
Form1.Picture2.Height = Round((rectVS.Bottom - rectVS.Top) * 0.18, 0)
Form1.Picture2.Left = 10
Form1.Picture2.Top = 10
'scale virtual screen
Form1.Picture2.ScaleLeft = rectVS.Left
Form1.Picture2.ScaleWidth = rectVS.Right - rectVS.Left
Form1.Picture2.ScaleTop = rectVS.Top
Form1.Picture2.ScaleHeight = rectVS.Bottom - rectVS.Top
'size background based on virtual screen
Form1.Picture1.Width = Form1.Picture2.Width + 22
Form1.Picture1.Height = Form1.Picture2.Height + 22
Form1.Picture1.Left = 10
Form1.Picture1.Top = 10
'size form based on background
Form1.Width = (Form1.Picture1.Width + 36) * Screen.TwipsPerPixelX
Form1.Height = (Form1.Picture1.ScaleHeight + 61) * Screen.TwipsPerPixelY
'position monitors on virtual screen
For i = 0 To i - 1
'load control array
If i > 0 Then
Load Form1.Label1(i)
Form1.Label1(i).Visible = True
End If
'move monitors to proper position on virtual screen
Form1.Label1(i).Left = rectMonitors(i).Left
Form1.Label1(i).Top = rectMonitors(i).Top
Form1.Label1(i).Width = rectMonitors(i).Right - rectMonitors(i).Left
Form1.Label1(i).Height = rectMonitors(i).Bottom - rectMonitors(i).Top
'display metrics
Form1.Label1(i).Caption = _
"Monitor " & i + 1 & vbLf & _
vbLf & _
rectMonitors(i).Right - rectMonitors(i).Left & " x " & _
rectMonitors(i).Bottom - rectMonitors(i).Top & vbLf & _
"(" & rectMonitors(i).Left & ", " & rectMonitors(i).Top & ")-(" & _
rectMonitors(i).Right & ", " & rectMonitors(i).Bottom & ")"
If rectMonitors(i).Left = 0 And rectMonitors(i).Top = 0 Then
Form1.Label1(i).Caption = Form1.Label1(i).Caption & _
vbLf & vbCrLf & "PRIMARY"
End If
Next
End Function
Private Function MonitorEnumProc(ByVal hMonitor As Long, ByVal hdcMonitor As Long, _
lprcMonitor As RECT, dwData As Long) As Long
' A MonitorEnumProc function is an application-defined callback function
' that is called by the EnumDisplayMonitors function.
ReDim Preserve rectMonitors(dwData)
rectMonitors(dwData) = lprcMonitor
UnionRect rectVS, rectVS, lprcMonitor 'merge all monitors together to get virtual screen
dwData = dwData + 1 'increase monitor count
MonitorEnumProc = 1 'continue
End Function
-
May 26th, 2022, 10:47 AM
#7
Re: Monitor Numbering
Originally Posted by mms_
I guess I have to give up on this, as I am spending way too much time and getting nowhere really.
Did you see this thread?
https://superuser.com/questions/1455...mbers-identity
What I read there gave me some ideas, things I'd try if I were doing this.
-
May 27th, 2022, 01:59 PM
#8
Thread Starter
Fanatic Member
Re: Monitor Numbering
Thanks Niya for the link.
No, I had not seen that before.
If you are referring to a possible solution as making registry changes,
then I'd rather stay away from that.
-
May 28th, 2022, 01:23 AM
#9
-
May 28th, 2022, 07:05 AM
#10
Thread Starter
Fanatic Member
Re: Monitor Numbering
A very slick implementation vbLewis, thank you for posting!!
Your code is well commented, and I can learn a lot from it.
The left-to-right approach of numbering (0-1-2) is very logical, and that is how your program shows my 3 monitors.
I notice in your screenshot above, a (1-0-2) set-up, where I assume 0 is your primary monitor? (this is how I was thinking at the outset btw)
If your SortMonitors routine sorts left to right (which I think it does), how do you end up with (1-0-2)?
Thank you again for posting, because this will definitely help me.
-
May 28th, 2022, 12:49 PM
#11
Lively Member
Re: Monitor Numbering
enumdisplaymonitors() enumerates the monitors in the order the system has them numbered with the primary display starting at 0 (i think. at least thats how mine is). So no matter how you arrange them in display properties the number they are "enum'ed" at stays the same.
The idea in my code is that you can use the Index from the Monitor() array to get its physical arrangement index from MonitorOrder() array. So lets say that the Monitor() array has three monitors in it, and you need to get the second monitors physical arrangement in display properties.
The second Monitor's index in the Monitor() array is 1 (0-1-2) so MonitorOrder(1) would be = to wherever the monitor is arranged in the display properties, in my case its the first one.
edit: i just noticed in Display Properties the numbers start at 1 so I'm thinking I should probably update my code to add 1 to the internal number.
Last edited by vbLewis; May 28th, 2022 at 01:45 PM.
-
May 30th, 2022, 10:10 AM
#12
Re: Monitor Numbering
as for me, I only need to know the current monitor. I actually don't care about what/where/how many.
so, if Im in monitor 1, I want my maximize/fullscreen buttons to work properly.
and if I move the form to monitor 2, it should do that correctly for that screen, so my form will not jump to monitor 1 if Im in 2.
or the resize will stretch to both monitors.
not sure the purpose here.
I use:
Code:
Private Declare Function MonitorFromRect Lib "user32" (rc As Rect, ByVal dwFlags As Long) As Long
Private Declare Function GetWindowRect Lib "user32.dll" (ByVal hwnd As Long, ByRef lpRect As Rect) As Long
GetWindowRect form.hwnd, lpRect
hMonitor = MonitorFromRect(lpRect, 1&)
hMonitor is the same u get from the Enumeration.
but since "I don't care" about the other display, I simply parse this one using GetMonitorInfo
and I get both the screen rect and the working rect. so I can avoid covering the taskbar when "maximize" (as I have both maximize and fullscreen options)
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|