Sort entry points alphabetically.
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include <stdarg.h>
23
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winerror.h"
27 #include "wine/server.h"
28 #include "wine/unicode.h"
29 #include "wine/debug.h"
30 #include "winnls.h"
31 #include "ntstatus.h"
32 #include "psapi.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(psapi);
35
36 /***********************************************************************
37  *           EmptyWorkingSet (PSAPI.@)
38  */
39 BOOL WINAPI EmptyWorkingSet(HANDLE hProcess)
40 {
41     return SetProcessWorkingSetSize(hProcess, 0xFFFFFFFF, 0xFFFFFFFF);
42 }
43
44 /***********************************************************************
45  *           EnumDeviceDrivers (PSAPI.@)
46  */
47 BOOL WINAPI EnumDeviceDrivers(LPVOID *lpImageBase, DWORD cb, LPDWORD lpcbNeeded)
48 {
49     FIXME("(%p, %ld, %p): stub\n", lpImageBase, cb, lpcbNeeded);
50
51     if (lpcbNeeded)
52         *lpcbNeeded = 0;
53
54     return TRUE;
55 }
56
57 /***********************************************************************
58  *           EnumPageFilesA (PSAPI.@)
59  */
60 BOOL WINAPI EnumPageFilesA( PENUM_PAGE_FILE_CALLBACKA callback, LPVOID context )
61 {
62     FIXME("(%p, %p) stub\n", callback, context );
63     return FALSE;
64 }
65
66 /***********************************************************************
67  *           EnumPageFilesW (PSAPI.@)
68  */
69 BOOL WINAPI EnumPageFilesW( PENUM_PAGE_FILE_CALLBACKW callback, LPVOID context )
70 {
71     FIXME("(%p, %p) stub\n", callback, context );
72     return FALSE;
73 }
74
75 /***********************************************************************
76  *           EnumProcesses (PSAPI.@)
77  */
78 BOOL WINAPI EnumProcesses(DWORD *lpdwProcessIDs, DWORD cb, DWORD *lpcbUsed)
79 {
80     SYSTEM_PROCESS_INFORMATION *spi;
81     NTSTATUS status;
82     PVOID pBuf = NULL;
83     ULONG nAlloc = 0x8000;
84
85     do {
86         if (pBuf != NULL) 
87         {
88             HeapFree(GetProcessHeap(), 0, pBuf);
89             nAlloc *= 2;
90         }
91
92         pBuf = HeapAlloc(GetProcessHeap(), 0, nAlloc);
93         if (pBuf == NULL)
94             return FALSE;
95
96         status = NtQuerySystemInformation(SystemProcessInformation, pBuf,
97                                           nAlloc, NULL);
98     } while (status == STATUS_INFO_LENGTH_MISMATCH);
99
100     if (status != STATUS_SUCCESS)
101     {
102         HeapFree(GetProcessHeap(), 0, pBuf);
103         SetLastError(RtlNtStatusToDosError(status));
104         return FALSE;
105     }
106
107     spi = pBuf;
108
109     for(*lpcbUsed = 0; cb >= sizeof(DWORD); cb -= sizeof(DWORD))
110     {
111         *lpdwProcessIDs++ = spi->dwProcessID;
112         *lpcbUsed += sizeof(DWORD);
113
114         if(spi->dwOffset == 0)
115             break;
116
117         spi = (SYSTEM_PROCESS_INFORMATION *)(((PCHAR)spi) + spi->dwOffset);
118     }
119
120     HeapFree(GetProcessHeap(), 0, pBuf);
121     return TRUE;
122 }
123
124 /***********************************************************************
125  *           EnumProcessModules (PSAPI.@)
126  */
127 BOOL WINAPI EnumProcessModules(HANDLE hProcess, HMODULE *lphModule, 
128                                DWORD cb, LPDWORD lpcbNeeded)
129 {
130     HANDLE      hSnapshot;
131     DWORD       pid;
132     DWORD       count;
133     DWORD       countMax;
134     int         ret;
135     HMODULE     hModule;
136
137     TRACE("(hProcess=%p, %p, %ld, %p)\n",
138           hProcess, lphModule, cb, lpcbNeeded );
139
140     if ( lphModule == NULL )
141         cb = 0;
142     if ( lpcbNeeded != NULL )
143         *lpcbNeeded = 0;
144
145     SERVER_START_REQ( get_process_info )
146     {
147         req->handle = hProcess;
148         if ( !wine_server_call_err( req ) )
149             pid = (DWORD)reply->pid;
150         else
151             pid = 0;
152     }
153     SERVER_END_REQ;
154
155     if ( pid == 0 )
156     {
157         FIXME("no pid for hProcess %p\n" ,hProcess);
158         return FALSE;
159     }
160
161     SERVER_START_REQ( create_snapshot )
162     {
163         req->flags   = SNAP_MODULE;
164         req->inherit = FALSE;
165         req->pid     = pid;
166         wine_server_call_err( req );
167         hSnapshot = reply->handle;
168     }
169     SERVER_END_REQ;
170     if ( hSnapshot == 0 )
171     {
172         FIXME("cannot create snapshot\n");
173         return FALSE;
174     }
175     count = 0;
176     countMax = cb / sizeof(HMODULE);
177     for (;;)
178     {
179         SERVER_START_REQ( next_module )
180         {
181             req->handle = hSnapshot;
182             req->reset = (count == 0);
183             if ((ret = !wine_server_call_err( req )))
184             {
185                 hModule = (HMODULE)reply->base;
186             }
187         }
188         SERVER_END_REQ;
189         if ( !ret ) break;
190         TRACE("module 0x%p\n", hModule);
191         if ( count < countMax )
192             lphModule[count] = hModule;
193         count++;
194     }
195     CloseHandle( hSnapshot );
196
197     if ( lpcbNeeded != NULL )
198         *lpcbNeeded = sizeof(HMODULE) * count;
199
200     TRACE("return %lu modules\n", count);
201
202     return TRUE;
203 }
204
205 /***********************************************************************
206  *          GetDeviceDriverBaseNameA (PSAPI.@)
207  */
208 DWORD WINAPI GetDeviceDriverBaseNameA(LPVOID ImageBase, LPSTR lpBaseName, 
209                                       DWORD nSize)
210 {
211     FIXME("(%p, %s, %ld): stub\n",
212           ImageBase, debugstr_a(lpBaseName), nSize);
213
214     if (lpBaseName && nSize)
215         lpBaseName[0] = '\0';
216
217     return 0;
218 }
219
220 /***********************************************************************
221  *           GetDeviceDriverBaseNameW (PSAPI.@)
222  */
223 DWORD WINAPI GetDeviceDriverBaseNameW(LPVOID ImageBase, LPWSTR lpBaseName, 
224                                       DWORD nSize)
225 {
226     FIXME("(%p, %s, %ld): stub\n",
227           ImageBase, debugstr_w(lpBaseName), nSize);
228
229     if (lpBaseName && nSize)
230         lpBaseName[0] = '\0';
231
232     return 0;
233 }
234
235 /***********************************************************************
236  *           GetDeviceDriverFileNameA (PSAPI.@)
237  */
238 DWORD WINAPI GetDeviceDriverFileNameA(LPVOID ImageBase, LPSTR lpFilename, 
239                                       DWORD nSize)
240 {
241     FIXME("(%p, %s, %ld): stub\n",
242           ImageBase, debugstr_a(lpFilename), nSize);
243
244     if (lpFilename && nSize)
245         lpFilename[0] = '\0';
246
247     return 0;
248 }
249
250 /***********************************************************************
251  *           GetDeviceDriverFileNameW (PSAPI.@)
252  */
253 DWORD WINAPI GetDeviceDriverFileNameW(LPVOID ImageBase, LPWSTR lpFilename, 
254                                       DWORD nSize)
255 {
256     FIXME("(%p, %s, %ld): stub\n",
257           ImageBase, debugstr_w(lpFilename), nSize);
258
259     if (lpFilename && nSize)
260         lpFilename[0] = '\0';
261
262     return 0;
263 }
264
265 /***********************************************************************
266  *           GetMappedFileNameA (PSAPI.@)
267  */
268 DWORD WINAPI GetMappedFileNameA(HANDLE hProcess, LPVOID lpv, LPSTR lpFilename, 
269                                 DWORD nSize)
270 {
271     FIXME("(hProcess=%p, %p, %s, %ld): stub\n",
272           hProcess, lpv, debugstr_a(lpFilename), nSize);
273
274     if (lpFilename && nSize)
275         lpFilename[0] = '\0';
276
277     return 0;
278 }
279
280 /***********************************************************************
281  *           GetMappedFileNameW (PSAPI.@)
282  */
283 DWORD WINAPI GetMappedFileNameW(HANDLE hProcess, LPVOID lpv, LPWSTR lpFilename, 
284                                 DWORD nSize)
285 {
286     FIXME("(hProcess=%p, %p, %s, %ld): stub\n",
287           hProcess, lpv, debugstr_w(lpFilename), nSize);
288
289     if (lpFilename && nSize)
290         lpFilename[0] = '\0';
291
292     return 0;
293 }
294
295 /***********************************************************************
296  *           GetModuleBaseNameA (PSAPI.@)
297  */
298 DWORD WINAPI GetModuleBaseNameA(HANDLE hProcess, HMODULE hModule, 
299                                 LPSTR lpBaseName, DWORD nSize)
300 {
301     WCHAR *lpBaseNameW;
302     DWORD buflenW, ret = 0;
303
304     if(!lpBaseName || !nSize) {
305         SetLastError(ERROR_INVALID_PARAMETER);
306         return 0;
307     }
308     lpBaseNameW = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * nSize);
309     buflenW = GetModuleBaseNameW(hProcess, hModule, lpBaseNameW, nSize);
310     TRACE("%ld, %s\n", buflenW, debugstr_w(lpBaseNameW));
311     if (buflenW)
312     {
313         ret = WideCharToMultiByte(CP_ACP, 0, lpBaseNameW, buflenW,
314                                   lpBaseName, nSize, NULL, NULL);
315         if (ret < nSize) lpBaseName[ret] = 0;
316     }
317     HeapFree(GetProcessHeap(), 0, lpBaseNameW);
318     return ret;
319 }
320
321 /***********************************************************************
322  *           GetModuleBaseNameW (PSAPI.@)
323  */
324 DWORD WINAPI GetModuleBaseNameW(HANDLE hProcess, HMODULE hModule, 
325                                 LPWSTR lpBaseName, DWORD nSize)
326 {
327     WCHAR  tmp[MAX_PATH];
328     WCHAR* ptr;
329     int    ptrlen;
330
331     if(!lpBaseName || !nSize) {
332         SetLastError(ERROR_INVALID_PARAMETER);
333         return 0;
334     }
335
336     if (!GetModuleFileNameExW(hProcess, hModule, tmp,
337                               sizeof(tmp)/sizeof(WCHAR)))
338         return 0;
339     TRACE("%s\n", debugstr_w(tmp));
340     if ((ptr = strrchrW(tmp, '\\')) != NULL) ptr++; else ptr = tmp;
341     ptrlen = strlenW(ptr);
342     memcpy(lpBaseName, ptr, min(ptrlen+1,nSize) * sizeof(WCHAR));
343     return min(ptrlen, nSize);
344 }
345
346 /***********************************************************************
347  *           GetModuleFileNameExA (PSAPI.@)
348  */
349 DWORD WINAPI GetModuleFileNameExA(HANDLE hProcess, HMODULE hModule, 
350                                   LPSTR lpFileName, DWORD nSize)
351 {
352     WCHAR *ptr;
353
354     TRACE("(hProcess=%p, hModule=%p, %p, %ld)\n",
355           hProcess, hModule, lpFileName, nSize);
356
357     if (!lpFileName || !nSize) return 0;
358
359     if ( hProcess == GetCurrentProcess() )
360     {
361         DWORD len = GetModuleFileNameA( hModule, lpFileName, nSize );
362         if (nSize) lpFileName[nSize - 1] = '\0';
363         return len;
364     }
365
366     if (!(ptr = HeapAlloc(GetProcessHeap(), 0, nSize * sizeof(WCHAR)))) return 0;
367
368     if (!GetModuleFileNameExW(hProcess, hModule, ptr, nSize))
369     {
370         lpFileName[0] = '\0';
371     }
372     else
373     {
374         if (!WideCharToMultiByte( CP_ACP, 0, ptr, -1, lpFileName, nSize, NULL, NULL ))
375             lpFileName[nSize - 1] = 0;
376     }
377
378     HeapFree(GetProcessHeap(), 0, ptr);
379     return strlen(lpFileName);
380 }
381
382 /***********************************************************************
383  *           GetModuleFileNameExW (PSAPI.@)
384  */
385 DWORD WINAPI GetModuleFileNameExW(HANDLE hProcess, HMODULE hModule, 
386                                   LPWSTR lpFileName, DWORD nSize)
387 {
388     DWORD len = 0;
389
390     TRACE("(hProcess=%p, hModule=%p, %p, %ld)\n",
391           hProcess, hModule, lpFileName, nSize);
392
393     if (!lpFileName || !nSize) return 0;
394
395     if ( hProcess == GetCurrentProcess() )
396     {
397         DWORD len = GetModuleFileNameW( hModule, lpFileName, nSize );
398         if (nSize) lpFileName[nSize - 1] = '\0';
399         TRACE("return (cur) %s (%lu)\n", debugstr_w(lpFileName), len);
400         return len;
401     }
402
403     lpFileName[0] = 0;
404
405     SERVER_START_REQ( get_dll_info )
406     {
407         req->handle       = hProcess;
408         req->base_address = hModule;
409         wine_server_set_reply( req, lpFileName, (nSize - 1) * sizeof(WCHAR) );
410         if (!wine_server_call_err( req ))
411         {
412             len = wine_server_reply_size(reply) / sizeof(WCHAR);
413             lpFileName[len] = 0;
414         }
415     }
416     SERVER_END_REQ;
417
418     TRACE("return %s (%lu)\n", debugstr_w(lpFileName), len);
419
420     return len;
421 }
422
423 /***********************************************************************
424  *           GetModuleInformation (PSAPI.@)
425  */
426 BOOL WINAPI GetModuleInformation(HANDLE hProcess, HMODULE hModule, 
427                                  LPMODULEINFO lpmodinfo, DWORD cb)
428 {
429     BOOL ret = FALSE;
430
431     TRACE("(hProcess=%p, hModule=%p, %p, %ld)\n",
432           hProcess, hModule, lpmodinfo, cb);
433
434     if (cb < sizeof(MODULEINFO)) return FALSE;
435
436     SERVER_START_REQ( get_dll_info )
437     {
438         req->handle       = hProcess;
439         req->base_address = (void*)hModule;
440         if (!wine_server_call_err( req ))
441         {
442             ret = TRUE;
443             lpmodinfo->lpBaseOfDll = (void*)hModule;
444             lpmodinfo->SizeOfImage = reply->size;
445             lpmodinfo->EntryPoint  = reply->entry_point;
446         }
447     }
448     SERVER_END_REQ;
449
450     return TRUE;
451 }
452
453 /***********************************************************************
454  *           GetPerformanceInfo (PSAPI.@)
455  */
456 BOOL WINAPI GetPerformanceInfo( PPERFORMANCE_INFORMATION info, DWORD size )
457 {
458     NTSTATUS status;
459
460     TRACE( "(%p, %ld)\n", info, size );
461
462     status = NtQueryInformationProcess( GetCurrentProcess(), SystemPerformanceInformation, info, size, NULL );
463
464     if (status)
465     {
466         SetLastError( RtlNtStatusToDosError( status ) );
467         return FALSE;
468     }
469     return TRUE;
470 }
471
472 /***********************************************************************
473  *           GetProcessImageFileNameA (PSAPI.@)
474  */
475 DWORD WINAPI GetProcessImageFileNameA( HANDLE process, LPSTR file, DWORD size )
476 {
477     FIXME("(%p, %p, %ld) stub\n", process, file, size );
478     return 0;
479 }
480
481 /***********************************************************************
482  *           GetProcessImageFileNameW (PSAPI.@)
483  */
484 DWORD WINAPI GetProcessImageFileNameW( HANDLE process, LPWSTR file, DWORD size )
485 {
486     FIXME("(%p, %p, %ld) stub\n", process, file, size );
487     return 0;
488 }
489
490 /***********************************************************************
491  *           GetProcessMemoryInfo (PSAPI.@)
492  *
493  * Retrieve memory usage information for a given process
494  *
495  */
496 BOOL WINAPI GetProcessMemoryInfo( HANDLE process, PPROCESS_MEMORY_COUNTERS counters, DWORD size )
497 {
498     NTSTATUS status;
499     VM_COUNTERS vmc;
500
501     TRACE( "(%p, %p, %ld)\n", process, counters, size );
502
503     status = NtQueryInformationProcess( process, ProcessVmCounters, &vmc, sizeof(vmc), NULL );
504
505     if (status)
506     {
507         SetLastError( RtlNtStatusToDosError( status ) );
508         return FALSE;
509     }
510
511     /* FIXME: check size */
512
513     counters->cb = sizeof(PROCESS_MEMORY_COUNTERS);
514     counters->PageFaultCount = vmc.PageFaultCount;
515     counters->PeakWorkingSetSize = vmc.PeakWorkingSetSize;
516     counters->WorkingSetSize = vmc.WorkingSetSize;
517     counters->QuotaPeakPagedPoolUsage = vmc.QuotaPeakPagedPoolUsage;
518     counters->QuotaPagedPoolUsage = vmc.QuotaPagedPoolUsage;
519     counters->QuotaPeakNonPagedPoolUsage = vmc.QuotaPeakNonPagedPoolUsage;
520     counters->QuotaNonPagedPoolUsage = vmc.QuotaNonPagedPoolUsage;
521     counters->PagefileUsage = vmc.PagefileUsage;
522     counters->PeakPagefileUsage = vmc.PeakPagefileUsage;
523
524     return TRUE;
525 }
526
527 /***********************************************************************
528  *           GetWsChanges (PSAPI.@)
529  */
530 BOOL WINAPI GetWsChanges( HANDLE process, PPSAPI_WS_WATCH_INFORMATION watchinfo, DWORD size )
531 {
532     NTSTATUS status;
533
534     TRACE( "(%p, %p, %ld)\n", process, watchinfo, size );
535
536     status = NtQueryVirtualMemory( process, NULL, ProcessWorkingSetWatch, watchinfo, size, NULL );
537
538     if (status)
539     {
540         SetLastError( RtlNtStatusToDosError( status ) );
541         return FALSE;
542     }
543     return TRUE;
544 }
545
546 /***********************************************************************
547  *           InitializeProcessForWsWatch (PSAPI.@)
548  */
549 BOOL WINAPI InitializeProcessForWsWatch(HANDLE hProcess)
550 {
551     FIXME("(hProcess=%p): stub\n", hProcess);
552
553     return TRUE;
554 }
555
556 /***********************************************************************
557  *           QueryWorkingSet (PSAPI.@)
558  */
559 BOOL WINAPI QueryWorkingSet( HANDLE process, LPVOID buffer, DWORD size )
560 {
561     NTSTATUS status;
562
563     TRACE( "(%p, %p, %ld)\n", process, buffer, size );
564
565     status = NtQueryVirtualMemory( process, NULL, MemoryWorkingSetList, buffer, size, NULL );
566
567     if (status)
568     {
569         SetLastError( RtlNtStatusToDosError( status ) );
570         return FALSE;
571     }
572     return TRUE;
573 }
574
575 /***********************************************************************
576  *           QueryWorkingSetEx (PSAPI.@)
577  */
578 BOOL WINAPI QueryWorkingSetEx( HANDLE process, LPVOID buffer, DWORD size )
579 {
580     NTSTATUS status;
581
582     TRACE( "(%p, %p, %ld)\n", process, buffer, size );
583
584     status = NtQueryVirtualMemory( process, NULL, MemoryWorkingSetList, buffer,  size, NULL );
585
586     if (status)
587     {
588         SetLastError( RtlNtStatusToDosError( status ) );
589         return FALSE;
590     }
591     return TRUE;
592 }