[PSAPI #2] Remove the other server requests, take 2

Felix Nawothnig felix.nawothnig at t-online.de
Mon Jun 20 10:46:14 CDT 2005


ChangeLog:
- Replaced server requests by native APIs in EnumProcessModules, 
GetModuleBaseNameW, GetModuleFileNameExW and GetModuleInformation
- Make EnumProcessModules return modules in load order
- Set ERROR_INSUFFICIENT_BUFFER in GetModuleInformation when failing due 
to (cb < sizeof(MODULEINFO))
-------------- next part --------------
Index: psapi_main.c
===================================================================
RCS file: /home/wine/wine/dlls/psapi/psapi_main.c,v
retrieving revision 1.24
diff -u -r1.24 psapi_main.c
--- psapi_main.c	15 Jun 2005 18:07:11 -0000	1.24
+++ psapi_main.c	20 Jun 2005 15:45:21 -0000
@@ -24,15 +24,130 @@
 #include "windef.h"
 #include "winbase.h"
 #include "winerror.h"
-#include "wine/server.h"
 #include "wine/unicode.h"
 #include "wine/debug.h"
 #include "winnls.h"
+#include "winternl.h"
 #include "ntstatus.h"
 #include "psapi.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(psapi);
 
+typedef struct
+{
+    HANDLE hProcess;             
+    PLIST_ENTRY pHead, pCurrent;
+    LDR_MODULE LdrModule;
+} MODULE_ITERATOR;
+
+/***********************************************************************
+ *           PSAPI_ModuleIteratorInit [internal]
+ *
+ * Prepares to iterate through the loaded modules of the given process.
+ *
+ * RETURNS
+ *  Success: TRUE
+ *  Failure: FALSE
+ */
+static BOOL PSAPI_ModuleIteratorInit(MODULE_ITERATOR *iter, HANDLE hProcess)
+{
+    PROCESS_BASIC_INFORMATION pbi;
+    PPEB_LDR_DATA pLdrData;
+    NTSTATUS status;
+
+    /* Get address of PEB */
+    status = NtQueryInformationProcess(hProcess, ProcessBasicInformation,
+                                       &pbi, sizeof(pbi), NULL);
+    if (status != STATUS_SUCCESS)
+    {
+        SetLastError(RtlNtStatusToDosError(status));
+        return FALSE;
+    }
+
+    /* Read address of LdrData from PEB */
+    if (!ReadProcessMemory(hProcess, &((PPEB)pbi.PebBaseAddress)->LdrData,
+                           &pLdrData, sizeof(pLdrData), NULL))
+        return FALSE;
+
+    /* Read address of first module from LdrData */
+    if (!ReadProcessMemory(hProcess,
+                           &pLdrData->InLoadOrderModuleList.Flink,
+                           &iter->pCurrent, sizeof(iter->pCurrent), NULL))
+        return FALSE;
+
+    iter->pHead = &pLdrData->InLoadOrderModuleList;
+    iter->hProcess = hProcess;
+
+    return TRUE;
+}
+
+/***********************************************************************
+ *           PSAPI_ModuleIteratorNext [internal]
+ *
+ * Iterates to the next module.
+ *
+ * RETURNS
+ *   1 : Success
+ *   0 : No more modules
+ *  -1 : Failure
+ *
+ * NOTES
+ *  Every function which uses this routine suffers from a race condition 
+ *  when a module is unloaded during the enumeration which can cause the
+ *  function to fail. As there is no way to lock the loader of another 
+ *  process we can't avoid that.
+ */
+static INT PSAPI_ModuleIteratorNext(MODULE_ITERATOR *iter)
+{   
+    SetLastError(ERROR_SUCCESS);
+
+    if (iter->pCurrent == iter->pHead)
+        return 0;
+
+    if (!ReadProcessMemory(iter->hProcess, CONTAINING_RECORD(iter->pCurrent,
+                           LDR_MODULE, InLoadOrderModuleList),
+                           &iter->LdrModule, sizeof(iter->LdrModule), NULL))
+         return -1;
+    else
+         iter->pCurrent = iter->LdrModule.InLoadOrderModuleList.Flink;
+
+    return 1;
+}
+
+/***********************************************************************
+ *           PSAPI_GetLdrModule [internal]
+ *
+ * Reads the LDR_MODULE structure of the given module.
+ *
+ * RETURNS
+ *  Success: TRUE
+ *  Failure: FALSE
+ */
+
+static BOOL PSAPI_GetLdrModule(HANDLE hProcess, HMODULE hModule, 
+                               LDR_MODULE *pLdrModule)
+{
+    MODULE_ITERATOR iter;
+    INT ret;
+
+    if (!PSAPI_ModuleIteratorInit(&iter, hProcess))
+        return FALSE;
+
+    while ((ret = PSAPI_ModuleIteratorNext(&iter)) > 0)
+        /* When hModule is NULL we return the process image - which will be
+         * the first module since our iterator uses InLoadOrderModuleList */
+        if (!hModule || hModule == (HMODULE)iter.LdrModule.BaseAddress)
+        {
+            *pLdrModule = iter.LdrModule;
+            return TRUE;
+        }
+
+    if (ret == 0)
+        SetLastError(ERROR_INVALID_HANDLE);
+
+    return FALSE;
+}
+
 /***********************************************************************
  *           EmptyWorkingSet (PSAPI.@)
  */
@@ -106,12 +221,12 @@
 
     spi = pBuf;
 
-    for(*lpcbUsed = 0; cb >= sizeof(DWORD); cb -= sizeof(DWORD))
+    for (*lpcbUsed = 0; cb >= sizeof(DWORD); cb -= sizeof(DWORD))
     {
         *lpdwProcessIDs++ = spi->dwProcessID;
         *lpcbUsed += sizeof(DWORD);
 
-        if(spi->dwOffset == 0)
+        if (spi->dwOffset == 0)
             break;
 
         spi = (SYSTEM_PROCESS_INFORMATION *)(((PCHAR)spi) + spi->dwOffset);
@@ -123,83 +238,32 @@
 
 /***********************************************************************
  *           EnumProcessModules (PSAPI.@)
+ *
+ * NOTES
+ *  Returned list is in load order.
  */
-BOOL WINAPI EnumProcessModules(HANDLE hProcess, HMODULE *lphModule, 
+BOOL WINAPI EnumProcessModules(HANDLE hProcess, HMODULE *lphModule,
                                DWORD cb, LPDWORD lpcbNeeded)
 {
-    HANDLE	hSnapshot;
-    DWORD	pid;
-    DWORD	count;
-    DWORD	countMax;
-    int         ret;
-    HMODULE     hModule;
-
-    TRACE("(hProcess=%p, %p, %ld, %p)\n",
-          hProcess, lphModule, cb, lpcbNeeded );
-
-    if ( lphModule == NULL )
-        cb = 0;
-    if ( lpcbNeeded != NULL )
-        *lpcbNeeded = 0;
-
-    SERVER_START_REQ( get_process_info )
-    {
-        req->handle = hProcess;
-        if ( !wine_server_call_err( req ) )
-            pid = (DWORD)reply->pid;
-        else
-            pid = 0;
-    }
-    SERVER_END_REQ;
+    MODULE_ITERATOR iter;
+    INT ret;
 
-    if ( pid == 0 )
-    {
-        FIXME("no pid for hProcess %p\n" ,hProcess);
+    if (!PSAPI_ModuleIteratorInit(&iter, hProcess))
         return FALSE;
-    }
 
-    SERVER_START_REQ( create_snapshot )
-    {
-        req->flags   = SNAP_MODULE;
-        req->inherit = FALSE;
-        req->pid     = pid;
-        wine_server_call_err( req );
-        hSnapshot = reply->handle;
-    }
-    SERVER_END_REQ;
-    if ( hSnapshot == 0 )
-    {
-        FIXME("cannot create snapshot\n");
-        return FALSE;
-    }
-    count = 0;
-    countMax = cb / sizeof(HMODULE);
-    for (;;)
+    *lpcbNeeded = 0;
+        
+    while ((ret = PSAPI_ModuleIteratorNext(&iter)) > 0)
     {
-        SERVER_START_REQ( next_module )
+        if (cb >= sizeof(HMODULE))
         {
-            req->handle = hSnapshot;
-            req->reset = (count == 0);
-            if ((ret = !wine_server_call_err( req )))
-            {
-                hModule = (HMODULE)reply->base;
-            }
+            *lphModule++ = (HMODULE)iter.LdrModule.BaseAddress;
+            cb -= sizeof(HMODULE);
         }
-        SERVER_END_REQ;
-        if ( !ret ) break;
-        TRACE("module 0x%p\n", hModule);
-        if ( count < countMax )
-            lphModule[count] = hModule;
-        count++;
+        *lpcbNeeded += sizeof(HMODULE);
     }
-    CloseHandle( hSnapshot );
-
-    if ( lpcbNeeded != NULL )
-        *lpcbNeeded = sizeof(HMODULE) * count;
-
-    TRACE("return %lu modules\n", count);
 
-    return TRUE;
+    return (ret == 0);
 }
 
 /***********************************************************************
@@ -324,23 +388,18 @@
 DWORD WINAPI GetModuleBaseNameW(HANDLE hProcess, HMODULE hModule, 
                                 LPWSTR lpBaseName, DWORD nSize)
 {
-    WCHAR  tmp[MAX_PATH];
-    WCHAR* ptr;
-    int    ptrlen;
+    LDR_MODULE LdrModule;
 
-    if(!lpBaseName || !nSize) {
-        SetLastError(ERROR_INVALID_PARAMETER);
+    if (!PSAPI_GetLdrModule(hProcess, hModule, &LdrModule))
         return 0;
-    }
 
-    if (!GetModuleFileNameExW(hProcess, hModule, tmp,
-                              sizeof(tmp)/sizeof(WCHAR)))
+    nSize = min(LdrModule.BaseDllName.Length / sizeof(WCHAR), nSize);
+    if (!ReadProcessMemory(hProcess, LdrModule.BaseDllName.Buffer,
+                           lpBaseName, nSize * sizeof(WCHAR), NULL))
         return 0;
-    TRACE("%s\n", debugstr_w(tmp));
-    if ((ptr = strrchrW(tmp, '\\')) != NULL) ptr++; else ptr = tmp;
-    ptrlen = strlenW(ptr);
-    memcpy(lpBaseName, ptr, min(ptrlen+1,nSize) * sizeof(WCHAR));
-    return min(ptrlen, nSize);
+
+    lpBaseName[nSize] = 0;
+    return nSize;
 }
 
 /***********************************************************************
@@ -385,39 +444,18 @@
 DWORD WINAPI GetModuleFileNameExW(HANDLE hProcess, HMODULE hModule, 
                                   LPWSTR lpFileName, DWORD nSize)
 {
-    DWORD len = 0;
-
-    TRACE("(hProcess=%p, hModule=%p, %p, %ld)\n",
-          hProcess, hModule, lpFileName, nSize);
-
-    if (!lpFileName || !nSize) return 0;
-
-    if ( hProcess == GetCurrentProcess() )
-    {
-        DWORD len = GetModuleFileNameW( hModule, lpFileName, nSize );
-        if (nSize) lpFileName[nSize - 1] = '\0';
-        TRACE("return (cur) %s (%lu)\n", debugstr_w(lpFileName), len);
-        return len;
-    }
-
-    lpFileName[0] = 0;
-
-    SERVER_START_REQ( get_dll_info )
-    {
-        req->handle       = hProcess;
-        req->base_address = hModule;
-        wine_server_set_reply( req, lpFileName, (nSize - 1) * sizeof(WCHAR) );
-        if (!wine_server_call_err( req ))
-        {
-            len = wine_server_reply_size(reply) / sizeof(WCHAR);
-            lpFileName[len] = 0;
-        }
-    }
-    SERVER_END_REQ;
-
-    TRACE("return %s (%lu)\n", debugstr_w(lpFileName), len);
+    LDR_MODULE LdrModule;
+    
+    if(!PSAPI_GetLdrModule(hProcess, hModule, &LdrModule))
+        return 0;
+        
+    nSize = min(LdrModule.FullDllName.Length / sizeof(WCHAR), nSize);
+    if (!ReadProcessMemory(hProcess, LdrModule.FullDllName.Buffer,
+                           lpFileName, nSize * sizeof(WCHAR), NULL))
+        return 0;
 
-    return len;
+    lpFileName[nSize] = 0;
+    return nSize;
 }
 
 /***********************************************************************
@@ -426,27 +464,20 @@
 BOOL WINAPI GetModuleInformation(HANDLE hProcess, HMODULE hModule, 
                                  LPMODULEINFO lpmodinfo, DWORD cb)
 {
-    BOOL ret = FALSE;
-
-    TRACE("(hProcess=%p, hModule=%p, %p, %ld)\n",
-          hProcess, hModule, lpmodinfo, cb);
+    LDR_MODULE LdrModule;
 
-    if (cb < sizeof(MODULEINFO)) return FALSE;
-
-    SERVER_START_REQ( get_dll_info )
+    if (cb < sizeof(MODULEINFO)) 
     {
-        req->handle       = hProcess;
-        req->base_address = (void*)hModule;
-        if (!wine_server_call_err( req ))
-        {
-            ret = TRUE;
-            lpmodinfo->lpBaseOfDll = (void*)hModule;
-            lpmodinfo->SizeOfImage = reply->size;
-            lpmodinfo->EntryPoint  = reply->entry_point;
-        }
+        SetLastError(ERROR_INSUFFICIENT_BUFFER);
+        return FALSE;
     }
-    SERVER_END_REQ;
 
+    if (!PSAPI_GetLdrModule(hProcess, hModule, &LdrModule))
+        return FALSE;
+
+    lpmodinfo->lpBaseOfDll = LdrModule.BaseAddress;
+    lpmodinfo->SizeOfImage = LdrModule.SizeOfImage;
+    lpmodinfo->EntryPoint  = LdrModule.EntryPoint;
     return TRUE;
 }
 


More information about the wine-patches mailing list