reactos/dll/win32/psapi/psapi.c
Hermès Bélusca-Maïto 65ce146169 Create a branch for working on csrss and co.
svn path=/branches/ros-csrss/; revision=57561
2012-10-14 13:04:31 +00:00

1420 lines
33 KiB
C

/* $Id$
*/
/*
* 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/misc/win32.c
* PURPOSE: Win32 interfaces for PSAPI
* PROGRAMMER: KJK::Hyperion <noog@libero.it>
* Thomas Weidenmueller <w3seek@reactos.com>
* UPDATE HISTORY:
* 10/06/2002: Created
*/
#include "precomp.h"
#define NDEBUG
#include <debug.h>
BOOLEAN
WINAPI
DllMain(HINSTANCE hDllHandle,
DWORD nReason,
LPVOID Reserved)
{
switch(nReason)
{
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hDllHandle);
break;
}
return TRUE;
}
/* INTERNAL *******************************************************************/
typedef struct _ENUM_DEVICE_DRIVERS_CONTEXT
{
LPVOID *lpImageBase;
DWORD nCount;
DWORD nTotal;
} ENUM_DEVICE_DRIVERS_CONTEXT, *PENUM_DEVICE_DRIVERS_CONTEXT;
NTSTATUS WINAPI
EnumDeviceDriversCallback(IN PRTL_PROCESS_MODULE_INFORMATION CurrentModule,
IN OUT PVOID CallbackContext)
{
PENUM_DEVICE_DRIVERS_CONTEXT Context = (PENUM_DEVICE_DRIVERS_CONTEXT)CallbackContext;
/* check if more buffer space is available */
if(Context->nCount != 0)
{
/* return current module */
*Context->lpImageBase = CurrentModule->ImageBase;
/* go to next array slot */
Context->lpImageBase++;
Context->nCount--;
}
Context->nTotal++;
return STATUS_SUCCESS;
}
typedef struct _ENUM_PROCESSES_CONTEXT
{
DWORD *lpidProcess;
DWORD nCount;
} ENUM_PROCESSES_CONTEXT, *PENUM_PROCESSES_CONTEXT;
NTSTATUS WINAPI
EnumProcessesCallback(IN PSYSTEM_PROCESS_INFORMATION CurrentProcess,
IN OUT PVOID CallbackContext)
{
PENUM_PROCESSES_CONTEXT Context = (PENUM_PROCESSES_CONTEXT)CallbackContext;
/* no more buffer space */
if(Context->nCount == 0)
{
return STATUS_INFO_LENGTH_MISMATCH;
}
/* return current process */
*Context->lpidProcess = (DWORD_PTR)CurrentProcess->UniqueProcessId;
/* go to next array slot */
Context->lpidProcess++;
Context->nCount--;
return STATUS_SUCCESS;
}
typedef struct _ENUM_PROCESS_MODULES_CONTEXT
{
HMODULE *lphModule;
DWORD nCount;
DWORD nTotal;
} ENUM_PROCESS_MODULES_CONTEXT, *PENUM_PROCESS_MODULES_CONTEXT;
NTSTATUS WINAPI
EnumProcessModulesCallback(IN HANDLE ProcessHandle,
IN PLDR_DATA_TABLE_ENTRY CurrentModule,
IN OUT PVOID CallbackContext)
{
PENUM_PROCESS_MODULES_CONTEXT Context = (PENUM_PROCESS_MODULES_CONTEXT)CallbackContext;
/* check if more buffer space is available */
if(Context->nCount != 0)
{
/* return current process */
*Context->lphModule = CurrentModule->DllBase;
/* go to next array slot */
Context->lphModule++;
Context->nCount--;
}
Context->nTotal++;
return STATUS_SUCCESS;
}
typedef struct _GET_DEVICE_DRIVER_NAME_CONTEXT
{
LPVOID ImageBase;
struct
{
ULONG bFullName : sizeof(ULONG) * 8 / 2;
ULONG bUnicode : sizeof(ULONG) * 8 / 2;
};
DWORD nSize;
union
{
LPVOID lpName;
LPSTR lpAnsiName;
LPWSTR lpUnicodeName;
};
} GET_DEVICE_DRIVER_NAME_CONTEXT, *PGET_DEVICE_DRIVER_NAME_CONTEXT;
NTSTATUS WINAPI
GetDeviceDriverNameCallback(IN PRTL_PROCESS_MODULE_INFORMATION CurrentModule,
IN OUT PVOID CallbackContext)
{
PGET_DEVICE_DRIVER_NAME_CONTEXT Context = (PGET_DEVICE_DRIVER_NAME_CONTEXT)CallbackContext;
/* module found */
if(Context->ImageBase == CurrentModule->ImageBase)
{
PCHAR pcModuleName;
ULONG l;
/* get the full name or just the filename part */
if(Context->bFullName)
pcModuleName = &CurrentModule->FullPathName[0];
else
pcModuleName = &CurrentModule->FullPathName[CurrentModule->OffsetToFileName];
/* get the length of the name */
l = strlen(pcModuleName);
if(Context->nSize <= l)
{
/* use the user buffer's length */
l = Context->nSize;
}
else
{
/* enough space for the null terminator */
Context->nSize = ++l;
}
/* copy the string */
if(Context->bUnicode)
{
ANSI_STRING AnsiString;
UNICODE_STRING UnicodeString;
UnicodeString.Length = 0;
UnicodeString.MaximumLength = l * sizeof(WCHAR);
UnicodeString.Buffer = Context->lpUnicodeName;
RtlInitAnsiString(&AnsiString, pcModuleName);
/* driver names should always be in language-neutral ASCII, so we don't
bother calling AreFileApisANSI() */
RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, FALSE);
}
else
{
memcpy(Context->lpAnsiName, pcModuleName, l);
}
/* terminate the enumeration */
return STATUS_NO_MORE_FILES;
}
else
{
/* continue searching */
return STATUS_SUCCESS;
}
}
static DWORD
InternalGetDeviceDriverName(BOOLEAN bUnicode,
BOOLEAN bFullName,
LPVOID ImageBase,
LPVOID lpName,
DWORD nSize)
{
GET_DEVICE_DRIVER_NAME_CONTEXT Context;
NTSTATUS Status;
if(lpName == NULL || nSize == 0)
{
return 0;
}
if(ImageBase == NULL)
{
SetLastError(ERROR_INVALID_HANDLE);
return 0;
}
Context.ImageBase = ImageBase;
Context.bFullName = bFullName;
Context.bUnicode = bUnicode;
Context.nSize = nSize;
Context.lpName = lpName;
/* start the enumeration */
Status = PsaEnumerateSystemModules(GetDeviceDriverNameCallback, &Context);
if(Status == STATUS_NO_MORE_FILES)
{
/* module was found, return string size */
return Context.nSize;
}
else if(NT_SUCCESS(Status))
{
/* module was not found */
SetLastError(ERROR_INVALID_HANDLE);
}
else
{
/* an error occurred */
SetLastErrorByStatus(Status);
}
return 0;
}
static DWORD
InternalGetMappedFileName(BOOLEAN bUnicode,
HANDLE hProcess,
LPVOID lpv,
LPVOID lpName,
DWORD nSize)
{
PMEMORY_SECTION_NAME pmsnName;
ULONG nBufSize;
NTSTATUS Status;
if(nSize == 0 || lpName == NULL)
{
return 0;
}
if(nSize > (0xFFFF / sizeof(WCHAR)))
{
/* if the user buffer contains more characters than would fit in an
UNICODE_STRING, limit the buffer size. RATIONALE: we don't limit buffer
size elsewhere because here superfluous buffer size will mean a larger
temporary buffer */
nBufSize = 0xFFFF / sizeof(WCHAR);
}
else
{
nBufSize = nSize * sizeof(WCHAR);
}
/* allocate the memory */
pmsnName = PsaiMalloc(nBufSize + sizeof(MEMORY_SECTION_NAME));
if(pmsnName == NULL)
{
SetLastError(ERROR_OUTOFMEMORY);
return 0;
}
/* initialize the destination buffer */
pmsnName->SectionFileName.Length = 0;
pmsnName->SectionFileName.Length = nBufSize;
#if 0
__try
{
#endif
/* query the name */
Status = NtQueryVirtualMemory(hProcess,
lpv,
MemorySectionName,
pmsnName,
nBufSize,
NULL);
if(!NT_SUCCESS(Status))
{
PsaiFree(pmsnName);
SetLastErrorByStatus(Status);
return 0;
}
if(bUnicode)
{
/* destination is an Unicode string: direct copy */
memcpy((LPWSTR)lpName, pmsnName + 1, pmsnName->SectionFileName.Length);
PsaiFree(pmsnName);
if(pmsnName->SectionFileName.Length < nSize)
{
/* null-terminate the string */
((LPWSTR)lpName)[pmsnName->SectionFileName.Length] = 0;
return pmsnName->SectionFileName.Length + 1;
}
return pmsnName->SectionFileName.Length;
}
else
{
ANSI_STRING AnsiString;
AnsiString.Length = 0;
AnsiString.MaximumLength = nSize;
AnsiString.Buffer = (LPSTR)lpName;
if(AreFileApisANSI())
RtlUnicodeStringToAnsiString(&AnsiString, &pmsnName->SectionFileName, FALSE);
else
RtlUnicodeStringToOemString(&AnsiString, &pmsnName->SectionFileName, FALSE);
PsaiFree(pmsnName);
if(AnsiString.Length < nSize)
{
/* null-terminate the string */
((LPSTR)lpName)[AnsiString.Length] = 0;
return AnsiString.Length + 1;
}
return AnsiString.Length;
}
#if 0
}
__finally
{
PsaiFree(pmsnName);
}
#endif
}
typedef struct _GET_MODULE_INFORMATION_FLAGS
{
ULONG bWantName : sizeof(ULONG) * 8 / 4;
ULONG bUnicode : sizeof(ULONG) * 8 / 4;
ULONG bFullName : sizeof(ULONG) * 8 / 4;
} GET_MODULE_INFORMATION_FLAGS, *PGET_MODULE_INFORMATION_FLAGS;
typedef struct _GET_MODULE_INFORMATION_CONTEXT
{
HMODULE hModule;
GET_MODULE_INFORMATION_FLAGS Flags;
DWORD nBufSize;
union
{
LPWSTR lpUnicodeName;
LPSTR lpAnsiName;
LPMODULEINFO lpmodinfo;
LPVOID lpBuffer;
};
} GET_MODULE_INFORMATION_CONTEXT, *PGET_MODULE_INFORMATION_CONTEXT;
NTSTATUS WINAPI
GetModuleInformationCallback(IN HANDLE ProcessHandle,
IN PLDR_DATA_TABLE_ENTRY CurrentModule,
IN OUT PVOID CallbackContext)
{
PGET_MODULE_INFORMATION_CONTEXT Context = (PGET_MODULE_INFORMATION_CONTEXT)CallbackContext;
/* found the module we were looking for */
if(CurrentModule->DllBase == Context->hModule)
{
/* we want the module name */
if(Context->Flags.bWantName)
{
PUNICODE_STRING SourceString;
ULONG l;
NTSTATUS Status;
if(Context->Flags.bFullName)
SourceString = &(CurrentModule->FullDllName);
else
SourceString = &(CurrentModule->BaseDllName);
SourceString->Length -= SourceString->Length % sizeof(WCHAR);
/* l is the byte size of the user buffer */
l = Context->nBufSize * sizeof(WCHAR);
/* if the user buffer has room for the string and a null terminator */
if(l >= (SourceString->Length + sizeof(WCHAR)))
{
/* limit the buffer size */
l = SourceString->Length;
/* null-terminate the string */
if(Context->Flags.bUnicode)
Context->lpUnicodeName[l / sizeof(WCHAR)] = 0;
else
Context->lpAnsiName[l / sizeof(WCHAR)] = 0;
}
if(Context->Flags.bUnicode)
{
/* Unicode: direct copy */
/* NOTE: I've chosen not to check for ProcessHandle == NtCurrentProcess(),
this function is complicated enough as it is */
Status = NtReadVirtualMemory(ProcessHandle,
SourceString->Buffer,
Context->lpUnicodeName,
l,
NULL);
if(!NT_SUCCESS(Status))
{
Context->nBufSize = 0;
return Status;
}
Context->nBufSize = l / sizeof(WCHAR);
}
else
{
/* ANSI/OEM: convert and copy */
LPWSTR pwcUnicodeBuf;
ANSI_STRING AnsiString;
UNICODE_STRING UnicodeString;
AnsiString.Length = 0;
AnsiString.MaximumLength = Context->nBufSize;
AnsiString.Buffer = Context->lpAnsiName;
/* allocate the local buffer */
pwcUnicodeBuf = PsaiMalloc(SourceString->Length);
#if 0
__try
{
#endif
if(pwcUnicodeBuf == NULL)
{
Status = STATUS_NO_MEMORY;
goto exitWithStatus;
}
/* copy the string in the local buffer */
Status = NtReadVirtualMemory(ProcessHandle,
SourceString->Buffer,
pwcUnicodeBuf,
l,
NULL);
if(!NT_SUCCESS(Status))
{
goto exitWithStatus;
}
/* initialize Unicode string buffer */
UnicodeString.Length = UnicodeString.MaximumLength = l;
UnicodeString.Buffer = pwcUnicodeBuf;
/* convert and copy */
if(AreFileApisANSI())
RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeString, FALSE);
else
RtlUnicodeStringToOemString(&AnsiString, &UnicodeString, FALSE);
/* return the string size */
Context->nBufSize = AnsiString.Length;
#if 0
}
__finally
{
/* free the buffer */
PsaiFree(pwcUnicodeBuf);
}
#else
Status = STATUS_NO_MORE_FILES;
exitWithStatus:
/* free the buffer */
PsaiFree(pwcUnicodeBuf);
return Status;
#endif
}
}
else
{
/* we want other module information */
ULONG nSize = Context->nBufSize;
/* base address */
if(nSize >= sizeof(CurrentModule->DllBase))
{
Context->lpmodinfo->lpBaseOfDll = CurrentModule->DllBase;
nSize -= sizeof(CurrentModule->DllBase);
}
/* image size */
if(nSize >= sizeof(CurrentModule->SizeOfImage))
{
Context->lpmodinfo->SizeOfImage = CurrentModule->SizeOfImage;
nSize -= sizeof(CurrentModule->SizeOfImage);
}
/* entry point */
if(nSize >= sizeof(CurrentModule->EntryPoint))
{
/* ??? FIXME? is "EntryPoint" just the offset, or the real address? */
Context->lpmodinfo->EntryPoint = (PVOID)CurrentModule->EntryPoint;
}
Context->nBufSize = TRUE;
}
return STATUS_NO_MORE_FILES;
}
return STATUS_SUCCESS;
}
static DWORD
InternalGetModuleInformation(HANDLE hProcess,
HMODULE hModule,
GET_MODULE_INFORMATION_FLAGS Flags,
LPVOID lpBuffer,
DWORD nBufSize)
{
GET_MODULE_INFORMATION_CONTEXT Context;
NTSTATUS Status;
Context.hModule = hModule;
Context.Flags = Flags;
Context.nBufSize = nBufSize;
Context.lpBuffer = lpBuffer;
Status = PsaEnumerateProcessModules(hProcess, GetModuleInformationCallback, &Context);
if(Status == STATUS_NO_MORE_FILES)
{
/* module was found, return string size */
return Context.nBufSize;
}
else if(NT_SUCCESS(Status))
{
/* module was not found */
SetLastError(ERROR_INVALID_HANDLE);
}
else
{
/* an error occurred */
SetLastErrorByStatus(Status);
}
return 0;
}
typedef struct _INTERNAL_ENUM_PAGE_FILES_CONTEXT
{
PENUM_PAGE_FILE_CALLBACKA pCallbackRoutine;
LPVOID lpContext;
} INTERNAL_ENUM_PAGE_FILES_CONTEXT, *PINTERNAL_ENUM_PAGE_FILES_CONTEXT;
static BOOL CALLBACK
InternalAnsiPageFileCallback(LPVOID pContext,
PENUM_PAGE_FILE_INFORMATION pPageFileInfo,
LPCWSTR lpFilename)
{
size_t slen;
LPSTR AnsiFileName;
PINTERNAL_ENUM_PAGE_FILES_CONTEXT Context = (PINTERNAL_ENUM_PAGE_FILES_CONTEXT)pContext;
slen = wcslen(lpFilename);
AnsiFileName = (LPSTR)LocalAlloc(LMEM_FIXED, (slen + 1) * sizeof(CHAR));
if(AnsiFileName != NULL)
{
BOOL Ret;
WideCharToMultiByte(CP_ACP,
0,
lpFilename,
-1, /* only works if the string is NULL-terminated!!! */
AnsiFileName,
(slen + 1) * sizeof(CHAR),
NULL,
NULL);
Ret = Context->pCallbackRoutine(Context->lpContext, pPageFileInfo, AnsiFileName);
LocalFree((HLOCAL)AnsiFileName);
return Ret;
}
return FALSE;
}
/* PUBLIC *********************************************************************/
/*
* @implemented
*/
BOOL
WINAPI
EmptyWorkingSet(HANDLE hProcess)
{
QUOTA_LIMITS QuotaLimits;
NTSTATUS Status;
/* query the working set */
Status = NtQueryInformationProcess(hProcess,
ProcessQuotaLimits,
&QuotaLimits,
sizeof(QuotaLimits),
NULL);
if(!NT_SUCCESS(Status))
{
SetLastErrorByStatus(Status);
return FALSE;
}
/* empty the working set */
QuotaLimits.MinimumWorkingSetSize = -1;
QuotaLimits.MaximumWorkingSetSize = -1;
/* set the working set */
Status = NtSetInformationProcess(hProcess,
ProcessQuotaLimits,
&QuotaLimits,
sizeof(QuotaLimits));
if(!NT_SUCCESS(Status))
{
SetLastErrorByStatus(Status);
return FALSE;
}
return TRUE;
}
/*
* @implemented
*/
BOOL
WINAPI
EnumDeviceDrivers(LPVOID *lpImageBase,
DWORD cb,
LPDWORD lpcbNeeded)
{
ENUM_DEVICE_DRIVERS_CONTEXT Context;
NTSTATUS Status;
cb /= sizeof(PVOID);
Context.lpImageBase = lpImageBase;
Context.nCount = cb;
Context.nTotal = 0;
Status = PsaEnumerateSystemModules(EnumDeviceDriversCallback, &Context);
/* return the count of bytes that would be needed for a complete enumeration */
*lpcbNeeded = Context.nTotal * sizeof(PVOID);
if(!NT_SUCCESS(Status))
{
SetLastErrorByStatus(Status);
return FALSE;
}
return TRUE;
}
/*
* @implemented
*/
BOOL
WINAPI
EnumProcesses(DWORD *lpidProcess,
DWORD cb,
LPDWORD lpcbNeeded)
{
ENUM_PROCESSES_CONTEXT Context;
NTSTATUS Status;
cb /= sizeof(DWORD);
if(cb == 0 || lpidProcess == NULL)
{
*lpcbNeeded = 0;
return TRUE;
}
Context.lpidProcess = lpidProcess;
Context.nCount = cb;
/* enumerate the process ids */
Status = PsaEnumerateProcesses(EnumProcessesCallback, &Context);
*lpcbNeeded = (cb - Context.nCount) * sizeof(DWORD);
if(!NT_SUCCESS(Status) && (Status != STATUS_INFO_LENGTH_MISMATCH))
{
SetLastErrorByStatus(Status);
return FALSE;
}
return TRUE;
}
/*
* @implemented
*/
BOOL
WINAPI
EnumProcessModules(HANDLE hProcess,
HMODULE *lphModule,
DWORD cb,
LPDWORD lpcbNeeded)
{
ENUM_PROCESS_MODULES_CONTEXT Context;
NTSTATUS Status;
cb /= sizeof(HMODULE);
Context.lphModule = lphModule;
Context.nCount = cb;
Context.nTotal = 0;
/* enumerate the process modules */
Status = PsaEnumerateProcessModules(hProcess, EnumProcessModulesCallback, &Context);
*lpcbNeeded = Context.nTotal * sizeof(HMODULE);
if(!NT_SUCCESS(Status))
{
SetLastErrorByStatus(Status);
return FALSE;
}
return TRUE;
}
/*
* @implemented
*/
DWORD
WINAPI
GetDeviceDriverBaseNameA(LPVOID ImageBase,
LPSTR lpBaseName,
DWORD nSize)
{
return InternalGetDeviceDriverName(FALSE, FALSE, ImageBase, lpBaseName, nSize);
}
/*
* @implemented
*/
DWORD
WINAPI
GetDeviceDriverFileNameA(LPVOID ImageBase,
LPSTR lpFilename,
DWORD nSize)
{
return InternalGetDeviceDriverName(FALSE, TRUE, ImageBase, lpFilename, nSize);
}
/*
* @implemented
*/
DWORD
WINAPI
GetDeviceDriverBaseNameW(LPVOID ImageBase,
LPWSTR lpBaseName,
DWORD nSize)
{
return InternalGetDeviceDriverName(TRUE, FALSE, ImageBase, lpBaseName, nSize);
}
/*
* @implemented
*/
DWORD
WINAPI
GetDeviceDriverFileNameW(LPVOID ImageBase,
LPWSTR lpFilename,
DWORD nSize)
{
return InternalGetDeviceDriverName(TRUE, TRUE, ImageBase, lpFilename, nSize);
}
/*
* @implemented
*/
DWORD
WINAPI
GetMappedFileNameA(HANDLE hProcess,
LPVOID lpv,
LPSTR lpFilename,
DWORD nSize)
{
return InternalGetMappedFileName(FALSE, hProcess, lpv, lpFilename, nSize);
}
/*
* @implemented
*/
DWORD
WINAPI
GetMappedFileNameW(HANDLE hProcess,
LPVOID lpv,
LPWSTR lpFilename,
DWORD nSize)
{
return InternalGetMappedFileName(TRUE, hProcess, lpv, lpFilename, nSize);
}
/*
* @implemented
*/
DWORD
WINAPI
GetModuleBaseNameA(HANDLE hProcess,
HMODULE hModule,
LPSTR lpBaseName,
DWORD nSize)
{
GET_MODULE_INFORMATION_FLAGS Flags = {TRUE, FALSE, FALSE};
return InternalGetModuleInformation(hProcess, hModule, Flags, lpBaseName, nSize);
}
/*
* @implemented
*/
DWORD
WINAPI
GetModuleBaseNameW(HANDLE hProcess,
HMODULE hModule,
LPWSTR lpBaseName,
DWORD nSize)
{
GET_MODULE_INFORMATION_FLAGS Flags = {TRUE, TRUE, FALSE};
return InternalGetModuleInformation(hProcess, hModule, Flags, lpBaseName, nSize);
}
/*
* @implemented
*/
DWORD
WINAPI
GetModuleFileNameExA(HANDLE hProcess,
HMODULE hModule,
LPSTR lpFilename,
DWORD nSize)
{
GET_MODULE_INFORMATION_FLAGS Flags = {TRUE, FALSE, TRUE};
return InternalGetModuleInformation(hProcess, hModule, Flags, lpFilename, nSize);
}
/*
* @implemented
*/
DWORD
WINAPI
GetModuleFileNameExW(HANDLE hProcess,
HMODULE hModule,
LPWSTR lpFilename,
DWORD nSize)
{
GET_MODULE_INFORMATION_FLAGS Flags = {TRUE, TRUE, TRUE};
return InternalGetModuleInformation(hProcess, hModule, Flags, lpFilename, nSize);
}
/*
* @implemented
*/
BOOL
WINAPI
GetModuleInformation(HANDLE hProcess,
HMODULE hModule,
LPMODULEINFO lpmodinfo,
DWORD cb)
{
GET_MODULE_INFORMATION_FLAGS Flags = {FALSE, FALSE, FALSE};
if (cb < sizeof(MODULEINFO))
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
return (BOOL)InternalGetModuleInformation(hProcess, hModule, Flags, lpmodinfo, cb);
}
/*
* @implemented
*/
BOOL
WINAPI
InitializeProcessForWsWatch(HANDLE hProcess)
{
NTSTATUS Status;
Status = NtSetInformationProcess(hProcess,
ProcessWorkingSetWatch,
NULL,
0);
if(!NT_SUCCESS(Status))
{
SetLastErrorByStatus(Status);
return FALSE;
}
return TRUE;
}
/*
* @implemented
*/
BOOL
WINAPI
GetWsChanges(HANDLE hProcess,
PPSAPI_WS_WATCH_INFORMATION lpWatchInfo,
DWORD cb)
{
NTSTATUS Status;
Status = NtQueryInformationProcess(hProcess,
ProcessWorkingSetWatch,
(PVOID)lpWatchInfo,
cb,
NULL);
if(!NT_SUCCESS(Status))
{
SetLastErrorByStatus(Status);
return FALSE;
}
return TRUE;
}
/*
* @implemented
*/
DWORD
WINAPI
GetProcessImageFileNameW(HANDLE hProcess,
LPWSTR lpImageFileName,
DWORD nSize)
{
PUNICODE_STRING ImageFileName;
SIZE_T BufferSize;
NTSTATUS Status;
DWORD Ret = 0;
BufferSize = sizeof(UNICODE_STRING) + (nSize * sizeof(WCHAR));
ImageFileName = (PUNICODE_STRING)LocalAlloc(LMEM_FIXED, BufferSize);
if(ImageFileName != NULL)
{
Status = NtQueryInformationProcess(hProcess,
ProcessImageFileName,
ImageFileName,
BufferSize,
NULL);
if(NT_SUCCESS(Status))
{
memcpy(lpImageFileName, ImageFileName->Buffer, ImageFileName->Length);
/* make sure the string is null-terminated! */
lpImageFileName[ImageFileName->Length / sizeof(WCHAR)] = L'\0';
Ret = ImageFileName->Length / sizeof(WCHAR);
}
else if(Status == STATUS_INFO_LENGTH_MISMATCH)
{
/* XP sets this error code for some reason if the buffer is too small */
SetLastError(ERROR_INSUFFICIENT_BUFFER);
}
else
{
SetLastErrorByStatus(Status);
}
LocalFree((HLOCAL)ImageFileName);
}
return Ret;
}
/*
* @implemented
*/
DWORD
WINAPI
GetProcessImageFileNameA(HANDLE hProcess,
LPSTR lpImageFileName,
DWORD nSize)
{
PUNICODE_STRING ImageFileName;
SIZE_T BufferSize;
NTSTATUS Status;
DWORD Ret = 0;
BufferSize = sizeof(UNICODE_STRING) + (nSize * sizeof(WCHAR));
ImageFileName = (PUNICODE_STRING)LocalAlloc(LMEM_FIXED, BufferSize);
if(ImageFileName != NULL)
{
Status = NtQueryInformationProcess(hProcess,
ProcessImageFileName,
ImageFileName,
BufferSize,
NULL);
if(NT_SUCCESS(Status))
{
WideCharToMultiByte(CP_ACP,
0,
ImageFileName->Buffer,
ImageFileName->Length / sizeof(WCHAR),
lpImageFileName,
nSize,
NULL,
NULL);
/* make sure the string is null-terminated! */
lpImageFileName[ImageFileName->Length / sizeof(WCHAR)] = '\0';
Ret = ImageFileName->Length / sizeof(WCHAR);
}
else if(Status == STATUS_INFO_LENGTH_MISMATCH)
{
/* XP sets this error code for some reason if the buffer is too small */
SetLastError(ERROR_INSUFFICIENT_BUFFER);
}
else
{
SetLastErrorByStatus(Status);
}
LocalFree((HLOCAL)ImageFileName);
}
return Ret;
}
/*
* @implemented
*/
BOOL
WINAPI
EnumPageFilesA(PENUM_PAGE_FILE_CALLBACKA pCallbackRoutine,
LPVOID lpContext)
{
INTERNAL_ENUM_PAGE_FILES_CONTEXT Context;
Context.pCallbackRoutine = pCallbackRoutine;
Context.lpContext = lpContext;
return EnumPageFilesW(InternalAnsiPageFileCallback, &Context);
}
/*
* @implemented
*/
BOOL
WINAPI
EnumPageFilesW(PENUM_PAGE_FILE_CALLBACKW pCallbackRoutine,
LPVOID lpContext)
{
NTSTATUS Status;
PVOID Buffer;
ULONG BufferSize = 0;
BOOL Ret = FALSE;
for(;;)
{
BufferSize += 0x1000;
Buffer = LocalAlloc(LMEM_FIXED, BufferSize);
if(Buffer == NULL)
{
return FALSE;
}
Status = NtQuerySystemInformation(SystemPageFileInformation,
Buffer,
BufferSize,
NULL);
if(Status == STATUS_INFO_LENGTH_MISMATCH)
{
LocalFree((HLOCAL)Buffer);
}
else
{
break;
}
}
if(NT_SUCCESS(Status))
{
ENUM_PAGE_FILE_INFORMATION Information;
PSYSTEM_PAGEFILE_INFORMATION pfi = (PSYSTEM_PAGEFILE_INFORMATION)Buffer;
ULONG Offset = 0;
do
{
PWCHAR Colon;
pfi = (PSYSTEM_PAGEFILE_INFORMATION)((ULONG_PTR)pfi + Offset);
Information.cb = sizeof(Information);
Information.Reserved = 0;
Information.TotalSize = pfi->TotalSize;
Information.TotalInUse = pfi->TotalInUse;
Information.PeakUsage = pfi->PeakUsage;
/* strip the \??\ prefix from the file name. We do this by searching for the first
: character and then just change Buffer to point to the previous character. */
Colon = wcschr(pfi->PageFileName.Buffer, L':');
if(Colon != NULL)
{
pfi->PageFileName.Buffer = --Colon;
}
/* FIXME - looks like the PageFileName string is always NULL-terminated on win.
At least I haven't encountered a different case so far, we should
propably manually NULL-terminate the string here... */
if(!pCallbackRoutine(lpContext, &Information, pfi->PageFileName.Buffer))
{
break;
}
Offset = pfi->NextEntryOffset;
} while(Offset != 0);
Ret = TRUE;
}
else
{
SetLastErrorByStatus(Status);
}
LocalFree((HLOCAL)Buffer);
return Ret;
}
/*
* @implemented
*/
BOOL
WINAPI
GetPerformanceInfo(PPERFORMANCE_INFORMATION pPerformanceInformation,
DWORD cb)
{
SYSTEM_PERFORMANCE_INFORMATION spi;
SYSTEM_BASIC_INFORMATION sbi;
SYSTEM_HANDLE_INFORMATION shi;
PSYSTEM_PROCESS_INFORMATION ProcessInfo;
ULONG BufferSize, ProcOffset, ProcessCount, ThreadCount;
PVOID Buffer;
NTSTATUS Status;
Status = NtQuerySystemInformation(SystemPerformanceInformation,
&spi,
sizeof(spi),
NULL);
if(!NT_SUCCESS(Status))
{
SetLastErrorByStatus(Status);
return FALSE;
}
Status = NtQuerySystemInformation(SystemBasicInformation,
&sbi,
sizeof(sbi),
NULL);
if(!NT_SUCCESS(Status))
{
SetLastErrorByStatus(Status);
return FALSE;
}
/*
* allocate enough memory to get a dump of all processes and threads
*/
BufferSize = 0;
for(;;)
{
BufferSize += 0x10000;
Buffer = (PVOID)LocalAlloc(LMEM_FIXED, BufferSize);
if(Buffer == NULL)
{
return FALSE;
}
Status = NtQuerySystemInformation(SystemProcessInformation,
Buffer,
BufferSize,
NULL);
if(Status == STATUS_INFO_LENGTH_MISMATCH)
{
LocalFree((HLOCAL)Buffer);
}
else
{
break;
}
}
if(!NT_SUCCESS(Status))
{
LocalFree((HLOCAL)Buffer);
SetLastErrorByStatus(Status);
return FALSE;
}
/*
* determine the process and thread count
*/
ProcessCount = ThreadCount = ProcOffset = 0;
ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)Buffer;
do
{
ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)((ULONG_PTR)ProcessInfo + ProcOffset);
ProcessCount++;
ThreadCount += ProcessInfo->NumberOfThreads;
ProcOffset = ProcessInfo->NextEntryOffset;
} while(ProcOffset != 0);
LocalFree((HLOCAL)Buffer);
/*
* it's enough to supply a SYSTEM_HANDLE_INFORMATION structure as buffer. Even
* though it returns STATUS_INFO_LENGTH_MISMATCH, it already sets the NumberOfHandles
* field which is all we're looking for anyway.
*/
Status = NtQuerySystemInformation(SystemHandleInformation,
&shi,
sizeof(shi),
NULL);
if(!NT_SUCCESS(Status) && (Status != STATUS_INFO_LENGTH_MISMATCH))
{
SetLastErrorByStatus(Status);
return FALSE;
}
/*
* all required information collected, fill the structure
*/
pPerformanceInformation->cb = sizeof(PERFORMANCE_INFORMATION);
pPerformanceInformation->CommitTotal = spi.CommittedPages;
pPerformanceInformation->CommitLimit = spi.CommitLimit;
pPerformanceInformation->CommitPeak = spi.PeakCommitment;
pPerformanceInformation->PhysicalTotal = sbi.NumberOfPhysicalPages;
pPerformanceInformation->PhysicalAvailable = spi.AvailablePages;
pPerformanceInformation->SystemCache = 0; /* FIXME - where to get this information from? */
pPerformanceInformation->KernelTotal = spi.PagedPoolPages + spi.NonPagedPoolPages;
pPerformanceInformation->KernelPaged = spi.PagedPoolPages;
pPerformanceInformation->KernelNonpaged = spi.NonPagedPoolPages;
pPerformanceInformation->PageSize = sbi.PageSize;
pPerformanceInformation->HandleCount = shi.NumberOfHandles;
pPerformanceInformation->ProcessCount = ProcessCount;
pPerformanceInformation->ThreadCount = ThreadCount;
return TRUE;
}
/*
* @implemented
*/
BOOL
WINAPI
GetProcessMemoryInfo(HANDLE Process,
PPROCESS_MEMORY_COUNTERS ppsmemCounters,
DWORD cb)
{
NTSTATUS Status;
VM_COUNTERS vmc;
BOOL Ret = FALSE;
/* XP's implementation secures access to ppsmemCounters in SEH, we should behave
similar so we can return the proper error codes when bad pointers are passed
to this function! */
_SEH2_TRY
{
if(cb < sizeof(PROCESS_MEMORY_COUNTERS))
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
_SEH2_LEAVE;
}
/* ppsmemCounters->cb isn't checked at all! */
Status = NtQueryInformationProcess(Process,
ProcessVmCounters,
&vmc,
sizeof(vmc),
NULL);
if(!NT_SUCCESS(Status))
{
SetLastErrorByStatus(Status);
_SEH2_LEAVE;
}
/* fill the structure with the collected information, in case of bad pointers
SEH will catch the exception and set the appropriate error code */
ppsmemCounters->cb = sizeof(PROCESS_MEMORY_COUNTERS);
ppsmemCounters->PageFaultCount = vmc.PageFaultCount;
ppsmemCounters->PeakWorkingSetSize = vmc.PeakWorkingSetSize;
ppsmemCounters->WorkingSetSize = vmc.WorkingSetSize;
ppsmemCounters->QuotaPeakPagedPoolUsage = vmc.QuotaPeakPagedPoolUsage;
ppsmemCounters->QuotaPagedPoolUsage = vmc.QuotaPagedPoolUsage;
ppsmemCounters->QuotaPeakNonPagedPoolUsage = vmc.QuotaPeakNonPagedPoolUsage;
ppsmemCounters->QuotaNonPagedPoolUsage = vmc.QuotaNonPagedPoolUsage;
ppsmemCounters->PagefileUsage = vmc.PagefileUsage;
ppsmemCounters->PeakPagefileUsage = vmc.PeakPagefileUsage;
Ret = TRUE;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
SetLastErrorByStatus(_SEH2_GetExceptionCode());
}
_SEH2_END;
return Ret;
}
/*
* @implemented
*/
BOOL
WINAPI
QueryWorkingSet(HANDLE hProcess,
PVOID pv,
DWORD cb)
{
NTSTATUS Status;
Status = NtQueryVirtualMemory(hProcess,
NULL,
MemoryWorkingSetList,
pv,
cb,
NULL);
if(!NT_SUCCESS(Status))
{
SetLastErrorByStatus(Status);
return FALSE;
}
return TRUE;
}
/*
* @unimplemented
*/
BOOL
WINAPI
QueryWorkingSetEx(IN HANDLE hProcess,
IN OUT PVOID pv,
IN DWORD cb)
{
UNIMPLEMENTED;
return FALSE;
}
/* EOF */