Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

How to detect when two monitors are being used 7

Status
Not open for further replies.

AncientTiger

Programmer
Jul 5, 2001
238
US
Scratching my head on this one...

Some of my customers have a dual-screen setup at their workstations, and some have a single screen.

I've got a VB6 program that "remembers" the last screen position and resumes it's location the next time the user starts it up.

The problem is that sometimes my dual-screen people log onto one of the single screen PC's and the program starts up WAY off the right side of the screen.

Is there a way for me to detect if the computer being used is a dual-screen computer, or a single screen so that I can adjust the startup position accordingly?

And yes...I'm ready to slap my forehead from the OBVIOUS answer ;)

------------------------------------
[yinyang] Over 20 years of programming, and still learning every day! [yinyang]
 

I do that in my application, but...

I started with Windows XP and checked for Screen height and width, and then check the ratio of both.
Code:
Private Sub Form_Resize()

If Screen.Height / Screen.Width < 0.6 Then[green]
    'We have a Dual Screen situation here[/green]
    ....
Else[green]
    'We have one Screen [/green]
    ...
End If

End Sub

Just to be safe you may want to check this on many different resolutions for the monitors.

That worked for years, but now we are in Widows 7, and something had changed. I think (I may be wrong) Windows 7 has one main monitor, and another one, so this logic may or may not work any more. Seams to still work for me, keep my finger crossed….


Have fun.

---- Andy
 
Unfortunately the Screen.Height/Width method is highly flawed.

The reason is that Windows supports muliple monitors in a highly flexible fashion. They can be placed side by side or stacked top to bottom, or even without any vertical or horizontal alignment (like a diagonal). Also, the number of monitors can be more than two, placed in a mix layout.

Moreover, different monitors can have different screen resolutions, physical sizes and aspect ratios. All these factors make it almost impossible to guess the number of monitors by merely looking at Screen dimensions.

Windows has an API function, EnumDisplayMonitors for this very purpose. EnumDisplayMonitors enumerates all display monitors
using a callback function.

See the following code which enumerates all monitors and returns their count. Start a new project, add a code module and insert the following code.
___
[tt]
Option Explicit
Private Declare Function EnumDisplayMonitors Lib "user32" (ByVal hDC As Long, lprcClip As Any, ByVal lpfnEnum As Long, dwData As Long) As Long
Sub Main()
MsgBox GetMonitorCount
End Sub
Private Function GetMonitorCount() As Long
EnumDisplayMonitors 0, ByVal 0&, AddressOf MonitorEnumProc, GetMonitorCount
End Function
Private Function MonitorEnumProc(ByVal hMonitor As Long, ByVal hDCMonitor As Long, ByVal lprcMonitor As Long, dwData As Long) As Long
dwData = dwData + 1 'increase monitor count
'Debug.Print dwData, hMonitor
MonitorEnumProc = 1
End Function[/tt]
___

Set the Startup Object to Sub Main and run the program. I tested on my notebook with projector output as extended screen and it worked fine.

Note that the callback function returns a unique handle, hMonitor, for each enumerated monitor. You can inquire more about the monitor by passing this handle to GetMonitorInfo API function which fills in a MONITORINFOEX structure which contains details like monitor resolution and its virtual screen coordinates. These details tell the exact layout of all monitors, if required.
 
Your code accurately reported 4 monitors on my computer.

-George
Microsoft SQL Server MVP
My Blogs
SQLCop
twitter
"The great things about standards is that there are so many to choose from." - Fortune Cookie Wisdom
 
>4 monitors

Cool computer! ... and thanks for testing :)
 
>I've got a VB6 program that "remembers" the last screen position and resumes it's location the next time the user starts it up.

So (all) we have to determine is if the previously saved position of a form is valid in the current monitor setup; if it is not we have to adjust its Left and Top to fall in the Primary or the Nearest monitor or display a message.
 
COOL code Hypetia!! Can't wait to try it! Thank you!!!

------------------------------------
[yinyang] Over 20 years of programming, and still learning every day! [yinyang]
 
>So (all) we have to determine is if the previously saved position of a form is valid in the current monitor setup; if it is not we have to adjust its Left and Top to fall in the Primary or the Nearest monitor or display a message.

That is pretty much it. When loading the application, we have to find a monitor which is closest to the saved window position.

Of course, the application will find the same monitor if the configuration is not changed.

If the configuration is changed or the user is running the application from another machine, and there is no monitor present at the saved location, we have to find a monitor closest to that location and move the window on that monitor instead.

See the working example which demonstrate this. It also shows how to get a layout of all monitors on the virtual screen using the EnumDisplayMonitors function.

1. Start a new project, set the border style of Form1 to Fixed Single.
2. Place a Label on the form. Set its name to lblMonitors and make it a control array by setting its Index to 0.
3. Insert the following code in Form1.
___
[tt]
Private Sub Form_Load()
EnumMonitors Me
LoadPosition hwnd
End Sub

Private Sub Form_Unload(Cancel As Integer)
SavePosition hwnd
End Sub[/tt]
___

4. Add a module and insert the following code and test the program with different monitor configurations.
___
[tt]
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 MonitorFromRect Lib "user32" (ByRef lprc As RECT, ByVal dwFlags As Long) As Long
Private Declare Function GetMonitorInfo Lib "user32" Alias "GetMonitorInfoA" (ByVal hMonitor As Long, ByRef lpmi As MONITORINFO) As Long
Private Declare Function GetWindowRect Lib "user32" (ByVal hwnd As Long, lpRect As RECT) As Long
Private Declare Function UnionRect Lib "user32" (lprcDst As RECT, lprcSrc1 As RECT, lprcSrc2 As RECT) As Long
Private Declare Function OffsetRect Lib "user32" (lpRect As RECT, ByVal x As Long, ByVal y As Long) As Long
Private Declare Function MoveWindow Lib "user32" (ByVal hwnd As Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal bRepaint As Long) As Long
Private Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Private Type MONITORINFO
cbSize As Long
rcMonitor As RECT
rcWork As RECT
dwFlags As Long
End Type
Const MONITOR_DEFAULTTONEAREST = &H2
Dim rcMonitors() As RECT 'coordinate array for all monitors
Dim rcVS As RECT 'coordinates for Virtual Screen
Function EnumMonitors(F As Form) As Long
Dim N As Long
EnumDisplayMonitors 0, ByVal 0&, AddressOf MonitorEnumProc, N
With F
.Move .Left, .Top, (rcVS.Right - rcVS.Left) * 2 + .Width - .ScaleWidth, (rcVS.Bottom - rcVS.Top) * 2 + .Height - .ScaleHeight
End With
F.Scale (rcVS.Left, rcVS.Top)-(rcVS.Right, rcVS.Bottom)
F.Caption = N & " Monitor" & IIf(N > 1, "s", vbNullString)
F.lblMonitors(0).Appearance = 0 'Flat
F.lblMonitors(0).BorderStyle = 1 'FixedSingle
For N = 0 To N - 1
If N Then
Load F.lblMonitors(N)
F.lblMonitors(N).Visible = True
End If
With rcMonitors(N)
F.lblMonitors(N).Move .Left, .Top, .Right - .Left, .Bottom - .Top
F.lblMonitors(N).Caption = "Monitor " & N + 1 & vbLf & _
.Right - .Left & " x " & .Bottom - .Top & vbLf & _
"(" & .Left & ", " & .Top & ")-(" & .Right & ", " & .Bottom & ")"
End With
Next
End Function
Private Function MonitorEnumProc(ByVal hMonitor As Long, ByVal hdcMonitor As Long, lprcMonitor As RECT, dwData As Long) As Long
ReDim Preserve rcMonitors(dwData)
rcMonitors(dwData) = lprcMonitor
UnionRect rcVS, rcVS, lprcMonitor 'merge all monitors together to get the virtual screen coordinates
dwData = dwData + 1 'increase monitor count
MonitorEnumProc = 1 'continue
End Function

Sub SavePosition(hwnd As Long)
Dim rc As RECT
GetWindowRect hwnd, rc 'save position in pixel units
SaveSetting "Multi Monitor Demo", "Position", "Left", rc.Left
SaveSetting "Multi Monitor Demo", "Position", "Top", rc.Top
End Sub

Sub LoadPosition(hwnd As Long)
Dim rc As RECT, Left As Long, Top As Long, hMonitor As Long, mi As MONITORINFO
GetWindowRect hwnd, rc 'obtain the window rectangle
'move the window rectangle to position saved previously
Left = GetSetting("Multi Monitor Demo", "Position", "Left", rc.Left)
Top = GetSetting("Multi Monitor Demo", "Position", "Top", rc.Left)
OffsetRect rc, Left - rc.Left, Top - rc.Top
'find the monitor closest to window rectangle
hMonitor = MonitorFromRect(rc, MONITOR_DEFAULTTONEAREST)
'get info about monitor coordinates and working area
mi.cbSize = Len(mi)
GetMonitorInfo hMonitor, mi
'adjust the window rectangle so it fits inside the work area of the monitor
If rc.Left < mi.rcWork.Left Then OffsetRect rc, mi.rcWork.Left - rc.Left, 0
If rc.Right > mi.rcWork.Right Then OffsetRect rc, mi.rcWork.Right - rc.Right, 0
If rc.Top < mi.rcWork.Top Then OffsetRect rc, 0, mi.rcWork.Top - rc.Top
If rc.Bottom > mi.rcWork.Bottom Then OffsetRect rc, 0, mi.rcWork.Bottom - rc.Bottom
'move the window to new calculated position
MoveWindow hwnd, rc.Left, rc.Top, rc.Right - rc.Left, rc.Bottom - rc.Top, 0
End Sub[/tt]
 
Ummm...
Sorry Hypetia I really did'nt intent to put you through all that. I was just quietly reffering back to the code I linked to in my first post.
 
Well, I tried it and I'm getting an error...

"Compile Error: Invalid use of AddressOf operator"
and "AddressOf MonitorEnumProc" is highlighted in the editor

I copied/pasted the code, so not sure what else it could be...

------------------------------------
[yinyang] Over 20 years of programming, and still learning every day! [yinyang]
 
Just in case it's needed, here's the source project files.

It's a "mini NIST" clock app that embeds a webbrowser object, which in turn displays the NIST clock widget.

------------------------------------
[yinyang] Over 20 years of programming, and still learning every day! [yinyang]
 
 http://www.ancient-tiger.com/bf2142/uploads/MiniNist.zip
>4. Add a module and insert the following code ...

The code will not run in a Form.
 
*SLAPS FOREHEAD*

Der.... it WOULD help if I read the instructions, wouldn't it?

I'll try that, thanks for directing ADOS tiger's attention to that little detail.

------------------------------------
[yinyang] Over 20 years of programming, and still learning every day! [yinyang]
 
And...it works like a charm!!!!!!!!!!!!

Thanks again Hypetia :D

------------------------------------
[yinyang] Over 20 years of programming, and still learning every day! [yinyang]
 
Watch out for the Label called lblMonitors which you'll need on the Form; set its Index Property to 0.
 
>I really did'nt intent to put you through all that.

Never mind Hugh, I did it for my own fun.

I worked at multiple monitors first time when a friend asked me to write a program for managing and displaying orders simultaneously. He set up a stall at a food festival and wanted an app for registering and displaying orders.

The main application window stayed on the primary monitor, where orders were registered and customers were given a coupon with an order number.

The second monitor contained a full screen, borderless form which displayed all orders in sequence which were ready for collection, along with the customer name. Contents of the second screen were controlled from the main window on the primary monitor.

Wrote that program on a short notice of about one day. :) He used a notebook with its VGA output connected to a projector as second screen.
 
>Your code accurately reported 4 monitors on my computer.

I want four monitors too.

An unforeseen consequence of the information revolution has been the exponential propagation of human error.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top