[KERNEL32]
[reactos.git] / reactos / dll / win32 / kernel32 / client / toolhelp.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: dll/win32/kernel32/misc/toolhelp.c
6 * PURPOSE: Toolhelp functions
7 * PROGRAMMER: Thomas Weidenmueller <w3seek@reactos.com>
8 * Robert Dickenson (robd@mok.lvcm.com)
9 *
10 * NOTES: Do NOT use the heap functions in here because they
11 * adulterate the heap statistics!
12 *
13 * UPDATE HISTORY:
14 * 10/30/2004 Implemented some parts (w3)
15 * Inspired by the book "Windows NT Native API"
16 * Created 05 January 2003 (robd)
17 */
18
19 #include <k32.h>
20
21 #include <tlhelp32.h>
22
23 #define NDEBUG
24 #include <debug.h>
25
26 /* INTERNAL DEFINITIONS *******************************************************/
27
28 typedef struct _RTLP_HEAP_ENTRY
29 {
30 ULONG Size;
31 USHORT Flags;
32 USHORT Unknown1; /* FIXME */
33 ULONG Unknown2; /* FIXME */
34 PVOID Address;
35 } RTLP_HEAP_ENTRY, *PRTLP_HEAP_ENTRY;
36
37 #define CHECK_PARAM_SIZE(ptr, siz) \
38 if((ptr) == NULL || (ptr)->dwSize != (siz)) \
39 { \
40 SetLastError(ERROR_INVALID_PARAMETER); \
41 return FALSE; \
42 }
43
44 /*
45 * Tests in win showed that the dwSize field can be greater than the actual size
46 * of the structure for the ansi functions. I found this out by accidently
47 * forgetting to set the dwSize field in a test application and it just didn't
48 * work in ros but in win.
49 */
50
51 #define CHECK_PARAM_SIZEA(ptr, siz) \
52 if((ptr) == NULL || (ptr)->dwSize < (siz)) \
53 { \
54 SetLastError(ERROR_INVALID_PARAMETER); \
55 return FALSE; \
56 }
57
58 #define OffsetToPtr(Snapshot, Offset) \
59 ((ULONG_PTR)((Snapshot) + 1) + (ULONG_PTR)(Offset))
60
61 typedef struct _TH32SNAPSHOT
62 {
63 /* Heap list */
64 ULONG HeapListCount;
65 ULONG HeapListIndex;
66 ULONG_PTR HeapListOffset;
67 /* Module list */
68 ULONG ModuleListCount;
69 ULONG ModuleListIndex;
70 ULONG_PTR ModuleListOffset;
71 /* Process list */
72 ULONG ProcessListCount;
73 ULONG ProcessListIndex;
74 ULONG_PTR ProcessListOffset;
75 /* Thread list */
76 ULONG ThreadListCount;
77 ULONG ThreadListIndex;
78 ULONG_PTR ThreadListOffset;
79 } TH32SNAPSHOT, *PTH32SNAPSHOT;
80
81 /* INTERNAL FUNCTIONS *********************************************************/
82
83 static VOID
84 TH32FreeAllocatedResources(PRTL_DEBUG_INFORMATION HeapDebug,
85 PRTL_DEBUG_INFORMATION ModuleDebug,
86 PVOID ProcThrdInfo,
87 SIZE_T ProcThrdInfoSize)
88 {
89 if(HeapDebug != NULL)
90 {
91 RtlDestroyQueryDebugBuffer(HeapDebug);
92 }
93 if(ModuleDebug != NULL)
94 {
95 RtlDestroyQueryDebugBuffer(ModuleDebug);
96 }
97
98 if(ProcThrdInfo != NULL)
99 {
100 NtFreeVirtualMemory(NtCurrentProcess(),
101 &ProcThrdInfo,
102 &ProcThrdInfoSize,
103 MEM_RELEASE);
104 }
105 }
106
107 static NTSTATUS
108 TH32CreateSnapshot(DWORD dwFlags,
109 DWORD th32ProcessID,
110 PRTL_DEBUG_INFORMATION *HeapDebug,
111 PRTL_DEBUG_INFORMATION *ModuleDebug,
112 PVOID *ProcThrdInfo,
113 SIZE_T *ProcThrdInfoSize)
114 {
115 NTSTATUS Status = STATUS_SUCCESS;
116
117 *HeapDebug = NULL;
118 *ModuleDebug = NULL;
119 *ProcThrdInfo = NULL;
120 *ProcThrdInfoSize = 0;
121
122 /*
123 * Allocate the debug information for a heap snapshot
124 */
125 if(dwFlags & TH32CS_SNAPHEAPLIST)
126 {
127 *HeapDebug = RtlCreateQueryDebugBuffer(0, FALSE);
128 if(*HeapDebug != NULL)
129 {
130 Status = RtlQueryProcessDebugInformation(th32ProcessID,
131 RTL_DEBUG_QUERY_HEAPS,
132 *HeapDebug);
133 }
134 else
135 Status = STATUS_UNSUCCESSFUL;
136 }
137
138 /*
139 * Allocate the debug information for a module snapshot
140 */
141 if(dwFlags & TH32CS_SNAPMODULE &&
142 NT_SUCCESS(Status))
143 {
144 *ModuleDebug = RtlCreateQueryDebugBuffer(0, FALSE);
145 if(*ModuleDebug != NULL)
146 {
147 Status = RtlQueryProcessDebugInformation(th32ProcessID,
148 RTL_DEBUG_QUERY_MODULES,
149 *ModuleDebug);
150 }
151 else
152 Status = STATUS_UNSUCCESSFUL;
153 }
154
155 /*
156 * Allocate enough memory for the system's process list
157 */
158
159 if(dwFlags & (TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD) &&
160 NT_SUCCESS(Status))
161 {
162 for(;;)
163 {
164 (*ProcThrdInfoSize) += 0x10000;
165 Status = NtAllocateVirtualMemory(NtCurrentProcess(),
166 ProcThrdInfo,
167 0,
168 ProcThrdInfoSize,
169 MEM_COMMIT,
170 PAGE_READWRITE);
171 if(!NT_SUCCESS(Status))
172 {
173 break;
174 }
175
176 Status = NtQuerySystemInformation(SystemProcessInformation,
177 *ProcThrdInfo,
178 *ProcThrdInfoSize,
179 NULL);
180 if(Status == STATUS_INFO_LENGTH_MISMATCH)
181 {
182 NtFreeVirtualMemory(NtCurrentProcess(),
183 ProcThrdInfo,
184 ProcThrdInfoSize,
185 MEM_RELEASE);
186 *ProcThrdInfo = NULL;
187 }
188 else
189 {
190 break;
191 }
192 }
193 }
194
195 /*
196 * Free resources in case of failure!
197 */
198
199 if(!NT_SUCCESS(Status))
200 {
201 TH32FreeAllocatedResources(*HeapDebug,
202 *ModuleDebug,
203 *ProcThrdInfo,
204 *ProcThrdInfoSize);
205 }
206
207 return Status;
208 }
209
210 static NTSTATUS
211 TH32CreateSnapshotSectionInitialize(DWORD dwFlags,
212 DWORD th32ProcessID,
213 PRTL_DEBUG_INFORMATION HeapDebug,
214 PRTL_DEBUG_INFORMATION ModuleDebug,
215 PVOID ProcThrdInfo,
216 HANDLE *SectionHandle)
217 {
218 PSYSTEM_PROCESS_INFORMATION ProcessInfo;
219 LPHEAPLIST32 HeapListEntry;
220 LPMODULEENTRY32W ModuleListEntry;
221 LPPROCESSENTRY32W ProcessListEntry;
222 LPTHREADENTRY32 ThreadListEntry;
223 OBJECT_ATTRIBUTES ObjectAttributes;
224 LARGE_INTEGER SSize, SOffset;
225 HANDLE hSection;
226 PTH32SNAPSHOT Snapshot;
227 ULONG_PTR DataOffset;
228 SIZE_T ViewSize;
229 ULONG i, nProcesses = 0, nThreads = 0, nHeaps = 0, nModules = 0;
230 ULONG RequiredSnapshotSize = sizeof(TH32SNAPSHOT);
231 PRTL_PROCESS_HEAPS hi = NULL;
232 PRTL_PROCESS_MODULES mi = NULL;
233 NTSTATUS Status = STATUS_SUCCESS;
234
235 /*
236 * Determine the required size for the heap snapshot
237 */
238 if(dwFlags & TH32CS_SNAPHEAPLIST)
239 {
240 hi = (PRTL_PROCESS_HEAPS)HeapDebug->Heaps;
241 nHeaps = hi->NumberOfHeaps;
242 RequiredSnapshotSize += nHeaps * sizeof(HEAPLIST32);
243 }
244
245 /*
246 * Determine the required size for the module snapshot
247 */
248 if(dwFlags & TH32CS_SNAPMODULE)
249 {
250 mi = (PRTL_PROCESS_MODULES)ModuleDebug->Modules;
251 nModules = mi->NumberOfModules;
252 RequiredSnapshotSize += nModules * sizeof(MODULEENTRY32W);
253 }
254
255 /*
256 * Determine the required size for the processes and threads snapshot
257 */
258 if(dwFlags & (TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD))
259 {
260 ULONG ProcOffset = 0;
261
262 ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)ProcThrdInfo;
263 do
264 {
265 ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)((ULONG_PTR)ProcessInfo + ProcOffset);
266 nProcesses++;
267 nThreads += ProcessInfo->NumberOfThreads;
268 ProcOffset = ProcessInfo->NextEntryOffset;
269 } while(ProcOffset != 0);
270
271 if(dwFlags & TH32CS_SNAPPROCESS)
272 {
273 RequiredSnapshotSize += nProcesses * sizeof(PROCESSENTRY32W);
274 }
275 if(dwFlags & TH32CS_SNAPTHREAD)
276 {
277 RequiredSnapshotSize += nThreads * sizeof(THREADENTRY32);
278 }
279 }
280
281 /*
282 * Create and map the section
283 */
284
285 SSize.QuadPart = RequiredSnapshotSize;
286
287 InitializeObjectAttributes(&ObjectAttributes,
288 NULL,
289 ((dwFlags & TH32CS_INHERIT) ? OBJ_INHERIT : 0),
290 NULL,
291 NULL);
292
293 Status = NtCreateSection(&hSection,
294 SECTION_ALL_ACCESS,
295 &ObjectAttributes,
296 &SSize,
297 PAGE_READWRITE,
298 SEC_COMMIT,
299 NULL);
300 if(!NT_SUCCESS(Status))
301 {
302 return Status;
303 }
304
305 SOffset.QuadPart = 0;
306 ViewSize = 0;
307 Snapshot = NULL;
308
309 Status = NtMapViewOfSection(hSection,
310 NtCurrentProcess(),
311 (PVOID*)&Snapshot,
312 0,
313 0,
314 &SOffset,
315 &ViewSize,
316 ViewShare,
317 0,
318 PAGE_READWRITE);
319 if(!NT_SUCCESS(Status))
320 {
321 NtClose(hSection);
322 return Status;
323 }
324
325 RtlZeroMemory(Snapshot, sizeof(TH32SNAPSHOT));
326 DataOffset = 0;
327
328 /*
329 * Initialize the section data and fill it with all the data we collected
330 */
331
332 /* initialize the heap list */
333 if(dwFlags & TH32CS_SNAPHEAPLIST)
334 {
335 Snapshot->HeapListCount = nHeaps;
336 Snapshot->HeapListOffset = DataOffset;
337 HeapListEntry = (LPHEAPLIST32)OffsetToPtr(Snapshot, DataOffset);
338 for(i = 0; i < nHeaps; i++)
339 {
340 HeapListEntry->dwSize = sizeof(HEAPLIST32);
341 HeapListEntry->th32ProcessID = th32ProcessID;
342 HeapListEntry->th32HeapID = (ULONG_PTR)hi->Heaps[i].BaseAddress;
343 HeapListEntry->dwFlags = hi->Heaps[i].Flags;
344
345 HeapListEntry++;
346 }
347
348 DataOffset += hi->NumberOfHeaps * sizeof(HEAPLIST32);
349 }
350
351 /* initialize the module list */
352 if(dwFlags & TH32CS_SNAPMODULE)
353 {
354 Snapshot->ModuleListCount = nModules;
355 Snapshot->ModuleListOffset = DataOffset;
356 ModuleListEntry = (LPMODULEENTRY32W)OffsetToPtr(Snapshot, DataOffset);
357 for(i = 0; i < nModules; i++)
358 {
359 ModuleListEntry->dwSize = sizeof(MODULEENTRY32W);
360 ModuleListEntry->th32ModuleID = 1; /* no longer used, always set to one! */
361 ModuleListEntry->th32ProcessID = th32ProcessID;
362 ModuleListEntry->GlblcntUsage = mi->Modules[i].LoadCount;
363 ModuleListEntry->ProccntUsage = mi->Modules[i].LoadCount;
364 ModuleListEntry->modBaseAddr = (BYTE*)mi->Modules[i].ImageBase;
365 ModuleListEntry->modBaseSize = mi->Modules[i].ImageSize;
366 ModuleListEntry->hModule = (HMODULE)mi->Modules[i].ImageBase;
367
368 MultiByteToWideChar(CP_ACP,
369 0,
370 &mi->Modules[i].FullPathName[mi->Modules[i].OffsetToFileName],
371 -1,
372 ModuleListEntry->szModule,
373 sizeof(ModuleListEntry->szModule) / sizeof(ModuleListEntry->szModule[0]));
374
375 MultiByteToWideChar(CP_ACP,
376 0,
377 mi->Modules[i].FullPathName,
378 -1,
379 ModuleListEntry->szExePath,
380 sizeof(ModuleListEntry->szExePath) / sizeof(ModuleListEntry->szExePath[0]));
381
382 ModuleListEntry++;
383 }
384
385 DataOffset += mi->NumberOfModules * sizeof(MODULEENTRY32W);
386 }
387
388 /* initialize the process list */
389 if(dwFlags & TH32CS_SNAPPROCESS)
390 {
391 ULONG ProcOffset = 0;
392
393 Snapshot->ProcessListCount = nProcesses;
394 Snapshot->ProcessListOffset = DataOffset;
395 ProcessListEntry = (LPPROCESSENTRY32W)OffsetToPtr(Snapshot, DataOffset);
396 ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)ProcThrdInfo;
397 do
398 {
399 ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)((ULONG_PTR)ProcessInfo + ProcOffset);
400
401 ProcessListEntry->dwSize = sizeof(PROCESSENTRY32W);
402 ProcessListEntry->cntUsage = 0; /* no longer used */
403 ProcessListEntry->th32ProcessID = (ULONG_PTR)ProcessInfo->UniqueProcessId;
404 ProcessListEntry->th32DefaultHeapID = 0; /* no longer used */
405 ProcessListEntry->th32ModuleID = 0; /* no longer used */
406 ProcessListEntry->cntThreads = ProcessInfo->NumberOfThreads;
407 ProcessListEntry->th32ParentProcessID = (ULONG_PTR)ProcessInfo->InheritedFromUniqueProcessId;
408 ProcessListEntry->pcPriClassBase = ProcessInfo->BasePriority;
409 ProcessListEntry->dwFlags = 0; /* no longer used */
410 if(ProcessInfo->ImageName.Buffer != NULL)
411 {
412 ULONG ExeFileLength = min(ProcessInfo->ImageName.Length,
413 sizeof(ProcessListEntry->szExeFile) - sizeof(WCHAR));
414 RtlCopyMemory(ProcessListEntry->szExeFile,
415 ProcessInfo->ImageName.Buffer,
416 ExeFileLength);
417 ProcessListEntry->szExeFile[ExeFileLength / sizeof(WCHAR)] = UNICODE_NULL;
418 }
419 else
420 {
421 lstrcpyW(ProcessListEntry->szExeFile, L"[System Process]");
422 }
423
424 ProcessListEntry++;
425
426 ProcOffset = ProcessInfo->NextEntryOffset;
427 } while(ProcOffset != 0);
428
429 DataOffset += nProcesses * sizeof(PROCESSENTRY32W);
430 }
431
432 /* initialize the thread list */
433 if(dwFlags & TH32CS_SNAPTHREAD)
434 {
435 ULONG ProcOffset = 0;
436
437 Snapshot->ThreadListCount = nThreads;
438 Snapshot->ThreadListOffset = DataOffset;
439 ThreadListEntry = (LPTHREADENTRY32)OffsetToPtr(Snapshot, DataOffset);
440 ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)ProcThrdInfo;
441 do
442 {
443 PSYSTEM_THREAD_INFORMATION ThreadInfo;
444 ULONG n;
445
446 ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)((ULONG_PTR)ProcessInfo + ProcOffset);
447 ThreadInfo = (PSYSTEM_THREAD_INFORMATION)(ProcessInfo + 1);
448
449 for(n = 0; n < ProcessInfo->NumberOfThreads; n++)
450 {
451 ThreadListEntry->dwSize = sizeof(THREADENTRY32);
452 ThreadListEntry->cntUsage = 0; /* no longer used */
453 ThreadListEntry->th32ThreadID = (ULONG_PTR)ThreadInfo->ClientId.UniqueThread;
454 ThreadListEntry->th32OwnerProcessID = (ULONG_PTR)ThreadInfo->ClientId.UniqueProcess;
455 ThreadListEntry->tpBasePri = ThreadInfo->BasePriority;
456 ThreadListEntry->tpDeltaPri = 0; /* no longer used */
457 ThreadListEntry->dwFlags = 0; /* no longer used */
458
459 ThreadInfo++;
460 ThreadListEntry++;
461 }
462
463 ProcOffset = ProcessInfo->NextEntryOffset;
464 } while(ProcOffset != 0);
465 }
466
467 /*
468 * We're done, unmap the view and return the section handle
469 */
470
471 Status = NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)Snapshot);
472
473 if(NT_SUCCESS(Status))
474 {
475 *SectionHandle = hSection;
476 }
477 else
478 {
479 NtClose(hSection);
480 }
481
482 return Status;
483 }
484
485 /* PUBLIC FUNCTIONS ***********************************************************/
486
487 /*
488 * @implemented
489 */
490 BOOL
491 WINAPI
492 Heap32First(LPHEAPENTRY32 lphe, DWORD th32ProcessID, DWORD th32HeapID)
493 {
494 PRTL_DEBUG_INFORMATION DebugInfo;
495 PRTL_HEAP_INFORMATION Heap;
496 PRTLP_HEAP_ENTRY Block, LastBlock;
497 ULONG i;
498 NTSTATUS Status;
499
500 CHECK_PARAM_SIZE(lphe, sizeof(HEAPENTRY32));
501
502 DebugInfo = RtlCreateQueryDebugBuffer(0,
503 FALSE);
504 if (DebugInfo == NULL)
505 {
506 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
507 return FALSE;
508 }
509
510 Status = RtlQueryProcessDebugInformation(th32ProcessID,
511 RTL_DEBUG_QUERY_HEAPS | RTL_DEBUG_QUERY_HEAP_BLOCKS,
512 DebugInfo);
513
514 if (NT_SUCCESS(Status))
515 {
516 Status = STATUS_NO_MORE_FILES;
517
518 for (i = 0;
519 i != DebugInfo->Heaps->NumberOfHeaps;
520 i++)
521 {
522 Heap = &DebugInfo->Heaps->Heaps[i];
523
524 if ((ULONG_PTR)Heap->BaseAddress == th32HeapID)
525 {
526 lphe->hHandle = (HANDLE)Heap->BaseAddress;
527 lphe->dwAddress = 0;
528 lphe->dwBlockSize = 0;
529 lphe->dwFlags = 0;
530 lphe->dwLockCount = 0;
531 lphe->dwResvd = 0;
532 lphe->th32ProcessID = th32ProcessID;
533 lphe->th32HeapID = (ULONG_PTR)Heap->BaseAddress;
534
535 Block = (PRTLP_HEAP_ENTRY)Heap->Entries;
536 LastBlock = Block + Heap->NumberOfEntries;
537
538 while (Block != LastBlock && (Block->Flags & PROCESS_HEAP_UNCOMMITTED_RANGE))
539 {
540 lphe->dwResvd++;
541 lphe->dwAddress = (ULONG_PTR)((ULONG_PTR)Block->Address + Heap->EntryOverhead);
542 Block++;
543 }
544
545 if (Block != LastBlock && lphe->dwResvd != 0)
546 {
547 lphe->dwBlockSize = Block->Size;
548
549 if (Block->Flags & 0x2F1) /* FIXME */
550 lphe->dwFlags = LF32_FIXED;
551 else if (Block->Flags & 0x20) /* FIXME */
552 lphe->dwFlags = LF32_MOVEABLE;
553 else if (Block->Flags & 0x100) /* FIXME */
554 lphe->dwFlags = LF32_FREE;
555
556 Status = STATUS_SUCCESS;
557 }
558
559 break;
560 }
561 }
562 }
563
564 RtlDestroyQueryDebugBuffer(DebugInfo);
565
566 if (!NT_SUCCESS(Status))
567 {
568 BaseSetLastNTError(Status);
569 return FALSE;
570 }
571
572 return TRUE;
573 }
574
575
576 /*
577 * @implemented
578 */
579 BOOL
580 WINAPI
581 Heap32Next(LPHEAPENTRY32 lphe)
582 {
583 PRTL_DEBUG_INFORMATION DebugInfo;
584 PRTL_HEAP_INFORMATION Heap;
585 PRTLP_HEAP_ENTRY Block, LastBlock;
586 BOOLEAN FoundUncommitted = FALSE;
587 ULONG i;
588 NTSTATUS Status;
589
590 CHECK_PARAM_SIZE(lphe, sizeof(HEAPENTRY32));
591
592 DebugInfo = RtlCreateQueryDebugBuffer(0,
593 FALSE);
594 if (DebugInfo == NULL)
595 {
596 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
597 return FALSE;
598 }
599
600 Status = RtlQueryProcessDebugInformation(lphe->th32ProcessID,
601 RTL_DEBUG_QUERY_HEAPS | RTL_DEBUG_QUERY_HEAP_BLOCKS,
602 DebugInfo);
603
604 if (NT_SUCCESS(Status))
605 {
606 Status = STATUS_NO_MORE_FILES;
607
608 for (i = 0;
609 i != DebugInfo->Heaps->NumberOfHeaps;
610 i++)
611 {
612 Heap = &DebugInfo->Heaps->Heaps[i];
613
614 if ((ULONG_PTR)Heap->BaseAddress == lphe->th32HeapID)
615 {
616 if (++lphe->dwResvd < Heap->NumberOfEntries)
617 {
618 lphe->dwFlags = 0;
619
620 Block = (PRTLP_HEAP_ENTRY)Heap->Entries + lphe->dwResvd;
621 LastBlock = (PRTLP_HEAP_ENTRY)Heap->Entries + Heap->NumberOfEntries;
622
623 while (Block < LastBlock && (Block->Flags & PROCESS_HEAP_UNCOMMITTED_RANGE))
624 {
625 lphe->dwResvd++;
626 lphe->dwAddress = (ULONG_PTR)((ULONG_PTR)Block->Address + Heap->EntryOverhead);
627 FoundUncommitted = TRUE;
628 Block++;
629 }
630
631 if (Block < LastBlock)
632 {
633 if (!FoundUncommitted)
634 lphe->dwAddress += lphe->dwBlockSize;
635
636 lphe->dwBlockSize = Block->Size;
637
638 if (Block->Flags & 0x2F1) /* FIXME */
639 lphe->dwFlags = LF32_FIXED;
640 else if (Block->Flags & 0x20) /* FIXME */
641 lphe->dwFlags = LF32_MOVEABLE;
642 else if (Block->Flags & 0x100) /* FIXME */
643 lphe->dwFlags = LF32_FREE;
644
645 Status = STATUS_SUCCESS;
646 }
647 }
648
649 break;
650 }
651 }
652 }
653
654 RtlDestroyQueryDebugBuffer(DebugInfo);
655
656 if (!NT_SUCCESS(Status))
657 {
658 BaseSetLastNTError(Status);
659 return FALSE;
660 }
661
662 return TRUE;
663
664 }
665
666
667 /*
668 * @implemented
669 */
670 BOOL
671 WINAPI
672 Heap32ListFirst(HANDLE hSnapshot, LPHEAPLIST32 lphl)
673 {
674 PTH32SNAPSHOT Snapshot;
675 LARGE_INTEGER SOffset;
676 SIZE_T ViewSize;
677 NTSTATUS Status;
678
679 CHECK_PARAM_SIZE(lphl, sizeof(HEAPLIST32));
680
681 SOffset.QuadPart = 0;
682 ViewSize = 0;
683 Snapshot = NULL;
684
685 Status = NtMapViewOfSection(hSnapshot,
686 NtCurrentProcess(),
687 (PVOID*)&Snapshot,
688 0,
689 0,
690 &SOffset,
691 &ViewSize,
692 ViewShare,
693 0,
694 PAGE_READWRITE);
695 if(NT_SUCCESS(Status))
696 {
697 BOOL Ret;
698
699 if(Snapshot->HeapListCount > 0)
700 {
701 LPHEAPLIST32 Entries = (LPHEAPLIST32)OffsetToPtr(Snapshot, Snapshot->HeapListOffset);
702 Snapshot->HeapListIndex = 1;
703 RtlCopyMemory(lphl, &Entries[0], sizeof(HEAPLIST32));
704 Ret = TRUE;
705 }
706 else
707 {
708 SetLastError(ERROR_NO_MORE_FILES);
709 Ret = FALSE;
710 }
711
712 NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)Snapshot);
713 return Ret;
714 }
715
716 BaseSetLastNTError(Status);
717 return FALSE;
718 }
719
720
721 /*
722 * @implemented
723 */
724 BOOL
725 WINAPI
726 Heap32ListNext(HANDLE hSnapshot, LPHEAPLIST32 lphl)
727 {
728 PTH32SNAPSHOT Snapshot;
729 LARGE_INTEGER SOffset;
730 SIZE_T ViewSize;
731 NTSTATUS Status;
732
733 CHECK_PARAM_SIZE(lphl, sizeof(HEAPLIST32));
734
735 SOffset.QuadPart = 0;
736 ViewSize = 0;
737 Snapshot = NULL;
738
739 Status = NtMapViewOfSection(hSnapshot,
740 NtCurrentProcess(),
741 (PVOID*)&Snapshot,
742 0,
743 0,
744 &SOffset,
745 &ViewSize,
746 ViewShare,
747 0,
748 PAGE_READWRITE);
749 if(NT_SUCCESS(Status))
750 {
751 BOOL Ret;
752
753 if(Snapshot->HeapListCount > 0 &&
754 Snapshot->HeapListIndex < Snapshot->HeapListCount)
755 {
756 LPHEAPLIST32 Entries = (LPHEAPLIST32)OffsetToPtr(Snapshot, Snapshot->HeapListOffset);
757 RtlCopyMemory(lphl, &Entries[Snapshot->HeapListIndex++], sizeof(HEAPLIST32));
758 Ret = TRUE;
759 }
760 else
761 {
762 SetLastError(ERROR_NO_MORE_FILES);
763 Ret = FALSE;
764 }
765
766 NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)Snapshot);
767 return Ret;
768 }
769
770 BaseSetLastNTError(Status);
771 return FALSE;
772 }
773
774
775 /*
776 * @implemented
777 */
778 BOOL
779 WINAPI
780 Module32First(HANDLE hSnapshot, LPMODULEENTRY32 lpme)
781 {
782 MODULEENTRY32W me;
783 BOOL Ret;
784
785 CHECK_PARAM_SIZEA(lpme, sizeof(MODULEENTRY32));
786
787 me.dwSize = sizeof(MODULEENTRY32W);
788
789 Ret = Module32FirstW(hSnapshot, &me);
790 if(Ret)
791 {
792 lpme->th32ModuleID = me.th32ModuleID;
793 lpme->th32ProcessID = me.th32ProcessID;
794 lpme->GlblcntUsage = me.GlblcntUsage;
795 lpme->ProccntUsage = me.ProccntUsage;
796 lpme->modBaseAddr = me.modBaseAddr;
797 lpme->modBaseSize = me.modBaseSize;
798 lpme->hModule = me.hModule;
799
800 WideCharToMultiByte(CP_ACP, 0, me.szModule, -1, lpme->szModule, sizeof(lpme->szModule), 0, 0);
801 WideCharToMultiByte(CP_ACP, 0, me.szExePath, -1, lpme->szExePath, sizeof(lpme->szExePath), 0, 0);
802 }
803
804 return Ret;
805 }
806
807
808 /*
809 * @implemented
810 */
811 BOOL
812 WINAPI
813 Module32FirstW(HANDLE hSnapshot, LPMODULEENTRY32W lpme)
814 {
815 PTH32SNAPSHOT Snapshot;
816 LARGE_INTEGER SOffset;
817 SIZE_T ViewSize;
818 NTSTATUS Status;
819
820 CHECK_PARAM_SIZE(lpme, sizeof(MODULEENTRY32W));
821
822 SOffset.QuadPart = 0;
823 ViewSize = 0;
824 Snapshot = NULL;
825
826 Status = NtMapViewOfSection(hSnapshot,
827 NtCurrentProcess(),
828 (PVOID*)&Snapshot,
829 0,
830 0,
831 &SOffset,
832 &ViewSize,
833 ViewShare,
834 0,
835 PAGE_READWRITE);
836 if(NT_SUCCESS(Status))
837 {
838 BOOL Ret;
839
840 if(Snapshot->ModuleListCount > 0)
841 {
842 LPMODULEENTRY32W Entries = (LPMODULEENTRY32W)OffsetToPtr(Snapshot, Snapshot->ModuleListOffset);
843 Snapshot->ModuleListIndex = 1;
844 RtlCopyMemory(lpme, &Entries[0], sizeof(MODULEENTRY32W));
845 Ret = TRUE;
846 }
847 else
848 {
849 SetLastError(ERROR_NO_MORE_FILES);
850 Ret = FALSE;
851 }
852
853 NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)Snapshot);
854 return Ret;
855 }
856
857 BaseSetLastNTError(Status);
858 return FALSE;
859 }
860
861
862 /*
863 * @implemented
864 */
865 BOOL
866 WINAPI
867 Module32Next(HANDLE hSnapshot, LPMODULEENTRY32 lpme)
868 {
869 MODULEENTRY32W me;
870 BOOL Ret;
871
872 CHECK_PARAM_SIZEA(lpme, sizeof(MODULEENTRY32));
873
874 me.dwSize = sizeof(MODULEENTRY32W);
875
876 Ret = Module32NextW(hSnapshot, &me);
877 if(Ret)
878 {
879 lpme->th32ModuleID = me.th32ModuleID;
880 lpme->th32ProcessID = me.th32ProcessID;
881 lpme->GlblcntUsage = me.GlblcntUsage;
882 lpme->ProccntUsage = me.ProccntUsage;
883 lpme->modBaseAddr = me.modBaseAddr;
884 lpme->modBaseSize = me.modBaseSize;
885 lpme->hModule = me.hModule;
886
887 WideCharToMultiByte(CP_ACP, 0, me.szModule, -1, lpme->szModule, sizeof(lpme->szModule), 0, 0);
888 WideCharToMultiByte(CP_ACP, 0, me.szExePath, -1, lpme->szExePath, sizeof(lpme->szExePath), 0, 0);
889 }
890
891 return Ret;
892 }
893
894
895 /*
896 * @implemented
897 */
898 BOOL
899 WINAPI
900 Module32NextW(HANDLE hSnapshot, LPMODULEENTRY32W lpme)
901 {
902 PTH32SNAPSHOT Snapshot;
903 LARGE_INTEGER SOffset;
904 SIZE_T ViewSize;
905 NTSTATUS Status;
906
907 CHECK_PARAM_SIZE(lpme, sizeof(MODULEENTRY32W));
908
909 SOffset.QuadPart = 0;
910 ViewSize = 0;
911 Snapshot = NULL;
912
913 Status = NtMapViewOfSection(hSnapshot,
914 NtCurrentProcess(),
915 (PVOID*)&Snapshot,
916 0,
917 0,
918 &SOffset,
919 &ViewSize,
920 ViewShare,
921 0,
922 PAGE_READWRITE);
923 if(NT_SUCCESS(Status))
924 {
925 BOOL Ret;
926
927 if((Snapshot->ModuleListCount > 0) &&
928 (Snapshot->ModuleListIndex < Snapshot->ModuleListCount))
929 {
930 LPMODULEENTRY32W Entries = (LPMODULEENTRY32W)OffsetToPtr(Snapshot, Snapshot->ModuleListOffset);
931 RtlCopyMemory(lpme, &Entries[Snapshot->ModuleListIndex++], sizeof(MODULEENTRY32W));
932 Ret = TRUE;
933 }
934 else
935 {
936 SetLastError(ERROR_NO_MORE_FILES);
937 Ret = FALSE;
938 }
939
940 NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)Snapshot);
941 return Ret;
942 }
943
944 BaseSetLastNTError(Status);
945 return FALSE;
946 }
947
948
949 /*
950 * @implemented
951 */
952 BOOL
953 WINAPI
954 Process32First(HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
955 {
956 PROCESSENTRY32W pe;
957 BOOL Ret;
958
959 CHECK_PARAM_SIZEA(lppe, sizeof(PROCESSENTRY32));
960
961 pe.dwSize = sizeof(PROCESSENTRY32W);
962
963 Ret = Process32FirstW(hSnapshot, &pe);
964 if(Ret)
965 {
966 lppe->cntUsage = pe.cntUsage;
967 lppe->th32ProcessID = pe.th32ProcessID;
968 lppe->th32DefaultHeapID = pe.th32DefaultHeapID;
969 lppe->th32ModuleID = pe.th32ModuleID;
970 lppe->cntThreads = pe.cntThreads;
971 lppe->th32ParentProcessID = pe.th32ParentProcessID;
972 lppe->pcPriClassBase = pe.pcPriClassBase;
973 lppe->dwFlags = pe.dwFlags;
974
975 WideCharToMultiByte(CP_ACP, 0, pe.szExeFile, -1, lppe->szExeFile, sizeof(lppe->szExeFile), 0, 0);
976 }
977
978 return Ret;
979 }
980
981
982 /*
983 * @implemented
984 */
985 BOOL
986 WINAPI
987 Process32FirstW(HANDLE hSnapshot, LPPROCESSENTRY32W lppe)
988 {
989 PTH32SNAPSHOT Snapshot;
990 LARGE_INTEGER SOffset;
991 SIZE_T ViewSize;
992 NTSTATUS Status;
993
994 CHECK_PARAM_SIZE(lppe, sizeof(PROCESSENTRY32W));
995
996 SOffset.QuadPart = 0;
997 ViewSize = 0;
998 Snapshot = NULL;
999
1000 Status = NtMapViewOfSection(hSnapshot,
1001 NtCurrentProcess(),
1002 (PVOID*)&Snapshot,
1003 0,
1004 0,
1005 &SOffset,
1006 &ViewSize,
1007 ViewShare,
1008 0,
1009 PAGE_READWRITE);
1010 if(NT_SUCCESS(Status))
1011 {
1012 BOOL Ret;
1013
1014 if(Snapshot->ProcessListCount > 0)
1015 {
1016 LPPROCESSENTRY32W Entries = (LPPROCESSENTRY32W)OffsetToPtr(Snapshot, Snapshot->ProcessListOffset);
1017
1018 Snapshot->ProcessListIndex = 1;
1019 RtlCopyMemory(lppe, &Entries[0], sizeof(PROCESSENTRY32W));
1020 Ret = TRUE;
1021 }
1022 else
1023 {
1024
1025 SetLastError(ERROR_NO_MORE_FILES);
1026 Ret = FALSE;
1027 }
1028
1029 NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)Snapshot);
1030 return Ret;
1031 }
1032
1033 BaseSetLastNTError(Status);
1034 return FALSE;
1035 }
1036
1037
1038 /*
1039 * @implemented
1040 */
1041 BOOL
1042 WINAPI
1043 Process32Next(HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
1044 {
1045 PROCESSENTRY32W pe;
1046 BOOL Ret;
1047
1048 CHECK_PARAM_SIZEA(lppe, sizeof(PROCESSENTRY32));
1049
1050 pe.dwSize = sizeof(PROCESSENTRY32W);
1051
1052 Ret = Process32NextW(hSnapshot, &pe);
1053 if(Ret)
1054 {
1055 lppe->cntUsage = pe.cntUsage;
1056 lppe->th32ProcessID = pe.th32ProcessID;
1057 lppe->th32DefaultHeapID = pe.th32DefaultHeapID;
1058 lppe->th32ModuleID = pe.th32ModuleID;
1059 lppe->cntThreads = pe.cntThreads;
1060 lppe->th32ParentProcessID = pe.th32ParentProcessID;
1061 lppe->pcPriClassBase = pe.pcPriClassBase;
1062 lppe->dwFlags = pe.dwFlags;
1063
1064 WideCharToMultiByte(CP_ACP, 0, pe.szExeFile, -1, lppe->szExeFile, sizeof(lppe->szExeFile), 0, 0);
1065 }
1066
1067 return Ret;
1068 }
1069
1070
1071 /*
1072 * @implemented
1073 */
1074 BOOL
1075 WINAPI
1076 Process32NextW(HANDLE hSnapshot, LPPROCESSENTRY32W lppe)
1077 {
1078 PTH32SNAPSHOT Snapshot;
1079 LARGE_INTEGER SOffset;
1080 SIZE_T ViewSize;
1081 NTSTATUS Status;
1082
1083 CHECK_PARAM_SIZE(lppe, sizeof(PROCESSENTRY32W));
1084
1085 SOffset.QuadPart = 0;
1086 ViewSize = 0;
1087 Snapshot = NULL;
1088
1089 Status = NtMapViewOfSection(hSnapshot,
1090 NtCurrentProcess(),
1091 (PVOID*)&Snapshot,
1092 0,
1093 0,
1094 &SOffset,
1095 &ViewSize,
1096 ViewShare,
1097 0,
1098 PAGE_READWRITE);
1099 if(NT_SUCCESS(Status))
1100 {
1101 BOOL Ret;
1102
1103 if(Snapshot->ProcessListCount > 0 &&
1104 Snapshot->ProcessListIndex < Snapshot->ProcessListCount)
1105 {
1106 LPPROCESSENTRY32W Entries = (LPPROCESSENTRY32W)OffsetToPtr(Snapshot, Snapshot->ProcessListOffset);
1107 RtlCopyMemory(lppe, &Entries[Snapshot->ProcessListIndex++], sizeof(PROCESSENTRY32W));
1108 Ret = TRUE;
1109 }
1110 else
1111 {
1112 SetLastError(ERROR_NO_MORE_FILES);
1113 Ret = FALSE;
1114 }
1115
1116 NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)Snapshot);
1117 return Ret;
1118 }
1119
1120 BaseSetLastNTError(Status);
1121 return FALSE;
1122 }
1123
1124
1125 /*
1126 * @implemented
1127 */
1128 BOOL
1129 WINAPI
1130 Thread32First(HANDLE hSnapshot, LPTHREADENTRY32 lpte)
1131 {
1132 PTH32SNAPSHOT Snapshot;
1133 LARGE_INTEGER SOffset;
1134 SIZE_T ViewSize;
1135 NTSTATUS Status;
1136
1137 CHECK_PARAM_SIZE(lpte, sizeof(THREADENTRY32));
1138
1139 SOffset.QuadPart = 0;
1140 ViewSize = 0;
1141 Snapshot = NULL;
1142
1143 Status = NtMapViewOfSection(hSnapshot,
1144 NtCurrentProcess(),
1145 (PVOID*)&Snapshot,
1146 0,
1147 0,
1148 &SOffset,
1149 &ViewSize,
1150 ViewShare,
1151 0,
1152 PAGE_READWRITE);
1153 if(NT_SUCCESS(Status))
1154 {
1155 BOOL Ret;
1156
1157 if(Snapshot->ThreadListCount > 0)
1158 {
1159 LPTHREADENTRY32 Entries = (LPTHREADENTRY32)OffsetToPtr(Snapshot, Snapshot->ThreadListOffset);
1160 Snapshot->ThreadListIndex = 1;
1161 RtlCopyMemory(lpte, &Entries[0], sizeof(THREADENTRY32));
1162 Ret = TRUE;
1163 }
1164 else
1165 {
1166 SetLastError(ERROR_NO_MORE_FILES);
1167 Ret = FALSE;
1168 }
1169
1170 NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)Snapshot);
1171 return Ret;
1172 }
1173
1174 BaseSetLastNTError(Status);
1175 return FALSE;
1176 }
1177
1178
1179 /*
1180 * @implemented
1181 */
1182 BOOL
1183 WINAPI
1184 Thread32Next(HANDLE hSnapshot, LPTHREADENTRY32 lpte)
1185 {
1186 PTH32SNAPSHOT Snapshot;
1187 LARGE_INTEGER SOffset;
1188 SIZE_T ViewSize;
1189 NTSTATUS Status;
1190
1191 CHECK_PARAM_SIZE(lpte, sizeof(THREADENTRY32));
1192
1193 SOffset.QuadPart = 0;
1194 ViewSize = 0;
1195 Snapshot = NULL;
1196
1197 Status = NtMapViewOfSection(hSnapshot,
1198 NtCurrentProcess(),
1199 (PVOID*)&Snapshot,
1200 0,
1201 0,
1202 &SOffset,
1203 &ViewSize,
1204 ViewShare,
1205 0,
1206 PAGE_READWRITE);
1207 if(NT_SUCCESS(Status))
1208 {
1209 BOOL Ret;
1210
1211 if(Snapshot->ThreadListCount > 0 &&
1212 Snapshot->ThreadListIndex < Snapshot->ThreadListCount)
1213 {
1214 LPTHREADENTRY32 Entries = (LPTHREADENTRY32)OffsetToPtr(Snapshot, Snapshot->ThreadListOffset);
1215 RtlCopyMemory(lpte, &Entries[Snapshot->ThreadListIndex++], sizeof(THREADENTRY32));
1216 Ret = TRUE;
1217 }
1218 else
1219 {
1220 SetLastError(ERROR_NO_MORE_FILES);
1221 Ret = FALSE;
1222 }
1223
1224 NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)Snapshot);
1225 return Ret;
1226 }
1227
1228 BaseSetLastNTError(Status);
1229 return FALSE;
1230 }
1231
1232
1233 /*
1234 * @implemented
1235 */
1236 BOOL
1237 WINAPI
1238 Toolhelp32ReadProcessMemory(DWORD th32ProcessID, LPCVOID lpBaseAddress,
1239 LPVOID lpBuffer, SIZE_T cbRead, SIZE_T* lpNumberOfBytesRead)
1240 {
1241 HANDLE hProcess = OpenProcess(PROCESS_VM_READ, FALSE, th32ProcessID);
1242 if(hProcess != NULL)
1243 {
1244 BOOL Ret = ReadProcessMemory(hProcess, lpBaseAddress, lpBuffer, cbRead, lpNumberOfBytesRead);
1245 CloseHandle(hProcess);
1246 return Ret;
1247 }
1248
1249 return FALSE;
1250 }
1251
1252
1253 /*
1254 * @implemented
1255 */
1256 HANDLE
1257 WINAPI
1258 CreateToolhelp32Snapshot(DWORD dwFlags, DWORD th32ProcessID)
1259 {
1260 PRTL_DEBUG_INFORMATION HeapDebug, ModuleDebug;
1261 PVOID ProcThrdInfo;
1262 SIZE_T ProcThrdInfoSize;
1263 NTSTATUS Status;
1264 HANDLE hSnapShotSection = NULL;
1265
1266 if(th32ProcessID == 0)
1267 {
1268 th32ProcessID = GetCurrentProcessId();
1269 }
1270
1271 /*
1272 * Get all information required for the snapshot
1273 */
1274 Status = TH32CreateSnapshot(dwFlags,
1275 th32ProcessID,
1276 &HeapDebug,
1277 &ModuleDebug,
1278 &ProcThrdInfo,
1279 &ProcThrdInfoSize);
1280 if(!NT_SUCCESS(Status))
1281 {
1282 BaseSetLastNTError(Status);
1283 return NULL;
1284 }
1285
1286 /*
1287 * Create a section handle and initialize the collected information
1288 */
1289 Status = TH32CreateSnapshotSectionInitialize(dwFlags,
1290 th32ProcessID,
1291 HeapDebug,
1292 ModuleDebug,
1293 ProcThrdInfo,
1294 &hSnapShotSection);
1295
1296 /*
1297 * Free the temporarily allocated memory which is no longer needed
1298 */
1299 TH32FreeAllocatedResources(HeapDebug,
1300 ModuleDebug,
1301 ProcThrdInfo,
1302 ProcThrdInfoSize);
1303
1304 if(!NT_SUCCESS(Status))
1305 {
1306 BaseSetLastNTError(Status);
1307 return NULL;
1308 }
1309
1310 return hSnapShotSection;
1311 }
1312
1313 /* EOF */