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