From 0a1dce40160c3a298b7bf996d25bcf7635251f0f Mon Sep 17 00:00:00 2001 From: Thomas Bluemel Date: Sun, 31 Oct 2004 00:04:19 +0000 Subject: [PATCH] implemented Heap32ListFirst(), Heap32ListNext(), Module32First(), Module32FirstW(), Module32Next(), Module32NextW(), Process32First(), Process32FirstW(), Process32Next(), Process32NextW(), Thread32First(), Thread32Next(), Toolhelp32ReadProcessMemory() and CreateToolhelp32Snapshot(). Currently only the flags TH32CS_SNAPPROCESS, TH32CS_SNAPTHREAD and TH32CS_INHERIT are supported, snapshots of heaps and modules are not fully implemented yet. svn path=/trunk/; revision=11489 --- reactos/lib/kernel32/misc/toolhelp.c | 1249 +++++++++++++++++++++----- 1 file changed, 1026 insertions(+), 223 deletions(-) diff --git a/reactos/lib/kernel32/misc/toolhelp.c b/reactos/lib/kernel32/misc/toolhelp.c index 73751eac262..47880cde93d 100644 --- a/reactos/lib/kernel32/misc/toolhelp.c +++ b/reactos/lib/kernel32/misc/toolhelp.c @@ -1,4 +1,22 @@ -/* $Id: toolhelp.c,v 1.4 2004/08/28 22:06:02 navaraf Exp $ +/* + * ReactOS kernel + * Copyright (C) 2004 ReactOS Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* $Id: toolhelp.c,v 1.5 2004/10/31 00:04:19 weiden Exp $ * * KERNEL32.DLL toolhelp functions * @@ -6,339 +24,1124 @@ * PROJECT: ReactOS system libraries * FILE: lib/kernel32/misc/toolhelp.c * PURPOSE: Toolhelp functions - * PROGRAMMER: Robert Dickenson (robd@mok.lvcm.com) + * PROGRAMMER: Thomas Weidenmueller + * Robert Dickenson (robd@mok.lvcm.com) + * + * NOTES: Do NOT use the heap functions in here because they + * adulterate the heap statistics! + * * UPDATE HISTORY: - * Created 05 January 2003 + * 10/30/2004 Implemented some parts (w3) + * Inspired by the book "Windows NT Native API" + * Created 05 January 2003 (robd) */ -#include -#include +#include +#define NDEBUG +#include "../include/debug.h" -#define CHECK_PARAM_SIZE(ptr, siz) \ - if (!ptr || ptr->dwSize != siz) { \ - SetLastError(ERROR_INVALID_PARAMETER); \ - return FALSE; \ +/* INTERNAL DEFINITIONS *******************************************************/ + +#define CHECK_PARAM_SIZE(ptr, siz) \ + if((ptr) == NULL || (ptr)->dwSize != (siz)) \ + { \ + SetLastError(ERROR_INVALID_PARAMETER); \ + return FALSE; \ + } + +/* + * Tests in win showed that the dwSize field can be greater than the actual size + * of the structure for the ansi functions. I found this out by accidently + * forgetting to set the dwSize field in a test application and it just didn't + * work in ros but in win. + */ + +#define CHECK_PARAM_SIZEA(ptr, siz) \ + if((ptr) == NULL || (ptr)->dwSize < (siz)) \ + { \ + SetLastError(ERROR_INVALID_PARAMETER); \ + return FALSE; \ + } + +#define OffsetToPtr(Snapshot, Offset) \ + ((ULONG_PTR)((Snapshot) + 1) + (ULONG_PTR)(Offset)) + +typedef struct _TH32SNAPSHOT +{ + /* Heap list */ + ULONG HeapListCount; + ULONG HeapListIndex; + ULONG_PTR HeapListOffset; + /* Module list */ + ULONG ModuleListCount; + ULONG ModuleListIndex; + ULONG_PTR ModuleListOffset; + /* Process list */ + ULONG ProcessListCount; + ULONG ProcessListIndex; + ULONG_PTR ProcessListOffset; + /* Thread list */ + ULONG ThreadListCount; + ULONG ThreadListIndex; + ULONG_PTR ThreadListOffset; +} TH32SNAPSHOT, *PTH32SNAPSHOT; + +/* INTERNAL FUNCTIONS *********************************************************/ + +static VOID +TH32FreeAllocatedResources(PDEBUG_BUFFER HeapDebug, + PDEBUG_BUFFER ModuleDebug, + PVOID ProcThrdInfo, + ULONG ProcThrdInfoSize) +{ + if(HeapDebug != NULL) + { + RtlDestroyQueryDebugBuffer(HeapDebug); + } + if(ModuleDebug != NULL) + { + RtlDestroyQueryDebugBuffer(ModuleDebug); + } + + if(ProcThrdInfo != NULL) + { + NtFreeVirtualMemory(NtCurrentProcess(), + ProcThrdInfo, + &ProcThrdInfoSize, + MEM_RELEASE); + } +} + +static NTSTATUS +TH32CreateSnapshot(DWORD dwFlags, + DWORD th32ProcessID, + PDEBUG_BUFFER *HeapDebug, + PDEBUG_BUFFER *ModuleDebug, + PVOID *ProcThrdInfo, + ULONG *ProcThrdInfoSize) +{ + NTSTATUS Status = STATUS_SUCCESS; + + *HeapDebug = NULL; + *ModuleDebug = NULL; + *ProcThrdInfo = NULL; + *ProcThrdInfoSize = 0; + + /* + * Allocate the debug information for a heap snapshot + */ + if(dwFlags & TH32CS_SNAPHEAPLIST) + { + *HeapDebug = RtlCreateQueryDebugBuffer(0, FALSE); + if(*HeapDebug != NULL) + { + Status = RtlQueryProcessDebugInformation(th32ProcessID, + PDI_HEAPS, + *HeapDebug); + } + else + Status = STATUS_UNSUCCESSFUL; + } + + /* + * Allocate the debug information for a module snapshot + */ + if(dwFlags & TH32CS_SNAPMODULE && + NT_SUCCESS(Status)) + { + *ModuleDebug = RtlCreateQueryDebugBuffer(0, FALSE); + if(*ModuleDebug != NULL) + { + Status = RtlQueryProcessDebugInformation(th32ProcessID, + PDI_MODULES, + *HeapDebug); + } + else + Status = STATUS_UNSUCCESSFUL; + } + + /* + * Allocate enough memory for the system's process list + */ + + if(dwFlags & (TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD) && + NT_SUCCESS(Status)) + { + for(;;) + { + (*ProcThrdInfoSize) += 0x10000; + Status = NtAllocateVirtualMemory(NtCurrentProcess(), + ProcThrdInfo, + 0, + ProcThrdInfoSize, + MEM_COMMIT, + PAGE_READWRITE); + if(!NT_SUCCESS(Status)) + { + break; + } + + Status = NtQuerySystemInformation(SystemProcessInformation, + *ProcThrdInfo, + *ProcThrdInfoSize, + NULL); + if(Status == STATUS_INFO_LENGTH_MISMATCH) + { + NtFreeVirtualMemory(NtCurrentProcess(), + ProcThrdInfo, + ProcThrdInfoSize, + MEM_RELEASE); + *ProcThrdInfo = NULL; + } + else + { + break; + } + } + } + + /* + * Free resources in case of failure! + */ + + if(!NT_SUCCESS(Status)) + { + TH32FreeAllocatedResources(*HeapDebug, + *ModuleDebug, + *ProcThrdInfo, + *ProcThrdInfoSize); + } + + return Status; +} + +static NTSTATUS +TH32CreateSnapshotSectionInitialize(DWORD dwFlags, + DWORD th32ProcessID, + PDEBUG_BUFFER HeapDebug, + PDEBUG_BUFFER ModuleDebug, + PVOID ProcThrdInfo, + HANDLE *SectionHandle) +{ + PSYSTEM_PROCESS_INFORMATION ProcessInfo; + LPHEAPLIST32 HeapListEntry; + LPMODULEENTRY32W ModuleListEntry; + LPPROCESSENTRY32W ProcessListEntry; + LPTHREADENTRY32 ThreadListEntry; + OBJECT_ATTRIBUTES ObjectAttributes; + LARGE_INTEGER SSize, SOffset; + HANDLE hSection; + PTH32SNAPSHOT Snapshot; + ULONG_PTR DataOffset; + ULONG ViewSize, i; + ULONG nProcesses = 0, nThreads = 0, nHeaps = 0, nModules = 0; + ULONG RequiredSnapshotSize = sizeof(TH32SNAPSHOT); + PHEAP_INFORMATION hi = NULL; + PMODULE_INFORMATION mi = NULL; + NTSTATUS Status = STATUS_SUCCESS; + + /* + * Determine the required size for the heap snapshot + */ + if(dwFlags & TH32CS_SNAPHEAPLIST) + { + hi = (PHEAP_INFORMATION)HeapDebug->HeapInformation; + nHeaps = hi->HeapCount; + RequiredSnapshotSize += nHeaps * sizeof(HEAPLIST32); + } + + /* + * Determine the required size for the module snapshot + */ + if(dwFlags & TH32CS_SNAPMODULE) + { + mi = (PMODULE_INFORMATION)ModuleDebug->ModuleInformation; + nModules = mi->ModuleCount; + RequiredSnapshotSize += nModules * sizeof(MODULEENTRY32W); + } + + /* + * Determine the required size for the processes and threads snapshot + */ + if(dwFlags & (TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD)) + { + ULONG ProcOffset = 0; + + ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)ProcThrdInfo; + do + { + ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)((ULONG_PTR)ProcessInfo + ProcOffset); + nProcesses++; + nThreads += ProcessInfo->NumberOfThreads; + ProcOffset = ProcessInfo->NextEntryOffset; + } while(ProcOffset != 0); + + if(dwFlags & TH32CS_SNAPPROCESS) + { + RequiredSnapshotSize += nProcesses * sizeof(PROCESSENTRY32W); + } + if(dwFlags & TH32CS_SNAPTHREAD) + { + RequiredSnapshotSize += nThreads * sizeof(THREADENTRY32); + } + } + + /* + * Create and map the section + */ + + SSize.QuadPart = RequiredSnapshotSize; + + InitializeObjectAttributes(&ObjectAttributes, + NULL, + ((dwFlags & TH32CS_INHERIT) ? OBJ_INHERIT : 0), + NULL, + NULL); + + Status = NtCreateSection(&hSection, + SECTION_ALL_ACCESS, + &ObjectAttributes, + &SSize, + PAGE_READWRITE, + SEC_COMMIT, + NULL); + if(!NT_SUCCESS(Status)) + { + return Status; + } + + SOffset.QuadPart = 0; + ViewSize = 0; + Snapshot = NULL; + + Status = NtMapViewOfSection(hSection, + NtCurrentProcess(), + (PVOID*)&Snapshot, + 0, + 0, + &SOffset, + &ViewSize, + ViewShare, + 0, + PAGE_READWRITE); + if(!NT_SUCCESS(Status)) + { + NtClose(hSection); + return Status; + } + + RtlZeroMemory(Snapshot, sizeof(TH32SNAPSHOT)); + DataOffset = 0; + + /* + * Initialize the section data and fill it with all the data we collected + */ + + /* initialize the heap list */ + if(dwFlags & TH32CS_SNAPHEAPLIST) + { + Snapshot->HeapListCount = nHeaps; + Snapshot->HeapListOffset = DataOffset; + HeapListEntry = (LPHEAPLIST32)OffsetToPtr(Snapshot, DataOffset); + for(i = 0; i < nHeaps; i++) + { + HeapListEntry->dwSize = sizeof(HEAPLIST32); + HeapListEntry->th32ProcessID = th32ProcessID; + HeapListEntry->th32HeapID = 0; /* FIXME - use the base address of the heap we're iterating */ + HeapListEntry->dwFlags = 0; /* FIXME - use the flags of the heap we're iterating */ + + HeapListEntry++; } + DataOffset += hi->HeapCount * sizeof(HEAPLIST32); + } + + /* initialize the module list */ + if(dwFlags & TH32CS_SNAPMODULE) + { + Snapshot->ModuleListCount = nModules; + Snapshot->ModuleListOffset = DataOffset; + ModuleListEntry = (LPMODULEENTRY32W)OffsetToPtr(Snapshot, DataOffset); + for(i = 0; i < nModules; i++) + { + ModuleListEntry->dwSize = sizeof(MODULEENTRY32W); + ModuleListEntry->th32ProcessID = th32ProcessID; + + /* FIXME - fill the MODULEENTRY32W structure */ + + ModuleListEntry++; + } + + DataOffset += mi->ModuleCount * sizeof(MODULEENTRY32W); + } + + /* initialize the process list */ + if(dwFlags & TH32CS_SNAPPROCESS) + { + ULONG ProcOffset = 0; + + Snapshot->ProcessListCount = nProcesses; + Snapshot->ProcessListOffset = DataOffset; + ProcessListEntry = (LPPROCESSENTRY32W)OffsetToPtr(Snapshot, DataOffset); + ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)ProcThrdInfo; + do + { + ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)((ULONG_PTR)ProcessInfo + ProcOffset); + + ProcessListEntry->dwSize = sizeof(PROCESSENTRY32W); + ProcessListEntry->cntUsage = 0; /* no longer used */ + ProcessListEntry->th32ProcessID = (ULONG)ProcessInfo->UniqueProcessId; + ProcessListEntry->th32DefaultHeapID = 0; /* no longer used */ + ProcessListEntry->th32ModuleID = 0; /* no longer used */ + ProcessListEntry->cntThreads = ProcessInfo->NumberOfThreads; + ProcessListEntry->th32ParentProcessID = (ULONG)ProcessInfo->InheritedFromUniqueProcessId; + ProcessListEntry->pcPriClassBase = ProcessInfo->BasePriority; + ProcessListEntry->dwFlags = 0; /* no longer used */ + if(ProcessInfo->ImageName.Buffer != NULL) + { + DbgPrint("proc: %ws\n", ProcessInfo->ImageName.Buffer); + lstrcpynW(ProcessListEntry->szExeFile, + ProcessInfo->ImageName.Buffer, + min(ProcessInfo->ImageName.Length, sizeof(ProcessListEntry->szExeFile) / sizeof(ProcessListEntry->szExeFile[0]))); + } + else + { + lstrcpyW(ProcessListEntry->szExeFile, L"[System Process]"); + } + + ProcessListEntry++; + + ProcOffset = ProcessInfo->NextEntryOffset; + } while(ProcOffset != 0); + + DataOffset += nProcesses * sizeof(PROCESSENTRY32W); + } + + /* initialize the thread list */ + if(dwFlags & TH32CS_SNAPTHREAD) + { + ULONG ProcOffset = 0; + + Snapshot->ThreadListCount = nThreads; + Snapshot->ThreadListOffset = DataOffset; + ThreadListEntry = (LPTHREADENTRY32)OffsetToPtr(Snapshot, DataOffset); + ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)ProcThrdInfo; + do + { + PSYSTEM_THREAD_INFORMATION ThreadInfo; + ULONG n; + + ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)((ULONG_PTR)ProcessInfo + ProcOffset); + ThreadInfo = (PSYSTEM_THREAD_INFORMATION)(ProcessInfo + 1); + + for(n = 0; n < ProcessInfo->NumberOfThreads; n++) + { + ThreadListEntry->dwSize = sizeof(THREADENTRY32); + ThreadListEntry->cntUsage = 0; /* no longer used */ + ThreadListEntry->th32ThreadID = (ULONG)ThreadInfo->ClientId.UniqueThread; + ThreadListEntry->th32OwnerProcessID = (ULONG)ThreadInfo->ClientId.UniqueProcess; + ThreadListEntry->tpBasePri = ThreadInfo->BasePriority; + ThreadListEntry->tpDeltaPri = 0; /* no longer used */ + ThreadListEntry->dwFlags = 0; /* no longer used */ + + ThreadInfo++; + ThreadListEntry++; + } + + ProcOffset = ProcessInfo->NextEntryOffset; + } while(ProcOffset != 0); + } + + /* + * We're done, unmap the view and return the section handle + */ + + Status = NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)Snapshot); + + if(NT_SUCCESS(Status)) + { + *SectionHandle = hSection; + } + else + { + NtClose(hSection); + } + + return Status; +} + +/* PUBLIC FUNCTIONS ***********************************************************/ /* * @unimplemented */ -BOOL WINAPI +BOOL +STDCALL Heap32First(LPHEAPENTRY32 lphe, DWORD th32ProcessID, DWORD th32HeapID) { - CHECK_PARAM_SIZE(lphe, sizeof(HEAPENTRY32)); + CHECK_PARAM_SIZE(lphe, sizeof(HEAPENTRY32)); - SetLastError(ERROR_NO_MORE_FILES); - return FALSE; + SetLastError(ERROR_NO_MORE_FILES); + return FALSE; } /* * @unimplemented */ -BOOL WINAPI +BOOL +STDCALL Heap32Next(LPHEAPENTRY32 lphe) { -/* -typedef struct tagHEAPENTRY32 { - DWORD dwSize; - HANDLE hHandle; - DWORD dwAddress; - DWORD dwBlockSize; - DWORD dwFlags; - DWORD dwLockCount; - DWORD dwResvd; - DWORD th32ProcessID; - DWORD th32HeapID; -} HEAPENTRY32,*PHEAPENTRY32,*LPHEAPENTRY32; - */ - SetLastError(ERROR_NO_MORE_FILES); - return FALSE; + CHECK_PARAM_SIZE(lphe, sizeof(HEAPENTRY32)); + + SetLastError(ERROR_NO_MORE_FILES); + return FALSE; } /* - * @unimplemented + * @implemented */ -BOOL WINAPI +BOOL +STDCALL Heap32ListFirst(HANDLE hSnapshot, LPHEAPLIST32 lphl) { - CHECK_PARAM_SIZE(lphl, sizeof(HEAPLIST32)); + PTH32SNAPSHOT Snapshot; + LARGE_INTEGER SOffset; + ULONG ViewSize; + NTSTATUS Status; - SetLastError(ERROR_NO_MORE_FILES); - return FALSE; + CHECK_PARAM_SIZE(lphl, sizeof(HEAPLIST32)); + + SOffset.QuadPart = 0; + ViewSize = 0; + Snapshot = NULL; + + Status = NtMapViewOfSection(hSnapshot, + NtCurrentProcess(), + (PVOID*)&Snapshot, + 0, + 0, + &SOffset, + &ViewSize, + ViewShare, + 0, + PAGE_READWRITE); + if(NT_SUCCESS(Status)) + { + BOOL Ret; + + if(Snapshot->ModuleListCount > 0) + { + LPHEAPLIST32 Entries = (LPHEAPLIST32)OffsetToPtr(Snapshot, Snapshot->HeapListOffset); + Snapshot->HeapListIndex = 1; + RtlCopyMemory(lphl, &Entries[0], sizeof(HEAPLIST32)); + Ret = TRUE; + } + else + { + SetLastError(ERROR_NO_MORE_FILES); + Ret = FALSE; + } + + NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)Snapshot); + return Ret; + } + + SetLastErrorByStatus(Status); + return FALSE; } /* - * @unimplemented + * @implemented */ -BOOL WINAPI -Heap32ListNext(HANDLE hSnapshot, LPHEAPLIST32 lph1) +BOOL +STDCALL +Heap32ListNext(HANDLE hSnapshot, LPHEAPLIST32 lphl) { -/* -typedef struct tagHEAPLIST32 { - DWORD dwSize; - DWORD th32ProcessID; - DWORD th32HeapID; - DWORD dwFlags; -} HEAPLIST32,*PHEAPLIST32,*LPHEAPLIST32; - */ - SetLastError(ERROR_NO_MORE_FILES); - return FALSE; + PTH32SNAPSHOT Snapshot; + LARGE_INTEGER SOffset; + ULONG ViewSize; + NTSTATUS Status; + + CHECK_PARAM_SIZE(lphl, sizeof(HEAPLIST32)); + + SOffset.QuadPart = 0; + ViewSize = 0; + Snapshot = NULL; + + Status = NtMapViewOfSection(hSnapshot, + NtCurrentProcess(), + (PVOID*)&Snapshot, + 0, + 0, + &SOffset, + &ViewSize, + ViewShare, + 0, + PAGE_READWRITE); + if(NT_SUCCESS(Status)) + { + BOOL Ret; + + if(Snapshot->HeapListCount > 0 && + Snapshot->HeapListIndex < Snapshot->HeapListCount) + { + LPHEAPLIST32 Entries = (LPHEAPLIST32)OffsetToPtr(Snapshot, Snapshot->HeapListOffset); + RtlCopyMemory(lphl, &Entries[Snapshot->HeapListIndex++], sizeof(HEAPLIST32)); + Ret = TRUE; + } + else + { + SetLastError(ERROR_NO_MORE_FILES); + Ret = FALSE; + } + + NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)Snapshot); + return Ret; + } + + SetLastErrorByStatus(Status); + return FALSE; } /* - * @unimplemented + * @implemented */ -BOOL WINAPI +BOOL +STDCALL Module32First(HANDLE hSnapshot, LPMODULEENTRY32 lpme) { - CHECK_PARAM_SIZE(lpme, sizeof(MODULEENTRY32)); + MODULEENTRY32W me; + BOOL Ret; - SetLastError(ERROR_NO_MORE_FILES); - return FALSE; + CHECK_PARAM_SIZEA(lpme, sizeof(MODULEENTRY32)); + + me.dwSize = sizeof(MODULEENTRY32W); + + Ret = Module32FirstW(hSnapshot, &me); + if(Ret) + { + lpme->th32ModuleID = me.th32ModuleID; + lpme->th32ProcessID = me.th32ProcessID; + lpme->GlblcntUsage = me.GlblcntUsage; + lpme->ProccntUsage = me.ProccntUsage; + lpme->modBaseAddr = me.modBaseAddr; + lpme->modBaseSize = me.modBaseSize; + lpme->hModule = me.hModule; + + WideCharToMultiByte(CP_ACP, 0, me.szModule, -1, lpme->szModule, sizeof(lpme->szModule), 0, 0); + WideCharToMultiByte(CP_ACP, 0, me.szExePath, -1, lpme->szExePath, sizeof(lpme->szExePath), 0, 0); + } + + return Ret; } /* - * @unimplemented + * @implemented */ -BOOL WINAPI +BOOL +STDCALL Module32FirstW(HANDLE hSnapshot, LPMODULEENTRY32W lpme) { - CHECK_PARAM_SIZE(lpme, sizeof(MODULEENTRY32W)); + PTH32SNAPSHOT Snapshot; + LARGE_INTEGER SOffset; + ULONG ViewSize; + NTSTATUS Status; - SetLastError(ERROR_NO_MORE_FILES); - return FALSE; + CHECK_PARAM_SIZE(lpme, sizeof(MODULEENTRY32W)); + + SOffset.QuadPart = 0; + ViewSize = 0; + Snapshot = NULL; + + Status = NtMapViewOfSection(hSnapshot, + NtCurrentProcess(), + (PVOID*)&Snapshot, + 0, + 0, + &SOffset, + &ViewSize, + ViewShare, + 0, + PAGE_READWRITE); + if(NT_SUCCESS(Status)) + { + BOOL Ret; + + if(Snapshot->ModuleListCount > 0) + { + LPMODULEENTRY32W Entries = (LPMODULEENTRY32W)OffsetToPtr(Snapshot, Snapshot->ModuleListOffset); + Snapshot->ModuleListIndex = 1; + RtlCopyMemory(lpme, &Entries[0], sizeof(MODULEENTRY32W)); + Ret = TRUE; + } + else + { + SetLastError(ERROR_NO_MORE_FILES); + Ret = FALSE; + } + + NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)Snapshot); + return Ret; + } + + SetLastErrorByStatus(Status); + return FALSE; } /* - * @unimplemented + * @implemented */ -BOOL WINAPI +BOOL +STDCALL Module32Next(HANDLE hSnapshot, LPMODULEENTRY32 lpme) { -/* -typedef struct tagMODULEENTRY32 { - DWORD dwSize; - DWORD th32ModuleID; - DWORD th32ProcessID; - DWORD GlblcntUsage; - DWORD ProccntUsage; - BYTE *modBaseAddr; - DWORD modBaseSize; - HMODULE hModule; - char szModule[MAX_MODULE_NAME32 + 1]; - char szExePath[MAX_PATH]; -} MODULEENTRY32,*PMODULEENTRY32,*LPMODULEENTRY32; - */ - SetLastError(ERROR_NO_MORE_FILES); - return FALSE; + MODULEENTRY32W me; + BOOL Ret; + + CHECK_PARAM_SIZEA(lpme, sizeof(MODULEENTRY32)); + + me.dwSize = sizeof(MODULEENTRY32W); + + Ret = Module32NextW(hSnapshot, &me); + if(Ret) + { + lpme->th32ModuleID = me.th32ModuleID; + lpme->th32ProcessID = me.th32ProcessID; + lpme->GlblcntUsage = me.GlblcntUsage; + lpme->ProccntUsage = me.ProccntUsage; + lpme->modBaseAddr = me.modBaseAddr; + lpme->modBaseSize = me.modBaseSize; + lpme->hModule = me.hModule; + + WideCharToMultiByte(CP_ACP, 0, me.szModule, -1, lpme->szModule, sizeof(lpme->szModule), 0, 0); + WideCharToMultiByte(CP_ACP, 0, me.szExePath, -1, lpme->szExePath, sizeof(lpme->szExePath), 0, 0); + } + + return Ret; } -BOOL WINAPI + +BOOL +STDCALL Module32NextW(HANDLE hSnapshot, LPMODULEENTRY32W lpme) { -/* -typedef struct tagMODULEENTRY32W { - DWORD dwSize; - DWORD th32ModuleID; - DWORD th32ProcessID; - DWORD GlblcntUsage; - DWORD ProccntUsage; - BYTE *modBaseAddr; - DWORD modBaseSize; - HMODULE hModule; - WCHAR szModule[MAX_MODULE_NAME32 + 1]; - WCHAR szExePath[MAX_PATH]; -} MODULEENTRY32W,*PMODULEENTRY32W,*LPMODULEENTRY32W; + PTH32SNAPSHOT Snapshot; + LARGE_INTEGER SOffset; + ULONG ViewSize; + NTSTATUS Status; - */ - SetLastError(ERROR_NO_MORE_FILES); - return FALSE; + CHECK_PARAM_SIZE(lpme, sizeof(MODULEENTRY32W)); + + SOffset.QuadPart = 0; + ViewSize = 0; + Snapshot = NULL; + + Status = NtMapViewOfSection(hSnapshot, + NtCurrentProcess(), + (PVOID*)&Snapshot, + 0, + 0, + &SOffset, + &ViewSize, + ViewShare, + 0, + PAGE_READWRITE); + if(NT_SUCCESS(Status)) + { + BOOL Ret; + + if(Snapshot->ModuleListCount > 0 && + Snapshot->ModuleListIndex < Snapshot->ModuleListCount) + { + LPMODULEENTRY32W Entries = (LPMODULEENTRY32W)OffsetToPtr(Snapshot, Snapshot->ModuleListOffset); + RtlCopyMemory(lpme, &Entries[Snapshot->ProcessListIndex++], sizeof(MODULEENTRY32W)); + Ret = TRUE; + } + else + { + SetLastError(ERROR_NO_MORE_FILES); + Ret = FALSE; + } + + NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)Snapshot); + return Ret; + } + + SetLastErrorByStatus(Status); + return FALSE; } /* - * @unimplemented + * @implemented */ -BOOL STDCALL +BOOL +STDCALL Process32First(HANDLE hSnapshot, LPPROCESSENTRY32 lppe) { - CHECK_PARAM_SIZE(lppe, sizeof(PROCESSENTRY32)); + PROCESSENTRY32W pe; + BOOL Ret; - SetLastError(ERROR_NO_MORE_FILES); - return FALSE; + CHECK_PARAM_SIZEA(lppe, sizeof(PROCESSENTRY32)); + + pe.dwSize = sizeof(PROCESSENTRY32W); + + Ret = Process32FirstW(hSnapshot, &pe); + if(Ret) + { + lppe->cntUsage = pe.cntUsage; + lppe->th32ProcessID = pe.th32ProcessID; + lppe->th32DefaultHeapID = pe.th32DefaultHeapID; + lppe->th32ModuleID = pe.th32ModuleID; + lppe->cntThreads = pe.cntThreads; + lppe->th32ParentProcessID = pe.th32ParentProcessID; + lppe->pcPriClassBase = pe.pcPriClassBase; + lppe->dwFlags = pe.dwFlags; + + WideCharToMultiByte(CP_ACP, 0, pe.szExeFile, -1, lppe->szExeFile, sizeof(lppe->szExeFile), 0, 0); + } + + return Ret; } /* - * @unimplemented + * @implemented */ -BOOL STDCALL -Process32Next(HANDLE hSnapshot, LPPROCESSENTRY32 lppe) -{ -/* -typedef struct tagPROCESSENTRY32 { - DWORD dwSize; - DWORD cntUsage; - DWORD th32ProcessID; - DWORD th32DefaultHeapID; - DWORD th32ModuleID; - DWORD cntThreads; - DWORD th32ParentProcessID; - LONG pcPriClassBase; - DWORD dwFlags; - CHAR szExeFile[MAX_PATH]; -} PROCESSENTRY32,*PPROCESSENTRY32,*LPPROCESSENTRY32; - */ - SetLastError(ERROR_NO_MORE_FILES); - return FALSE; -} - - -/* - * @unimplemented - */ -BOOL STDCALL +BOOL +STDCALL Process32FirstW(HANDLE hSnapshot, LPPROCESSENTRY32W lppe) { - CHECK_PARAM_SIZE(lppe, sizeof(PROCESSENTRY32W)); + PTH32SNAPSHOT Snapshot; + LARGE_INTEGER SOffset; + ULONG ViewSize; + NTSTATUS Status; - SetLastError(ERROR_NO_MORE_FILES); - return FALSE; + CHECK_PARAM_SIZE(lppe, sizeof(PROCESSENTRY32W)); + + SOffset.QuadPart = 0; + ViewSize = 0; + Snapshot = NULL; + + Status = NtMapViewOfSection(hSnapshot, + NtCurrentProcess(), + (PVOID*)&Snapshot, + 0, + 0, + &SOffset, + &ViewSize, + ViewShare, + 0, + PAGE_READWRITE); + if(NT_SUCCESS(Status)) + { + BOOL Ret; + + if(Snapshot->ProcessListCount > 0) + { + LPPROCESSENTRY32W Entries = (LPPROCESSENTRY32W)OffsetToPtr(Snapshot, Snapshot->ProcessListOffset); + + Snapshot->ProcessListIndex = 1; + RtlCopyMemory(lppe, &Entries[0], sizeof(PROCESSENTRY32W)); + Ret = TRUE; + } + else + { + + SetLastError(ERROR_NO_MORE_FILES); + Ret = FALSE; + } + + NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)Snapshot); + return Ret; + } + + SetLastErrorByStatus(Status); + return FALSE; } /* - * @unimplemented + * @implemented */ -BOOL STDCALL +BOOL +STDCALL +Process32Next(HANDLE hSnapshot, LPPROCESSENTRY32 lppe) +{ + PROCESSENTRY32W pe; + BOOL Ret; + + CHECK_PARAM_SIZEA(lppe, sizeof(PROCESSENTRY32)); + + pe.dwSize = sizeof(PROCESSENTRY32W); + + Ret = Process32NextW(hSnapshot, &pe); + if(Ret) + { + lppe->cntUsage = pe.cntUsage; + lppe->th32ProcessID = pe.th32ProcessID; + lppe->th32DefaultHeapID = pe.th32DefaultHeapID; + lppe->th32ModuleID = pe.th32ModuleID; + lppe->cntThreads = pe.cntThreads; + lppe->th32ParentProcessID = pe.th32ParentProcessID; + lppe->pcPriClassBase = pe.pcPriClassBase; + lppe->dwFlags = pe.dwFlags; + + WideCharToMultiByte(CP_ACP, 0, pe.szExeFile, -1, lppe->szExeFile, sizeof(lppe->szExeFile), 0, 0); + } + + return Ret; +} + + +/* + * @implemented + */ +BOOL +STDCALL Process32NextW(HANDLE hSnapshot, LPPROCESSENTRY32W lppe) { -/* -typedef struct tagPROCESSENTRY32W { - DWORD dwSize; - DWORD cntUsage; - DWORD th32ProcessID; - DWORD th32DefaultHeapID; - DWORD th32ModuleID; - DWORD cntThreads; - DWORD th32ParentProcessID; - LONG pcPriClassBase; - DWORD dwFlags; - WCHAR szExeFile[MAX_PATH]; -} PROCESSENTRY32W,*PPROCESSENTRY32W,*LPPROCESSENTRY32W; - */ - SetLastError(ERROR_NO_MORE_FILES); - return FALSE; + PTH32SNAPSHOT Snapshot; + LARGE_INTEGER SOffset; + ULONG ViewSize; + NTSTATUS Status; + + CHECK_PARAM_SIZE(lppe, sizeof(PROCESSENTRY32W)); + + SOffset.QuadPart = 0; + ViewSize = 0; + Snapshot = NULL; + + Status = NtMapViewOfSection(hSnapshot, + NtCurrentProcess(), + (PVOID*)&Snapshot, + 0, + 0, + &SOffset, + &ViewSize, + ViewShare, + 0, + PAGE_READWRITE); + if(NT_SUCCESS(Status)) + { + BOOL Ret; + + if(Snapshot->ProcessListCount > 0 && + Snapshot->ProcessListIndex < Snapshot->ProcessListCount) + { + LPPROCESSENTRY32W Entries = (LPPROCESSENTRY32W)OffsetToPtr(Snapshot, Snapshot->ProcessListOffset); + RtlCopyMemory(lppe, &Entries[Snapshot->ProcessListIndex++], sizeof(PROCESSENTRY32W)); + Ret = TRUE; + } + else + { + SetLastError(ERROR_NO_MORE_FILES); + Ret = FALSE; + } + + NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)Snapshot); + return Ret; + } + + SetLastErrorByStatus(Status); + return FALSE; } -BOOL WINAPI Thread32First(HANDLE hSnapshot, LPTHREADENTRY32 lpte) +/* + * @implemented + */ +BOOL +STDCALL +Thread32First(HANDLE hSnapshot, LPTHREADENTRY32 lpte) { - CHECK_PARAM_SIZE(lpte, sizeof(THREADENTRY32)); + PTH32SNAPSHOT Snapshot; + LARGE_INTEGER SOffset; + ULONG ViewSize; + NTSTATUS Status; - SetLastError(ERROR_NO_MORE_FILES); - return FALSE; + CHECK_PARAM_SIZE(lpte, sizeof(THREADENTRY32)); + + SOffset.QuadPart = 0; + ViewSize = 0; + Snapshot = NULL; + + Status = NtMapViewOfSection(hSnapshot, + NtCurrentProcess(), + (PVOID*)&Snapshot, + 0, + 0, + &SOffset, + &ViewSize, + ViewShare, + 0, + PAGE_READWRITE); + if(NT_SUCCESS(Status)) + { + BOOL Ret; + + if(Snapshot->ThreadListCount > 0) + { + LPTHREADENTRY32 Entries = (LPTHREADENTRY32)OffsetToPtr(Snapshot, Snapshot->ThreadListOffset); + Snapshot->ThreadListIndex = 1; + RtlCopyMemory(lpte, &Entries[0], sizeof(THREADENTRY32)); + Ret = TRUE; + } + else + { + SetLastError(ERROR_NO_MORE_FILES); + Ret = FALSE; + } + + NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)Snapshot); + return Ret; + } + + SetLastErrorByStatus(Status); + return FALSE; } /* - * @unimplemented + * @implemented */ -BOOL WINAPI Thread32Next(HANDLE hSnapshot, LPTHREADENTRY32 lpte) +BOOL +STDCALL +Thread32Next(HANDLE hSnapshot, LPTHREADENTRY32 lpte) { -/* -typedef struct tagTHREADENTRY32 { - DWORD dwSize; - DWORD cntUsage; - DWORD th32ThreadID; - DWORD th32OwnerProcessID; - LONG tpBasePri; - LONG tpDeltaPri; - DWORD dwFlags; -} THREADENTRY32,*PTHREADENTRY32,*LPTHREADENTRY32; - */ - SetLastError(ERROR_NO_MORE_FILES); - return FALSE; + PTH32SNAPSHOT Snapshot; + LARGE_INTEGER SOffset; + ULONG ViewSize; + NTSTATUS Status; + + CHECK_PARAM_SIZE(lpte, sizeof(THREADENTRY32)); + + SOffset.QuadPart = 0; + ViewSize = 0; + Snapshot = NULL; + + Status = NtMapViewOfSection(hSnapshot, + NtCurrentProcess(), + (PVOID*)&Snapshot, + 0, + 0, + &SOffset, + &ViewSize, + ViewShare, + 0, + PAGE_READWRITE); + if(NT_SUCCESS(Status)) + { + BOOL Ret; + + if(Snapshot->ThreadListCount > 0 && + Snapshot->ThreadListIndex < Snapshot->ThreadListCount) + { + LPTHREADENTRY32 Entries = (LPTHREADENTRY32)OffsetToPtr(Snapshot, Snapshot->ThreadListOffset); + RtlCopyMemory(lpte, &Entries[Snapshot->ThreadListIndex++], sizeof(THREADENTRY32)); + Ret = TRUE; + } + else + { + SetLastError(ERROR_NO_MORE_FILES); + Ret = FALSE; + } + + NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)Snapshot); + return Ret; + } + + SetLastErrorByStatus(Status); + return FALSE; } /* - * @unimplemented + * @implemented */ -BOOL WINAPI -Toolhelp32ReadProcessMemory(DWORD th32ProcessID, - LPCVOID lpBaseAddress, LPVOID lpBuffer, - DWORD cbRead, LPDWORD lpNumberOfBytesRead) +BOOL +STDCALL +Toolhelp32ReadProcessMemory(DWORD th32ProcessID, LPCVOID lpBaseAddress, + LPVOID lpBuffer, DWORD cbRead, LPDWORD lpNumberOfBytesRead) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; + HANDLE hProcess = OpenProcess(PROCESS_VM_READ, FALSE, th32ProcessID); + if(hProcess != NULL) + { + BOOL Ret = ReadProcessMemory(hProcess, lpBaseAddress, lpBuffer, cbRead, lpNumberOfBytesRead); + CloseHandle(hProcess); + return Ret; + } + + return FALSE; } /* - * @unimplemented + * @implemented */ -HANDLE STDCALL +HANDLE +STDCALL CreateToolhelp32Snapshot(DWORD dwFlags, DWORD th32ProcessID) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return INVALID_HANDLE_VALUE; + PDEBUG_BUFFER HeapDebug, ModuleDebug; + PVOID ProcThrdInfo; + ULONG ProcThrdInfoSize; + HANDLE hSnapShotSection; + NTSTATUS Status; + + if(th32ProcessID == 0) + { + th32ProcessID = GetCurrentProcessId(); + } + + /* + * Get all information required for the snapshot + */ + Status = TH32CreateSnapshot(dwFlags, + th32ProcessID, + &HeapDebug, + &ModuleDebug, + &ProcThrdInfo, + &ProcThrdInfoSize); + if(!NT_SUCCESS(Status)) + { + SetLastErrorByStatus(Status); + return NULL; + } + + /* + * Create a section handle and initialize the collected information + */ + Status = TH32CreateSnapshotSectionInitialize(dwFlags, + th32ProcessID, + HeapDebug, + ModuleDebug, + ProcThrdInfo, + &hSnapShotSection); + + /* + * Free the temporarily allocated memory to collect all information + */ + TH32FreeAllocatedResources(HeapDebug, + ModuleDebug, + ProcThrdInfo, + ProcThrdInfoSize); + + if(!NT_SUCCESS(Status)) + { + SetLastErrorByStatus(Status); + return NULL; + } + + return hSnapShotSection; } - -#if 0 /* extracted from mingw tlhelp32.h for easy reference while working above */ -/* -#define HF32_DEFAULT 1 -#define HF32_SHARED 2 -#define LF32_FIXED 0x1 -#define LF32_FREE 0x2 -#define LF32_MOVEABLE 0x4 -#define MAX_MODULE_NAME32 255 -#define TH32CS_SNAPHEAPLIST 0x1 -#define TH32CS_SNAPPROCESS 0x2 -#define TH32CS_SNAPTHREAD 0x4 -#define TH32CS_SNAPMODULE 0x8 -#define TH32CS_SNAPALL (TH32CS_SNAPHEAPLIST|TH32CS_SNAPPROCESS|TH32CS_SNAPTHREAD|TH32CS_SNAPMODULE) -#define TH32CS_INHERIT 0x80000000 - -BOOL WINAPI Heap32First(LPHEAPENTRY32,DWORD,DWORD); -BOOL WINAPI Heap32ListFirst(HANDLE,LPHEAPLIST32); -BOOL WINAPI Heap32ListNext(HANDLE,LPHEAPLIST32); -BOOL WINAPI Heap32Next(LPHEAPENTRY32); -BOOL WINAPI Module32First(HANDLE,LPMODULEENTRY32); -BOOL WINAPI Module32FirstW(HANDLE,LPMODULEENTRY32W); -BOOL WINAPI Module32Next(HANDLE,LPMODULEENTRY32); -BOOL WINAPI Module32NextW(HANDLE,LPMODULEENTRY32W); -BOOL WINAPI Process32First(HANDLE,LPPROCESSENTRY32); -BOOL WINAPI Process32FirstW(HANDLE,LPPROCESSENTRY32W); -BOOL WINAPI Process32Next(HANDLE,LPPROCESSENTRY32); -BOOL WINAPI Process32NextW(HANDLE,LPPROCESSENTRY32W); -BOOL WINAPI Thread32First(HANDLE,LPTHREADENTRY32); -BOOL WINAPI Thread32Next(HANDLE,LPTHREADENTRY32); -BOOL WINAPI Toolhelp32ReadProcessMemory(DWORD,LPCVOID,LPVOID,DWORD,LPDWORD); -HANDLE WINAPI CreateToolhelp32Snapshot(DWORD,DWORD); - -#ifdef UNICODE -#define LPMODULEENTRY32 LPMODULEENTRY32W -#define LPPROCESSENTRY32 LPPROCESSENTRY32W -#define MODULEENTRY32 MODULEENTRY32W -#define Module32First Module32FirstW -#define Module32Next Module32NextW -#define PMODULEENTRY32 PMODULEENTRY32W -#define PPROCESSENTRY32 PPROCESSENTRY32W -#define PROCESSENTRY32 PROCESSENTRY32W -#define Process32First Process32FirstW -#define Process32Next Process32NextW -#endif // UNICODE - */ -#endif /* 0 */ - /* EOF */