Wrox Home  
Search P2P Archive for: Go

  Return to Index  

pro_vb thread: Enumerating running applications


Message #1 by "Padgett Rowell" <padgett@i...> on Tue, 11 Sep 2001 00:31:23 +0800
Hello all,

I have posted something similar to this question before.  I have made
some headway (yeah!) but am finding a few anomalies that someone may be
able to shed some light on.

My aim to produce a list of currently running applications, as seen in
the 'Windows task manager'.

The class listed below was donated by Marco.  I have extended it by
adding a few extra window related properties.

Currently I am looping through all the running processes, getting the
window they belong to and "filtering" out the ones that I consider to be
NOT applications.

The "filters" that are producing unexpected results are 'WindowTitle'
and 'Visible'.

When I am running outlook, word, notepad and VB I get the following
debug output:  (I have cut out all 'non application processes')

ProcessName		Visible	WindowTitle

OUTLOOK.EXE   False         
WINWORD.EXE   True          Enumerating running applications - Message -
Microsoft Word
winamp.exe    False         Winamp Playlist Editor
NOTEPAD.EXE   True          netsh.txt - Notepad
VB6.EXE       False         

AS you can see, the visibility for both outlook and VB are false.  I can
certainly see them.

Outlook shows as having no WindowTitle, though it does, as does VB.
I am running two instances of word, one with this email title (as word
is my default editor for outlook).  The second instance of word, with a
new document waiting, is not listed at all.

Notepad is the only application that shows true.

Does anyone have any clues as to why this behaviour is occurring?

Cheers,

Padgett

'Code to test:
Option Explicit

Private Sub Form_Load()

Const PROCESS_TERMINATE = &H1
Const PROCESS_CREATE_THREAD = &H2
Const PROCESS_VM_OPERATION = &H8
Const PROCESS_VM_READ = &H10
Const PROCESS_VM_WRITE = &H20
Const PROCESS_DUP_HANDLE = &H40
Const PROCESS_CREATE_PROCESS = &H80
Const PROCESS_SET_QUOTA = &H100
Const PROCESS_SET_INFORMATION = &H200
Const PROCESS_QUERY_INFORMATION = &H400

     Dim plist As New CProcessInfo
     Dim j As Integer
     Dim num As Long

     num = plist.GetProcessesList
     For j = 0 To num - 1
         plist.ProcessID = plist.ListProcessID(j)
           
        Select Case plist.ProcessID
            Case 0
                Debug.Print plist.ProcessName, plist.ProcessID,
plist.ProcessPath, "System Idle Process"
            Case 2
              Debug.Print plist.ProcessName, plist.ProcessID,
plist.ProcessPath, "System"
            Case Else
                Debug.Print plist.ProcessName, plist.Visible,
plist.WindowTitle
                If plist.Enabled And plist.IsAWindow Then
                    lstProcesses.AddItem plist.ProcessName
                End If
        End Select
     Next j
End Sub

'CProcessInfo
Option Explicit

Private Const PROCESS_QUERY_INFORMATION = 1024
Private Const PROCESS_VM_READ = 16
Private Const MAX_PATH = 260
Private Const STANDARD_RIGHTS_REQUIRED = &HF0000
Private Const SYNCHRONIZE = &H100000
Private Const PROCESS_ALL_ACCESS = &H1F0FFF
Private Const GW_HWNDNEXT = 2

Private Declare Function EnumProcesses Lib "psapi.dll" (ByRef
lpidProcess As Long, ByVal cb As Long, ByRef cbNeeded As Long) As Long
Private Declare Function OpenProcess Lib "Kernel32.dll" (ByVal
dwDesiredAccessas As Long, ByVal bInheritHandle As Long, ByVal dwProcId
As Long) As Long
Private Declare Function CloseHandle Lib "Kernel32.dll" (ByVal Handle As
Long) As Long
Private Declare Function GetModuleBaseName Lib "psapi.dll" (ByVal
hProcess As Long, ByVal hModule As Long, ByVal BaseName As String, ByVal
nSize As Long) As Long
Private Declare Function GetModuleFileNameExA Lib "psapi.dll" (ByVal
hProcess As Long, ByVal hModule As Long, ByVal ModuleName As String,
ByVal nSize As Long) As Long
Private Declare Function EnumProcessModules Lib "psapi.dll" (ByVal
hProcess As Long, ByRef lphModule As Long, ByVal cb As Long, ByRef
cbNeeded As Long) As Long


Private Declare Function FindWindow Lib "user32" Alias "FindWindowA"
(ByVal lpClassName As Long, ByVal lpWindowName As Long) As Long
Private Declare Function GetParent Lib "user32" (ByVal hwnd As Long) As
Long
Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal
hwnd As Long, lpdwProcessId As Long) As Long
Private Declare Function GetWindow Lib "user32" (ByVal hwnd As Long,
ByVal wCmd 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 GetWindowText Lib "user32" Alias
"GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, ByVal
cch As Long) As Long
Private Declare Function agGetStringFromLPSTR$ Lib "apigid32.dll" (ByVal
src$)


Private Declare Function IsWindowVisible Lib "user32" (ByVal hwnd 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 m_lProcess() As Long
Private m_lNumProcesses As Long
Private m_lCurrentPID As Long
Private m_strAppName As String
Private m_strPath As String
Private m_strClassName As String
Private m_strWindowTitle As String
Private m_lhwnd As Long
Private m_bolVisible As Boolean
Private m_bolIsWindow As Boolean
Private m_bolEnabled As Boolean

 Public Property Get GetProcessesList() As Long

     Dim cb As Long
     Dim cbNeeded As Long

     cb = 1024
     Do
        cb = cb * 2
        ReDim m_lProcess(cb / 4 - 1) As Long
        EnumProcesses m_lProcess(0), cb, cbNeeded
        If cbNeeded < cb Then Exit Do
     Loop

     If cbNeeded = 0 Then
         m_lNumProcesses = 0
     Else
         m_lNumProcesses = cbNeeded / 4
         ReDim Preserve m_lProcess(m_lNumProcesses - 1)
     End If

     GetProcessesList = m_lNumProcesses
     GetProcessInfo

 End Property
 Public Property Get NumProcesses() As Long
     NumProcesses = m_lNumProcesses
 End Property
 Public Property Get ListProcessID(ByVal index As Long) As Long
     ListProcessID = m_lProcess(index)
 End Property
 Public Property Let ProcessID(ByVal pid As Long)
     m_lCurrentPID = pid
     GetProcessInfo
 End Property
 Public Property Get ProcessID() As Long
     ProcessID = m_lCurrentPID
 End Property
 Public Property Get ProcessName() As String
     ProcessName = m_strAppName
 End Property
 Public Property Get ProcessPath() As String
     ProcessPath = m_strPath
 End Property
Public Property Get ProcessHwnd() As Long
    ProcessHwnd = m_lhwnd
End Property
Public Property Get ClassName() As String
    ClassName = m_strClassName
End Property
Public Property Get WindowTitle() As String
    WindowTitle = m_strWindowTitle
End Property
Public Property Get Visible() As Boolean
    Visible = m_bolVisible
End Property
Public Property Get IsAWindow() As Boolean
    IsAWindow = m_bolIsWindow
End Property
Public Property Get Enabled() As Boolean
    Enabled = m_bolEnabled
End Property
Private Sub GetProcessInfo()

     On Error GoTo exitsub

     Dim hProcess As Long
     Dim lProp As Long

     m_strPath = ""
     m_strAppName = ""

     lProp = PROCESS_QUERY_INFORMATION Or PROCESS_VM_READ
     hProcess = OpenProcess(lProp, 0, m_lCurrentPID)
     If hProcess = 0 Then GoTo exitsub

     Dim lRet As Long
     Dim cbNeeded As Long
     Dim Modules()  As Long

     'Retrieve the number of bytes that the array of module handles
requires
     ReDim Modules(1023)

     lRet = EnumProcessModules(hProcess, Modules(0), 1024, cbNeeded)
     If lRet = 0 Then GoTo exitsub
     ReDim Modules(cbNeeded / 4 - 1)
     'Get an array of the module handles for the specified process
     lRet = EnumProcessModules(hProcess, Modules(0), cbNeeded, cbNeeded)
     If lRet = 0 Then GoTo exitsub

     Dim nSize As Long

     m_strAppName = Space(MAX_PATH)
     nSize = 500
     lRet = GetModuleFileNameExA(hProcess, Modules(0), m_strAppName,
nSize)
     m_strAppName = Left$(m_strAppName, lRet)

     m_strPath = m_strAppName
     lRet = InStrRev(m_strAppName, "\")
     If lRet > 0 Then
         m_strAppName = Right(m_strPath, Len(m_strPath) - lRet)
         m_strPath = Left(m_strPath, lRet)
     End If
         
     m_lhwnd = ProcessToWnd(m_lCurrentPID)
     m_strWindowTitle = GetTitle(m_lhwnd)
     m_strClassName = GetMyClassName(m_lhwnd)
     m_bolVisible = CBool(IsWindowVisible(m_lhwnd))
     m_bolIsWindow = CBool(IsWindow(m_lhwnd))
     m_bolEnabled = CBool(IsWindowEnabled(m_lhwnd))
     
exitsub:
     CloseHandle hProcess
 End Sub

Private Function ProcessToWnd(ByVal target_pid As Long) As Long
    Dim test_hwnd As Long, test_pid As Long, test_thread_id As Long
    'Find the first window
    test_hwnd = FindWindow(ByVal 0&, ByVal 0&)
    Do While test_hwnd <> 0
        'Check if the window isn't a child
        If GetParent(test_hwnd) = 0 Then
            'Get the window's thread
            test_thread_id = GetWindowThreadProcessId(test_hwnd,
test_pid)
            If test_pid = target_pid Then
                ProcessToWnd = test_hwnd
                Exit Do
            End If
        End If
        'retrieve the next window
        test_hwnd = GetWindow(test_hwnd, GW_HWNDNEXT)
    Loop
End Function
Private Function GetTitle(ByVal hwnd As Long) As String
    Dim tbuf$
    Dim dl&
    tbuf$ = String$(256, 0) ' Initialize space again
    dl& = GetWindowText(hwnd&, tbuf$, 255)
    tbuf$ = agGetStringFromLPSTR$(tbuf$)
    GetTitle$ = tbuf$
End Function


Private Function GetMyClassName(ByVal hwnd As Long) As String
    Dim tbuf$
    Dim dl&
    tbuf$ = String$(256, 0) ' Initialize space again
    dl& = GetClassName(hwnd&, tbuf$, 255)
    tbuf$ = agGetStringFromLPSTR$(tbuf$)
    GetMyClassName = tbuf$ 'desc$
End Function


********************
Padgett Rowell 
Aspect7
Office: +61 (08) 9202 1433
Mobile: 0402 122 419



  Return to Index