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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include "wine/unicode.h"
28 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(psapi);
39 PLIST_ENTRY pHead, pCurrent;
43 /***********************************************************************
44 * PSAPI_ModuleIteratorInit [internal]
46 * Prepares to iterate through the loaded modules of the given process.
52 static BOOL PSAPI_ModuleIteratorInit(MODULE_ITERATOR *iter, HANDLE hProcess)
54 PROCESS_BASIC_INFORMATION pbi;
55 PPEB_LDR_DATA pLdrData;
58 /* Get address of PEB */
59 status = NtQueryInformationProcess(hProcess, ProcessBasicInformation,
60 &pbi, sizeof(pbi), NULL);
61 if (status != STATUS_SUCCESS)
63 SetLastError(RtlNtStatusToDosError(status));
67 /* Read address of LdrData from PEB */
68 if (!ReadProcessMemory(hProcess, &((PPEB)pbi.PebBaseAddress)->LdrData,
69 &pLdrData, sizeof(pLdrData), NULL))
72 /* Read address of first module from LdrData */
73 if (!ReadProcessMemory(hProcess,
74 &pLdrData->InLoadOrderModuleList.Flink,
75 &iter->pCurrent, sizeof(iter->pCurrent), NULL))
78 iter->pHead = &pLdrData->InLoadOrderModuleList;
79 iter->hProcess = hProcess;
84 /***********************************************************************
85 * PSAPI_ModuleIteratorNext [internal]
87 * Iterates to the next module.
95 * Every function which uses this routine suffers from a race condition
96 * when a module is unloaded during the enumeration which can cause the
97 * function to fail. As there is no way to lock the loader of another
98 * process we can't avoid that.
100 static INT PSAPI_ModuleIteratorNext(MODULE_ITERATOR *iter)
102 if (iter->pCurrent == iter->pHead)
105 if (!ReadProcessMemory(iter->hProcess, CONTAINING_RECORD(iter->pCurrent,
106 LDR_MODULE, InLoadOrderModuleList),
107 &iter->LdrModule, sizeof(iter->LdrModule), NULL))
110 iter->pCurrent = iter->LdrModule.InLoadOrderModuleList.Flink;
115 /***********************************************************************
116 * PSAPI_GetLdrModule [internal]
118 * Reads the LDR_MODULE structure of the given module.
125 static BOOL PSAPI_GetLdrModule(HANDLE hProcess, HMODULE hModule,
126 LDR_MODULE *pLdrModule)
128 MODULE_ITERATOR iter;
131 if (!PSAPI_ModuleIteratorInit(&iter, hProcess))
134 while ((ret = PSAPI_ModuleIteratorNext(&iter)) > 0)
135 /* When hModule is NULL we return the process image - which will be
136 * the first module since our iterator uses InLoadOrderModuleList */
137 if (!hModule || hModule == (HMODULE)iter.LdrModule.BaseAddress)
139 *pLdrModule = iter.LdrModule;
144 SetLastError(ERROR_INVALID_HANDLE);
149 /***********************************************************************
150 * EmptyWorkingSet (PSAPI.@)
152 BOOL WINAPI EmptyWorkingSet(HANDLE hProcess)
154 return SetProcessWorkingSetSize(hProcess, 0xFFFFFFFF, 0xFFFFFFFF);
157 /***********************************************************************
158 * EnumDeviceDrivers (PSAPI.@)
160 BOOL WINAPI EnumDeviceDrivers(LPVOID *lpImageBase, DWORD cb, LPDWORD lpcbNeeded)
162 FIXME("(%p, %ld, %p): stub\n", lpImageBase, cb, lpcbNeeded);
170 /***********************************************************************
171 * EnumPageFilesA (PSAPI.@)
173 BOOL WINAPI EnumPageFilesA( PENUM_PAGE_FILE_CALLBACKA callback, LPVOID context )
175 FIXME("(%p, %p) stub\n", callback, context );
179 /***********************************************************************
180 * EnumPageFilesW (PSAPI.@)
182 BOOL WINAPI EnumPageFilesW( PENUM_PAGE_FILE_CALLBACKW callback, LPVOID context )
184 FIXME("(%p, %p) stub\n", callback, context );
188 /***********************************************************************
189 * EnumProcesses (PSAPI.@)
191 BOOL WINAPI EnumProcesses(DWORD *lpdwProcessIDs, DWORD cb, DWORD *lpcbUsed)
193 SYSTEM_PROCESS_INFORMATION *spi;
196 ULONG nAlloc = 0x8000;
201 HeapFree(GetProcessHeap(), 0, pBuf);
205 pBuf = HeapAlloc(GetProcessHeap(), 0, nAlloc);
209 status = NtQuerySystemInformation(SystemProcessInformation, pBuf,
211 } while (status == STATUS_INFO_LENGTH_MISMATCH);
213 if (status != STATUS_SUCCESS)
215 HeapFree(GetProcessHeap(), 0, pBuf);
216 SetLastError(RtlNtStatusToDosError(status));
222 for (*lpcbUsed = 0; cb >= sizeof(DWORD); cb -= sizeof(DWORD))
224 *lpdwProcessIDs++ = spi->dwProcessID;
225 *lpcbUsed += sizeof(DWORD);
227 if (spi->dwOffset == 0)
230 spi = (SYSTEM_PROCESS_INFORMATION *)(((PCHAR)spi) + spi->dwOffset);
233 HeapFree(GetProcessHeap(), 0, pBuf);
237 /***********************************************************************
238 * EnumProcessModules (PSAPI.@)
241 * Returned list is in load order.
243 BOOL WINAPI EnumProcessModules(HANDLE hProcess, HMODULE *lphModule,
244 DWORD cb, LPDWORD lpcbNeeded)
246 MODULE_ITERATOR iter;
249 if (!PSAPI_ModuleIteratorInit(&iter, hProcess))
254 while ((ret = PSAPI_ModuleIteratorNext(&iter)) > 0)
256 if (cb >= sizeof(HMODULE))
258 *lphModule++ = (HMODULE)iter.LdrModule.BaseAddress;
259 cb -= sizeof(HMODULE);
261 *lpcbNeeded += sizeof(HMODULE);
267 /***********************************************************************
268 * GetDeviceDriverBaseNameA (PSAPI.@)
270 DWORD WINAPI GetDeviceDriverBaseNameA(LPVOID ImageBase, LPSTR lpBaseName,
273 FIXME("(%p, %p, %ld): stub\n", ImageBase, lpBaseName, nSize);
275 if (lpBaseName && nSize)
276 lpBaseName[0] = '\0';
281 /***********************************************************************
282 * GetDeviceDriverBaseNameW (PSAPI.@)
284 DWORD WINAPI GetDeviceDriverBaseNameW(LPVOID ImageBase, LPWSTR lpBaseName,
287 FIXME("(%p, %p, %ld): stub\n", ImageBase, lpBaseName, nSize);
289 if (lpBaseName && nSize)
290 lpBaseName[0] = '\0';
295 /***********************************************************************
296 * GetDeviceDriverFileNameA (PSAPI.@)
298 DWORD WINAPI GetDeviceDriverFileNameA(LPVOID ImageBase, LPSTR lpFilename,
301 FIXME("(%p, %p, %ld): stub\n", ImageBase, lpFilename, nSize);
303 if (lpFilename && nSize)
304 lpFilename[0] = '\0';
309 /***********************************************************************
310 * GetDeviceDriverFileNameW (PSAPI.@)
312 DWORD WINAPI GetDeviceDriverFileNameW(LPVOID ImageBase, LPWSTR lpFilename,
315 FIXME("(%p, %p, %ld): stub\n", ImageBase, lpFilename, nSize);
317 if (lpFilename && nSize)
318 lpFilename[0] = '\0';
323 /***********************************************************************
324 * GetMappedFileNameA (PSAPI.@)
326 DWORD WINAPI GetMappedFileNameA(HANDLE hProcess, LPVOID lpv, LPSTR lpFilename,
329 FIXME("(%p, %p, %p, %ld): stub\n", hProcess, lpv, lpFilename, nSize);
331 if (lpFilename && nSize)
332 lpFilename[0] = '\0';
337 /***********************************************************************
338 * GetMappedFileNameW (PSAPI.@)
340 DWORD WINAPI GetMappedFileNameW(HANDLE hProcess, LPVOID lpv, LPWSTR lpFilename,
343 FIXME("(%p, %p, %p, %ld): stub\n", hProcess, lpv, lpFilename, nSize);
345 if (lpFilename && nSize)
346 lpFilename[0] = '\0';
351 /***********************************************************************
352 * GetModuleBaseNameA (PSAPI.@)
354 DWORD WINAPI GetModuleBaseNameA(HANDLE hProcess, HMODULE hModule,
355 LPSTR lpBaseName, DWORD nSize)
358 DWORD buflenW, ret = 0;
360 if(!lpBaseName || !nSize) {
361 SetLastError(ERROR_INVALID_PARAMETER);
364 lpBaseNameW = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * nSize);
365 buflenW = GetModuleBaseNameW(hProcess, hModule, lpBaseNameW, nSize);
366 TRACE("%ld, %s\n", buflenW, debugstr_w(lpBaseNameW));
369 ret = WideCharToMultiByte(CP_ACP, 0, lpBaseNameW, buflenW,
370 lpBaseName, nSize, NULL, NULL);
371 if (ret < nSize) lpBaseName[ret] = 0;
373 HeapFree(GetProcessHeap(), 0, lpBaseNameW);
377 /***********************************************************************
378 * GetModuleBaseNameW (PSAPI.@)
380 DWORD WINAPI GetModuleBaseNameW(HANDLE hProcess, HMODULE hModule,
381 LPWSTR lpBaseName, DWORD nSize)
383 LDR_MODULE LdrModule;
385 if (!PSAPI_GetLdrModule(hProcess, hModule, &LdrModule))
388 nSize = min(LdrModule.BaseDllName.Length / sizeof(WCHAR), nSize);
389 if (!ReadProcessMemory(hProcess, LdrModule.BaseDllName.Buffer,
390 lpBaseName, nSize * sizeof(WCHAR), NULL))
393 lpBaseName[nSize] = 0;
397 /***********************************************************************
398 * GetModuleFileNameExA (PSAPI.@)
400 DWORD WINAPI GetModuleFileNameExA(HANDLE hProcess, HMODULE hModule,
401 LPSTR lpFileName, DWORD nSize)
405 TRACE("(hProcess=%p, hModule=%p, %p, %ld)\n",
406 hProcess, hModule, lpFileName, nSize);
408 if (!lpFileName || !nSize) return 0;
410 if ( hProcess == GetCurrentProcess() )
412 DWORD len = GetModuleFileNameA( hModule, lpFileName, nSize );
413 if (nSize) lpFileName[nSize - 1] = '\0';
417 if (!(ptr = HeapAlloc(GetProcessHeap(), 0, nSize * sizeof(WCHAR)))) return 0;
419 if (!GetModuleFileNameExW(hProcess, hModule, ptr, nSize))
421 lpFileName[0] = '\0';
425 if (!WideCharToMultiByte( CP_ACP, 0, ptr, -1, lpFileName, nSize, NULL, NULL ))
426 lpFileName[nSize - 1] = 0;
429 HeapFree(GetProcessHeap(), 0, ptr);
430 return strlen(lpFileName);
433 /***********************************************************************
434 * GetModuleFileNameExW (PSAPI.@)
436 DWORD WINAPI GetModuleFileNameExW(HANDLE hProcess, HMODULE hModule,
437 LPWSTR lpFileName, DWORD nSize)
439 LDR_MODULE LdrModule;
441 if(!PSAPI_GetLdrModule(hProcess, hModule, &LdrModule))
444 nSize = min(LdrModule.FullDllName.Length / sizeof(WCHAR), nSize);
445 if (!ReadProcessMemory(hProcess, LdrModule.FullDllName.Buffer,
446 lpFileName, nSize * sizeof(WCHAR), NULL))
449 lpFileName[nSize] = 0;
453 /***********************************************************************
454 * GetModuleInformation (PSAPI.@)
456 BOOL WINAPI GetModuleInformation(HANDLE hProcess, HMODULE hModule,
457 LPMODULEINFO lpmodinfo, DWORD cb)
459 LDR_MODULE LdrModule;
461 if (cb < sizeof(MODULEINFO))
463 SetLastError(ERROR_INSUFFICIENT_BUFFER);
467 if (!PSAPI_GetLdrModule(hProcess, hModule, &LdrModule))
470 lpmodinfo->lpBaseOfDll = LdrModule.BaseAddress;
471 lpmodinfo->SizeOfImage = LdrModule.SizeOfImage;
472 lpmodinfo->EntryPoint = LdrModule.EntryPoint;
476 /***********************************************************************
477 * GetPerformanceInfo (PSAPI.@)
479 BOOL WINAPI GetPerformanceInfo( PPERFORMANCE_INFORMATION info, DWORD size )
483 TRACE( "(%p, %ld)\n", info, size );
485 status = NtQueryInformationProcess( GetCurrentProcess(), SystemPerformanceInformation, info, size, NULL );
489 SetLastError( RtlNtStatusToDosError( status ) );
495 /***********************************************************************
496 * GetProcessImageFileNameA (PSAPI.@)
498 DWORD WINAPI GetProcessImageFileNameA( HANDLE process, LPSTR file, DWORD size )
500 FIXME("(%p, %p, %ld) stub\n", process, file, size );
504 /***********************************************************************
505 * GetProcessImageFileNameW (PSAPI.@)
507 DWORD WINAPI GetProcessImageFileNameW( HANDLE process, LPWSTR file, DWORD size )
509 FIXME("(%p, %p, %ld) stub\n", process, file, size );
513 /***********************************************************************
514 * GetProcessMemoryInfo (PSAPI.@)
516 * Retrieve memory usage information for a given process
519 BOOL WINAPI GetProcessMemoryInfo(HANDLE hProcess,
520 PPROCESS_MEMORY_COUNTERS pmc, DWORD cb)
525 if (cb < sizeof(PROCESS_MEMORY_COUNTERS))
527 SetLastError(ERROR_INSUFFICIENT_BUFFER);
531 status = NtQueryInformationProcess(hProcess, ProcessVmCounters,
532 &vmc, sizeof(vmc), NULL);
536 SetLastError(RtlNtStatusToDosError(status));
540 pmc->cb = sizeof(PROCESS_MEMORY_COUNTERS);
541 pmc->PageFaultCount = vmc.PageFaultCount;
542 pmc->PeakWorkingSetSize = vmc.PeakWorkingSetSize;
543 pmc->WorkingSetSize = vmc.WorkingSetSize;
544 pmc->QuotaPeakPagedPoolUsage = vmc.QuotaPeakPagedPoolUsage;
545 pmc->QuotaPagedPoolUsage = vmc.QuotaPagedPoolUsage;
546 pmc->QuotaPeakNonPagedPoolUsage = vmc.QuotaPeakNonPagedPoolUsage;
547 pmc->QuotaNonPagedPoolUsage = vmc.QuotaNonPagedPoolUsage;
548 pmc->PagefileUsage = vmc.PagefileUsage;
549 pmc->PeakPagefileUsage = vmc.PeakPagefileUsage;
554 /***********************************************************************
555 * GetWsChanges (PSAPI.@)
557 BOOL WINAPI GetWsChanges( HANDLE process, PPSAPI_WS_WATCH_INFORMATION watchinfo, DWORD size )
561 TRACE( "(%p, %p, %ld)\n", process, watchinfo, size );
563 status = NtQueryVirtualMemory( process, NULL, ProcessWorkingSetWatch, watchinfo, size, NULL );
567 SetLastError( RtlNtStatusToDosError( status ) );
573 /***********************************************************************
574 * InitializeProcessForWsWatch (PSAPI.@)
576 BOOL WINAPI InitializeProcessForWsWatch(HANDLE hProcess)
578 FIXME("(hProcess=%p): stub\n", hProcess);
583 /***********************************************************************
584 * QueryWorkingSet (PSAPI.@)
586 BOOL WINAPI QueryWorkingSet( HANDLE process, LPVOID buffer, DWORD size )
590 TRACE( "(%p, %p, %ld)\n", process, buffer, size );
592 status = NtQueryVirtualMemory( process, NULL, MemoryWorkingSetList, buffer, size, NULL );
596 SetLastError( RtlNtStatusToDosError( status ) );
602 /***********************************************************************
603 * QueryWorkingSetEx (PSAPI.@)
605 BOOL WINAPI QueryWorkingSetEx( HANDLE process, LPVOID buffer, DWORD size )
609 TRACE( "(%p, %p, %ld)\n", process, buffer, size );
611 status = NtQueryVirtualMemory( process, NULL, MemoryWorkingSetList, buffer, size, NULL );
615 SetLastError( RtlNtStatusToDosError( status ) );