mmdevapi/tests: Add tests for volume control interfaces.
[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  *          GetDeviceDriverBaseNameA (PSAPI.@)
183  */
184 DWORD WINAPI GetDeviceDriverBaseNameA(LPVOID ImageBase, LPSTR lpBaseName, 
185                                       DWORD nSize)
186 {
187     FIXME("(%p, %p, %d): stub\n", ImageBase, lpBaseName, nSize);
188
189     if (lpBaseName && nSize)
190         lpBaseName[0] = '\0';
191
192     return 0;
193 }
194
195 /***********************************************************************
196  *           GetDeviceDriverBaseNameW (PSAPI.@)
197  */
198 DWORD WINAPI GetDeviceDriverBaseNameW(LPVOID ImageBase, LPWSTR lpBaseName, 
199                                       DWORD nSize)
200 {
201     FIXME("(%p, %p, %d): stub\n", ImageBase, lpBaseName, nSize);
202
203     if (lpBaseName && nSize)
204         lpBaseName[0] = '\0';
205
206     return 0;
207 }
208
209 /***********************************************************************
210  *           GetDeviceDriverFileNameA (PSAPI.@)
211  */
212 DWORD WINAPI GetDeviceDriverFileNameA(LPVOID ImageBase, LPSTR lpFilename, 
213                                       DWORD nSize)
214 {
215     FIXME("(%p, %p, %d): stub\n", ImageBase, lpFilename, nSize);
216
217     if (lpFilename && nSize)
218         lpFilename[0] = '\0';
219
220     return 0;
221 }
222
223 /***********************************************************************
224  *           GetDeviceDriverFileNameW (PSAPI.@)
225  */
226 DWORD WINAPI GetDeviceDriverFileNameW(LPVOID ImageBase, LPWSTR lpFilename, 
227                                       DWORD nSize)
228 {
229     FIXME("(%p, %p, %d): stub\n", ImageBase, lpFilename, nSize);
230
231     if (lpFilename && nSize)
232         lpFilename[0] = '\0';
233
234     return 0;
235 }
236
237 /***********************************************************************
238  *           GetMappedFileNameA (PSAPI.@)
239  */
240 DWORD WINAPI GetMappedFileNameA(HANDLE hProcess, LPVOID lpv, LPSTR lpFilename, 
241                                 DWORD nSize)
242 {
243     FIXME("(%p, %p, %p, %d): stub\n", hProcess, lpv, lpFilename, nSize);
244
245     if (lpFilename && nSize)
246         lpFilename[0] = '\0';
247
248     return 0;
249 }
250
251 /***********************************************************************
252  *           GetMappedFileNameW (PSAPI.@)
253  */
254 DWORD WINAPI GetMappedFileNameW(HANDLE hProcess, LPVOID lpv, LPWSTR lpFilename, 
255                                 DWORD nSize)
256 {
257     FIXME("(%p, %p, %p, %d): stub\n", hProcess, lpv, lpFilename, nSize);
258
259     if (lpFilename && nSize)
260         lpFilename[0] = '\0';
261
262     return 0;
263 }
264
265 /***********************************************************************
266  *           GetModuleBaseNameA (PSAPI.@)
267  */
268 DWORD WINAPI GetModuleBaseNameA(HANDLE hProcess, HMODULE hModule, 
269                                 LPSTR lpBaseName, DWORD nSize)
270 {
271     WCHAR *lpBaseNameW;
272     DWORD buflenW, ret = 0;
273
274     if(!lpBaseName || !nSize) {
275         SetLastError(ERROR_INVALID_PARAMETER);
276         return 0;
277     }
278     lpBaseNameW = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * nSize);
279     buflenW = GetModuleBaseNameW(hProcess, hModule, lpBaseNameW, nSize);
280     TRACE("%d, %s\n", buflenW, debugstr_w(lpBaseNameW));
281     if (buflenW)
282     {
283         ret = WideCharToMultiByte(CP_ACP, 0, lpBaseNameW, buflenW,
284                                   lpBaseName, nSize, NULL, NULL);
285         if (ret < nSize) lpBaseName[ret] = 0;
286     }
287     HeapFree(GetProcessHeap(), 0, lpBaseNameW);
288     return ret;
289 }
290
291 /***********************************************************************
292  *           GetModuleBaseNameW (PSAPI.@)
293  */
294 DWORD WINAPI GetModuleBaseNameW(HANDLE hProcess, HMODULE hModule, 
295                                 LPWSTR lpBaseName, DWORD nSize)
296 {
297     LDR_MODULE LdrModule;
298
299     if (!PSAPI_GetLdrModule(hProcess, hModule, &LdrModule))
300         return 0;
301
302     nSize = min(LdrModule.BaseDllName.Length / sizeof(WCHAR), nSize);
303     if (!ReadProcessMemory(hProcess, LdrModule.BaseDllName.Buffer,
304                            lpBaseName, nSize * sizeof(WCHAR), NULL))
305         return 0;
306
307     lpBaseName[nSize] = 0;
308     return nSize;
309 }
310
311 /***********************************************************************
312  *           GetModuleFileNameExA (PSAPI.@)
313  */
314 DWORD WINAPI GetModuleFileNameExA(HANDLE hProcess, HMODULE hModule, 
315                                   LPSTR lpFileName, DWORD nSize)
316 {
317     WCHAR *ptr;
318
319     TRACE("(hProcess=%p, hModule=%p, %p, %d)\n",
320           hProcess, hModule, lpFileName, nSize);
321
322     if (!lpFileName || !nSize) return 0;
323
324     if ( hProcess == GetCurrentProcess() )
325     {
326         DWORD len = GetModuleFileNameA( hModule, lpFileName, nSize );
327         if (nSize) lpFileName[nSize - 1] = '\0';
328         return len;
329     }
330
331     if (!(ptr = HeapAlloc(GetProcessHeap(), 0, nSize * sizeof(WCHAR)))) return 0;
332
333     if (!GetModuleFileNameExW(hProcess, hModule, ptr, nSize))
334     {
335         lpFileName[0] = '\0';
336     }
337     else
338     {
339         if (!WideCharToMultiByte( CP_ACP, 0, ptr, -1, lpFileName, nSize, NULL, NULL ))
340             lpFileName[nSize - 1] = 0;
341     }
342
343     HeapFree(GetProcessHeap(), 0, ptr);
344     return strlen(lpFileName);
345 }
346
347 /***********************************************************************
348  *           GetModuleFileNameExW (PSAPI.@)
349  */
350 DWORD WINAPI GetModuleFileNameExW(HANDLE hProcess, HMODULE hModule, 
351                                   LPWSTR lpFileName, DWORD nSize)
352 {
353     LDR_MODULE LdrModule;
354     
355     if(!PSAPI_GetLdrModule(hProcess, hModule, &LdrModule))
356         return 0;
357         
358     nSize = min(LdrModule.FullDllName.Length / sizeof(WCHAR), nSize);
359     if (!ReadProcessMemory(hProcess, LdrModule.FullDllName.Buffer,
360                            lpFileName, nSize * sizeof(WCHAR), NULL))
361         return 0;
362
363     lpFileName[nSize] = 0;
364     return nSize;
365 }
366
367 /***********************************************************************
368  *           GetModuleInformation (PSAPI.@)
369  */
370 BOOL WINAPI GetModuleInformation(HANDLE hProcess, HMODULE hModule, 
371                                  LPMODULEINFO lpmodinfo, DWORD cb)
372 {
373     LDR_MODULE LdrModule;
374
375     if (cb < sizeof(MODULEINFO)) 
376     {
377         SetLastError(ERROR_INSUFFICIENT_BUFFER);
378         return FALSE;
379     }
380
381     if (!PSAPI_GetLdrModule(hProcess, hModule, &LdrModule))
382         return FALSE;
383
384     lpmodinfo->lpBaseOfDll = LdrModule.BaseAddress;
385     lpmodinfo->SizeOfImage = LdrModule.SizeOfImage;
386     lpmodinfo->EntryPoint  = LdrModule.EntryPoint;
387     return TRUE;
388 }
389
390 /***********************************************************************
391  *           GetPerformanceInfo (PSAPI.@)
392  */
393 BOOL WINAPI GetPerformanceInfo( PPERFORMANCE_INFORMATION info, DWORD size )
394 {
395     NTSTATUS status;
396
397     TRACE( "(%p, %d)\n", info, size );
398
399     status = NtQuerySystemInformation( SystemPerformanceInformation, info, size, NULL );
400
401     if (status)
402     {
403         SetLastError( RtlNtStatusToDosError( status ) );
404         return FALSE;
405     }
406     return TRUE;
407 }
408
409 /***********************************************************************
410  *           GetProcessMemoryInfo (PSAPI.@)
411  *
412  * Retrieve memory usage information for a given process
413  *
414  */
415 BOOL WINAPI GetProcessMemoryInfo(HANDLE hProcess, 
416                                  PPROCESS_MEMORY_COUNTERS pmc, DWORD cb)
417 {
418     NTSTATUS status;
419     VM_COUNTERS vmc;
420
421     if (cb < sizeof(PROCESS_MEMORY_COUNTERS))
422     {
423         SetLastError(ERROR_INSUFFICIENT_BUFFER);
424         return FALSE;
425     }
426
427     status = NtQueryInformationProcess(hProcess, ProcessVmCounters, 
428                                        &vmc, sizeof(vmc), NULL);
429
430     if (status)
431     {
432         SetLastError(RtlNtStatusToDosError(status));
433         return FALSE;
434     }
435
436     pmc->cb = sizeof(PROCESS_MEMORY_COUNTERS);
437     pmc->PageFaultCount = vmc.PageFaultCount;
438     pmc->PeakWorkingSetSize = vmc.PeakWorkingSetSize;
439     pmc->WorkingSetSize = vmc.WorkingSetSize;
440     pmc->QuotaPeakPagedPoolUsage = vmc.QuotaPeakPagedPoolUsage;
441     pmc->QuotaPagedPoolUsage = vmc.QuotaPagedPoolUsage;
442     pmc->QuotaPeakNonPagedPoolUsage = vmc.QuotaPeakNonPagedPoolUsage;
443     pmc->QuotaNonPagedPoolUsage = vmc.QuotaNonPagedPoolUsage;
444     pmc->PagefileUsage = vmc.PagefileUsage;
445     pmc->PeakPagefileUsage = vmc.PeakPagefileUsage;
446
447     return TRUE;
448 }
449
450 /***********************************************************************
451  *           GetWsChanges (PSAPI.@)
452  */
453 BOOL WINAPI GetWsChanges( HANDLE process, PPSAPI_WS_WATCH_INFORMATION watchinfo, DWORD size )
454 {
455     NTSTATUS status;
456
457     TRACE( "(%p, %p, %d)\n", process, watchinfo, size );
458
459     status = NtQueryInformationProcess( process, ProcessWorkingSetWatch, watchinfo, size, NULL );
460
461     if (status)
462     {
463         SetLastError( RtlNtStatusToDosError( status ) );
464         return FALSE;
465     }
466     return TRUE;
467 }
468
469 /***********************************************************************
470  *           InitializeProcessForWsWatch (PSAPI.@)
471  */
472 BOOL WINAPI InitializeProcessForWsWatch(HANDLE hProcess)
473 {
474     FIXME("(hProcess=%p): stub\n", hProcess);
475
476     return TRUE;
477 }
478
479 /***********************************************************************
480  *           QueryWorkingSet (PSAPI.@)
481  */
482 BOOL WINAPI QueryWorkingSet( HANDLE process, LPVOID buffer, DWORD size )
483 {
484     NTSTATUS status;
485
486     TRACE( "(%p, %p, %d)\n", process, buffer, size );
487
488     status = NtQueryVirtualMemory( process, NULL, MemoryWorkingSetList, buffer, size, NULL );
489
490     if (status)
491     {
492         SetLastError( RtlNtStatusToDosError( status ) );
493         return FALSE;
494     }
495     return TRUE;
496 }
497
498 /***********************************************************************
499  *           QueryWorkingSetEx (PSAPI.@)
500  */
501 BOOL WINAPI QueryWorkingSetEx( HANDLE process, LPVOID buffer, DWORD size )
502 {
503     NTSTATUS status;
504
505     TRACE( "(%p, %p, %d)\n", process, buffer, size );
506
507     status = NtQueryVirtualMemory( process, NULL, MemoryWorkingSetList, buffer,  size, NULL );
508
509     if (status)
510     {
511         SetLastError( RtlNtStatusToDosError( status ) );
512         return FALSE;
513     }
514     return TRUE;
515 }