From 63325330375365e7e4e86eb001d9f37dfa9e9fd7 Mon Sep 17 00:00:00 2001 From: "KJK::Hyperion" Date: Thu, 29 Aug 2002 23:57:54 +0000 Subject: [PATCH] PSAPI almost finished svn path=/trunk/; revision=3439 --- reactos/lib/psapi/enum/module.c | 267 +++++++++++++++++---- reactos/lib/psapi/enum/process.c | 109 ++++----- reactos/lib/psapi/include/internal/psapi.h | 54 ++++- reactos/lib/psapi/misc/dllmain.c | 9 +- reactos/lib/psapi/misc/malloc.c | 2 + reactos/lib/psapi/misc/stubs.c | 13 +- reactos/lib/psapi/misc/win32.c | 210 ++++++++++++++-- 7 files changed, 499 insertions(+), 165 deletions(-) diff --git a/reactos/lib/psapi/enum/module.c b/reactos/lib/psapi/enum/module.c index d052429d2df..1c6428cfcb3 100644 --- a/reactos/lib/psapi/enum/module.c +++ b/reactos/lib/psapi/enum/module.c @@ -1,53 +1,76 @@ -/* $Id: module.c,v 1.1 2002/06/18 22:12:51 hyperion Exp $ +/* $Id: module.c,v 1.2 2002/08/29 23:57:53 hyperion Exp $ */ /* * COPYRIGHT: See COPYING in the top level directory + * LICENSE: See LGPL.txt in the top level directory * PROJECT: ReactOS system libraries * FILE: reactos/lib/psapi/enum/module.c - * PURPOSE: Enumerate system modules + * PURPOSE: Enumerate system and process modules * PROGRAMMER: KJK::Hyperion * UPDATE HISTORY: * 10/06/2002: Created + * 29/08/2002: Generalized the interface to improve reusability, + * more efficient use of memory operations */ #include +#include #include -#include +#include NTSTATUS STDCALL PsaEnumerateSystemModules ( - OUT PVOID * Modules, - IN ULONG ModulesLength, - OUT ULONG * ReturnLength OPTIONAL + IN PSYSMOD_ENUM_ROUTINE Callback, + IN OUT PVOID CallbackContext, + IN OUT PVOID AllocatorContext ) { - NTSTATUS nErrCode = STATUS_SUCCESS; - ULONG nSize = sizeof(ULONG); - PULONG pnModuleCount = NULL; - PSYSTEM_MODULE_ENTRY psmeCurModule; - ULONG nBufSize; + ULONG nSize; + register NTSTATUS nErrCode = STATUS_SUCCESS; + register PULONG pnModuleCount = &nSize; + register PSYSTEM_MODULE_ENTRY psmeCurModule; + register ULONG nModuleCount; - /* ignore buffer size if buffer is null */ - if(Modules == NULL) - ModulesLength = 0; - /* ignore buffer if buffer size is zero */ - else if(ModulesLength == 0) - Modules = NULL; + /* initial probe */ + nErrCode = NtQuerySystemInformation + ( + SystemModuleInformation, + pnModuleCount, + sizeof(nSize), + NULL + ); + + if(nErrCode != STATUS_INFO_LENGTH_MISMATCH && !NT_SUCCESS(nErrCode)) + { + /* failure */ + DPRINT(FAILED_WITH_STATUS, "NtQuerySystemInformation", nErrCode); + return nErrCode; + } + + /* RATIONALE: the loading of a system module is a rare occurrence. To minimize + memory operations that could be expensive, or fragment the pool/heap, we try + to determine the buffer size in advance, knowing that the number of elements + is unlikely to change */ + nSize = sizeof(ULONG) + nSize * sizeof(SYSTEM_MODULE_ENTRY); + pnModuleCount = NULL; do { - void * pTmp; - - /* resize and/or move the buffer */ - pTmp = realloc(pnModuleCount, nSize); + register void * pTmp; + + /* free the buffer, and reallocate it to the new size. RATIONALE: since we + ignore the buffer's content at this point, there's no point in a realloc(), + that could end up copying a large chunk of data we'd discard anyway */ + PsaFree(AllocatorContext, pnModuleCount); + pTmp = PsaMalloc(AllocatorContext, nSize); if(pTmp == NULL) { /* failure */ nErrCode = STATUS_NO_MEMORY; - goto end; + goto esm_Finalize; } pnModuleCount = pTmp; @@ -61,48 +84,192 @@ PsaEnumerateSystemModules NULL ); - /* while this is less efficient than doubling the buffer size, it should be - executed only once in most cases */ - nSize += sizeof(SYSTEM_MODULE_ENTRY) * (*pnModuleCount); + /* double the buffer for the next loop */ + nSize += nSize; } /* repeat until the buffer is big enough */ while(nErrCode == STATUS_INFO_LENGTH_MISMATCH); + if(!NT_SUCCESS(nErrCode)) + { + /* failure */ + DPRINT(FAILED_WITH_STATUS, "NtQuerySystemInformation", nErrCode); + goto esm_Finalize; + } + /* the array of modules starts right after an ULONG storing their count */ psmeCurModule = (PSYSTEM_MODULE_ENTRY)(pnModuleCount + 1); - - /* element count */ - nBufSize = ModulesLength / sizeof(*Modules); - - /* not enough elements in the buffer */ - if((*pnModuleCount) > nBufSize) - nErrCode = STATUS_INFO_LENGTH_MISMATCH; - /* too many elements in the buffer */ - else - nBufSize = *pnModuleCount; - - /* return the needed buffer size */ - if(ReturnLength) - (*ReturnLength) = (*pnModuleCount) * sizeof(*Modules); - - /* repeat until the buffer is empty or all modules have been returned */ - while(nBufSize > 0) + + nModuleCount = *pnModuleCount; + + /* repeat until all modules have been returned */ + while(nModuleCount > 0) { - /* return current module base */ - (*Modules) = psmeCurModule->BaseAddress; + /* return current module to the callback */ + nErrCode = Callback(nModuleCount, psmeCurModule, CallbackContext); - /* next buffer element */ - Modules ++; - nBufSize --; + if(!NT_SUCCESS(nErrCode)) + /* failure */ + goto esm_Finalize; /* next module */ psmeCurModule ++; + nModuleCount --; } + +esm_Finalize: + /* free the buffer */ + PsaFree(AllocatorContext, pnModuleCount); + + return (nErrCode); +} + +NTSTATUS +STDCALL +PsaEnumerateProcessModules +( + IN HANDLE ProcessHandle, + IN PPROCMOD_ENUM_ROUTINE Callback, + IN OUT PVOID CallbackContext +) +{ + register NTSTATUS nErrCode; + + /* current process - use direct memory copy */ + if(ProcessHandle == NtCurrentProcess()) + { + register PLIST_ENTRY pleListHead; + register PLIST_ENTRY pleCurEntry; + +#if 0 + /* FIXME: activate this when GCC supports SEH */ + __try + { +#endif + pleListHead = &(NtCurrentPeb()->Ldr->InLoadOrderModuleList); + pleCurEntry = pleListHead->Flink; -end: - free(pnModuleCount); + while(pleCurEntry != pleListHead) + { + register PLDR_MODULE plmModule = CONTAINING_RECORD + ( + pleCurEntry, + LDR_MODULE, + InLoadOrderModuleList + ); + + /* return the current module to the callback */ + nErrCode = Callback(ProcessHandle, plmModule, CallbackContext); + + if(!NT_SUCCESS(nErrCode)) + /* failure */ + goto epm_Failure; + + pleCurEntry = plmModule->InLoadOrderModuleList.Flink; + } +#if 0 + /* FIXME: activate this when GCC supports SEH */ + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } +#endif + } + /* another process */ + else + { + PROCESS_BASIC_INFORMATION pbiInfo; + PPEB_LDR_DATA ppldLdrData; + LDR_MODULE lmModule; + PLIST_ENTRY pleListHead; + PLIST_ENTRY pleCurEntry; + + /* query the process basic information (includes the PEB address) */ + nErrCode = NtQueryInformationProcess + ( + ProcessHandle, + ProcessBasicInformation, + &pbiInfo, + sizeof(pbiInfo), + NULL + ); + + if(!NT_SUCCESS(nErrCode)) + { + /* failure */ + DPRINT(FAILED_WITH_STATUS, "NtQueryInformationProcess", nErrCode); + goto epm_Failure; + } + + /* get the address of the PE Loader data */ + nErrCode = NtReadVirtualMemory + ( + ProcessHandle, + &(pbiInfo.PebBaseAddress->Ldr), + &ppldLdrData, + sizeof(ppldLdrData), + NULL + ); + + if(!NT_SUCCESS(nErrCode)) + { + /* failure */ + DPRINT(FAILED_WITH_STATUS, "NtReadVirtualMemory", nErrCode); + goto epm_Failure; + } + + /* head of the module list: the last element in the list will point to this */ + pleListHead = &ppldLdrData->InLoadOrderModuleList; + + /* get the address of the first element in the list */ + nErrCode = NtReadVirtualMemory + ( + ProcessHandle, + &(ppldLdrData->InLoadOrderModuleList.Flink), + &pleCurEntry, + sizeof(pleCurEntry), + NULL + ); + + while(pleCurEntry != pleListHead) + { + /* read the current module */ + nErrCode = NtReadVirtualMemory + ( + ProcessHandle, + CONTAINING_RECORD(pleCurEntry, LDR_MODULE, InLoadOrderModuleList), + &lmModule, + sizeof(lmModule), + NULL + ); + + if(!NT_SUCCESS(nErrCode)) + { + /* failure */ + DPRINT(FAILED_WITH_STATUS, "NtReadVirtualMemory", nErrCode); + goto epm_Failure; + } + + /* return the current module to the callback */ + nErrCode = Callback(ProcessHandle, &lmModule, CallbackContext); + + if(!NT_SUCCESS(nErrCode)) + /* failure */ + goto epm_Failure; + + /* address of the next module in the list */ + pleCurEntry = lmModule.InLoadOrderModuleList.Flink; + } + + } + + /* success */ + return (STATUS_SUCCESS); + +epm_Failure: + /* failure */ return (nErrCode); } /* EOF */ - diff --git a/reactos/lib/psapi/enum/process.c b/reactos/lib/psapi/enum/process.c index 38de9ff03d9..9b3dbb85dc9 100644 --- a/reactos/lib/psapi/enum/process.c +++ b/reactos/lib/psapi/enum/process.c @@ -1,54 +1,58 @@ -/* $Id: process.c,v 1.1 2002/06/18 22:12:51 hyperion Exp $ +/* $Id: process.c,v 1.2 2002/08/29 23:57:53 hyperion Exp $ */ /* * COPYRIGHT: See COPYING in the top level directory + * LICENSE: See LGPL.txt in the top level directory * PROJECT: ReactOS system libraries * FILE: reactos/lib/psapi/enum/process.c - * PURPOSE: Enumerate process ids + * PURPOSE: Enumerate processes * PROGRAMMER: KJK::Hyperion * UPDATE HISTORY: * 10/06/2002: Created + * 29/08/2002: Generalized the interface to improve reusability, + * more efficient use of memory operations */ -#include -#include #include +#include +#include +#include NTSTATUS STDCALL -PsaEnumerateProcessIds +PsaEnumerateProcesses ( - OUT ULONG * ProcessIds, - IN ULONG ProcessIdsLength, - OUT ULONG * ReturnLength OPTIONAL + IN PPROC_ENUM_ROUTINE Callback, + IN OUT PVOID CallbackContext, + IN OUT PVOID AllocatorContext ) { - NTSTATUS nErrCode = STATUS_SUCCESS; + register NTSTATUS nErrCode = STATUS_SUCCESS; + PSYSTEM_PROCESS_INFORMATION pInfoBuffer = NULL; + PSYSTEM_PROCESS_INFORMATION pInfoHead = NULL; ULONG nSize = 32768; - SYSTEM_PROCESS_INFORMATION * pInfoBuffer = NULL; - SYSTEM_PROCESS_INFORMATION * pInfoHead = NULL; - ULONG nBufSize; - ULONG nRetLen = 0; - /* ignore buffer size if buffer is null */ - if(ProcessIds == NULL) - ProcessIdsLength = 0; - /* ignore buffer if buffer size is zero */ - else if(ProcessIdsLength == 0) - ProcessIds = NULL; - + /* FIXME: if the system has loaded several processes and threads, the buffer + could get really big. But if there's several processes and threads, the + system is already under stress, and a huge buffer could only make things + worse. The function should be profiled to see what's the average minimum + buffer size, to succeed on the first shot */ do { void * pTmp; - /* resize and/or move the buffer */ - pTmp = realloc(pInfoBuffer, nSize); + /* free the buffer, and reallocate it to the new size. RATIONALE: since we + ignore the buffer's contents at this point, there's no point in a realloc() + that could end up copying a large chunk of data we'd discard anyway */ + PsaFree(AllocatorContext, pInfoBuffer); + pTmp = PsaMalloc(AllocatorContext, nSize); if(pTmp == NULL) { /* failure */ + DPRINT(FAILED_WITH_STATUS, "malloc", STATUS_NO_MEMORY); nErrCode = STATUS_NO_MEMORY; - goto end; + goto esp_Finalize; } pInfoBuffer = pTmp; @@ -70,26 +74,23 @@ PsaEnumerateProcessIds /* failure */ if(!NT_SUCCESS(nErrCode)) - goto end; + { + DPRINT(FAILED_WITH_STATUS, "NtQuerySystemInformation", nErrCode); + goto esp_Finalize; + } - /* size of ProcessIds in elements */ - nBufSize = ProcessIdsLength / sizeof(*ProcessIds); /* list head */ pInfoHead = pInfoBuffer; - /* repeat until the buffer is empty */ - while(nBufSize > 0) + /* scan the list */ + while(1) { - /* return the current process id */ - (*ProcessIds) = pInfoHead->ProcessId; - - /* move to the next buffer entry */ - ProcessIds ++; - nBufSize --; - nRetLen ++; - - /* end of process list */ - if(pInfoHead->RelativeOffset == 0) + /* notify the callback */ + nErrCode = Callback(pInfoHead, CallbackContext); + + /* if the callback returned an error or this is the end of the process list, + break out */ + if(!NT_SUCCESS(nErrCode) || pInfoHead->RelativeOffset == 0) break; /* move to the next process */ @@ -98,37 +99,9 @@ PsaEnumerateProcessIds ((ULONG)pInfoHead + pInfoHead->RelativeOffset); } - if(pInfoHead->RelativeOffset == 0) - /* all process ids were returned */ - nErrCode = STATUS_SUCCESS; - else - { - /* insufficient buffer */ - nErrCode = STATUS_INFO_LENGTH_MISMATCH; - - /* caller doesn't need buffer size */ - if(ReturnLength == NULL) - goto end; - - /* repeat while there are still processes */ - while(pInfoHead->RelativeOffset != 0) - { - pInfoHead = - (SYSTEM_PROCESS_INFORMATION*) - ((ULONG)pInfoHead + pInfoHead->RelativeOffset); - - nRetLen++; - } - - } - - /* used buffer size */ - if(ReturnLength) - (*ReturnLength) = nRetLen * sizeof(DWORD); - -end: +esp_Finalize: /* free the buffer */ - free(pInfoBuffer); + PsaFree(AllocatorContext, pInfoBuffer); /* return the last status */ return (nErrCode); diff --git a/reactos/lib/psapi/include/internal/psapi.h b/reactos/lib/psapi/include/internal/psapi.h index 9d9116eb7f9..f78e153a529 100644 --- a/reactos/lib/psapi/include/internal/psapi.h +++ b/reactos/lib/psapi/include/internal/psapi.h @@ -1,9 +1,9 @@ -/* $Id: psapi.h,v 1.1 2002/06/18 22:15:57 hyperion Exp $ +/* $Id: psapi.h,v 1.2 2002/08/29 23:57:54 hyperion Exp $ */ /* * internal/psapi.h * - * Process Status Helper API + * Process Status Helper API, native interface * * This file is part of the ReactOS Operating System. * @@ -27,33 +27,69 @@ /* INCLUDES */ #include +#include /* OBJECTS */ /* TYPES */ +typedef NTSTATUS STDCALL (*PPROC_ENUM_ROUTINE) +( + IN PSYSTEM_PROCESS_INFORMATION CurrentProcess, + IN OUT PVOID CallbackContext +); + +typedef NTSTATUS STDCALL (*PSYSMOD_ENUM_ROUTINE) +( + IN ULONG ModuleCount, + IN PSYSTEM_MODULE_ENTRY CurrentModule, + IN OUT PVOID CallbackContext +); + +typedef NTSTATUS STDCALL (*PPROCMOD_ENUM_ROUTINE) +( + IN HANDLE ProcessHandle, + IN PLDR_MODULE CurrentModule, + IN OUT PVOID CallbackContext +); /* CONSTANTS */ +#define FAILED_WITH_STATUS DEFINE_DBG_MSG("%s() failed, status 0x%08X") /* PROTOTYPES */ NTSTATUS STDCALL -PsaEnumerateProcessIds +PsaEnumerateProcesses ( - OUT ULONG * ProcessIds, - IN ULONG ProcessIdsLength, - OUT ULONG * ReturnLength OPTIONAL + IN PPROC_ENUM_ROUTINE Callback, + IN OUT PVOID CallbackContext, + IN OUT PVOID AllocatorContext ); NTSTATUS STDCALL PsaEnumerateSystemModules ( - OUT PVOID * Modules, - IN ULONG ModulesLength, - OUT ULONG * ReturnLength OPTIONAL + IN PSYSMOD_ENUM_ROUTINE Callback, + IN OUT PVOID CallbackContext, + IN OUT PVOID AllocatorContext ); +NTSTATUS +STDCALL +PsaEnumerateProcessModules +( + IN HANDLE ProcessHandle, + IN PPROCMOD_ENUM_ROUTINE Callback, + IN OUT PVOID CallbackContext +); + +/* the user must provide these */ +PVOID STDCALL PsaMalloc(IN OUT PVOID Context, IN ULONG Size); +PVOID STDCALL PsaRealloc(IN OUT PVOID Context, IN PVOID Addr, IN ULONG Size); +VOID STDCALL PsaFree(IN OUT PVOID Context, IN PVOID Addr); + /* MACROS */ +#define DEFINE_DBG_MSG(__str__) "PSAPI: " __str__ "\n" #endif /* __INTERNAL_PSAPI_H_INCLUDED__ */ diff --git a/reactos/lib/psapi/misc/dllmain.c b/reactos/lib/psapi/misc/dllmain.c index 99b01ba5622..b7202696fe9 100644 --- a/reactos/lib/psapi/misc/dllmain.c +++ b/reactos/lib/psapi/misc/dllmain.c @@ -1,8 +1,9 @@ -/* $Id: dllmain.c,v 1.2 2002/06/18 22:15:58 hyperion Exp $ +/* $Id: dllmain.c,v 1.3 2002/08/29 23:57:54 hyperion Exp $ * * ReactOS PSAPI.DLL */ #include +#include BOOLEAN STDCALL DllMain ( @@ -11,6 +12,12 @@ BOOLEAN STDCALL DllMain PVOID reserved ) { + if(dwReason == DLL_PROCESS_ATTACH) + /* don't bother calling the entry point on thread startup - PSAPI.DLL doesn't + store any per-thread data */ + LdrDisableThreadCalloutsForDll(hinstDll); + return (TRUE); } + /* EOF */ diff --git a/reactos/lib/psapi/misc/malloc.c b/reactos/lib/psapi/misc/malloc.c index 6353f05c109..2a31d9fed92 100644 --- a/reactos/lib/psapi/misc/malloc.c +++ b/reactos/lib/psapi/misc/malloc.c @@ -1,3 +1,5 @@ +/* $Id: malloc.c,v 1.2 2002/08/29 23:57:54 hyperion Exp $ + */ /* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS system libraries diff --git a/reactos/lib/psapi/misc/stubs.c b/reactos/lib/psapi/misc/stubs.c index ebe3801c909..3b805e9e243 100644 --- a/reactos/lib/psapi/misc/stubs.c +++ b/reactos/lib/psapi/misc/stubs.c @@ -1,4 +1,4 @@ -/* $Id: stubs.c,v 1.2 2002/06/18 22:15:58 hyperion Exp $ */ +/* $Id: stubs.c,v 1.3 2002/08/29 23:57:54 hyperion Exp $ */ #include #include @@ -12,17 +12,6 @@ BOOL STDCALL EnumPageFiles( return FALSE; } #endif -BOOL STDCALL EnumProcessModules( - HANDLE hProcess, // handle to process - HMODULE *lphModule, // array of module handles - DWORD cb, // size of array - LPDWORD lpcbNeeded // number of bytes required -) -{ - SetLastError(ERROR_INVALID_FUNCTION); - return FALSE; -} - DWORD STDCALL GetDeviceDriverBaseNameA( LPVOID ImageBase, // driver load address LPSTR lpBaseName, // driver base name buffer diff --git a/reactos/lib/psapi/misc/win32.c b/reactos/lib/psapi/misc/win32.c index b4d28005135..9b6b61b3bb0 100644 --- a/reactos/lib/psapi/misc/win32.c +++ b/reactos/lib/psapi/misc/win32.c @@ -1,19 +1,38 @@ -/* $Id: win32.c,v 1.1 2002/06/18 22:14:07 hyperion Exp $ +/* $Id: win32.c,v 1.2 2002/08/29 23:57:54 hyperion Exp $ */ /* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS system libraries * FILE: reactos/lib/psapi/misc/win32.c - * PURPOSE: Win32 stubs for PSAPI + * PURPOSE: Win32 interfaces for PSAPI * PROGRAMMER: KJK::Hyperion * UPDATE HISTORY: * 10/06/2002: Created */ #include -#include #include +#include +#include +#include +/* Memory allocators for PSAPI */ +PVOID STDCALL PsaMalloc(IN OUT PVOID Context, IN ULONG Size) +{ + return malloc(Size); +} + +PVOID STDCALL PsaRealloc(IN OUT PVOID Context, IN PVOID Addr, IN ULONG Size) +{ + return realloc(Addr, Size); +} + +VOID STDCALL PsaFree(IN OUT PVOID Context, IN PVOID Addr) +{ + free(Addr); +} + +/* EmptyWorkingSet */ BOOL STDCALL EmptyWorkingSet(HANDLE hProcess) { NTSTATUS nErrCode; @@ -56,6 +75,40 @@ fail: return (FALSE); } +/* EnumDeviceDrivers */ +/* callback context */ +typedef struct _ENUM_DEVICE_DRIVERS_CONTEXT +{ + LPVOID *lpImageBase; + DWORD nCount; +} ENUM_DEVICE_DRIVERS_CONTEXT, *PENUM_DEVICE_DRIVERS_CONTEXT; + +/* callback routine */ +NTSTATUS STDCALL EnumDeviceDriversCallback +( + IN ULONG ModuleCount, + IN PSYSTEM_MODULE_ENTRY CurrentModule, + IN OUT PVOID CallbackContext +) +{ + register PENUM_DEVICE_DRIVERS_CONTEXT peddcContext = + (PENUM_DEVICE_DRIVERS_CONTEXT)CallbackContext; + + /* no more buffer space */ + if(peddcContext->nCount == 0) + return STATUS_INFO_LENGTH_MISMATCH; + + /* return current module */ + *(peddcContext->lpImageBase) = CurrentModule->BaseAddress; + + /* go to next array slot */ + (peddcContext->lpImageBase) ++; + (peddcContext->nCount) --; + + return STATUS_SUCCESS; +} + +/* exported interface */ BOOL STDCALL EnumDeviceDrivers ( LPVOID *lpImageBase, @@ -63,29 +116,32 @@ BOOL STDCALL EnumDeviceDrivers LPDWORD lpcbNeeded ) { - NTSTATUS nErrCode; - + register NTSTATUS nErrCode; + ENUM_DEVICE_DRIVERS_CONTEXT eddcContext = {lpImageBase, cb / sizeof(PVOID)}; + + cb /= sizeof(PVOID); + /* do nothing if the buffer is empty */ - if(cb < sizeof(DWORD) || lpImageBase == NULL) + if(cb == 0 || lpImageBase == NULL) { *lpcbNeeded = 0; return (TRUE); } /* enumerate the system modules */ - nErrCode = PsaEnumerateSystemModules(lpImageBase, cb, lpcbNeeded); + nErrCode = PsaEnumerateSystemModules + ( + &EnumDeviceDriversCallback, + &eddcContext, + NULL + ); + /* return the count of bytes returned */ + *lpcbNeeded = (cb - eddcContext.nCount) * sizeof(PVOID); + /* success */ - if(NT_SUCCESS(nErrCode)) + if(NT_SUCCESS(nErrCode) || nErrCode == STATUS_INFO_LENGTH_MISMATCH) return (TRUE); - - /* failure or partial success */ - if(nErrCode == STATUS_INFO_LENGTH_MISMATCH) - { - /* insufficient buffer: ignore this error */ - *lpcbNeeded = cb; - return (TRUE); - } else { /* failure */ @@ -94,6 +150,39 @@ BOOL STDCALL EnumDeviceDrivers } } +/* EnumProcesses */ +/* callback context */ +typedef struct _ENUM_PROCESSES_CONTEXT +{ + DWORD *lpidProcess; + DWORD nCount; +} ENUM_PROCESSES_CONTEXT, *PENUM_PROCESSES_CONTEXT; + +/* callback routine */ +NTSTATUS STDCALL EnumProcessesCallback +( + IN PSYSTEM_PROCESS_INFORMATION CurrentProcess, + IN OUT PVOID CallbackContext +) +{ + register PENUM_PROCESSES_CONTEXT pepcContext = + (PENUM_PROCESSES_CONTEXT)CallbackContext; + + /* no more buffer space */ + if(pepcContext->nCount == 0) + return STATUS_INFO_LENGTH_MISMATCH; + + /* return current process */ + *(pepcContext->lpidProcess) = CurrentProcess->ProcessId; + + /* go to next array slot */ + (pepcContext->lpidProcess) ++; + (pepcContext->nCount) --; + + return STATUS_SUCCESS; +} + +/* exported interface */ BOOL STDCALL EnumProcesses ( DWORD *lpidProcess, @@ -101,29 +190,100 @@ BOOL STDCALL EnumProcesses LPDWORD lpcbNeeded ) { - NTSTATUS nErrCode; + register NTSTATUS nErrCode; + ENUM_PROCESSES_CONTEXT epcContext = {lpidProcess, cb / sizeof(DWORD)}; + cb /= sizeof(DWORD); + /* do nothing if the buffer is empty */ - if(cb < sizeof(DWORD) || lpidProcess == NULL) + if(cb == 0 || lpidProcess == NULL) { *lpcbNeeded = 0; return (TRUE); } /* enumerate the process ids */ - nErrCode = PsaEnumerateProcessIds(lpidProcess, cb, lpcbNeeded); + nErrCode = PsaEnumerateProcesses(&EnumProcessesCallback, &epcContext, NULL); + *lpcbNeeded = (cb - epcContext.nCount) * sizeof(DWORD); + /* success */ - if(NT_SUCCESS(nErrCode)) + if(NT_SUCCESS(nErrCode) || nErrCode == STATUS_INFO_LENGTH_MISMATCH) return (TRUE); - - /* failure or partial success */ - if(nErrCode == STATUS_INFO_LENGTH_MISMATCH) + else { - /* insufficient buffer: ignore this error */ - *lpcbNeeded = cb; + /* failure */ + SetLastError(RtlNtStatusToDosError(nErrCode)); + return (FALSE); + } +} + +/* EnumProcessModules */ +/* callback context */ +typedef struct _ENUM_PROCESS_MODULES_CONTEXT +{ + HMODULE *lphModule; + DWORD nCount; +} ENUM_PROCESS_MODULES_CONTEXT, *PENUM_PROCESS_MODULES_CONTEXT; + +/* callback routine */ +NTSTATUS STDCALL EnumProcessModulesCallback +( + IN HANDLE ProcessHandle, + IN PLDR_MODULE CurrentModule, + IN OUT PVOID CallbackContext +) +{ + register PENUM_PROCESS_MODULES_CONTEXT pepmcContext = + (PENUM_PROCESS_MODULES_CONTEXT)CallbackContext; + + /* no more buffer space */ + if(pepmcContext->nCount == 0) + return STATUS_INFO_LENGTH_MISMATCH; + + /* return current process */ + *(pepmcContext->lphModule) = CurrentModule->BaseAddress; + + /* go to next array slot */ + (pepmcContext->lphModule) ++; + (pepmcContext->nCount) --; + + return STATUS_SUCCESS; +} + +/* exported interface */ +BOOL STDCALL EnumProcessModules( + HANDLE hProcess, // handle to process + HMODULE *lphModule, // array of module handles + DWORD cb, // size of array + LPDWORD lpcbNeeded // number of bytes required +) +{ + register NTSTATUS nErrCode; + ENUM_PROCESS_MODULES_CONTEXT epmcContext = {lphModule, cb / sizeof(HMODULE)}; + + cb /= sizeof(DWORD); + + /* do nothing if the buffer is empty */ + if(cb == 0 || lphModule == NULL) + { + *lpcbNeeded = 0; return (TRUE); } + + /* enumerate the process modules */ + nErrCode = PsaEnumerateProcessModules + ( + hProcess, + &EnumProcessModulesCallback, + &epmcContext + ); + + *lpcbNeeded = (cb - epmcContext.nCount) * sizeof(DWORD); + + /* success */ + if(NT_SUCCESS(nErrCode) || nErrCode == STATUS_INFO_LENGTH_MISMATCH) + return (TRUE); else { /* failure */