update for HEAD-2003091401
[reactos.git] / lib / epsapi / enum / drivers.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/drivers.c
8  * PURPOSE:     Enumerate system modules
9  * PROGRAMMER:  KJK::Hyperion <noog@libero.it>
10  * UPDATE HISTORY:
11  *              02/04/2003: Created
12  *              12/04/2003: internal PSAPI renamed EPSAPI (Extended PSAPI) and
13  *                          isolated in its own library to clear the confusion
14  *                          and improve reusability
15  */
16
17 #include <stddef.h>
18 #define NTOS_MODE_USER
19 #include <ntos.h>
20
21 #define NDEBUG
22 #include <debug.h>
23
24 #include <epsapi.h>
25
26 NTSTATUS
27 NTAPI
28 PsaEnumerateSystemModules
29 (
30  IN PSYSMOD_ENUM_ROUTINE Callback,
31  IN OUT PVOID CallbackContext
32 )
33 {
34  register NTSTATUS nErrCode = STATUS_SUCCESS;
35  PSYSTEM_MODULE_INFORMATION psmModules = NULL;
36
37 #if 0
38  __try
39  {
40 #endif
41   do
42   {
43    /* capture the system modules */
44    nErrCode = PsaCaptureSystemModules(&psmModules);
45    
46    if(!NT_SUCCESS(nErrCode))
47     /* failure */
48     break;
49  
50    /* walk the system modules */
51    nErrCode = PsaWalkSystemModules(psmModules, Callback, CallbackContext);
52   }
53   while(0);
54 #if 0
55  }
56  __finally
57  {
58 #endif
59   /* free the capture */
60   PsaFreeCapture(psmModules);
61 #if 0
62  }
63 #endif
64  
65  /* return the last status */
66  return nErrCode;
67 }
68
69 NTSTATUS
70 NTAPI
71 PsaCaptureSystemModules
72 (
73  OUT PSYSTEM_MODULE_INFORMATION * SystemModules
74 )
75 {
76  SIZE_T nSize = 0;
77  register NTSTATUS nErrCode;
78  register PSYSTEM_MODULE_INFORMATION psmModules = (PSYSTEM_MODULE_INFORMATION)&nSize;
79
80 #if 0
81  __try
82  {
83 #endif
84   do
85   {
86    /* initial probe. We just get the count of system modules */
87    nErrCode = NtQuerySystemInformation
88    (
89     SystemModuleInformation,
90     psmModules,
91     sizeof(nSize),
92     NULL
93    );
94
95    if(nErrCode != STATUS_INFO_LENGTH_MISMATCH && !NT_SUCCESS(nErrCode))
96    {
97     /* failure */
98     DPRINT(FAILED_WITH_STATUS, "NtQuerySystemInformation", nErrCode);
99     break;
100    }
101
102    /* RATIONALE: the loading of a system module is a rare occurrence. To
103       minimize memory operations that could be expensive, or fragment the
104       pool/heap, we try to determine the buffer size in advance, knowing that
105       the number of elements is unlikely to change */
106    nSize =
107     sizeof(*psmModules) +
108     (psmModules->Count - 1) * sizeof(SYSTEM_MODULE_INFORMATION);
109
110    psmModules = NULL;
111
112    do
113    {
114     register void * pTmp;
115   
116     /* free the buffer, and reallocate it to the new size. RATIONALE: since we
117        ignore the buffer's content at this point, there's no point in a realloc,
118        that could end up copying a large chunk of data we'd discard anyway */
119     PsaiFree(psmModules);
120     pTmp = PsaiMalloc(nSize);
121     
122     if(pTmp == NULL)
123     {
124      /* failure */
125      nErrCode = STATUS_NO_MEMORY;
126      DPRINT(FAILED_WITH_STATUS, "PsaiMalloc", nErrCode);
127      break;
128     }
129
130     psmModules = pTmp;
131
132     /* query the information */
133     nErrCode = NtQuerySystemInformation
134     (
135      SystemModuleInformation,
136      psmModules,
137      nSize,
138      NULL
139     );
140
141     /* double the buffer for the next loop */
142     nSize += nSize;
143    }
144    /* repeat until the buffer is big enough */
145    while(nErrCode == STATUS_INFO_LENGTH_MISMATCH);
146
147    if(!NT_SUCCESS(nErrCode))
148    {
149     /* failure */
150     DPRINT(FAILED_WITH_STATUS, "NtQuerySystemInformation", nErrCode);
151     break;
152    }
153
154    /* success */
155    *SystemModules = psmModules;
156
157    nErrCode = STATUS_SUCCESS;
158   }
159   while(0);
160 #if 0
161  }
162  __finally
163  {
164 #endif
165   /* in case of failure, free the buffer */
166   if(!NT_SUCCESS(nErrCode))
167    PsaiFree(psmModules);
168 #if 0
169  }
170 #endif
171
172  /* return the last status */
173  return (nErrCode);
174 }
175
176 NTSTATUS
177 NTAPI
178 PsaWalkSystemModules
179 (
180  IN PSYSTEM_MODULE_INFORMATION SystemModules,
181  IN PSYSMOD_ENUM_ROUTINE Callback,
182  IN OUT PVOID CallbackContext
183 )
184 {
185  register NTSTATUS nErrCode;
186  register SIZE_T i;
187
188  /* repeat until all modules have been returned */
189  for(i = 0; i < SystemModules->Count; ++ i)
190  {
191   /* return current module to the callback */
192   nErrCode = Callback(&(SystemModules->Module[i]), CallbackContext);
193   
194   if(!NT_SUCCESS(nErrCode))
195    /* failure */
196    return nErrCode;
197  }
198
199  /* success */
200  return STATUS_SUCCESS;
201 }
202
203 PSYSTEM_MODULE_INFORMATION_ENTRY
204 FASTCALL
205 PsaWalkFirstSystemModule
206 (
207  IN PSYSTEM_MODULE_INFORMATION SystemModules
208 )
209
210  return &(SystemModules->Module[0]);
211 }
212
213 PSYSTEM_MODULE_INFORMATION_ENTRY
214 FASTCALL
215 PsaWalkNextSystemModule
216 (
217  IN PSYSTEM_MODULE_INFORMATION CurrentSystemModule
218 )
219 {
220  return (PSYSTEM_MODULE_INFORMATION_ENTRY)
221  (
222   (ULONG_PTR)CurrentSystemModule +
223   (
224    offsetof(SYSTEM_MODULE_INFORMATION, Module[1]) -
225    offsetof(SYSTEM_MODULE_INFORMATION, Module[0])
226   )
227  );
228 }
229
230 /* EOF */