Visual Basic System Services
FindWindow: Window Title and Class Name Demo
Posted:   Saturday March 1, 1997
Updated:   Monday December 26, 2011
Applies to:   VB4-32, VB5, VB6
Developed with:   VB6, Windows NT4
OS restrictions:   None
Author:   VBnet - Randy Birch

Although setup of the following project appears complicated, all setup code is performed in the form load event.  Thus it's just a matter of adding the controls as specified below and running the demo.

This demo implements the FindWindowLike routine.  The FindWindowLike method does not require you to first know the precise (current) window name of the application you're trying to locate, allowing even partial strings in searching out the window. The only condition that the code makes is that, at a minimum, the ClassName parameter be at least "*".

The original author of the FindWindowLike routine is unknown.

 BAS Module Code

 Form Code
Start a new project, and add the following controls to the form: 
  • Seven command buttons (Command1 through Command7).  Set the Index property of Command4 to 0 to create a control array.
  • Two text boxes (Text1, Text2)
  • One list box (List1)
  • One label (Label1)
  • One additional label (Label2), and set its index property to 0 to create a control array.

Add the following code:

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.
Dim hwndSelected As Long
Dim sClassSelected As String
Dim sTitleSelected  As String

Private Type RECT
  Left    As Long
  Top     As Long
  Right   As Long
  Bottom  As Long
End Type

Private Type POINTAPI
  x       As Long
  y       As Long
End Type

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

Private Const LB_SETTABSTOPS = &H192

Private Const GW_HWNDNEXT = 2
Private Const GW_CHILD = 5
Private Const GWW_ID = (-12)

Private Const SW_SHOWNORMAL = 1
Private Const SW_SHOWMINIMIZED = 2
Private Const SW_SHOWMAXIMIZED = 3

Private Declare Function FindWindow Lib "user32" _
   Alias "FindWindowA" _
  (ByVal lpClassName As String, _
   ByVal lpWindowName As String) As Long
Private Declare Function GetDesktopWindow Lib "user32" () As Long

Private Declare Function GetWindow Lib "user32" _
  (ByVal hwnd As Long, _
   ByVal wCmd As Long) As Long

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

Private Declare Function GetWindowRect Lib "user32" _
  (ByVal hwnd As Long, _
   lpRect As RECT) 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 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 Declare Function SendMessage Lib "user32" _
   Alias "SendMessageA" _
  (ByVal hwnd As Long, _
   ByVal wMsg As Long, _
   ByVal wParam As Long, _
   lParam As Any) As Long

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

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

Private Declare Function ShowWindow Lib "user32" _
  (ByVal hwnd As Long, _
   ByVal nCommand5 As Long) As Long

Private Sub Form_Load()

  'The control positioning in this routine
  'was calculated on a screen using small fonts.
  'If you use large fonts you'll have to tweak the
  'settings slightly.
   Load Command4(1)
   Load Command4(2)
   Command4(0).Visible = True
   Command4(1).Visible = True
   Command4(2).Visible = True
   Load Label2(1)
   Load Label2(2)
   Load Label2(3)
   Load Label2(4)
   Label2(0).Visible = True
   Label2(1).Visible = True
   Label2(2).Visible = True
   Label2(3).Visible = True
   Label2(4).Visible = True
   Label2(0).AutoSize = True
   Label2(1).AutoSize = True
   Label2(2).AutoSize = True
   Label2(3).AutoSize = True
   Label2(4).AutoSize = True
   With Me
      .Width = 8225
      .Height = 5065
      .Move (Screen.Width - .Width) \ 2, (Screen.Height - .Height) \ 2
      .Caption = "VBnet FindWindow / Window Title and Class Name Demo"
   End With

   Command1.Caption = "Reset Names"
   Command2.Caption = "Find"
   Command3.Caption = "Show"
   Command4(0).Caption = "< Tab"
   Command4(1).Caption = "Tab >"
   Command4(2).Caption = "Reset"
   Command5.Caption = "Use as Window Class"
   Command6.Caption = "Use as Window Title"
   Command7.Caption = "End"
   Label1.Caption = "<results here>"
   Lable1.AutoSize = True
   Label2(0).Caption = "Class name (* for any)"
   Label2(1).Caption = "Full or partial title (* for any)"
   Label2(2).Caption = "hwnd:"
   Label2(3).Caption = "Class name:"
   Label2(4).Caption = "Full window title:"

   Text1.Move 200, 400, 1700, 285
   Text2.Move 2000, 400, 3000, 285
   Label2(0).Move Text1.Left, Text1.Top - 200
   Label2(1).Move Text2.Left, 150
   Command1.Move 5300, Text1.Top - 50, 1500, 365
   Label1.Move 200, 800
   List1.Move 200, 1400, Me.ScaleWidth - 400, 2200
   Label2(2).Move List1.Left, List1.Top - 250
   Label2(3).Move List1.Left + 940, List1.Top - 250
   Label2(4).Move List1.Left + 2500, List1.Top - 250
   Command2.Move 200, 3700, 2200, 365
   Command3.Move 200, 4100, 2200, 365
   Command4(0).Move 2500, Command2.Top, 800, 365
   Command4(1).Move 3300, Command2.Top, 800, 365
   Command4(2).Move 4100, Command2.Top, 800, 365
   Command5.Move 5000, Command2.Top, 1800, 365
   Command6.Move 5000, Command3.Top, 1800, 365
   Command7.Move 7000, Command5.Top, 800, 365
  'Initialize controls
   Text2.Text = "*Microsoft Internet Explorer"
   Text1.Text = "*"
   Command4_Click 2
End Sub

Private Sub Command1_Click()
  'Initialize controls
   Text2.Text = "*Microsoft Internet Explorer"
   Text1.Text = "*"
End Sub

Private Sub Command2_Click()

   Dim hWnds() As Long 'Used to return window handles
   Dim cnt As Long
   Dim sTitle As String
   Dim sClass As String
  'Initialize controls
   Command6.Enabled = False
   Command5.Enabled = False
   Command3.Enabled = False
  'Set the FindWindowLike text values
   sTitle = Text2.Text & "*"
   sClass = Text1.Text
   cnt = FindWindowLike(hWnds(), 0, sTitle, sClass)
   Label1.Caption = "Found : " & cnt & " windows."
   Command4(0).Enabled = cnt > 0
   Command4(1).Enabled = cnt > 0

End Sub

Private Sub Command3_Click()
   Dim msg As String
   Dim currRect As RECT
   currWinP.Length = Len(currWinP)
   Call GetWindowPlacement(hwndSelected, currWinP)
   If currWinP.showCmd = SW_SHOWMINIMIZED Then
      msg = "The selected window is presently minimized." & vbCrLf & vbCrLf
      msg = msg & "Select: " & vbCrLf
      msg = msg & "     Yes to restore it to the top," & vbCrLf
      msg = msg & "     No to restore it without activating, or" & vbCrLf
      msg = msg & "     Cancel to abort this action."
      Select Case MsgBox(msg, 291, sTitleSelected)
        Case vbYes
         currWinP.Length = Len(currWinP)
         currWinP.flags = 0&
         currWinP.showCmd = SW_SHOWNORMAL
         Call SetWindowPlacement(hwndSelected, currWinP)
         Case vbNo
         currWinP.Length = Len(currWinP)
         currWinP.flags = 0&
         currWinP.showCmd = SW_SHOWNOACTIVATE
         Call SetWindowPlacement(hwndSelected, currWinP)
       Case Else
      End Select

      Select Case MsgBox("Bring the selected window to the top?", 292, sTitleSelected)
         Case vbYes
            Call SetForegroundWindow(hwndSelected)
         Case Else
      End Select
   End If
   If Err Then MsgBox "Couldn't activate " & sTitleSelected, , Me.Caption

End Sub

Private Sub Command4_Click(Index As Integer)

  'TAB ADJUST - moves tabstops to align wide items
   Static classTab As Long
   Static winTab As Long
   Select Case Index
      Case 0: classTab = classTab& - 2: winTab = winTab - 3
      Case 1: classTab = classTab& + 2: winTab = winTab + 3
      Case 2: classTab = 42: winTab = 110
   End Select
   If classTab < 26 Then classTab = 26
   If winTab < 90 Then winTab = 90
   Command4(0).Enabled = (classTab <> 35 And winTab <> 90)
   ReDim tabs(1 To 2) As Long
   tabs(1) = classTab    'class
   tabs(2) = winTab   'window title
  'reset the initial tabstops then set the defined ones
   Call SendMessage(List1.hwnd, LB_SETTABSTOPS, 0&, ByVal 0&)
   Call SendMessage(List1.hwnd, LB_SETTABSTOPS, UBound(tabs), tabs(1))
   Command4(2).Enabled = (classTab <> 42) And (winTab <> 110)

End Sub

Private Sub Command5_Click()
  'SET CLASS TEXT - if item selected in list
   If Len(sClassSelected) > 0 Then
      Text1.Text = sClassSelected
   End If

End Sub

Private Sub Command7_Click()
   Unload Me
End Sub

Private Sub Command6_Click()
  'SET TITLE TEXT - if item selected in list
   If Len(sTitleSelected) > 0 Then
      Text2.Text = sTitleSelected
   End If
End Sub

Private Sub List1_Click()

   Dim sItem As String
   Dim pos1 As Integer
   Dim pos2 As Integer
   Command3.Enabled = List1.ListIndex > -1  'Show button
   Command5.Enabled = List1.ListIndex > -1  'Use as Class button
   Command6.Enabled = List1.ListIndex > -1  'Use as Title button
  'extract the data from the selected list item
  'get the selected item's handle
   sItem = List1.List(List1.ListIndex)
   pos1 = InStr(sItem, vbTab)
  'get the selected item class name
   If pos1 Then hwndSelected = CLng(Left$(sItem, pos1 - 1))
  'get the selected item window class and title
   sItem = Mid$(sItem, pos1 + 1, Len(sItem))
   pos2 = InStr(sItem, vbTab)
   If pos2 Then
      sClassSelected = Left$(sItem, pos2 - 1)
      sTitleSelected = Mid$(sItem, pos2 + 1, Len(sItem))
   End If
End Sub

Private Function FindWindowLike(hWndArray() As Long, _
                                ByVal hWndStart As Long, _
                                WindowText As String, _
                                Classname As String) As Long
   Dim hwnd As Long
   Dim sWindowText As String
   Dim sClassname As String
   Dim r As Long
  'Hold the level of recursion and
  'hold the number of matching windows
   Static level As Long
   Static found As Long
  'Initialize if necessary
   If level = 0 Then
     found = 0
     ReDim hWndArray(0 To 0)
     If hWndStart = 0 Then hWndStart = GetDesktopWindow()
   End If
  'Increase recursion counter
   level = level + 1
  'Get first child window
   hwnd = GetWindow(hWndStart, GW_CHILD)

   Do Until hwnd = 0
      'Search children by recursion
       Call FindWindowLike(hWndArray(), hwnd, WindowText, Classname)
      'Get the window text and class name
       sWindowText = Space(255)
       r = GetWindowText(hwnd, sWindowText, 255)
       sWindowText = Left(sWindowText, r)
       sClassname = Space(255)
       r = GetClassName(hwnd, sClassname, 255)
       sClassname = Left(sClassname, r)
      'Check that window matches the search parameters
       If (sWindowText Like WindowText) And (sClassname Like Classname) Then
           found = found + 1
           ReDim Preserve hWndArray(0 To found)
           hWndArray(found) = hwnd
           List1.AddItem hWndArray(found) & vbTab & sClassname & vbTab & sWindowText

       End If
      'Get next child window
       hwnd = GetWindow(hwnd, GW_HWNDNEXT)
  'Decrement recursion counter
   level = level - 1
  'Return the number of windows found
    FindWindowLike = found

End Function
Save the project, then run. Enter the full or partial window title to locate, and/or the class name, if known. Note that the search is case-sensitive.

Pressing Find, the list box will return the matches. Select an item, and either:

  1. Press 'Use as Window Class' to add just the class name to the search, or
  2. Press 'Use as Window Title' to add just the window title to the search, or
  3. Double click the entry to add both.

Press Find again to narrow the search, repeating as needed. At any point, once an item is selected, the Show Selected button will become enabled. When pressed, depending on the current window state of the selected item, one of two Message boxes will appear.

Use the buttons to change the column spacing of the list, if needed.

Note as well that the textbox containing the text you've entered will also appear in the list because of the call to the GetWindowText API. You could code the routine to only list parent windows by discarding those who return a value to an IsChild() API call.


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