2 * COPYRIGHT: See COPYING in the top level directory
3 * LICENSE: See LGPL.txt in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: reactos/lib/epsapi/enum/processes.c
6 * PURPOSE: Enumerate processes and threads
7 * PROGRAMMER: KJK::Hyperion <noog@libero.it>
10 * 29/08/2002: Generalized the interface to improve reusability,
11 * more efficient use of memory operations
12 * 12/02/2003: malloc and free renamed to PsaiMalloc and PsaiFree,
13 * for better reusability. PsaEnumerateProcesses now
15 * - PsaCaptureProcessesAndThreads
17 * - PsaWalkProcessesAndThreads
20 * - PsaWalkFirstProcess
21 * - PsaWalkNextProcess
22 * - PsaWalkFirstThread
24 * - PsaEnumerateProcessesAndThreads
25 * - PsaEnumerateProcesses
26 * - PsaEnumerateThreads
27 * 12/04/2003: internal PSAPI renamed EPSAPI (Extended PSAPI) and
28 * isolated in its own library to clear the confusion
29 * and improve reusability
38 PsaCaptureProcessesAndThreads(OUT PSYSTEM_PROCESS_INFORMATION
*ProcessesAndThreads
)
40 PSYSTEM_PROCESS_INFORMATION pInfoBuffer
= NULL
;
41 SIZE_T nSize
= 0x8000;
44 if(ProcessesAndThreads
== NULL
)
46 return STATUS_INVALID_PARAMETER_1
;
49 /* FIXME: if the system has loaded several processes and threads, the buffer
50 could get really big. But if there's several processes and threads, the
51 system is already under stress, and a huge buffer could only make things
52 worse. The function should be profiled to see what's the average minimum
53 buffer size, to succeed on the first shot */
58 /* free the buffer, and reallocate it to the new size. RATIONALE: since we
59 ignore the buffer's contents at this point, there's no point in a realloc()
60 that could end up copying a large chunk of data we'd discard anyway */
61 PsaiFree(pInfoBuffer
);
62 pTmp
= PsaiMalloc(nSize
);
66 DPRINT(FAILED_WITH_STATUS
, "PsaiMalloc", STATUS_NO_MEMORY
);
67 Status
= STATUS_NO_MEMORY
;
73 /* query the information */
74 Status
= NtQuerySystemInformation(SystemProcessInformation
,
79 /* double the buffer size */
81 } while(Status
== STATUS_INFO_LENGTH_MISMATCH
);
83 if(!NT_SUCCESS(Status
))
85 DPRINT(FAILED_WITH_STATUS
, "NtQuerySystemInformation", Status
);
89 *ProcessesAndThreads
= pInfoBuffer
;
90 return STATUS_SUCCESS
;
94 PsaWalkProcessesAndThreads(IN PSYSTEM_PROCESS_INFORMATION ProcessesAndThreads
,
95 IN PPROC_ENUM_ROUTINE ProcessCallback
,
96 IN OUT PVOID ProcessCallbackContext
,
97 IN PTHREAD_ENUM_ROUTINE ThreadCallback
,
98 IN OUT PVOID ThreadCallbackContext
)
102 if(ProcessCallback
== NULL
&& ThreadCallback
== NULL
)
104 return STATUS_INVALID_PARAMETER
;
107 Status
= STATUS_SUCCESS
;
109 ProcessesAndThreads
= PsaWalkFirstProcess(ProcessesAndThreads
);
111 /* scan the process list */
116 Status
= ProcessCallback(ProcessesAndThreads
, ProcessCallbackContext
);
118 if(!NT_SUCCESS(Status
))
124 /* if the caller provided a thread callback */
128 PSYSTEM_THREAD_INFORMATION pCurThread
;
130 /* scan the current process's thread list */
131 for(i
= 0, pCurThread
= PsaWalkFirstThread(ProcessesAndThreads
);
132 i
< ProcessesAndThreads
->NumberOfThreads
;
133 i
++, pCurThread
= PsaWalkNextThread(pCurThread
))
135 Status
= ThreadCallback(pCurThread
, ThreadCallbackContext
);
137 if(!NT_SUCCESS(Status
))
144 /* move to the next process */
145 ProcessesAndThreads
= PsaWalkNextProcess(ProcessesAndThreads
);
146 } while(ProcessesAndThreads
);
153 PsaEnumerateProcessesAndThreads(IN PPROC_ENUM_ROUTINE ProcessCallback
,
154 IN OUT PVOID ProcessCallbackContext
,
155 IN PTHREAD_ENUM_ROUTINE ThreadCallback
,
156 IN OUT PVOID ThreadCallbackContext
)
158 PSYSTEM_PROCESS_INFORMATION pInfoBuffer
= NULL
;
161 if(ProcessCallback
== NULL
&& ThreadCallback
== NULL
)
163 return STATUS_INVALID_PARAMETER
;
166 /* get the processes and threads list */
167 Status
= PsaCaptureProcessesAndThreads(&pInfoBuffer
);
169 if(!NT_SUCCESS(Status
))
174 /* walk the processes and threads list */
175 Status
= PsaWalkProcessesAndThreads(pInfoBuffer
,
177 ProcessCallbackContext
,
179 ThreadCallbackContext
);
182 PsaFreeCapture(pInfoBuffer
);
188 PsaFreeCapture(IN PVOID Capture
)
194 PsaWalkProcesses(IN PSYSTEM_PROCESS_INFORMATION ProcessesAndThreads
,
195 IN PPROC_ENUM_ROUTINE Callback
,
196 IN OUT PVOID CallbackContext
)
198 return PsaWalkProcessesAndThreads(ProcessesAndThreads
,
206 PsaWalkThreads(IN PSYSTEM_PROCESS_INFORMATION ProcessesAndThreads
,
207 IN PTHREAD_ENUM_ROUTINE Callback
,
208 IN OUT PVOID CallbackContext
)
210 return PsaWalkProcessesAndThreads(ProcessesAndThreads
,
218 PsaEnumerateProcesses(IN PPROC_ENUM_ROUTINE Callback
,
219 IN OUT PVOID CallbackContext
)
221 return PsaEnumerateProcessesAndThreads(Callback
,
228 PsaEnumerateThreads(IN PTHREAD_ENUM_ROUTINE Callback
,
229 IN OUT PVOID CallbackContext
)
231 return PsaEnumerateProcessesAndThreads(NULL
,
237 PSYSTEM_PROCESS_INFORMATION FASTCALL
238 PsaWalkFirstProcess(IN PSYSTEM_PROCESS_INFORMATION ProcessesAndThreads
)
240 return ProcessesAndThreads
;
243 PSYSTEM_PROCESS_INFORMATION FASTCALL
244 PsaWalkNextProcess(IN PSYSTEM_PROCESS_INFORMATION CurrentProcess
)
246 if(CurrentProcess
->NextEntryOffset
== 0)
252 return (PSYSTEM_PROCESS_INFORMATION
)((ULONG_PTR
)CurrentProcess
+ CurrentProcess
->NextEntryOffset
);
256 PSYSTEM_THREAD_INFORMATION FASTCALL
257 PsaWalkFirstThread(IN PSYSTEM_PROCESS_INFORMATION CurrentProcess
)
259 static SIZE_T nOffsetOfThreads
= 0;
261 /* get the offset of the Threads field */
262 nOffsetOfThreads
= sizeof(SYSTEM_PROCESS_INFORMATION
);
264 return (PSYSTEM_THREAD_INFORMATION
)((ULONG_PTR
)CurrentProcess
+ nOffsetOfThreads
);
267 PSYSTEM_THREAD_INFORMATION FASTCALL
268 PsaWalkNextThread(IN PSYSTEM_THREAD_INFORMATION CurrentThread
)
270 return (PSYSTEM_THREAD_INFORMATION
)((ULONG_PTR
)CurrentThread
+
271 ((sizeof(SYSTEM_PROCESS_INFORMATION
) + sizeof(SYSTEM_THREAD_INFORMATION
)) -
272 sizeof(SYSTEM_PROCESS_INFORMATION
)));