Create a function to read a property as an integer.
[wine/hacks.git] / dlls / psapi / psapi_main.c
blob9e98ad9d0bdf3caab98433dccf5e3114f66ef55d
1 /*
2 * PSAPI library
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
22 #include <stdarg.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winerror.h"
27 #include "wine/unicode.h"
28 #include "wine/debug.h"
29 #include "winnls.h"
30 #include "winternl.h"
31 #include "ntstatus.h"
32 #include "psapi.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(psapi);
36 typedef struct
38 HANDLE hProcess;
39 PLIST_ENTRY pHead, pCurrent;
40 LDR_MODULE LdrModule;
41 } MODULE_ITERATOR;
43 /***********************************************************************
44 * PSAPI_ModuleIteratorInit [internal]
46 * Prepares to iterate through the loaded modules of the given process.
48 * RETURNS
49 * Success: TRUE
50 * Failure: FALSE
52 static BOOL PSAPI_ModuleIteratorInit(MODULE_ITERATOR *iter, HANDLE hProcess)
54 PROCESS_BASIC_INFORMATION pbi;
55 PPEB_LDR_DATA pLdrData;
56 NTSTATUS status;
58 /* Get address of PEB */
59 status = NtQueryInformationProcess(hProcess, ProcessBasicInformation,
60 &pbi, sizeof(pbi), NULL);
61 if (status != STATUS_SUCCESS)
63 SetLastError(RtlNtStatusToDosError(status));
64 return FALSE;
67 /* Read address of LdrData from PEB */
68 if (!ReadProcessMemory(hProcess, &((PPEB)pbi.PebBaseAddress)->LdrData,
69 &pLdrData, sizeof(pLdrData), NULL))
70 return FALSE;
72 /* Read address of first module from LdrData */
73 if (!ReadProcessMemory(hProcess,
74 &pLdrData->InLoadOrderModuleList.Flink,
75 &iter->pCurrent, sizeof(iter->pCurrent), NULL))
76 return FALSE;
78 iter->pHead = &pLdrData->InLoadOrderModuleList;
79 iter->hProcess = hProcess;
81 return TRUE;
84 /***********************************************************************
85 * PSAPI_ModuleIteratorNext [internal]
87 * Iterates to the next module.
89 * RETURNS
90 * 1 : Success
91 * 0 : No more modules
92 * -1 : Failure
94 * NOTES
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)
103 return 0;
105 if (!ReadProcessMemory(iter->hProcess, CONTAINING_RECORD(iter->pCurrent,
106 LDR_MODULE, InLoadOrderModuleList),
107 &iter->LdrModule, sizeof(iter->LdrModule), NULL))
108 return -1;
109 else
110 iter->pCurrent = iter->LdrModule.InLoadOrderModuleList.Flink;
112 return 1;
115 /***********************************************************************
116 * PSAPI_GetLdrModule [internal]
118 * Reads the LDR_MODULE structure of the given module.
120 * RETURNS
121 * Success: TRUE
122 * Failure: FALSE
125 static BOOL PSAPI_GetLdrModule(HANDLE hProcess, HMODULE hModule,
126 LDR_MODULE *pLdrModule)
128 MODULE_ITERATOR iter;
129 INT ret;
131 if (!PSAPI_ModuleIteratorInit(&iter, hProcess))
132 return FALSE;
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;
140 return TRUE;
143 if (ret == 0)
144 SetLastError(ERROR_INVALID_HANDLE);
146 return FALSE;
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);
164 if (lpcbNeeded)
165 *lpcbNeeded = 0;
167 return TRUE;
170 /***********************************************************************
171 * EnumPageFilesA (PSAPI.@)
173 BOOL WINAPI EnumPageFilesA( PENUM_PAGE_FILE_CALLBACKA callback, LPVOID context )
175 FIXME("(%p, %p) stub\n", callback, context );
176 return FALSE;
179 /***********************************************************************
180 * EnumPageFilesW (PSAPI.@)
182 BOOL WINAPI EnumPageFilesW( PENUM_PAGE_FILE_CALLBACKW callback, LPVOID context )
184 FIXME("(%p, %p) stub\n", callback, context );
185 return FALSE;
188 /***********************************************************************
189 * EnumProcesses (PSAPI.@)
191 BOOL WINAPI EnumProcesses(DWORD *lpdwProcessIDs, DWORD cb, DWORD *lpcbUsed)
193 SYSTEM_PROCESS_INFORMATION *spi;
194 NTSTATUS status;
195 PVOID pBuf = NULL;
196 ULONG nAlloc = 0x8000;
198 do {
199 if (pBuf != NULL)
201 HeapFree(GetProcessHeap(), 0, pBuf);
202 nAlloc *= 2;
205 pBuf = HeapAlloc(GetProcessHeap(), 0, nAlloc);
206 if (pBuf == NULL)
207 return FALSE;
209 status = NtQuerySystemInformation(SystemProcessInformation, pBuf,
210 nAlloc, NULL);
211 } while (status == STATUS_INFO_LENGTH_MISMATCH);
213 if (status != STATUS_SUCCESS)
215 HeapFree(GetProcessHeap(), 0, pBuf);
216 SetLastError(RtlNtStatusToDosError(status));
217 return FALSE;
220 spi = pBuf;
222 for (*lpcbUsed = 0; cb >= sizeof(DWORD); cb -= sizeof(DWORD))
224 *lpdwProcessIDs++ = spi->dwProcessID;
225 *lpcbUsed += sizeof(DWORD);
227 if (spi->dwOffset == 0)
228 break;
230 spi = (SYSTEM_PROCESS_INFORMATION *)(((PCHAR)spi) + spi->dwOffset);
233 HeapFree(GetProcessHeap(), 0, pBuf);
234 return TRUE;
237 /***********************************************************************
238 * EnumProcessModules (PSAPI.@)
240 * NOTES
241 * Returned list is in load order.
243 BOOL WINAPI EnumProcessModules(HANDLE hProcess, HMODULE *lphModule,
244 DWORD cb, LPDWORD lpcbNeeded)
246 MODULE_ITERATOR iter;
247 INT ret;
249 if (!PSAPI_ModuleIteratorInit(&iter, hProcess))
250 return FALSE;
252 *lpcbNeeded = 0;
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);
264 return (ret == 0);
267 /***********************************************************************
268 * GetDeviceDriverBaseNameA (PSAPI.@)
270 DWORD WINAPI GetDeviceDriverBaseNameA(LPVOID ImageBase, LPSTR lpBaseName,
271 DWORD nSize)
273 FIXME("(%p, %p, %ld): stub\n", ImageBase, lpBaseName, nSize);
275 if (lpBaseName && nSize)
276 lpBaseName[0] = '\0';
278 return 0;
281 /***********************************************************************
282 * GetDeviceDriverBaseNameW (PSAPI.@)
284 DWORD WINAPI GetDeviceDriverBaseNameW(LPVOID ImageBase, LPWSTR lpBaseName,
285 DWORD nSize)
287 FIXME("(%p, %p, %ld): stub\n", ImageBase, lpBaseName, nSize);
289 if (lpBaseName && nSize)
290 lpBaseName[0] = '\0';
292 return 0;
295 /***********************************************************************
296 * GetDeviceDriverFileNameA (PSAPI.@)
298 DWORD WINAPI GetDeviceDriverFileNameA(LPVOID ImageBase, LPSTR lpFilename,
299 DWORD nSize)
301 FIXME("(%p, %p, %ld): stub\n", ImageBase, lpFilename, nSize);
303 if (lpFilename && nSize)
304 lpFilename[0] = '\0';
306 return 0;
309 /***********************************************************************
310 * GetDeviceDriverFileNameW (PSAPI.@)
312 DWORD WINAPI GetDeviceDriverFileNameW(LPVOID ImageBase, LPWSTR lpFilename,
313 DWORD nSize)
315 FIXME("(%p, %p, %ld): stub\n", ImageBase, lpFilename, nSize);
317 if (lpFilename && nSize)
318 lpFilename[0] = '\0';
320 return 0;
323 /***********************************************************************
324 * GetMappedFileNameA (PSAPI.@)
326 DWORD WINAPI GetMappedFileNameA(HANDLE hProcess, LPVOID lpv, LPSTR lpFilename,
327 DWORD nSize)
329 FIXME("(%p, %p, %p, %ld): stub\n", hProcess, lpv, lpFilename, nSize);
331 if (lpFilename && nSize)
332 lpFilename[0] = '\0';
334 return 0;
337 /***********************************************************************
338 * GetMappedFileNameW (PSAPI.@)
340 DWORD WINAPI GetMappedFileNameW(HANDLE hProcess, LPVOID lpv, LPWSTR lpFilename,
341 DWORD nSize)
343 FIXME("(%p, %p, %p, %ld): stub\n", hProcess, lpv, lpFilename, nSize);
345 if (lpFilename && nSize)
346 lpFilename[0] = '\0';
348 return 0;
351 /***********************************************************************
352 * GetModuleBaseNameA (PSAPI.@)
354 DWORD WINAPI GetModuleBaseNameA(HANDLE hProcess, HMODULE hModule,
355 LPSTR lpBaseName, DWORD nSize)
357 WCHAR *lpBaseNameW;
358 DWORD buflenW, ret = 0;
360 if(!lpBaseName || !nSize) {
361 SetLastError(ERROR_INVALID_PARAMETER);
362 return 0;
364 lpBaseNameW = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * nSize);
365 buflenW = GetModuleBaseNameW(hProcess, hModule, lpBaseNameW, nSize);
366 TRACE("%ld, %s\n", buflenW, debugstr_w(lpBaseNameW));
367 if (buflenW)
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);
374 return ret;
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))
386 return 0;
388 nSize = min(LdrModule.BaseDllName.Length / sizeof(WCHAR), nSize);
389 if (!ReadProcessMemory(hProcess, LdrModule.BaseDllName.Buffer,
390 lpBaseName, nSize * sizeof(WCHAR), NULL))
391 return 0;
393 lpBaseName[nSize] = 0;
394 return nSize;
397 /***********************************************************************
398 * GetModuleFileNameExA (PSAPI.@)
400 DWORD WINAPI GetModuleFileNameExA(HANDLE hProcess, HMODULE hModule,
401 LPSTR lpFileName, DWORD nSize)
403 WCHAR *ptr;
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';
414 return len;
417 if (!(ptr = HeapAlloc(GetProcessHeap(), 0, nSize * sizeof(WCHAR)))) return 0;
419 if (!GetModuleFileNameExW(hProcess, hModule, ptr, nSize))
421 lpFileName[0] = '\0';
423 else
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))
442 return 0;
444 nSize = min(LdrModule.FullDllName.Length / sizeof(WCHAR), nSize);
445 if (!ReadProcessMemory(hProcess, LdrModule.FullDllName.Buffer,
446 lpFileName, nSize * sizeof(WCHAR), NULL))
447 return 0;
449 lpFileName[nSize] = 0;
450 return nSize;
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);
464 return FALSE;
467 if (!PSAPI_GetLdrModule(hProcess, hModule, &LdrModule))
468 return FALSE;
470 lpmodinfo->lpBaseOfDll = LdrModule.BaseAddress;
471 lpmodinfo->SizeOfImage = LdrModule.SizeOfImage;
472 lpmodinfo->EntryPoint = LdrModule.EntryPoint;
473 return TRUE;
476 /***********************************************************************
477 * GetPerformanceInfo (PSAPI.@)
479 BOOL WINAPI GetPerformanceInfo( PPERFORMANCE_INFORMATION info, DWORD size )
481 NTSTATUS status;
483 TRACE( "(%p, %ld)\n", info, size );
485 status = NtQueryInformationProcess( GetCurrentProcess(), SystemPerformanceInformation, info, size, NULL );
487 if (status)
489 SetLastError( RtlNtStatusToDosError( status ) );
490 return FALSE;
492 return TRUE;
495 /***********************************************************************
496 * GetProcessImageFileNameA (PSAPI.@)
498 DWORD WINAPI GetProcessImageFileNameA( HANDLE process, LPSTR file, DWORD size )
500 FIXME("(%p, %p, %ld) stub\n", process, file, size );
501 return 0;
504 /***********************************************************************
505 * GetProcessImageFileNameW (PSAPI.@)
507 DWORD WINAPI GetProcessImageFileNameW( HANDLE process, LPWSTR file, DWORD size )
509 FIXME("(%p, %p, %ld) stub\n", process, file, size );
510 return 0;
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)
522 NTSTATUS status;
523 VM_COUNTERS vmc;
525 if (cb < sizeof(PROCESS_MEMORY_COUNTERS))
527 SetLastError(ERROR_INSUFFICIENT_BUFFER);
528 return FALSE;
531 status = NtQueryInformationProcess(hProcess, ProcessVmCounters,
532 &vmc, sizeof(vmc), NULL);
534 if (status)
536 SetLastError(RtlNtStatusToDosError(status));
537 return FALSE;
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;
551 return TRUE;
554 /***********************************************************************
555 * GetWsChanges (PSAPI.@)
557 BOOL WINAPI GetWsChanges( HANDLE process, PPSAPI_WS_WATCH_INFORMATION watchinfo, DWORD size )
559 NTSTATUS status;
561 TRACE( "(%p, %p, %ld)\n", process, watchinfo, size );
563 status = NtQueryVirtualMemory( process, NULL, ProcessWorkingSetWatch, watchinfo, size, NULL );
565 if (status)
567 SetLastError( RtlNtStatusToDosError( status ) );
568 return FALSE;
570 return TRUE;
573 /***********************************************************************
574 * InitializeProcessForWsWatch (PSAPI.@)
576 BOOL WINAPI InitializeProcessForWsWatch(HANDLE hProcess)
578 FIXME("(hProcess=%p): stub\n", hProcess);
580 return TRUE;
583 /***********************************************************************
584 * QueryWorkingSet (PSAPI.@)
586 BOOL WINAPI QueryWorkingSet( HANDLE process, LPVOID buffer, DWORD size )
588 NTSTATUS status;
590 TRACE( "(%p, %p, %ld)\n", process, buffer, size );
592 status = NtQueryVirtualMemory( process, NULL, MemoryWorkingSetList, buffer, size, NULL );
594 if (status)
596 SetLastError( RtlNtStatusToDosError( status ) );
597 return FALSE;
599 return TRUE;
602 /***********************************************************************
603 * QueryWorkingSetEx (PSAPI.@)
605 BOOL WINAPI QueryWorkingSetEx( HANDLE process, LPVOID buffer, DWORD size )
607 NTSTATUS status;
609 TRACE( "(%p, %p, %ld)\n", process, buffer, size );
611 status = NtQueryVirtualMemory( process, NULL, MemoryWorkingSetList, buffer, size, NULL );
613 if (status)
615 SetLastError( RtlNtStatusToDosError( status ) );
616 return FALSE;
618 return TRUE;