1 /*
2  * Unit test suite for PSAPI
3  *
4  * Copyright (C) 2005 Felix Nawothnig
5  * Copyright (C) 2012 Dmitry Timoshkov
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 /* 0x0600 makes PROCESS_ALL_ACCESS not compatible with pre-Vista versions */
23 #ifndef __REACTOS__
24 #define _WIN32_WINNT 0x0500
25 #endif
26 
27 #include <stdarg.h>
28 
29 #include "ntstatus.h"
30 #define WIN32_NO_STATUS
31 
32 #include "windef.h"
33 #include "winbase.h"
34 #include "winreg.h"
35 #include "winnt.h"
36 #include "wine/winternl.h"
37 #include "winnls.h"
38 #include "psapi.h"
39 #include "wine/test.h"
40 
41 #define PSAPI_GET_PROC(func) \
42     p ## func = (void*)GetProcAddress(hpsapi, #func); \
43     if(!p ## func) { \
44         ok(0, "GetProcAddress(%s) failed\n", #func); \
45         FreeLibrary(hpsapi); \
46         return FALSE; \
47     }
48 
49 static BOOL  (WINAPI *pEmptyWorkingSet)(HANDLE);
50 static BOOL  (WINAPI *pEnumProcesses)(DWORD*, DWORD, DWORD*);
51 static BOOL  (WINAPI *pEnumProcessModules)(HANDLE, HMODULE*, DWORD, LPDWORD);
52 static DWORD (WINAPI *pGetModuleBaseNameA)(HANDLE, HMODULE, LPSTR, DWORD);
53 static DWORD (WINAPI *pGetModuleFileNameExA)(HANDLE, HMODULE, LPSTR, DWORD);
54 static DWORD (WINAPI *pGetModuleFileNameExW)(HANDLE, HMODULE, LPWSTR, DWORD);
55 static BOOL  (WINAPI *pGetModuleInformation)(HANDLE, HMODULE, LPMODULEINFO, DWORD);
56 static DWORD (WINAPI *pGetMappedFileNameA)(HANDLE, LPVOID, LPSTR, DWORD);
57 static DWORD (WINAPI *pGetMappedFileNameW)(HANDLE, LPVOID, LPWSTR, DWORD);
58 static BOOL  (WINAPI *pGetPerformanceInfo)(PPERFORMANCE_INFORMATION, DWORD);
59 static DWORD (WINAPI *pGetProcessImageFileNameA)(HANDLE, LPSTR, DWORD);
60 static DWORD (WINAPI *pGetProcessImageFileNameW)(HANDLE, LPWSTR, DWORD);
61 static BOOL  (WINAPI *pGetProcessMemoryInfo)(HANDLE, PPROCESS_MEMORY_COUNTERS, DWORD);
62 static BOOL  (WINAPI *pGetWsChanges)(HANDLE, PPSAPI_WS_WATCH_INFORMATION, DWORD);
63 static BOOL  (WINAPI *pInitializeProcessForWsWatch)(HANDLE);
64 static BOOL  (WINAPI *pQueryWorkingSet)(HANDLE, PVOID, DWORD);
65 static NTSTATUS (WINAPI *pNtQuerySystemInformation)(SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG);
66 static NTSTATUS (WINAPI *pNtQueryVirtualMemory)(HANDLE, LPCVOID, ULONG, PVOID, SIZE_T, SIZE_T *);
67 
68 static BOOL InitFunctionPtrs(HMODULE hpsapi)
69 {
70     PSAPI_GET_PROC(EmptyWorkingSet);
71     PSAPI_GET_PROC(EnumProcessModules);
72     PSAPI_GET_PROC(EnumProcesses);
73     PSAPI_GET_PROC(GetModuleBaseNameA);
74     PSAPI_GET_PROC(GetModuleFileNameExA);
75     PSAPI_GET_PROC(GetModuleFileNameExW);
76     PSAPI_GET_PROC(GetModuleInformation);
77     PSAPI_GET_PROC(GetMappedFileNameA);
78     PSAPI_GET_PROC(GetMappedFileNameW);
79     PSAPI_GET_PROC(GetProcessMemoryInfo);
80     PSAPI_GET_PROC(GetWsChanges);
81     PSAPI_GET_PROC(InitializeProcessForWsWatch);
82     PSAPI_GET_PROC(QueryWorkingSet);
83     /* GetProcessImageFileName is not exported on NT4 */
84     pGetPerformanceInfo =
85       (void *)GetProcAddress(hpsapi, "GetPerformanceInfo");
86     pGetProcessImageFileNameA =
87       (void *)GetProcAddress(hpsapi, "GetProcessImageFileNameA");
88     pGetProcessImageFileNameW =
89       (void *)GetProcAddress(hpsapi, "GetProcessImageFileNameW");
90     pNtQuerySystemInformation = (void *)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtQuerySystemInformation");
91     pNtQueryVirtualMemory = (void *)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtQueryVirtualMemory");
92     return TRUE;
93 }
94 
95 static HANDLE hpSR, hpQI, hpVR, hpQV, hpAA;
96 static const HANDLE hBad = (HANDLE)0xdeadbeef;
97 
98 static void test_EnumProcesses(void)
99 {
100     DWORD pid, ret, cbUsed = 0xdeadbeef;
101 
102     SetLastError(0xdeadbeef);
103     ret = pEnumProcesses(NULL, 0, &cbUsed);
104     ok(ret == 1, "failed with %d\n", GetLastError());
105     ok(cbUsed == 0, "cbUsed=%d\n", cbUsed);
106 
107     SetLastError(0xdeadbeef);
108     ret = pEnumProcesses(&pid, 4, &cbUsed);
109     ok(ret == 1, "failed with %d\n", GetLastError());
110     ok(cbUsed == 4, "cbUsed=%d\n", cbUsed);
111 }
112 
113 static void test_EnumProcessModules(void)
114 {
115     HMODULE hMod;
116     DWORD ret, cbNeeded = 0xdeadbeef;
117 
118     SetLastError(0xdeadbeef);
119     pEnumProcessModules(NULL, NULL, 0, &cbNeeded);
120     ok(GetLastError() == ERROR_INVALID_HANDLE, "expected error=ERROR_INVALID_HANDLE but got %d\n", GetLastError());
121 
122     SetLastError(0xdeadbeef);
123     pEnumProcessModules(hpQI, NULL, 0, &cbNeeded);
124     ok(GetLastError() == ERROR_ACCESS_DENIED, "expected error=ERROR_ACCESS_DENIED but got %d\n", GetLastError());
125 
126     SetLastError(0xdeadbeef);
127     hMod = (void *)0xdeadbeef;
128     ret = pEnumProcessModules(hpQI, &hMod, sizeof(HMODULE), NULL);
129     ok(!ret, "succeeded\n");
130     ok(GetLastError() == ERROR_ACCESS_DENIED, "expected error=ERROR_ACCESS_DENIED but got %d\n", GetLastError());
131 
132     SetLastError(0xdeadbeef);
133     hMod = (void *)0xdeadbeef;
134     ret = pEnumProcessModules(hpQV, &hMod, sizeof(HMODULE), NULL);
135     ok(!ret, "succeeded\n");
136     ok(GetLastError() == ERROR_NOACCESS, "expected error=ERROR_NOACCESS but got %d\n", GetLastError());
137     ok(hMod == GetModuleHandleA(NULL),
138        "hMod=%p GetModuleHandleA(NULL)=%p\n", hMod, GetModuleHandleA(NULL));
139 
140     SetLastError(0xdeadbeef);
141     ret = pEnumProcessModules(hpQV, NULL, 0, &cbNeeded);
142     ok(ret == 1, "failed with %d\n", GetLastError());
143 
144     SetLastError(0xdeadbeef);
145     ret = pEnumProcessModules(hpQV, NULL, sizeof(HMODULE), &cbNeeded);
146     ok(!ret, "succeeded\n");
147     ok(GetLastError() == ERROR_NOACCESS, "expected error=ERROR_NOACCESS but got %d\n", GetLastError());
148 
149     SetLastError(0xdeadbeef);
150     hMod = (void *)0xdeadbeef;
151     ret = pEnumProcessModules(hpQV, &hMod, sizeof(HMODULE), &cbNeeded);
152     ok(ret == 1, "got %d, failed with %d\n", ret, GetLastError());
153     ok(hMod == GetModuleHandleA(NULL),
154        "hMod=%p GetModuleHandleA(NULL)=%p\n", hMod, GetModuleHandleA(NULL));
155     ok(cbNeeded % sizeof(hMod) == 0, "not a multiple of sizeof(HMODULE) cbNeeded=%d\n", cbNeeded);
156 }
157 
158 static void test_GetModuleInformation(void)
159 {
160     HMODULE hMod = GetModuleHandleA(NULL);
161     DWORD *tmp, counter = 0;
162     MODULEINFO info;
163     DWORD ret;
164 
165     SetLastError(0xdeadbeef);
166     pGetModuleInformation(NULL, hMod, &info, sizeof(info));
167     ok(GetLastError() == ERROR_INVALID_HANDLE, "expected error=ERROR_INVALID_HANDLE but got %d\n", GetLastError());
168 
169     SetLastError(0xdeadbeef);
170     pGetModuleInformation(hpQI, hMod, &info, sizeof(info));
171     ok(GetLastError() == ERROR_ACCESS_DENIED, "expected error=ERROR_ACCESS_DENIED but got %d\n", GetLastError());
172 
173     SetLastError(0xdeadbeef);
174     pGetModuleInformation(hpQV, hBad, &info, sizeof(info));
175     ok(GetLastError() == ERROR_INVALID_HANDLE, "expected error=ERROR_INVALID_HANDLE but got %d\n", GetLastError());
176 
177     SetLastError(0xdeadbeef);
178     pGetModuleInformation(hpQV, hMod, &info, sizeof(info)-1);
179     ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "expected error=ERROR_INSUFFICIENT_BUFFER but got %d\n", GetLastError());
180 
181     ret = pGetModuleInformation(hpQV, hMod, &info, sizeof(info));
182     ok(ret == 1, "failed with %d\n", GetLastError());
183     ok(info.lpBaseOfDll == hMod, "lpBaseOfDll=%p hMod=%p\n", info.lpBaseOfDll, hMod);
184 
185     hMod = LoadLibraryA("shell32.dll");
186     ok(hMod != NULL, "Failed to load shell32.dll, error: %u\n", GetLastError());
187 
188     ret = pGetModuleInformation(hpQV, hMod, &info, sizeof(info));
189     ok(ret == 1, "failed with %d\n", GetLastError());
190     info.SizeOfImage /= sizeof(DWORD);
191     for (tmp = (DWORD *)hMod; info.SizeOfImage; info.SizeOfImage--)
192         counter ^= *tmp++;
193     trace("xor of shell32: %08x\n", counter);
194 
195     FreeLibrary(hMod);
196 }
197 
198 static BOOL check_with_margin(SIZE_T perf, SIZE_T sysperf, int margin)
199 {
200     return (perf >= max(sysperf, margin) - margin && perf <= sysperf + margin);
201 }
202 
203 static void test_GetPerformanceInfo(void)
204 {
205     PERFORMANCE_INFORMATION info;
206     NTSTATUS status;
207     DWORD size;
208     BOOL ret;
209 
210     SetLastError(0xdeadbeef);
211     ret = pGetPerformanceInfo(&info, sizeof(info)-1);
212     ok(!ret, "GetPerformanceInfo unexpectedly succeeded\n");
213     ok(GetLastError() == ERROR_BAD_LENGTH, "expected error=ERROR_BAD_LENGTH but got %d\n", GetLastError());
214 
215     SetLastError(0xdeadbeef);
216     ret = pGetPerformanceInfo(&info, sizeof(info));
217     ok(ret, "GetPerformanceInfo failed with %d\n", GetLastError());
218     ok(info.cb == sizeof(PERFORMANCE_INFORMATION), "got %d\n", info.cb);
219 
220     if (!pNtQuerySystemInformation)
221         win_skip("NtQuerySystemInformation not found, skipping tests\n");
222     else
223     {
224         char performance_buffer[sizeof(SYSTEM_PERFORMANCE_INFORMATION) + 16]; /* larger on w2k8/win7 */
225         SYSTEM_PERFORMANCE_INFORMATION *sys_performance_info = (SYSTEM_PERFORMANCE_INFORMATION *)performance_buffer;
226         SYSTEM_PROCESS_INFORMATION *sys_process_info = NULL, *spi;
227         SYSTEM_BASIC_INFORMATION sys_basic_info;
228         DWORD process_count, handle_count, thread_count;
229 
230         /* compare with values from SYSTEM_PERFORMANCE_INFORMATION */
231         size = 0;
232         status = pNtQuerySystemInformation(SystemPerformanceInformation, sys_performance_info, sizeof(performance_buffer), &size);
233         ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status);
234         ok(size >= sizeof(SYSTEM_PERFORMANCE_INFORMATION), "incorrect length %d\n", size);
235 
236 
237         ok(check_with_margin(info.CommitTotal,          sys_performance_info->TotalCommittedPages,  288),
238            "expected approximately %ld but got %d\n", info.CommitTotal, sys_performance_info->TotalCommittedPages);
239 
240         ok(check_with_margin(info.CommitLimit,          sys_performance_info->TotalCommitLimit,     32),
241            "expected approximately %ld but got %d\n", info.CommitLimit, sys_performance_info->TotalCommitLimit);
242 
243         ok(check_with_margin(info.CommitPeak,           sys_performance_info->PeakCommitment,       32),
244            "expected approximately %ld but got %d\n", info.CommitPeak, sys_performance_info->PeakCommitment);
245 
246         ok(check_with_margin(info.PhysicalAvailable,    sys_performance_info->AvailablePages,       512),
247            "expected approximately %ld but got %d\n", info.PhysicalAvailable, sys_performance_info->AvailablePages);
248 
249         /* TODO: info.SystemCache not checked yet - to which field(s) does this value correspond to? */
250 
251         ok(check_with_margin(info.KernelTotal, sys_performance_info->PagedPoolUsage + sys_performance_info->NonPagedPoolUsage, 256),
252            "expected approximately %ld but got %d\n", info.KernelTotal,
253            sys_performance_info->PagedPoolUsage + sys_performance_info->NonPagedPoolUsage);
254 
255         ok(check_with_margin(info.KernelPaged,          sys_performance_info->PagedPoolUsage,       256),
256            "expected approximately %ld but got %d\n", info.KernelPaged, sys_performance_info->PagedPoolUsage);
257 
258         ok(check_with_margin(info.KernelNonpaged,       sys_performance_info->NonPagedPoolUsage,    16),
259            "expected approximately %ld but got %d\n", info.KernelNonpaged, sys_performance_info->NonPagedPoolUsage);
260 
261         /* compare with values from SYSTEM_BASIC_INFORMATION */
262         size = 0;
263         status = pNtQuerySystemInformation(SystemBasicInformation, &sys_basic_info, sizeof(sys_basic_info), &size);
264         ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status);
265         ok(size >= sizeof(SYSTEM_BASIC_INFORMATION), "incorrect length %d\n", size);
266 
267         ok(info.PhysicalTotal == sys_basic_info.MmNumberOfPhysicalPages,
268            "expected info.PhysicalTotal=%u but got %u\n",
269            sys_basic_info.MmNumberOfPhysicalPages, (ULONG)info.PhysicalTotal);
270 
271         ok(info.PageSize == sys_basic_info.PageSize,
272            "expected info.PageSize=%u but got %u\n",
273            sys_basic_info.PageSize, (ULONG)info.PageSize);
274 
275         /* compare with values from SYSTEM_PROCESS_INFORMATION */
276         size = 0;
277         status = pNtQuerySystemInformation(SystemProcessInformation, NULL, 0, &size);
278         ok(status == STATUS_INFO_LENGTH_MISMATCH, "expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status);
279         ok(size > 0, "incorrect length %d\n", size);
280         while (status == STATUS_INFO_LENGTH_MISMATCH)
281         {
282             sys_process_info = HeapAlloc(GetProcessHeap(), 0, size);
283             ok(sys_process_info != NULL, "failed to allocate memory\n");
284             status = pNtQuerySystemInformation(SystemProcessInformation, sys_process_info, size, &size);
285             if (status == STATUS_SUCCESS) break;
286             HeapFree(GetProcessHeap(), 0, sys_process_info);
287         }
288         ok(status == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %08x\n", status);
289 
290         process_count = handle_count = thread_count = 0;
291         for (spi = sys_process_info;; spi = (SYSTEM_PROCESS_INFORMATION *)(((char *)spi) + spi->NextEntryOffset))
292         {
293             process_count++;
294             handle_count += spi->HandleCount;
295             thread_count += spi->dwThreadCount;
296             if (spi->NextEntryOffset == 0) break;
297         }
298         HeapFree(GetProcessHeap(), 0, sys_process_info);
299 
300         ok(check_with_margin(info.HandleCount,  handle_count,  24),
301            "expected approximately %d but got %d\n", info.HandleCount, handle_count);
302 
303         ok(check_with_margin(info.ProcessCount, process_count, 4),
304            "expected approximately %d but got %d\n", info.ProcessCount, process_count);
305 
306         ok(check_with_margin(info.ThreadCount,  thread_count,  4),
307            "expected approximately %d but got %d\n", info.ThreadCount, thread_count);
308     }
309 }
310 
311 
312 static void test_GetProcessMemoryInfo(void)
313 {
314     PROCESS_MEMORY_COUNTERS pmc;
315     DWORD ret;
316 
317     SetLastError(0xdeadbeef);
318     ret = pGetProcessMemoryInfo(NULL, &pmc, sizeof(pmc));
319     ok(!ret, "GetProcessMemoryInfo should fail\n");
320     ok(GetLastError() == ERROR_INVALID_HANDLE, "expected error=ERROR_INVALID_HANDLE but got %d\n", GetLastError());
321 
322     SetLastError(0xdeadbeef);
323     ret = pGetProcessMemoryInfo(hpSR, &pmc, sizeof(pmc));
324     ok(!ret, "GetProcessMemoryInfo should fail\n");
325     ok(GetLastError() == ERROR_ACCESS_DENIED, "expected error=ERROR_ACCESS_DENIED but got %d\n", GetLastError());
326 
327     SetLastError(0xdeadbeef);
328     ret = pGetProcessMemoryInfo(hpQI, &pmc, sizeof(pmc)-1);
329     ok(!ret, "GetProcessMemoryInfo should fail\n");
330     ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "expected error=ERROR_INSUFFICIENT_BUFFER but got %d\n", GetLastError());
331 
332     SetLastError(0xdeadbeef);
333     ret = pGetProcessMemoryInfo(hpQI, &pmc, sizeof(pmc));
334     ok(ret == 1, "failed with %d\n", GetLastError());
335 }
336 
337 static BOOL nt_get_mapped_file_name(HANDLE process, LPVOID addr, LPWSTR name, DWORD len)
338 {
339     MEMORY_SECTION_NAME *section_name;
340     WCHAR *buf;
341     SIZE_T buf_len, ret_len;
342     NTSTATUS status;
343 
344     if (!pNtQueryVirtualMemory) return FALSE;
345 
346     buf_len = len * sizeof(WCHAR) + sizeof(MEMORY_SECTION_NAME);
347     buf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buf_len);
348 
349     ret_len = 0xdeadbeef;
350     status = pNtQueryVirtualMemory(process, addr, MemorySectionName, buf, buf_len, &ret_len);
351     ok(!status, "NtQueryVirtualMemory error %x\n", status);
352 
353     section_name = (MEMORY_SECTION_NAME *)buf;
354     ok(ret_len == section_name->SectionFileName.MaximumLength + sizeof(*section_name), "got %lu, %u\n",
355        ret_len, section_name->SectionFileName.MaximumLength);
356     ok((char *)section_name->SectionFileName.Buffer == (char *)section_name + sizeof(*section_name), "got %p, %p\n",
357        section_name, section_name->SectionFileName.Buffer);
358     ok(section_name->SectionFileName.MaximumLength == section_name->SectionFileName.Length + sizeof(WCHAR), "got %u, %u\n",
359        section_name->SectionFileName.MaximumLength, section_name->SectionFileName.Length);
360     ok(section_name->SectionFileName.Length == lstrlenW(section_name->SectionFileName.Buffer) * sizeof(WCHAR), "got %u, %u\n",
361        section_name->SectionFileName.Length, lstrlenW(section_name->SectionFileName.Buffer));
362 
363     memcpy(name, section_name->SectionFileName.Buffer, section_name->SectionFileName.MaximumLength);
364     HeapFree(GetProcessHeap(), 0, buf);
365     return TRUE;
366 }
367 
368 static void test_GetMappedFileName(void)
369 {
370     HMODULE hMod = GetModuleHandleA(NULL);
371     char szMapPath[MAX_PATH], szModPath[MAX_PATH], *szMapBaseName;
372     DWORD ret;
373     char *base;
374     char temp_path[MAX_PATH], file_name[MAX_PATH], map_name[MAX_PATH], device_name[MAX_PATH], drive[3];
375     WCHAR map_nameW[MAX_PATH], nt_map_name[MAX_PATH];
376     HANDLE hfile, hmap;
377     HANDLE current_process;
378 
379     DuplicateHandle( GetCurrentProcess(), GetCurrentProcess(),
380                      GetCurrentProcess(), &current_process, 0, 0, DUPLICATE_SAME_ACCESS );
381 
382     SetLastError(0xdeadbeef);
383     ret = pGetMappedFileNameA(NULL, hMod, szMapPath, sizeof(szMapPath));
384     ok(!ret, "GetMappedFileName should fail\n");
385     ok(GetLastError() == ERROR_INVALID_HANDLE, "expected error=ERROR_INVALID_HANDLE but got %d\n", GetLastError());
386 
387     SetLastError(0xdeadbeef);
388     ret = pGetMappedFileNameA(hpSR, hMod, szMapPath, sizeof(szMapPath));
389     ok(!ret, "GetMappedFileName should fail\n");
390     ok(GetLastError() == ERROR_ACCESS_DENIED, "expected error=ERROR_ACCESS_DENIED but got %d\n", GetLastError());
391 
392     SetLastError( 0xdeadbeef );
393     ret = pGetMappedFileNameA(hpQI, hMod, szMapPath, sizeof(szMapPath));
394     ok( ret || broken(GetLastError() == ERROR_UNEXP_NET_ERR), /* win2k */
395         "GetMappedFileNameA failed with error %u\n", GetLastError() );
396     if (ret)
397     {
398         ok(ret == strlen(szMapPath), "szMapPath=\"%s\" ret=%d\n", szMapPath, ret);
399         ok(szMapPath[0] == '\\', "szMapPath=\"%s\"\n", szMapPath);
400         szMapBaseName = strrchr(szMapPath, '\\'); /* That's close enough for us */
401         ok(szMapBaseName && *szMapBaseName, "szMapPath=\"%s\"\n", szMapPath);
402         if (szMapBaseName)
403         {
404             GetModuleFileNameA(NULL, szModPath, sizeof(szModPath));
405             ok(!strcmp(strrchr(szModPath, '\\'), szMapBaseName),
406                "szModPath=\"%s\" szMapBaseName=\"%s\"\n", szModPath, szMapBaseName);
407         }
408     }
409 
410     GetTempPathA(MAX_PATH, temp_path);
411     GetTempFileNameA(temp_path, "map", 0, file_name);
412 
413     drive[0] = file_name[0];
414     drive[1] = ':';
415     drive[2] = 0;
416     SetLastError(0xdeadbeef);
417     ret = QueryDosDeviceA(drive, device_name, sizeof(device_name));
418     ok(ret, "QueryDosDeviceA error %d\n", GetLastError());
419     trace("%s -> %s\n", drive, device_name);
420 
421     SetLastError(0xdeadbeef);
422     hfile = CreateFileA(file_name, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
423     ok(hfile != INVALID_HANDLE_VALUE, "CreateFileA(%s) error %d\n", file_name, GetLastError());
424     SetFilePointer(hfile, 0x4000, NULL, FILE_BEGIN);
425     SetEndOfFile(hfile);
426 
427     SetLastError(0xdeadbeef);
428     hmap = CreateFileMappingA(hfile, NULL, PAGE_READONLY | SEC_COMMIT, 0, 0, NULL);
429     ok(hmap != 0, "CreateFileMappingA error %d\n", GetLastError());
430 
431     SetLastError(0xdeadbeef);
432     base = MapViewOfFile(hmap, FILE_MAP_READ, 0, 0, 0);
433     ok(base != NULL, "MapViewOfFile error %d\n", GetLastError());
434 
435     SetLastError(0xdeadbeef);
436     ret = pGetMappedFileNameA(GetCurrentProcess(), base, map_name, 0);
437     ok(!ret, "GetMappedFileName should fail\n");
438     ok(GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == ERROR_INSUFFICIENT_BUFFER,
439        "wrong error %d\n", GetLastError());
440 
441     SetLastError(0xdeadbeef);
442     ret = pGetMappedFileNameA(GetCurrentProcess(), base, 0, sizeof(map_name));
443     ok(!ret, "GetMappedFileName should fail\n");
444     ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
445 
446     SetLastError(0xdeadbeef);
447     ret = pGetMappedFileNameA(GetCurrentProcess(), base, map_name, 1);
448     ok(ret == 1, "GetMappedFileName error %d\n", GetLastError());
449     ok(!map_name[0] || broken(map_name[0] == device_name[0]) /* before win2k */, "expected 0, got %c\n", map_name[0]);
450 
451     SetLastError(0xdeadbeef);
452     ret = pGetMappedFileNameA(GetCurrentProcess(), base, map_name, sizeof(map_name));
453     ok(ret, "GetMappedFileName error %d\n", GetLastError());
454     ok(ret > strlen(device_name), "map_name should be longer than device_name\n");
455     ok(memcmp(map_name, device_name, strlen(device_name)) == 0, "map name does not start with a device name: %s\n", map_name);
456 
457     SetLastError(0xdeadbeef);
458     ret = pGetMappedFileNameW(GetCurrentProcess(), base, map_nameW, sizeof(map_nameW)/sizeof(map_nameW[0]));
459     ok(ret, "GetMappedFileNameW error %d\n", GetLastError());
460     ok(ret > strlen(device_name), "map_name should be longer than device_name\n");
461 
462     if (nt_get_mapped_file_name(GetCurrentProcess(), base, nt_map_name, sizeof(nt_map_name)/sizeof(nt_map_name[0])))
463     {
464         ok(memcmp(map_nameW, nt_map_name, lstrlenW(map_nameW)) == 0, "map name does not start with a device name: %s\n", map_name);
465         WideCharToMultiByte(CP_ACP, 0, map_nameW, -1, map_name, MAX_PATH, NULL, NULL);
466         ok(memcmp(map_name, device_name, strlen(device_name)) == 0, "map name does not start with a device name: %s\n", map_name);
467     }
468 
469     SetLastError(0xdeadbeef);
470     ret = pGetMappedFileNameW(current_process, base, map_nameW, sizeof(map_nameW)/sizeof(map_nameW[0]));
471     ok(ret, "GetMappedFileNameW error %d\n", GetLastError());
472     ok(ret > strlen(device_name), "map_name should be longer than device_name\n");
473 
474     if (nt_get_mapped_file_name(current_process, base, nt_map_name, sizeof(nt_map_name)/sizeof(nt_map_name[0])))
475     {
476         ok(memcmp(map_nameW, nt_map_name, lstrlenW(map_nameW)) == 0, "map name does not start with a device name: %s\n", map_name);
477         WideCharToMultiByte(CP_ACP, 0, map_nameW, -1, map_name, MAX_PATH, NULL, NULL);
478         ok(memcmp(map_name, device_name, strlen(device_name)) == 0, "map name does not start with a device name: %s\n", map_name);
479     }
480 
481     SetLastError(0xdeadbeef);
482     ret = pGetMappedFileNameA(GetCurrentProcess(), base + 0x2000, map_name, sizeof(map_name));
483     ok(ret, "GetMappedFileName error %d\n", GetLastError());
484     ok(ret > strlen(device_name), "map_name should be longer than device_name\n");
485     ok(memcmp(map_name, device_name, strlen(device_name)) == 0, "map name does not start with a device name: %s\n", map_name);
486 
487     SetLastError(0xdeadbeef);
488     ret = pGetMappedFileNameA(GetCurrentProcess(), base + 0x4000, map_name, sizeof(map_name));
489     ok(!ret, "GetMappedFileName should fail\n");
490     ok(GetLastError() == ERROR_UNEXP_NET_ERR, "expected ERROR_UNEXP_NET_ERR, got %d\n", GetLastError());
491 
492     SetLastError(0xdeadbeef);
493     ret = pGetMappedFileNameA(GetCurrentProcess(), NULL, map_name, sizeof(map_name));
494     ok(!ret, "GetMappedFileName should fail\n");
495 todo_wine
496     ok(GetLastError() == ERROR_UNEXP_NET_ERR, "expected ERROR_UNEXP_NET_ERR, got %d\n", GetLastError());
497 
498     SetLastError(0xdeadbeef);
499     ret = pGetMappedFileNameA(0, base, map_name, sizeof(map_name));
500     ok(!ret, "GetMappedFileName should fail\n");
501     ok(GetLastError() == ERROR_INVALID_HANDLE, "expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
502 
503     UnmapViewOfFile(base);
504     CloseHandle(hmap);
505     CloseHandle(hfile);
506     DeleteFileA(file_name);
507 
508     SetLastError(0xdeadbeef);
509     hmap = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READONLY | SEC_COMMIT, 0, 4096, NULL);
510     ok(hmap != 0, "CreateFileMappingA error %d\n", GetLastError());
511 
512     SetLastError(0xdeadbeef);
513     base = MapViewOfFile(hmap, FILE_MAP_READ, 0, 0, 0);
514     ok(base != NULL, "MapViewOfFile error %d\n", GetLastError());
515 
516     SetLastError(0xdeadbeef);
517     ret = pGetMappedFileNameA(GetCurrentProcess(), base, map_name, sizeof(map_name));
518     ok(!ret, "GetMappedFileName should fail\n");
519     ok(GetLastError() == ERROR_FILE_INVALID, "expected ERROR_FILE_INVALID, got %d\n", GetLastError());
520 
521     CloseHandle(current_process);
522     UnmapViewOfFile(base);
523     CloseHandle(hmap);
524 }
525 
526 static void test_GetProcessImageFileName(void)
527 {
528     HMODULE hMod = GetModuleHandleA(NULL);
529     char szImgPath[MAX_PATH], szMapPath[MAX_PATH];
530     WCHAR szImgPathW[MAX_PATH];
531     DWORD ret, ret1;
532 
533     if(pGetProcessImageFileNameA == NULL)
534         return;
535 
536     /* This function is available on WinXP+ only */
537     SetLastError(0xdeadbeef);
538     if(!pGetProcessImageFileNameA(hpQI, szImgPath, sizeof(szImgPath)))
539     {
540         if(GetLastError() == ERROR_INVALID_FUNCTION) {
541 	    win_skip("GetProcessImageFileName not implemented\n");
542             return;
543         }
544 
545         if(GetLastError() == 0xdeadbeef)
546 	    todo_wine ok(0, "failed without error code\n");
547 	else
548 	    todo_wine ok(0, "failed with %d\n", GetLastError());
549     }
550 
551     SetLastError(0xdeadbeef);
552     pGetProcessImageFileNameA(NULL, szImgPath, sizeof(szImgPath));
553     ok(GetLastError() == ERROR_INVALID_HANDLE, "expected error=ERROR_INVALID_HANDLE but got %d\n", GetLastError());
554 
555     SetLastError(0xdeadbeef);
556     pGetProcessImageFileNameA(hpSR, szImgPath, sizeof(szImgPath));
557     ok(GetLastError() == ERROR_ACCESS_DENIED, "expected error=ERROR_ACCESS_DENIED but got %d\n", GetLastError());
558 
559     SetLastError(0xdeadbeef);
560     pGetProcessImageFileNameA(hpQI, szImgPath, 0);
561     ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "expected error=ERROR_INSUFFICIENT_BUFFER but got %d\n", GetLastError());
562 
563     ret = pGetProcessImageFileNameA(hpQI, szImgPath, sizeof(szImgPath));
564     ret1 = pGetMappedFileNameA(hpQV, hMod, szMapPath, sizeof(szMapPath));
565     if(ret && ret1)
566     {
567         /* Windows returns 2*strlen-1 */
568         ok(ret >= strlen(szImgPath), "szImgPath=\"%s\" ret=%d\n", szImgPath, ret);
569         ok(!strcmp(szImgPath, szMapPath), "szImgPath=\"%s\" szMapPath=\"%s\"\n", szImgPath, szMapPath);
570     }
571 
572     SetLastError(0xdeadbeef);
573     pGetProcessImageFileNameW(NULL, szImgPathW, sizeof(szImgPathW));
574     ok(GetLastError() == ERROR_INVALID_HANDLE, "expected error=ERROR_INVALID_HANDLE but got %d\n", GetLastError());
575 
576     /* no information about correct buffer size returned: */
577     SetLastError(0xdeadbeef);
578     pGetProcessImageFileNameW(hpQI, szImgPathW, 0);
579     ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "expected error=ERROR_INSUFFICIENT_BUFFER but got %d\n", GetLastError());
580 
581     SetLastError(0xdeadbeef);
582     pGetProcessImageFileNameW(hpQI, NULL, 0);
583     ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "expected error=ERROR_INSUFFICIENT_BUFFER but got %d\n", GetLastError());
584 
585     /* correct call */
586     memset(szImgPathW, 0xff, sizeof(szImgPathW));
587     ret = pGetProcessImageFileNameW(hpQI, szImgPathW, sizeof(szImgPathW)/sizeof(WCHAR));
588     ok(ret > 0, "GetProcessImageFileNameW should have succeeded.\n");
589     ok(szImgPathW[0] == '\\', "GetProcessImageFileNameW should have returned an NT path.\n");
590     ok(lstrlenW(szImgPathW) == ret, "Expected length to be %d, got %d\n", ret, lstrlenW(szImgPathW));
591 
592     /* boundary values of 'size' */
593     SetLastError(0xdeadbeef);
594     pGetProcessImageFileNameW(hpQI, szImgPathW, ret);
595     ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "expected error=ERROR_INSUFFICIENT_BUFFER but got %d\n", GetLastError());
596 
597     memset(szImgPathW, 0xff, sizeof(szImgPathW));
598     ret = pGetProcessImageFileNameW(hpQI, szImgPathW, ret + 1);
599     ok(ret > 0, "GetProcessImageFileNameW should have succeeded.\n");
600     ok(szImgPathW[0] == '\\', "GetProcessImageFileNameW should have returned an NT path.\n");
601     ok(lstrlenW(szImgPathW) == ret, "Expected length to be %d, got %d\n", ret, lstrlenW(szImgPathW));
602 }
603 
604 static void test_GetModuleFileNameEx(void)
605 {
606     HMODULE hMod = GetModuleHandleA(NULL);
607     char szModExPath[MAX_PATH+1], szModPath[MAX_PATH+1];
608     WCHAR buffer[MAX_PATH];
609     DWORD ret;
610 
611     SetLastError(0xdeadbeef);
612     ret = pGetModuleFileNameExA(NULL, hMod, szModExPath, sizeof(szModExPath));
613     ok( !ret, "GetModuleFileNameExA succeeded\n" );
614     ok(GetLastError() == ERROR_INVALID_HANDLE, "expected error=ERROR_INVALID_HANDLE but got %d\n", GetLastError());
615 
616     SetLastError(0xdeadbeef);
617     ret = pGetModuleFileNameExA(hpQI, hMod, szModExPath, sizeof(szModExPath));
618     ok( !ret, "GetModuleFileNameExA succeeded\n" );
619     ok(GetLastError() == ERROR_ACCESS_DENIED, "expected error=ERROR_ACCESS_DENIED but got %d\n", GetLastError());
620 
621     SetLastError(0xdeadbeef);
622     ret = pGetModuleFileNameExA(hpQV, hBad, szModExPath, sizeof(szModExPath));
623     ok( !ret, "GetModuleFileNameExA succeeded\n" );
624     ok(GetLastError() == ERROR_INVALID_HANDLE, "expected error=ERROR_INVALID_HANDLE but got %d\n", GetLastError());
625 
626     ret = pGetModuleFileNameExA(hpQV, NULL, szModExPath, sizeof(szModExPath));
627     if(!ret)
628             return;
629     ok(ret == strlen(szModExPath), "szModExPath=\"%s\" ret=%d\n", szModExPath, ret);
630     GetModuleFileNameA(NULL, szModPath, sizeof(szModPath));
631     ok(!strncmp(szModExPath, szModPath, MAX_PATH),
632        "szModExPath=\"%s\" szModPath=\"%s\"\n", szModExPath, szModPath);
633 
634     SetLastError(0xdeadbeef);
635     memset( szModExPath, 0xcc, sizeof(szModExPath) );
636     ret = pGetModuleFileNameExA(hpQV, NULL, szModExPath, 4 );
637     ok( ret == 4 || ret == strlen(szModExPath), "wrong length %u\n", ret );
638     ok( broken(szModExPath[3]) /*w2kpro*/ || strlen(szModExPath) == 3,
639         "szModExPath=\"%s\" ret=%d\n", szModExPath, ret );
640     ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
641 
642     if (0) /* crashes on Windows 10 */
643     {
644         SetLastError(0xdeadbeef);
645         ret = pGetModuleFileNameExA(hpQV, NULL, szModExPath, 0 );
646         ok( ret == 0, "wrong length %u\n", ret );
647         ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %d\n", GetLastError());
648     }
649 
650     SetLastError(0xdeadbeef);
651     memset( buffer, 0xcc, sizeof(buffer) );
652     ret = pGetModuleFileNameExW(hpQV, NULL, buffer, 4 );
653     ok( ret == 4 || ret == lstrlenW(buffer), "wrong length %u\n", ret );
654     ok( broken(buffer[3]) /*w2kpro*/ || lstrlenW(buffer) == 3,
655         "buffer=%s ret=%d\n", wine_dbgstr_w(buffer), ret );
656     ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
657 
658     if (0) /* crashes on Windows 10 */
659     {
660         SetLastError(0xdeadbeef);
661         buffer[0] = 0xcc;
662         ret = pGetModuleFileNameExW(hpQV, NULL, buffer, 0 );
663         ok( ret == 0, "wrong length %u\n", ret );
664         ok(GetLastError() == 0xdeadbeef, "got error %d\n", GetLastError());
665         ok( buffer[0] == 0xcc, "buffer modified %s\n", wine_dbgstr_w(buffer) );
666     }
667 }
668 
669 static void test_GetModuleBaseName(void)
670 {
671     HMODULE hMod = GetModuleHandleA(NULL);
672     char szModPath[MAX_PATH], szModBaseName[MAX_PATH];
673     DWORD ret;
674 
675     SetLastError(0xdeadbeef);
676     pGetModuleBaseNameA(NULL, hMod, szModBaseName, sizeof(szModBaseName));
677     ok(GetLastError() == ERROR_INVALID_HANDLE, "expected error=ERROR_INVALID_HANDLE but got %d\n", GetLastError());
678 
679     SetLastError(0xdeadbeef);
680     pGetModuleBaseNameA(hpQI, hMod, szModBaseName, sizeof(szModBaseName));
681     ok(GetLastError() == ERROR_ACCESS_DENIED, "expected error=ERROR_ACCESS_DENIED but got %d\n", GetLastError());
682 
683     SetLastError(0xdeadbeef);
684     pGetModuleBaseNameA(hpQV, hBad, szModBaseName, sizeof(szModBaseName));
685     ok(GetLastError() == ERROR_INVALID_HANDLE, "expected error=ERROR_INVALID_HANDLE but got %d\n", GetLastError());
686 
687     ret = pGetModuleBaseNameA(hpQV, NULL, szModBaseName, sizeof(szModBaseName));
688     if(!ret)
689         return;
690     ok(ret == strlen(szModBaseName), "szModBaseName=\"%s\" ret=%d\n", szModBaseName, ret);
691     GetModuleFileNameA(NULL, szModPath, sizeof(szModPath));
692     ok(!strcmp(strrchr(szModPath, '\\') + 1, szModBaseName),
693        "szModPath=\"%s\" szModBaseName=\"%s\"\n", szModPath, szModBaseName);
694 }
695 
696 static void test_ws_functions(void)
697 {
698     PSAPI_WS_WATCH_INFORMATION wswi[4096];
699     ULONG_PTR pages[4096];
700     char *addr;
701     unsigned int i;
702     BOOL ret;
703 
704     SetLastError(0xdeadbeef);
705     pEmptyWorkingSet(NULL);
706     todo_wine ok(GetLastError() == ERROR_INVALID_HANDLE, "expected error=ERROR_INVALID_HANDLE but got %d\n", GetLastError());
707 
708     SetLastError(0xdeadbeef);
709     pEmptyWorkingSet(hpSR);
710     todo_wine ok(GetLastError() == ERROR_ACCESS_DENIED, "expected error=ERROR_ACCESS_DENIED but got %d\n", GetLastError());
711 
712     SetLastError(0xdeadbeef);
713     ret = pEmptyWorkingSet(hpAA);
714     ok(ret == 1, "failed with %d\n", GetLastError());
715 
716     SetLastError( 0xdeadbeef );
717     ret = pInitializeProcessForWsWatch( NULL );
718     todo_wine ok( !ret, "InitializeProcessForWsWatch succeeded\n" );
719     if (!ret)
720     {
721         if (GetLastError() == ERROR_INVALID_FUNCTION)  /* not supported on xp in wow64 mode */
722         {
723             trace( "InitializeProcessForWsWatch not supported\n" );
724             return;
725         }
726         ok( GetLastError() == ERROR_INVALID_HANDLE, "wrong error %u\n", GetLastError() );
727     }
728     SetLastError(0xdeadbeef);
729     ret = pInitializeProcessForWsWatch(hpAA);
730     ok(ret == 1, "failed with %d\n", GetLastError());
731 
732     addr = VirtualAlloc(NULL, 1, MEM_COMMIT, PAGE_READWRITE);
733     if(!addr)
734         return;
735 
736     *addr = 0; /* make sure it's paged in (needed on wow64) */
737     if(!VirtualLock(addr, 1))
738     {
739         trace("locking failed (error=%d) - skipping test\n", GetLastError());
740         goto free_page;
741     }
742 
743     SetLastError(0xdeadbeef);
744     ret = pQueryWorkingSet(hpQI, pages, 4096 * sizeof(ULONG_PTR));
745     todo_wine ok(ret == 1, "failed with %d\n", GetLastError());
746     if(ret == 1)
747     {
748        for(i = 0; i < pages[0]; i++)
749            if((pages[i+1] & ~0xfffL) == (ULONG_PTR)addr)
750 	   {
751 	       todo_wine ok(ret == 1, "QueryWorkingSet found our page\n");
752 	       goto test_gwsc;
753 	   }
754 
755        todo_wine ok(0, "QueryWorkingSet didn't find our page\n");
756     }
757 
758 test_gwsc:
759     SetLastError(0xdeadbeef);
760     ret = pGetWsChanges(hpQI, wswi, sizeof(wswi));
761     todo_wine ok(ret == 1, "failed with %d\n", GetLastError());
762     if(ret == 1)
763     {
764         for(i = 0; wswi[i].FaultingVa; i++)
765 	    if(((ULONG_PTR)wswi[i].FaultingVa & ~0xfffL) == (ULONG_PTR)addr)
766 	    {
767 	        todo_wine ok(ret == 1, "GetWsChanges found our page\n");
768 		goto free_page;
769 	    }
770 
771 	todo_wine ok(0, "GetWsChanges didn't find our page\n");
772     }
773 
774 free_page:
775     VirtualFree(addr, 0, MEM_RELEASE);
776 }
777 
778 START_TEST(psapi_main)
779 {
780     HMODULE hpsapi = LoadLibraryA("psapi.dll");
781 
782     if(!hpsapi)
783     {
784         win_skip("Could not load psapi.dll\n");
785         return;
786     }
787 
788     if(InitFunctionPtrs(hpsapi))
789     {
790         DWORD pid = GetCurrentProcessId();
791 
792     hpSR = OpenProcess(STANDARD_RIGHTS_REQUIRED, FALSE, pid);
793     hpQI = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
794     hpVR = OpenProcess(PROCESS_VM_READ, FALSE, pid);
795     hpQV = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
796     hpAA = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
797 
798     if(hpSR && hpQI && hpVR && hpQV && hpAA)
799         {
800 	    test_EnumProcesses();
801 	    test_EnumProcessModules();
802 	    test_GetModuleInformation();
803             test_GetPerformanceInfo();
804 	    test_GetProcessMemoryInfo();
805             test_GetMappedFileName();
806             test_GetProcessImageFileName();
807             test_GetModuleFileNameEx();
808             test_GetModuleBaseName();
809 	    test_ws_functions();
810 	}
811 	CloseHandle(hpSR);
812 	CloseHandle(hpQI);
813 	CloseHandle(hpVR);
814 	CloseHandle(hpQV);
815 	CloseHandle(hpAA);
816     }
817 
818     FreeLibrary(hpsapi);
819 }
820