Go Back  Xtreme Visual Basic Talk > Legacy Visual Basic (VB 4/5/6) > Knowledge Base > Tutors' Corner > FindWindowEx v EnumChildWindows


Reply
 
Thread Tools Display Modes
  #1  
Old 12-23-2003, 01:04 AM
Mathimagics's Avatar
Mathimagics Mathimagics is offline
Algorithms 'R' Us

Forum Leader
* Guru *
 
Join Date: Jun 2002
Location: Canberra
Posts: 4,123
Default FindWindowEx v EnumChildWindows


.
Child windows - Enumerate or Find?

A common requirement is to be able to enumerate (list all) or find a child window that belongs to some target parent window, or to some descendant of that parent window.

There are 2 powerful API tools for this job, FindWindowEx and EnumChildWindows. This tutorial assumes you are familiar with how EnumChildWindows works, but even if you aren't you can still use the code.

I'll deal with the 2 functions in the following posts. All examples will use the same module declarations shown below.

But first a couple of important API issues relevant to the topic:

GetWindowText vs WM_GETTEXT

The GetWindowText function does NOT work for child windows in another process, only top-level windows.

To get the text of any window that has a text property, you should use the SendMessage function with the WM_GETTEXT message.

In these examples I declare an alias for SendMessage, called SendMessageS in which lParam is declared as a String. This is convenient when using the WM_GETTEXT message in VB.


FindWindowEx vs Caption/Classname params

Many standard API declarations for FindWindow and FindWindowEx specify the final 2 parameters as type String. This is because these functions can be used to search for particular captions and/or classnames.

For enumeration or iterative finding, we want to pass zero for both these parameters - not the string "0", nor an empty string, but 0.
To do this, we need to declare FindWindowEx as having both parameters specified as "ByVal param As Long".

In these examples I declare an alias for FindWindowEx, called FindWindowX.

Code:
Option Explicit ' ' Enumerating and finding child windows ' using FindWindowEx and EnumChildWindows ' ' [email]MathImagics@yahoo.co.uk[/email] ' '==================================================================== ' ' note: alias API declarations FindWindowEx and SendmessageS ' '==================================================================== Declare Function GetParent Lib "user32" (ByVal hwnd As Long) As Long Declare Function EnumChildWindows Lib "user32" (ByVal hWndParent _ As Long, ByVal lpEnumFunc As Long, ByVal lParam As Long) As Long Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hwnd As Long, _ ByVal lpClassName As String, ByVal nMaxCount As Long) As Long Declare Function SendMessageS Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, _ ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As String) As Long Declare Function FindWindowX Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, _ ByVal hWnd2 As Long, ByVal lpsz1 As Long, ByVal lpsz2 As Long) As Long Public Const WM_GETTEXT = &HD
__________________
Cogito, ergo codo
Reply With Quote
  #2  
Old 12-23-2003, 01:35 AM
Mathimagics's Avatar
Mathimagics Mathimagics is offline
Algorithms 'R' Us

Forum Leader
* Guru *
 
Join Date: Jun 2002
Location: Canberra
Posts: 4,123
Default EnumChildWindows

EnumChildWindows

EnumChildWindows will pass through every child window of the starting window, calling the enumertion function whose address you specify.

The enumeration function is passed a new window handle each time your function is called.

Also, if any window handle it passes you itself has children, it will call you for each of those as well, enumerating in this way the entire window subtree.

Here is a simple enumeration function called EnumChildWindow, which prints the window's handle, classname, and text (if available) in the debug window.

Note that the function MUST be placed in a Module, not on a Form! You can call from anywhere, of course.

Code:
Function EnumChildWindow(ByVal hChild As Long, ByVal lParam As Long) As Long Dim wClass As String, wText As String Dim j As Integer wClass = Space(64) j = GetClassName(hChild, wClass, 63) wClass = Left(wClass, j) wText = Space(256) j = SendMessageS(hChild, WM_GETTEXT, 255, wText) wText = Left(wText, j) Debug.Print "Enum " & hChild; ", "; wClass; If Len(wText) Then Debug.Print ", """; wText; """"; Debug.Print EnumChildWindow = 1 ' Continue enumeration End Function

The parameter lParam is not used by us, but must be declared in the function for compatibility with the Win32 API.

It can be useful if you want to have the same enumeration function perform different tasks (a generic enumerator).

When you call EnumChildWindows, you can give a different value that will then be passed to your enumeration function, and this value can be used as a "mode" selector during the current enumeration.

To list a window and all it's children, we call our enumeration function once directly to "enumerate" the starting window, then call EnumChildWindows to enumerate the children:
Code:
EnumChildWindow hParent, 0 ' one call directly to list parent EnumChildWindows hParent, AddressOf EnumChildWindow, 0

Here's some sample output from a Windows Explorer application window:
  • Enum 6423866, ExploreWClass, "My Documents"
  • Enum 3671040, WorkerW
  • Enum 9372726, ReBarWindow32
  • Enum 2557106, ToolbarWindow32
  • Enum 984332, ComboBoxEx32, "My Documents"
  • Enum 1705154, ToolbarWindow32
  • Enum 2557142, ComboBox
  • Enum 1377446, Edit, "My Documents"
  • Enum 7931064, ToolbarWindow32
  • Enum 2622682, WorkerW
  • Enum 11470104, ToolbarWindow32
  • Enum 3212492, WorkerW
  • Enum 1901600, msctls_statusbar32, "50 object(s) (Disk free space: 14.9 GB)"
  • Enum 2294932, SHELLDLL_DefView
  • Enum 3081442, SysListView32
  • Enum 2294824, SysHeader32
  • Enum 2426026, BaseBar
  • Enum 1639554, ReBarWindow32
  • Enum 1049860, ToolbarWindow32
  • Enum 2819166, SysTreeView32, "Folders"
__________________
Cogito, ergo codo

Last edited by MathImagics; 12-23-2003 at 01:46 AM.
Reply With Quote
  #3  
Old 12-23-2003, 02:46 AM
Mathimagics's Avatar
Mathimagics Mathimagics is offline
Algorithms 'R' Us

Forum Leader
* Guru *
 
Join Date: Jun 2002
Location: Canberra
Posts: 4,123
Default

FindWindowEx

FindWindowEx returns a single window handle. When used to enumerate child windows, one call is made to find the first child of a window, then further calls are made to get the next sibling, until it returns 0.

It's just like the VB Dir$ function, or the TreeView .Child (first child) and .Next properties!

Here's how we'd enumerate all children of a window (we'll use the EnumChildWindow function already listed to report the window details)
Code:
Dim hChild As Long EnumChildWindow hParent, 0 hChild = FindWindowX(hParent, 0, 0, 0) ' get first child of hParent While hChild EnumChildWindow hChild, 0 ' call our EnumProc directly hChild = FindWindowX(hParent, hChild, 0, 0) ' get next sibling of hChild Wend
Here's the results from the same Windows Explorer application window used in the previous example.:[list]
  • Enum 6423866, ExploreWClass, "My Documents"
  • Enum 3671040, WorkerW
  • Enum 3212492, WorkerW
  • Enum 1901600, msctls_statusbar32, "50 object(s) (Disk free space: 14.9 GB)"
  • Enum 2294932, SHELLDLL_DefView
  • Enum 2426026, BaseBar

You can see it can't enumerate the children of these windows like EnumChildWindows did, because we are not being recursive!

Emulating EnumChildWindows

We can use FindWindowEx to exactly emulate EnumChildWindows. This is useful not just to show how EnumChildWindows works, but we'll see later on that it can sometimes be more convenient to use our own.

Here's how it might look if coded in VB (and we could put AddressOf in a function call!)
Code:
Function EnumChildWindows(ByVal hParent As Long, _
      ByVal EnumProc As Long, ByVal lParam As Long) As Long
   
   Dim hChild As Long
   Dim Continue As Boolean

   Continue = AddressOf EnumProc(hParent, lParam)

   hChild = FindWindowX(hParent, 0, 0, 0)
   While hChild And Continue
      Continue = EnumChildWindows(hChild, 0, 0)  ' recursive call!
      hChild = FindWindowX(hParent, hChild, 0, 0)
      Wend
   EnumChildWindows = Continue
   End Function
You can see it's very straight-forward, it enumerates the current window, then calls itself to recursively enumerate each child window.

Really, all we have to do is substitute our enumeration procedure calls and introduce a mechanism that allows us to NOT enumerate the starting window, and we have our own EnumChildWindows function we'll call FindChildWindows.

Code:
Function FindChildWindows(ByVal hParent As Long, ByVal ChildFlag As Integer) Dim hChild As Long Dim Continue As Boolean Continue = True hChild = FindWindowX(hParent, 0, 0, 0) If ChildFlag Then Continue = EnumChildWindow(hParent, 0) While hChild And Continue If Continue Then Continue = FindChildWindows(hChild, 1) hChild = FindWindowX(hParent, hChild, 0, 0) Wend FindChildWindows = Continue End Function
The ChildFlag parameter is introduced to allow the caller to prevent the function from enumerating the starting window. That's how EnumChildWindows works.

To emulate EnumChildWindows exactly pass 0, or pass 1 to enumerate the starting window, as we do here:

Code:
FindChildWindows hParent, 1

This now reproduces the complete list that we got from calling EnumChildWindow (to list the starting window), and then EnumChildWindows
  • Enum 6423866, ExploreWClass, "My Documents"
  • Enum 3671040, WorkerW
  • Enum 9372726, ReBarWindow32
  • Enum 2557106, ToolbarWindow32
  • Enum 984332, ComboBoxEx32, "My Documents"
  • Enum 1705154, ToolbarWindow32
  • Enum 2557142, ComboBox
  • Enum 1377446, Edit, "My Documents"
  • Enum 7931064, ToolbarWindow32
  • Enum 2622682, WorkerW
  • Enum 11470104, ToolbarWindow32
  • Enum 3212492, WorkerW
  • Enum 1901600, msctls_statusbar32, "50 object(s) (Disk free space: 14.9 GB)"
  • Enum 2294932, SHELLDLL_DefView
  • Enum 3081442, SysListView32
  • Enum 2294824, SysHeader32
  • Enum 2426026, BaseBar
  • Enum 1639554, ReBarWindow32
  • Enum 1049860, ToolbarWindow32
  • Enum 2819166, SysTreeView32, "Folders"
__________________
Cogito, ergo codo
Reply With Quote
  #4  
Old 12-23-2003, 03:29 AM
Mathimagics's Avatar
Mathimagics Mathimagics is offline
Algorithms 'R' Us

Forum Leader
* Guru *
 
Join Date: Jun 2002
Location: Canberra
Posts: 4,123
Default

FindWindowEx for Enumeration

I said it could be convenient to use FindWindowEx to emulate EnumChildWindows.

One case is where we wish to be aware of the window tree structure - which child is parent to whom. Using EnumChildWindows, our enumeration function would have do a bit of work to establish the ancestry of each window (like call GetParent, look up a table, etc).

But inside EnumChildWindows (or our emulation), we can pass parent information to ourselves, making it easy to know where in the tree we are.

To illustrate, let's build a TreeView of the target window, instead of just listing the details in the debug window.

We simply combine the window information extraction code from our previous EnumChildWindow function, and combine it with the FindWindowsChild recursive logic, and we have a new Sub called BuildWindowTree.

The only assumption here is that there is a control called TreeView1.
Code:
Sub BuildWindowTree(ByVal hChild As Long, ByVal ParentKey As String) Dim wNode As Node ' node for this window Dim wKey As String ' key for this window Dim wClass As String, wText As String Dim j As Integer wClass = Space(64) j = GetClassName(hChild, wClass, 63) wClass = Left(wClass, j) wText = Space(256) j = SendMessageS(hChild, WM_GETTEXT, 255, wText) wText = Left(wText, j) If Len(wText) Then wText = wClass & ", """ & wText & """" Else wText = wClass End If wKey = "W" & hChild If ParentKey = "" Then Set wNode = TreeView1.Nodes.Add(, , wKey, hChild & ", " & wText) Else Set wNode = TreeView1.Nodes.Add(ParentKey, tvwChild, wKey, hChild & ", " & wText) End If Dim hParent As Long hParent = hChild hChild = FindWindowX(hChild, 0, 0, 0) While hChild BuildWindowTree hChild, wKey hChild = FindWindowX(hParent, hChild, 0, 0) Wend wNode.Expanded = True End Sub
__________________
Cogito, ergo codo
Reply With Quote
Reply


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
FindwindowEx Question :) mattnhcc04 API 2 11-16-2003 05:49 PM
FindWindowEX dallen API 0 08-08-2003 02:35 PM
EnumChildWindows Blaggut API 5 07-31-2003 02:26 PM
FindWindowEx tezcanalinca API 4 01-26-2003 02:36 PM
Problems with ByVal in EnumChildWindows Ykroc123 API 1 06-28-2002 05:37 PM

Advertisement:





Free Publications
The ASP.NET 2.0 Anthology
101 Essential Tips, Tricks & Hacks - Free 156 Page Preview. Learn the most practical features and best approaches for ASP.NET.
subscribe
Programmers Heaven C# School Book -Free 338 Page eBook
The Programmers Heaven C# School book covers the .NET framework and the C# language.
subscribe
Build Your Own ASP.NET 3.5 Web Site Using C# & VB, 3rd Edition - Free 219 Page Preview!
This comprehensive step-by-step guide will help get your database-driven ASP.NET web site up and running in no time..
subscribe
 
 
-->