1 /* $Id: module.c,v 1.2 2002/08/29 23:57:53 hyperion Exp $
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/psapi/enum/module.c
8 * PURPOSE: Enumerate system and process modules
9 * PROGRAMMER: KJK::Hyperion <noog@libero.it>
12 * 29/08/2002: Generalized the interface to improve reusability,
13 * more efficient use of memory operations
16 #include <ddk/ntddk.h>
18 #include <internal/psapi.h>
19 #include <ntdll/ldr.h>
23 PsaEnumerateSystemModules
25 IN PSYSMOD_ENUM_ROUTINE Callback
,
26 IN OUT PVOID CallbackContext
,
27 IN OUT PVOID AllocatorContext
31 register NTSTATUS nErrCode
= STATUS_SUCCESS
;
32 register PULONG pnModuleCount
= &nSize
;
33 register PSYSTEM_MODULE_ENTRY psmeCurModule
;
34 register ULONG nModuleCount
;
37 nErrCode
= NtQuerySystemInformation
39 SystemModuleInformation
,
45 if(nErrCode
!= STATUS_INFO_LENGTH_MISMATCH
&& !NT_SUCCESS(nErrCode
))
48 DPRINT(FAILED_WITH_STATUS
, "NtQuerySystemInformation", nErrCode
);
52 /* RATIONALE: the loading of a system module is a rare occurrence. To minimize
53 memory operations that could be expensive, or fragment the pool/heap, we try
54 to determine the buffer size in advance, knowing that the number of elements
55 is unlikely to change */
56 nSize
= sizeof(ULONG
) + nSize
* sizeof(SYSTEM_MODULE_ENTRY
);
63 /* free the buffer, and reallocate it to the new size. RATIONALE: since we
64 ignore the buffer's content at this point, there's no point in a realloc(),
65 that could end up copying a large chunk of data we'd discard anyway */
66 PsaFree(AllocatorContext
, pnModuleCount
);
67 pTmp
= PsaMalloc(AllocatorContext
, nSize
);
72 nErrCode
= STATUS_NO_MEMORY
;
78 /* query the information */
79 nErrCode
= NtQuerySystemInformation
81 SystemModuleInformation
,
87 /* double the buffer for the next loop */
90 /* repeat until the buffer is big enough */
91 while(nErrCode
== STATUS_INFO_LENGTH_MISMATCH
);
93 if(!NT_SUCCESS(nErrCode
))
96 DPRINT(FAILED_WITH_STATUS
, "NtQuerySystemInformation", nErrCode
);
100 /* the array of modules starts right after an ULONG storing their count */
101 psmeCurModule
= (PSYSTEM_MODULE_ENTRY
)(pnModuleCount
+ 1);
103 nModuleCount
= *pnModuleCount
;
105 /* repeat until all modules have been returned */
106 while(nModuleCount
> 0)
108 /* return current module to the callback */
109 nErrCode
= Callback(nModuleCount
, psmeCurModule
, CallbackContext
);
111 if(!NT_SUCCESS(nErrCode
))
121 /* free the buffer */
122 PsaFree(AllocatorContext
, pnModuleCount
);
129 PsaEnumerateProcessModules
131 IN HANDLE ProcessHandle
,
132 IN PPROCMOD_ENUM_ROUTINE Callback
,
133 IN OUT PVOID CallbackContext
136 register NTSTATUS nErrCode
;
138 /* current process - use direct memory copy */
139 if(ProcessHandle
== NtCurrentProcess())
141 register PLIST_ENTRY pleListHead
;
142 register PLIST_ENTRY pleCurEntry
;
145 /* FIXME: activate this when GCC supports SEH */
149 pleListHead
= &(NtCurrentPeb()->Ldr
->InLoadOrderModuleList
);
150 pleCurEntry
= pleListHead
->Flink
;
152 while(pleCurEntry
!= pleListHead
)
154 register PLDR_MODULE plmModule
= CONTAINING_RECORD
158 InLoadOrderModuleList
161 /* return the current module to the callback */
162 nErrCode
= Callback(ProcessHandle
, plmModule
, CallbackContext
);
164 if(!NT_SUCCESS(nErrCode
))
168 pleCurEntry
= plmModule
->InLoadOrderModuleList
.Flink
;
171 /* FIXME: activate this when GCC supports SEH */
173 __except(EXCEPTION_EXECUTE_HANDLER
)
175 return GetExceptionCode();
179 /* another process */
182 PROCESS_BASIC_INFORMATION pbiInfo
;
183 PPEB_LDR_DATA ppldLdrData
;
185 PLIST_ENTRY pleListHead
;
186 PLIST_ENTRY pleCurEntry
;
188 /* query the process basic information (includes the PEB address) */
189 nErrCode
= NtQueryInformationProcess
192 ProcessBasicInformation
,
198 if(!NT_SUCCESS(nErrCode
))
201 DPRINT(FAILED_WITH_STATUS
, "NtQueryInformationProcess", nErrCode
);
205 /* get the address of the PE Loader data */
206 nErrCode
= NtReadVirtualMemory
209 &(pbiInfo
.PebBaseAddress
->Ldr
),
215 if(!NT_SUCCESS(nErrCode
))
218 DPRINT(FAILED_WITH_STATUS
, "NtReadVirtualMemory", nErrCode
);
222 /* head of the module list: the last element in the list will point to this */
223 pleListHead
= &ppldLdrData
->InLoadOrderModuleList
;
225 /* get the address of the first element in the list */
226 nErrCode
= NtReadVirtualMemory
229 &(ppldLdrData
->InLoadOrderModuleList
.Flink
),
235 while(pleCurEntry
!= pleListHead
)
237 /* read the current module */
238 nErrCode
= NtReadVirtualMemory
241 CONTAINING_RECORD(pleCurEntry
, LDR_MODULE
, InLoadOrderModuleList
),
247 if(!NT_SUCCESS(nErrCode
))
250 DPRINT(FAILED_WITH_STATUS
, "NtReadVirtualMemory", nErrCode
);
254 /* return the current module to the callback */
255 nErrCode
= Callback(ProcessHandle
, &lmModule
, CallbackContext
);
257 if(!NT_SUCCESS(nErrCode
))
261 /* address of the next module in the list */
262 pleCurEntry
= lmModule
.InLoadOrderModuleList
.Flink
;
268 return (STATUS_SUCCESS
);