4 * COPYRIGHT: See COPYING in the top level directory
5 * LICENSE: See LGPL.txt in the top level directory
6 * PROJECT: ReactOS system libraries
7 * FILE: reactos/lib/epsapi/enum/processes.c
8 * PURPOSE: Enumerate processes and threads
9 * PROGRAMMER: KJK::Hyperion <noog@libero.it>
12 * 29/08/2002: Generalized the interface to improve reusability,
13 * more efficient use of memory operations
14 * 12/02/2003: malloc and free renamed to PsaiMalloc and PsaiFree,
15 * for better reusability. PsaEnumerateProcesses now
17 * - PsaCaptureProcessesAndThreads
19 * - PsaWalkProcessesAndThreads
22 * - PsaWalkFirstProcess
23 * - PsaWalkNextProcess
24 * - PsaWalkFirstThread
26 * - PsaEnumerateProcessesAndThreads
27 * - PsaEnumerateProcesses
28 * - PsaEnumerateThreads
29 * 12/04/2003: internal PSAPI renamed EPSAPI (Extended PSAPI) and
30 * isolated in its own library to clear the confusion
31 * and improve reusability
33 #define WIN32_NO_STATUS
35 #define NTOS_MODE_USER
36 #include <ndk/ntndk.h>
38 #include <epsapi/epsapi.h>
44 PsaCaptureProcessesAndThreads(OUT PSYSTEM_PROCESS_INFORMATION
*ProcessesAndThreads
)
46 PSYSTEM_PROCESS_INFORMATION pInfoBuffer
= NULL
;
47 SIZE_T nSize
= 0x8000;
50 if(ProcessesAndThreads
== NULL
)
52 return STATUS_INVALID_PARAMETER_1
;
55 /* FIXME: if the system has loaded several processes and threads, the buffer
56 could get really big. But if there's several processes and threads, the
57 system is already under stress, and a huge buffer could only make things
58 worse. The function should be profiled to see what's the average minimum
59 buffer size, to succeed on the first shot */
64 /* free the buffer, and reallocate it to the new size. RATIONALE: since we
65 ignore the buffer's contents at this point, there's no point in a realloc()
66 that could end up copying a large chunk of data we'd discard anyway */
67 PsaiFree(pInfoBuffer
);
68 pTmp
= PsaiMalloc(nSize
);
72 DPRINT(FAILED_WITH_STATUS
, "PsaiMalloc", STATUS_NO_MEMORY
);
73 Status
= STATUS_NO_MEMORY
;
79 /* query the information */
80 Status
= NtQuerySystemInformation(SystemProcessInformation
,
85 /* double the buffer size */
87 } while(Status
== STATUS_INFO_LENGTH_MISMATCH
);
89 if(!NT_SUCCESS(Status
))
91 DPRINT(FAILED_WITH_STATUS
, "NtQuerySystemInformation", Status
);
95 *ProcessesAndThreads
= pInfoBuffer
;
96 return STATUS_SUCCESS
;
100 PsaWalkProcessesAndThreads(IN PSYSTEM_PROCESS_INFORMATION ProcessesAndThreads
,
101 IN PPROC_ENUM_ROUTINE ProcessCallback
,
102 IN OUT PVOID ProcessCallbackContext
,
103 IN PTHREAD_ENUM_ROUTINE ThreadCallback
,
104 IN OUT PVOID ThreadCallbackContext
)
108 if(ProcessCallback
== NULL
&& ThreadCallback
== NULL
)
110 return STATUS_INVALID_PARAMETER
;
113 Status
= STATUS_SUCCESS
;
115 ProcessesAndThreads
= PsaWalkFirstProcess(ProcessesAndThreads
);
117 /* scan the process list */
122 Status
= ProcessCallback(ProcessesAndThreads
, ProcessCallbackContext
);
124 if(!NT_SUCCESS(Status
))
130 /* if the caller provided a thread callback */
134 PSYSTEM_THREAD_INFORMATION pCurThread
;
136 /* scan the current process's thread list */
137 for(i
= 0, pCurThread
= PsaWalkFirstThread(ProcessesAndThreads
);
138 i
< ProcessesAndThreads
->NumberOfThreads
;
139 i
++, pCurThread
= PsaWalkNextThread(pCurThread
))
141 Status
= ThreadCallback(pCurThread
, ThreadCallbackContext
);
143 if(!NT_SUCCESS(Status
))
150 /* move to the next process */
151 ProcessesAndThreads
= PsaWalkNextProcess(ProcessesAndThreads
);
152 } while(ProcessesAndThreads
);
159 PsaEnumerateProcessesAndThreads(IN PPROC_ENUM_ROUTINE ProcessCallback
,
160 IN OUT PVOID ProcessCallbackContext
,
161 IN PTHREAD_ENUM_ROUTINE ThreadCallback
,
162 IN OUT PVOID ThreadCallbackContext
)
164 PSYSTEM_PROCESS_INFORMATION pInfoBuffer
= NULL
;
167 if(ProcessCallback
== NULL
&& ThreadCallback
== NULL
)
169 return STATUS_INVALID_PARAMETER
;
172 /* get the processes and threads list */
173 Status
= PsaCaptureProcessesAndThreads(&pInfoBuffer
);
175 if(!NT_SUCCESS(Status
))
180 /* walk the processes and threads list */
181 Status
= PsaWalkProcessesAndThreads(pInfoBuffer
,
183 ProcessCallbackContext
,
185 ThreadCallbackContext
);
188 PsaFreeCapture(pInfoBuffer
);
194 PsaFreeCapture(IN PVOID Capture
)
200 PsaWalkProcesses(IN PSYSTEM_PROCESS_INFORMATION ProcessesAndThreads
,
201 IN PPROC_ENUM_ROUTINE Callback
,
202 IN OUT PVOID CallbackContext
)
204 return PsaWalkProcessesAndThreads(ProcessesAndThreads
,
212 PsaWalkThreads(IN PSYSTEM_PROCESS_INFORMATION ProcessesAndThreads
,
213 IN PTHREAD_ENUM_ROUTINE Callback
,
214 IN OUT PVOID CallbackContext
)
216 return PsaWalkProcessesAndThreads(ProcessesAndThreads
,
224 PsaEnumerateProcesses(IN PPROC_ENUM_ROUTINE Callback
,
225 IN OUT PVOID CallbackContext
)
227 return PsaEnumerateProcessesAndThreads(Callback
,
234 PsaEnumerateThreads(IN PTHREAD_ENUM_ROUTINE Callback
,
235 IN OUT PVOID CallbackContext
)
237 return PsaEnumerateProcessesAndThreads(NULL
,
243 PSYSTEM_PROCESS_INFORMATION FASTCALL
244 PsaWalkFirstProcess(IN PSYSTEM_PROCESS_INFORMATION ProcessesAndThreads
)
246 return ProcessesAndThreads
;
249 PSYSTEM_PROCESS_INFORMATION FASTCALL
250 PsaWalkNextProcess(IN PSYSTEM_PROCESS_INFORMATION CurrentProcess
)
252 if(CurrentProcess
->NextEntryOffset
== 0)
258 return (PSYSTEM_PROCESS_INFORMATION
)((ULONG_PTR
)CurrentProcess
+ CurrentProcess
->NextEntryOffset
);
262 PSYSTEM_THREAD_INFORMATION FASTCALL
263 PsaWalkFirstThread(IN PSYSTEM_PROCESS_INFORMATION CurrentProcess
)
265 static SIZE_T nOffsetOfThreads
= 0;
267 /* get the offset of the Threads field */
268 nOffsetOfThreads
= sizeof(SYSTEM_PROCESS_INFORMATION
);
270 return (PSYSTEM_THREAD_INFORMATION
)((ULONG_PTR
)CurrentProcess
+ nOffsetOfThreads
);
273 PSYSTEM_THREAD_INFORMATION FASTCALL
274 PsaWalkNextThread(IN PSYSTEM_THREAD_INFORMATION CurrentThread
)
276 return (PSYSTEM_THREAD_INFORMATION
)((ULONG_PTR
)CurrentThread
+
277 ((sizeof(SYSTEM_PROCESS_INFORMATION
) + sizeof(SYSTEM_THREAD_INFORMATION
)) -
278 sizeof(SYSTEM_PROCESS_INFORMATION
)));