Processes and Threads

This section covers the Windows API functions for creating, managing, and interacting with processes and their associated threads. Understanding process and thread management is fundamental to building robust and efficient Windows applications.

Core Process Concepts

A process is an instance of a running program. It contains one or more threads, a virtual address space, handles to system resources (like files, devices, and inter-process communication objects), and security information.

A thread is the basic unit of CPU utilization. It comprises a thread ID, a program counter, a register set, and a stack. Threads belonging to the same process share the process's virtual address space and resources.

Key Process Management Functions

Creating Processes

The primary functions for creating a new process are CreateProcess and CreateProcessAsUser.

CreateProcess

Creates a new process and its primary thread. The new process runs in the same address space of the calling process or in a separate address space, depending on the creation flags.

BOOL CreateProcess(
    LPCSTR lpApplicationName,
    LPSTR lpCommandLine,
    LPSECURITY_ATTRIBUTES lpProcessAttributes,
    LPSECURITY_ATTRIBUTES lpThreadAttributes,
    BOOL bInheritHandles,
    DWORD dwCreationFlags,
    LPVOID lpEnvironment,
    LPCSTR lpCurrentDirectory,
    LPSTARTUPINFO lpStartupInfo,
    LPPROCESS_INFORMATION lpProcessInformation
);
  • lpApplicationName: The name of the module to be executed.
  • lpCommandLine: The command line for the application.
  • lpProcessAttributes: Security attributes for the process object.
  • lpThreadAttributes: Security attributes for the primary thread object.
  • bInheritHandles: If this parameter is TRUE, the child process inherits the handles possessed by the parent process.
  • dwCreationFlags: Flags that control the priority class and behavior of the new process.
  • lpEnvironment: Pointer to a block of memory containing a list of environment variables for the new process.
  • lpCurrentDirectory: Pointer to a null-terminated string that specifies the fully qualified path of the current directory for the process.
  • lpStartupInfo: Pointer to a STARTUPINFO structure that specifies how the main window of the application is to be displayed.
  • lpProcessInformation: Pointer to a PROCESS_INFORMATION structure that receives identification information about the new process and its primary thread.

CreateProcess is a versatile function that allows fine-grained control over how a new process is created, including its environment, working directory, and execution priority.

Process Information

When a process is created, the system returns a PROCESS_INFORMATION structure containing handles and identifiers for the new process and its primary thread.

typedef struct _PROCESS_INFORMATION {
    HANDLE hProcess;
    HANDLE hThread;
    DWORD dwProcessId;
    DWORD dwThreadId;
} PROCESS_INFORMATION, *LPPROCESS_INFORMATION;

Terminating Processes

A process can be terminated using the TerminateProcess function.

TerminateProcess

Ends the calling process and any threads that it owns. This function is used to terminate a process.

BOOL TerminateProcess(
    HANDLE hProcess,
    UINT uExitCode
);
  • hProcess: A handle to the process to be terminated.
  • uExitCode: The exit code for the process. Use STILL_ACTIVE (defined as 259) if the exit code is not available.

TerminateProcess is a forceful termination. It does not allow the process to perform cleanup operations. Use with caution.

Process Identifiers and Handles

You can obtain the current process's handle and ID using:

  • GetCurrentProcess(): Returns a pseudo-handle for the current process.
  • GetCurrentProcessId(): Returns the identifier of the current process.

Enumerating Processes

To list running processes, you can use functions like EnumProcesses, EnumProcessModules, and query the system using tools like WMI or PSAPI.

EnumProcesses

Retrieves the process identifiers for all processes currently running on the local computer.

BOOL EnumProcesses(
    DWORD* lpidProcess,
    DWORD cb,
    DWORD* pcbNeeded
);

Thread Management

Threads are managed similarly, with functions like CreateThread, ExitThread, GetCurrentThread, and GetCurrentThreadId.

CreateThread

Creates a new thread within the address space of the calling process.

HANDLE CreateThread(
    LPSECURITY_ATTRIBUTES lpThreadAttributes,
    SIZE_T dwStackSize,
    LPTHREAD_START_ROUTINE lpStartAddress,
    LPVOID lpParameter,
    DWORD dwCreationFlags,
    LPDWORD lpThreadId
);

ExitThread

Ends a calling thread. This function is used to terminate a thread and is called automatically when a thread returns from its starting address.

VOID ExitThread(
    DWORD dwExitCode
);

Example: Creating a Simple Process

The following C++ snippet demonstrates how to create a new process running Notepad.

#include <windows.h>
#include <iostream>

int main() {
    STARTUPINFO si;
    PROCESS_INFORMATION pi;

    ZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);
    ZeroMemory(&pi, sizeof(pi));

    // Start the child process.
    if (!CreateProcess(NULL,   // No module name (use command line)
                       "notepad.exe", // Command line
                       NULL,        // Process handle not inheritable
                       NULL,        // Thread handle not inheritable
                       FALSE,       // Set handle inheritance to FALSE
                       0,           // No creation flags
                       NULL,        // Use parent's environment block
                       NULL,        // Use parent's starting directory
                       &si,         // Pointer to STARTUPINFO structure
                       &pi)         // Pointer to PROCESS_INFORMATION structure
    ) {
        std::cerr << "CreateProcess failed (" << GetLastError() << ")." << std::endl;
        return 1;
    }

    // Wait until child process exits.
    WaitForSingleObject(pi.hProcess, INFINITE);

    // Close process and thread handles.
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);

    std::cout << "Notepad process created and waited for." << std::endl;

    return 0;
}

Inter-Process Communication (IPC)

Processes often need to communicate with each other. The Win32 API provides several mechanisms for IPC, including:

  • Pipes (Anonymous and Named)
  • Memory-Mapped Files
  • Message Queues
  • Sockets
  • Window Messages

Further Reading

Back to Top