Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Win32 APIs for Process Retrieval

0.00/5 (No votes)
11 Feb 2004 1  
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