4 * Copyright 1998 Patrik Stridvall
5 * Copyright 2003 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
25 #define WIN32_NO_STATUS
29 #include "wine/unicode.h"
30 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(psapi);
40 PLIST_ENTRY pHead, pCurrent;
44 /***********************************************************************
45 * PSAPI_ModuleIteratorInit [internal]
47 * Prepares to iterate through the loaded modules of the given process.
53 static BOOL PSAPI_ModuleIteratorInit(MODULE_ITERATOR *iter, HANDLE hProcess)
55 PROCESS_BASIC_INFORMATION pbi;
56 PPEB_LDR_DATA pLdrData;
59 /* Get address of PEB */
60 status = NtQueryInformationProcess(hProcess, ProcessBasicInformation,
61 &pbi, sizeof(pbi), NULL);
62 if (status != STATUS_SUCCESS)
64 SetLastError(RtlNtStatusToDosError(status));
68 /* Read address of LdrData from PEB */
69 if (!ReadProcessMemory(hProcess, &pbi.PebBaseAddress->LdrData,
70 &pLdrData, sizeof(pLdrData), NULL))
73 /* Read address of first module from LdrData */
74 if (!ReadProcessMemory(hProcess,
75 &pLdrData->InLoadOrderModuleList.Flink,
76 &iter->pCurrent, sizeof(iter->pCurrent), NULL))
79 iter->pHead = &pLdrData->InLoadOrderModuleList;
80 iter->hProcess = hProcess;
85 /***********************************************************************
86 * PSAPI_ModuleIteratorNext [internal]
88 * Iterates to the next module.
96 * Every function which uses this routine suffers from a race condition
97 * when a module is unloaded during the enumeration which can cause the
98 * function to fail. As there is no way to lock the loader of another
99 * process we can't avoid that.
101 static INT PSAPI_ModuleIteratorNext(MODULE_ITERATOR *iter)
103 if (iter->pCurrent == iter->pHead)
106 if (!ReadProcessMemory(iter->hProcess, CONTAINING_RECORD(iter->pCurrent,
107 LDR_MODULE, InLoadOrderModuleList),
108 &iter->LdrModule, sizeof(iter->LdrModule), NULL))
111 iter->pCurrent = iter->LdrModule.InLoadOrderModuleList.Flink;
116 /***********************************************************************
117 * PSAPI_GetLdrModule [internal]
119 * Reads the LDR_MODULE structure of the given module.
126 static BOOL PSAPI_GetLdrModule(HANDLE hProcess, HMODULE hModule,
127 LDR_MODULE *pLdrModule)
129 MODULE_ITERATOR iter;
132 if (!PSAPI_ModuleIteratorInit(&iter, hProcess))
135 while ((ret = PSAPI_ModuleIteratorNext(&iter)) > 0)
136 /* When hModule is NULL we return the process image - which will be
137 * the first module since our iterator uses InLoadOrderModuleList */
138 if (!hModule || hModule == iter.LdrModule.BaseAddress)
140 *pLdrModule = iter.LdrModule;
145 SetLastError(ERROR_INVALID_HANDLE);
150 /***********************************************************************
151 * EnumDeviceDrivers (PSAPI.@)
153 BOOL WINAPI EnumDeviceDrivers(LPVOID *lpImageBase, DWORD cb, LPDWORD lpcbNeeded)
155 FIXME("(%p, %d, %p): stub\n", lpImageBase, cb, lpcbNeeded);
163 /***********************************************************************
164 * EnumPageFilesA (PSAPI.@)
166 BOOL WINAPI EnumPageFilesA( PENUM_PAGE_FILE_CALLBACKA callback, LPVOID context )
168 FIXME("(%p, %p) stub\n", callback, context );
172 /***********************************************************************
173 * EnumPageFilesW (PSAPI.@)
175 BOOL WINAPI EnumPageFilesW( PENUM_PAGE_FILE_CALLBACKW callback, LPVOID context )
177 FIXME("(%p, %p) stub\n", callback, context );
181 /***********************************************************************
182 * EnumProcesses (PSAPI.@)
184 BOOL WINAPI EnumProcesses(DWORD *lpdwProcessIDs, DWORD cb, DWORD *lpcbUsed)
186 SYSTEM_PROCESS_INFORMATION *spi;
189 ULONG nAlloc = 0x8000;
194 HeapFree(GetProcessHeap(), 0, pBuf);
198 pBuf = HeapAlloc(GetProcessHeap(), 0, nAlloc);
202 status = NtQuerySystemInformation(SystemProcessInformation, pBuf,
204 } while (status == STATUS_INFO_LENGTH_MISMATCH);
206 if (status != STATUS_SUCCESS)
208 HeapFree(GetProcessHeap(), 0, pBuf);
209 SetLastError(RtlNtStatusToDosError(status));
215 for (*lpcbUsed = 0; cb >= sizeof(DWORD); cb -= sizeof(DWORD))
217 *lpdwProcessIDs++ = HandleToUlong(spi->UniqueProcessId);
218 *lpcbUsed += sizeof(DWORD);
220 if (spi->NextEntryOffset == 0)
223 spi = (SYSTEM_PROCESS_INFORMATION *)(((PCHAR)spi) + spi->NextEntryOffset);
226 HeapFree(GetProcessHeap(), 0, pBuf);
230 /***********************************************************************
231 * EnumProcessModules (PSAPI.@)
234 * Returned list is in load order.
236 BOOL WINAPI EnumProcessModules(HANDLE hProcess, HMODULE *lphModule,
237 DWORD cb, LPDWORD lpcbNeeded)
239 MODULE_ITERATOR iter;
242 if (!PSAPI_ModuleIteratorInit(&iter, hProcess))
247 while ((ret = PSAPI_ModuleIteratorNext(&iter)) > 0)
249 if (cb >= sizeof(HMODULE))
251 *lphModule++ = iter.LdrModule.BaseAddress;
252 cb -= sizeof(HMODULE);
254 *lpcbNeeded += sizeof(HMODULE);
260 /***********************************************************************
261 * GetDeviceDriverBaseNameA (PSAPI.@)
263 DWORD WINAPI GetDeviceDriverBaseNameA(LPVOID ImageBase, LPSTR lpBaseName,
266 FIXME("(%p, %p, %d): stub\n", ImageBase, lpBaseName, nSize);
268 if (lpBaseName && nSize)
269 lpBaseName[0] = '\0';
274 /***********************************************************************
275 * GetDeviceDriverBaseNameW (PSAPI.@)
277 DWORD WINAPI GetDeviceDriverBaseNameW(LPVOID ImageBase, LPWSTR lpBaseName,
280 FIXME("(%p, %p, %d): stub\n", ImageBase, lpBaseName, nSize);
282 if (lpBaseName && nSize)
283 lpBaseName[0] = '\0';
288 /***********************************************************************
289 * GetDeviceDriverFileNameA (PSAPI.@)
291 DWORD WINAPI GetDeviceDriverFileNameA(LPVOID ImageBase, LPSTR lpFilename,
294 FIXME("(%p, %p, %d): stub\n", ImageBase, lpFilename, nSize);
296 if (lpFilename && nSize)
297 lpFilename[0] = '\0';
302 /***********************************************************************
303 * GetDeviceDriverFileNameW (PSAPI.@)
305 DWORD WINAPI GetDeviceDriverFileNameW(LPVOID ImageBase, LPWSTR lpFilename,
308 FIXME("(%p, %p, %d): stub\n", ImageBase, lpFilename, nSize);
310 if (lpFilename && nSize)
311 lpFilename[0] = '\0';
316 /***********************************************************************
317 * GetMappedFileNameA (PSAPI.@)
319 DWORD WINAPI GetMappedFileNameA(HANDLE hProcess, LPVOID lpv, LPSTR lpFilename,
322 FIXME("(%p, %p, %p, %d): stub\n", hProcess, lpv, lpFilename, nSize);
324 if (lpFilename && nSize)
325 lpFilename[0] = '\0';
330 /***********************************************************************
331 * GetMappedFileNameW (PSAPI.@)
333 DWORD WINAPI GetMappedFileNameW(HANDLE hProcess, LPVOID lpv, LPWSTR lpFilename,
336 FIXME("(%p, %p, %p, %d): stub\n", hProcess, lpv, lpFilename, nSize);
338 if (lpFilename && nSize)
339 lpFilename[0] = '\0';
344 /***********************************************************************
345 * GetModuleBaseNameA (PSAPI.@)
347 DWORD WINAPI GetModuleBaseNameA(HANDLE hProcess, HMODULE hModule,
348 LPSTR lpBaseName, DWORD nSize)
351 DWORD buflenW, ret = 0;
353 if(!lpBaseName || !nSize) {
354 SetLastError(ERROR_INVALID_PARAMETER);
357 lpBaseNameW = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * nSize);
358 buflenW = GetModuleBaseNameW(hProcess, hModule, lpBaseNameW, nSize);
359 TRACE("%d, %s\n", buflenW, debugstr_w(lpBaseNameW));
362 ret = WideCharToMultiByte(CP_ACP, 0, lpBaseNameW, buflenW,
363 lpBaseName, nSize, NULL, NULL);
364 if (ret < nSize) lpBaseName[ret] = 0;
366 HeapFree(GetProcessHeap(), 0, lpBaseNameW);
370 /***********************************************************************
371 * GetModuleBaseNameW (PSAPI.@)
373 DWORD WINAPI GetModuleBaseNameW(HANDLE hProcess, HMODULE hModule,
374 LPWSTR lpBaseName, DWORD nSize)
376 LDR_MODULE LdrModule;
378 if (!PSAPI_GetLdrModule(hProcess, hModule, &LdrModule))
381 nSize = min(LdrModule.BaseDllName.Length / sizeof(WCHAR), nSize);
382 if (!ReadProcessMemory(hProcess, LdrModule.BaseDllName.Buffer,
383 lpBaseName, nSize * sizeof(WCHAR), NULL))
386 lpBaseName[nSize] = 0;
390 /***********************************************************************
391 * GetModuleFileNameExA (PSAPI.@)
393 DWORD WINAPI GetModuleFileNameExA(HANDLE hProcess, HMODULE hModule,
394 LPSTR lpFileName, DWORD nSize)
398 TRACE("(hProcess=%p, hModule=%p, %p, %d)\n",
399 hProcess, hModule, lpFileName, nSize);
401 if (!lpFileName || !nSize) return 0;
403 if ( hProcess == GetCurrentProcess() )
405 DWORD len = GetModuleFileNameA( hModule, lpFileName, nSize );
406 if (nSize) lpFileName[nSize - 1] = '\0';
410 if (!(ptr = HeapAlloc(GetProcessHeap(), 0, nSize * sizeof(WCHAR)))) return 0;
412 if (!GetModuleFileNameExW(hProcess, hModule, ptr, nSize))
414 lpFileName[0] = '\0';
418 if (!WideCharToMultiByte( CP_ACP, 0, ptr, -1, lpFileName, nSize, NULL, NULL ))
419 lpFileName[nSize - 1] = 0;
422 HeapFree(GetProcessHeap(), 0, ptr);
423 return strlen(lpFileName);
426 /***********************************************************************
427 * GetModuleFileNameExW (PSAPI.@)
429 DWORD WINAPI GetModuleFileNameExW(HANDLE hProcess, HMODULE hModule,
430 LPWSTR lpFileName, DWORD nSize)
432 LDR_MODULE LdrModule;
434 if(!PSAPI_GetLdrModule(hProcess, hModule, &LdrModule))
437 nSize = min(LdrModule.FullDllName.Length / sizeof(WCHAR), nSize);
438 if (!ReadProcessMemory(hProcess, LdrModule.FullDllName.Buffer,
439 lpFileName, nSize * sizeof(WCHAR), NULL))
442 lpFileName[nSize] = 0;
446 /***********************************************************************
447 * GetModuleInformation (PSAPI.@)
449 BOOL WINAPI GetModuleInformation(HANDLE hProcess, HMODULE hModule,
450 LPMODULEINFO lpmodinfo, DWORD cb)
452 LDR_MODULE LdrModule;
454 if (cb < sizeof(MODULEINFO))
456 SetLastError(ERROR_INSUFFICIENT_BUFFER);
460 if (!PSAPI_GetLdrModule(hProcess, hModule, &LdrModule))
463 lpmodinfo->lpBaseOfDll = LdrModule.BaseAddress;
464 lpmodinfo->SizeOfImage = LdrModule.SizeOfImage;
465 lpmodinfo->EntryPoint = LdrModule.EntryPoint;
469 /***********************************************************************
470 * GetPerformanceInfo (PSAPI.@)
472 BOOL WINAPI GetPerformanceInfo( PPERFORMANCE_INFORMATION info, DWORD size )
476 TRACE( "(%p, %d)\n", info, size );
478 status = NtQuerySystemInformation( SystemPerformanceInformation, info, size, NULL );
482 SetLastError( RtlNtStatusToDosError( status ) );
488 /***********************************************************************
489 * GetProcessMemoryInfo (PSAPI.@)
491 * Retrieve memory usage information for a given process
494 BOOL WINAPI GetProcessMemoryInfo(HANDLE hProcess,
495 PPROCESS_MEMORY_COUNTERS pmc, DWORD cb)
500 if (cb < sizeof(PROCESS_MEMORY_COUNTERS))
502 SetLastError(ERROR_INSUFFICIENT_BUFFER);
506 status = NtQueryInformationProcess(hProcess, ProcessVmCounters,
507 &vmc, sizeof(vmc), NULL);
511 SetLastError(RtlNtStatusToDosError(status));
515 pmc->cb = sizeof(PROCESS_MEMORY_COUNTERS);
516 pmc->PageFaultCount = vmc.PageFaultCount;
517 pmc->PeakWorkingSetSize = vmc.PeakWorkingSetSize;
518 pmc->WorkingSetSize = vmc.WorkingSetSize;
519 pmc->QuotaPeakPagedPoolUsage = vmc.QuotaPeakPagedPoolUsage;
520 pmc->QuotaPagedPoolUsage = vmc.QuotaPagedPoolUsage;
521 pmc->QuotaPeakNonPagedPoolUsage = vmc.QuotaPeakNonPagedPoolUsage;
522 pmc->QuotaNonPagedPoolUsage = vmc.QuotaNonPagedPoolUsage;
523 pmc->PagefileUsage = vmc.PagefileUsage;
524 pmc->PeakPagefileUsage = vmc.PeakPagefileUsage;
529 /***********************************************************************
530 * GetWsChanges (PSAPI.@)
532 BOOL WINAPI GetWsChanges( HANDLE process, PPSAPI_WS_WATCH_INFORMATION watchinfo, DWORD size )
536 TRACE( "(%p, %p, %d)\n", process, watchinfo, size );
538 status = NtQueryInformationProcess( process, ProcessWorkingSetWatch, watchinfo, size, NULL );
542 SetLastError( RtlNtStatusToDosError( status ) );
548 /***********************************************************************
549 * InitializeProcessForWsWatch (PSAPI.@)
551 BOOL WINAPI InitializeProcessForWsWatch(HANDLE hProcess)
553 FIXME("(hProcess=%p): stub\n", hProcess);
558 /***********************************************************************
559 * QueryWorkingSet (PSAPI.@)
561 BOOL WINAPI QueryWorkingSet( HANDLE process, LPVOID buffer, DWORD size )
565 TRACE( "(%p, %p, %d)\n", process, buffer, size );
567 status = NtQueryVirtualMemory( process, NULL, MemoryWorkingSetList, buffer, size, NULL );
571 SetLastError( RtlNtStatusToDosError( status ) );
577 /***********************************************************************
578 * QueryWorkingSetEx (PSAPI.@)
580 BOOL WINAPI QueryWorkingSetEx( HANDLE process, LPVOID buffer, DWORD size )
584 TRACE( "(%p, %p, %d)\n", process, buffer, size );
586 status = NtQueryVirtualMemory( process, NULL, MemoryWorkingSetList, buffer, size, NULL );
590 SetLastError( RtlNtStatusToDosError( status ) );