- Revert 44301
[reactos.git] / lib / epsapi / enum / processes.c
1 /* $Id$
2 */
3 /*
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>
10 * UPDATE HISTORY:
11 * 10/06/2002: Created
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
16 * expanded into:
17 * - PsaCaptureProcessesAndThreads
18 * - PsaFreeCapture
19 * - PsaWalkProcessesAndThreads
20 * - PsaWalkProcesses
21 * - PsaWalkThreads
22 * - PsaWalkFirstProcess
23 * - PsaWalkNextProcess
24 * - PsaWalkFirstThread
25 * - PsaWalkNextThread
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
32 */
33 #define WIN32_NO_STATUS
34 #include <windows.h>
35 #define NTOS_MODE_USER
36 #include <ndk/ntndk.h>
37
38 #include <epsapi/epsapi.h>
39
40 #define NDEBUG
41 #include <debug.h>
42
43 NTSTATUS NTAPI
44 PsaCaptureProcessesAndThreads(OUT PSYSTEM_PROCESS_INFORMATION *ProcessesAndThreads)
45 {
46 PSYSTEM_PROCESS_INFORMATION pInfoBuffer = NULL;
47 SIZE_T nSize = 0x8000;
48 NTSTATUS Status;
49
50 if(ProcessesAndThreads == NULL)
51 {
52 return STATUS_INVALID_PARAMETER_1;
53 }
54
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 */
60 do
61 {
62 PVOID pTmp;
63
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);
69
70 if(pTmp == NULL)
71 {
72 DPRINT(FAILED_WITH_STATUS, "PsaiMalloc", STATUS_NO_MEMORY);
73 Status = STATUS_NO_MEMORY;
74 break;
75 }
76
77 pInfoBuffer = pTmp;
78
79 /* query the information */
80 Status = NtQuerySystemInformation(SystemProcessInformation,
81 pInfoBuffer,
82 nSize,
83 NULL);
84
85 /* double the buffer size */
86 nSize *= 2;
87 } while(Status == STATUS_INFO_LENGTH_MISMATCH);
88
89 if(!NT_SUCCESS(Status))
90 {
91 DPRINT(FAILED_WITH_STATUS, "NtQuerySystemInformation", Status);
92 return Status;
93 }
94
95 *ProcessesAndThreads = pInfoBuffer;
96 return STATUS_SUCCESS;
97 }
98
99 NTSTATUS NTAPI
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)
105 {
106 NTSTATUS Status;
107
108 if(ProcessCallback == NULL && ThreadCallback == NULL)
109 {
110 return STATUS_INVALID_PARAMETER;
111 }
112
113 Status = STATUS_SUCCESS;
114
115 ProcessesAndThreads = PsaWalkFirstProcess(ProcessesAndThreads);
116
117 /* scan the process list */
118 do
119 {
120 if(ProcessCallback)
121 {
122 Status = ProcessCallback(ProcessesAndThreads, ProcessCallbackContext);
123
124 if(!NT_SUCCESS(Status))
125 {
126 break;
127 }
128 }
129
130 /* if the caller provided a thread callback */
131 if(ThreadCallback)
132 {
133 ULONG i;
134 PSYSTEM_THREAD_INFORMATION pCurThread;
135
136 /* scan the current process's thread list */
137 for(i = 0, pCurThread = PsaWalkFirstThread(ProcessesAndThreads);
138 i < ProcessesAndThreads->NumberOfThreads;
139 i++, pCurThread = PsaWalkNextThread(pCurThread))
140 {
141 Status = ThreadCallback(pCurThread, ThreadCallbackContext);
142
143 if(!NT_SUCCESS(Status))
144 {
145 goto Bail;
146 }
147 }
148 }
149
150 /* move to the next process */
151 ProcessesAndThreads = PsaWalkNextProcess(ProcessesAndThreads);
152 } while(ProcessesAndThreads);
153
154 Bail:
155 return Status;
156 }
157
158 NTSTATUS NTAPI
159 PsaEnumerateProcessesAndThreads(IN PPROC_ENUM_ROUTINE ProcessCallback,
160 IN OUT PVOID ProcessCallbackContext,
161 IN PTHREAD_ENUM_ROUTINE ThreadCallback,
162 IN OUT PVOID ThreadCallbackContext)
163 {
164 PSYSTEM_PROCESS_INFORMATION pInfoBuffer = NULL;
165 NTSTATUS Status;
166
167 if(ProcessCallback == NULL && ThreadCallback == NULL)
168 {
169 return STATUS_INVALID_PARAMETER;
170 }
171
172 /* get the processes and threads list */
173 Status = PsaCaptureProcessesAndThreads(&pInfoBuffer);
174
175 if(!NT_SUCCESS(Status))
176 {
177 goto Bail;
178 }
179
180 /* walk the processes and threads list */
181 Status = PsaWalkProcessesAndThreads(pInfoBuffer,
182 ProcessCallback,
183 ProcessCallbackContext,
184 ThreadCallback,
185 ThreadCallbackContext);
186
187 Bail:
188 PsaFreeCapture(pInfoBuffer);
189
190 return Status;
191 }
192
193 VOID NTAPI
194 PsaFreeCapture(IN PVOID Capture)
195 {
196 PsaiFree(Capture);
197 }
198
199 NTSTATUS NTAPI
200 PsaWalkProcesses(IN PSYSTEM_PROCESS_INFORMATION ProcessesAndThreads,
201 IN PPROC_ENUM_ROUTINE Callback,
202 IN OUT PVOID CallbackContext)
203 {
204 return PsaWalkProcessesAndThreads(ProcessesAndThreads,
205 Callback,
206 CallbackContext,
207 NULL,
208 NULL);
209 }
210
211 NTSTATUS NTAPI
212 PsaWalkThreads(IN PSYSTEM_PROCESS_INFORMATION ProcessesAndThreads,
213 IN PTHREAD_ENUM_ROUTINE Callback,
214 IN OUT PVOID CallbackContext)
215 {
216 return PsaWalkProcessesAndThreads(ProcessesAndThreads,
217 NULL,
218 NULL,
219 Callback,
220 CallbackContext);
221 }
222
223 NTSTATUS NTAPI
224 PsaEnumerateProcesses(IN PPROC_ENUM_ROUTINE Callback,
225 IN OUT PVOID CallbackContext)
226 {
227 return PsaEnumerateProcessesAndThreads(Callback,
228 CallbackContext,
229 NULL,
230 NULL);
231 }
232
233 NTSTATUS NTAPI
234 PsaEnumerateThreads(IN PTHREAD_ENUM_ROUTINE Callback,
235 IN OUT PVOID CallbackContext)
236 {
237 return PsaEnumerateProcessesAndThreads(NULL,
238 NULL,
239 Callback,
240 CallbackContext);
241 }
242
243 PSYSTEM_PROCESS_INFORMATION FASTCALL
244 PsaWalkFirstProcess(IN PSYSTEM_PROCESS_INFORMATION ProcessesAndThreads)
245 {
246 return ProcessesAndThreads;
247 }
248
249 PSYSTEM_PROCESS_INFORMATION FASTCALL
250 PsaWalkNextProcess(IN PSYSTEM_PROCESS_INFORMATION CurrentProcess)
251 {
252 if(CurrentProcess->NextEntryOffset == 0)
253 {
254 return NULL;
255 }
256 else
257 {
258 return (PSYSTEM_PROCESS_INFORMATION)((ULONG_PTR)CurrentProcess + CurrentProcess->NextEntryOffset);
259 }
260 }
261
262 PSYSTEM_THREAD_INFORMATION FASTCALL
263 PsaWalkFirstThread(IN PSYSTEM_PROCESS_INFORMATION CurrentProcess)
264 {
265 static SIZE_T nOffsetOfThreads = 0;
266
267 /* get the offset of the Threads field */
268 nOffsetOfThreads = sizeof(SYSTEM_PROCESS_INFORMATION);
269
270 return (PSYSTEM_THREAD_INFORMATION)((ULONG_PTR)CurrentProcess + nOffsetOfThreads);
271 }
272
273 PSYSTEM_THREAD_INFORMATION FASTCALL
274 PsaWalkNextThread(IN PSYSTEM_THREAD_INFORMATION CurrentThread)
275 {
276 return (PSYSTEM_THREAD_INFORMATION)((ULONG_PTR)CurrentThread +
277 ((sizeof(SYSTEM_PROCESS_INFORMATION) + sizeof(SYSTEM_THREAD_INFORMATION)) -
278 sizeof(SYSTEM_PROCESS_INFORMATION)));
279 }
280
281 /* EOF */