amstream: Implement AMAudioStream::NewSegment.
[wine/zf.git] / dlls / kernel32 / toolhelp.c
blobd55e8185f2952625d948d2797757c3bd8907caad
1 /*
2 * Misc Toolhelp functions
4 * Copyright 1996 Marcus Meissner
5 * Copyright 2005 Eric Pouech
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "config.h"
24 #include <stdarg.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #ifdef HAVE_UNISTD_H
28 # include <unistd.h>
29 #endif
30 #include <ctype.h>
31 #include <assert.h>
32 #include "ntstatus.h"
33 #define WIN32_NO_STATUS
34 #include "windef.h"
35 #include "winbase.h"
36 #include "winerror.h"
37 #include "tlhelp32.h"
38 #include "winnls.h"
39 #include "winternl.h"
41 #include "kernel_private.h"
42 #include "wine/debug.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(toolhelp);
46 struct snapshot
48 int process_count;
49 int process_pos;
50 int process_offset;
51 int thread_count;
52 int thread_pos;
53 int thread_offset;
54 int module_count;
55 int module_pos;
56 int module_offset;
57 char data[1];
60 static WCHAR *fetch_string( HANDLE hProcess, UNICODE_STRING* us)
62 WCHAR* local;
64 local = HeapAlloc( GetProcessHeap(), 0, us->Length );
65 if (local)
67 if (!ReadProcessMemory( hProcess, us->Buffer, local, us->Length, NULL))
69 HeapFree( GetProcessHeap(), 0, local );
70 local = NULL;
73 us->Buffer = local;
74 return local;
77 static BOOL fetch_module( DWORD process, DWORD flags, LDR_DATA_TABLE_ENTRY **ldr_mod, ULONG *num )
79 HANDLE hProcess;
80 PROCESS_BASIC_INFORMATION pbi;
81 PPEB_LDR_DATA pLdrData;
82 PLIST_ENTRY head, curr;
83 BOOL ret = FALSE;
85 *num = 0;
87 if (!(flags & TH32CS_SNAPMODULE)) return TRUE;
89 if (process)
91 hProcess = OpenProcess( PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, process );
92 if (!hProcess) return FALSE;
94 else
95 hProcess = GetCurrentProcess();
97 if (set_ntstatus( NtQueryInformationProcess( hProcess, ProcessBasicInformation,
98 &pbi, sizeof(pbi), NULL )))
100 if (ReadProcessMemory( hProcess, &pbi.PebBaseAddress->LdrData,
101 &pLdrData, sizeof(pLdrData), NULL ) &&
102 ReadProcessMemory( hProcess,
103 &pLdrData->InLoadOrderModuleList.Flink,
104 &curr, sizeof(curr), NULL ))
106 head = &pLdrData->InLoadOrderModuleList;
108 while (curr != head)
110 if (!*num)
111 *ldr_mod = HeapAlloc( GetProcessHeap(), 0, sizeof(LDR_DATA_TABLE_ENTRY) );
112 else
113 *ldr_mod = HeapReAlloc( GetProcessHeap(), 0, *ldr_mod,
114 (*num + 1) * sizeof(LDR_DATA_TABLE_ENTRY) );
115 if (!*ldr_mod) break;
116 if (!ReadProcessMemory( hProcess,
117 CONTAINING_RECORD(curr, LDR_DATA_TABLE_ENTRY,
118 InLoadOrderLinks),
119 &(*ldr_mod)[*num],
120 sizeof(LDR_DATA_TABLE_ENTRY), NULL))
121 break;
122 curr = (*ldr_mod)[*num].InLoadOrderLinks.Flink;
123 /* if we cannot fetch the strings, then just ignore this LDR_DATA_TABLE_ENTRY
124 * and continue loading the other ones in the list
126 if (!fetch_string( hProcess, &(*ldr_mod)[*num].BaseDllName )) continue;
127 if (fetch_string( hProcess, &(*ldr_mod)[*num].FullDllName ))
128 (*num)++;
129 else
130 HeapFree( GetProcessHeap(), 0, (*ldr_mod)[*num].BaseDllName.Buffer );
132 ret = TRUE;
136 if (process) CloseHandle( hProcess );
137 return ret;
140 static void fill_module( struct snapshot* snap, ULONG* offset, ULONG process,
141 LDR_DATA_TABLE_ENTRY* ldr_mod, ULONG num )
143 MODULEENTRY32W* mod;
144 ULONG i;
145 SIZE_T l;
147 snap->module_count = num;
148 snap->module_pos = 0;
149 if (!num) return;
150 snap->module_offset = *offset;
152 mod = (MODULEENTRY32W*)&snap->data[*offset];
154 for (i = 0; i < num; i++)
156 mod->dwSize = sizeof(MODULEENTRY32W);
157 mod->th32ModuleID = 1; /* toolhelp internal id, never used */
158 mod->th32ProcessID = process ? process : GetCurrentProcessId();
159 mod->GlblcntUsage = 0xFFFF; /* FIXME */
160 mod->ProccntUsage = 0xFFFF; /* FIXME */
161 mod->modBaseAddr = ldr_mod[i].DllBase;
162 mod->modBaseSize = ldr_mod[i].SizeOfImage;
163 mod->hModule = ldr_mod[i].DllBase;
165 l = min(ldr_mod[i].BaseDllName.Length, sizeof(mod->szModule) - sizeof(WCHAR));
166 memcpy(mod->szModule, ldr_mod[i].BaseDllName.Buffer, l);
167 mod->szModule[l / sizeof(WCHAR)] = '\0';
168 l = min(ldr_mod[i].FullDllName.Length, sizeof(mod->szExePath) - sizeof(WCHAR));
169 memcpy(mod->szExePath, ldr_mod[i].FullDllName.Buffer, l);
170 mod->szExePath[l / sizeof(WCHAR)] = '\0';
172 mod++;
175 *offset += num * sizeof(MODULEENTRY32W);
178 static BOOL fetch_process_thread( DWORD flags, SYSTEM_PROCESS_INFORMATION** pspi,
179 ULONG* num_pcs, ULONG* num_thd)
181 NTSTATUS status;
182 ULONG size, offset;
183 PSYSTEM_PROCESS_INFORMATION spi;
185 *num_pcs = *num_thd = 0;
186 if (!(flags & (TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD))) return TRUE;
188 *pspi = HeapAlloc( GetProcessHeap(), 0, size = 4096 );
189 for (;;)
191 status = NtQuerySystemInformation( SystemProcessInformation, *pspi,
192 size, NULL );
193 switch (status)
195 case STATUS_SUCCESS:
196 *num_pcs = *num_thd = offset = 0;
197 spi = *pspi;
200 spi = (SYSTEM_PROCESS_INFORMATION*)((char*)spi + offset);
201 if (flags & TH32CS_SNAPPROCESS) (*num_pcs)++;
202 if (flags & TH32CS_SNAPTHREAD) *num_thd += spi->dwThreadCount;
203 } while ((offset = spi->NextEntryOffset));
204 return TRUE;
205 case STATUS_INFO_LENGTH_MISMATCH:
206 *pspi = HeapReAlloc( GetProcessHeap(), 0, *pspi, size *= 2 );
207 break;
208 default:
209 SetLastError( RtlNtStatusToDosError( status ) );
210 return FALSE;
215 static void fill_process( struct snapshot* snap, ULONG* offset,
216 SYSTEM_PROCESS_INFORMATION* spi, ULONG num )
218 PROCESSENTRY32W* pcs_entry;
219 ULONG poff = 0;
220 SIZE_T l;
222 snap->process_count = num;
223 snap->process_pos = 0;
224 if (!num) return;
225 snap->process_offset = *offset;
227 pcs_entry = (PROCESSENTRY32W*)&snap->data[*offset];
231 spi = (SYSTEM_PROCESS_INFORMATION*)((char*)spi + poff);
233 pcs_entry->dwSize = sizeof(PROCESSENTRY32W);
234 pcs_entry->cntUsage = 0; /* MSDN says no longer used, always 0 */
235 pcs_entry->th32ProcessID = HandleToUlong(spi->UniqueProcessId);
236 pcs_entry->th32DefaultHeapID = 0; /* MSDN says no longer used, always 0 */
237 pcs_entry->th32ModuleID = 0; /* MSDN says no longer used, always 0 */
238 pcs_entry->cntThreads = spi->dwThreadCount;
239 pcs_entry->th32ParentProcessID = HandleToUlong(spi->ParentProcessId);
240 pcs_entry->pcPriClassBase = spi->dwBasePriority;
241 pcs_entry->dwFlags = 0; /* MSDN says no longer used, always 0 */
242 l = min(spi->ProcessName.Length, sizeof(pcs_entry->szExeFile) - sizeof(WCHAR));
243 memcpy(pcs_entry->szExeFile, spi->ProcessName.Buffer, l);
244 pcs_entry->szExeFile[l / sizeof(WCHAR)] = '\0';
245 pcs_entry++;
246 } while ((poff = spi->NextEntryOffset));
248 *offset += num * sizeof(PROCESSENTRY32W);
251 static void fill_thread( struct snapshot* snap, ULONG* offset, LPVOID info, ULONG num )
253 THREADENTRY32* thd_entry;
254 SYSTEM_PROCESS_INFORMATION* spi;
255 SYSTEM_THREAD_INFORMATION* sti;
256 ULONG i, poff = 0;
258 snap->thread_count = num;
259 snap->thread_pos = 0;
260 if (!num) return;
261 snap->thread_offset = *offset;
263 thd_entry = (THREADENTRY32*)&snap->data[*offset];
265 spi = info;
268 spi = (SYSTEM_PROCESS_INFORMATION*)((char*)spi + poff);
269 sti = &spi->ti[0];
271 for (i = 0; i < spi->dwThreadCount; i++)
273 thd_entry->dwSize = sizeof(THREADENTRY32);
274 thd_entry->cntUsage = 0; /* MSDN says no longer used, always 0 */
275 thd_entry->th32ThreadID = HandleToUlong(sti->ClientId.UniqueThread);
276 thd_entry->th32OwnerProcessID = HandleToUlong(sti->ClientId.UniqueProcess);
277 thd_entry->tpBasePri = sti->dwBasePriority;
278 thd_entry->tpDeltaPri = 0; /* MSDN says no longer used, always 0 */
279 thd_entry->dwFlags = 0; /* MSDN says no longer used, always 0" */
281 sti++;
282 thd_entry++;
284 } while ((poff = spi->NextEntryOffset));
285 *offset += num * sizeof(THREADENTRY32);
288 /***********************************************************************
289 * CreateToolhelp32Snapshot (KERNEL32.@)
291 HANDLE WINAPI CreateToolhelp32Snapshot( DWORD flags, DWORD process )
293 SYSTEM_PROCESS_INFORMATION* spi = NULL;
294 LDR_DATA_TABLE_ENTRY *mod = NULL;
295 ULONG num_pcs, num_thd, num_mod;
296 HANDLE hSnapShot = 0;
298 TRACE("%x,%x\n", flags, process );
299 if (!(flags & (TH32CS_SNAPPROCESS|TH32CS_SNAPTHREAD|TH32CS_SNAPMODULE)))
301 FIXME("flags %x not implemented\n", flags );
302 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
303 return INVALID_HANDLE_VALUE;
306 if (fetch_module( process, flags, &mod, &num_mod ) &&
307 fetch_process_thread( flags, &spi, &num_pcs, &num_thd ))
309 ULONG sect_size;
310 struct snapshot*snap;
311 SECURITY_ATTRIBUTES sa;
313 /* create & fill the snapshot section */
314 sect_size = sizeof(struct snapshot) - 1; /* for last data[1] */
315 if (flags & TH32CS_SNAPMODULE) sect_size += num_mod * sizeof(MODULEENTRY32W);
316 if (flags & TH32CS_SNAPPROCESS) sect_size += num_pcs * sizeof(PROCESSENTRY32W);
317 if (flags & TH32CS_SNAPTHREAD) sect_size += num_thd * sizeof(THREADENTRY32);
318 if (flags & TH32CS_SNAPHEAPLIST)FIXME("Unimplemented: heap list snapshot\n");
320 sa.bInheritHandle = (flags & TH32CS_INHERIT) != 0;
321 sa.lpSecurityDescriptor = NULL;
323 hSnapShot = CreateFileMappingW( INVALID_HANDLE_VALUE, &sa,
324 SEC_COMMIT | PAGE_READWRITE,
325 0, sect_size, NULL );
326 if (hSnapShot && (snap = MapViewOfFile( hSnapShot, FILE_MAP_ALL_ACCESS, 0, 0, 0 )))
328 DWORD offset = 0;
330 fill_module( snap, &offset, process, mod, num_mod );
331 fill_process( snap, &offset, spi, num_pcs );
332 fill_thread( snap, &offset, spi, num_thd );
333 UnmapViewOfFile( snap );
337 while (num_mod--)
339 HeapFree( GetProcessHeap(), 0, mod[num_mod].BaseDllName.Buffer );
340 HeapFree( GetProcessHeap(), 0, mod[num_mod].FullDllName.Buffer );
342 HeapFree( GetProcessHeap(), 0, mod );
343 HeapFree( GetProcessHeap(), 0, spi );
345 if (!hSnapShot) return INVALID_HANDLE_VALUE;
346 return hSnapShot;
349 static BOOL next_thread( HANDLE hSnapShot, LPTHREADENTRY32 lpte, BOOL first )
351 struct snapshot* snap;
352 BOOL ret = FALSE;
354 if (lpte->dwSize < sizeof(THREADENTRY32))
356 SetLastError( ERROR_INSUFFICIENT_BUFFER );
357 WARN("Result buffer too small (%d)\n", lpte->dwSize);
358 return FALSE;
360 if ((snap = MapViewOfFile( hSnapShot, FILE_MAP_ALL_ACCESS, 0, 0, 0 )))
362 if (first) snap->thread_pos = 0;
363 if (snap->thread_pos < snap->thread_count)
365 LPTHREADENTRY32 te = (THREADENTRY32*)&snap->data[snap->thread_offset];
366 *lpte = te[snap->thread_pos++];
367 ret = TRUE;
369 else SetLastError( ERROR_NO_MORE_FILES );
370 UnmapViewOfFile( snap );
372 return ret;
375 /***********************************************************************
376 * Thread32First (KERNEL32.@)
378 * Return info about the first thread in a toolhelp32 snapshot
380 BOOL WINAPI Thread32First( HANDLE hSnapShot, LPTHREADENTRY32 lpte )
382 return next_thread( hSnapShot, lpte, TRUE );
385 /***********************************************************************
386 * Thread32Next (KERNEL32.@)
388 * Return info about the first thread in a toolhelp32 snapshot
390 BOOL WINAPI Thread32Next( HANDLE hSnapShot, LPTHREADENTRY32 lpte )
392 return next_thread( hSnapShot, lpte, FALSE );
395 /***********************************************************************
396 * process_next
398 * Implementation of Process32First/Next. Note that the ANSI / Unicode
399 * version check is a bit of a hack as it relies on the fact that only
400 * the last field is actually different.
402 static BOOL process_next( HANDLE hSnapShot, LPPROCESSENTRY32W lppe,
403 BOOL first, BOOL unicode )
405 struct snapshot* snap;
406 BOOL ret = FALSE;
407 DWORD sz = unicode ? sizeof(PROCESSENTRY32W) : sizeof(PROCESSENTRY32);
409 if (lppe->dwSize < sz)
411 SetLastError( ERROR_INSUFFICIENT_BUFFER );
412 WARN("Result buffer too small (%d)\n", lppe->dwSize);
413 return FALSE;
415 if ((snap = MapViewOfFile( hSnapShot, FILE_MAP_ALL_ACCESS, 0, 0, 0 )))
417 if (first) snap->process_pos = 0;
418 if (snap->process_pos < snap->process_count)
420 LPPROCESSENTRY32W pe = (PROCESSENTRY32W*)&snap->data[snap->process_offset];
421 if (unicode)
422 *lppe = pe[snap->process_pos];
423 else
425 lppe->cntUsage = pe[snap->process_pos].cntUsage;
426 lppe->th32ProcessID = pe[snap->process_pos].th32ProcessID;
427 lppe->th32DefaultHeapID = pe[snap->process_pos].th32DefaultHeapID;
428 lppe->th32ModuleID = pe[snap->process_pos].th32ModuleID;
429 lppe->cntThreads = pe[snap->process_pos].cntThreads;
430 lppe->th32ParentProcessID = pe[snap->process_pos].th32ParentProcessID;
431 lppe->pcPriClassBase = pe[snap->process_pos].pcPriClassBase;
432 lppe->dwFlags = pe[snap->process_pos].dwFlags;
434 WideCharToMultiByte( CP_ACP, 0, pe[snap->process_pos].szExeFile, -1,
435 (char*)lppe->szExeFile, sizeof(lppe->szExeFile),
436 0, 0 );
438 snap->process_pos++;
439 ret = TRUE;
441 else SetLastError( ERROR_NO_MORE_FILES );
442 UnmapViewOfFile( snap );
445 return ret;
449 /***********************************************************************
450 * Process32First (KERNEL32.@)
452 * Return info about the first process in a toolhelp32 snapshot
454 BOOL WINAPI Process32First(HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
456 return process_next( hSnapshot, (PROCESSENTRY32W*)lppe, TRUE, FALSE /* ANSI */ );
459 /***********************************************************************
460 * Process32Next (KERNEL32.@)
462 * Return info about the "next" process in a toolhelp32 snapshot
464 BOOL WINAPI Process32Next(HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
466 return process_next( hSnapshot, (PROCESSENTRY32W*)lppe, FALSE, FALSE /* ANSI */ );
469 /***********************************************************************
470 * Process32FirstW (KERNEL32.@)
472 * Return info about the first process in a toolhelp32 snapshot
474 BOOL WINAPI Process32FirstW(HANDLE hSnapshot, LPPROCESSENTRY32W lppe)
476 return process_next( hSnapshot, lppe, TRUE, TRUE /* Unicode */ );
479 /***********************************************************************
480 * Process32NextW (KERNEL32.@)
482 * Return info about the "next" process in a toolhelp32 snapshot
484 BOOL WINAPI Process32NextW(HANDLE hSnapshot, LPPROCESSENTRY32W lppe)
486 return process_next( hSnapshot, lppe, FALSE, TRUE /* Unicode */ );
489 /***********************************************************************
490 * module_nextW
492 * Implementation of Module32{First|Next}W
494 static BOOL module_nextW( HANDLE hSnapShot, LPMODULEENTRY32W lpme, BOOL first )
496 struct snapshot* snap;
497 BOOL ret = FALSE;
499 if (lpme->dwSize < sizeof (MODULEENTRY32W))
501 SetLastError( ERROR_INSUFFICIENT_BUFFER );
502 WARN("Result buffer too small (was: %d)\n", lpme->dwSize);
503 return FALSE;
505 if ((snap = MapViewOfFile( hSnapShot, FILE_MAP_ALL_ACCESS, 0, 0, 0 )))
507 if (first) snap->module_pos = 0;
508 if (snap->module_pos < snap->module_count)
510 LPMODULEENTRY32W pe = (MODULEENTRY32W*)&snap->data[snap->module_offset];
511 *lpme = pe[snap->module_pos++];
512 ret = TRUE;
514 else SetLastError( ERROR_NO_MORE_FILES );
515 UnmapViewOfFile( snap );
518 return ret;
521 /***********************************************************************
522 * Module32FirstW (KERNEL32.@)
524 * Return info about the "first" module in a toolhelp32 snapshot
526 BOOL WINAPI Module32FirstW(HANDLE hSnapshot, LPMODULEENTRY32W lpme)
528 return module_nextW( hSnapshot, lpme, TRUE );
531 /***********************************************************************
532 * Module32NextW (KERNEL32.@)
534 * Return info about the "next" module in a toolhelp32 snapshot
536 BOOL WINAPI Module32NextW(HANDLE hSnapshot, LPMODULEENTRY32W lpme)
538 return module_nextW( hSnapshot, lpme, FALSE );
541 /***********************************************************************
542 * module_nextA
544 * Implementation of Module32{First|Next}A
546 static BOOL module_nextA( HANDLE handle, LPMODULEENTRY32 lpme, BOOL first )
548 BOOL ret;
549 MODULEENTRY32W mew;
551 if (lpme->dwSize < sizeof(MODULEENTRY32))
553 SetLastError( ERROR_INSUFFICIENT_BUFFER );
554 WARN("Result buffer too small (was: %d)\n", lpme->dwSize);
555 return FALSE;
558 mew.dwSize = sizeof(mew);
559 if ((ret = module_nextW( handle, &mew, first )))
561 lpme->th32ModuleID = mew.th32ModuleID;
562 lpme->th32ProcessID = mew.th32ProcessID;
563 lpme->GlblcntUsage = mew.GlblcntUsage;
564 lpme->ProccntUsage = mew.ProccntUsage;
565 lpme->modBaseAddr = mew.modBaseAddr;
566 lpme->modBaseSize = mew.modBaseSize;
567 lpme->hModule = mew.hModule;
568 WideCharToMultiByte( CP_ACP, 0, mew.szModule, -1, lpme->szModule, sizeof(lpme->szModule), NULL, NULL );
569 WideCharToMultiByte( CP_ACP, 0, mew.szExePath, -1, lpme->szExePath, sizeof(lpme->szExePath), NULL, NULL );
571 return ret;
574 /***********************************************************************
575 * Module32First (KERNEL32.@)
577 * Return info about the "first" module in a toolhelp32 snapshot
579 BOOL WINAPI Module32First(HANDLE hSnapshot, LPMODULEENTRY32 lpme)
581 return module_nextA( hSnapshot, lpme, TRUE );
584 /***********************************************************************
585 * Module32Next (KERNEL32.@)
587 * Return info about the "next" module in a toolhelp32 snapshot
589 BOOL WINAPI Module32Next(HANDLE hSnapshot, LPMODULEENTRY32 lpme)
591 return module_nextA( hSnapshot, lpme, FALSE );
594 /************************************************************************
595 * Heap32ListFirst (KERNEL32.@)
598 BOOL WINAPI Heap32ListFirst(HANDLE hSnapshot, LPHEAPLIST32 lphl)
600 FIXME(": stub\n");
601 return FALSE;
604 /******************************************************************
605 * Toolhelp32ReadProcessMemory (KERNEL32.@)
609 BOOL WINAPI Toolhelp32ReadProcessMemory(DWORD pid, const void* base,
610 void* buf, SIZE_T len, SIZE_T* r)
612 HANDLE h;
613 BOOL ret = FALSE;
615 h = (pid) ? OpenProcess(PROCESS_VM_READ, FALSE, pid) : GetCurrentProcess();
616 if (h != NULL)
618 ret = ReadProcessMemory(h, base, buf, len, r);
619 if (pid) CloseHandle(h);
621 return ret;