PSAPI almost finished

svn path=/trunk/; revision=3439
This commit is contained in:
KJK::Hyperion 2002-08-29 23:57:54 +00:00
parent 3ede8f0814
commit 6332533037
7 changed files with 499 additions and 165 deletions

View file

@ -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 <noog@libero.it>
* UPDATE HISTORY:
* 10/06/2002: Created
* 29/08/2002: Generalized the interface to improve reusability,
* more efficient use of memory operations
*/
#include <ddk/ntddk.h>
#include <debug.h>
#include <internal/psapi.h>
#include <stdlib.h>
#include <ntdll/ldr.h>
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 */

View file

@ -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 <noog@libero.it>
* UPDATE HISTORY:
* 10/06/2002: Created
* 29/08/2002: Generalized the interface to improve reusability,
* more efficient use of memory operations
*/
#include <ddk/ntddk.h>
#include <internal/psapi.h>
#include <stdlib.h>
#include <ddk/ntddk.h>
#include <debug.h>
#include <internal/psapi.h>
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);

View file

@ -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 <ddk/ntddk.h>
#include <ntdll/ldr.h>
/* 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__ */

View file

@ -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 <windows.h>
#include <ntdll/ldr.h>
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 */

View file

@ -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

View file

@ -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 <windows.h>
#include <psapi.h>
@ -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

View file

@ -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 <noog@libero.it>
* UPDATE HISTORY:
* 10/06/2002: Created
*/
#include <windows.h>
#include <internal/psapi.h>
#include <psapi.h>
#include <stdlib.h>
#include <ddk/ntddk.h>
#include <internal/psapi.h>
/* 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 */