Visual Basic Enumeration/Callback Routines
EnumDisplayDevices: Enumerating System Display Devices
Posted:   Friday March 29, 2002
Updated:   Monday December 26, 2011
Applies to:   VB4-32, VB5, VB6
Developed with:   VB6, Windows XP
OS restrictions:   Windows 98 or greater, Windows 2000 or greater
Author:   VBnet - Randy Birch


ChangeDisplaySettings: Change Display Resolution
EnumDisplaySettings: Enumerate Available Display Resolutions
EnumDisplayDevices: Enumerating System Display Devices

EnumDisplayMonitors: Enumerating System Monitor Info
Windows 98 and later, Windows 2000 and later.

EnumDisplayDevices provides information about the display devices in a system, and can be used in two ways.

The call to EnumDisplayDevices passes four parameters:

  • lpDevice - the device name.
  • iDevNum - the index value that specifies the display device of interest. The operating system identifies each display device with an index value. The index values are consecutive integers, starting at 0. If a system has three display devices, for example, they are specified by the index values 0, 1, and 2.
  • lpDisplayDevice - a DISPLAY_DEVICE structure that receives information about the display device specified by iDevNum, and
  • dwFlags - currently not used and should be set to zero.

To enumerate devices - aka adapters, the lpDevice member of the EnumDisplayDevices, which normally would point to a device name, is passed as 0&. The iDevNum member, is incremented in successive calls to the API until the call returns 0.  On each call, the DISPLAY_DEVICE structure passed is filled with appropriate information about the device (as shown by the Device info in the illustration).

When you want to retrieve information about the physical monitor attached to a specific device, the iDevNum member is not used and is passed as 0&, whereas the lpDevice member of EnumDisplayDevices is passed containing the device name of interest (i.e. \\.\DISPLAY1), where DISPLAY_DEVICE structure is filled with appropriate information about the monitor (as shown by the Accoc Monitor info in the illustration).

This demo shows building that loop, calling the API to retrieve the device info, extracting the device name, and calling again to retrieve the monitor info for the device (if available).

 BAS Module Code

 Form Code
Add a listview (LV) and a command button to a form. To the listview, add five column headers as indicated, and set the style to report mode. Add the following to the form:

Option Explicit
' Copyright 1996-2011 VBnet/Randy Birch, All Rights Reserved.
' Some pages may also contain other copyrights by the author.
' Distribution: You can freely use this code in your own
'               applications, but you may not reproduce 
'               or publish this code on any web site,
'               online service, or distribute as source 
'               on any media without express permission.
'for listview column auto-resizing
Private Const LVM_FIRST As Long = &H1000
Private Const LVM_SETCOLUMNWIDTH As Long = (LVM_FIRST + 30)
Private Const LVSCW_AUTOSIZE As Long = -1

Private Declare Function SendMessage Lib "user32" _
   Alias "SendMessageA" _
  (ByVal hwnd As Long, _
   ByVal wMsg As Long, _
   ByVal wParam As Long, _
   lParam As Any) As Long

'EnumDisplayDevices Requirements
'  Windows NT/2000/XP: Included in Windows 2000 and later.
'  Windows 95/98/Me:   Included in Windows 98 and later.
   cb As Long
   DeviceName(0 To 31) As Byte
   DeviceString(0 To 127) As Byte
   StateFlags As Long
   DeviceID(0 To 127) As Byte
   DeviceKey(0 To 127) As Byte
End Type

Private Const DD_ATTACHED_TO_DESKTOP As Long = &H1
Private Const DD_MULTI_DRIVER        As Long = &H2
Private Const DD_PRIMARY_DEVICE      As Long = &H4
Private Const DD_MIRRORING_DRIVER    As Long = &H8
Private Const DD_VGA_COMPATIBLE      As Long = &H10
Private Const DD_REMOVABLE           As Long = &H20
Private Const DD_DISCONNECT          As Long = &H2000000 'WINVER >= 5
Private Const DD_REMOTE              As Long = &H4000000 'WINVER >= 5
Private Const DD_MODESPRUNED         As Long = &H8000000 'WINVER >= 5

Private Declare Function EnumDisplayDevices Lib "user32" _
   Alias "EnumDisplayDevicesA" _
  (ByVal lpDevice As Any, _
   ByVal iDevNum As Long, _
   lpDisplayDevice As DISPLAY_DEVICE, _
   ByVal dwFlags As Long) As Long

Private Sub Form_Load()

   With ListView1
      .View = lvwReport
      .Sorted = False
      .ColumnHeaders.Add , , "DisplayDevice Member"
      .ListItems.Add , , "Device Name"
      .ListItems.Add , , "Device String"
      .ListItems.Add , , "Device StateFlags:"
      .ListItems.Add , , "  - part of desktop"
      .ListItems.Add , , "  - primary device"
      .ListItems.Add , , "  - pseudo device"
      .ListItems.Add , , "  - VGA compatible"
      .ListItems.Add , , "  - removable (cannot be primary)"
      .ListItems.Add , , "  - more modes than output device"
      .ListItems.Add , , "Assoc Monitor Name"
      .ListItems.Add , , "Assoc Monitor String"
      .ListItems.Add , , "Assoc Monitor StateFlags:"
      .ListItems.Add , , "  - multi-driver"
   End With

   Command1.Caption = "EnumDisplayDevices"

End Sub

Private Sub Command1_Click()

   Call EnumSystemDisplayDevices
   Call lvAutosizeControl(ListView1)
End Sub

Private Sub EnumSystemDisplayDevices()
   Dim iDevNum As Long
   Dim thiscol As Long
   Dim sDeviceName As String 'required in 3 places
  'Query all display devices in the system by
  'calling EnumDisplayDevices in a loop, starting
  'with iDevNum set to 0, and incrementing until
  'the function fails (call returns non-zero if
  'true or 0 if false).
   dev.cb = Len(dev)
   iDevNum = 0
   Do While EnumDisplayDevices(0&, iDevNum, dev, 0&)

     'for each display device returned,
     'add a new column to the listview
     'and populate its data
      With ListView1
         sDeviceName = TrimNull(StrConv(dev.DeviceName, vbUnicode))
         .ColumnHeaders.Add , , sDeviceName
         thiscol = (.ColumnHeaders.Count - 1)
         .ListItems(1).SubItems(thiscol) = sDeviceName
         .ListItems(2).SubItems(thiscol) = TrimNull(StrConv(dev.DeviceString, vbUnicode))
         .ListItems(3).SubItems(thiscol) = dev.StateFlags
         If dev.StateFlags And DD_ATTACHED_TO_DESKTOP Then
            .ListItems(4).SubItems(thiscol) = "Yes"
         End If
         If dev.StateFlags And DD_PRIMARY_DEVICE Then
            .ListItems(5).SubItems(thiscol) = "Yes"
         End If
         If dev.StateFlags And DD_MIRRORING_DRIVER Then
            .ListItems(6).SubItems(thiscol) = "Yes"
         End If
         If dev.StateFlags And DD_VGA_COMPATIBLE Then
            .ListItems(7).SubItems(thiscol) = "Yes"
         End If
         If dev.StateFlags And DD_REMOVABLE Then
            .ListItems(8).SubItems(thiscol) = "Yes"
         End If
         If dev.StateFlags And DD_MODESPRUNED Then
            .ListItems(9).SubItems(thiscol) = "Yes"
         End If
        'When null was passed as lpDevice above,
        'information about the display device (adapter)
        'was returned. By calling the API once again,
        'this time specifying lpDevice=dev.devicename and
        'iDevNum=0, the same call returns information about
        'the monitor connected to the specified device.
         If EnumDisplayDevices(sDeviceName, 0, dev, 0&) <> 0 Then
            .ListItems(10).SubItems(thiscol) = TrimNull(StrConv(dev.DeviceName, vbUnicode))
            .ListItems(11).SubItems(thiscol) = TrimNull(StrConv(dev.DeviceString, vbUnicode))
            .ListItems(12).SubItems(thiscol) = dev.StateFlags
            If dev.StateFlags And DD_MULTI_DRIVER Then
               .ListItems(13).SubItems(thiscol) = "Yes"
            End If
         End If
      End With

      iDevNum = iDevNum + 1

End Sub

Private Sub lvAutosizeControl(lv As ListView)

   Dim col2adjust As Long

  'Size each column based on the maximum of
  'either the ColumnHeader text width, or,
  'if the items below it are wider, the
  'widest list item in the column
   lv.Visible = False
   For col2adjust = 0 To lv.ColumnHeaders.Count - 1
      Call SendMessage(lv.hwnd, _
                       LVM_SETCOLUMNWIDTH, _
                       col2adjust, _
                       ByVal LVSCW_AUTOSIZE_USEHEADER)

   lv.Visible = True
End Sub

Private Function TrimNull(item As String)

    Dim pos As Integer
   'double check that there is a chr$(0) in the string
    pos = InStr(item, Chr$(0))
    If pos Then
       TrimNull = Left$(item, pos - 1)
       TrimNull = item
    End If
End Function


PayPal Link
Make payments with PayPal - it's fast, free and secure!


Copyright 1996-2011 VBnet and Randy Birch. All Rights Reserved.
Terms of Use  |  Your Privacy


Hit Counter