|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Visual Basic Enumeration/Callback Routines EnumChildWindows: Enumeration of Parent and Child Windows via Callbacks |
|
Posted: | Wednesday January 26, 2000 |
Updated: | Monday December 26, 2011 |
Applies to: | VB5, VB6 |
Developed with: | VB6, Windows NT4 |
OS restrictions: | None |
Author: | VBnet - Randy Birch |
Prerequisites |
VB5 / VB6. Note that the indent may only display correctly on the VB5 version of the demo. |
|
Many
Windows' Enum APIs provide callback data for specific tasks.
This project demonstrates using both EnumWindows and EnumChildWindows APIs and their respective EnumWindowProc and EnumChildProc callbacks. The main form in the demo enumerates all top-level windows on the system populating ListView with the window information. Double-clicking a ListItem will open a child form containing the windows under the parent passed. Where a window does not have text, its class name is substituted in the first column. The second column is the window handle and the third reflects the type of data contained in the first column. The last column is the window class name, redundant for those displaying classes in the first column. And as a bonus, the demo shows how to indent list items for subordinate data. Note however that indentation required that a imagelist be associated with the control.
|
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. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Private Const LVIF_INDENT As Long = &H10 Private Const LVIF_TEXT As Long = &H1 Private Const LVM_FIRST As Long = &H1000 Private Const LVM_SETITEM As Long = (LVM_FIRST + 6) Private Type LVITEM mask As Long iItem As Long iSubItem As Long state As Long stateMask As Long pszText As String cchTextMax As Long iImage As Long lParam As Long iIndent As Long End Type Public Declare Function EnumWindows Lib "user32" _ (ByVal lpEnumFunc As Long, _ ByVal lParam As Long) As Long Public Declare Function EnumChildWindows Lib "user32" _ (ByVal hWndParent As Long, _ ByVal lpEnumFunc As Long, _ ByVal lParam As Long) As Long Private Declare Function GetWindowTextLength Lib "user32" _ Alias "GetWindowTextLengthA" _ (ByVal hwnd 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 IsWindowVisible Lib "user32" _ (ByVal hwnd As Long) As Long Private Declare Function GetParent Lib "user32" _ (ByVal hwnd 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 Public Function EnumWindowProc(ByVal hwnd As Long, _ ByVal lParam As Long) As Long 'working vars Dim nSize As Long Dim sTitle As String Dim sClass As String Dim sIDType As String Dim itmX As ListItem Dim nodX As Node 'eliminate windows that are not top-level. If GetParent(hwnd) = 0& And _ IsWindowVisible(hwnd) Then 'get the window title / class name sTitle = GetWindowIdentification(hwnd, sIDType, sClass) 'add to the listview Set itmX = Form1.ListView1.ListItems.Add(Text:=sTitle, Key:=CStr(hwnd) & "h") itmX.SmallIcon = Form1.ImageList1.ListImages("parent").Key itmX.SubItems(1) = CStr(hwnd) itmX.SubItems(2) = sIDType itmX.SubItems(3) = sClass 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 Private Function GetWindowIdentification(ByVal hwnd As Long, _ sIDType As String, _ sClass As String) As String Dim nSize As Long Dim sTitle As String '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) sIDType = "title" sClass = Space$(64) Call GetClassName(hwnd, sClass, 64) Else 'no title, so get the class name instead sTitle = Space$(64) Call GetClassName(hwnd, sTitle, 64) sClass = sTitle sIDType = "class" End If GetWindowIdentification = TrimNull(sTitle) End Function Public Function EnumChildProc(ByVal hwnd As Long, _ ByVal lParam As Long) As Long 'working vars Dim sTitle As String Dim sClass As String Dim sIDType As String Dim itmX As ListItem 'get the window title / class name sTitle = GetWindowIdentification(hwnd, sIDType, sClass) 'add to the listview Set itmX = Form2.ListView1.ListItems.Add(,, sTitle) itmX.SubItems(1) = hwnd itmX.SubItems(2) = sIDType itmX.SubItems(3) = sClass Listview_IndentItem Form2.ListView1.hwnd, CLng(itmX.Index), 1 EnumChildProc = 1 End Function Private 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 'if this far, there was 'no Chr$(0), so return the string TrimNull = startstr End Function Private Sub Listview_IndentItem(hwnd As Long, _ nItem As Long, _ nIndent As Long) Dim LV As LVITEM 'if nIndent indicates that indentation 'is requested nItem is the item to indent If nIndent > 0 Then With LV .mask = LVIF_INDENT .iItem = nItem - 1 '0-based .iIndent = nIndent End With Call SendMessage(hwnd, LVM_SETITEM, 0&, LV) End If End Sub |
Form1 Code |
To Form1, add a listview with 4 columns, a command button (Command1)
. Note the illustrations above show ListImages but the code below does
not use them in order to provide a rapid demo): To Form2, just add a listview (Listview1). Add the following code to Form1: |
|
Option Explicit Private Sub Command1_Click() ListView1.ListItems.Clear Call EnumWindows(AddressOf EnumWindowProc, &H0) End Sub Private Sub Form_Load() Me.Move (Screen.Width - Me.Width) / 2, (Screen.Height - Me.Height) / 2 With ListView1 .ColumnHeaders.Add , , "Window Class or Title" .ColumnHeaders.Add , , "Handle" .ColumnHeaders.Add , , "Type" .ColumnHeaders.Add , , "Class Name" .View = lvwReport End With End Sub Private Sub ListView1_DblClick() Dim hwndSelected As Long hwndSelected = Val(ListView1.SelectedItem.Key) Load Form2 Call Form2.EnumSelectedWindow(ListView1.SelectedItem.Text, hwndSelected) End Sub |
Form2 Code |
Add the following code to Form2 (the illustrations above show ListImages but the code below does not use them in order to provide a rapid demo): |
|
Option Explicit Public Sub EnumSelectedWindow(sItem As String, hwnd As Long) ListView1.ListItems.Clear ListView1.ListItems.Add ,, sItem Call EnumChildWindows(hwnd, AddressOf EnumChildProc, &H0) Me.Show vbModal End Sub Private Sub Form_Load() Me.Move (Screen.Width - Me.Width) / 2, (Screen.Height - Me.Height) / 2 With ListView1 .ColumnHeaders.Add , , "Window Class or Title" .ColumnHeaders.Add , , "Handle" .ColumnHeaders.Add , , "Type" .ColumnHeaders.Add , , "Class Name" .View = lvwReport End With End Sub |
Comments |
Clicking the Enum Windows button will fill the listview with the top-level windows on the system. Double clicking an item will display the child windows for the selected window handle. |
|
|
|
|||||
|
|||||
|
|||||
Copyright ©1996-2011 VBnet and Randy Birch. All Rights Reserved. |