www.pudn.com > windowsrunning > Enumerator.cls


VERSION 1.0 CLASS 
BEGIN 
  MultiUse = -1  'True 
  Persistable = 0  'NotPersistable 
  DataBindingBehavior = 0  'vbNone 
  DataSourceBehavior  = 0  'vbNone 
  MTSTransactionMode  = 0  'NotAnMTSObject 
END 
Attribute VB_Name = "Enumerator" 
Attribute VB_GlobalNameSpace = True 
Attribute VB_Creatable = True 
Attribute VB_PredeclaredId = False 
Attribute VB_Exposed = False 
Attribute VB_Description = "Use this Class to perform all of the enumeration functions. This class also has many functions to do with windows in general, plus a few explicit to the edit control." 
Attribute VB_Ext_KEY = "SavedWithClassBuilder6" ,"Yes" 
Attribute VB_Ext_KEY = "Top_Level" ,"Yes" 
Option Explicit 
' 
'  I have been to great troubles to learn all of the techniques in this program. 
'  I have spent many, many hours and late nights coding the many functions which I 
'  have included. As much as I resent it, Planet Source Code requires that I put 
'  the source code in the zip file. So I have placed it in here for you to view. 
'  Please use it wisely. And give me credit for all of the hard work that I have 
'  done. My biggest fear is that somebody will do an almost straight rip of this 
'  code, and take the credit for themselves. Please do not let this happening. I'm 
'  placing a lot of trust there. So please, use this program, use this code, and 
'  give me credit for it. If anybody rips all my routines, then my secret spy's 
'  (and I have a lot of them, as soon as I hire them) will tell me, and I'll get 
'  into my private jet (as soon as I buy it) and track you down over the whole 
'  world and eventually KILL YOU. You get the idea? Thanks. Read on for something 
'  a little more interesting! 
' 
' Code is Copyright Jolyon Bloomfield, February 2000 
' 
 
' A series of declares that drive this class around... 
Private Const MAX_PATH& = 260 
Private Const PROCESS_ALL_ACCESS = 0 
 
Private Const TH32CS_SNAPPROCESS = 2& 
Private Const TH32CS_SNAPTHREAD = 4& 
 
' ShowWindow() Commands 
Private Const SW_HIDE = 0 
Private Const SW_SHOWNORMAL = 1 
Private Const SW_NORMAL = 1 
Private Const SW_SHOWMINIMIZED = 2 
Private Const SW_SHOWMAXIMIZED = 3 
Private Const SW_MAXIMIZE = 3 
Private Const SW_SHOWNOACTIVATE = 4 
Private Const SW_SHOW = 5 
Private Const SW_MINIMIZE = 6 
Private Const SW_SHOWMINNOACTIVE = 7 
Private Const SW_SHOWNA = 8 
Private Const SW_RESTORE = 9 
Private Const SW_SHOWDEFAULT = 10 
Private Const SW_MAX = 10 
 
' For GetWindowLong 
Private Const GWL_WNDPROC = (-4) 
Private Const GWL_HINSTANCE = (-6) 
Private Const GWL_HWNDPARENT = (-8) 
Private Const GWL_STYLE = (-16) 
Private Const GWL_EXSTYLE = (-20) 
Private Const GWL_USERDATA = (-21) 
Private Const GWL_ID = (-12) 
 
' GetClassLong indexes 
Private Const GCL_WNDPROC = (-24) 
Private Const GCL_STYLE = (-26) 
Private Const GCL_MENUNAME = (-8) 
Private Const GCL_HMODULE = (-16) 
Private Const GCL_HICON = (-14) 
Private Const GCL_HCURSOR = (-12) 
Private Const GCL_HBRBACKGROUND = (-10) 
Private Const GCL_CBWNDEXTRA = (-18) 
Private Const GCL_CBCLSEXTRA = (-20) 
 
' SetWindowPos Flags 
Private Const SWP_NOSIZE = &H1 
Private Const SWP_NOMOVE = &H2 
Private Const SWP_NOZORDER = &H4 
Private Const SWP_NOREDRAW = &H8 
Private Const SWP_NOACTIVATE = &H10 
Private Const SWP_FRAMECHANGED = &H20        '  The frame changed: send WM_NCCALCSIZE 
Private Const SWP_SHOWWINDOW = &H40 
Private Const SWP_HIDEWINDOW = &H80 
Private Const SWP_NOCOPYBITS = &H100 
Private Const SWP_NOOWNERZORDER = &H200      '  Don't do owner Z ordering 
 
' SetWindowPos() hwndInsertAfter values 
Private Const HWND_TOP = 0 
Private Const HWND_BOTTOM = 1 
Private Const HWND_TOPMOST = -1 
Private Const HWND_NOTOPMOST = -2 
 
' 
' Note: All of the Window's Styles, Window's Extended Styles, 
' Window's messages, etc, etc, etc, messages, are stored in modConst.Bas 
' 
 
' All of the data types that this class requires (+ some in the global module) 
Private Type THREADENTRY32 
  lSize As Long 
  lUsage As Long 
  lThreadID As Long 
  lOwnerProcessID As Long 
  lBasePri As Long 
  lDeltaPri As Long 
  lFlags As Long 
End Type 
 
Private Type WINDOWPLACEMENT 
  Length As Long 
  flags As Long 
  showCmd As Long 
  ptMinPosition As POINTAPI 
  ptMaxPosition As POINTAPI 
  rcNormalPosition As RECT 
End Type 
 
Private Type PROCESSENTRY32 
  dwSize As Long 
  cntUsage As Long 
  th32ProcessID As Long 
  th32DefaultHeapID As Long 
  th32ModuleID As Long 
  cntThreads As Long 
  th32ParentProcessID As Long 
  pcPriClassBase As Long 
  dwFlags As Long 
  szexeFile As String * MAX_PATH 
End Type 
 
Private Type ThreadIt 
  ID As Long 
  Process As Long 
End Type 
 
Private Type Winded 
  hWnd As Long 
  Parent As Long 
  StringParentUse As String 
  ClassName As String 
  Text As String 
  UseMe As Boolean 
  Thread As Long 
  Process As Long 
  DisplayText As String 
End Type 
 
Public Enum EnumPos 
  Normal = 0 
  Maximized = 1 
  Minimized = 2 
End Enum 
 
Public Enum Relations 
  GW_HWNDFIRST = 0 
  GW_HWNDLAST = 1 
  GW_HWNDNEXT = 2 
  GW_HWNDPREV = 3 
  GW_OWNER = 4 
  GW_CHILD = 5 
End Enum 
 
' What a heck of a lot of declares!!! 
Private Declare Function GetLastError Lib "kernel32" () As Long 
Private Declare Function TerminateProcess Lib "kernel32" (ByVal ApphProcess As Long, ByVal uExitCode As Long) As Long 
Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal blnheritHandle As Long, ByVal dwAppProcessId As Long) As Long 
Private Declare Function ProcessFirst Lib "kernel32" Alias "Process32First" (ByVal hSnapshot As Long, uProcess As PROCESSENTRY32) As Long 
Private Declare Function ProcessNext Lib "kernel32" Alias "Process32Next" (ByVal hSnapshot As Long, uProcess As PROCESSENTRY32) As Long 
Private Declare Function CreateToolhelpSnapshot Lib "kernel32" Alias "CreateToolhelp32Snapshot" (ByVal lFlags As Long, lProcessId As Long) As Long 
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long 
Private Declare Function GetExitCodeProcess Lib "kernel32" (ByVal hProcess As Long, lpExitCode As Long) As Long 
Private Declare Function GetDesktopWindow Lib "user32" () 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 GetWindowTextLength Lib "user32" Alias "GetWindowTextLengthA" (ByVal hWnd As Long) As Long 
Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hWnd As Long, lpdwProcessId As Long) As Long 
Private Declare Function GetParent Lib "user32" (ByVal hWnd As Long) As Long 
Private Declare Function EnumWindows Lib "user32" (ByVal lpEnumFunc As Long, ByRef lParam() As Long) As Long 
Private Declare Function EnumChildWindows Lib "user32" (ByVal hWndParent As Long, ByVal lpEnumFunc As Long, ByRef lParam() As Long) As Long 
Private Declare Function IsWindow Lib "user32" (ByVal hWnd As Long) As Long 
Private Declare Function IsWindowEnabled Lib "user32" (ByVal hWnd As Long) As Long 
Private Declare Function IsWindowVisible 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 
Private Declare Function PostMessage Lib "user32" Alias "PostMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long 
Private Declare Function SetFocus Lib "user32" (ByVal hWnd As Long) As Long 
Private Declare Function SetForegroundWindow Lib "user32" (ByVal hWnd As Long) As Long 
Private Declare Function GetCurrentProcessId Lib "kernel32" () 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 GetMenu Lib "user32" (ByVal hWnd As Long) As Long 
Private Declare Function GetSubMenu Lib "user32" (ByVal hMenu As Long, ByVal nPos As Long) As Long 
Private Declare Function IsMenu Lib "user32" (ByVal hMenu As Long) As Long 
Private Declare Function GetWindowPlacement Lib "user32" (ByVal hWnd As Long, lpwndpl As WINDOWPLACEMENT) 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 SetWindowPlacement Lib "user32" (ByVal hWnd As Long, lpwndpl As WINDOWPLACEMENT) As Long 
Private Declare Function SetWindowPos Lib "user32" (ByVal hWnd As Long, ByVal hWndInsertAfter As Long, ByVal X As Long, ByVal Y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long 
Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long) As Long 
Private Declare Function EnableWindow Lib "user32" (ByVal hWnd As Long, ByVal fEnable As Long) As Long 
Private Declare Function ShowWindow Lib "user32" (ByVal hWnd As Long, ByVal nCmdShow As Long) As Long 
Private Declare Function SetActiveWindow Lib "user32" (ByVal hWnd As Long) As Long 
Private Declare Function Thread32First Lib "kernel32" (ByVal hSnapshot As Long, uProcess As THREADENTRY32) As Long 
Private Declare Function Thread32Next Lib "kernel32" (ByVal hSnapshot As Long, uThread As THREADENTRY32) As Long 
Private Declare Function IsHungThread Lib "user32" (ByVal lThreadID As Long) As Long 
Private Declare Function SetParentA Lib "user32" Alias "SetParent" (ByVal hWndChild As Long, ByVal hWndNewParent As Long) As Long 
Private Declare Function IsZoomed Lib "user32" (ByVal hWnd As Long) As Long 
Private Declare Function IsIconic Lib "user32" (ByVal hWnd As Long) As Long 
Private Declare Function FlashWindow Lib "user32" (ByVal hWnd As Long, ByVal bInvert As Long) As Long 
Private Declare Function GetWindow Lib "user32" (ByVal hWnd As Long, ByVal wCmd As Long) As Long 
Private Declare Function GetNextWindow Lib "user32" Alias "GetWindow" (ByVal hWnd As Long, ByVal wFlag As Long) As Long 
Private Declare Function GetWindowDC Lib "user32" (ByVal hWnd As Long) As Long 
Private Declare Function ReleaseDC Lib "user32" (ByVal hWnd As Long, ByVal hdc As Long) As Long 
Private Declare Function BringWindowToTop Lib "user32" (ByVal hWnd As Long) As Long 
Private Declare Function SetWindowText Lib "user32" Alias "SetWindowTextA" (ByVal hWnd As Long, ByVal lpString As String) As Long 
Private Declare Function InvalidateRect Lib "user32" (ByVal hWnd As Long, lpRect As Any, ByVal bErase As Long) As Long 
Private Declare Function UpdateWindow Lib "user32" (ByVal hWnd As Long) As Long 
Private Declare Function GetClassLong Lib "user32" Alias "GetClassLongA" (ByVal hWnd As Long, ByVal nIndex As Long) As Long 
 
' These are the three enumerations. 
Private WindsEnum() As Long 
Private ThreadsEnum() As ThreadIt 
Private ProcessEnum() As Long 
 
' Other variables of sorts 
Private mvarEnumsReady As Boolean 
Private mvarNewEnum As ReEnumType 
Private DoingSomething As Boolean 
 
' 
' Sets how EnumIt looks after enumerations that are already there. 
' 
Public Property Let NewEnum(ByVal EnumNew As ReEnumType) 
Attribute NewEnum.VB_Description = "Sets what to do when a function is called that requires an enumeration to be present, but the enumeration doesn't exits." 
mvarNewEnum = EnumNew 
End Property 
Public Property Get NewEnum() As ReEnumType 
NewEnum = mvarNewEnum 
End Property 
 
' 
' Returns a window's process from it's hWnd 
' 
Public Function WindProcess(ByVal hWnd As Long) As Long 
Dim Temp As Long 
Temp = GetWindowThreadProcessId(hWnd, WindProcess) 
End Function 
 
' 
' Returns a window's thread from it's hWnd 
' 
Public Function WindThread(ByVal hWnd As Long) As Long 
Dim Temp As Long 
WindThread = GetWindowThreadProcessId(hWnd, Temp) 
End Function 
 
' 
' Returns the module path for a process through it's processId 
' 
Public Function ProcessName(ByVal ProcessID As Long) As String 
 
Dim uProcess As PROCESSENTRY32 
Dim rProcessFound As Long 
Dim hSnapshot As Long 
Dim i As Integer 
 
uProcess.dwSize = Len(uProcess) 
hSnapshot = CreateToolhelpSnapshot(TH32CS_SNAPPROCESS, 0&) 
rProcessFound = ProcessFirst(hSnapshot, uProcess) 
 
Do While rProcessFound 
  If uProcess.th32ProcessID = ProcessID Then ProcessName = FixApi(uProcess.szexeFile): Call CloseHandle(hSnapshot): Exit Function 
  rProcessFound = ProcessNext(hSnapshot, uProcess) 
Loop 
 
ProcessName = "" 
 
Call CloseHandle(hSnapshot) 
 
End Function 
 
' 
' Returns the parent of a window 
' 
Public Function ParentWind(ByVal hWnd As Long) As Long 
ParentWind = GetParent(hWnd) 
End Function 
 
' 
' Returns the desktop window 
' 
Public Function DesktopWind() As Long 
DesktopWind = GetDesktopWindow() 
End Function 
 
' 
' Formats a long value into hexedecimal, using 8 characters 
' 
Public Function Format8(ByVal Value As Long) As String 
Format8 = String(8 - Len(Trim(Hex(Value))), "0") & Trim(Hex(Value)) 
End Function 
 
' 
' Returns an enumeration of processes 
' 
Public Sub ReturnProcessEnum(ByRef Process() As Long) 
 
If (EnumsReady = False Or NewEnum = 1) And DoingSomething = False Then EnumAll 
 
Dim i As Long 
ReDim Process(LBound(ProcessEnum) To UBound(ProcessEnum)) As Long 
 
For i = LBound(ProcessEnum) To UBound(ProcessEnum) 
  Process(i) = ProcessEnum(i) 
Next i 
 
End Sub 
 
' 
' Returns an enumeration of threads 
' 
Public Sub ReturnThreadEnum(ByRef Threads() As Long) 
 
If (EnumsReady = False Or NewEnum = 1) And DoingSomething = False Then EnumAll 
 
Dim i As Long 
ReDim Threads(LBound(ThreadsEnum) To UBound(ThreadsEnum)) As Long 
 
For i = LBound(ThreadsEnum) To UBound(ThreadsEnum) 
  Threads(i) = ThreadsEnum(i).ID 
Next i 
 
End Sub 
 
' 
' Returns an enumeration of windows 
' 
Public Sub ReturnWindEnum(ByRef Winds() As Long) 
' 
' also remember to put the desktop window inside the enumeration 
' 
 
If (EnumsReady = False Or NewEnum = 1) And DoingSomething = False Then EnumAll 
 
Dim i As Long 
ReDim Winds(LBound(WindsEnum) To UBound(WindsEnum)) As Long 
 
For i = LBound(WindsEnum) To UBound(WindsEnum) 
  Winds(i) = WindsEnum(i) 
Next i 
 
End Sub 
 
' 
' Enumerates everything in a treeview control, according to the style) 
' 
Public Sub EnumInTreeView(ByRef TreeView As TreeView, Optional PicList As ImageList, Optional DesktopPic As String = "", Optional ProcessPic As String = "", Optional ThreadPic As String = "", Optional WindPic As String = "", Optional ByVal Style As DispEnum = 0) 
 
Dim Mouser As Hourglass 
Set Mouser = New Hourglass 
 
If (EnumsReady = False Or NewEnum = 1) And DoingSomething = False Then EnumAll 
TreeView.Visible = False 
 
Select Case Style 
  Case Is = DispEnum.Full 
    TreeFull TreeView, PicList, DesktopPic, ProcessPic, ThreadPic, WindPic 
End Select 
 
TreeView.Visible = True 
 
End Sub 
 
' 
' Returns if a window is valid or not 
' 
Public Function IsValidWindow(ByVal hWnd As Long) As Boolean 
IsValidWindow = IsWindow(hWnd) 
End Function 
 
' 
' Destroys all enumerations 
' 
Public Sub DestroyEnums() 
 
mvarEnumsReady = False 
ReDim ProcessEnum(0 To 0) As Long 
ReDim ThreadsEnum(0 To 0) As ThreadIt 
ReDim WindsEnum(0 To 0) As Long 
 
End Sub 
 
' 
' Returns whether or not the enumerations are ready 
' 
Public Property Get EnumsReady() As Boolean 
EnumsReady = mvarEnumsReady 
End Property 
 
' 
' Enumerates everything 
' 
Public Sub EnumAll() 
 
Dim Mouser As Hourglass 
Set Mouser = New Hourglass 
 
' Dimensioning 
Dim i As Long 
Dim k As Long 
Dim Temp As Long 
 
' First, we destroy the enumerations. 
DestroyEnums 
 
' 
' Now to enumerate the windows. 
' 
' Send it off to the module, as I can't use the addressof operator insed a class module. 
 
ReDim WindsEnum(0 To 0) As Long 
modConst.EnumAllWinds WindsEnum 
 
' 
' The windows are now enumerated. Now to enumerate the processes. 
' 
 
Dim uProcess As PROCESSENTRY32 
Dim rProcessFound As Long 
Dim hSnapshot As Long 
ReDim ProcessEnum(0 To 0) As Long 
 
uProcess.dwSize = Len(uProcess) 
hSnapshot = CreateToolhelpSnapshot(TH32CS_SNAPPROCESS, 0&) 
rProcessFound = ProcessFirst(hSnapshot, uProcess) 
 
Do While rProcessFound 
  ReDim Preserve ProcessEnum(0 To UBound(ProcessEnum) + 1) As Long 
  ProcessEnum(UBound(ProcessEnum)) = uProcess.th32ProcessID 
  rProcessFound = ProcessNext(hSnapshot, uProcess) 
Loop 
 
Call CloseHandle(hSnapshot) 
 
' 
' The processes are now also enumerated. 
' 
 
' 
' Thankyou to Konstantin Tretyakov (kt_ee@yahoo.com) for a lot of the code that went 
' into all of these enumerations!!! 
' 
 
'  /--- Code used before I found enumeration APIs 
' \/ 
' 
'Dim Found As Boolean 
'Dim CurrentThread As Long 
' 
'ReDim ThreadsEnum(0 To 0) As ThreadIt 
' 
'For i = 1 To UBound(WindsEnum) 
'  Found = False 
'  CurrentThread = WindThread(WindsEnum(i)) 
'  For k = 1 To UBound(ThreadsEnum) 
'    If CurrentThread = ThreadsEnum(k).ID Then Found = True: Exit For 
'  Next k 
'  If Found = False Then 
'    ReDim Preserve ThreadsEnum(0 To UBound(ThreadsEnum) + 1) As ThreadIt 
'    ThreadsEnum(UBound(ThreadsEnum)).ID = CurrentThread 
'    ThreadsEnum(UBound(ThreadsEnum)).Process = WindProcess(WindsEnum(i)) 
'  End If 
'Next i 
 
Dim lSnapShot As Long 
Dim CanEnum As Long 
Dim uThread  As THREADENTRY32 
Dim ItemToAdd As String 
ReDim ThreadsEnum(0 To 0) As ThreadIt 
 
lSnapShot = CreateToolhelpSnapshot(TH32CS_SNAPTHREAD, 0&) 
 
If lSnapShot <> 0 Then 
  uThread.lSize = Len(uThread) 
  CanEnum = Thread32First(lSnapShot, uThread) 
  Do While CanEnum 
    ReDim Preserve ThreadsEnum(0 To UBound(ThreadsEnum) + 1) As ThreadIt 
    ThreadsEnum(UBound(ThreadsEnum)).ID = uThread.lThreadID 
    ThreadsEnum(UBound(ThreadsEnum)).Process = uThread.lOwnerProcessID 
    CanEnum = Thread32Next(lSnapShot, uThread) 
  Loop 
  CloseHandle (lSnapShot) 
End If 
 
' 
' Good Lord! I thought I'd never get through all of that! well, I did => 
' 
 
mvarEnumsReady = True 
 
End Sub 
 
' 
' Kills a task by it's process Id 
' 
Public Function KillProcess(ByVal ProcessID As Long) As Boolean 
 
Const PROCESS_ALL_ACCESS = &H0 
Dim exitCode As Long 
Dim myProcess As Long 
 
' Get the process 
myProcess = OpenProcess(PROCESS_ALL_ACCESS, False, ProcessID) 
If IsNull(myProcess) = True Or myProcess = 0 Then KillProcess = False: GoTo closit 
 
' Get the Exit Code 
If GetExitCodeProcess(ProcessID, exitCode) = False Then 
  If GetLastError = True Then 
    KillProcess = False 
    GoTo closit 
  End If 
End If 
 
' Kill the process 
KillProcess = TerminateProcess(myProcess, exitCode) 
 
closit: 
 
' ... and close the handle 
Call CloseHandle(myProcess) 
 
End Function 
 
Public Function NumOfWinds() As Long 
NumOfWinds = UBound(WindsEnum) 
End Function 
 
Public Function NumOfProcesses() As Long 
NumOfProcesses = UBound(ProcessEnum) 
End Function 
 
Public Function NumOfThreads() As Long 
NumOfThreads = UBound(ThreadsEnum) 
End Function 
 
Public Function FixApi(ByVal APIString As String) As String 
If InStr(APIString, Chr(0)) <> 0 Then FixApi = Left$(APIString, InStr(APIString, Chr(0)) - 1) Else FixApi = APIString 
End Function 
 
Private Sub TreeFull(ByRef Tree As TreeView, Optional PicList As ImageList, Optional DesktopPic As String, Optional ProcessPic As String, Optional ThreadPic As String, Optional WindPic As String) 
 
' 
' Whack all of the data into the treeview control, with nice formatting and junk. 
' 
 
Dim NodesWork As Node 
Dim i As Long 
 
On Error GoTo errhandler 
 
' First of all, lets get rid of all of the nodes that are there already. 
Tree.Nodes.Clear 
' And do all of the property setting business... 
Tree.ImageList = PicList 
 
' Next, we place the desktop on the topmost node. 
Set NodesWork = Tree.Nodes.Add(, , "_" & Format8(DesktopWind), Format8(DesktopWind) & " " & ClassName(DesktopWind) & " (Desktop Window) " & GetWindText(DesktopWind), DesktopPic) 
NodesWork.Tag = DesktopWind 
 
' Now go through and place in all of the processes 
For i = 1 To UBound(ProcessEnum) 
  Set NodesWork = Tree.Nodes.Add("_" & Format8(DesktopWind), tvwChild, "_" & Format8(ProcessEnum(i)), Format8(ProcessEnum(i)) & " """ & ProcessName(ProcessEnum(i)) & """", ProcessPic) 
  NodesWork.Tag = ProcessEnum(i) 
Next i 
 
' Next goes in the threads... 
For i = 1 To UBound(ThreadsEnum) 
  Set NodesWork = Tree.Nodes.Add("_" & Format8(ThreadsEnum(i).Process), tvwChild, "_" & Format8(ThreadsEnum(i).ID), Format8(ThreadsEnum(i).ID) & IIf(ThreadHung(ThreadsEnum(i).ID), "  This thread is not responding.", ""), ThreadPic) 
  NodesWork.Tag = ThreadsEnum(i).ID 
Next i 
 
' And guess what? The next item to do is the windows =P 
' First of all, though, create a new array with a data type that stores 
' all sorts of info; i.e., text, id, classname, and the would-be key of the parent node. 
' Also check for a window being a child of the desktop. In such a case, 
' put it in under it's thread, and add some text to the string to display. 
 
Dim Winds2() As Winded 
Dim k As Long 
ReDim Winds2(0 To 0) As Winded 
k = 0 
 
For i = 1 To UBound(WindsEnum) 
  If WindsEnum(i) <> DesktopWind Then 
    ReDim Preserve Winds2(0 To UBound(Winds2) + 1) As Winded 
    k = k + 1 
    Winds2(k).hWnd = WindsEnum(k) 
    Winds2(k).ClassName = ClassName(Winds2(k).hWnd) 
    Winds2(k).Parent = ParentWind(Winds2(k).hWnd) 
    Winds2(k).Text = GetWindText(Winds2(k).hWnd) 
    Winds2(k).Thread = WindThread(Winds2(k).hWnd) 
    Winds2(k).Process = WindProcess(Winds2(k).hWnd) 
    Winds2(k).UseMe = True 
    If Winds2(k).Parent = 0 Then 
      Winds2(k).StringParentUse = "_" & Format8(Winds2(k).Thread) 
    ElseIf Winds2(k).Parent = DesktopWind Then 
      Winds2(k).StringParentUse = "_" & Format8(Winds2(k).Thread) 
    Else 
      Winds2(k).StringParentUse = "_" & Format8(Winds2(k).Parent) 
    End If 
    If Winds2(k).Parent = DesktopWind Then 
      With Winds2(k) 
        .DisplayText = Format8(Winds2(k).hWnd) & " " & .ClassName & " (This is a child of the desktop window) """ & .Text & """" 
      End With 
    Else 
      With Winds2(k) 
        .DisplayText = Format8(Winds2(k).hWnd) & " " & .ClassName & " """ & .Text & """" 
      End With 
    End If 
  End If 
Next i 
 
Dim Changed As Boolean 
 
Doadds: 
Do 
  Changed = False 
  For i = 1 To UBound(Winds2) 
    If Winds2(i).UseMe = True And ParentIsIn(Tree.Nodes, Winds2(i).StringParentUse) = True Then 
      Set NodesWork = Tree.Nodes.Add(Winds2(i).StringParentUse, tvwChild, "_" & Format8(Winds2(i).hWnd), Winds2(i).DisplayText, WindPic) 
      NodesWork.Tag = Winds2(i).hWnd 
      Winds2(i).UseMe = False 
      Changed = True 
    End If 
  Next i 
Loop While Changed = True 
 
' Now go through and look for broken windows. 
For i = 1 To UBound(Winds2) 
  If Winds2(i).UseMe = True Then 
    ' For some reason, there is a broken window in the system somewhere. 
    ' Add it in underneath it's thread, and add a little bit to the display string. 
    Set NodesWork = Tree.Nodes.Add("_" & Format8(Winds2(i).Thread), tvwChild, "_" & Format8(Winds2(i).hWnd), Winds2(i).DisplayText & " The parental link to this window is broken.", WindPic) 
    NodesWork.Tag = Winds2(i).hWnd 
    Winds2(i).UseMe = False 
    ' This might clear up some errors, so go back and retry it. 
    GoTo Doadds 
  End If 
Next i 
 
' Finally, make the whole list sorted 
For Each NodesWork In Tree.Nodes 
  NodesWork.Sorted = True 
Next NodesWork 
 
' Put out the desktop selection 
Tree.Nodes("_" & Format8(DesktopWind)).Expanded = True 
Tree.Nodes("_" & Format8(DesktopWind)).Selected = True 
 
Exit Sub 
 
errhandler: 
MsgBox "There has been an error parsing data inside the enumerator class. This may have been due to a window, thread, or complete program terminating, and changing records that were currently being processed. As a result, the list will not be loaded. Please try again.", vbCritical, "Critical Error" 
Tree.Nodes.Clear 
 
End Sub 
 
Public Function ClassName(ByVal hWnd As Long) As String 
ClassName = Space(500) 
GetClassName hWnd, ClassName, Len(ClassName) 
ClassName = FixApi(ClassName) 
End Function 
 
Public Function GetWindText(ByVal hWnd As Long) As String 
GetWindText = Space(GetWindTextLength(hWnd) + 1) 
GetWindowText hWnd, GetWindText, Len(GetWindText) 
GetWindText = FixApi(GetWindText) 
End Function 
 
Public Function GetWindTextLength(ByVal hWnd As Long) As Long 
GetWindTextLength = GetWindowTextLength(hWnd) 
End Function 
 
Private Sub Class_Initialize() 
DestroyEnums 
End Sub 
 
Private Sub Class_Terminate() 
DestroyEnums 
End Sub 
 
Private Function ParentIsIn(ByRef NodeCol As Nodes, ByVal ParentKey As String) 
 
Dim Dummy As String 
On Error Resume Next 
Dummy = NodeCol(ParentKey).Key 
If Err Then ParentIsIn = False Else ParentIsIn = True 
 
End Function 
 
Public Function Progenitor(ByVal hWnd As Long) As Long 
 
Dim NewParent As Long 
 
NewParent = hWnd 
 
Do While NewParent 
  Progenitor = NewParent 
  NewParent = GetParent(Progenitor) 
Loop 
 
' The Progenitor variables now holds the progenitor... well, what did you expect? 
 
End Function 
 
Public Function IsEnabled(ByVal hWnd As Long) As Boolean 
IsEnabled = IsWindowEnabled(hWnd) 
End Function 
 
Public Function IsVisible(ByVal hWnd As Long) As Boolean 
IsVisible = IsWindowVisible(hWnd) 
End Function 
 
Public Function ThreadProcess(ByVal ThreadID As Long) As Long 
' Call around to get hold of all of the threads. 
 
Dim lSnapShot As Long 
Dim CanEnum As Long 
Dim uThread  As THREADENTRY32 
Dim ItemToAdd As String 
ReDim ThreadsEnum(0 To 0) As ThreadIt 
 
lSnapShot = CreateToolhelpSnapshot(TH32CS_SNAPTHREAD, 0&) 
 
If lSnapShot <> 0 Then 
  uThread.lSize = Len(uThread) 
  CanEnum = Thread32First(lSnapShot, uThread) 
  Do While CanEnum 
    If uThread.lThreadID = ThreadID Then ThreadProcess = uThread.lOwnerProcessID: Exit Do 
    CanEnum = Thread32Next(lSnapShot, uThread) 
  Loop 
  CloseHandle (lSnapShot) 
End If 
 
End Function 
 
Public Function ThreadHung(ByVal ThreadID As Long) As Boolean 
ThreadHung = IsHungThread(ThreadID) 
End Function 
 
Public Function MenuHandle(ByVal hWnd As Long) As Long 
MenuHandle = GetMenu(hWnd) 
If IsMenu(MenuHandle) = False Then MenuHandle = 0 
End Function 
 
Public Function SubMenu(ByVal hMenu As Long, ByVal Pos As Long) As Long 
If IsMenu(hMenu) = False Then Exit Function 
SubMenu = GetSubMenu(hMenu, Pos) 
End Function 
 
Public Function IsOnTop(ByVal hWnd As Long) As Boolean 
Dim Styles As Long 
Styles = GetWindowLong(hWnd, GWL_EXSTYLE) 
If IsStyle(Styles, WS_EX_TOPMOST) = True Then IsOnTop = True 
End Function 
 
Public Function IsStyle(ByVal StyleLong As Long, ByVal StyleCheck As Long) As Boolean 
If (StyleLong And StyleCheck) = StyleCheck Then IsStyle = True 
End Function 
 
Public Function StyleVal(ByVal hWnd As Long) As Long 
If IsValidWindow(hWnd) = True Then 
  StyleVal = GetWindowLong(hWnd, GWL_STYLE) 
End If 
End Function 
 
Public Function ExtStyleVal(ByVal hWnd As Long) As Long 
If IsValidWindow(hWnd) = True Then 
  ExtStyleVal = GetWindowLong(hWnd, GWL_EXSTYLE) 
End If 
End Function 
 
Public Function GetHandleInstance(ByVal hWnd As Long) As Long 
If IsValidWindow(hWnd) = True Then 
  GetHandleInstance = GetWindowLong(hWnd, GWL_HINSTANCE) 
End If 
End Function 
 
Public Function GetUserData(ByVal hWnd As Long) As Long 
If IsValidWindow(hWnd) = True Then 
  GetUserData = GetWindowLong(hWnd, GWL_USERDATA) 
End If 
End Function 
 
Public Function GetWndProc(ByVal hWnd As Long) As Long 
If IsValidWindow(hWnd) = True Then 
  GetWndProc = GetWindowLong(hWnd, GWL_WNDPROC) 
End If 
End Function 
 
Public Function GetControlID(ByVal hWnd As Long) As Long 
If IsValidWindow(hWnd) = True Then 
  GetControlID = GetWindowLong(hWnd, GWL_ID) 
End If 
End Function 
 
Public Function SetParent(ByVal hWnd As Long, ByVal NewParent As Long) As Boolean 
SetParent = CBool(SetParentA(hWnd, NewParent)) 
End Function 
 
Public Function SetVisible(ByVal hWnd As Long, ByVal Visible As Boolean) As Boolean 
If Visible = True Then 
  SetVisible = ShowWindow(hWnd, SW_SHOWNA) 
Else 
  SetVisible = ShowWindow(hWnd, SW_HIDE) 
End If 
End Function 
 
Public Function SetOntop(ByVal hWnd As Long, ByVal TopMost As Boolean) As Boolean 
SetOntop = SetWindowPos(hWnd, IIf(TopMost, HWND_TOPMOST, HWND_NOTOPMOST), 0, 0, 0, 0, SWP_NOMOVE Or SWP_NOSIZE) 
End Function 
 
Public Function SetEnabled(ByVal hWnd As Long, ByVal Enabled As Boolean) As Boolean 
SetEnabled = EnableWindow(hWnd, Enabled) 
End Function 
 
Public Sub ForeGround(ByVal hWnd As Long) 
SetForegroundWindow hWnd 
End Sub 
 
Public Sub ActiveWind(ByVal hWnd As Long) 
SetActiveWindow hWnd 
End Sub 
 
Public Sub FocusWind(ByVal hWnd As Long) 
SetFocus hWnd 
End Sub 
 
Public Sub SetWindPos(ByVal hWnd As Long, ByVal Pos As Integer) 
' Sets the Min, Max, or Normal attribute 
Select Case Pos 
  Case Is = 0 
    ' Normal 
    ShowWindow hWnd, SW_SHOWNORMAL 
  Case Is = 2 
    ' Minimised 
    ShowWindow hWnd, SW_SHOWMINIMIZED 
  Case Is = 1 
    ' Maximised 
    ShowWindow hWnd, SW_SHOWMAXIMIZED 
End Select 
End Sub 
 
Public Sub TerminateWind(ByVal hWnd As Long) 
PostMessage hWnd, modConst.WM_CLOSE, &O0, &O0 
End Sub 
 
Public Function WindPos(ByVal hWnd As Long) As EnumPos 
If IsZoomed(hWnd) Then 
  WindPos = Maximized 
ElseIf IsIconic(hWnd) Then 
  WindPos = Minimized 
Else 
  WindPos = Normal 
End If 
End Function 
 
Public Function Flash(ByVal hWnd As Long, ByVal Flasher As Boolean) As Long 
Flash = FlashWindow(hWnd, Flasher) 
End Function 
 
Public Sub SetWinSizePos(ByVal hWnd As Long, ByVal X As Long, ByVal Y As Long, ByVal Width As Long, ByVal Height As Long) 
MoveWindow hWnd, X, Y, Width, Height, True 
End Sub 
 
Public Function GetRelWindow(ByVal hWnd As Long, ByVal RelType As Relations) As Long 
GetRelWindow = GetWindow(hWnd, RelType) 
End Function 
 
Public Sub BringToTop(ByVal hWnd As Long) 
BringWindowToTop hWnd 
End Sub 
 
Public Sub SendToBottom(ByVal hWnd As Long) 
SetWindowPos hWnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE Or SWP_NOSIZE 
End Sub 
 
Public Function GetDC(ByVal hWnd As Long) As Long 
GetDC = GetWindowDC(hWnd) 
End Function 
 
Public Sub RelDC(ByVal hWnd As Long, ByVal hdc As Long) 
ReleaseDC hWnd, hdc 
End Sub 
 
Public Sub SetWindText(ByVal hWnd As Long, ByVal Text As String) 
SetWindowText hWnd, Text 
End Sub 
 
Public Sub ForceRedraw(ByVal hWnd As Long) 
Call InvalidateRect(hWnd, CLng(0), 1) 
Call UpdateWindow(hWnd) 
End Sub 
 
Public Function GetBigIconH(ByVal hWnd As Long) As Long 
GetBigIconH = SendMessage(hWnd, WM_GETICON, 1, 0) ' 1 = ICON_BIG 
End Function 
 
Public Function GetSmallIconH(ByVal hWnd As Long) As Long 
GetSmallIconH = SendMessage(hWnd, WM_GETICON, 0, 0) ' 0 = ICON_SMALL 
End Function 
 
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' 
' From here down, the functions are to do with class information ' 
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' 
Public Function GetClassExtraBytes(ByVal hWnd As Long) As Long 
GetClassExtraBytes = GetClassLong(hWnd, GCL_CBCLSEXTRA) 
End Function 
 
Public Function GetClassExtraWndBytes(ByVal hWnd As Long) As Long 
GetClassExtraWndBytes = GetClassLong(hWnd, GCL_CBWNDEXTRA) 
End Function 
 
Public Function GetClasshBackgroundBrush(ByVal hWnd As Long) As Long 
GetClasshBackgroundBrush = GetClassLong(hWnd, GCL_HBRBACKGROUND) 
End Function 
 
Public Function GetClassHCursor(ByVal hWnd As Long) As Long 
GetClassHCursor = GetClassLong(hWnd, GCL_HCURSOR) 
End Function 
 
Public Function GetClassHIcon(ByVal hWnd As Long) As Long 
GetClassHIcon = GetClassLong(hWnd, GCL_HICON) 
End Function 
 
Public Function GetClasshSmallIcon(ByVal hWnd As Long) As Long 
GetClasshSmallIcon = GetClassLong(hWnd, GCL_WNDPROC) 
End Function 
 
Public Function GetClassHModule(ByVal hWnd As Long) As Long 
GetClassHModule = GetClassLong(hWnd, GCL_HMODULE) 
End Function 
 
Public Function GetClassMenuName(ByVal hWnd As Long) As Long 
GetClassMenuName = GetClassLong(hWnd, GCL_MENUNAME) 
End Function 
 
Public Function GetClassStyle(ByVal hWnd As Long) As Long 
GetClassStyle = GetClassLong(hWnd, GCL_STYLE) 
End Function 
 
Public Function GetClassWndProc(ByVal hWnd As Long) As Long 
GetClassWndProc = GetClassLong(hWnd, GCL_WNDPROC) 
End Function