toolhelp.c 20.6 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2 3 4
/*
 * Misc Toolhelp functions
 *
 * Copyright 1996 Marcus Meissner
5
 * Copyright 2005 Eric Pouech
6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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
Alexandre Julliard's avatar
Alexandre Julliard committed
20 21
 */

22 23
#include "config.h"

24
#include <stdarg.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
25 26
#include <stdlib.h>
#include <string.h>
27 28 29
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
Alexandre Julliard's avatar
Alexandre Julliard committed
30
#include <ctype.h>
31
#include <assert.h>
32 33
#include "ntstatus.h"
#define WIN32_NO_STATUS
34
#include "windef.h"
35
#include "winbase.h"
36 37
#include "winerror.h"
#include "tlhelp32.h"
38 39 40
#include "winnls.h"
#include "winternl.h"

41
#include "wine/debug.h"
42

43
WINE_DEFAULT_DEBUG_CHANNEL(toolhelp);
44

45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
struct snapshot
{
    int         process_count;
    int         process_pos;
    int         process_offset;
    int         thread_count;
    int         thread_pos;
    int         thread_offset;
    int         module_count;
    int         module_pos;
    int         module_offset;
    char        data[1];
};

static WCHAR *fetch_string( HANDLE hProcess, UNICODE_STRING* us)
{
    WCHAR*      local;

    local = HeapAlloc( GetProcessHeap(), 0, us->Length );
    if (local)
    {
        if (!ReadProcessMemory( hProcess, us->Buffer, local, us->Length, NULL))
        {
            HeapFree( GetProcessHeap(), 0, local );
            local = NULL;
        }
    }
    us->Buffer = local;
    return local;
}

static BOOL fetch_module( DWORD process, DWORD flags, LDR_MODULE** ldr_mod, ULONG* num )
{
    HANDLE                      hProcess;
    PROCESS_BASIC_INFORMATION   pbi;
    PPEB_LDR_DATA               pLdrData;
    NTSTATUS                    status;
    PLIST_ENTRY                 head, curr;
    BOOL                        ret = FALSE;

    *num = 0;

    if (!(flags & TH32CS_SNAPMODULE)) return TRUE;

    if (process)
    {
        hProcess = OpenProcess( PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, process );
        if (!hProcess) return FALSE;
    }
    else
        hProcess = GetCurrentProcess();

    status = NtQueryInformationProcess( hProcess, ProcessBasicInformation,
                                        &pbi, sizeof(pbi), NULL );
    if (!status)
    {
101
        if (ReadProcessMemory( hProcess, &pbi.PebBaseAddress->LdrData,
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
                               &pLdrData, sizeof(pLdrData), NULL ) &&
            ReadProcessMemory( hProcess,
                               &pLdrData->InLoadOrderModuleList.Flink,
                               &curr, sizeof(curr), NULL ))
        {
            head = &pLdrData->InLoadOrderModuleList;

            while (curr != head)
            {
                if (!*num)
                    *ldr_mod = HeapAlloc( GetProcessHeap(), 0, sizeof(LDR_MODULE) );
                else
                    *ldr_mod = HeapReAlloc( GetProcessHeap(), 0, *ldr_mod,
                                            (*num + 1) * sizeof(LDR_MODULE) );
                if (!*ldr_mod) break;
                if (!ReadProcessMemory( hProcess,
                                        CONTAINING_RECORD(curr, LDR_MODULE,
                                                          InLoadOrderModuleList),
                                        &(*ldr_mod)[*num],
                                        sizeof(LDR_MODULE), NULL))
                    break;
                curr = (*ldr_mod)[*num].InLoadOrderModuleList.Flink;
                /* if we cannot fetch the strings, then just ignore this LDR_MODULE
                 * and continue loading the other ones in the list
                 */
                if (!fetch_string( hProcess, &(*ldr_mod)[*num].BaseDllName )) continue;
                if (fetch_string( hProcess, &(*ldr_mod)[*num].FullDllName ))
                    (*num)++;
                else
                    HeapFree( GetProcessHeap(), 0, (*ldr_mod)[*num].BaseDllName.Buffer );
            }
            ret = TRUE;
        }
    }
    else SetLastError( RtlNtStatusToDosError( status ) );

    if (process) CloseHandle( hProcess );
    return ret;
}

static void fill_module( struct snapshot* snap, ULONG* offset, ULONG process,
                         LDR_MODULE* ldr_mod, ULONG num )
{
    MODULEENTRY32W*     mod;
    ULONG               i;
    SIZE_T              l;

    snap->module_count = num;
    snap->module_pos = 0;
    if (!num) return;
    snap->module_offset = *offset;

    mod = (MODULEENTRY32W*)&snap->data[*offset];

    for (i = 0; i < num; i++)
    {
        mod->dwSize = sizeof(MODULEENTRY32W);
        mod->th32ModuleID = 1; /* toolhelp internal id, never used */
        mod->th32ProcessID = process ? process : GetCurrentProcessId();
        mod->GlblcntUsage = 0xFFFF; /* FIXME */
        mod->ProccntUsage = 0xFFFF; /* FIXME */
        mod->modBaseAddr = (BYTE*)ldr_mod[i].BaseAddress;
        mod->modBaseSize = ldr_mod[i].SizeOfImage;
        mod->hModule = (HMODULE)ldr_mod[i].BaseAddress;

        l = min(ldr_mod[i].BaseDllName.Length, sizeof(mod->szModule) - sizeof(WCHAR));
        memcpy(mod->szModule, ldr_mod[i].BaseDllName.Buffer, l);
        mod->szModule[l / sizeof(WCHAR)] = '\0';
        l = min(ldr_mod[i].FullDllName.Length, sizeof(mod->szExePath) - sizeof(WCHAR));
        memcpy(mod->szExePath, ldr_mod[i].FullDllName.Buffer, l);
        mod->szExePath[l / sizeof(WCHAR)] = '\0';

        mod++;
    }

    *offset += num * sizeof(MODULEENTRY32W);
}

static BOOL fetch_process_thread( DWORD flags, SYSTEM_PROCESS_INFORMATION** pspi,
                                  ULONG* num_pcs, ULONG* num_thd)
{
    NTSTATUS                    status;
    ULONG                       size, offset;
    PSYSTEM_PROCESS_INFORMATION spi;

    *num_pcs = *num_thd = 0;
    if (!(flags & (TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD))) return TRUE;

    *pspi = HeapAlloc( GetProcessHeap(), 0, size = 4096 );
    for (;;)
    {
        status = NtQuerySystemInformation( SystemProcessInformation, *pspi,
                                           size, NULL );
        switch (status)
        {
        case STATUS_SUCCESS:
            *num_pcs = *num_thd = offset = 0;
            spi = *pspi;
            do
            {
                spi = (SYSTEM_PROCESS_INFORMATION*)((char*)spi + offset);
                if (flags & TH32CS_SNAPPROCESS) (*num_pcs)++;
                if (flags & TH32CS_SNAPTHREAD) *num_thd += spi->dwThreadCount;
            } while ((offset = spi->dwOffset));
            return TRUE;
        case STATUS_INFO_LENGTH_MISMATCH:
            *pspi = HeapReAlloc( GetProcessHeap(), 0, *pspi, size *= 2 );
            break;
        default:
            SetLastError( RtlNtStatusToDosError( status ) );
            break;
        }
    }
}

static void fill_process( struct snapshot* snap, ULONG* offset, 
                          SYSTEM_PROCESS_INFORMATION* spi, ULONG num )
{
    PROCESSENTRY32W*            pcs_entry;
    ULONG                       poff = 0;
    SIZE_T                      l;

    snap->process_count = num;
    snap->process_pos = 0;
    if (!num) return;
    snap->process_offset = *offset;

    pcs_entry = (PROCESSENTRY32W*)&snap->data[*offset];

    do
    {
        spi = (SYSTEM_PROCESS_INFORMATION*)((char*)spi + poff);

        pcs_entry->dwSize = sizeof(PROCESSENTRY32W);
        pcs_entry->cntUsage = 0; /* MSDN says no longer used, always 0 */
        pcs_entry->th32ProcessID = spi->dwProcessID;
        pcs_entry->th32DefaultHeapID = 0; /* MSDN says no longer used, always 0 */
        pcs_entry->th32ModuleID = 0; /* MSDN says no longer used, always 0 */
        pcs_entry->cntThreads = spi->dwThreadCount;
        pcs_entry->th32ParentProcessID = spi->dwParentProcessID;
        pcs_entry->pcPriClassBase = spi->dwBasePriority;
        pcs_entry->dwFlags = 0; /* MSDN says no longer used, always 0 */
        l = min(spi->ProcessName.Length, sizeof(pcs_entry->szExeFile) - sizeof(WCHAR));
        memcpy(pcs_entry->szExeFile, spi->ProcessName.Buffer, l);
        pcs_entry->szExeFile[l / sizeof(WCHAR)] = '\0';
        pcs_entry++;
    } while ((poff = spi->dwOffset));

    *offset += num * sizeof(PROCESSENTRY32W);
}

static void fill_thread( struct snapshot* snap, ULONG* offset, LPVOID info, ULONG num )
{
    THREADENTRY32*              thd_entry;
    SYSTEM_PROCESS_INFORMATION* spi;
    SYSTEM_THREAD_INFORMATION*  sti;
    ULONG                       i, poff = 0;

    snap->thread_count = num;
    snap->thread_pos = 0;
    if (!num) return;
    snap->thread_offset = *offset;

    thd_entry = (THREADENTRY32*)&snap->data[*offset];

    spi = (SYSTEM_PROCESS_INFORMATION*)info;
    do
    {
        spi = (SYSTEM_PROCESS_INFORMATION*)((char*)spi + poff);
        sti = &spi->ti[0];

        for (i = 0; i < spi->dwThreadCount; i++)
        {
            thd_entry->dwSize = sizeof(THREADENTRY32);
            thd_entry->cntUsage = 0; /* MSDN says no longer used, always 0 */
277 278
            thd_entry->th32ThreadID = sti->dwThreadID;
            thd_entry->th32OwnerProcessID = sti->dwOwningPID;
279 280 281 282 283 284 285 286 287 288
            thd_entry->tpBasePri = sti->dwBasePriority;
            thd_entry->tpDeltaPri = 0; /* MSDN says no longer used, always 0 */
            thd_entry->dwFlags = 0; /* MSDN says no longer used, always 0" */

            sti++;
            thd_entry++;
      }
    } while ((poff = spi->dwOffset));
    *offset += num * sizeof(THREADENTRY32);
}
289

Alexandre Julliard's avatar
Alexandre Julliard committed
290
/***********************************************************************
291
 *           CreateToolhelp32Snapshot			(KERNEL32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
292
 */
293
HANDLE WINAPI CreateToolhelp32Snapshot( DWORD flags, DWORD process )
294
{
295 296 297 298
    SYSTEM_PROCESS_INFORMATION* spi = NULL;
    LDR_MODULE*         mod = NULL;
    ULONG               num_pcs, num_thd, num_mod;
    HANDLE              hSnapShot = 0;
299

300
    TRACE("%x,%x\n", flags, process );
301
    if (!(flags & (TH32CS_SNAPPROCESS|TH32CS_SNAPTHREAD|TH32CS_SNAPMODULE)))
302
    {
303
        FIXME("flags %x not implemented\n", flags );
304
        SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
305
        return INVALID_HANDLE_VALUE;
306
    }
307

308 309
    if (fetch_module( process, flags, &mod, &num_mod ) &&
        fetch_process_thread( flags, &spi, &num_pcs, &num_thd ))
310
    {
311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336
        ULONG sect_size;
        struct snapshot*snap;
        SECURITY_ATTRIBUTES sa;

        /* create & fill the snapshot section */
        sect_size = sizeof(struct snapshot) - 1; /* for last data[1] */
        if (flags & TH32CS_SNAPMODULE)  sect_size += num_mod * sizeof(MODULEENTRY32W);
        if (flags & TH32CS_SNAPPROCESS) sect_size += num_pcs * sizeof(PROCESSENTRY32W);
        if (flags & TH32CS_SNAPTHREAD)  sect_size += num_thd * sizeof(THREADENTRY32);
        if (flags & TH32CS_SNAPHEAPLIST)FIXME("Unimplemented: heap list snapshot\n");

        sa.bInheritHandle = (flags & TH32CS_INHERIT) ? TRUE : FALSE;
        sa.lpSecurityDescriptor = NULL;

        hSnapShot = CreateFileMappingW( INVALID_HANDLE_VALUE, &sa,
                                        SEC_COMMIT | PAGE_READWRITE,
                                        0, sect_size, NULL );
        if (hSnapShot && (snap = MapViewOfFile( hSnapShot, FILE_MAP_ALL_ACCESS, 0, 0, 0 )))
        {
            DWORD   offset = 0;

            fill_module( snap, &offset, process, mod, num_mod );
            fill_process( snap, &offset, spi, num_pcs );
            fill_thread( snap, &offset, spi, num_thd );
            UnmapViewOfFile( snap );
        }
337
    }
338

339 340 341 342 343 344 345
    while (num_mod--)
    {
        HeapFree( GetProcessHeap(), 0, mod[num_mod].BaseDllName.Buffer );
        HeapFree( GetProcessHeap(), 0, mod[num_mod].FullDllName.Buffer );
    }
    HeapFree( GetProcessHeap(), 0, mod );
    HeapFree( GetProcessHeap(), 0, spi );
346

347 348 349 350 351
    if (!hSnapShot) return INVALID_HANDLE_VALUE;
    return hSnapShot;
}

static BOOL next_thread( HANDLE hSnapShot, LPTHREADENTRY32 lpte, BOOL first )
352
{
353 354
    struct snapshot*    snap;
    BOOL                ret = FALSE;
355 356 357 358

    if (lpte->dwSize < sizeof(THREADENTRY32))
    {
        SetLastError( ERROR_INSUFFICIENT_BUFFER );
359
        WARN("Result buffer too small (%d)\n", lpte->dwSize);
360 361
        return FALSE;
    }
362
    if ((snap = MapViewOfFile( hSnapShot, FILE_MAP_ALL_ACCESS, 0, 0, 0 )))
363
    {
364 365
        if (first) snap->thread_pos = 0;
        if (snap->thread_pos < snap->thread_count)
366
        {
367 368 369
            LPTHREADENTRY32 te = (THREADENTRY32*)&snap->data[snap->thread_offset];
            *lpte = te[snap->thread_pos++];
            ret = TRUE;
370
        }
371 372
        else SetLastError( ERROR_NO_MORE_FILES );
        UnmapViewOfFile( snap );
373 374
    }
    return ret;
375 376
}

377
/***********************************************************************
378
 *		Thread32First    (KERNEL32.@)
379 380 381
 *
 * Return info about the first thread in a toolhelp32 snapshot
 */
382
BOOL WINAPI Thread32First( HANDLE hSnapShot, LPTHREADENTRY32 lpte )
383
{
384
    return next_thread( hSnapShot, lpte, TRUE );
385 386 387
}

/***********************************************************************
388
 *		Thread32Next    (KERNEL32.@)
389
 *
390
 * Return info about the first thread in a toolhelp32 snapshot
391
 */
392
BOOL WINAPI Thread32Next( HANDLE hSnapShot, LPTHREADENTRY32 lpte )
393
{
394
    return next_thread( hSnapShot, lpte, FALSE );
395 396
}

397
/***********************************************************************
398
 *		process_next
399
 *
400 401 402
 * Implementation of Process32First/Next. Note that the ANSI / Unicode
 * version check is a bit of a hack as it relies on the fact that only
 * the last field is actually different.
403
 */
404 405
static BOOL process_next( HANDLE hSnapShot, LPPROCESSENTRY32W lppe,
                          BOOL first, BOOL unicode )
406
{
407 408 409
    struct snapshot*    snap;
    BOOL                ret = FALSE;
    DWORD               sz = unicode ? sizeof(PROCESSENTRY32W) : sizeof(PROCESSENTRY32);
410

411
    if (lppe->dwSize < sz)
412
    {
413
        SetLastError( ERROR_INSUFFICIENT_BUFFER );
414
        WARN("Result buffer too small (%d)\n", lppe->dwSize);
415
        return FALSE;
416
    }
417
    if ((snap = MapViewOfFile( hSnapShot, FILE_MAP_ALL_ACCESS, 0, 0, 0 )))
418
    {
419 420
        if (first) snap->process_pos = 0;
        if (snap->process_pos < snap->process_count)
421
        {
422
            LPPROCESSENTRY32W pe = (PROCESSENTRY32W*)&snap->data[snap->process_offset];
423
            if (unicode)
424
                *lppe = pe[snap->process_pos];
425 426
            else
            {
427 428 429 430 431 432 433 434 435 436 437 438
                lppe->cntUsage = pe[snap->process_pos].cntUsage;
                lppe->th32ProcessID = pe[snap->process_pos].th32ProcessID;
                lppe->th32DefaultHeapID = pe[snap->process_pos].th32DefaultHeapID;
                lppe->th32ModuleID = pe[snap->process_pos].th32ModuleID;
                lppe->cntThreads = pe[snap->process_pos].cntThreads;
                lppe->th32ParentProcessID = pe[snap->process_pos].th32ParentProcessID;
                lppe->pcPriClassBase = pe[snap->process_pos].pcPriClassBase;
                lppe->dwFlags = pe[snap->process_pos].dwFlags;

                WideCharToMultiByte( CP_ACP, 0, pe[snap->process_pos].szExeFile, -1,
                                     (char*)lppe->szExeFile, sizeof(lppe->szExeFile),
                                     0, 0 );
439
            }
440 441
            snap->process_pos++;
            ret = TRUE;
442
        }
443 444
        else SetLastError( ERROR_NO_MORE_FILES );
        UnmapViewOfFile( snap );
445
    }
446

447
    return ret;
448 449
}

450

451
/***********************************************************************
452
 *		Process32First    (KERNEL32.@)
453
 *
454 455
 * Return info about the first process in a toolhelp32 snapshot
 */
456
BOOL WINAPI Process32First(HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
457
{
458
    return process_next( hSnapshot, (PROCESSENTRY32W*)lppe, TRUE, FALSE /* ANSI */ );
459 460 461
}

/***********************************************************************
462
 *		Process32Next   (KERNEL32.@)
463
 *
464 465
 * Return info about the "next" process in a toolhelp32 snapshot
 */
466
BOOL WINAPI Process32Next(HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
467
{
468
    return process_next( hSnapshot, (PROCESSENTRY32W*)lppe, FALSE, FALSE /* ANSI */ );
469 470 471 472 473 474 475 476 477
}

/***********************************************************************
 *		Process32FirstW    (KERNEL32.@)
 *
 * Return info about the first process in a toolhelp32 snapshot
 */
BOOL WINAPI Process32FirstW(HANDLE hSnapshot, LPPROCESSENTRY32W lppe)
{
478
    return process_next( hSnapshot, lppe, TRUE, TRUE /* Unicode */ );
479 480 481 482 483 484 485 486 487
}

/***********************************************************************
 *		Process32NextW   (KERNEL32.@)
 *
 * Return info about the "next" process in a toolhelp32 snapshot
 */
BOOL WINAPI Process32NextW(HANDLE hSnapshot, LPPROCESSENTRY32W lppe)
{
488
    return process_next( hSnapshot, lppe, FALSE, TRUE /* Unicode */ );
Alexandre Julliard's avatar
Alexandre Julliard committed
489
}
Marcus Meissner's avatar
Marcus Meissner committed
490

491
/***********************************************************************
492
 *		module_nextW
493
 *
494
 * Implementation of Module32{First|Next}W
495
 */
496
static BOOL module_nextW( HANDLE hSnapShot, LPMODULEENTRY32W lpme, BOOL first )
497
{
498 499
    struct snapshot*    snap;
    BOOL                ret = FALSE;
500

501
    if (lpme->dwSize < sizeof (MODULEENTRY32W))
502 503
    {
        SetLastError( ERROR_INSUFFICIENT_BUFFER );
504
        WARN("Result buffer too small (was: %d)\n", lpme->dwSize);
505 506
        return FALSE;
    }
507
    if ((snap = MapViewOfFile( hSnapShot, FILE_MAP_ALL_ACCESS, 0, 0, 0 )))
508
    {
509 510
        if (first) snap->module_pos = 0;
        if (snap->module_pos < snap->module_count)
511
        {
512 513 514
            LPMODULEENTRY32W pe = (MODULEENTRY32W*)&snap->data[snap->module_offset];
            *lpme = pe[snap->module_pos++];
            ret = TRUE;
515
        }
516 517
        else SetLastError( ERROR_NO_MORE_FILES );
        UnmapViewOfFile( snap );
518
    }
519

520
    return ret;
521 522
}

523
/***********************************************************************
524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544
 *		Module32FirstW   (KERNEL32.@)
 *
 * Return info about the "first" module in a toolhelp32 snapshot
 */
BOOL WINAPI Module32FirstW(HANDLE hSnapshot, LPMODULEENTRY32W lpme)
{
    return module_nextW( hSnapshot, lpme, TRUE );
}

/***********************************************************************
 *		Module32NextW   (KERNEL32.@)
 *
 * Return info about the "next" module in a toolhelp32 snapshot
 */
BOOL WINAPI Module32NextW(HANDLE hSnapshot, LPMODULEENTRY32W lpme)
{
    return module_nextW( hSnapshot, lpme, FALSE );
}

/***********************************************************************
 *		module_nextA
545
 *
546
 * Implementation of Module32{First|Next}A
547
 */
548
static BOOL module_nextA( HANDLE handle, LPMODULEENTRY32 lpme, BOOL first )
549 550 551
{
    BOOL ret;
    MODULEENTRY32W mew;
552 553

    if (lpme->dwSize < sizeof(MODULEENTRY32))
554 555
    {
        SetLastError( ERROR_INSUFFICIENT_BUFFER );
556
        WARN("Result buffer too small (was: %d)\n", lpme->dwSize);
557 558
        return FALSE;
    }
559

560
    mew.dwSize = sizeof(mew);
561
    if ((ret = module_nextW( handle, &mew, first )))
562 563 564 565 566 567
    {
        lpme->th32ModuleID  = mew.th32ModuleID;
        lpme->th32ProcessID = mew.th32ProcessID;
        lpme->GlblcntUsage  = mew.GlblcntUsage;
        lpme->ProccntUsage  = mew.ProccntUsage;
        lpme->modBaseAddr   = mew.modBaseAddr;
568
        lpme->modBaseSize   = mew.modBaseSize;
569 570 571 572 573 574 575
        lpme->hModule       = mew.hModule;
        WideCharToMultiByte( CP_ACP, 0, mew.szModule, -1, lpme->szModule, sizeof(lpme->szModule), NULL, NULL );
        WideCharToMultiByte( CP_ACP, 0, mew.szExePath, -1, lpme->szExePath, sizeof(lpme->szExePath), NULL, NULL );
    }
    return ret;
}

Marcus Meissner's avatar
Marcus Meissner committed
576
/***********************************************************************
577
 *		Module32First   (KERNEL32.@)
Marcus Meissner's avatar
Marcus Meissner committed
578 579 580
 *
 * Return info about the "first" module in a toolhelp32 snapshot
 */
581
BOOL WINAPI Module32First(HANDLE hSnapshot, LPMODULEENTRY32 lpme)
Marcus Meissner's avatar
Marcus Meissner committed
582
{
583
    return module_nextA( hSnapshot, lpme, TRUE );
Marcus Meissner's avatar
Marcus Meissner committed
584 585 586
}

/***********************************************************************
587
 *		Module32Next   (KERNEL32.@)
Marcus Meissner's avatar
Marcus Meissner committed
588 589 590
 *
 * Return info about the "next" module in a toolhelp32 snapshot
 */
591
BOOL WINAPI Module32Next(HANDLE hSnapshot, LPMODULEENTRY32 lpme)
Marcus Meissner's avatar
Marcus Meissner committed
592
{
593
    return module_nextA( hSnapshot, lpme, FALSE );
Marcus Meissner's avatar
Marcus Meissner committed
594
}
595 596

/************************************************************************
597
 *              Heap32ListFirst (KERNEL32.@)
598 599 600 601 602 603 604
 *
 */
BOOL WINAPI Heap32ListFirst(HANDLE hSnapshot, LPHEAPLIST32 lphl)
{
    FIXME(": stub\n");
    return FALSE;
}
605 606

/******************************************************************
607
 *		Toolhelp32ReadProcessMemory (KERNEL32.@)
608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624
 *
 *
 */
BOOL WINAPI Toolhelp32ReadProcessMemory(DWORD pid, const void* base,
                                        void* buf, SIZE_T len, SIZE_T* r)
{
    HANDLE h;
    BOOL   ret = FALSE;

    h = (pid) ? OpenProcess(PROCESS_VM_READ, FALSE, pid) : GetCurrentProcess();
    if (h != NULL)
    {
        ret = ReadProcessMemory(h, base, buf, len, r);
        if (pid) CloseHandle(h);
    }
    return ret;
}