Get Window Handles Associated With Process in vb.net

For an application, it became necessary to find all handles (hWND) associated with that process and not just the main window. Here is what I came up with. I won’t be able to use these concepts at work yet but will once we upgrade our framework version. Hope it helps someone.

Imports System.Collections.Generic
Imports System.Runtime.InteropServices
Imports System.Text
 
Public Class ApiWindow
  Public MainWindowTitle As String = ""
  Public ClassName As String = ""
  Public hWnd As Int32
End Class
 
''' <summary> 
''' Enumerate top-level and child windows 
''' </summary> 
''' <example> 
''' Dim enumerator As New WindowsEnumerator()
''' For Each top As ApiWindow in enumerator.GetTopLevelWindows()
'''    Console.WriteLine(top.MainWindowTitle)
'''    For Each child As ApiWindow child in enumerator.GetChildWindows(top.hWnd) 
'''        Console.WriteLine(" " + child.MainWindowTitle)
'''    Next child
''' Next top
''' </example> 
Public Class WindowsEnumerator
 
  Private Delegate Function EnumCallBackDelegate(ByVal hwnd As Integer, ByVal lParam As Integer) As Integer
 
  ' Top-level windows.
  Private Declare Function EnumWindows Lib "user32" _
   (ByVal lpEnumFunc As EnumCallBackDelegate, ByVal lParam As Integer) As Integer
 
  ' Child windows.
  Private Declare Function EnumChildWindows Lib "user32" _
   (ByVal hWndParent As Integer, ByVal lpEnumFunc As EnumCallBackDelegate, ByVal lParam As Integer) As Integer
 
  ' Get the window class.
  Private Declare Function GetClassName _
   Lib "user32" Alias "GetClassNameA" _
   (ByVal hwnd As Integer, ByVal lpClassName As StringBuilder, ByVal nMaxCount As Integer) As Integer
 
  ' Test if the window is visible--only get visible ones.
  Private Declare Function IsWindowVisible Lib "user32" _
   (ByVal hwnd As Integer) As Integer
 
  ' Test if the window's parent--only get the one's without parents.
  Private Declare Function GetParent Lib "user32" _
   (ByVal hwnd As Integer) As Integer
 
  ' Get window text length signature.
  Private Declare Function SendMessage _
   Lib "user32" Alias "SendMessageA" _
   (ByVal hwnd As Int32, ByVal wMsg As Int32, ByVal wParam As Int32, ByVal lParam As Int32) As Int32
 
  ' Get window text signature.
  Private Declare Function SendMessage _
   Lib "user32" Alias "SendMessageA" _
   (ByVal hwnd As Int32, ByVal wMsg As Int32, ByVal wParam As Int32, ByVal lParam As StringBuilder) As Int32
 
  Private _listChildren As New List(Of ApiWindow)
  Private _listTopLevel As New List(Of ApiWindow)
 
  Private _topLevelClass As String = ""
  Private _childClass As String = ""
 
  ''' <summary>
  ''' Get all top-level window information
  ''' </summary>
  ''' <returns>List of window information objects</returns>
  Public Overloads Function GetTopLevelWindows() As List(Of ApiWindow)
 
    EnumWindows(AddressOf EnumWindowProc, &H0)
 
    Return _listTopLevel
 
  End Function
 
  Public Overloads Function GetTopLevelWindows(ByVal className As String) As List(Of ApiWindow)
 
    _topLevelClass = className
 
    Return Me.GetTopLevelWindows()
 
  End Function
 
  ''' <summary>
  ''' Get all child windows for the specific windows handle (hwnd).
  ''' </summary>
  ''' <returns>List of child windows for parent window</returns>
  Public Overloads Function GetChildWindows(ByVal hwnd As Int32) As List(Of ApiWindow)
 
    ' Clear the window list.
    _listChildren = New List(Of ApiWindow)
 
    ' Start the enumeration process.
    EnumChildWindows(hwnd, AddressOf EnumChildWindowProc, &H0)
 
    ' Return the children list when the process is completed.
    Return _listChildren
 
  End Function
 
  Public Overloads Function GetChildWindows(ByVal hwnd As Int32, ByVal childClass As String) As List(Of ApiWindow)
 
    ' Set the search
    _childClass = childClass
 
    Return Me.GetChildWindows(hwnd)
 
  End Function
 
  ''' <summary>
  ''' Callback function that does the work of enumerating top-level windows.
  ''' </summary>
  ''' <param name="hwnd">Discovered Window handle</param>
  ''' <returns>1=keep going, 0=stop</returns>
  Private Function EnumWindowProc(ByVal hwnd As Int32, ByVal lParam As Int32) As Int32
 
    ' Eliminate windows that are not top-level.
    If GetParent(hwnd) = 0 AndAlso CBool(IsWindowVisible(hwnd)) Then
 
      ' Get the window title / class name.
      Dim window As ApiWindow = GetWindowIdentification(hwnd)
 
      ' Match the class name if searching for a specific window class.
      If _topLevelClass.Length = 0 OrElse window.ClassName.ToLower() = _topLevelClass.ToLower() Then
        _listTopLevel.Add(window)
      End If
 
    End If
 
    ' To continue enumeration, return True (1), and to stop enumeration 
    ' return False (0).
    ' When 1 is returned, enumeration continues until there are no 
    ' more windows left.
 
    Return 1
 
  End Function
 
  ''' <summary>
  ''' Callback function that does the work of enumerating child windows.
  ''' </summary>
  ''' <param name="hwnd">Discovered Window handle</param>
  ''' <returns>1=keep going, 0=stop</returns>
  Private Function EnumChildWindowProc(ByVal hwnd As Int32, ByVal lParam As Int32) As Int32
 
    Dim window As ApiWindow = GetWindowIdentification(hwnd)
 
    ' Attempt to match the child class, if one was specified, otherwise
    ' enumerate all the child windows.
    If _childClass.Length = 0 OrElse window.ClassName.ToLower() = _childClass.ToLower() Then
      _listChildren.Add(window)
    End If
 
    Return 1
 
  End Function
 
  ''' <summary>
  ''' Build the ApiWindow object to hold information about the Window object.
  ''' </summary>
  Private Function GetWindowIdentification(ByVal hwnd As Integer) As ApiWindow
 
    Const WM_GETTEXT As Int32 = &HD
    Const WM_GETTEXTLENGTH As Int32 = &HE
 
    Dim window As New ApiWindow()
 
    Dim title As New StringBuilder()
 
    ' Get the size of the string required to hold the window title.
    Dim size As Int32 = SendMessage(hwnd, WM_GETTEXTLENGTH, 0, 0)
 
    ' If the return is 0, there is no title.
    If size > 0 Then
      title = New StringBuilder(size + 1)
 
      SendMessage(hwnd, WM_GETTEXT, title.Capacity, title)
    End If
 
    ' Get the class name for the window.
    Dim classBuilder As New StringBuilder(64)
    GetClassName(hwnd, classBuilder, 64)
 
    ' Set the properties for the ApiWindow object.
    window.ClassName = classBuilder.ToString()
    window.MainWindowTitle = title.ToString()
    window.hWnd = hwnd
 
    Return window
 
  End Function
 
End Class

Consulting Requests

Feedback

Blog Front Page

 


Join me on Facebook

Technorati Tags: ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,

Windows Live Tags: vb.net,.NET Framework,csharp,Handles,Window,Process,System,Generic,Runtime,InteropServices,Text,ApiWindow,MainWindowTitle,WindowsEnumerator,GetTopLevelWindows,GetChildWindows,Delegate,EnumCallBackDelegate,EnumWindows,EnumChildWindows,GetClassName,Alias,IsWindowVisible,parent,GetParent,signature,SendMessage,SendMessageA,EnumWindowProc,enumeration,EnumChildWindowProc,Callback,WM_GETTEXT,WM_GETTEXTLENGTH,collection,hWND,enumerator

  1. #1 by SRINIVAS on November 15, 2008 - 10:25 am

    Hi,i want to find all hwnd of a given process id, which of the above functions should i call for that?Thanks,-srinivas y.

  2. #2 by Kelly on November 15, 2008 - 12:44 pm

  3. #3 by BillNew on May 23, 2012 - 6:13 pm

    While this is interesting… it simply doesn’t work properly.

    This is a better program but alas it is in C++:
    http://www.catch22.net/software/winspy-17

    I have a separate program that has multiple dialogs in MFC C++ that I need to find the handles to the Visible Form Dialogs. Once that I can do that then I will use them in another program to show all the Visible Form Dialogs in a VB.Net 2003 Application on their own “panels” within an existing program. This will give me the best of both programs without having to rely on switching between them.

    I have seen MANY code examples that will give you the items within the Form Dialog when you have its’ handle… but that is useless for my project!

    Thank you for your interesting code… Sadly it won’t help me finish my task!

    See this link:
    http://social.msdn.microsoft.com/Forums/en-US/vblanguage/thread/8e904352-53a3-47a6-b945-e8c0e9456b6a

  4. #4 by Scott Wheeler on August 16, 2012 - 10:50 am

    ‘Well done’ on this class! I had to change a bit of syntax in the following example, but it worked perfectly after that!

    Dim enumerator As New WindowsEnumerator()
    For Each top As WindowsEnumerator.ApiWindow In enumerator.GetTopLevelWindows

    Console.WriteLine(top.MainWindowTitle)

    For Each child As WindowsEnumerator.ApiWindow In enumerator.GetChildWindows(top.hWnd)

    Console.WriteLine(child.MainWindowTitle)

    Next child

    Next top

    The Windows Spy++ presents a ‘Control ID’ property for the individual windows detected. Would it be possible to include this in the ApiWindow object? If so, could you indicate how?

    Thanks.

Leave a comment