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
30 register NTSTATUS nErrCode = STATUS_SUCCESS;
31 register PULONG pnModuleCount = &nSize;
32 register PSYSTEM_MODULE_ENTRY psmeCurModule;
33 register ULONG nModuleCount;
36 nErrCode = NtQuerySystemInformation
38 SystemModuleInformation,
44 if(nErrCode != STATUS_INFO_LENGTH_MISMATCH && !NT_SUCCESS(nErrCode))
47 DPRINT(FAILED_WITH_STATUS, "NtQuerySystemInformation", nErrCode);
51 /* RATIONALE: the loading of a system module is a rare occurrence. To minimize
52 memory operations that could be expensive, or fragment the pool/heap, we try
53 to determine the buffer size in advance, knowing that the number of elements
54 is unlikely to change */
55 nSize = sizeof(ULONG) + nSize * sizeof(SYSTEM_MODULE_ENTRY);
62 /* free the buffer, and reallocate it to the new size. RATIONALE: since we
63 ignore the buffer's content at this point, there's no point in a realloc(),
64 that could end up copying a large chunk of data we'd discard anyway */
71 nErrCode = STATUS_NO_MEMORY;
77 /* query the information */
78 nErrCode = NtQuerySystemInformation
80 SystemModuleInformation,
86 /* double the buffer for the next loop */
89 /* repeat until the buffer is big enough */
90 while(nErrCode == STATUS_INFO_LENGTH_MISMATCH);
92 if(!NT_SUCCESS(nErrCode))
95 DPRINT(FAILED_WITH_STATUS, "NtQuerySystemInformation", nErrCode);
99 /* the array of modules starts right after an ULONG storing their count */
100 psmeCurModule = (PSYSTEM_MODULE_ENTRY)(pnModuleCount + 1);
102 nModuleCount = *pnModuleCount;
104 /* repeat until all modules have been returned */
105 while(nModuleCount > 0)
107 /* return current module to the callback */
108 nErrCode = Callback(nModuleCount, psmeCurModule, CallbackContext);
110 if(!NT_SUCCESS(nErrCode))
120 /* free the buffer */
128 PsaEnumerateProcessModules
130 IN HANDLE ProcessHandle,
131 IN PPROCMOD_ENUM_ROUTINE Callback,
132 IN OUT PVOID CallbackContext
135 register NTSTATUS nErrCode;
137 /* current process - use direct memory copy */
138 if(ProcessHandle == NtCurrentProcess())
140 register PLIST_ENTRY pleListHead;
141 register PLIST_ENTRY pleCurEntry;
144 /* FIXME: activate this when GCC supports SEH */
148 pleListHead = &(NtCurrentPeb()->Ldr->InLoadOrderModuleList);
149 pleCurEntry = pleListHead->Flink;
151 while(pleCurEntry != pleListHead)
153 register PLDR_MODULE plmModule = CONTAINING_RECORD
157 InLoadOrderModuleList
160 /* return the current module to the callback */
161 nErrCode = Callback(ProcessHandle, plmModule, CallbackContext);
163 if(!NT_SUCCESS(nErrCode))
167 pleCurEntry = plmModule->InLoadOrderModuleList.Flink;
170 /* FIXME: activate this when GCC supports SEH */
172 __except(EXCEPTION_EXECUTE_HANDLER)
174 return GetExceptionCode();
178 /* another process */
181 PROCESS_BASIC_INFORMATION pbiInfo;
182 PPEB_LDR_DATA ppldLdrData;
184 PLIST_ENTRY pleListHead;
185 PLIST_ENTRY pleCurEntry;
187 /* query the process basic information (includes the PEB address) */
188 nErrCode = NtQueryInformationProcess
191 ProcessBasicInformation,
197 if(!NT_SUCCESS(nErrCode))
200 DPRINT(FAILED_WITH_STATUS, "NtQueryInformationProcess", nErrCode);
204 /* get the address of the PE Loader data */
205 nErrCode = NtReadVirtualMemory
208 &(pbiInfo.PebBaseAddress->Ldr),
214 if(!NT_SUCCESS(nErrCode))
217 DPRINT(FAILED_WITH_STATUS, "NtReadVirtualMemory", nErrCode);
221 /* head of the module list: the last element in the list will point to this */
222 pleListHead = &ppldLdrData->InLoadOrderModuleList;
224 /* get the address of the first element in the list */
225 nErrCode = NtReadVirtualMemory
228 &(ppldLdrData->InLoadOrderModuleList.Flink),
234 while(pleCurEntry != pleListHead)
236 /* read the current module */
237 nErrCode = NtReadVirtualMemory
240 CONTAINING_RECORD(pleCurEntry, LDR_MODULE, InLoadOrderModuleList),
246 if(!NT_SUCCESS(nErrCode))
249 DPRINT(FAILED_WITH_STATUS, "NtReadVirtualMemory", nErrCode);
253 /* return the current module to the callback */
254 nErrCode = Callback(ProcessHandle, &lmModule, CallbackContext);
256 if(!NT_SUCCESS(nErrCode))
260 /* address of the next module in the list */
261 pleCurEntry = lmModule.InLoadOrderModuleList.Flink;
267 return (STATUS_SUCCESS);