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
, &((PPEB
)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
== (HMODULE
)iter
.LdrModule
.BaseAddress
)
140 *pLdrModule
= iter
.LdrModule
;
145 SetLastError(ERROR_INVALID_HANDLE
);
150 /***********************************************************************
151 * EmptyWorkingSet (PSAPI.@)
153 BOOL WINAPI
EmptyWorkingSet(HANDLE hProcess
)
155 return SetProcessWorkingSetSize(hProcess
, 0xFFFFFFFF, 0xFFFFFFFF);
158 /***********************************************************************
159 * EnumDeviceDrivers (PSAPI.@)
161 BOOL WINAPI
EnumDeviceDrivers(LPVOID
*lpImageBase
, DWORD cb
, LPDWORD lpcbNeeded
)
163 FIXME("(%p, %ld, %p): stub\n", lpImageBase
, cb
, lpcbNeeded
);
171 /***********************************************************************
172 * EnumPageFilesA (PSAPI.@)
174 BOOL WINAPI
EnumPageFilesA( PENUM_PAGE_FILE_CALLBACKA callback
, LPVOID context
)
176 FIXME("(%p, %p) stub\n", callback
, context
);
180 /***********************************************************************
181 * EnumPageFilesW (PSAPI.@)
183 BOOL WINAPI
EnumPageFilesW( PENUM_PAGE_FILE_CALLBACKW callback
, LPVOID context
)
185 FIXME("(%p, %p) stub\n", callback
, context
);
189 /***********************************************************************
190 * EnumProcesses (PSAPI.@)
192 BOOL WINAPI
EnumProcesses(DWORD
*lpdwProcessIDs
, DWORD cb
, DWORD
*lpcbUsed
)
194 SYSTEM_PROCESS_INFORMATION
*spi
;
197 ULONG nAlloc
= 0x8000;
202 HeapFree(GetProcessHeap(), 0, pBuf
);
206 pBuf
= HeapAlloc(GetProcessHeap(), 0, nAlloc
);
210 status
= NtQuerySystemInformation(SystemProcessInformation
, pBuf
,
212 } while (status
== STATUS_INFO_LENGTH_MISMATCH
);
214 if (status
!= STATUS_SUCCESS
)
216 HeapFree(GetProcessHeap(), 0, pBuf
);
217 SetLastError(RtlNtStatusToDosError(status
));
223 for (*lpcbUsed
= 0; cb
>= sizeof(DWORD
); cb
-= sizeof(DWORD
))
225 *lpdwProcessIDs
++ = spi
->dwProcessID
;
226 *lpcbUsed
+= sizeof(DWORD
);
228 if (spi
->dwOffset
== 0)
231 spi
= (SYSTEM_PROCESS_INFORMATION
*)(((PCHAR
)spi
) + spi
->dwOffset
);
234 HeapFree(GetProcessHeap(), 0, pBuf
);
238 /***********************************************************************
239 * EnumProcessModules (PSAPI.@)
242 * Returned list is in load order.
244 BOOL WINAPI
EnumProcessModules(HANDLE hProcess
, HMODULE
*lphModule
,
245 DWORD cb
, LPDWORD lpcbNeeded
)
247 MODULE_ITERATOR iter
;
250 if (!PSAPI_ModuleIteratorInit(&iter
, hProcess
))
255 while ((ret
= PSAPI_ModuleIteratorNext(&iter
)) > 0)
257 if (cb
>= sizeof(HMODULE
))
259 *lphModule
++ = (HMODULE
)iter
.LdrModule
.BaseAddress
;
260 cb
-= sizeof(HMODULE
);
262 *lpcbNeeded
+= sizeof(HMODULE
);
268 /***********************************************************************
269 * GetDeviceDriverBaseNameA (PSAPI.@)
271 DWORD WINAPI
GetDeviceDriverBaseNameA(LPVOID ImageBase
, LPSTR lpBaseName
,
274 FIXME("(%p, %p, %ld): stub\n", ImageBase
, lpBaseName
, nSize
);
276 if (lpBaseName
&& nSize
)
277 lpBaseName
[0] = '\0';
282 /***********************************************************************
283 * GetDeviceDriverBaseNameW (PSAPI.@)
285 DWORD WINAPI
GetDeviceDriverBaseNameW(LPVOID ImageBase
, LPWSTR lpBaseName
,
288 FIXME("(%p, %p, %ld): stub\n", ImageBase
, lpBaseName
, nSize
);
290 if (lpBaseName
&& nSize
)
291 lpBaseName
[0] = '\0';
296 /***********************************************************************
297 * GetDeviceDriverFileNameA (PSAPI.@)
299 DWORD WINAPI
GetDeviceDriverFileNameA(LPVOID ImageBase
, LPSTR lpFilename
,
302 FIXME("(%p, %p, %ld): stub\n", ImageBase
, lpFilename
, nSize
);
304 if (lpFilename
&& nSize
)
305 lpFilename
[0] = '\0';
310 /***********************************************************************
311 * GetDeviceDriverFileNameW (PSAPI.@)
313 DWORD WINAPI
GetDeviceDriverFileNameW(LPVOID ImageBase
, LPWSTR lpFilename
,
316 FIXME("(%p, %p, %ld): stub\n", ImageBase
, lpFilename
, nSize
);
318 if (lpFilename
&& nSize
)
319 lpFilename
[0] = '\0';
324 /***********************************************************************
325 * GetMappedFileNameA (PSAPI.@)
327 DWORD WINAPI
GetMappedFileNameA(HANDLE hProcess
, LPVOID lpv
, LPSTR lpFilename
,
330 FIXME("(%p, %p, %p, %ld): stub\n", hProcess
, lpv
, lpFilename
, nSize
);
332 if (lpFilename
&& nSize
)
333 lpFilename
[0] = '\0';
338 /***********************************************************************
339 * GetMappedFileNameW (PSAPI.@)
341 DWORD WINAPI
GetMappedFileNameW(HANDLE hProcess
, LPVOID lpv
, LPWSTR lpFilename
,
344 FIXME("(%p, %p, %p, %ld): stub\n", hProcess
, lpv
, lpFilename
, nSize
);
346 if (lpFilename
&& nSize
)
347 lpFilename
[0] = '\0';
352 /***********************************************************************
353 * GetModuleBaseNameA (PSAPI.@)
355 DWORD WINAPI
GetModuleBaseNameA(HANDLE hProcess
, HMODULE hModule
,
356 LPSTR lpBaseName
, DWORD nSize
)
359 DWORD buflenW
, ret
= 0;
361 if(!lpBaseName
|| !nSize
) {
362 SetLastError(ERROR_INVALID_PARAMETER
);
365 lpBaseNameW
= HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR
) * nSize
);
366 buflenW
= GetModuleBaseNameW(hProcess
, hModule
, lpBaseNameW
, nSize
);
367 TRACE("%ld, %s\n", buflenW
, debugstr_w(lpBaseNameW
));
370 ret
= WideCharToMultiByte(CP_ACP
, 0, lpBaseNameW
, buflenW
,
371 lpBaseName
, nSize
, NULL
, NULL
);
372 if (ret
< nSize
) lpBaseName
[ret
] = 0;
374 HeapFree(GetProcessHeap(), 0, lpBaseNameW
);
378 /***********************************************************************
379 * GetModuleBaseNameW (PSAPI.@)
381 DWORD WINAPI
GetModuleBaseNameW(HANDLE hProcess
, HMODULE hModule
,
382 LPWSTR lpBaseName
, DWORD nSize
)
384 LDR_MODULE LdrModule
;
386 if (!PSAPI_GetLdrModule(hProcess
, hModule
, &LdrModule
))
389 nSize
= min(LdrModule
.BaseDllName
.Length
/ sizeof(WCHAR
), nSize
);
390 if (!ReadProcessMemory(hProcess
, LdrModule
.BaseDllName
.Buffer
,
391 lpBaseName
, nSize
* sizeof(WCHAR
), NULL
))
394 lpBaseName
[nSize
] = 0;
398 /***********************************************************************
399 * GetModuleFileNameExA (PSAPI.@)
401 DWORD WINAPI
GetModuleFileNameExA(HANDLE hProcess
, HMODULE hModule
,
402 LPSTR lpFileName
, DWORD nSize
)
406 TRACE("(hProcess=%p, hModule=%p, %p, %ld)\n",
407 hProcess
, hModule
, lpFileName
, nSize
);
409 if (!lpFileName
|| !nSize
) return 0;
411 if ( hProcess
== GetCurrentProcess() )
413 DWORD len
= GetModuleFileNameA( hModule
, lpFileName
, nSize
);
414 if (nSize
) lpFileName
[nSize
- 1] = '\0';
418 if (!(ptr
= HeapAlloc(GetProcessHeap(), 0, nSize
* sizeof(WCHAR
)))) return 0;
420 if (!GetModuleFileNameExW(hProcess
, hModule
, ptr
, nSize
))
422 lpFileName
[0] = '\0';
426 if (!WideCharToMultiByte( CP_ACP
, 0, ptr
, -1, lpFileName
, nSize
, NULL
, NULL
))
427 lpFileName
[nSize
- 1] = 0;
430 HeapFree(GetProcessHeap(), 0, ptr
);
431 return strlen(lpFileName
);
434 /***********************************************************************
435 * GetModuleFileNameExW (PSAPI.@)
437 DWORD WINAPI
GetModuleFileNameExW(HANDLE hProcess
, HMODULE hModule
,
438 LPWSTR lpFileName
, DWORD nSize
)
440 LDR_MODULE LdrModule
;
442 if(!PSAPI_GetLdrModule(hProcess
, hModule
, &LdrModule
))
445 nSize
= min(LdrModule
.FullDllName
.Length
/ sizeof(WCHAR
), nSize
);
446 if (!ReadProcessMemory(hProcess
, LdrModule
.FullDllName
.Buffer
,
447 lpFileName
, nSize
* sizeof(WCHAR
), NULL
))
450 lpFileName
[nSize
] = 0;
454 /***********************************************************************
455 * GetModuleInformation (PSAPI.@)
457 BOOL WINAPI
GetModuleInformation(HANDLE hProcess
, HMODULE hModule
,
458 LPMODULEINFO lpmodinfo
, DWORD cb
)
460 LDR_MODULE LdrModule
;
462 if (cb
< sizeof(MODULEINFO
))
464 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
468 if (!PSAPI_GetLdrModule(hProcess
, hModule
, &LdrModule
))
471 lpmodinfo
->lpBaseOfDll
= LdrModule
.BaseAddress
;
472 lpmodinfo
->SizeOfImage
= LdrModule
.SizeOfImage
;
473 lpmodinfo
->EntryPoint
= LdrModule
.EntryPoint
;
477 /***********************************************************************
478 * GetPerformanceInfo (PSAPI.@)
480 BOOL WINAPI
GetPerformanceInfo( PPERFORMANCE_INFORMATION info
, DWORD size
)
484 TRACE( "(%p, %ld)\n", info
, size
);
486 status
= NtQueryInformationProcess( GetCurrentProcess(), SystemPerformanceInformation
, info
, size
, NULL
);
490 SetLastError( RtlNtStatusToDosError( status
) );
496 /***********************************************************************
497 * GetProcessImageFileNameA (PSAPI.@)
499 DWORD WINAPI
GetProcessImageFileNameA( HANDLE process
, LPSTR file
, DWORD size
)
501 FIXME("(%p, %p, %ld) stub\n", process
, file
, size
);
505 /***********************************************************************
506 * GetProcessImageFileNameW (PSAPI.@)
508 DWORD WINAPI
GetProcessImageFileNameW( HANDLE process
, LPWSTR file
, DWORD size
)
510 FIXME("(%p, %p, %ld) stub\n", process
, file
, size
);
514 /***********************************************************************
515 * GetProcessMemoryInfo (PSAPI.@)
517 * Retrieve memory usage information for a given process
520 BOOL WINAPI
GetProcessMemoryInfo(HANDLE hProcess
,
521 PPROCESS_MEMORY_COUNTERS pmc
, DWORD cb
)
526 if (cb
< sizeof(PROCESS_MEMORY_COUNTERS
))
528 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
532 status
= NtQueryInformationProcess(hProcess
, ProcessVmCounters
,
533 &vmc
, sizeof(vmc
), NULL
);
537 SetLastError(RtlNtStatusToDosError(status
));
541 pmc
->cb
= sizeof(PROCESS_MEMORY_COUNTERS
);
542 pmc
->PageFaultCount
= vmc
.PageFaultCount
;
543 pmc
->PeakWorkingSetSize
= vmc
.PeakWorkingSetSize
;
544 pmc
->WorkingSetSize
= vmc
.WorkingSetSize
;
545 pmc
->QuotaPeakPagedPoolUsage
= vmc
.QuotaPeakPagedPoolUsage
;
546 pmc
->QuotaPagedPoolUsage
= vmc
.QuotaPagedPoolUsage
;
547 pmc
->QuotaPeakNonPagedPoolUsage
= vmc
.QuotaPeakNonPagedPoolUsage
;
548 pmc
->QuotaNonPagedPoolUsage
= vmc
.QuotaNonPagedPoolUsage
;
549 pmc
->PagefileUsage
= vmc
.PagefileUsage
;
550 pmc
->PeakPagefileUsage
= vmc
.PeakPagefileUsage
;
555 /***********************************************************************
556 * GetWsChanges (PSAPI.@)
558 BOOL WINAPI
GetWsChanges( HANDLE process
, PPSAPI_WS_WATCH_INFORMATION watchinfo
, DWORD size
)
562 TRACE( "(%p, %p, %ld)\n", process
, watchinfo
, size
);
564 status
= NtQueryVirtualMemory( process
, NULL
, ProcessWorkingSetWatch
, watchinfo
, size
, NULL
);
568 SetLastError( RtlNtStatusToDosError( status
) );
574 /***********************************************************************
575 * InitializeProcessForWsWatch (PSAPI.@)
577 BOOL WINAPI
InitializeProcessForWsWatch(HANDLE hProcess
)
579 FIXME("(hProcess=%p): stub\n", hProcess
);
584 /***********************************************************************
585 * QueryWorkingSet (PSAPI.@)
587 BOOL WINAPI
QueryWorkingSet( HANDLE process
, LPVOID buffer
, DWORD size
)
591 TRACE( "(%p, %p, %ld)\n", process
, buffer
, size
);
593 status
= NtQueryVirtualMemory( process
, NULL
, MemoryWorkingSetList
, buffer
, size
, NULL
);
597 SetLastError( RtlNtStatusToDosError( status
) );
603 /***********************************************************************
604 * QueryWorkingSetEx (PSAPI.@)
606 BOOL WINAPI
QueryWorkingSetEx( HANDLE process
, LPVOID buffer
, DWORD size
)
610 TRACE( "(%p, %p, %ld)\n", process
, buffer
, size
);
612 status
= NtQueryVirtualMemory( process
, NULL
, MemoryWorkingSetList
, buffer
, size
, NULL
);
616 SetLastError( RtlNtStatusToDosError( status
) );