Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276/* * COPYRIGHT: See COPYING in the top level directory * LICENSE: See LGPL.txt in the top level directory * PROJECT: ReactOS system libraries * FILE: reactos/lib/epsapi/enum/processes.c * PURPOSE: Enumerate processes and threads * PROGRAMMER: KJK::Hyperion <noog@libero.it> * UPDATE HISTORY: * 10/06/2002: Created * 29/08/2002: Generalized the interface to improve reusability, * more efficient use of memory operations * 12/02/2003: malloc and free renamed to PsaiMalloc and PsaiFree, * for better reusability. PsaEnumerateProcesses now * expanded into: * - PsaCaptureProcessesAndThreads * - PsaFreeCapture * - PsaWalkProcessesAndThreads * - PsaWalkProcesses * - PsaWalkThreads * - PsaWalkFirstProcess * - PsaWalkNextProcess * - PsaWalkFirstThread * - PsaWalkNextThread * - PsaEnumerateProcessesAndThreads * - PsaEnumerateProcesses * - PsaEnumerateThreads * 12/04/2003: internal PSAPI renamed EPSAPI (Extended PSAPI) and * isolated in its own library to clear the confusion * and improve reusability */
#include "precomp.h"
#define NDEBUG#include <debug.h>
NTSTATUS NTAPIPsaCaptureProcessesAndThreads(OUT PSYSTEM_PROCESS_INFORMATION *ProcessesAndThreads){ PSYSTEM_PROCESS_INFORMATION pInfoBuffer = NULL; SIZE_T nSize = 0x8000; NTSTATUS Status;
if(ProcessesAndThreads == NULL) { return STATUS_INVALID_PARAMETER_1; }
/* FIXME: if the system has loaded several processes and threads, the buffer could get really big. But if there's several processes and threads, the system is already under stress, and a huge buffer could only make things worse. The function should be profiled to see what's the average minimum buffer size, to succeed on the first shot */ do { PVOID pTmp;
/* free the buffer, and reallocate it to the new size. RATIONALE: since we ignore the buffer's contents at this point, there's no point in a realloc() that could end up copying a large chunk of data we'd discard anyway */ PsaiFree(pInfoBuffer); pTmp = PsaiMalloc(nSize);
if(pTmp == NULL) { DPRINT(FAILED_WITH_STATUS, "PsaiMalloc", STATUS_NO_MEMORY); Status = STATUS_NO_MEMORY; break; }
pInfoBuffer = pTmp;
/* query the information */ Status = NtQuerySystemInformation(SystemProcessInformation, pInfoBuffer, nSize, NULL);
/* double the buffer size */ nSize *= 2; } while(Status == STATUS_INFO_LENGTH_MISMATCH);
if(!NT_SUCCESS(Status)) { DPRINT(FAILED_WITH_STATUS, "NtQuerySystemInformation", Status); return Status; }
*ProcessesAndThreads = pInfoBuffer; return STATUS_SUCCESS;}
NTSTATUS NTAPIPsaWalkProcessesAndThreads(IN PSYSTEM_PROCESS_INFORMATION ProcessesAndThreads, IN PPROC_ENUM_ROUTINE ProcessCallback, IN OUT PVOID ProcessCallbackContext, IN PTHREAD_ENUM_ROUTINE ThreadCallback, IN OUT PVOID ThreadCallbackContext){ NTSTATUS Status;
if(ProcessCallback == NULL && ThreadCallback == NULL) { return STATUS_INVALID_PARAMETER; }
Status = STATUS_SUCCESS;
ProcessesAndThreads = PsaWalkFirstProcess(ProcessesAndThreads);
/* scan the process list */ do { if(ProcessCallback) { Status = ProcessCallback(ProcessesAndThreads, ProcessCallbackContext);
if(!NT_SUCCESS(Status)) { break; } }
/* if the caller provided a thread callback */ if(ThreadCallback) { ULONG i; PSYSTEM_THREAD_INFORMATION pCurThread;
/* scan the current process's thread list */ for(i = 0, pCurThread = PsaWalkFirstThread(ProcessesAndThreads); i < ProcessesAndThreads->NumberOfThreads; i++, pCurThread = PsaWalkNextThread(pCurThread)) { Status = ThreadCallback(pCurThread, ThreadCallbackContext);
if(!NT_SUCCESS(Status)) { goto Bail; } } }
/* move to the next process */ ProcessesAndThreads = PsaWalkNextProcess(ProcessesAndThreads); } while(ProcessesAndThreads);
Bail: return Status;}
NTSTATUS NTAPIPsaEnumerateProcessesAndThreads(IN PPROC_ENUM_ROUTINE ProcessCallback, IN OUT PVOID ProcessCallbackContext, IN PTHREAD_ENUM_ROUTINE ThreadCallback, IN OUT PVOID ThreadCallbackContext){ PSYSTEM_PROCESS_INFORMATION pInfoBuffer = NULL; NTSTATUS Status;
if(ProcessCallback == NULL && ThreadCallback == NULL) { return STATUS_INVALID_PARAMETER; }
/* get the processes and threads list */ Status = PsaCaptureProcessesAndThreads(&pInfoBuffer);
if(!NT_SUCCESS(Status)) { goto Bail; }
/* walk the processes and threads list */ Status = PsaWalkProcessesAndThreads(pInfoBuffer, ProcessCallback, ProcessCallbackContext, ThreadCallback, ThreadCallbackContext);
Bail: PsaFreeCapture(pInfoBuffer);
return Status;}
VOID NTAPIPsaFreeCapture(IN PVOID Capture){ PsaiFree(Capture);}
NTSTATUS NTAPIPsaWalkProcesses(IN PSYSTEM_PROCESS_INFORMATION ProcessesAndThreads, IN PPROC_ENUM_ROUTINE Callback, IN OUT PVOID CallbackContext){ return PsaWalkProcessesAndThreads(ProcessesAndThreads, Callback, CallbackContext, NULL, NULL);}
NTSTATUS NTAPIPsaWalkThreads(IN PSYSTEM_PROCESS_INFORMATION ProcessesAndThreads, IN PTHREAD_ENUM_ROUTINE Callback, IN OUT PVOID CallbackContext){ return PsaWalkProcessesAndThreads(ProcessesAndThreads, NULL, NULL, Callback, CallbackContext);}
NTSTATUS NTAPIPsaEnumerateProcesses(IN PPROC_ENUM_ROUTINE Callback, IN OUT PVOID CallbackContext){ return PsaEnumerateProcessesAndThreads(Callback, CallbackContext, NULL, NULL);}
NTSTATUS NTAPIPsaEnumerateThreads(IN PTHREAD_ENUM_ROUTINE Callback, IN OUT PVOID CallbackContext){ return PsaEnumerateProcessesAndThreads(NULL, NULL, Callback, CallbackContext);}
PSYSTEM_PROCESS_INFORMATION FASTCALLPsaWalkFirstProcess(IN PSYSTEM_PROCESS_INFORMATION ProcessesAndThreads){ return ProcessesAndThreads;}
PSYSTEM_PROCESS_INFORMATION FASTCALLPsaWalkNextProcess(IN PSYSTEM_PROCESS_INFORMATION CurrentProcess){ if(CurrentProcess->NextEntryOffset == 0) { return NULL; } else { return (PSYSTEM_PROCESS_INFORMATION)((ULONG_PTR)CurrentProcess + CurrentProcess->NextEntryOffset); }}
PSYSTEM_THREAD_INFORMATION FASTCALLPsaWalkFirstThread(IN PSYSTEM_PROCESS_INFORMATION CurrentProcess){ static SIZE_T nOffsetOfThreads = 0;
/* get the offset of the Threads field */ nOffsetOfThreads = sizeof(SYSTEM_PROCESS_INFORMATION);
return (PSYSTEM_THREAD_INFORMATION)((ULONG_PTR)CurrentProcess + nOffsetOfThreads);}
PSYSTEM_THREAD_INFORMATION FASTCALLPsaWalkNextThread(IN PSYSTEM_THREAD_INFORMATION CurrentThread){ return (PSYSTEM_THREAD_INFORMATION)((ULONG_PTR)CurrentThread + ((sizeof(SYSTEM_PROCESS_INFORMATION) + sizeof(SYSTEM_THREAD_INFORMATION)) - sizeof(SYSTEM_PROCESS_INFORMATION)));}
/* EOF */