user32: Mark internal functions with hidden visibility.
[wine] / dlls / psapi / psapi_main.c
1 /*
2  *      PSAPI library
3  *
4  * Copyright 1998 Patrik Stridvall
5  * Copyright 2003 Eric Pouech
6  *
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.
11  *
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.
16  *
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
20  */
21
22 #include <stdarg.h>
23
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"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(psapi);
36
37 typedef struct
38 {
39     HANDLE hProcess;             
40     PLIST_ENTRY pHead, pCurrent;
41     LDR_MODULE LdrModule;
42 } MODULE_ITERATOR;
43
44 /***********************************************************************
45  *           PSAPI_ModuleIteratorInit [internal]
46  *
47  * Prepares to iterate through the loaded modules of the given process.
48  *
49  * RETURNS
50  *  Success: TRUE
51  *  Failure: FALSE
52  */
53 static BOOL PSAPI_ModuleIteratorInit(MODULE_ITERATOR *iter, HANDLE hProcess)
54 {
55     PROCESS_BASIC_INFORMATION pbi;
56     PPEB_LDR_DATA pLdrData;
57     NTSTATUS status;
58
59     /* Get address of PEB */
60     status = NtQueryInformationProcess(hProcess, ProcessBasicInformation,
61                                        &pbi, sizeof(pbi), NULL);
62     if (status != STATUS_SUCCESS)
63     {
64         SetLastError(RtlNtStatusToDosError(status));
65         return FALSE;
66     }
67
68     /* Read address of LdrData from PEB */
69     if (!ReadProcessMemory(hProcess, &pbi.PebBaseAddress->LdrData,
70                            &pLdrData, sizeof(pLdrData), NULL))
71         return FALSE;
72
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;
78
79     iter->pHead = &pLdrData->InLoadOrderModuleList;
80     iter->hProcess = hProcess;
81
82     return TRUE;
83 }
84
85 /***********************************************************************
86  *           PSAPI_ModuleIteratorNext [internal]
87  *
88  * Iterates to the next module.
89  *
90  * RETURNS
91  *   1 : Success
92  *   0 : No more modules
93  *  -1 : Failure
94  *
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.
100  */
101 static INT PSAPI_ModuleIteratorNext(MODULE_ITERATOR *iter)
102 {
103     if (iter->pCurrent == iter->pHead)
104         return 0;
105
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;
112
113     return 1;
114 }
115
116 /***********************************************************************
117  *           PSAPI_GetLdrModule [internal]
118  *
119  * Reads the LDR_MODULE structure of the given module.
120  *
121  * RETURNS
122  *  Success: TRUE
123  *  Failure: FALSE
124  */
125
126 static BOOL PSAPI_GetLdrModule(HANDLE hProcess, HMODULE hModule, 
127                                LDR_MODULE *pLdrModule)
128 {
129     MODULE_ITERATOR iter;
130     INT ret;
131
132     if (!PSAPI_ModuleIteratorInit(&iter, hProcess))
133         return FALSE;
134
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 == iter.LdrModule.BaseAddress)
139         {
140             *pLdrModule = iter.LdrModule;
141             return TRUE;
142         }
143
144     if (ret == 0)
145         SetLastError(ERROR_INVALID_HANDLE);
146
147     return FALSE;
148 }
149
150 /***********************************************************************
151  *           EnumDeviceDrivers (PSAPI.@)
152  */
153 BOOL WINAPI EnumDeviceDrivers(LPVOID *lpImageBase, DWORD cb, LPDWORD lpcbNeeded)
154 {
155     FIXME("(%p, %d, %p): stub\n", lpImageBase, cb, lpcbNeeded);
156
157     if (lpcbNeeded)
158         *lpcbNeeded = 0;
159
160     return TRUE;
161 }
162
163 /***********************************************************************
164  *           EnumPageFilesA (PSAPI.@)
165  */
166 BOOL WINAPI EnumPageFilesA( PENUM_PAGE_FILE_CALLBACKA callback, LPVOID context )
167 {
168     FIXME("(%p, %p) stub\n", callback, context );
169     return FALSE;
170 }
171
172 /***********************************************************************
173  *           EnumPageFilesW (PSAPI.@)
174  */
175 BOOL WINAPI EnumPageFilesW( PENUM_PAGE_FILE_CALLBACKW callback, LPVOID context )
176 {
177     FIXME("(%p, %p) stub\n", callback, context );
178     return FALSE;
179 }
180
181 /***********************************************************************
182  *           EnumProcesses (PSAPI.@)
183  */
184 BOOL WINAPI EnumProcesses(DWORD *lpdwProcessIDs, DWORD cb, DWORD *lpcbUsed)
185 {
186     SYSTEM_PROCESS_INFORMATION *spi;
187     NTSTATUS status;
188     PVOID pBuf = NULL;
189     ULONG nAlloc = 0x8000;
190
191     do {
192         if (pBuf != NULL) 
193         {
194             HeapFree(GetProcessHeap(), 0, pBuf);
195             nAlloc *= 2;
196         }
197
198         pBuf = HeapAlloc(GetProcessHeap(), 0, nAlloc);
199         if (pBuf == NULL)
200             return FALSE;
201
202         status = NtQuerySystemInformation(SystemProcessInformation, pBuf,
203                                           nAlloc, NULL);
204     } while (status == STATUS_INFO_LENGTH_MISMATCH);
205
206     if (status != STATUS_SUCCESS)
207     {
208         HeapFree(GetProcessHeap(), 0, pBuf);
209         SetLastError(RtlNtStatusToDosError(status));
210         return FALSE;
211     }
212
213     spi = pBuf;
214
215     for (*lpcbUsed = 0; cb >= sizeof(DWORD); cb -= sizeof(DWORD))
216     {
217         *lpdwProcessIDs++ = HandleToUlong(spi->UniqueProcessId);
218         *lpcbUsed += sizeof(DWORD);
219
220         if (spi->NextEntryOffset == 0)
221             break;
222
223         spi = (SYSTEM_PROCESS_INFORMATION *)(((PCHAR)spi) + spi->NextEntryOffset);
224     }
225
226     HeapFree(GetProcessHeap(), 0, pBuf);
227     return TRUE;
228 }
229
230 /***********************************************************************
231  *           EnumProcessModules (PSAPI.@)
232  *
233  * NOTES
234  *  Returned list is in load order.
235  */
236 BOOL WINAPI EnumProcessModules(HANDLE hProcess, HMODULE *lphModule,
237                                DWORD cb, LPDWORD lpcbNeeded)
238 {
239     MODULE_ITERATOR iter;
240     INT ret;
241
242     if (!PSAPI_ModuleIteratorInit(&iter, hProcess))
243         return FALSE;
244
245     *lpcbNeeded = 0;
246         
247     while ((ret = PSAPI_ModuleIteratorNext(&iter)) > 0)
248     {
249         if (cb >= sizeof(HMODULE))
250         {
251             *lphModule++ = iter.LdrModule.BaseAddress;
252             cb -= sizeof(HMODULE);
253         }
254         *lpcbNeeded += sizeof(HMODULE);
255     }
256
257     return (ret == 0);
258 }
259
260 /***********************************************************************
261  *          GetDeviceDriverBaseNameA (PSAPI.@)
262  */
263 DWORD WINAPI GetDeviceDriverBaseNameA(LPVOID ImageBase, LPSTR lpBaseName, 
264                                       DWORD nSize)
265 {
266     FIXME("(%p, %p, %d): stub\n", ImageBase, lpBaseName, nSize);
267
268     if (lpBaseName && nSize)
269         lpBaseName[0] = '\0';
270
271     return 0;
272 }
273
274 /***********************************************************************
275  *           GetDeviceDriverBaseNameW (PSAPI.@)
276  */
277 DWORD WINAPI GetDeviceDriverBaseNameW(LPVOID ImageBase, LPWSTR lpBaseName, 
278                                       DWORD nSize)
279 {
280     FIXME("(%p, %p, %d): stub\n", ImageBase, lpBaseName, nSize);
281
282     if (lpBaseName && nSize)
283         lpBaseName[0] = '\0';
284
285     return 0;
286 }
287
288 /***********************************************************************
289  *           GetDeviceDriverFileNameA (PSAPI.@)
290  */
291 DWORD WINAPI GetDeviceDriverFileNameA(LPVOID ImageBase, LPSTR lpFilename, 
292                                       DWORD nSize)
293 {
294     FIXME("(%p, %p, %d): stub\n", ImageBase, lpFilename, nSize);
295
296     if (lpFilename && nSize)
297         lpFilename[0] = '\0';
298
299     return 0;
300 }
301
302 /***********************************************************************
303  *           GetDeviceDriverFileNameW (PSAPI.@)
304  */
305 DWORD WINAPI GetDeviceDriverFileNameW(LPVOID ImageBase, LPWSTR lpFilename, 
306                                       DWORD nSize)
307 {
308     FIXME("(%p, %p, %d): stub\n", ImageBase, lpFilename, nSize);
309
310     if (lpFilename && nSize)
311         lpFilename[0] = '\0';
312
313     return 0;
314 }
315
316 /***********************************************************************
317  *           GetMappedFileNameA (PSAPI.@)
318  */
319 DWORD WINAPI GetMappedFileNameA(HANDLE hProcess, LPVOID lpv, LPSTR lpFilename, 
320                                 DWORD nSize)
321 {
322     FIXME("(%p, %p, %p, %d): stub\n", hProcess, lpv, lpFilename, nSize);
323
324     if (lpFilename && nSize)
325         lpFilename[0] = '\0';
326
327     return 0;
328 }
329
330 /***********************************************************************
331  *           GetMappedFileNameW (PSAPI.@)
332  */
333 DWORD WINAPI GetMappedFileNameW(HANDLE hProcess, LPVOID lpv, LPWSTR lpFilename, 
334                                 DWORD nSize)
335 {
336     FIXME("(%p, %p, %p, %d): stub\n", hProcess, lpv, lpFilename, nSize);
337
338     if (lpFilename && nSize)
339         lpFilename[0] = '\0';
340
341     return 0;
342 }
343
344 /***********************************************************************
345  *           GetModuleBaseNameA (PSAPI.@)
346  */
347 DWORD WINAPI GetModuleBaseNameA(HANDLE hProcess, HMODULE hModule, 
348                                 LPSTR lpBaseName, DWORD nSize)
349 {
350     WCHAR *lpBaseNameW;
351     DWORD buflenW, ret = 0;
352
353     if(!lpBaseName || !nSize) {
354         SetLastError(ERROR_INVALID_PARAMETER);
355         return 0;
356     }
357     lpBaseNameW = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * nSize);
358     buflenW = GetModuleBaseNameW(hProcess, hModule, lpBaseNameW, nSize);
359     TRACE("%d, %s\n", buflenW, debugstr_w(lpBaseNameW));
360     if (buflenW)
361     {
362         ret = WideCharToMultiByte(CP_ACP, 0, lpBaseNameW, buflenW,
363                                   lpBaseName, nSize, NULL, NULL);
364         if (ret < nSize) lpBaseName[ret] = 0;
365     }
366     HeapFree(GetProcessHeap(), 0, lpBaseNameW);
367     return ret;
368 }
369
370 /***********************************************************************
371  *           GetModuleBaseNameW (PSAPI.@)
372  */
373 DWORD WINAPI GetModuleBaseNameW(HANDLE hProcess, HMODULE hModule, 
374                                 LPWSTR lpBaseName, DWORD nSize)
375 {
376     LDR_MODULE LdrModule;
377
378     if (!PSAPI_GetLdrModule(hProcess, hModule, &LdrModule))
379         return 0;
380
381     nSize = min(LdrModule.BaseDllName.Length / sizeof(WCHAR), nSize);
382     if (!ReadProcessMemory(hProcess, LdrModule.BaseDllName.Buffer,
383                            lpBaseName, nSize * sizeof(WCHAR), NULL))
384         return 0;
385
386     lpBaseName[nSize] = 0;
387     return nSize;
388 }
389
390 /***********************************************************************
391  *           GetModuleFileNameExA (PSAPI.@)
392  */
393 DWORD WINAPI GetModuleFileNameExA(HANDLE hProcess, HMODULE hModule, 
394                                   LPSTR lpFileName, DWORD nSize)
395 {
396     WCHAR *ptr;
397
398     TRACE("(hProcess=%p, hModule=%p, %p, %d)\n",
399           hProcess, hModule, lpFileName, nSize);
400
401     if (!lpFileName || !nSize) return 0;
402
403     if ( hProcess == GetCurrentProcess() )
404     {
405         DWORD len = GetModuleFileNameA( hModule, lpFileName, nSize );
406         if (nSize) lpFileName[nSize - 1] = '\0';
407         return len;
408     }
409
410     if (!(ptr = HeapAlloc(GetProcessHeap(), 0, nSize * sizeof(WCHAR)))) return 0;
411
412     if (!GetModuleFileNameExW(hProcess, hModule, ptr, nSize))
413     {
414         lpFileName[0] = '\0';
415     }
416     else
417     {
418         if (!WideCharToMultiByte( CP_ACP, 0, ptr, -1, lpFileName, nSize, NULL, NULL ))
419             lpFileName[nSize - 1] = 0;
420     }
421
422     HeapFree(GetProcessHeap(), 0, ptr);
423     return strlen(lpFileName);
424 }
425
426 /***********************************************************************
427  *           GetModuleFileNameExW (PSAPI.@)
428  */
429 DWORD WINAPI GetModuleFileNameExW(HANDLE hProcess, HMODULE hModule, 
430                                   LPWSTR lpFileName, DWORD nSize)
431 {
432     LDR_MODULE LdrModule;
433     
434     if(!PSAPI_GetLdrModule(hProcess, hModule, &LdrModule))
435         return 0;
436         
437     nSize = min(LdrModule.FullDllName.Length / sizeof(WCHAR), nSize);
438     if (!ReadProcessMemory(hProcess, LdrModule.FullDllName.Buffer,
439                            lpFileName, nSize * sizeof(WCHAR), NULL))
440         return 0;
441
442     lpFileName[nSize] = 0;
443     return nSize;
444 }
445
446 /***********************************************************************
447  *           GetModuleInformation (PSAPI.@)
448  */
449 BOOL WINAPI GetModuleInformation(HANDLE hProcess, HMODULE hModule, 
450                                  LPMODULEINFO lpmodinfo, DWORD cb)
451 {
452     LDR_MODULE LdrModule;
453
454     if (cb < sizeof(MODULEINFO)) 
455     {
456         SetLastError(ERROR_INSUFFICIENT_BUFFER);
457         return FALSE;
458     }
459
460     if (!PSAPI_GetLdrModule(hProcess, hModule, &LdrModule))
461         return FALSE;
462
463     lpmodinfo->lpBaseOfDll = LdrModule.BaseAddress;
464     lpmodinfo->SizeOfImage = LdrModule.SizeOfImage;
465     lpmodinfo->EntryPoint  = LdrModule.EntryPoint;
466     return TRUE;
467 }
468
469 /***********************************************************************
470  *           GetPerformanceInfo (PSAPI.@)
471  */
472 BOOL WINAPI GetPerformanceInfo( PPERFORMANCE_INFORMATION info, DWORD size )
473 {
474     NTSTATUS status;
475
476     TRACE( "(%p, %d)\n", info, size );
477
478     status = NtQuerySystemInformation( SystemPerformanceInformation, info, size, NULL );
479
480     if (status)
481     {
482         SetLastError( RtlNtStatusToDosError( status ) );
483         return FALSE;
484     }
485     return TRUE;
486 }
487
488 /***********************************************************************
489  *           GetProcessMemoryInfo (PSAPI.@)
490  *
491  * Retrieve memory usage information for a given process
492  *
493  */
494 BOOL WINAPI GetProcessMemoryInfo(HANDLE hProcess, 
495                                  PPROCESS_MEMORY_COUNTERS pmc, DWORD cb)
496 {
497     NTSTATUS status;
498     VM_COUNTERS vmc;
499
500     if (cb < sizeof(PROCESS_MEMORY_COUNTERS))
501     {
502         SetLastError(ERROR_INSUFFICIENT_BUFFER);
503         return FALSE;
504     }
505
506     status = NtQueryInformationProcess(hProcess, ProcessVmCounters, 
507                                        &vmc, sizeof(vmc), NULL);
508
509     if (status)
510     {
511         SetLastError(RtlNtStatusToDosError(status));
512         return FALSE;
513     }
514
515     pmc->cb = sizeof(PROCESS_MEMORY_COUNTERS);
516     pmc->PageFaultCount = vmc.PageFaultCount;
517     pmc->PeakWorkingSetSize = vmc.PeakWorkingSetSize;
518     pmc->WorkingSetSize = vmc.WorkingSetSize;
519     pmc->QuotaPeakPagedPoolUsage = vmc.QuotaPeakPagedPoolUsage;
520     pmc->QuotaPagedPoolUsage = vmc.QuotaPagedPoolUsage;
521     pmc->QuotaPeakNonPagedPoolUsage = vmc.QuotaPeakNonPagedPoolUsage;
522     pmc->QuotaNonPagedPoolUsage = vmc.QuotaNonPagedPoolUsage;
523     pmc->PagefileUsage = vmc.PagefileUsage;
524     pmc->PeakPagefileUsage = vmc.PeakPagefileUsage;
525
526     return TRUE;
527 }
528
529 /***********************************************************************
530  *           GetWsChanges (PSAPI.@)
531  */
532 BOOL WINAPI GetWsChanges( HANDLE process, PPSAPI_WS_WATCH_INFORMATION watchinfo, DWORD size )
533 {
534     NTSTATUS status;
535
536     TRACE( "(%p, %p, %d)\n", process, watchinfo, size );
537
538     status = NtQueryInformationProcess( process, ProcessWorkingSetWatch, watchinfo, size, NULL );
539
540     if (status)
541     {
542         SetLastError( RtlNtStatusToDosError( status ) );
543         return FALSE;
544     }
545     return TRUE;
546 }
547
548 /***********************************************************************
549  *           InitializeProcessForWsWatch (PSAPI.@)
550  */
551 BOOL WINAPI InitializeProcessForWsWatch(HANDLE hProcess)
552 {
553     FIXME("(hProcess=%p): stub\n", hProcess);
554
555     return TRUE;
556 }
557
558 /***********************************************************************
559  *           QueryWorkingSet (PSAPI.@)
560  */
561 BOOL WINAPI QueryWorkingSet( HANDLE process, LPVOID buffer, DWORD size )
562 {
563     NTSTATUS status;
564
565     TRACE( "(%p, %p, %d)\n", process, buffer, size );
566
567     status = NtQueryVirtualMemory( process, NULL, MemoryWorkingSetList, buffer, size, NULL );
568
569     if (status)
570     {
571         SetLastError( RtlNtStatusToDosError( status ) );
572         return FALSE;
573     }
574     return TRUE;
575 }
576
577 /***********************************************************************
578  *           QueryWorkingSetEx (PSAPI.@)
579  */
580 BOOL WINAPI QueryWorkingSetEx( HANDLE process, LPVOID buffer, DWORD size )
581 {
582     NTSTATUS status;
583
584     TRACE( "(%p, %p, %d)\n", process, buffer, size );
585
586     status = NtQueryVirtualMemory( process, NULL, MemoryWorkingSetList, buffer,  size, NULL );
587
588     if (status)
589     {
590         SetLastError( RtlNtStatusToDosError( status ) );
591         return FALSE;
592     }
593     return TRUE;
594 }