This guide details the steps of the Process Information Tool (ProcessInfoTool.cpp
), a C++ application that displays detailed information about running processes on a Windows system, including Process ID, name, parent process, memory usage, loaded modules, and thread count. Each step includes code snippets, reasoning, Mermaid diagrams to illustrate the process flow, and references to Microsoft documentation.
- Operating System: Windows 11 (x64 or ARM64 with x64 emulation).
- Development Environment: Visual Studio 2022 with C++ Desktop Development workload and Windows SDK.
- Libraries:
Psapi.lib
for process module and memory functions. - Permissions: Run as Administrator for full process access.
Purpose: Include Windows API and standard C++ headers to access process, thread, and module information.
Code Snippet:
#include <windows.h>
#include <tlhelp32.h>
#include <psapi.h>
#include <stdio.h>
Reasoning:
<windows.h>
provides core Windows API functions likeOpenProcess
.<tlhelp32.h>
enables process and thread enumeration viaCreateToolhelp32Snapshot
.<psapi.h>
providesEnumProcessModules
andGetProcessMemoryInfo
for module and memory details.<stdio.h>
supports console output withprintf
.
Diagram:
graph TD
A[Start] --> B[Include windows.h]
B --> C[Include tlhelp32.h]
C --> D[Include psapi.h]
D --> E[Include stdio.h]
E --> F[Access Windows API functions]
Documentation:
Purpose: Open a process by its ID to query its information.
Code Snippet:
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID);
if (hProcess == NULL) {
printf("Unable to open process %d\n", processID);
return;
}
Reasoning:
OpenProcess
requires specific access rights:PROCESS_QUERY_INFORMATION
for memory and module info, andPROCESS_VM_READ
for reading module names.- If the handle is
NULL
, the process might be inaccessible (e.g., system process or insufficient permissions). - Running as Administrator reduces access errors.
Diagram:
graph TD
A[Start] --> B[Call OpenProcess]
B -->|Specify PROCESS_QUERY_INFORMATION| C[Check Handle]
B -->|Specify PROCESS_VM_READ| C
C -->|Handle Valid| D[Proceed to Query Process]
C -->|Handle NULL| E[Print Error and Return]
Documentation:
Purpose: Retrieve the executable name of the process.
Code Snippet:
WCHAR processName[MAX_PATH] = L"<unknown>";
if (GetModuleBaseNameW(hProcess, NULL, processName, MAX_PATH)) {
printf("\nProcess: %ws (PID: %d)\n", processName, processID);
} else {
printf("\nProcess: <unknown> (PID: %d)\n", processID);
}
Reasoning:
GetModuleBaseNameW
retrieves the name of the main executable module for the process.- Uses Unicode (
WCHAR
) for compatibility with modern Windows systems. - Fallback to "unknown" if the call fails (e.g., for protected processes).
Diagram:
graph TD
A[Start] --> B[Initialize processName]
B --> C[Call GetModuleBaseNameW]
C -->|Success| D[Print Process Name and PID]
C -->|Failure| E[Print unknown and PID]
Documentation:
Purpose: Identify the parent process of the given process.
Code Snippet:
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
DWORD parentPID = 0;
if (hSnapshot != INVALID_HANDLE_VALUE) {
PROCESSENTRY32 pe32;
pe32.dwSize = sizeof(PROCESSENTRY32);
if (Process32First(hSnapshot, &pe32)) {
do {
if (pe32.th32ProcessID == processID) {
parentPID = pe32.th32ParentProcessID;
break;
}
} while (Process32Next(hSnapshot, &pe32));
}
CloseHandle(hSnapshot);
}
printf("Parent PID: %d\n", parentPID);
Reasoning:
CreateToolhelp32Snapshot
withTH32CS_SNAPPROCESS
creates a snapshot of all running processes.Process32First
andProcess32Next
iterate through processes to find the matchingprocessID
and retrieveth32ParentProcessID
.- The snapshot handle is closed to prevent resource leaks.
Diagram:
graph TD
A[Start] --> B[Create Snapshot with TH32CS_SNAPPROCESS]
B -->|Valid Handle| C[Initialize PROCESSENTRY32]
B -->|Invalid Handle| D[Set parentPID to 0]
C --> E[Call Process32First]
E --> F[Loop with Process32Next]
F -->|Match processID| G[Set parentPID]
F -->|No Match| H[Continue Loop]
G --> I[Close Snapshot]
H -->|End of Processes| I
I --> J[Print parentPID]
Documentation:
- CreateToolhelp32Snapshot (Microsoft Learn)
- Process32First (Microsoft Learn)
- Process32Next (Microsoft Learn)
Purpose: Retrieve memory usage statistics for the process.
Code Snippet:
PROCESS_MEMORY_COUNTERS pmc;
if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc))) {
printf("Working Set Size: %zu KB\n", pmc.WorkingSetSize / 1024);
printf("Peak Working Set Size: %zu KB\n", pmc.PeakWorkingSetSize / 1024);
printf("Pagefile Usage: %zu KB\n", pmc.PagefileUsage / 1024);
}
Reasoning:
GetProcessMemoryInfo
populates aPROCESS_MEMORY_COUNTERS
structure with memory usage data.- Key metrics include
WorkingSetSize
(current memory in RAM),PeakWorkingSetSize
(maximum RAM usage), andPagefileUsage
(virtual memory usage). - Values are converted to KB for readability.
Diagram:
graph TD
A[Start] --> B[Initialize PROCESS_MEMORY_COUNTERS]
B --> C[Call GetProcessMemoryInfo]
C -->|Success| D[Print Working Set Size]
D --> E[Print Peak Working Set Size]
E --> F[Print Pagefile Usage]
C -->|Failure| G[Skip Memory Info]
Documentation:
Purpose: Count the number of threads owned by the process.
Code Snippet:
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
int threadCount = 0;
if (hSnapshot != INVALID_HANDLE_VALUE) {
THREADENTRY32 te32;
te32.dwSize = sizeof(THREADENTRY32);
if (Thread32First(hSnapshot, &te32)) {
do {
if (te32.th32OwnerProcessID == processID) {
threadCount++;
}
} while (Thread32Next(hSnapshot, &te32));
}
CloseHandle(hSnapshot);
}
printf("Thread Count: %d\n", threadCount);
Reasoning:
CreateToolhelp32Snapshot
withTH32CS_SNAPTHREAD
captures all threads in the system.Thread32First
andThread32Next
iterate through threads, incrementingthreadCount
whenth32OwnerProcessID
matches the target process.- The snapshot handle is closed to free resources.
Diagram:
graph TD
A[Start] --> B[Create Snapshot with TH32CS_SNAPTHREAD]
B -->|Valid Handle| C[Initialize THREADENTRY32]
B -->|Invalid Handle| D[Set threadCount to 0]
C --> E[Call Thread32First]
E --> F[Loop with Thread32Next]
F -->|Match th32OwnerProcessID| G[Increment threadCount]
F -->|No Match| H[Continue Loop]
G --> H
H -->|End of Threads| I[Close Snapshot]
I --> J[Print threadCount]
Documentation:
Purpose: List all modules (DLLs and executable) loaded by the process.
Code Snippet:
HMODULE hMods[1024];
DWORD cbNeeded;
printf("Loaded Modules:\n");
if (EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded)) {
for (unsigned int i = 0; i < (cbNeeded / sizeof(HMODULE)); i++) {
WCHAR modName[MAX_PATH];
if (GetModuleFileNameExW(hProcess, hMods[i], modName, MAX_PATH)) {
printf(" %ws\n", modName);
}
}
}
Reasoning:
EnumProcessModules
retrieves handles to all modules loaded by the process.GetModuleFileNameExW
gets the full path of each module.- The loop iterates through module handles, printing each module's path.
cbNeeded
indicates the number of modules retrieved.
Diagram:
graph TD
A[Start] --> B[Initialize Module Array]
B --> C[Call EnumProcessModules]
C -->|Success| D[Loop through Modules]
C -->|Failure| E[Skip Module Listing]
D --> F[Call GetModuleFileNameExW]
F -->|Success| G[Print Module Path]
F -->|Failure| H[Skip Module]
G --> I[Next Module]
H --> I
I -->|More Modules| F
I -->|No More Modules| J[End]
Documentation:
Purpose: Enumerate all running processes and apply the above steps to each.
Code Snippet:
int main() {
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnapshot == INVALID_HANDLE_VALUE) {
printf("Failed to create process snapshot\n");
return 1;
}
PROCESSENTRY32 pe32;
pe32.dwSize = sizeof(PROCESSENTRY32);
if (Process32First(hSnapshot, &pe32)) {
do {
PrintProcessInfo(pe32.th32ProcessID);
} while (Process32Next(hSnapshot, &pe32));
}
CloseHandle(hSnapshot);
return 0;
}
Reasoning:
CreateToolhelp32Snapshot
withTH32CS_SNAPPROCESS
captures all processes.Process32First
andProcess32Next
iterate through each process, passing its ID toPrintProcessInfo
.- Returns exit code 0 on success, 1 on snapshot failure.
- The snapshot handle is closed to prevent leaks.
Diagram:
graph TD
A[Start] --> B[Create Snapshot with TH32CS_SNAPPROCESS]
B -->|Valid Handle| C[Initialize PROCESSENTRY32]
B -->|Invalid Handle| D[Print Error and Exit]
C --> E[Call Process32First]
E -->|Success| F[Call PrintProcessInfo]
F --> G[Call Process32Next]
G -->|More Processes| F
G -->|No More Processes| H[Close Snapshot]
H --> I[Return 0]
Documentation:
- CreateToolhelp32Snapshot (Microsoft Learn)
- Process32First (Microsoft Learn)
- Process32Next (Microsoft Learn)
Purpose: Compile and execute the tool on a Windows 11 x64 system.
Steps:
- Install Visual Studio 2022 with the C++ Desktop Development workload and Windows SDK.
- Create a new Win32 Console Application project in Visual Studio.
- Add the
ProcessInfoTool.cpp
code to the main source file. - Configure the project:
- In Project Properties > General, set Platform Target to x64.
- In Project Properties > Linker > Input, add
Psapi.lib
to Additional Dependencies.
- Build the solution by selecting Build > Build Solution or pressing
Ctrl+Shift+B
(Release) orF5
(Debug). - Run the generated
.exe
as Administrator to ensure access to all process information.
Reasoning:
- Visual Studio 2022 is the recommended IDE for building C++ applications on Windows 11 x64, providing native x64 compilation.
Psapi.lib
is required for linkingEnumProcessModules
andGetProcessMemoryInfo
functions.- Running as Administrator minimizes access-denied errors for system processes.
- The x64 target ensures compatibility with the Windows 11 x64 environment, avoiding emulation overhead.
Diagram:
graph TD
A[Start] --> B[Install Visual Studio 2022]
B --> C[Create Win32 Console Project]
C --> D[Add ProcessInfoTool.cpp]
D --> E[Set Platform to x64]
E --> F[Add Psapi.lib to Linker]
F --> G[Build Solution]
G --> H[Run as Administrator]
H --> I[Display Process Info]
Documentation:
- Error Handling: The tool checks for invalid handles and failed API calls, printing errors where appropriate.
- Permissions: Some system processes (e.g., PID 0 or 4) may be inaccessible without elevated privileges.
- Performance: The tool processes all running processes, which may be resource-intensive on systems with many processes.
- Compatibility: The code uses standard Windows APIs, fully compatible with Windows 11 x64.