Click here to Skip to main content
Click here to Skip to main content

Win32 APIs for Process Retrieval

, 11 Feb 2004
Rate this:
Please Sign up or sign in to vote.
Discover what other tasks are running on the system.

Sample Image - Tasks.jpg

Introduction

This program will show you several ways to find out what other programs, tasks, and DLLs are running in Windows at any given time. You will see how you can determine the main-level windows that are on the screen, as well as the actual tasks running (which may or may not have a window on the screen) and the DLLs that are loaded by programs.

Using this methodology doesn't mean you can replace Windows Task Manager, but it can show you how to get to other running processes when you need to do so in your applications.

Technique

A task is a running Windows application, whether it is displaying a window on the screen or not. A task may have several windows associated with it. The main window is the "parent" window on the desktop, and all other windows are "children" of the parent. Child windows normally are displayed within the borders of the main window but can appear outside of it. In either case, all child windows belong to a task as well.

Steps

I will give you the steps of creating the code. As we go along the code, I will explain much of the functionality as comments in the source code so you can catch up with the specific elements of the code. Then I will summarize how it all works.

1.

Create a simple Dialog based application using MFC AppWizard (exe).

2.

In the Dialog Resource Editor, add a list box and three buttons and label them as shown in the screen shot. Delete the Cancel button and change the caption of the OK button to read "Close".

3.

Add the following code to the OnInitDialog() member function of the dialog just before the function returns:

// Make the dialog window centered
CenterWindow();

// Init toolhelp 32 functions
if(!InitToolhelp32())
   {
     MessageBox("Unable to initialize tool help functions", "Error",MB_OK);
     EndDialog(IDCANCEL);
     return FALSE;
   }

The function InitToolhelp32() is an initializer function that we will create to get to the Windows kernel and use it to call a number of other functions that we will use to deal with processes, modules, and threads.

4.

Add the following code to the BN_CLICKED message handler of the Process button:

// Get a snapshot of the thread li
HANDLE hSnapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 pe;

if(!hSnapshot)
    return;

CListBox* pList = (CListBox*)GetDlgItem(IDC_LIST1);

// Clear out the list box
pList->ResetContent();

// Initialize size in structure
pe.dwSize = sizeof(pe);

for(int i = pProcess32First(hSnapshot, &pe); i; i=
    pProcess32Next(hSnapshot, &pe))
{
    HANDLE hModuleSnap = NULL;
    MODULEENTRY32 me;

    // Take a snapshot of all modules in the specified process
    hModuleSnap = pCreateToolhelp32Snapshot(TH32CS_SNAPMODULE,
        pe.th32ProcessID);

    if(hModuleSnap == (HANDLE) -1)
        return;

    // Fill the size of the structure before using it
    me.dwSize = sizeof(MODULEENTRY32);

    // Walk the module list of the process, and find the module of
    // interest. Then copy the information to the buffer pointed
    // to by lpMe32 so that it can be returned to the caller
    if(pModule32First(hModuleSnap, &me))
    {
        do
        {
            if(me.th32ModuleID == pe.th32ModuleID)
            {
                pList->AddString(me.szExePath);
                break;
            }
        }
        while(pModule32Next(hModuleSnap, &me));
    }
        
}
    
CloseHandle(hSnapshot); // Done with this snapshot. Free it

5.

Add the following code to the BN_CLICKED message handler of the Windows button:

// Get the list box from the dialog

CListBox* pList = (CListBox*)GetDlgItem(IDC_LIST1);

// Clear out the list box
pList->ResetContent();

// Make a callback procedure for Windows to use to iterate
// through the Window list
FARPROC EnumProcInstance = MakeProcInstance((FARPROC)EnumWindowsProc,
    AfxGetInstanceHandle());

// Call the EnumWindows function to start the iteration
EnumWindows((WNDENUMPROC)EnumProcInstance, (LPARAM)pList);

// Free up the allocated memory handle
FreeProcInstance(EnumProcInstance);

// Update the dialog
UpdateData();

6.

Add the following code just above the handler for the Windows button:

BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lParam)
{
    // Get the list box
    CListBox* pList = (CListBox*)lParam;

    // Get the window text to insert
    char buffer[256];
    GetWindowText(hWnd, buffer, 256);

    // Insert it into the list box
    if(strlen(buffer))
        pList->AddString(buffer);

    return TRUE;
}

7.

Add the following code to the BN_CLICKED message handler of the Modules button:

MODULEENTRY32 me;

// Get the list box
CListBox* pList = (CListBox*)GetDlgItem(IDC_LIST1);
pList->ResetContent();

// Initialize the MODULEENTRY structure to 0 and set the
// size of the structure in the dwSize element
memset(&me, 0, sizeof(me));
me.dwSize = sizeof(MODULEENTRY32);

HANDLE hSnapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

if(!hSnapshot)
    return;

for(int i = pModule32First(hSnapshot, &me); i; i=
    pModule32Next(hSnapshot, &me))
{
    pList->AddString(me.szExePath);
}

CloseHandle(hSnapshot);

8.

Add the following declarations and code to the top of the dialog's .cpp file:

//////////////////////////////////////////////////////////////////////
// Type definitions for pointers to call tool help functions
typedef BOOL (WINAPI* MODULEWALK)(HANDLE hSnapshot, LPMODULEENTRY32 lpme);

typedef BOOL (WINAPI* THREADWALK)(HANDLE hSnapshot, LPTHREADENTRY32 lpte);

typedef BOOL (WINAPI* PROCESSWALK)(HANDLE hSnapshot, LPPROCESSENTRY32 lppe);

typedef HANDLE (WINAPI* CREATESNAPSHOT)(DWORD dwFlags, DWORD th32ProcessID);

// File scope globals. These pointers are declared because of the need
// to dynamically link to the functions. They are exported only by
// the Windows kernel. Explicitly linking to them will make this
// application unloadable in Windows NT and will produce an ugly
// system dialog box

static CREATESNAPSHOT pCreateToolhelp32Snapshot = NULL;
static MODULEWALK pModule32First = NULL;
static MODULEWALK pModule32Next = NULL;
static PROCESSWALK pProcess32First = NULL;
static PROCESSWALK pProcess32Next = NULL;
static THREADWALK pThread32First = NULL;
static THREADWALK pThread32Next = NULL;

// Function that initializes tool help functions
BOOL InitToolhelp32(void)
{
    BOOL bRet = FALSE;
    HINSTANCE hKernel = NULL;

    // Obtain the module handle of the kernel to retrieve addresses
    // of the tool helper functions
    hKernel = GetModuleHandle("KERNEL32.DLL");

    if(hKernel)
    {
    pCreateToolhelp32Snapshot = 
    (CREATESNAPSHOT)GetProcAddress(hKernel,    "CreateToolhelp32Snapshot");

    pModule32First = (MODULEWALK)GetProcAddress(hKernel,"Module32First");

    pModule32Next = (MODULEWALK)GetProcAddress(hKernel,"Module32Next");

    pProcess32First=(PROCESSWALK)GetProcAddress(hKernel,"Process32First");

    pProcess32Next = (PROCESSWALK)GetProcAddress(hKernel,"Process32Next");

    pThread32First = (THREADWALK)GetProcAddress(hKernel,"Thread32First");

    pThread32Next = (THREADWALK)GetProcAddress(hKernel,"Thread32Next");

    // All addresses must be non-NULL to be successful.
    // If one of these addresses is NULL, one of the needed
    // list cannot be walked.
    bRet = pModule32First && pModule32Next && pProcess32First &&
           pProcess32Next && pThread32First && pThread32Next &&
           pCreateToolhelp32Snapshot;
    }
    else
        bRet = FALSE; // could not even get the handle of kernel

    return bRet;
}

9.

Finally, add the following include file line to the dialog's .cpp file:

#include <tlhelp32.h>

Then compile and run the application.

How it works

Here, we are using three different Windows API function sets.

The first method, listing processes, makes use of the Windows API functions Process32First() and Process32Next(). To use these functions, the programmer must first initialize the Toolhelp functionality by loading the functions from the Kernel32.dll. This is accomplished using the InitToolhelp32() function defined in step 8. These functions will "walk" the process list, returning process identifiers for each running process. From these identifiers, the Module functions (Module32First()and Module32Next()) are used to walk through the modules to find the corresponding names of the processes.

The second method, listing windows, uses a more advanced and slightly less intuitive set of Windows API functions, the MakeProcInstance() and EnumWindows() functions. MakeProcInstance() takes the address of a function in your program and converts it into something called FARPROC. This FARPROC is then passed to Windows to iterate through all of the open windows on the desktop. Note that only main-level windows are listed by the function. The function that is called is EnumWindowsProc() and accepts two arguments. The first will be the handle of the window that is currently being examined, and the second is a user-defined argument that is passed to the EnumWindows() function. In our case, the argument passed is the CListBox member that we would like data stored in. In the EnumWindowsProc() function (also known as a callback function, since it is called by Windows), the title of the window is stored in the list box for the user to view.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

Ahmed Alhosaini
Architect
United States United States
Ahmed had his M.S. Degree in Electrical and Computer Engineering in USA and the B.Sc. Degree in Automatic Control and Computer Systems Engineering in Egypt. He programmed with Assembly, Fortran77, Prolog, C/C++, Microsoft Visual Basic, Microsoft Visual C++, ATL/COM, Microsoft Visual C#, VB.NET, ASP.NET, AJAX, SharePoint 2007/2010, Microsoft Commerce Server, and MATLAB and Maple for technical computing. His programming experience is about 15+ years and he is a Microsoft Certified Professional. He also has a working experience in Database technologies and administration of SQL Server databases on Windows NT/2000/2003/2008 Windows Server platforms. Ahmed is interested in developing enterprise business solutions and has participated in many business, services and consultancy projects.

Comments and Discussions

 
GeneralGood article. PinmemberWREY14-Feb-04 0:02 
GeneralRe: Good article. PinmemberAhmad Yassin14-Feb-04 0:29 
GeneralRe: Good article. PinmemberWREY15-Feb-04 1:32 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140827.1 | Last Updated 12 Feb 2004
Article Copyright 2004 by Ahmed Alhosaini
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid