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