Visual Basic Enumeration/Callback Routines

EnumWindows: Enumerate (and Restore) a Window via Callback
     
Posted:   Wednesday March 1, 2000
Updated:   Monday December 26, 2011
     
Applies to:   VB5, VB6
Developed with:   VB5, Windows 95
OS restrictions:   None
Author:   VBnet - Randy Birch
     

Related:  

SetWindowPlacement: Restore and Activate a Window via its hWnd
GetWindowThreadProcessId: Obtain the hWnd of an App Started with Shell()
     
 Prerequisites
None.

Here's a quick routine that will enumerate all top-level windows and provide a Restore feature to restore the app to the foreground. Once again the venerable EnumWindows API forms the base for this demo, with supporting roles going to GetWindowPlacement, BringWindowToTop, and friends.

The routine enumerates the top-level windows and adds each to a list, also assigning the window's handle to the list item's ItemData property. On selecting an item, GetWindowPlacement is called and the current window state is reflected in one of the three option buttons. Pressing the Restore button activates the selected window, and restores it regardless of its previous state. As coded, the option buttons are for displaying the current state, but a simple change in the RestoreWindow routine would provide the ability to specify the restore state.

Where a window is top-level, but has no title, the class name is shown along with the word (class) following it (as with item 1 in the list).

 BAS Module Code
Place the following code into the general declarations area of a bas module:

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.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Public Type RECT
    Left    As Long
    Top     As Long
    Right   As Long
    Bottom  As Long
End Type

Public Type POINTAPI
    x       As Long
    y       As Long
End Type

Public Type WINDOWPLACEMENT
    Length            As Long
    flags             As Long
    showCmd           As Long
    ptMinPosition     As POINTAPI
    ptMaxPosition     As POINTAPI
    rcNormalPosition  As RECT
End Type

Public Const SW_SHOWNORMAL = 1
Public Const SW_SHOWMINIMIZED = 2
Public Const SW_SHOWMAXIMIZED = 3
Public Const SW_SHOWNOACTIVATE = 4
Public Const WPF_RESTORETOMAXIMIZED = &H2

Public Declare Function EnumWindows Lib "user32" _
  (ByVal lpEnumFunc As Long, _
   ByVal lParam As Long) As Long

Private Declare Function GetWindowText Lib "user32" _
    Alias "GetWindowTextA" _
   (ByVal hwnd As Long, _
    ByVal lpString As String, _
    ByVal cch As Long) As Long
    
Private Declare Function GetClassName Lib "user32" _
    Alias "GetClassNameA" _
   (ByVal hwnd As Long, _
    ByVal lpClassName As String, _
    ByVal nMaxCount As Long) As Long

Private Declare Function GetWindowTextLength Lib "user32" _
    Alias "GetWindowTextLengthA" (ByVal hwnd As Long) As Long
 
Private Declare Function IsWindowVisible Lib "user32" _
   (ByVal hwnd As Long) As Long
   
Private Declare Function GetParent Lib "user32" _
   (ByVal hwnd As Long) As Long

Private Declare Function IsWindowEnabled Lib "user32" _
   (ByVal hwnd As Long) As Long

Public Declare Function IsZoomed Lib "user32" _
   (ByVal hwnd As Long) As Long

Public Declare Function GetWindowPlacement Lib "user32" _
  (ByVal hwnd As Long, _
   lpwndpl As WINDOWPLACEMENT) As Long
   
Public Declare Function SetWindowPlacement Lib "user32" _
  (ByVal hwnd As Long, _
   lpwndpl As WINDOWPLACEMENT) As Long
   
Public Declare Function BringWindowToTop Lib "user32" _
   (ByVal hwnd As Long) As Long

Public Declare Function SetForegroundWindow Lib "user32" _
   (ByVal hwnd As Long) As Long

Public Function EnumWindowProc(ByVal hwnd As Long, ByVal lParam As Long) As Long
   
  'working vars
   Dim nSize As Long
   Dim sTitle As String
   Dim pos As Integer
   
  'eliminate windows that are not top-level.
   If GetParent(hwnd) = 0& And _
      IsWindowVisible(hwnd) And _
      IsWindowEnabled(hwnd) Then

     'get the size of the string required
     'to hold the window title
      nSize = GetWindowTextLength(hwnd)
         
     'if the return is 0, there is no title
      If nSize > 0 Then
         
         sTitle = Space$(nSize + 1)
         Call GetWindowText(hwnd, sTitle, nSize + 1)
         sTitle = TrimNull(sTitle)
            
      Else
         
        'no title, so get the class name instead
         sTitle = Space$(64)
         Call GetClassName(hwnd, sTitle, 64)
         sTitle = TrimNull(sTitle) & "  (class)"
         
      End If

     'add the items to the list
      Form1.List1.AddItem sTitle
      Form1.List1.ItemData(Form1.List1.NewIndex) = hwnd
   
   End If
   
                       
  'To continue enumeration, return True
  'To stop enumeration return False (0).
  'When 1 is returned, enumeration continues
  'until there are no more windows left.
   EnumWindowProc = 1
   
End Function


Public Function TrimNull(startstr As String) As String

  Dim pos As Integer

  pos = InStr(startstr, Chr$(0))
  
  If pos Then
      TrimNull = Left$(startstr, pos - 1)
      Exit Function
  End If
  
  TrimNull = startstr
  
End Function
 Form Code
To a form, add a list (List1), a command button (Command1), a label (Label1) and a control array of option buttons using indexes 1 through 3 (Option1(1)-Option1(3). Option1(0) is not used and can be deleted. Add the following code to the form:

Option Explicit

Private Sub RestoreWindow(hWndToRestore As Long)

   Dim currWinP As WINDOWPLACEMENT
   
  'if a window handle passed
   If hWndToRestore Then
   
     'prepare the WINDOWPLACEMENT type
     'to receive the window coordinates
     'of the specified handle
      currWinP.Length = Len(currWinP)
   
     'get the info...
      If GetWindowPlacement(hWndToRestore, currWinP) > 0 Then
      
        'based on the returned info,
        'determine the window state
         If currWinP.showCmd = SW_SHOWMINIMIZED Then
      
           'it is minimized, so restore it
            With currWinP
               .Length = Len(currWinP)
               .flags = 0&
               .showCmd = SW_SHOWNORMAL
            End With
            
            Call SetWindowPlacement(hWndToRestore, currWinP)
         
         Else
           
           'it is on-screen, so make it visible
            Call SetForegroundWindow(hWndToRestore)
            Call BringWindowToTop(hWndToRestore)
         
         End If
      End If
   End If
   
End Sub

Private Sub List1_Click()

   Dim hWndSelected As Long
   Dim currWinP As WINDOWPLACEMENT
   
   hWndSelected = List1.ItemData(List1.ListIndex)
   
   Label2.Caption = "hwnd: " & hWndSelected
   
  'if a window handle...
   If hWndSelected Then
   
     'prepare the WINDOWPLACEMENT type
     'to receive the window coordinates
     'of the specified handle
      currWinP.Length = Len(currWinP)
   
     'get the info...
      If GetWindowPlacement(hWndSelected, currWinP) > 0 Then
      
        'based on the returned info,
        'determine the window state. 
        'Conveniently, the option array 
        'indices and the SW_ window state 
        'values match, allowing the direct 
        'assigning of the values.
         Option1(currWinP.showCmd).Value = True
         
      End If
   
   End If
   
End Sub


Private Sub Command1_Click()

  'retrieve the hwnd from the list's
  'ItemData and pass to the RestoreWindow routine
   RestoreWindow List1.ItemData(List1.ListIndex)

End Sub

Private Sub Form_Load()
  
   Call EnumWindows(AddressOf EnumWindowProc, &H0)
   
   If List1.ListCount Then List1.ListIndex = 0
   
   Label1.Caption = List1.ListCount & " windows found."

End Sub
 Comments
You could add or remove API or logic in the Enum proc to modify the results. And if you want to add more info into the list itself, you might want to take a look at designing the listbox layout using the CoolTabs util.

 
 

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