xref: /reactos/sdk/lib/epsapi/enum/processes.c (revision c2c66aff)
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