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