[PATCH] [Kernel32]: toolhelp

Eric Pouech eric.pouech at wanadoo.fr
Sat Apr 8 04:22:45 CDT 2006


- rewrote toolhelp implementation only on top of ntdll functions

A+
---

 dlls/kernel/toolhelp.c |  543 +++++++++++++++++++++++++++++++++++-------------
 1 files changed, 391 insertions(+), 152 deletions(-)

diff --git a/dlls/kernel/toolhelp.c b/dlls/kernel/toolhelp.c
index 2aef731..8c91666 100644
--- a/dlls/kernel/toolhelp.c
+++ b/dlls/kernel/toolhelp.c
@@ -2,6 +2,7 @@
  * Misc Toolhelp functions
  *
  * Copyright 1996 Marcus Meissner
+ *           2005 Eric Pouech
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -28,23 +29,276 @@
 #endif
 #include <ctype.h>
 #include <assert.h>
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
 #include "windef.h"
 #include "winbase.h"
 #include "winerror.h"
 #include "tlhelp32.h"
-#include "wine/server.h"
-#include "wine/unicode.h"
+#include "winnls.h"
+#include "winternl.h"
+
 #include "wine/debug.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(toolhelp);
 
+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 BOOL fetch_string( HANDLE hProcess, UNICODE_STRING* us)
+{
+    WCHAR*      local;
+    BOOL        ret = FALSE;
+
+    local = HeapAlloc( GetProcessHeap(), 0, us->Length );
+    if (local)
+    {
+        if (!ReadProcessMemory( hProcess, us->Buffer, local, us->Length, NULL))
+        {
+            HeapFree( GetProcessHeap(), 0, local );
+            local = NULL;
+        }
+        else ret = TRUE;
+    }
+            
+    us->Buffer = local;
+    return ret;
+}
+
+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 == INVALID_HANDLE_VALUE) return FALSE;
+    }
+    else
+        hProcess = GetCurrentProcess();
+
+    status = NtQueryInformationProcess( hProcess, ProcessBasicInformation,
+                                        &pbi, sizeof(pbi), NULL );
+    if (!status)
+    {
+        if (ReadProcessMemory( hProcess, &((PEB*)pbi.PebBaseAddress)->LdrData,
+                               &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->szModule) - 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 */
+            thd_entry->th32ThreadID = (ULONG)sti->dwThreadID;
+            thd_entry->th32OwnerProcessID = (ULONG)sti->dwOwningPID;
+            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);
+}
 
 /***********************************************************************
  *           CreateToolhelp32Snapshot			(KERNEL32.@)
  */
 HANDLE WINAPI CreateToolhelp32Snapshot( DWORD flags, DWORD process )
 {
-    HANDLE ret;
+    SYSTEM_PROCESS_INFORMATION* spi = NULL;
+    LDR_MODULE*         mod = NULL;
+    ULONG               num_pcs, num_thd, num_mod;
+    HANDLE              hSnapShot = INVALID_HANDLE_VALUE;
 
     TRACE("%lx,%lx\n", flags, process );
     if (!(flags & (TH32CS_SNAPPROCESS|TH32CS_SNAPTHREAD|TH32CS_SNAPMODULE)))
@@ -54,54 +308,72 @@ HANDLE WINAPI CreateToolhelp32Snapshot( 
         return INVALID_HANDLE_VALUE;
     }
 
-    /* Now do the snapshot */
-    SERVER_START_REQ( create_snapshot )
+    if (fetch_module( process, flags, &mod, &num_mod ) &&
+        fetch_process_thread( flags, &spi, &num_pcs, &num_thd ))
     {
-        req->flags = 0;
-        if (flags & TH32CS_SNAPMODULE)   req->flags |= SNAP_MODULE;
-        if (flags & TH32CS_SNAPPROCESS)  req->flags |= SNAP_PROCESS;
-        if (flags & TH32CS_SNAPTHREAD)   req->flags |= SNAP_THREAD;
-        req->attributes = (flags & TH32CS_INHERIT) ? OBJ_INHERIT : 0;
-        req->pid        = process;
-        wine_server_call_err( req );
-        ret = reply->handle;
+        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 != INVALID_HANDLE_VALUE &&        
+            (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( (void*)snap );
+        }
     }
-    SERVER_END_REQ;
-    if (!ret) ret = INVALID_HANDLE_VALUE;
-    return ret;
-}
 
+    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 );
+
+    return hSnapShot;
+}
 
-/***********************************************************************
- *		TOOLHELP_Thread32Next
- *
- * Implementation of Thread32First/Next
- */
-static BOOL TOOLHELP_Thread32Next( HANDLE handle, LPTHREADENTRY32 lpte, BOOL first )
+static BOOL next_thread( HANDLE hSnapShot, LPTHREADENTRY32 lpte, BOOL first )
 {
-    BOOL ret;
+    struct snapshot*    snap;
+    BOOL                ret = FALSE;
 
     if (lpte->dwSize < sizeof(THREADENTRY32))
     {
         SetLastError( ERROR_INSUFFICIENT_BUFFER );
-        ERR("Result buffer too small (%ld)\n", lpte->dwSize);
+        WARN("Result buffer too small (%ld)\n", lpte->dwSize);
         return FALSE;
     }
-    SERVER_START_REQ( next_thread )
+    if ((snap = MapViewOfFile( hSnapShot, FILE_MAP_ALL_ACCESS, 0, 0, 0 )))
     {
-        req->handle = handle;
-        req->reset = first;
-        if ((ret = !wine_server_call_err( req )))
+        if (first) snap->thread_pos = 0;
+        if (snap->thread_pos < snap->thread_count)
         {
-            lpte->cntUsage           = reply->count;
-            lpte->th32ThreadID       = (DWORD)reply->tid;
-            lpte->th32OwnerProcessID = (DWORD)reply->pid;
-            lpte->tpBasePri          = reply->base_pri;
-            lpte->tpDeltaPri         = reply->delta_pri;
-            lpte->dwFlags            = 0;  /* SDK: "reserved; do not use" */
+            LPTHREADENTRY32 te = (THREADENTRY32*)&snap->data[snap->thread_offset];
+            *lpte = te[snap->thread_pos++];
+            ret = TRUE;
         }
+        else SetLastError( ERROR_NO_MORE_FILES );
+        UnmapViewOfFile( (void*)snap );
     }
-    SERVER_END_REQ;
     return ret;
 }
 
@@ -110,92 +382,71 @@ static BOOL TOOLHELP_Thread32Next( HANDL
  *
  * Return info about the first thread in a toolhelp32 snapshot
  */
-BOOL WINAPI Thread32First(HANDLE hSnapshot, LPTHREADENTRY32 lpte)
+BOOL WINAPI Thread32First( HANDLE hSnapShot, LPTHREADENTRY32 lpte )
 {
-    return TOOLHELP_Thread32Next(hSnapshot, lpte, TRUE);
+    return next_thread( hSnapShot, lpte, TRUE );
 }
 
 /***********************************************************************
- *		Thread32Next   (KERNEL32.@)
+ *		Thread32Next    (KERNEL32.@)
  *
- * Return info about the "next" thread in a toolhelp32 snapshot
+ * Return info about the first thread in a toolhelp32 snapshot
  */
-BOOL WINAPI Thread32Next(HANDLE hSnapshot, LPTHREADENTRY32 lpte)
+BOOL WINAPI Thread32Next( HANDLE hSnapShot, LPTHREADENTRY32 lpte )
 {
-    return TOOLHELP_Thread32Next(hSnapshot, lpte, FALSE);
+    return next_thread( hSnapShot, lpte, FALSE );
 }
 
 /***********************************************************************
- *		TOOLHELP_Process32Next
+ *		process_next
  *
  * 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.
  */
-static BOOL TOOLHELP_Process32Next( HANDLE handle, LPPROCESSENTRY32W lppe, BOOL first, BOOL unicode )
+static BOOL process_next( HANDLE hSnapShot, LPPROCESSENTRY32W lppe,
+                          BOOL first, BOOL unicode )
 {
-    BOOL ret;
-    WCHAR exe[MAX_PATH-1];
-    DWORD len, sz;
+    struct snapshot*    snap;
+    BOOL                ret = FALSE;
+    DWORD               sz = unicode ? sizeof(PROCESSENTRY32W) : sizeof(PROCESSENTRY32);
 
-    sz = unicode ? sizeof(PROCESSENTRY32W) : sizeof(PROCESSENTRY32);
     if (lppe->dwSize < sz)
     {
         SetLastError( ERROR_INSUFFICIENT_BUFFER );
-        ERR("Result buffer too small (req: %ld, was: %ld)\n", sz, lppe->dwSize);
+        WARN("Result buffer too small (%ld)\n", lppe->dwSize);
         return FALSE;
     }
-
-    SERVER_START_REQ( next_process )
+    if ((snap = MapViewOfFile( hSnapShot, FILE_MAP_ALL_ACCESS, 0, 0, 0 )))
     {
-        req->handle = handle;
-        req->reset = first;
-        wine_server_set_reply( req, exe, sizeof(exe) );
-        if ((ret = !wine_server_call_err( req )))
+        if (first) snap->process_pos = 0;
+        if (snap->process_pos < snap->process_count)
         {
-            lppe->cntUsage            = reply->count;
-            lppe->th32ProcessID       = reply->pid;
-            lppe->th32DefaultHeapID   = (DWORD)reply->heap;
-            lppe->th32ModuleID        = (DWORD)reply->module;
-            lppe->cntThreads          = reply->threads;
-            lppe->th32ParentProcessID = reply->ppid;
-            switch (reply->priority)
-            {
-            case PROCESS_PRIOCLASS_IDLE:
-                lppe->pcPriClassBase = IDLE_PRIORITY_CLASS; break;
-            case PROCESS_PRIOCLASS_BELOW_NORMAL:
-                lppe->pcPriClassBase = BELOW_NORMAL_PRIORITY_CLASS; break;
-            case PROCESS_PRIOCLASS_NORMAL:
-                lppe->pcPriClassBase = NORMAL_PRIORITY_CLASS; break;
-            case PROCESS_PRIOCLASS_ABOVE_NORMAL:
-                lppe->pcPriClassBase = ABOVE_NORMAL_PRIORITY_CLASS; break;
-            case PROCESS_PRIOCLASS_HIGH:
-                lppe->pcPriClassBase = HIGH_PRIORITY_CLASS; break;
-            case PROCESS_PRIOCLASS_REALTIME:
-                lppe->pcPriClassBase = REALTIME_PRIORITY_CLASS; break;
-            default:
-                FIXME("Unknown NT priority class %d, setting to normal\n", reply->priority);
-                lppe->pcPriClassBase = NORMAL_PRIORITY_CLASS;
-                break;
-            }
-            lppe->dwFlags             = -1; /* FIXME */
+            LPPROCESSENTRY32W pe = (PROCESSENTRY32W*)&snap->data[snap->process_offset];
             if (unicode)
-            {
-                len = wine_server_reply_size(reply) / sizeof(WCHAR);
-                memcpy(lppe->szExeFile, reply, wine_server_reply_size(reply));
-                lppe->szExeFile[len] = 0;
-            }
+                *lppe = pe[snap->process_pos];
             else
             {
-                LPPROCESSENTRY32 lppe_a = (LPPROCESSENTRY32) lppe;
-
-                len = WideCharToMultiByte( CP_ACP, 0, exe, wine_server_reply_size(reply) / sizeof(WCHAR),
-                                           lppe_a->szExeFile, sizeof(lppe_a->szExeFile)-1, NULL, NULL );
-                lppe_a->szExeFile[len] = 0;
+                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 );
             }
+            snap->process_pos++;
+            ret = TRUE;
         }
+        else SetLastError( ERROR_NO_MORE_FILES );
+        UnmapViewOfFile( (void*)snap );
     }
-    SERVER_END_REQ;
+
     return ret;
 }
 
@@ -207,7 +458,7 @@ static BOOL TOOLHELP_Process32Next( HAND
  */
 BOOL WINAPI Process32First(HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
 {
-    return TOOLHELP_Process32Next( hSnapshot, (LPPROCESSENTRY32W) lppe, TRUE, FALSE /* ANSI */ );
+    return process_next( hSnapshot, (PROCESSENTRY32W*)lppe, TRUE, FALSE /* ANSI */ );
 }
 
 /***********************************************************************
@@ -217,7 +468,7 @@ BOOL WINAPI Process32First(HANDLE hSnaps
  */
 BOOL WINAPI Process32Next(HANDLE hSnapshot, LPPROCESSENTRY32 lppe)
 {
-    return TOOLHELP_Process32Next( hSnapshot, (LPPROCESSENTRY32W) lppe, FALSE, FALSE /* ANSI */ );
+    return process_next( hSnapshot, (PROCESSENTRY32W*)lppe, FALSE, FALSE /* ANSI */ );
 }
 
 /***********************************************************************
@@ -227,7 +478,7 @@ BOOL WINAPI Process32Next(HANDLE hSnapsh
  */
 BOOL WINAPI Process32FirstW(HANDLE hSnapshot, LPPROCESSENTRY32W lppe)
 {
-    return TOOLHELP_Process32Next( hSnapshot, lppe, TRUE, TRUE /* Unicode */ );
+    return process_next( hSnapshot, lppe, TRUE, TRUE /* Unicode */ );
 }
 
 /***********************************************************************
@@ -237,79 +488,87 @@ BOOL WINAPI Process32FirstW(HANDLE hSnap
  */
 BOOL WINAPI Process32NextW(HANDLE hSnapshot, LPPROCESSENTRY32W lppe)
 {
-    return TOOLHELP_Process32Next( hSnapshot, lppe, FALSE, TRUE /* Unicode */ );
+    return process_next( hSnapshot, lppe, FALSE, TRUE /* Unicode */ );
 }
 
-
 /***********************************************************************
- *		TOOLHELP_Module32NextW
+ *		module_nextW
  *
- * Implementation of Module32First/Next
+ * Implementation of Module32{First|Next}W
  */
-static BOOL TOOLHELP_Module32NextW( HANDLE handle, LPMODULEENTRY32W lpme, BOOL first )
+static BOOL module_nextW( HANDLE hSnapShot, LPMODULEENTRY32W lpme, BOOL first )
 {
-    BOOL ret;
-    WCHAR exe[MAX_PATH];
-    DWORD len;
+    struct snapshot*    snap;
+    BOOL                ret = FALSE;
 
     if (lpme->dwSize < sizeof (MODULEENTRY32W))
     {
         SetLastError( ERROR_INSUFFICIENT_BUFFER );
-        ERR("Result buffer too small (req: %d, was: %ld)\n", sizeof(MODULEENTRY32W), lpme->dwSize);
+        WARN("Result buffer too small (req: %d, was: %ld)\n", sizeof(MODULEENTRY32W), lpme->dwSize);
         return FALSE;
     }
-    SERVER_START_REQ( next_module )
+    if ((snap = MapViewOfFile( hSnapShot, FILE_MAP_ALL_ACCESS, 0, 0, 0 )))
     {
-        req->handle = handle;
-        req->reset = first;
-        wine_server_set_reply( req, exe, sizeof(exe) );
-        if ((ret = !wine_server_call_err( req )))
+        if (first) snap->module_pos = 0;
+        if (snap->module_pos < snap->module_count)
         {
-            const WCHAR* ptr;
-            lpme->th32ModuleID   = 1; /* toolhelp internal id, never used */
-            lpme->th32ProcessID  = reply->pid;
-            lpme->GlblcntUsage   = 0xFFFF; /* FIXME */
-            lpme->ProccntUsage   = 0xFFFF; /* FIXME */
-            lpme->modBaseAddr    = reply->base;
-            lpme->modBaseSize    = reply->size;
-            lpme->hModule        = reply->base;
-            len = wine_server_reply_size(reply) / sizeof(WCHAR);
-            memcpy(lpme->szExePath, exe, wine_server_reply_size(reply));
-            lpme->szExePath[len] = 0;
-            if ((ptr = strrchrW(lpme->szExePath, '\\'))) ptr++;
-            else ptr = lpme->szExePath;
-            lstrcpynW( lpme->szModule, ptr, sizeof(lpme->szModule)/sizeof(lpme->szModule[0]));
+            LPMODULEENTRY32W pe = (MODULEENTRY32W*)&snap->data[snap->module_offset];
+            *lpme = pe[snap->module_pos++];
+            ret = TRUE;
         }
+        else SetLastError( ERROR_NO_MORE_FILES );
+        UnmapViewOfFile( (void*)snap );
     }
-    SERVER_END_REQ;
+
     return ret;
 }
 
 /***********************************************************************
- *		TOOLHELP_Module32NextA
+ *		Module32FirstW   (KERNEL32.@)
  *
- * Implementation of Module32First/Next
+ * Return info about the "first" module in a toolhelp32 snapshot
  */
-static BOOL TOOLHELP_Module32NextA( HANDLE handle, LPMODULEENTRY32 lpme, BOOL first )
+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
+ *
+ * Implementation of Module32{First|Next}A
+ */
+static BOOL module_nextA( HANDLE handle, LPMODULEENTRY32 lpme, BOOL first )
 {
     BOOL ret;
     MODULEENTRY32W mew;
     
-    if (lpme->dwSize < sizeof (MODULEENTRY32))
+    if (lpme->dwSize < sizeof(MODULEENTRY32))
     {
         SetLastError( ERROR_INSUFFICIENT_BUFFER );
-        ERR("Result buffer too small (req: %d, was: %ld)\n", sizeof(MODULEENTRY32), lpme->dwSize);
+        WARN("Result buffer too small (req: %d, was: %ld)\n", sizeof(MODULEENTRY32), lpme->dwSize);
         return FALSE;
     }
     
     mew.dwSize = sizeof(mew);
-    if ((ret = TOOLHELP_Module32NextW( handle, &mew, first )))
+    if ((ret = module_nextW( handle, &mew, first )))
     {
         lpme->th32ModuleID  = mew.th32ModuleID;
         lpme->th32ProcessID = mew.th32ProcessID;
         lpme->GlblcntUsage  = mew.GlblcntUsage;
         lpme->ProccntUsage  = mew.ProccntUsage;
         lpme->modBaseAddr   = mew.modBaseAddr;
+        lpme->modBaseSize   = mew.modBaseSize;
         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 );
@@ -318,33 +577,13 @@ static BOOL TOOLHELP_Module32NextA( HAND
 }
 
 /***********************************************************************
- *		Module32FirstW   (KERNEL32.@)
- *
- * Return info about the "first" module in a toolhelp32 snapshot
- */
-BOOL WINAPI Module32FirstW(HANDLE hSnapshot, LPMODULEENTRY32W lpme)
-{
-    return TOOLHELP_Module32NextW( hSnapshot, lpme, TRUE );
-}
-
-/***********************************************************************
  *		Module32First   (KERNEL32.@)
  *
  * Return info about the "first" module in a toolhelp32 snapshot
  */
 BOOL WINAPI Module32First(HANDLE hSnapshot, LPMODULEENTRY32 lpme)
 {
-    return TOOLHELP_Module32NextA( hSnapshot, lpme, TRUE );
-}
-
-/***********************************************************************
- *		Module32NextW   (KERNEL32.@)
- *
- * Return info about the "next" module in a toolhelp32 snapshot
- */
-BOOL WINAPI Module32NextW(HANDLE hSnapshot, LPMODULEENTRY32W lpme)
-{
-    return TOOLHELP_Module32NextW( hSnapshot, lpme, FALSE );
+    return module_nextA( hSnapshot, lpme, TRUE );
 }
 
 /***********************************************************************
@@ -354,7 +593,7 @@ BOOL WINAPI Module32NextW(HANDLE hSnapsh
  */
 BOOL WINAPI Module32Next(HANDLE hSnapshot, LPMODULEENTRY32 lpme)
 {
-    return TOOLHELP_Module32NextA( hSnapshot, lpme, FALSE );
+    return module_nextA( hSnapshot, lpme, FALSE );
 }
 
 /************************************************************************





More information about the wine-patches mailing list