/* * PSAPI library * * Copyright 1998 Patrik Stridvall * Copyright 2003 Eric Pouech * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include "windef.h" #include "winbase.h" #include "winerror.h" #include "wine/server.h" #include "wine/unicode.h" #include "wine/debug.h" #include "winnls.h" #include "ntstatus.h" #include "psapi.h" WINE_DEFAULT_DEBUG_CHANNEL(psapi); /*********************************************************************** * EmptyWorkingSet (PSAPI.@) */ BOOL WINAPI EmptyWorkingSet(HANDLE hProcess) { return SetProcessWorkingSetSize(hProcess, 0xFFFFFFFF, 0xFFFFFFFF); } /*********************************************************************** * EnumDeviceDrivers (PSAPI.@) */ BOOL WINAPI EnumDeviceDrivers(LPVOID *lpImageBase, DWORD cb, LPDWORD lpcbNeeded) { FIXME("(%p, %ld, %p): stub\n", lpImageBase, cb, lpcbNeeded); if (lpcbNeeded) *lpcbNeeded = 0; return TRUE; } /*********************************************************************** * EnumPageFilesA (PSAPI.@) */ BOOL WINAPI EnumPageFilesA( PENUM_PAGE_FILE_CALLBACKA callback, LPVOID context ) { FIXME("(%p, %p) stub\n", callback, context ); return FALSE; } /*********************************************************************** * EnumPageFilesW (PSAPI.@) */ BOOL WINAPI EnumPageFilesW( PENUM_PAGE_FILE_CALLBACKW callback, LPVOID context ) { FIXME("(%p, %p) stub\n", callback, context ); return FALSE; } /*********************************************************************** * EnumProcesses (PSAPI.@) */ BOOL WINAPI EnumProcesses(DWORD *lpidProcess, DWORD cb, DWORD *lpcbNeeded) { HANDLE hSnapshot; DWORD count; DWORD countMax; DWORD pid; int ret; TRACE("(%p, %ld, %p)\n", lpidProcess,cb, lpcbNeeded); if ( lpidProcess == NULL ) cb = 0; if ( lpcbNeeded != NULL ) *lpcbNeeded = 0; SERVER_START_REQ( create_snapshot ) { req->flags = SNAP_PROCESS; req->inherit = FALSE; req->pid = 0; wine_server_call_err( req ); hSnapshot = reply->handle; } SERVER_END_REQ; if ( hSnapshot == 0 ) { FIXME("cannot create snapshot\n"); return FALSE; } count = 0; countMax = cb / sizeof(DWORD); for (;;) { SERVER_START_REQ( next_process ) { req->handle = hSnapshot; req->reset = (count == 0); if ((ret = !wine_server_call_err( req ))) pid = reply->pid; } SERVER_END_REQ; if (!ret) break; TRACE("process 0x%08lx\n", pid); if ( count < countMax ) lpidProcess[count] = pid; count++; } CloseHandle( hSnapshot ); if ( lpcbNeeded != NULL ) *lpcbNeeded = sizeof(DWORD) * count; TRACE("return %lu processes\n", count); return TRUE; } /*********************************************************************** * EnumProcessModules (PSAPI.@) */ BOOL WINAPI EnumProcessModules(HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded) { HANDLE hSnapshot; DWORD pid; DWORD count; DWORD countMax; int ret; HMODULE hModule; TRACE("(hProcess=%p, %p, %ld, %p)\n", hProcess, lphModule, cb, lpcbNeeded ); if ( lphModule == NULL ) cb = 0; if ( lpcbNeeded != NULL ) *lpcbNeeded = 0; SERVER_START_REQ( get_process_info ) { req->handle = hProcess; if ( !wine_server_call_err( req ) ) pid = (DWORD)reply->pid; else pid = 0; } SERVER_END_REQ; if ( pid == 0 ) { FIXME("no pid for hProcess %p\n" ,hProcess); return FALSE; } SERVER_START_REQ( create_snapshot ) { req->flags = SNAP_MODULE; req->inherit = FALSE; req->pid = pid; wine_server_call_err( req ); hSnapshot = reply->handle; } SERVER_END_REQ; if ( hSnapshot == 0 ) { FIXME("cannot create snapshot\n"); return FALSE; } count = 0; countMax = cb / sizeof(HMODULE); for (;;) { SERVER_START_REQ( next_module ) { req->handle = hSnapshot; req->reset = (count == 0); if ((ret = !wine_server_call_err( req ))) { hModule = (HMODULE)reply->base; } } SERVER_END_REQ; if ( !ret ) break; TRACE("module 0x%p\n", hModule); if ( count < countMax ) lphModule[count] = hModule; count++; } CloseHandle( hSnapshot ); if ( lpcbNeeded != NULL ) *lpcbNeeded = sizeof(HMODULE) * count; TRACE("return %lu modules\n", count); return TRUE; } /*********************************************************************** * GetDeviceDriverBaseNameA (PSAPI.@) */ DWORD WINAPI GetDeviceDriverBaseNameA(LPVOID ImageBase, LPSTR lpBaseName, DWORD nSize) { FIXME("(%p, %s, %ld): stub\n", ImageBase, debugstr_a(lpBaseName), nSize); if (lpBaseName && nSize) lpBaseName[0] = '\0'; return 0; } /*********************************************************************** * GetDeviceDriverBaseNameW (PSAPI.@) */ DWORD WINAPI GetDeviceDriverBaseNameW(LPVOID ImageBase, LPWSTR lpBaseName, DWORD nSize) { FIXME("(%p, %s, %ld): stub\n", ImageBase, debugstr_w(lpBaseName), nSize); if (lpBaseName && nSize) lpBaseName[0] = '\0'; return 0; } /*********************************************************************** * GetDeviceDriverFileNameA (PSAPI.@) */ DWORD WINAPI GetDeviceDriverFileNameA(LPVOID ImageBase, LPSTR lpFilename, DWORD nSize) { FIXME("(%p, %s, %ld): stub\n", ImageBase, debugstr_a(lpFilename), nSize); if (lpFilename && nSize) lpFilename[0] = '\0'; return 0; } /*********************************************************************** * GetDeviceDriverFileNameW (PSAPI.@) */ DWORD WINAPI GetDeviceDriverFileNameW(LPVOID ImageBase, LPWSTR lpFilename, DWORD nSize) { FIXME("(%p, %s, %ld): stub\n", ImageBase, debugstr_w(lpFilename), nSize); if (lpFilename && nSize) lpFilename[0] = '\0'; return 0; } /*********************************************************************** * GetMappedFileNameA (PSAPI.@) */ DWORD WINAPI GetMappedFileNameA(HANDLE hProcess, LPVOID lpv, LPSTR lpFilename, DWORD nSize) { FIXME("(hProcess=%p, %p, %s, %ld): stub\n", hProcess, lpv, debugstr_a(lpFilename), nSize); if (lpFilename && nSize) lpFilename[0] = '\0'; return 0; } /*********************************************************************** * GetMappedFileNameW (PSAPI.@) */ DWORD WINAPI GetMappedFileNameW(HANDLE hProcess, LPVOID lpv, LPWSTR lpFilename, DWORD nSize) { FIXME("(hProcess=%p, %p, %s, %ld): stub\n", hProcess, lpv, debugstr_w(lpFilename), nSize); if (lpFilename && nSize) lpFilename[0] = '\0'; return 0; } /*********************************************************************** * GetModuleBaseNameA (PSAPI.@) */ DWORD WINAPI GetModuleBaseNameA(HANDLE hProcess, HMODULE hModule, LPSTR lpBaseName, DWORD nSize) { WCHAR *lpBaseNameW; DWORD buflenW, ret = 0; if(!lpBaseName || !nSize) { SetLastError(ERROR_INVALID_PARAMETER); return 0; } lpBaseNameW = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * nSize); buflenW = GetModuleBaseNameW(hProcess, hModule, lpBaseNameW, nSize); TRACE("%ld, %s\n", buflenW, debugstr_w(lpBaseNameW)); if (buflenW) { ret = WideCharToMultiByte(CP_ACP, 0, lpBaseNameW, buflenW, lpBaseName, nSize, NULL, NULL); if (ret < nSize) lpBaseName[ret] = 0; } HeapFree(GetProcessHeap(), 0, lpBaseNameW); return ret; } /*********************************************************************** * GetModuleBaseNameW (PSAPI.@) */ DWORD WINAPI GetModuleBaseNameW(HANDLE hProcess, HMODULE hModule, LPWSTR lpBaseName, DWORD nSize) { WCHAR tmp[MAX_PATH]; WCHAR* ptr; int ptrlen; if(!lpBaseName || !nSize) { SetLastError(ERROR_INVALID_PARAMETER); return 0; } if (!GetModuleFileNameExW(hProcess, hModule, tmp, sizeof(tmp)/sizeof(WCHAR))) return 0; TRACE("%s\n", debugstr_w(tmp)); if ((ptr = strrchrW(tmp, '\\')) != NULL) ptr++; else ptr = tmp; ptrlen = strlenW(ptr); memcpy(lpBaseName, ptr, min(ptrlen+1,nSize) * sizeof(WCHAR)); return min(ptrlen, nSize); } /*********************************************************************** * GetModuleFileNameExA (PSAPI.@) */ DWORD WINAPI GetModuleFileNameExA(HANDLE hProcess, HMODULE hModule, LPSTR lpFileName, DWORD nSize) { WCHAR *ptr; TRACE("(hProcess=%p, hModule=%p, %p, %ld)\n", hProcess, hModule, lpFileName, nSize); if (!lpFileName || !nSize) return 0; if ( hProcess == GetCurrentProcess() ) { DWORD len = GetModuleFileNameA( hModule, lpFileName, nSize ); if (nSize) lpFileName[nSize - 1] = '\0'; return len; } if (!(ptr = HeapAlloc(GetProcessHeap(), 0, nSize * sizeof(WCHAR)))) return 0; if (!GetModuleFileNameExW(hProcess, hModule, ptr, nSize)) { lpFileName[0] = '\0'; } else { if (!WideCharToMultiByte( CP_ACP, 0, ptr, -1, lpFileName, nSize, NULL, NULL )) lpFileName[nSize - 1] = 0; } HeapFree(GetProcessHeap(), 0, ptr); return strlen(lpFileName); } /*********************************************************************** * GetModuleFileNameExW (PSAPI.@) */ DWORD WINAPI GetModuleFileNameExW(HANDLE hProcess, HMODULE hModule, LPWSTR lpFileName, DWORD nSize) { DWORD len = 0; TRACE("(hProcess=%p, hModule=%p, %p, %ld)\n", hProcess, hModule, lpFileName, nSize); if (!lpFileName || !nSize) return 0; if ( hProcess == GetCurrentProcess() ) { DWORD len = GetModuleFileNameW( hModule, lpFileName, nSize ); if (nSize) lpFileName[nSize - 1] = '\0'; TRACE("return (cur) %s (%lu)\n", debugstr_w(lpFileName), len); return len; } lpFileName[0] = 0; SERVER_START_REQ( get_dll_info ) { req->handle = hProcess; req->base_address = hModule; wine_server_set_reply( req, lpFileName, (nSize - 1) * sizeof(WCHAR) ); if (!wine_server_call_err( req )) { len = wine_server_reply_size(reply) / sizeof(WCHAR); lpFileName[len] = 0; } } SERVER_END_REQ; TRACE("return %s (%lu)\n", debugstr_w(lpFileName), len); return len; } /*********************************************************************** * GetModuleInformation (PSAPI.@) */ BOOL WINAPI GetModuleInformation(HANDLE hProcess, HMODULE hModule, LPMODULEINFO lpmodinfo, DWORD cb) { BOOL ret = FALSE; TRACE("(hProcess=%p, hModule=%p, %p, %ld)\n", hProcess, hModule, lpmodinfo, cb); if (cb < sizeof(MODULEINFO)) return FALSE; SERVER_START_REQ( get_dll_info ) { req->handle = hProcess; req->base_address = (void*)hModule; if (!wine_server_call_err( req )) { ret = TRUE; lpmodinfo->lpBaseOfDll = (void*)hModule; lpmodinfo->SizeOfImage = reply->size; lpmodinfo->EntryPoint = reply->entry_point; } } SERVER_END_REQ; return TRUE; } /*********************************************************************** * GetPerformanceInfo (PSAPI.@) */ BOOL WINAPI GetPerformanceInfo( PPERFORMANCE_INFORMATION info, DWORD size ) { NTSTATUS status; TRACE( "(%p, %ld)\n", info, size ); status = NtQueryInformationProcess( GetCurrentProcess(), SystemPerformanceInformation, info, size, NULL ); if (status) { SetLastError( RtlNtStatusToDosError( status ) ); return FALSE; } return TRUE; } /*********************************************************************** * GetProcessImageFileNameA (PSAPI.@) */ DWORD WINAPI GetProcessImageFileNameA( HANDLE process, LPSTR file, DWORD size ) { FIXME("(%p, %p, %ld) stub\n", process, file, size ); return 0; } /*********************************************************************** * GetProcessImageFileNameW (PSAPI.@) */ DWORD WINAPI GetProcessImageFileNameW( HANDLE process, LPWSTR file, DWORD size ) { FIXME("(%p, %p, %ld) stub\n", process, file, size ); return 0; } /*********************************************************************** * GetProcessMemoryInfo (PSAPI.@) * * Retrieve memory usage information for a given process * */ BOOL WINAPI GetProcessMemoryInfo( HANDLE process, PPROCESS_MEMORY_COUNTERS counters, DWORD size ) { NTSTATUS status; VM_COUNTERS vmc; TRACE( "(%p, %p, %ld)\n", process, counters, size ); status = NtQueryInformationProcess( process, ProcessVmCounters, &vmc, sizeof(vmc), NULL ); if (status) { SetLastError( RtlNtStatusToDosError( status ) ); return FALSE; } /* FIXME: check size */ counters->cb = sizeof(PROCESS_MEMORY_COUNTERS); counters->PageFaultCount = vmc.PageFaultCount; counters->PeakWorkingSetSize = vmc.PeakWorkingSetSize; counters->WorkingSetSize = vmc.WorkingSetSize; counters->QuotaPeakPagedPoolUsage = vmc.QuotaPeakPagedPoolUsage; counters->QuotaPagedPoolUsage = vmc.QuotaPagedPoolUsage; counters->QuotaPeakNonPagedPoolUsage = vmc.QuotaPeakNonPagedPoolUsage; counters->QuotaNonPagedPoolUsage = vmc.QuotaNonPagedPoolUsage; counters->PagefileUsage = vmc.PagefileUsage; counters->PeakPagefileUsage = vmc.PeakPagefileUsage; return TRUE; } /*********************************************************************** * GetWsChanges (PSAPI.@) */ BOOL WINAPI GetWsChanges( HANDLE process, PPSAPI_WS_WATCH_INFORMATION watchinfo, DWORD size ) { NTSTATUS status; TRACE( "(%p, %p, %ld)\n", process, watchinfo, size ); status = NtQueryVirtualMemory( process, NULL, ProcessWorkingSetWatch, watchinfo, size, NULL ); if (status) { SetLastError( RtlNtStatusToDosError( status ) ); return FALSE; } return TRUE; } /*********************************************************************** * InitializeProcessForWsWatch (PSAPI.@) */ BOOL WINAPI InitializeProcessForWsWatch(HANDLE hProcess) { FIXME("(hProcess=%p): stub\n", hProcess); return TRUE; } /*********************************************************************** * QueryWorkingSet (PSAPI.@) */ BOOL WINAPI QueryWorkingSet( HANDLE process, LPVOID buffer, DWORD size ) { NTSTATUS status; TRACE( "(%p, %p, %ld)\n", process, buffer, size ); status = NtQueryVirtualMemory( process, NULL, MemoryWorkingSetList, buffer, size, NULL ); if (status) { SetLastError( RtlNtStatusToDosError( status ) ); return FALSE; } return TRUE; } /*********************************************************************** * QueryWorkingSetEx (PSAPI.@) */ BOOL WINAPI QueryWorkingSetEx( HANDLE process, LPVOID buffer, DWORD size ) { NTSTATUS status; TRACE( "(%p, %p, %ld)\n", process, buffer, size ); status = NtQueryVirtualMemory( process, NULL, MemoryWorkingSetList, buffer, size, NULL ); if (status) { SetLastError( RtlNtStatusToDosError( status ) ); return FALSE; } return TRUE; }