user32: Fix a message test that would only pass on wine.
[wine.git] / dlls / psapi / psapi_main.c
blob9fe8281f9d369e96697ce29b3b8cb803ab64242b
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include <stdarg.h>
24 #include "ntstatus.h"
25 #define WIN32_NO_STATUS
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winerror.h"
29 #include "wine/unicode.h"
30 #include "wine/debug.h"
31 #include "winnls.h"
32 #include "winternl.h"
33 #include "psapi.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(psapi);
37 typedef struct
39 HANDLE hProcess;
40 PLIST_ENTRY pHead, pCurrent;
41 LDR_MODULE LdrModule;
42 } MODULE_ITERATOR;
44 /***********************************************************************
45 * PSAPI_ModuleIteratorInit [internal]
47 * Prepares to iterate through the loaded modules of the given process.
49 * RETURNS
50 * Success: TRUE
51 * Failure: FALSE
53 static BOOL PSAPI_ModuleIteratorInit(MODULE_ITERATOR *iter, HANDLE hProcess)
55 PROCESS_BASIC_INFORMATION pbi;
56 PPEB_LDR_DATA pLdrData;
57 NTSTATUS status;
59 /* Get address of PEB */
60 status = NtQueryInformationProcess(hProcess, ProcessBasicInformation,
61 &pbi, sizeof(pbi), NULL);
62 if (status != STATUS_SUCCESS)
64 SetLastError(RtlNtStatusToDosError(status));
65 return FALSE;
68 /* Read address of LdrData from PEB */
69 if (!ReadProcessMemory(hProcess, &pbi.PebBaseAddress->LdrData,
70 &pLdrData, sizeof(pLdrData), NULL))
71 return FALSE;
73 /* Read address of first module from LdrData */
74 if (!ReadProcessMemory(hProcess,
75 &pLdrData->InLoadOrderModuleList.Flink,
76 &iter->pCurrent, sizeof(iter->pCurrent), NULL))
77 return FALSE;
79 iter->pHead = &pLdrData->InLoadOrderModuleList;
80 iter->hProcess = hProcess;
82 return TRUE;
85 /***********************************************************************
86 * PSAPI_ModuleIteratorNext [internal]
88 * Iterates to the next module.
90 * RETURNS
91 * 1 : Success
92 * 0 : No more modules
93 * -1 : Failure
95 * NOTES
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)
104 return 0;
106 if (!ReadProcessMemory(iter->hProcess, CONTAINING_RECORD(iter->pCurrent,
107 LDR_MODULE, InLoadOrderModuleList),
108 &iter->LdrModule, sizeof(iter->LdrModule), NULL))
109 return -1;
110 else
111 iter->pCurrent = iter->LdrModule.InLoadOrderModuleList.Flink;
113 return 1;
116 /***********************************************************************
117 * PSAPI_GetLdrModule [internal]
119 * Reads the LDR_MODULE structure of the given module.
121 * RETURNS
122 * Success: TRUE
123 * Failure: FALSE
126 static BOOL PSAPI_GetLdrModule(HANDLE hProcess, HMODULE hModule,
127 LDR_MODULE *pLdrModule)
129 MODULE_ITERATOR iter;
130 INT ret;
132 if (!PSAPI_ModuleIteratorInit(&iter, hProcess))
133 return FALSE;
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;
141 return TRUE;
144 if (ret == 0)
145 SetLastError(ERROR_INVALID_HANDLE);
147 return FALSE;
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, %d, %p): stub\n", lpImageBase, cb, lpcbNeeded);
165 if (lpcbNeeded)
166 *lpcbNeeded = 0;
168 return TRUE;
171 /***********************************************************************
172 * EnumPageFilesA (PSAPI.@)
174 BOOL WINAPI EnumPageFilesA( PENUM_PAGE_FILE_CALLBACKA callback, LPVOID context )
176 FIXME("(%p, %p) stub\n", callback, context );
177 return FALSE;
180 /***********************************************************************
181 * EnumPageFilesW (PSAPI.@)
183 BOOL WINAPI EnumPageFilesW( PENUM_PAGE_FILE_CALLBACKW callback, LPVOID context )
185 FIXME("(%p, %p) stub\n", callback, context );
186 return FALSE;
189 /***********************************************************************
190 * EnumProcesses (PSAPI.@)
192 BOOL WINAPI EnumProcesses(DWORD *lpdwProcessIDs, DWORD cb, DWORD *lpcbUsed)
194 SYSTEM_PROCESS_INFORMATION *spi;
195 NTSTATUS status;
196 PVOID pBuf = NULL;
197 ULONG nAlloc = 0x8000;
199 do {
200 if (pBuf != NULL)
202 HeapFree(GetProcessHeap(), 0, pBuf);
203 nAlloc *= 2;
206 pBuf = HeapAlloc(GetProcessHeap(), 0, nAlloc);
207 if (pBuf == NULL)
208 return FALSE;
210 status = NtQuerySystemInformation(SystemProcessInformation, pBuf,
211 nAlloc, NULL);
212 } while (status == STATUS_INFO_LENGTH_MISMATCH);
214 if (status != STATUS_SUCCESS)
216 HeapFree(GetProcessHeap(), 0, pBuf);
217 SetLastError(RtlNtStatusToDosError(status));
218 return FALSE;
221 spi = pBuf;
223 for (*lpcbUsed = 0; cb >= sizeof(DWORD); cb -= sizeof(DWORD))
225 *lpdwProcessIDs++ = spi->dwProcessID;
226 *lpcbUsed += sizeof(DWORD);
228 if (spi->dwOffset == 0)
229 break;
231 spi = (SYSTEM_PROCESS_INFORMATION *)(((PCHAR)spi) + spi->dwOffset);
234 HeapFree(GetProcessHeap(), 0, pBuf);
235 return TRUE;
238 /***********************************************************************
239 * EnumProcessModules (PSAPI.@)
241 * NOTES
242 * Returned list is in load order.
244 BOOL WINAPI EnumProcessModules(HANDLE hProcess, HMODULE *lphModule,
245 DWORD cb, LPDWORD lpcbNeeded)
247 MODULE_ITERATOR iter;
248 INT ret;
250 if (!PSAPI_ModuleIteratorInit(&iter, hProcess))
251 return FALSE;
253 *lpcbNeeded = 0;
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);
265 return (ret == 0);
268 /***********************************************************************
269 * GetDeviceDriverBaseNameA (PSAPI.@)
271 DWORD WINAPI GetDeviceDriverBaseNameA(LPVOID ImageBase, LPSTR lpBaseName,
272 DWORD nSize)
274 FIXME("(%p, %p, %d): stub\n", ImageBase, lpBaseName, nSize);
276 if (lpBaseName && nSize)
277 lpBaseName[0] = '\0';
279 return 0;
282 /***********************************************************************
283 * GetDeviceDriverBaseNameW (PSAPI.@)
285 DWORD WINAPI GetDeviceDriverBaseNameW(LPVOID ImageBase, LPWSTR lpBaseName,
286 DWORD nSize)
288 FIXME("(%p, %p, %d): stub\n", ImageBase, lpBaseName, nSize);
290 if (lpBaseName && nSize)
291 lpBaseName[0] = '\0';
293 return 0;
296 /***********************************************************************
297 * GetDeviceDriverFileNameA (PSAPI.@)
299 DWORD WINAPI GetDeviceDriverFileNameA(LPVOID ImageBase, LPSTR lpFilename,
300 DWORD nSize)
302 FIXME("(%p, %p, %d): stub\n", ImageBase, lpFilename, nSize);
304 if (lpFilename && nSize)
305 lpFilename[0] = '\0';
307 return 0;
310 /***********************************************************************
311 * GetDeviceDriverFileNameW (PSAPI.@)
313 DWORD WINAPI GetDeviceDriverFileNameW(LPVOID ImageBase, LPWSTR lpFilename,
314 DWORD nSize)
316 FIXME("(%p, %p, %d): stub\n", ImageBase, lpFilename, nSize);
318 if (lpFilename && nSize)
319 lpFilename[0] = '\0';
321 return 0;
324 /***********************************************************************
325 * GetMappedFileNameA (PSAPI.@)
327 DWORD WINAPI GetMappedFileNameA(HANDLE hProcess, LPVOID lpv, LPSTR lpFilename,
328 DWORD nSize)
330 FIXME("(%p, %p, %p, %d): stub\n", hProcess, lpv, lpFilename, nSize);
332 if (lpFilename && nSize)
333 lpFilename[0] = '\0';
335 return 0;
338 /***********************************************************************
339 * GetMappedFileNameW (PSAPI.@)
341 DWORD WINAPI GetMappedFileNameW(HANDLE hProcess, LPVOID lpv, LPWSTR lpFilename,
342 DWORD nSize)
344 FIXME("(%p, %p, %p, %d): stub\n", hProcess, lpv, lpFilename, nSize);
346 if (lpFilename && nSize)
347 lpFilename[0] = '\0';
349 return 0;
352 /***********************************************************************
353 * GetModuleBaseNameA (PSAPI.@)
355 DWORD WINAPI GetModuleBaseNameA(HANDLE hProcess, HMODULE hModule,
356 LPSTR lpBaseName, DWORD nSize)
358 WCHAR *lpBaseNameW;
359 DWORD buflenW, ret = 0;
361 if(!lpBaseName || !nSize) {
362 SetLastError(ERROR_INVALID_PARAMETER);
363 return 0;
365 lpBaseNameW = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * nSize);
366 buflenW = GetModuleBaseNameW(hProcess, hModule, lpBaseNameW, nSize);
367 TRACE("%d, %s\n", buflenW, debugstr_w(lpBaseNameW));
368 if (buflenW)
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);
375 return ret;
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))
387 return 0;
389 nSize = min(LdrModule.BaseDllName.Length / sizeof(WCHAR), nSize);
390 if (!ReadProcessMemory(hProcess, LdrModule.BaseDllName.Buffer,
391 lpBaseName, nSize * sizeof(WCHAR), NULL))
392 return 0;
394 lpBaseName[nSize] = 0;
395 return nSize;
398 /***********************************************************************
399 * GetModuleFileNameExA (PSAPI.@)
401 DWORD WINAPI GetModuleFileNameExA(HANDLE hProcess, HMODULE hModule,
402 LPSTR lpFileName, DWORD nSize)
404 WCHAR *ptr;
406 TRACE("(hProcess=%p, hModule=%p, %p, %d)\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';
415 return len;
418 if (!(ptr = HeapAlloc(GetProcessHeap(), 0, nSize * sizeof(WCHAR)))) return 0;
420 if (!GetModuleFileNameExW(hProcess, hModule, ptr, nSize))
422 lpFileName[0] = '\0';
424 else
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))
443 return 0;
445 nSize = min(LdrModule.FullDllName.Length / sizeof(WCHAR), nSize);
446 if (!ReadProcessMemory(hProcess, LdrModule.FullDllName.Buffer,
447 lpFileName, nSize * sizeof(WCHAR), NULL))
448 return 0;
450 lpFileName[nSize] = 0;
451 return nSize;
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);
465 return FALSE;
468 if (!PSAPI_GetLdrModule(hProcess, hModule, &LdrModule))
469 return FALSE;
471 lpmodinfo->lpBaseOfDll = LdrModule.BaseAddress;
472 lpmodinfo->SizeOfImage = LdrModule.SizeOfImage;
473 lpmodinfo->EntryPoint = LdrModule.EntryPoint;
474 return TRUE;
477 /***********************************************************************
478 * GetPerformanceInfo (PSAPI.@)
480 BOOL WINAPI GetPerformanceInfo( PPERFORMANCE_INFORMATION info, DWORD size )
482 NTSTATUS status;
484 TRACE( "(%p, %d)\n", info, size );
486 status = NtQuerySystemInformation( SystemPerformanceInformation, info, size, NULL );
488 if (status)
490 SetLastError( RtlNtStatusToDosError( status ) );
491 return FALSE;
493 return TRUE;
496 /***********************************************************************
497 * GetProcessImageFileNameA (PSAPI.@)
499 DWORD WINAPI GetProcessImageFileNameA( HANDLE process, LPSTR file, DWORD size )
501 FIXME("(%p, %p, %d) stub\n", process, file, size );
502 return 0;
505 /***********************************************************************
506 * GetProcessImageFileNameW (PSAPI.@)
508 DWORD WINAPI GetProcessImageFileNameW( HANDLE process, LPWSTR file, DWORD size )
510 FIXME("(%p, %p, %d) stub\n", process, file, size );
511 return 0;
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)
523 NTSTATUS status;
524 VM_COUNTERS vmc;
526 if (cb < sizeof(PROCESS_MEMORY_COUNTERS))
528 SetLastError(ERROR_INSUFFICIENT_BUFFER);
529 return FALSE;
532 status = NtQueryInformationProcess(hProcess, ProcessVmCounters,
533 &vmc, sizeof(vmc), NULL);
535 if (status)
537 SetLastError(RtlNtStatusToDosError(status));
538 return FALSE;
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;
552 return TRUE;
555 /***********************************************************************
556 * GetWsChanges (PSAPI.@)
558 BOOL WINAPI GetWsChanges( HANDLE process, PPSAPI_WS_WATCH_INFORMATION watchinfo, DWORD size )
560 NTSTATUS status;
562 TRACE( "(%p, %p, %d)\n", process, watchinfo, size );
564 status = NtQueryInformationProcess( process, ProcessWorkingSetWatch, watchinfo, size, NULL );
566 if (status)
568 SetLastError( RtlNtStatusToDosError( status ) );
569 return FALSE;
571 return TRUE;
574 /***********************************************************************
575 * InitializeProcessForWsWatch (PSAPI.@)
577 BOOL WINAPI InitializeProcessForWsWatch(HANDLE hProcess)
579 FIXME("(hProcess=%p): stub\n", hProcess);
581 return TRUE;
584 /***********************************************************************
585 * QueryWorkingSet (PSAPI.@)
587 BOOL WINAPI QueryWorkingSet( HANDLE process, LPVOID buffer, DWORD size )
589 NTSTATUS status;
591 TRACE( "(%p, %p, %d)\n", process, buffer, size );
593 status = NtQueryVirtualMemory( process, NULL, MemoryWorkingSetList, buffer, size, NULL );
595 if (status)
597 SetLastError( RtlNtStatusToDosError( status ) );
598 return FALSE;
600 return TRUE;
603 /***********************************************************************
604 * QueryWorkingSetEx (PSAPI.@)
606 BOOL WINAPI QueryWorkingSetEx( HANDLE process, LPVOID buffer, DWORD size )
608 NTSTATUS status;
610 TRACE( "(%p, %p, %d)\n", process, buffer, size );
612 status = NtQueryVirtualMemory( process, NULL, MemoryWorkingSetList, buffer, size, NULL );
614 if (status)
616 SetLastError( RtlNtStatusToDosError( status ) );
617 return FALSE;
619 return TRUE;