Get the List of the Active Tasks

By | 2019-09-26

We’ve already seen how you can kill a task or process, but how about getting a list of running tasks? This should fit the bill nicely.

Module

Option Explicit

' API Constants
Const WS_MINIMIZE = &H20000000 ' Style bit 'is minimized'
Const HWND_TOP = 0 ' Move to top of z-order
Const SWP_NOSIZE = &H1 ' Do not re-size window
Const SWP_NOMOVE = &H2 ' Do not reposition window
Const SWP_SHOWWINDOW = &H40 ' Make window visible/active
Const GW_HWNDFIRST = 0 ' Get first Window handle
Const GW_HWNDNEXT = 2 ' Get next window handle
Const GWL_STYLE = (-16) ' Get Window's style bits
Const SW_RESTORE = 9 ' Restore window

' The following constants will be combined to define properties
' of a 'normal' task top-level window. Any window with ' these set will be
' included in the list:
Const WS_VISIBLE = &H10000000 ' Window is not hidden
Const WS_BORDER = &H800000 ' Window has a border
' Other bits that are normally set include:
Const WS_CLIPSIBLINGS = &H4000000 ' can clip windows
Const WS_THICKFRAME = &H40000 ' Window has thick border
Const WS_GROUP = &H20000 ' Window is top of group
Const WS_TABSTOP = &H10000 ' Window has tabstop

' API Functions Definition
Private Declare Function GetWindow Lib "user32.dll" (ByVal hWnd As Long, ByVal wCmd As Long) As Long
Private Declare Function GetWindowWord Lib "user32.dll" (ByVal hWnd As Long, ByVal nIndex As Long) As Integer
Private Declare Function GetWindowLong Lib "user32.dll" Alias "GetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long) As Long
Private Declare Function GetWindowText Lib "user32.dll" Alias "GetWindowTextA" (ByVal hWnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
Private Declare Function GetWindowTextLength Lib "user32.dll" Alias "GetWindowTextLengthA" (ByVal hWnd As Long) As Long
Private Declare Function SetWindowPos Lib "user32.dll" (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 ShowWindow Lib "user32.dll" (ByVal hWnd As Long, ByVal nCmdShow As Long) As Long

' Public Task Item Structure
Public Type TASK_STRUCT
    TaskName As String
    TaskID As Long
End Type

'Structure filled by FillTaskList Sub call
Public TaskList(1000) As TASK_STRUCT
Public NumTasks As Long

' Returns if a Process is a Visible Window
Public Function IsTask(hwndTask As Long) As Boolean
    Dim WndStyle As Long
    Const IsTaskStyle = WS_VISIBLE Or WS_BORDER

    WndStyle = GetWindowLong(hwndTask, GWL_STYLE)
    If (WndStyle And IsTaskStyle) = IsTaskStyle Then IsTask = True
End Function

' Fills the Task structure with captions and hWnd of all active programs
Public Sub FillTaskList(hWnd As Long)
    Dim hwndTask As Long
    Dim intLen As Long
    Dim strTitle As String
    Dim cnt As Integer

    cnt = 0
    ' process all top-level windows in master window list
    hwndTask = GetWindow(hWnd, GW_HWNDFIRST) ' get first window
    Do While hwndTask ' repeat for all windows
        If hwndTask <> hWnd And IsTask(hwndTask) Then
            intLen = GetWindowTextLength(hwndTask) + 1 ' Get length
            strTitle = Space(intLen) ' Get caption
            intLen = GetWindowText(hwndTask, strTitle, intLen)
            If intLen > 0 Then ' If we have anything, add it
                TaskList(cnt).TaskName = strTitle
                TaskList(cnt).TaskID = hwndTask
                cnt = cnt + 1
            End If
        End If
        hwndTask = GetWindow(hwndTask, GW_HWNDNEXT)
    Loop
    NumTasks = cnt
End Sub

' Give focus to another Task
Public Sub SwitchTo(hWnd As Long)
    Dim ret As Long
    Dim WStyle As Long ' Window Style bits

' Get style bits for window
    WStyle = GetWindowLong(hWnd, GWL_STYLE)
    ' If minimized do a restore
    If WStyle And WS_MINIMIZE Then
        ret = ShowWindow(hWnd, SW_RESTORE)
    End If
    ' Move window to top of z-order/activate; no move/resize
    ret = SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE Or SWP_NOSIZE Or SWP_SHOWWINDOW)
End Sub

Usage

Make a form with 3 Command buttons: cmdExit, cmdRefresh and cmdSwitch. Add a ListBox named lstApp.

Place the following code in Form1 code window:

Option Explicit

Sub cmdExit_Click()
    Unload Me
End Sub

Sub cmdRefresh_Click()
    Dim i As Integer

    ' Clear the ListBox
    lstApp.Clear
    ' Fills the Task List Structure
    FillTaskList Me.hWnd
    ' Add items into the ListBox
    For i = 0 To NumTasks - 1
        lstApp.AddItem TaskList(i).TaskName
        lstApp.ItemData(lstApp.NewIndex) = TaskList(i).TaskID
    Next
End Sub

Sub cmdSwitch_Click()
    Dim hWnd As Long

    If lstApp.ListIndex < 0 Then Beep: Exit Sub
    ' Get window handle from listbox array
    hWnd = lstApp.ItemData(lstApp.ListIndex)
    ' Switch to the selected Task
    SwitchTo hWnd
End Sub

Sub Form_Load()
    cmdRefresh.Value = True
End Sub

Sub lstApp_DblClick()
    cmdSwitch.Value = True
End Sub

Author: dwirch

Derek Wirch is a seasoned IT professional with an impressive career dating back to 1986. He brings a wealth of knowledge and hands-on experience that is invaluable to those embarking on their journey in the tech industry.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.