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
) );