Page 1 of 1

Get a list of active windows & their process names Rate Topic: -----

#1 Jack Eagles1  Icon User is offline

  • Pugnacious Penguin (inspired by no2pencil)
  • member icon

Reputation: 183
  • View blog
  • Posts: 1,152
  • Joined: 10-December 08

Posted 27 December 2010 - 04:31 PM

Okay. For this tutorial, I'm going to show you how to get a list of active window titles, and the processes which they are associated with.

There are going to be two parts to this tutorial. One part is going to be for less advanced users, and the second part is going to be for those who know a little more about VB and Windows.

So, to start with, create a new WinForms Project.
Go to the designer for your main form, and add a listbox, and two buttons.
Name the listbox "lstMain", the first button "btnRefresh", and the second button "btnKill".

Your form should now look somewhat like this:
Posted Image

If you are just beginning in Visual Basic, follow these instructions, otherwise skip down to the next underlined title:

1: Double click "btnRefresh" to switch to the code view. In the Button_Click event, add this code:
        'Clear all the items in the listbox
        lstMain.Items.Clear()
        'For every process which is running on the computer
        For Each p As Process In Process.GetProcesses
            'If the MainWindowTitle of the process is not empty 
            If p.MainWindowTitle = String.Empty = False Then
                'Add the process name, the main window title, and the process ID (what windows uses to identify the process) to the listbox)
                lstMain.Items.Add(p.ProcessName & " # " & p.MainWindowTitle & " # " & p.Id)
            End If
        Next



Now press F5 to debug your project. On your form, press "btnRefresh". The listbox should be populated with the window titles of most of the running applications*.

So, stop debugging, and go back to your designer. Double click "btnKill", and add this code:
        Try
            'Get the selected item on the listbox
            Dim whole As String = lstMain.SelectedItem.ToString
            'Get all the text after the last "#" in the item
            Dim pid = whole.Substring(whole.LastIndexOf(" # "))
            'Replace " # " with nothing, to leave the ID of the process alone
            pid = pid.Replace(" # ", "")
            'Get the process which has the same ID as the one selected in the listbox
            Dim p As Process = Process.GetProcessById(pid)
            Try
                'Try to kill the process (this may not work if you're not an Administrator, if the process has already ended, or if the process has been protected at kernel ring zero (maybe I'll do a tutorial on that later...)
                p.Kill()
            Catch ex As Exception
                'If we can't kill the process, show an error
                MessageBox.Show(ex.Message)
            End Try
        Catch ex As Exception
            'If we can't get the selected item of the listbox (most likely because the user has not selected it), then show an error.
            MessageBox.Show(ex.Message)
        End Try



So, press F5 to debug your code, press "btnRefresh", and then select a process you want to kill, and press "btnKill". Don't select your antivirus's window because if it's any good, the kill command won't work on it.
___END OF BEGINNER TUTORIAL___

*You may notice that this code does not retrieve all open windows. This is because one process can have multiple open windows, and a process does not have to register a MainWindowTitle when starting, so you could have a process open without it having a MainWindowTitle attribute, but the process might have a window open.

If you are more advanced, and you are more experienced using Visual Basic, and know about calling APIs from Windows, then this is the tutorial you should follow:


Firstly, switch to the code view, and import the following:
Imports System.Runtime.InteropServices
Imports System.Text



So, having created our main form (see picture above), double click anywhere on the form, and then add the following declarations (separate from any events):
  <DllImport("USER32.DLL")> _
    Private Shared Function GetShellWindow() As IntPtr
    End Function

    <DllImport("USER32.DLL")> _
    Private Shared Function GetWindowText(ByVal hWnd As IntPtr, ByVal lpString As StringBuilder, ByVal nMaxCount As Integer) As Integer
    End Function

    <DllImport("USER32.DLL")> _
    Private Shared Function GetWindowTextLength(ByVal hWnd As IntPtr) As Integer
    End Function

    <DllImport("user32.dll", SetLastError:=True)> _
    Private Shared Function GetWindowThreadProcessId(ByVal hWnd As IntPtr, <Out()> ByRef lpdwProcessId As UInt32) As UInt32
    End Function

    <DllImport("USER32.DLL")> _
    Private Shared Function IsWindowVisible(ByVal hWnd As IntPtr) As Boolean
    End Function

    Private Delegate Function EnumWindowsProc(ByVal hWnd As IntPtr, ByVal lParam As Integer) As Boolean

    <DllImport("USER32.DLL")> _
    Private Shared Function EnumWindows(ByVal enumFunc As EnumWindowsProc, ByVal lParam As Integer) As Boolean
    End Function

    Private hShellWindow As IntPtr = GetShellWindow()
    Private dictWindows As New Dictionary(Of IntPtr, String)
    Private currentProcessID As Integer


    Public Function GetOpenWindowsFromPID(ByVal processID As Integer) As IDictionary(Of IntPtr, String)
        dictWindows.Clear()
        currentProcessID = processID
        EnumWindows(AddressOf enumWindowsInternal, 0)
        Return dictWindows
    End Function
   
    Private Function enumWindowsInternal(ByVal hWnd As IntPtr, ByVal lParam As Integer) As Boolean
        If (hWnd <> hShellWindow) Then
            Dim windowPid As UInt32
            If Not IsWindowVisible(hWnd) Then
                Return True
            End If
            Dim length As Integer = GetWindowTextLength(hWnd)
            If (length = 0) Then
                Return True
            End If
            GetWindowThreadProcessId(hWnd, windowPid)
            If (windowPid <> currentProcessID) Then
                Return True
            End If
            Dim stringBuilder As New System.Text.StringBuilder(length)
            GetWindowText(hWnd, stringBuilder, (length + 1))
            dictWindows.Add(hWnd, stringBuilder.ToString)
        End If
        Return True
    End Function



Well, there's quite a lot there. The bottom line is that these declarations well help us use some pretty complicated OS calls which will let us get all the open windows, including Dialogs, and MessageBoxes.

Now, double click your "btnRefresh". Add this code to the Click Event:
      'For every process running
      For Each P As Process In Process.GetProcesses
       'Get a list of ALL of the open windows associated with the process   
       Dim windows As IDictionary(Of IntPtr, String) = GetOpenWindowsFromPID(p.Id)
           For Each kvp As KeyValuePair(Of IntPtr, String) In windows
               'This small if statement lets us ignore the start menu...
               If kvp.Value.ToLower = "start" = False Then
                   '''If it's not the start menu, then add the ProcessName, windowtitle, and ID to the list...
                   lstMain.Items.Add(P.ProcessName & " # " & kvp.Value & " # " & P.ID)
               End If
           Next
      Next



Press F5 to begin debugging, and click "btnRefresh". You should see the titles, process names & process IDs of all the open windows, incuding dialogs, OpenFileWindows, and MessageBoxes.
When finished, stop debugging, and add the follwing code to the Click event of the "btnKill":

So, stop debugging, and go back to your designer. Double click "btnKill", and add this code:
        Try
            'Get the selected item on the listbox
            Dim whole As String = lstMain.SelectedItem.ToString
            'Get all the text after the last "#" in the item
            Dim pid = whole.Substring(whole.LastIndexOf(" # "))
            'Replace " # " with nothing, to leave the ID of the process alone
            pid = pid.Replace(" # ", "")
            'Get the process which has the same ID as the one selected in the listbox
            Dim p As Process = Process.GetProcessById(pid)
            Try
                'Try to kill the process (this may not work if you're not an Administrator, if the process has already ended, or if the process has been protected at kernel ring zero (maybe I'll do a tutorial on that later...)
                p.Kill()
            Catch ex As Exception
                'If we can't kill the process, show an error
                MessageBox.Show(ex.Message)
            End Try
        Catch ex As Exception
            'If we can't get the selected item of the listbox (most likely because the user has not selected it), then show an error.
            MessageBox.Show(ex.Message)
        End Try



So the code basically stays the same as in the basic tutorial...


I hope you enjoyed this tutorial, and I hope you were able to make an application from it.

Is This A Good Question/Topic? 4
  • +

Replies To: Get a list of active windows & their process names

#2 pharaon  Icon User is offline

  • D.I.C Head

Reputation: 0
  • View blog
  • Posts: 71
  • Joined: 18-October 07

Posted 19 January 2011 - 11:55 AM

i like your tutorial man
thanks a lot for it
Was This Post Helpful? 0
  • +
  • -

#3 Jack Eagles1  Icon User is offline

  • Pugnacious Penguin (inspired by no2pencil)
  • member icon

Reputation: 183
  • View blog
  • Posts: 1,152
  • Joined: 10-December 08

Posted 22 January 2011 - 06:49 AM

That's fine! Hope it helped you! Feel free to +rep if you liked it!

This post has been edited by Jack Eagles1: 01 February 2011 - 08:53 AM

Was This Post Helpful? 1
  • +
  • -

#4 Guest_John Smith*


Reputation:

Posted 18 February 2011 - 11:22 PM

View PostJack Eagles1, on 22 January 2011 - 06:49 AM, said:

That's fine! Hope it helped you! Feel free to +rep if you liked it!

Was This Post Helpful? 0

#5 Guest_Devil_Doc*


Reputation:

Posted 18 February 2011 - 11:25 PM

Excellent tutorial! I am having one problem. I would like to know the size of the active windows associated with the processes. I have been unsuccessful in converting the GetWindowRect from the user32.dll into VB 2010. How would you write the dllimport properly for this? Thanks!
Was This Post Helpful? 0

Page 1 of 1