* Sync to trunk HEAD (r53298).
[reactos.git] / 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 lstrcpynW(ProcessListEntry->szExeFile,
413 ProcessInfo->ImageName.Buffer,
414 min(ProcessInfo->ImageName.Length / sizeof(WCHAR), sizeof(ProcessListEntry->szExeFile) / sizeof(ProcessListEntry->szExeFile[0])));
415 }
416 else
417 {
418 lstrcpyW(ProcessListEntry->szExeFile, L"[System Process]");
419 }
420
421 ProcessListEntry++;
422
423 ProcOffset = ProcessInfo->NextEntryOffset;
424 } while(ProcOffset != 0);
425
426 DataOffset += nProcesses * sizeof(PROCESSENTRY32W);
427 }
428
429 /* initialize the thread list */
430 if(dwFlags & TH32CS_SNAPTHREAD)
431 {
432 ULONG ProcOffset = 0;
433
434 Snapshot->ThreadListCount = nThreads;
435 Snapshot->ThreadListOffset = DataOffset;
436 ThreadListEntry = (LPTHREADENTRY32)OffsetToPtr(Snapshot, DataOffset);
437 ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)ProcThrdInfo;
438 do
439 {
440 PSYSTEM_THREAD_INFORMATION ThreadInfo;
441 ULONG n;
442
443 ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)((ULONG_PTR)ProcessInfo + ProcOffset);
444 ThreadInfo = (PSYSTEM_THREAD_INFORMATION)(ProcessInfo + 1);
445
446 for(n = 0; n < ProcessInfo->NumberOfThreads; n++)
447 {
448 ThreadListEntry->dwSize = sizeof(THREADENTRY32);
449 ThreadListEntry->cntUsage = 0; /* no longer used */
450 ThreadListEntry->th32ThreadID = (ULONG_PTR)ThreadInfo->ClientId.UniqueThread;
451 ThreadListEntry->th32OwnerProcessID = (ULONG_PTR)ThreadInfo->ClientId.UniqueProcess;
452 ThreadListEntry->tpBasePri = ThreadInfo->BasePriority;
453 ThreadListEntry->tpDeltaPri = 0; /* no longer used */
454 ThreadListEntry->dwFlags = 0; /* no longer used */
455
456 ThreadInfo++;
457 ThreadListEntry++;
458 }
459
460 ProcOffset = ProcessInfo->NextEntryOffset;
461 } while(ProcOffset != 0);
462 }
463
464 /*
465 * We're done, unmap the view and return the section handle
466 */
467
468 Status = NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)Snapshot);
469
470 if(NT_SUCCESS(Status))
471 {
472 *SectionHandle = hSection;
473 }
474 else
475 {
476 NtClose(hSection);
477 }
478
479 return Status;
480 }
481
482 /* PUBLIC FUNCTIONS ***********************************************************/
483
484 /*
485 * @implemented
486 */
487 BOOL
488 WINAPI
489 Heap32First(LPHEAPENTRY32 lphe, DWORD th32ProcessID, DWORD th32HeapID)
490 {
491 PRTL_DEBUG_INFORMATION DebugInfo;
492 PRTL_HEAP_INFORMATION Heap;
493 PRTLP_HEAP_ENTRY Block, LastBlock;
494 ULONG i;
495 NTSTATUS Status;
496
497 CHECK_PARAM_SIZE(lphe, sizeof(HEAPENTRY32));
498
499 DebugInfo = RtlCreateQueryDebugBuffer(0,
500 FALSE);
501 if (DebugInfo == NULL)
502 {
503 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
504 return FALSE;
505 }
506
507 Status = RtlQueryProcessDebugInformation(th32ProcessID,
508 RTL_DEBUG_QUERY_HEAPS | RTL_DEBUG_QUERY_HEAP_BLOCKS,
509 DebugInfo);
510
511 if (NT_SUCCESS(Status))
512 {
513 Status = STATUS_NO_MORE_FILES;
514
515 for (i = 0;
516 i != DebugInfo->Heaps->NumberOfHeaps;
517 i++)
518 {
519 Heap = &DebugInfo->Heaps->Heaps[i];
520
521 if ((ULONG_PTR)Heap->BaseAddress == th32HeapID)
522 {
523 lphe->hHandle = (HANDLE)Heap->BaseAddress;
524 lphe->dwAddress = 0;
525 lphe->dwBlockSize = 0;
526 lphe->dwFlags = 0;
527 lphe->dwLockCount = 0;
528 lphe->dwResvd = 0;
529 lphe->th32ProcessID = th32ProcessID;
530 lphe->th32HeapID = (ULONG_PTR)Heap->BaseAddress;
531
532 Block = (PRTLP_HEAP_ENTRY)Heap->Entries;
533 LastBlock = Block + Heap->NumberOfEntries;
534
535 while (Block != LastBlock && (Block->Flags & PROCESS_HEAP_UNCOMMITTED_RANGE))
536 {
537 lphe->dwResvd++;
538 lphe->dwAddress = (ULONG_PTR)((ULONG_PTR)Block->Address + Heap->EntryOverhead);
539 Block++;
540 }
541
542 if (Block != LastBlock && lphe->dwResvd != 0)
543 {
544 lphe->dwBlockSize = Block->Size;
545
546 if (Block->Flags & 0x2F1) /* FIXME */
547 lphe->dwFlags = LF32_FIXED;
548 else if (Block->Flags & 0x20) /* FIXME */
549 lphe->dwFlags = LF32_MOVEABLE;
550 else if (Block->Flags & 0x100) /* FIXME */
551 lphe->dwFlags = LF32_FREE;
552
553 Status = STATUS_SUCCESS;
554 }
555
556 break;
557 }
558 }
559 }
560
561 RtlDestroyQueryDebugBuffer(DebugInfo);
562
563 if (!NT_SUCCESS(Status))
564 {
565 BaseSetLastNTError(Status);
566 return FALSE;
567 }
568
569 return TRUE;
570 }
571
572
573 /*
574 * @implemented
575 */
576 BOOL
577 WINAPI
578 Heap32Next(LPHEAPENTRY32 lphe)
579 {
580 PRTL_DEBUG_INFORMATION DebugInfo;
581 PRTL_HEAP_INFORMATION Heap;
582 PRTLP_HEAP_ENTRY Block, LastBlock;
583 BOOLEAN FoundUncommitted = FALSE;
584 ULONG i;
585 NTSTATUS Status;
586
587 CHECK_PARAM_SIZE(lphe, sizeof(HEAPENTRY32));
588
589 DebugInfo = RtlCreateQueryDebugBuffer(0,
590 FALSE);
591 if (DebugInfo == NULL)
592 {
593 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
594 return FALSE;
595 }
596
597 Status = RtlQueryProcessDebugInformation(lphe->th32ProcessID,
598 RTL_DEBUG_QUERY_HEAPS | RTL_DEBUG_QUERY_HEAP_BLOCKS,
599 DebugInfo);
600
601 if (NT_SUCCESS(Status))
602 {
603 Status = STATUS_NO_MORE_FILES;
604
605 for (i = 0;
606 i != DebugInfo->Heaps->NumberOfHeaps;
607 i++)
608 {
609 Heap = &DebugInfo->Heaps->Heaps[i];
610
611 if ((ULONG_PTR)Heap->BaseAddress == lphe->th32HeapID)
612 {
613 if (++lphe->dwResvd < Heap->NumberOfEntries)
614 {
615 lphe->dwFlags = 0;
616
617 Block = (PRTLP_HEAP_ENTRY)Heap->Entries + lphe->dwResvd;
618 LastBlock = (PRTLP_HEAP_ENTRY)Heap->Entries + Heap->NumberOfEntries;
619
620 while (Block < LastBlock && (Block->Flags & PROCESS_HEAP_UNCOMMITTED_RANGE))
621 {
622 lphe->dwResvd++;
623 lphe->dwAddress = (ULONG_PTR)((ULONG_PTR)Block->Address + Heap->EntryOverhead);
624 FoundUncommitted = TRUE;
625 Block++;
626 }
627
628 if (Block < LastBlock)
629 {
630 if (!FoundUncommitted)
631 lphe->dwAddress += lphe->dwBlockSize;
632
633 lphe->dwBlockSize = Block->Size;
634
635 if (Block->Flags & 0x2F1) /* FIXME */
636 lphe->dwFlags = LF32_FIXED;
637 else if (Block->Flags & 0x20) /* FIXME */
638 lphe->dwFlags = LF32_MOVEABLE;
639 else if (Block->Flags & 0x100) /* FIXME */
640 lphe->dwFlags = LF32_FREE;
641
642 Status = STATUS_SUCCESS;
643 }
644 }
645
646 break;
647 }
648 }
649 }
650
651 RtlDestroyQueryDebugBuffer(DebugInfo);
652
653 if (!NT_SUCCESS(Status))
654 {
655 BaseSetLastNTError(Status);
656 return FALSE;
657 }
658
659 return TRUE;
660
661 }
662
663
664 /*
665 * @implemented
666 */
667 BOOL
668 WINAPI
669 Heap32ListFirst(HANDLE hSnapshot, LPHEAPLIST32 lphl)
670 {
671 PTH32SNAPSHOT Snapshot;
672 LARGE_INTEGER SOffset;
673 SIZE_T ViewSize;
674 NTSTATUS Status;
675
676 CHECK_PARAM_SIZE(lphl, sizeof(HEAPLIST32));
677
678 SOffset.QuadPart = 0;
679 ViewSize = 0;
680 Snapshot = NULL;
681
682 Status = NtMapViewOfSection(hSnapshot,
683 NtCurrentProcess(),
684 (PVOID*)&Snapshot,
685 0,
686 0,
687 &SOffset,
688 &ViewSize,
689 ViewShare,
690 0,
691 PAGE_READWRITE);
692 if(NT_SUCCESS(Status))
693 {
694 BOOL Ret;
695
696 if(Snapshot->HeapListCount > 0)
697 {
698 LPHEAPLIST32 Entries = (LPHEAPLIST32)OffsetToPtr(Snapshot, Snapshot->HeapListOffset);
699 Snapshot->HeapListIndex = 1;
700 RtlCopyMemory(lphl, &Entries[0], sizeof(HEAPLIST32));
701 Ret = TRUE;
702 }
703 else
704 {
705 SetLastError(ERROR_NO_MORE_FILES);
706 Ret = FALSE;
707 }
708
709 NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)Snapshot);
710 return Ret;
711 }
712
713 BaseSetLastNTError(Status);
714 return FALSE;
715 }
716
717
718 /*
719 * @implemented
720 */
721 BOOL
722 WINAPI
723 Heap32ListNext(HANDLE hSnapshot, LPHEAPLIST32 lphl)
724 {
725 PTH32SNAPSHOT Snapshot;
726 LARGE_INTEGER SOffset;
727 SIZE_T ViewSize;
728 NTSTATUS Status;
729
730 CHECK_PARAM_SIZE(lphl, sizeof(HEAPLIST32));
731
732 SOffset.QuadPart = 0;
733 ViewSize = 0;
734 Snapshot = NULL;
735
736 Status = NtMapViewOfSection(hSnapshot,
737 NtCurrentProcess(),
738 (PVOID*)&Snapshot,
739 0,
740 0,
741 &SOffset,
742 &ViewSize,
743 ViewShare,
744 0,
745 PAGE_READWRITE);
746 if(NT_SUCCESS(Status))
747 {
748 BOOL Ret;
749
750 if(Snapshot->HeapListCount > 0 &&
751 Snapshot->HeapListIndex < Snapshot->HeapListCount)
752 {
753 LPHEAPLIST32 Entries = (LPHEAPLIST32)OffsetToPtr(Snapshot, Snapshot->HeapListOffset);
754 RtlCopyMemory(lphl, &Entries[Snapshot->HeapListIndex++], sizeof(HEAPLIST32));
755 Ret = TRUE;
756 }
757 else
758 {
759 SetLastError(ERROR_NO_MORE_FILES);
760 Ret = FALSE;
761 }
762
763 NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)Snapshot);
764 return Ret;
765 }
766
767 BaseSetLastNTError(Status);
768 return FALSE;
769 }
770
771
772 /*
773 * @implemented
774 */
775 BOOL
776 WINAPI
777 Module32First(HANDLE hSnapshot, LPMODULEENTRY32 lpme)
778 {
779 MODULEENTRY32W me;
780 BOOL Ret;
781
782 CHECK_PARAM_SIZEA(lpme, sizeof(MODULEENTRY32));
783
784 me.dwSize = sizeof(MODULEENTRY32W);
785
786 Ret = Module32FirstW(hSnapshot, &me);
787 if(Ret)
788 {
789 lpme->th32ModuleID = me.th32ModuleID;
790 lpme->th32ProcessID = me.th32ProcessID;
791 lpme->GlblcntUsage = me.GlblcntUsage;
792 lpme->ProccntUsage = me.ProccntUsage;
793 lpme->modBaseAddr = me.modBaseAddr;
794 lpme->modBaseSize = me.modBaseSize;
795 lpme->hModule = me.hModule;
796
797 WideCharToMultiByte(CP_ACP, 0, me.szModule, -1, lpme->szModule, sizeof(lpme->szModule), 0, 0);
798 WideCharToMultiByte(CP_ACP, 0, me.szExePath, -1, lpme->szExePath, sizeof(lpme->szExePath), 0, 0);
799 }
800
801 return Ret;
802 }
803
804
805 /*
806 * @implemented
807 */
808 BOOL
809 WINAPI
810 Module32FirstW(HANDLE hSnapshot, LPMODULEENTRY32W lpme)
811 {
812 PTH32SNAPSHOT Snapshot;
813 LARGE_INTEGER SOffset;
814 SIZE_T ViewSize;
815 NTSTATUS Status;
816
817 CHECK_PARAM_SIZE(lpme, sizeof(MODULEENTRY32W));
818
819 SOffset.QuadPart = 0;
820 ViewSize = 0;
821 Snapshot = NULL;
822
823 Status = NtMapViewOfSection(hSnapshot,
824 NtCurrentProcess(),
825 (PVOID*)&Snapshot,
826 0,
827 0,
828 &SOffset,
829 &ViewSize,
830 ViewShare,
831 0,
832 PAGE_READWRITE);
833 if(NT_SUCCESS(Status))
834 {
835 BOOL Ret;
836
837 if(Snapshot->ModuleListCount > 0)
838 {
839 LPMODULEENTRY32W Entries = (LPMODULEENTRY32W)OffsetToPtr(Snapshot, Snapshot->ModuleListOffset);
840 Snapshot->ModuleListIndex = 1;
841 RtlCopyMemory(lpme, &Entries[0], sizeof(MODULEENTRY32W));
842 Ret = TRUE;
843 }
844 else
845 {
846 SetLastError(ERROR_NO_MORE_FILES);
847 Ret = FALSE;
848 }
849
850 NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)Snapshot);
851 return Ret;
852 }
853
854 BaseSetLastNTError(Status);
855 return FALSE;
856 }
857
858
859 /*
860 * @implemented
861 */
862 BOOL
863 WINAPI
864 Module32Next(HANDLE hSnapshot, LPMODULEENTRY32 lpme)
865 {
866 MODULEENTRY32W me;
867 BOOL Ret;
868
869 CHECK_PARAM_SIZEA(lpme, sizeof(MODULEENTRY32));
870
871 me.dwSize = sizeof(MODULEENTRY32W);
872
873 Ret = Module32NextW(hSnapshot, &me);
874 if(Ret)
875 {
876 lpme->th32ModuleID = me.th32ModuleID;
877 lpme->th32ProcessID = me.th32ProcessID;
878 lpme->GlblcntUsage = me.GlblcntUsage;
879 lpme->ProccntUsage = me.ProccntUsage;
880 lpme->modBaseAddr = me.modBaseAddr;
881 lpme->modBaseSize = me.modBaseSize;
882 lpme->hModule = me.hModule;
883
884 WideCharToMultiByte(CP_ACP, 0, me.szModule, -1, lpme->szModule, sizeof(lpme->szModule), 0, 0);
885 WideCharToMultiByte(CP_ACP, 0, me.szExePath, -1, lpme->szExePath, sizeof(lpme->szExePath), 0, 0);
886 }
887
888 return Ret;
889 }
890
891
892 /*
893 * @implemented
894 */
895 BOOL
896 WINAPI
897 Module32NextW(HANDLE hSnapshot, LPMODULEENTRY32W lpme)
898 {
899 PTH32SNAPSHOT Snapshot;
900 LARGE_INTEGER SOffset;
901 SIZE_T ViewSize;
902 NTSTATUS Status;
903
904 CHECK_PARAM_SIZE(lpme, sizeof(MODULEENTRY32W));
905
906 SOffset.QuadPart = 0;
907 ViewSize = 0;
908 Snapshot = NULL;
909
910 Status = NtMapViewOfSection(hSnapshot,
911 NtCurrentProcess(),
912 (PVOID*)&Snapshot,
913 0,
914 0,
915 &SOffset,
916 &ViewSize,
917 ViewShare,
918 0,
919 PAGE_READWRITE);
920 if(NT_SUCCESS(Status))
921 {
922 BOOL Ret;
923
924 if((Snapshot->ModuleListCount > 0) &&
925 (Snapshot->ModuleListIndex < Snapshot->ModuleListCount))
926 {
927 LPMODULEENTRY32W Entries = (LPMODULEENTRY32W)OffsetToPtr(Snapshot, Snapshot->ModuleListOffset);
928 RtlCopyMemory(lpme, &Entries[Snapshot->ModuleListIndex++], sizeof(MODULEENTRY32W));
929 Ret = TRUE;
930 }
931 else
932 {
933 SetLastError(ERROR_NO_MORE_FILES);
934 Ret = FALSE;
935 }
936
937 NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)Snapshot);
938 return Ret;
939 }
940
941 BaseSetLastNTError(Status);
942 return FALSE;
943 }
944
945
946 /*
947 * @implemented
948 */
949 BOOL
950 WINAPI
951 Process32First(HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
952 {
953 PROCESSENTRY32W pe;
954 BOOL Ret;
955
956 CHECK_PARAM_SIZEA(lppe, sizeof(PROCESSENTRY32));
957
958 pe.dwSize = sizeof(PROCESSENTRY32W);
959
960 Ret = Process32FirstW(hSnapshot, &pe);
961 if(Ret)
962 {
963 lppe->cntUsage = pe.cntUsage;
964 lppe->th32ProcessID = pe.th32ProcessID;
965 lppe->th32DefaultHeapID = pe.th32DefaultHeapID;
966 lppe->th32ModuleID = pe.th32ModuleID;
967 lppe->cntThreads = pe.cntThreads;
968 lppe->th32ParentProcessID = pe.th32ParentProcessID;
969 lppe->pcPriClassBase = pe.pcPriClassBase;
970 lppe->dwFlags = pe.dwFlags;
971
972 WideCharToMultiByte(CP_ACP, 0, pe.szExeFile, -1, lppe->szExeFile, sizeof(lppe->szExeFile), 0, 0);
973 }
974
975 return Ret;
976 }
977
978
979 /*
980 * @implemented
981 */
982 BOOL
983 WINAPI
984 Process32FirstW(HANDLE hSnapshot, LPPROCESSENTRY32W lppe)
985 {
986 PTH32SNAPSHOT Snapshot;
987 LARGE_INTEGER SOffset;
988 SIZE_T ViewSize;
989 NTSTATUS Status;
990
991 CHECK_PARAM_SIZE(lppe, sizeof(PROCESSENTRY32W));
992
993 SOffset.QuadPart = 0;
994 ViewSize = 0;
995 Snapshot = NULL;
996
997 Status = NtMapViewOfSection(hSnapshot,
998 NtCurrentProcess(),
999 (PVOID*)&Snapshot,
1000 0,
1001 0,
1002 &SOffset,
1003 &ViewSize,
1004 ViewShare,
1005 0,
1006 PAGE_READWRITE);
1007 if(NT_SUCCESS(Status))
1008 {
1009 BOOL Ret;
1010
1011 if(Snapshot->ProcessListCount > 0)
1012 {
1013 LPPROCESSENTRY32W Entries = (LPPROCESSENTRY32W)OffsetToPtr(Snapshot, Snapshot->ProcessListOffset);
1014
1015 Snapshot->ProcessListIndex = 1;
1016 RtlCopyMemory(lppe, &Entries[0], sizeof(PROCESSENTRY32W));
1017 Ret = TRUE;
1018 }
1019 else
1020 {
1021
1022 SetLastError(ERROR_NO_MORE_FILES);
1023 Ret = FALSE;
1024 }
1025
1026 NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)Snapshot);
1027 return Ret;
1028 }
1029
1030 BaseSetLastNTError(Status);
1031 return FALSE;
1032 }
1033
1034
1035 /*
1036 * @implemented
1037 */
1038 BOOL
1039 WINAPI
1040 Process32Next(HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
1041 {
1042 PROCESSENTRY32W pe;
1043 BOOL Ret;
1044
1045 CHECK_PARAM_SIZEA(lppe, sizeof(PROCESSENTRY32));
1046
1047 pe.dwSize = sizeof(PROCESSENTRY32W);
1048
1049 Ret = Process32NextW(hSnapshot, &pe);
1050 if(Ret)
1051 {
1052 lppe->cntUsage = pe.cntUsage;
1053 lppe->th32ProcessID = pe.th32ProcessID;
1054 lppe->th32DefaultHeapID = pe.th32DefaultHeapID;
1055 lppe->th32ModuleID = pe.th32ModuleID;
1056 lppe->cntThreads = pe.cntThreads;
1057 lppe->th32ParentProcessID = pe.th32ParentProcessID;
1058 lppe->pcPriClassBase = pe.pcPriClassBase;
1059 lppe->dwFlags = pe.dwFlags;
1060
1061 WideCharToMultiByte(CP_ACP, 0, pe.szExeFile, -1, lppe->szExeFile, sizeof(lppe->szExeFile), 0, 0);
1062 }
1063
1064 return Ret;
1065 }
1066
1067
1068 /*
1069 * @implemented
1070 */
1071 BOOL
1072 WINAPI
1073 Process32NextW(HANDLE hSnapshot, LPPROCESSENTRY32W lppe)
1074 {
1075 PTH32SNAPSHOT Snapshot;
1076 LARGE_INTEGER SOffset;
1077 SIZE_T ViewSize;
1078 NTSTATUS Status;
1079
1080 CHECK_PARAM_SIZE(lppe, sizeof(PROCESSENTRY32W));
1081
1082 SOffset.QuadPart = 0;
1083 ViewSize = 0;
1084 Snapshot = NULL;
1085
1086 Status = NtMapViewOfSection(hSnapshot,
1087 NtCurrentProcess(),
1088 (PVOID*)&Snapshot,
1089 0,
1090 0,
1091 &SOffset,
1092 &ViewSize,
1093 ViewShare,
1094 0,
1095 PAGE_READWRITE);
1096 if(NT_SUCCESS(Status))
1097 {
1098 BOOL Ret;
1099
1100 if(Snapshot->ProcessListCount > 0 &&
1101 Snapshot->ProcessListIndex < Snapshot->ProcessListCount)
1102 {
1103 LPPROCESSENTRY32W Entries = (LPPROCESSENTRY32W)OffsetToPtr(Snapshot, Snapshot->ProcessListOffset);
1104 RtlCopyMemory(lppe, &Entries[Snapshot->ProcessListIndex++], sizeof(PROCESSENTRY32W));
1105 Ret = TRUE;
1106 }
1107 else
1108 {
1109 SetLastError(ERROR_NO_MORE_FILES);
1110 Ret = FALSE;
1111 }
1112
1113 NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)Snapshot);
1114 return Ret;
1115 }
1116
1117 BaseSetLastNTError(Status);
1118 return FALSE;
1119 }
1120
1121
1122 /*
1123 * @implemented
1124 */
1125 BOOL
1126 WINAPI
1127 Thread32First(HANDLE hSnapshot, LPTHREADENTRY32 lpte)
1128 {
1129 PTH32SNAPSHOT Snapshot;
1130 LARGE_INTEGER SOffset;
1131 SIZE_T ViewSize;
1132 NTSTATUS Status;
1133
1134 CHECK_PARAM_SIZE(lpte, sizeof(THREADENTRY32));
1135
1136 SOffset.QuadPart = 0;
1137 ViewSize = 0;
1138 Snapshot = NULL;
1139
1140 Status = NtMapViewOfSection(hSnapshot,
1141 NtCurrentProcess(),
1142 (PVOID*)&Snapshot,
1143 0,
1144 0,
1145 &SOffset,
1146 &ViewSize,
1147 ViewShare,
1148 0,
1149 PAGE_READWRITE);
1150 if(NT_SUCCESS(Status))
1151 {
1152 BOOL Ret;
1153
1154 if(Snapshot->ThreadListCount > 0)
1155 {
1156 LPTHREADENTRY32 Entries = (LPTHREADENTRY32)OffsetToPtr(Snapshot, Snapshot->ThreadListOffset);
1157 Snapshot->ThreadListIndex = 1;
1158 RtlCopyMemory(lpte, &Entries[0], sizeof(THREADENTRY32));
1159 Ret = TRUE;
1160 }
1161 else
1162 {
1163 SetLastError(ERROR_NO_MORE_FILES);
1164 Ret = FALSE;
1165 }
1166
1167 NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)Snapshot);
1168 return Ret;
1169 }
1170
1171 BaseSetLastNTError(Status);
1172 return FALSE;
1173 }
1174
1175
1176 /*
1177 * @implemented
1178 */
1179 BOOL
1180 WINAPI
1181 Thread32Next(HANDLE hSnapshot, LPTHREADENTRY32 lpte)
1182 {
1183 PTH32SNAPSHOT Snapshot;
1184 LARGE_INTEGER SOffset;
1185 SIZE_T ViewSize;
1186 NTSTATUS Status;
1187
1188 CHECK_PARAM_SIZE(lpte, sizeof(THREADENTRY32));
1189
1190 SOffset.QuadPart = 0;
1191 ViewSize = 0;
1192 Snapshot = NULL;
1193
1194 Status = NtMapViewOfSection(hSnapshot,
1195 NtCurrentProcess(),
1196 (PVOID*)&Snapshot,
1197 0,
1198 0,
1199 &SOffset,
1200 &ViewSize,
1201 ViewShare,
1202 0,
1203 PAGE_READWRITE);
1204 if(NT_SUCCESS(Status))
1205 {
1206 BOOL Ret;
1207
1208 if(Snapshot->ThreadListCount > 0 &&
1209 Snapshot->ThreadListIndex < Snapshot->ThreadListCount)
1210 {
1211 LPTHREADENTRY32 Entries = (LPTHREADENTRY32)OffsetToPtr(Snapshot, Snapshot->ThreadListOffset);
1212 RtlCopyMemory(lpte, &Entries[Snapshot->ThreadListIndex++], sizeof(THREADENTRY32));
1213 Ret = TRUE;
1214 }
1215 else
1216 {
1217 SetLastError(ERROR_NO_MORE_FILES);
1218 Ret = FALSE;
1219 }
1220
1221 NtUnmapViewOfSection(NtCurrentProcess(), (PVOID)Snapshot);
1222 return Ret;
1223 }
1224
1225 BaseSetLastNTError(Status);
1226 return FALSE;
1227 }
1228
1229
1230 /*
1231 * @implemented
1232 */
1233 BOOL
1234 WINAPI
1235 Toolhelp32ReadProcessMemory(DWORD th32ProcessID, LPCVOID lpBaseAddress,
1236 LPVOID lpBuffer, SIZE_T cbRead, SIZE_T* lpNumberOfBytesRead)
1237 {
1238 HANDLE hProcess = OpenProcess(PROCESS_VM_READ, FALSE, th32ProcessID);
1239 if(hProcess != NULL)
1240 {
1241 BOOL Ret = ReadProcessMemory(hProcess, lpBaseAddress, lpBuffer, cbRead, lpNumberOfBytesRead);
1242 CloseHandle(hProcess);
1243 return Ret;
1244 }
1245
1246 return FALSE;
1247 }
1248
1249
1250 /*
1251 * @implemented
1252 */
1253 HANDLE
1254 WINAPI
1255 CreateToolhelp32Snapshot(DWORD dwFlags, DWORD th32ProcessID)
1256 {
1257 PRTL_DEBUG_INFORMATION HeapDebug, ModuleDebug;
1258 PVOID ProcThrdInfo;
1259 SIZE_T ProcThrdInfoSize;
1260 NTSTATUS Status;
1261 HANDLE hSnapShotSection = NULL;
1262
1263 if(th32ProcessID == 0)
1264 {
1265 th32ProcessID = GetCurrentProcessId();
1266 }
1267
1268 /*
1269 * Get all information required for the snapshot
1270 */
1271 Status = TH32CreateSnapshot(dwFlags,
1272 th32ProcessID,
1273 &HeapDebug,
1274 &ModuleDebug,
1275 &ProcThrdInfo,
1276 &ProcThrdInfoSize);
1277 if(!NT_SUCCESS(Status))
1278 {
1279 BaseSetLastNTError(Status);
1280 return NULL;
1281 }
1282
1283 /*
1284 * Create a section handle and initialize the collected information
1285 */
1286 Status = TH32CreateSnapshotSectionInitialize(dwFlags,
1287 th32ProcessID,
1288 HeapDebug,
1289 ModuleDebug,
1290 ProcThrdInfo,
1291 &hSnapShotSection);
1292
1293 /*
1294 * Free the temporarily allocated memory which is no longer needed
1295 */
1296 TH32FreeAllocatedResources(HeapDebug,
1297 ModuleDebug,
1298 ProcThrdInfo,
1299 ProcThrdInfoSize);
1300
1301 if(!NT_SUCCESS(Status))
1302 {
1303 BaseSetLastNTError(Status);
1304 return NULL;
1305 }
1306
1307 return hSnapShotSection;
1308 }
1309
1310 /* EOF */