1*c2c66affSColin Finck /*
2*c2c66affSColin Finck * COPYRIGHT: See COPYING in the top level directory
3*c2c66affSColin Finck * LICENSE: See LGPL.txt in the top level directory
4*c2c66affSColin Finck * PROJECT: ReactOS system libraries
5*c2c66affSColin Finck * FILE: reactos/lib/epsapi/enum/processes.c
6*c2c66affSColin Finck * PURPOSE: Enumerate processes and threads
7*c2c66affSColin Finck * PROGRAMMER: KJK::Hyperion <noog@libero.it>
8*c2c66affSColin Finck * UPDATE HISTORY:
9*c2c66affSColin Finck * 10/06/2002: Created
10*c2c66affSColin Finck * 29/08/2002: Generalized the interface to improve reusability,
11*c2c66affSColin Finck * more efficient use of memory operations
12*c2c66affSColin Finck * 12/02/2003: malloc and free renamed to PsaiMalloc and PsaiFree,
13*c2c66affSColin Finck * for better reusability. PsaEnumerateProcesses now
14*c2c66affSColin Finck * expanded into:
15*c2c66affSColin Finck * - PsaCaptureProcessesAndThreads
16*c2c66affSColin Finck * - PsaFreeCapture
17*c2c66affSColin Finck * - PsaWalkProcessesAndThreads
18*c2c66affSColin Finck * - PsaWalkProcesses
19*c2c66affSColin Finck * - PsaWalkThreads
20*c2c66affSColin Finck * - PsaWalkFirstProcess
21*c2c66affSColin Finck * - PsaWalkNextProcess
22*c2c66affSColin Finck * - PsaWalkFirstThread
23*c2c66affSColin Finck * - PsaWalkNextThread
24*c2c66affSColin Finck * - PsaEnumerateProcessesAndThreads
25*c2c66affSColin Finck * - PsaEnumerateProcesses
26*c2c66affSColin Finck * - PsaEnumerateThreads
27*c2c66affSColin Finck * 12/04/2003: internal PSAPI renamed EPSAPI (Extended PSAPI) and
28*c2c66affSColin Finck * isolated in its own library to clear the confusion
29*c2c66affSColin Finck * and improve reusability
30*c2c66affSColin Finck */
31*c2c66affSColin Finck
32*c2c66affSColin Finck #include "precomp.h"
33*c2c66affSColin Finck
34*c2c66affSColin Finck #define NDEBUG
35*c2c66affSColin Finck #include <debug.h>
36*c2c66affSColin Finck
37*c2c66affSColin Finck NTSTATUS NTAPI
PsaCaptureProcessesAndThreads(OUT PSYSTEM_PROCESS_INFORMATION * ProcessesAndThreads)38*c2c66affSColin Finck PsaCaptureProcessesAndThreads(OUT PSYSTEM_PROCESS_INFORMATION *ProcessesAndThreads)
39*c2c66affSColin Finck {
40*c2c66affSColin Finck PSYSTEM_PROCESS_INFORMATION pInfoBuffer = NULL;
41*c2c66affSColin Finck SIZE_T nSize = 0x8000;
42*c2c66affSColin Finck NTSTATUS Status;
43*c2c66affSColin Finck
44*c2c66affSColin Finck if(ProcessesAndThreads == NULL)
45*c2c66affSColin Finck {
46*c2c66affSColin Finck return STATUS_INVALID_PARAMETER_1;
47*c2c66affSColin Finck }
48*c2c66affSColin Finck
49*c2c66affSColin Finck /* FIXME: if the system has loaded several processes and threads, the buffer
50*c2c66affSColin Finck could get really big. But if there's several processes and threads, the
51*c2c66affSColin Finck system is already under stress, and a huge buffer could only make things
52*c2c66affSColin Finck worse. The function should be profiled to see what's the average minimum
53*c2c66affSColin Finck buffer size, to succeed on the first shot */
54*c2c66affSColin Finck do
55*c2c66affSColin Finck {
56*c2c66affSColin Finck PVOID pTmp;
57*c2c66affSColin Finck
58*c2c66affSColin Finck /* free the buffer, and reallocate it to the new size. RATIONALE: since we
59*c2c66affSColin Finck ignore the buffer's contents at this point, there's no point in a realloc()
60*c2c66affSColin Finck that could end up copying a large chunk of data we'd discard anyway */
61*c2c66affSColin Finck PsaiFree(pInfoBuffer);
62*c2c66affSColin Finck pTmp = PsaiMalloc(nSize);
63*c2c66affSColin Finck
64*c2c66affSColin Finck if(pTmp == NULL)
65*c2c66affSColin Finck {
66*c2c66affSColin Finck DPRINT(FAILED_WITH_STATUS, "PsaiMalloc", STATUS_NO_MEMORY);
67*c2c66affSColin Finck Status = STATUS_NO_MEMORY;
68*c2c66affSColin Finck break;
69*c2c66affSColin Finck }
70*c2c66affSColin Finck
71*c2c66affSColin Finck pInfoBuffer = pTmp;
72*c2c66affSColin Finck
73*c2c66affSColin Finck /* query the information */
74*c2c66affSColin Finck Status = NtQuerySystemInformation(SystemProcessInformation,
75*c2c66affSColin Finck pInfoBuffer,
76*c2c66affSColin Finck nSize,
77*c2c66affSColin Finck NULL);
78*c2c66affSColin Finck
79*c2c66affSColin Finck /* double the buffer size */
80*c2c66affSColin Finck nSize *= 2;
81*c2c66affSColin Finck } while(Status == STATUS_INFO_LENGTH_MISMATCH);
82*c2c66affSColin Finck
83*c2c66affSColin Finck if(!NT_SUCCESS(Status))
84*c2c66affSColin Finck {
85*c2c66affSColin Finck DPRINT(FAILED_WITH_STATUS, "NtQuerySystemInformation", Status);
86*c2c66affSColin Finck return Status;
87*c2c66affSColin Finck }
88*c2c66affSColin Finck
89*c2c66affSColin Finck *ProcessesAndThreads = pInfoBuffer;
90*c2c66affSColin Finck return STATUS_SUCCESS;
91*c2c66affSColin Finck }
92*c2c66affSColin Finck
93*c2c66affSColin Finck NTSTATUS NTAPI
PsaWalkProcessesAndThreads(IN PSYSTEM_PROCESS_INFORMATION ProcessesAndThreads,IN PPROC_ENUM_ROUTINE ProcessCallback,IN OUT PVOID ProcessCallbackContext,IN PTHREAD_ENUM_ROUTINE ThreadCallback,IN OUT PVOID ThreadCallbackContext)94*c2c66affSColin Finck PsaWalkProcessesAndThreads(IN PSYSTEM_PROCESS_INFORMATION ProcessesAndThreads,
95*c2c66affSColin Finck IN PPROC_ENUM_ROUTINE ProcessCallback,
96*c2c66affSColin Finck IN OUT PVOID ProcessCallbackContext,
97*c2c66affSColin Finck IN PTHREAD_ENUM_ROUTINE ThreadCallback,
98*c2c66affSColin Finck IN OUT PVOID ThreadCallbackContext)
99*c2c66affSColin Finck {
100*c2c66affSColin Finck NTSTATUS Status;
101*c2c66affSColin Finck
102*c2c66affSColin Finck if(ProcessCallback == NULL && ThreadCallback == NULL)
103*c2c66affSColin Finck {
104*c2c66affSColin Finck return STATUS_INVALID_PARAMETER;
105*c2c66affSColin Finck }
106*c2c66affSColin Finck
107*c2c66affSColin Finck Status = STATUS_SUCCESS;
108*c2c66affSColin Finck
109*c2c66affSColin Finck ProcessesAndThreads = PsaWalkFirstProcess(ProcessesAndThreads);
110*c2c66affSColin Finck
111*c2c66affSColin Finck /* scan the process list */
112*c2c66affSColin Finck do
113*c2c66affSColin Finck {
114*c2c66affSColin Finck if(ProcessCallback)
115*c2c66affSColin Finck {
116*c2c66affSColin Finck Status = ProcessCallback(ProcessesAndThreads, ProcessCallbackContext);
117*c2c66affSColin Finck
118*c2c66affSColin Finck if(!NT_SUCCESS(Status))
119*c2c66affSColin Finck {
120*c2c66affSColin Finck break;
121*c2c66affSColin Finck }
122*c2c66affSColin Finck }
123*c2c66affSColin Finck
124*c2c66affSColin Finck /* if the caller provided a thread callback */
125*c2c66affSColin Finck if(ThreadCallback)
126*c2c66affSColin Finck {
127*c2c66affSColin Finck ULONG i;
128*c2c66affSColin Finck PSYSTEM_THREAD_INFORMATION pCurThread;
129*c2c66affSColin Finck
130*c2c66affSColin Finck /* scan the current process's thread list */
131*c2c66affSColin Finck for(i = 0, pCurThread = PsaWalkFirstThread(ProcessesAndThreads);
132*c2c66affSColin Finck i < ProcessesAndThreads->NumberOfThreads;
133*c2c66affSColin Finck i++, pCurThread = PsaWalkNextThread(pCurThread))
134*c2c66affSColin Finck {
135*c2c66affSColin Finck Status = ThreadCallback(pCurThread, ThreadCallbackContext);
136*c2c66affSColin Finck
137*c2c66affSColin Finck if(!NT_SUCCESS(Status))
138*c2c66affSColin Finck {
139*c2c66affSColin Finck goto Bail;
140*c2c66affSColin Finck }
141*c2c66affSColin Finck }
142*c2c66affSColin Finck }
143*c2c66affSColin Finck
144*c2c66affSColin Finck /* move to the next process */
145*c2c66affSColin Finck ProcessesAndThreads = PsaWalkNextProcess(ProcessesAndThreads);
146*c2c66affSColin Finck } while(ProcessesAndThreads);
147*c2c66affSColin Finck
148*c2c66affSColin Finck Bail:
149*c2c66affSColin Finck return Status;
150*c2c66affSColin Finck }
151*c2c66affSColin Finck
152*c2c66affSColin Finck NTSTATUS NTAPI
PsaEnumerateProcessesAndThreads(IN PPROC_ENUM_ROUTINE ProcessCallback,IN OUT PVOID ProcessCallbackContext,IN PTHREAD_ENUM_ROUTINE ThreadCallback,IN OUT PVOID ThreadCallbackContext)153*c2c66affSColin Finck PsaEnumerateProcessesAndThreads(IN PPROC_ENUM_ROUTINE ProcessCallback,
154*c2c66affSColin Finck IN OUT PVOID ProcessCallbackContext,
155*c2c66affSColin Finck IN PTHREAD_ENUM_ROUTINE ThreadCallback,
156*c2c66affSColin Finck IN OUT PVOID ThreadCallbackContext)
157*c2c66affSColin Finck {
158*c2c66affSColin Finck PSYSTEM_PROCESS_INFORMATION pInfoBuffer = NULL;
159*c2c66affSColin Finck NTSTATUS Status;
160*c2c66affSColin Finck
161*c2c66affSColin Finck if(ProcessCallback == NULL && ThreadCallback == NULL)
162*c2c66affSColin Finck {
163*c2c66affSColin Finck return STATUS_INVALID_PARAMETER;
164*c2c66affSColin Finck }
165*c2c66affSColin Finck
166*c2c66affSColin Finck /* get the processes and threads list */
167*c2c66affSColin Finck Status = PsaCaptureProcessesAndThreads(&pInfoBuffer);
168*c2c66affSColin Finck
169*c2c66affSColin Finck if(!NT_SUCCESS(Status))
170*c2c66affSColin Finck {
171*c2c66affSColin Finck goto Bail;
172*c2c66affSColin Finck }
173*c2c66affSColin Finck
174*c2c66affSColin Finck /* walk the processes and threads list */
175*c2c66affSColin Finck Status = PsaWalkProcessesAndThreads(pInfoBuffer,
176*c2c66affSColin Finck ProcessCallback,
177*c2c66affSColin Finck ProcessCallbackContext,
178*c2c66affSColin Finck ThreadCallback,
179*c2c66affSColin Finck ThreadCallbackContext);
180*c2c66affSColin Finck
181*c2c66affSColin Finck Bail:
182*c2c66affSColin Finck PsaFreeCapture(pInfoBuffer);
183*c2c66affSColin Finck
184*c2c66affSColin Finck return Status;
185*c2c66affSColin Finck }
186*c2c66affSColin Finck
187*c2c66affSColin Finck VOID NTAPI
PsaFreeCapture(IN PVOID Capture)188*c2c66affSColin Finck PsaFreeCapture(IN PVOID Capture)
189*c2c66affSColin Finck {
190*c2c66affSColin Finck PsaiFree(Capture);
191*c2c66affSColin Finck }
192*c2c66affSColin Finck
193*c2c66affSColin Finck NTSTATUS NTAPI
PsaWalkProcesses(IN PSYSTEM_PROCESS_INFORMATION ProcessesAndThreads,IN PPROC_ENUM_ROUTINE Callback,IN OUT PVOID CallbackContext)194*c2c66affSColin Finck PsaWalkProcesses(IN PSYSTEM_PROCESS_INFORMATION ProcessesAndThreads,
195*c2c66affSColin Finck IN PPROC_ENUM_ROUTINE Callback,
196*c2c66affSColin Finck IN OUT PVOID CallbackContext)
197*c2c66affSColin Finck {
198*c2c66affSColin Finck return PsaWalkProcessesAndThreads(ProcessesAndThreads,
199*c2c66affSColin Finck Callback,
200*c2c66affSColin Finck CallbackContext,
201*c2c66affSColin Finck NULL,
202*c2c66affSColin Finck NULL);
203*c2c66affSColin Finck }
204*c2c66affSColin Finck
205*c2c66affSColin Finck NTSTATUS NTAPI
PsaWalkThreads(IN PSYSTEM_PROCESS_INFORMATION ProcessesAndThreads,IN PTHREAD_ENUM_ROUTINE Callback,IN OUT PVOID CallbackContext)206*c2c66affSColin Finck PsaWalkThreads(IN PSYSTEM_PROCESS_INFORMATION ProcessesAndThreads,
207*c2c66affSColin Finck IN PTHREAD_ENUM_ROUTINE Callback,
208*c2c66affSColin Finck IN OUT PVOID CallbackContext)
209*c2c66affSColin Finck {
210*c2c66affSColin Finck return PsaWalkProcessesAndThreads(ProcessesAndThreads,
211*c2c66affSColin Finck NULL,
212*c2c66affSColin Finck NULL,
213*c2c66affSColin Finck Callback,
214*c2c66affSColin Finck CallbackContext);
215*c2c66affSColin Finck }
216*c2c66affSColin Finck
217*c2c66affSColin Finck NTSTATUS NTAPI
PsaEnumerateProcesses(IN PPROC_ENUM_ROUTINE Callback,IN OUT PVOID CallbackContext)218*c2c66affSColin Finck PsaEnumerateProcesses(IN PPROC_ENUM_ROUTINE Callback,
219*c2c66affSColin Finck IN OUT PVOID CallbackContext)
220*c2c66affSColin Finck {
221*c2c66affSColin Finck return PsaEnumerateProcessesAndThreads(Callback,
222*c2c66affSColin Finck CallbackContext,
223*c2c66affSColin Finck NULL,
224*c2c66affSColin Finck NULL);
225*c2c66affSColin Finck }
226*c2c66affSColin Finck
227*c2c66affSColin Finck NTSTATUS NTAPI
PsaEnumerateThreads(IN PTHREAD_ENUM_ROUTINE Callback,IN OUT PVOID CallbackContext)228*c2c66affSColin Finck PsaEnumerateThreads(IN PTHREAD_ENUM_ROUTINE Callback,
229*c2c66affSColin Finck IN OUT PVOID CallbackContext)
230*c2c66affSColin Finck {
231*c2c66affSColin Finck return PsaEnumerateProcessesAndThreads(NULL,
232*c2c66affSColin Finck NULL,
233*c2c66affSColin Finck Callback,
234*c2c66affSColin Finck CallbackContext);
235*c2c66affSColin Finck }
236*c2c66affSColin Finck
237*c2c66affSColin Finck PSYSTEM_PROCESS_INFORMATION FASTCALL
PsaWalkFirstProcess(IN PSYSTEM_PROCESS_INFORMATION ProcessesAndThreads)238*c2c66affSColin Finck PsaWalkFirstProcess(IN PSYSTEM_PROCESS_INFORMATION ProcessesAndThreads)
239*c2c66affSColin Finck {
240*c2c66affSColin Finck return ProcessesAndThreads;
241*c2c66affSColin Finck }
242*c2c66affSColin Finck
243*c2c66affSColin Finck PSYSTEM_PROCESS_INFORMATION FASTCALL
PsaWalkNextProcess(IN PSYSTEM_PROCESS_INFORMATION CurrentProcess)244*c2c66affSColin Finck PsaWalkNextProcess(IN PSYSTEM_PROCESS_INFORMATION CurrentProcess)
245*c2c66affSColin Finck {
246*c2c66affSColin Finck if(CurrentProcess->NextEntryOffset == 0)
247*c2c66affSColin Finck {
248*c2c66affSColin Finck return NULL;
249*c2c66affSColin Finck }
250*c2c66affSColin Finck else
251*c2c66affSColin Finck {
252*c2c66affSColin Finck return (PSYSTEM_PROCESS_INFORMATION)((ULONG_PTR)CurrentProcess + CurrentProcess->NextEntryOffset);
253*c2c66affSColin Finck }
254*c2c66affSColin Finck }
255*c2c66affSColin Finck
256*c2c66affSColin Finck PSYSTEM_THREAD_INFORMATION FASTCALL
PsaWalkFirstThread(IN PSYSTEM_PROCESS_INFORMATION CurrentProcess)257*c2c66affSColin Finck PsaWalkFirstThread(IN PSYSTEM_PROCESS_INFORMATION CurrentProcess)
258*c2c66affSColin Finck {
259*c2c66affSColin Finck static SIZE_T nOffsetOfThreads = 0;
260*c2c66affSColin Finck
261*c2c66affSColin Finck /* get the offset of the Threads field */
262*c2c66affSColin Finck nOffsetOfThreads = sizeof(SYSTEM_PROCESS_INFORMATION);
263*c2c66affSColin Finck
264*c2c66affSColin Finck return (PSYSTEM_THREAD_INFORMATION)((ULONG_PTR)CurrentProcess + nOffsetOfThreads);
265*c2c66affSColin Finck }
266*c2c66affSColin Finck
267*c2c66affSColin Finck PSYSTEM_THREAD_INFORMATION FASTCALL
PsaWalkNextThread(IN PSYSTEM_THREAD_INFORMATION CurrentThread)268*c2c66affSColin Finck PsaWalkNextThread(IN PSYSTEM_THREAD_INFORMATION CurrentThread)
269*c2c66affSColin Finck {
270*c2c66affSColin Finck return (PSYSTEM_THREAD_INFORMATION)((ULONG_PTR)CurrentThread +
271*c2c66affSColin Finck ((sizeof(SYSTEM_PROCESS_INFORMATION) + sizeof(SYSTEM_THREAD_INFORMATION)) -
272*c2c66affSColin Finck sizeof(SYSTEM_PROCESS_INFORMATION)));
273*c2c66affSColin Finck }
274*c2c66affSColin Finck
275*c2c66affSColin Finck /* EOF */
276