/* $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 * Thomas Weidenmueller * UPDATE HISTORY: * 10/06/2002: Created */ #include "precomp.h" #define NDEBUG #include 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 */