Reactos
1/*
2 * COPYRIGHT: See COPYING in the top level directory
3 * LICENSE: See LGPL.txt in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: reactos/lib/psapi/misc/win32.c
6 * PURPOSE: Win32 interfaces for PSAPI
7 * PROGRAMMER: KJK::Hyperion <noog@libero.it>
8 * Thomas Weidenmueller <w3seek@reactos.com>
9 * Pierre Schweitzer <pierre@reactos.org>
10 * UPDATE HISTORY:
11 * 10/06/2002: Created
12 */
13
14#include <stdarg.h>
15
16#define WIN32_NO_STATUS
17#include <windef.h>
18#include <winbase.h>
19#include <winnls.h>
20#define NTOS_MODE_USER
21#include <ndk/exfuncs.h>
22#include <ndk/mmfuncs.h>
23#include <ndk/psfuncs.h>
24#include <ndk/rtlfuncs.h>
25
26#include <psapi.h>
27
28#include <pseh/pseh2.h>
29
30#define NDEBUG
31#include <debug.h>
32
33#define MAX_MODULES 0x2710 // Matches 10.000 modules
34#define INIT_MEMORY_SIZE 0x1000 // Matches 4kB
35
36/* INTERNAL *******************************************************************/
37
38/*
39 * @implemented
40 */
41static BOOL NTAPI
42FindDeviceDriver(IN PVOID ImageBase,
43 OUT PRTL_PROCESS_MODULE_INFORMATION MatchingModule)
44{
45 NTSTATUS Status;
46 DWORD i, RequiredSize;
47 PRTL_PROCESS_MODULES Information;
48 RTL_PROCESS_MODULE_INFORMATION Module;
49 /* By default, to prevent too many reallocations, we already make room for 4 modules */
50 DWORD Size = sizeof(RTL_PROCESS_MODULES) + 3 * sizeof(RTL_PROCESS_MODULE_INFORMATION);
51
52 while (TRUE)
53 {
54 /* Allocate a buffer to hold modules information */
55 Information = LocalAlloc(LMEM_FIXED, Size);
56 if (!Information)
57 {
58 SetLastError(ERROR_NO_SYSTEM_RESOURCES);
59 return FALSE;
60 }
61
62 /* Query information */
63 Status = NtQuerySystemInformation(SystemModuleInformation, Information, Size, &RequiredSize);
64 if (!NT_SUCCESS(Status))
65 {
66 /* Free the current buffer */
67 LocalFree(Information);
68
69 /* If it was not a length mismatch (ie, buffer too small), just leave */
70 if (Status != STATUS_INFO_LENGTH_MISMATCH)
71 {
72 SetLastError(RtlNtStatusToDosError(Status));
73 return FALSE;
74 }
75
76 /* Try again with the required size */
77 Size = RequiredSize;
78 continue;
79 }
80
81 /* No modules returned? Leave */
82 if (Information->NumberOfModules == 0)
83 {
84 break;
85 }
86
87 /* Try to find which module matches the base address given */
88 for (i = 0; i < Information->NumberOfModules; ++i)
89 {
90 Module = Information->Modules[i];
91 if (Module.ImageBase == ImageBase)
92 {
93 /* Copy the matching module and leave */
94 memcpy(MatchingModule, &Module, sizeof(Module));
95 LocalFree(Information);
96 return TRUE;
97 }
98 }
99
100 /* If we arrive here, it means we were not able to find matching base address */
101 break;
102 }
103
104 /* Release and leave */
105 LocalFree(Information);
106 SetLastError(ERROR_INVALID_HANDLE);
107
108 return FALSE;
109}
110
111/*
112 * @implemented
113 */
114static BOOL NTAPI
115FindModule(IN HANDLE hProcess,
116 IN HMODULE hModule OPTIONAL,
117 OUT PLDR_DATA_TABLE_ENTRY Module)
118{
119 DWORD Count;
120 NTSTATUS Status;
121 PPEB_LDR_DATA LoaderData;
122 PLIST_ENTRY ListHead, ListEntry;
123 PROCESS_BASIC_INFORMATION ProcInfo;
124
125 /* Query the process information to get its PEB address */
126 Status = NtQueryInformationProcess(hProcess, ProcessBasicInformation, &ProcInfo, sizeof(ProcInfo), NULL);
127 if (!NT_SUCCESS(Status))
128 {
129 SetLastError(RtlNtStatusToDosError(Status));
130 return FALSE;
131 }
132
133 /* If no module was provided, get base as module */
134 if (hModule == NULL)
135 {
136 if (!ReadProcessMemory(hProcess, &ProcInfo.PebBaseAddress->ImageBaseAddress, &hModule, sizeof(hModule), NULL))
137 {
138 return FALSE;
139 }
140 }
141
142 /* Read loader data address from PEB */
143 if (!ReadProcessMemory(hProcess, &ProcInfo.PebBaseAddress->Ldr, &LoaderData, sizeof(LoaderData), NULL))
144 {
145 return FALSE;
146 }
147
148 if (LoaderData == NULL)
149 {
150 SetLastError(ERROR_INVALID_HANDLE);
151 return FALSE;
152 }
153
154 /* Store list head address */
155 ListHead = &(LoaderData->InMemoryOrderModuleList);
156
157 /* Read first element in the modules list */
158 if (!ReadProcessMemory(hProcess,
159 &(LoaderData->InMemoryOrderModuleList.Flink),
160 &ListEntry,
161 sizeof(ListEntry),
162 NULL))
163 {
164 return FALSE;
165 }
166
167 Count = 0;
168
169 /* Loop on the modules */
170 while (ListEntry != ListHead)
171 {
172 /* Load module data */
173 if (!ReadProcessMemory(hProcess,
174 CONTAINING_RECORD(ListEntry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks),
175 Module,
176 sizeof(*Module),
177 NULL))
178 {
179 return FALSE;
180 }
181
182 /* Does that match the module we're looking for? */
183 if (Module->DllBase == hModule)
184 {
185 return TRUE;
186 }
187
188 ++Count;
189 if (Count > MAX_MODULES)
190 {
191 break;
192 }
193
194 /* Get to next listed module */
195 ListEntry = Module->InMemoryOrderLinks.Flink;
196 }
197
198 SetLastError(ERROR_INVALID_HANDLE);
199 return FALSE;
200}
201
202typedef struct _INTERNAL_ENUM_PAGE_FILES_CONTEXT
203{
204 LPVOID lpContext;
205 PENUM_PAGE_FILE_CALLBACKA pCallbackRoutine;
206 DWORD dwErrCode;
207} INTERNAL_ENUM_PAGE_FILES_CONTEXT, *PINTERNAL_ENUM_PAGE_FILES_CONTEXT;
208
209/*
210 * @implemented
211 */
212static BOOL CALLBACK
213CallBackConvertToAscii(LPVOID pContext,
214 PENUM_PAGE_FILE_INFORMATION pPageFileInfo,
215 LPCWSTR lpFilename)
216{
217 BOOL Ret;
218 SIZE_T Len;
219 LPSTR AnsiFileName;
220 PINTERNAL_ENUM_PAGE_FILES_CONTEXT Context = (PINTERNAL_ENUM_PAGE_FILES_CONTEXT)pContext;
221
222 Len = wcslen(lpFilename);
223
224 /* Alloc space for the ANSI string */
225 AnsiFileName = LocalAlloc(LMEM_FIXED, (Len * sizeof(CHAR)) + sizeof(ANSI_NULL));
226 if (AnsiFileName == NULL)
227 {
228 Context->dwErrCode = RtlNtStatusToDosError(STATUS_INSUFFICIENT_RESOURCES);
229 return FALSE;
230 }
231
232 /* Convert string to ANSI */
233 if (WideCharToMultiByte(CP_ACP, 0, lpFilename, -1, AnsiFileName, (Len * sizeof(CHAR)) + sizeof(ANSI_NULL), NULL, NULL) == 0)
234 {
235 Context->dwErrCode = GetLastError();
236 LocalFree(AnsiFileName);
237 return FALSE;
238 }
239
240 /* And finally call "real" callback */
241 Ret = Context->pCallbackRoutine(Context->lpContext, pPageFileInfo, AnsiFileName);
242 LocalFree(AnsiFileName);
243
244 return Ret;
245}
246
247/*
248 * @implemented
249 */
250BOOL
251WINAPI
252EmptyWorkingSet(HANDLE hProcess)
253{
254 SYSTEM_INFO SystemInfo;
255 QUOTA_LIMITS QuotaLimits;
256 NTSTATUS Status;
257
258 GetSystemInfo(&SystemInfo);
259
260 /* Query the working set */
261 Status = NtQueryInformationProcess(hProcess,
262 ProcessQuotaLimits,
263 &QuotaLimits,
264 sizeof(QuotaLimits),
265 NULL);
266
267 if (!NT_SUCCESS(Status))
268 {
269 SetLastError(RtlNtStatusToDosError(Status));
270 return FALSE;
271 }
272
273 /* Empty the working set */
274 QuotaLimits.MinimumWorkingSetSize = -1;
275 QuotaLimits.MaximumWorkingSetSize = -1;
276
277 /* Set the working set */
278 Status = NtSetInformationProcess(hProcess,
279 ProcessQuotaLimits,
280 &QuotaLimits,
281 sizeof(QuotaLimits));
282 if (!NT_SUCCESS(Status) && Status != STATUS_PRIVILEGE_NOT_HELD)
283 {
284 SetLastError(RtlNtStatusToDosError(Status));
285 return FALSE;
286 }
287
288 return TRUE;
289}
290
291
292/*
293 * @implemented
294 */
295BOOL
296WINAPI
297EnumDeviceDrivers(LPVOID *lpImageBase,
298 DWORD cb,
299 LPDWORD lpcbNeeded)
300{
301 NTSTATUS Status;
302 DWORD NewSize, Count;
303 PRTL_PROCESS_MODULES Information;
304 /* By default, to prevent too many reallocations, we already make room for 4 modules */
305 DWORD Size = sizeof(RTL_PROCESS_MODULES) + 3 * sizeof(RTL_PROCESS_MODULE_INFORMATION);
306
307 do
308 {
309 /* Allocate a buffer to hold modules information */
310 Information = LocalAlloc(LMEM_FIXED, Size);
311 if (!Information)
312 {
313 SetLastError(ERROR_NO_SYSTEM_RESOURCES);
314 return FALSE;
315 }
316
317 /* Query information */
318 Status = NtQuerySystemInformation(SystemModuleInformation, Information, Size, &Count);
319 /* In case of an error */
320 if (!NT_SUCCESS(Status))
321 {
322 /* Save the amount of output modules */
323 NewSize = Information->NumberOfModules;
324 /* And free buffer */
325 LocalFree(Information);
326
327 /* If it was not a length mismatch (ie, buffer too small), just leave */
328 if (Status != STATUS_INFO_LENGTH_MISMATCH)
329 {
330 SetLastError(RtlNtStatusToDosError(Status));
331 return FALSE;
332 }
333
334 /* Compute new size length */
335 ASSERT(Size >= sizeof(RTL_PROCESS_MODULES));
336 NewSize *= sizeof(RTL_PROCESS_MODULE_INFORMATION);
337 NewSize += sizeof(ULONG);
338 ASSERT(NewSize >= sizeof(RTL_PROCESS_MODULES));
339 /* Check whether it is really bigger - otherwise, leave */
340 if (NewSize < Size)
341 {
342 ASSERT(NewSize > Size);
343 SetLastError(RtlNtStatusToDosError(STATUS_INFO_LENGTH_MISMATCH));
344 return FALSE;
345 }
346
347 /* Loop again with that new buffer */
348 Size = NewSize;
349 continue;
350 }
351
352 /* End of allocation loop */
353 break;
354 } while (TRUE);
355
356 _SEH2_TRY
357 {
358 for (Count = 0; Count < Information->NumberOfModules && Count < cb / sizeof(LPVOID); ++Count)
359 {
360 lpImageBase[Count] = Information->Modules[Count].ImageBase;
361 }
362
363 *lpcbNeeded = Information->NumberOfModules * sizeof(LPVOID);
364 }
365 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
366 {
367 SetLastError(RtlNtStatusToDosError(_SEH2_GetExceptionCode()));
368 _SEH2_YIELD(return FALSE);
369 }
370 _SEH2_END;
371
372 return TRUE;
373}
374
375
376/*
377 * @implemented
378 */
379BOOL
380WINAPI
381EnumProcesses(DWORD *lpidProcess,
382 DWORD cb,
383 LPDWORD lpcbNeeded)
384{
385 NTSTATUS Status;
386 DWORD Size = MAXSHORT, Count;
387 PSYSTEM_PROCESS_INFORMATION ProcInfo;
388 PSYSTEM_PROCESS_INFORMATION ProcInfoArray;
389
390 /* First of all, query all the processes */
391 do
392 {
393 ProcInfoArray = LocalAlloc(LMEM_FIXED, Size);
394 if (ProcInfoArray == NULL)
395 {
396 return FALSE;
397 }
398
399 Status = NtQuerySystemInformation(SystemProcessInformation, ProcInfoArray, Size, NULL);
400 if (Status == STATUS_INFO_LENGTH_MISMATCH)
401 {
402 LocalFree(ProcInfoArray);
403 Size += MAXSHORT;
404 continue;
405 }
406
407 break;
408 }
409 while (TRUE);
410
411 if (!NT_SUCCESS(Status))
412 {
413 LocalFree(ProcInfoArray);
414 SetLastError(RtlNtStatusToDosError(Status));
415 return FALSE;
416 }
417
418 /* Then, loop to output data */
419 Count = 0;
420 ProcInfo = ProcInfoArray;
421
422 _SEH2_TRY
423 {
424 do
425 {
426 /* It may sound weird, but actually MS only updated Count on
427 * successful write. So, it cannot measure the amount of space needed!
428 * This is really tricky.
429 */
430 if (Count < cb / sizeof(DWORD))
431 {
432 lpidProcess[Count] = HandleToUlong(ProcInfo->UniqueProcessId);
433 Count++;
434 }
435
436 if (ProcInfo->NextEntryOffset == 0)
437 {
438 break;
439 }
440
441 ProcInfo = (PSYSTEM_PROCESS_INFORMATION)((ULONG_PTR)ProcInfo + ProcInfo->NextEntryOffset);
442 }
443 while (TRUE);
444
445 *lpcbNeeded = Count * sizeof(DWORD);
446 }
447 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
448 {
449 SetLastError(RtlNtStatusToDosError(_SEH2_GetExceptionCode()));
450 LocalFree(ProcInfoArray);
451 _SEH2_YIELD(return FALSE);
452 }
453 _SEH2_END;
454
455 LocalFree(ProcInfoArray);
456 return TRUE;
457}
458
459
460/*
461 * @implemented
462 */
463BOOL
464WINAPI
465EnumProcessModules(HANDLE hProcess,
466 HMODULE *lphModule,
467 DWORD cb,
468 LPDWORD lpcbNeeded)
469{
470 NTSTATUS Status;
471 DWORD NbOfModules, Count;
472 PPEB_LDR_DATA LoaderData;
473 PLIST_ENTRY ListHead, ListEntry;
474 PROCESS_BASIC_INFORMATION ProcInfo;
475 LDR_DATA_TABLE_ENTRY CurrentModule;
476
477 /* Query the process information to get its PEB address */
478 Status = NtQueryInformationProcess(hProcess, ProcessBasicInformation, &ProcInfo, sizeof(ProcInfo), NULL);
479 if (!NT_SUCCESS(Status))
480 {
481 SetLastError(RtlNtStatusToDosError(Status));
482 return FALSE;
483 }
484
485 if (ProcInfo.PebBaseAddress == NULL)
486 {
487 SetLastError(RtlNtStatusToDosError(STATUS_PARTIAL_COPY));
488 return FALSE;
489 }
490
491 /* Read loader data address from PEB */
492 if (!ReadProcessMemory(hProcess, &ProcInfo.PebBaseAddress->Ldr, &LoaderData, sizeof(LoaderData), NULL))
493 {
494 return FALSE;
495 }
496
497 /* Store list head address */
498 ListHead = &LoaderData->InLoadOrderModuleList;
499
500 /* Read first element in the modules list */
501 if (!ReadProcessMemory(hProcess, &LoaderData->InLoadOrderModuleList.Flink, &ListEntry, sizeof(ListEntry), NULL))
502 {
503 return FALSE;
504 }
505
506 NbOfModules = cb / sizeof(HMODULE);
507 Count = 0;
508
509 /* Loop on the modules */
510 while (ListEntry != ListHead)
511 {
512 /* Load module data */
513 if (!ReadProcessMemory(hProcess,
514 CONTAINING_RECORD(ListEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks),
515 &CurrentModule,
516 sizeof(CurrentModule),
517 NULL))
518 {
519 return FALSE;
520 }
521
522 /* Check if we can output module, do it if so */
523 if (Count < NbOfModules)
524 {
525 _SEH2_TRY
526 {
527 lphModule[Count] = CurrentModule.DllBase;
528 }
529 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
530 {
531 SetLastError(RtlNtStatusToDosError(_SEH2_GetExceptionCode()));
532 _SEH2_YIELD(return FALSE);
533 }
534 _SEH2_END;
535 }
536
537 ++Count;
538 if (Count > MAX_MODULES)
539 {
540 SetLastError(ERROR_INVALID_HANDLE);
541 return FALSE;
542 }
543
544 /* Get to next listed module */
545 ListEntry = CurrentModule.InLoadOrderLinks.Flink;
546 }
547
548 _SEH2_TRY
549 {
550 *lpcbNeeded = Count * sizeof(HMODULE);
551 }
552 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
553 {
554 SetLastError(RtlNtStatusToDosError(_SEH2_GetExceptionCode()));
555 _SEH2_YIELD(return FALSE);
556 }
557 _SEH2_END;
558
559 return TRUE;
560}
561
562
563/*
564 * @implemented
565 */
566DWORD
567WINAPI
568GetDeviceDriverBaseNameA(LPVOID ImageBase,
569 LPSTR lpBaseName,
570 DWORD nSize)
571{
572 SIZE_T Len, LenWithNull;
573 RTL_PROCESS_MODULE_INFORMATION Module;
574
575 /* Get the associated device driver to the base address */
576 if (!FindDeviceDriver(ImageBase, &Module))
577 {
578 return 0;
579 }
580
581 /* And copy as much as possible to output buffer.
582 * Try to add 1 to the len, to copy the null char as well.
583 */
584 Len =
585 LenWithNull = strlen(&Module.FullPathName[Module.OffsetToFileName]) + 1;
586 if (Len > nSize)
587 {
588 Len = nSize;
589 }
590
591 memcpy(lpBaseName, &Module.FullPathName[Module.OffsetToFileName], Len);
592 /* In case we copied null char, remove it from final len */
593 if (Len == LenWithNull)
594 {
595 --Len;
596 }
597
598 return Len;
599}
600
601
602/*
603 * @implemented
604 */
605DWORD
606WINAPI
607GetDeviceDriverFileNameA(LPVOID ImageBase,
608 LPSTR lpFilename,
609 DWORD nSize)
610{
611 SIZE_T Len, LenWithNull;
612 RTL_PROCESS_MODULE_INFORMATION Module;
613
614 /* Get the associated device driver to the base address */
615 if (!FindDeviceDriver(ImageBase, &Module))
616 {
617 return 0;
618 }
619
620 /* And copy as much as possible to output buffer.
621 * Try to add 1 to the len, to copy the null char as well.
622 */
623 Len =
624 LenWithNull = strlen(Module.FullPathName) + 1;
625 if (Len > nSize)
626 {
627 Len = nSize;
628 }
629
630 memcpy(lpFilename, Module.FullPathName, Len);
631 /* In case we copied null char, remove it from final len */
632 if (Len == LenWithNull)
633 {
634 --Len;
635 }
636
637 return Len;
638}
639
640
641/*
642 * @implemented
643 */
644DWORD
645WINAPI
646GetDeviceDriverBaseNameW(LPVOID ImageBase,
647 LPWSTR lpBaseName,
648 DWORD nSize)
649{
650 DWORD Len;
651 LPSTR BaseName;
652
653 /* Allocate internal buffer for conversion */
654 BaseName = LocalAlloc(LMEM_FIXED, nSize);
655 if (BaseName == 0)
656 {
657 return 0;
658 }
659
660 /* Call A API */
661 Len = GetDeviceDriverBaseNameA(ImageBase, BaseName, nSize);
662 if (Len == 0)
663 {
664 LocalFree(BaseName);
665 return 0;
666 }
667
668 /* And convert output */
669 if (MultiByteToWideChar(CP_ACP, 0, BaseName, (Len < nSize) ? Len + 1 : Len, lpBaseName, nSize) == 0)
670 {
671 LocalFree(BaseName);
672 return 0;
673 }
674
675 LocalFree(BaseName);
676 return Len;
677}
678
679
680/*
681 * @implemented
682 */
683DWORD
684WINAPI
685GetDeviceDriverFileNameW(LPVOID ImageBase,
686 LPWSTR lpFilename,
687 DWORD nSize)
688{
689 DWORD Len;
690 LPSTR FileName;
691
692 /* Allocate internal buffer for conversion */
693 FileName = LocalAlloc(LMEM_FIXED, nSize);
694 if (FileName == 0)
695 {
696 return 0;
697 }
698
699 /* Call A API */
700 Len = GetDeviceDriverFileNameA(ImageBase, FileName, nSize);
701 if (Len == 0)
702 {
703 LocalFree(FileName);
704 return 0;
705 }
706
707 /* And convert output */
708 if (MultiByteToWideChar(CP_ACP, 0, FileName, (Len < nSize) ? Len + 1 : Len, lpFilename, nSize) == 0)
709 {
710 LocalFree(FileName);
711 return 0;
712 }
713
714 LocalFree(FileName);
715 return Len;
716}
717
718
719/*
720 * @implemented
721 */
722DWORD
723WINAPI
724GetMappedFileNameA(HANDLE hProcess,
725 LPVOID lpv,
726 LPSTR lpFilename,
727 DWORD nSize)
728{
729 DWORD Len;
730 LPWSTR FileName;
731
732 DPRINT("GetMappedFileNameA(%p, %p, %p, %lu)\n", hProcess, lpv, lpFilename, nSize);
733
734 /* Allocate internal buffer for conversion */
735 FileName = LocalAlloc(LMEM_FIXED, nSize * sizeof(WCHAR));
736 if (FileName == NULL)
737 {
738 return 0;
739 }
740
741 /* Call W API */
742 Len = GetMappedFileNameW(hProcess, lpv, FileName, nSize);
743
744 /* And convert output */
745 if (WideCharToMultiByte(CP_ACP, 0, FileName, (Len < nSize) ? Len + 1 : Len, lpFilename, nSize, NULL, NULL) == 0)
746 {
747 Len = 0;
748 }
749
750 LocalFree(FileName);
751 return Len;
752}
753
754
755/*
756 * @implemented
757 */
758DWORD
759WINAPI
760GetMappedFileNameW(HANDLE hProcess,
761 LPVOID lpv,
762 LPWSTR lpFilename,
763 DWORD nSize)
764{
765 DWORD Len;
766 SIZE_T OutSize;
767 NTSTATUS Status;
768 struct
769 {
770 MEMORY_SECTION_NAME;
771 WCHAR CharBuffer[MAX_PATH];
772 } SectionName;
773
774 DPRINT("GetMappedFileNameW(%p, %p, %p, %lu)\n", hProcess, lpv, lpFilename, nSize);
775
776 /* If no buffer, no need to keep going on */
777 if (nSize == 0)
778 {
779 SetLastError(ERROR_INSUFFICIENT_BUFFER);
780 return 0;
781 }
782
783 /* Query section name */
784 Status = NtQueryVirtualMemory(hProcess, lpv, MemorySectionName,
785 &SectionName, sizeof(SectionName), &OutSize);
786 if (!NT_SUCCESS(Status))
787 {
788 SetLastError(RtlNtStatusToDosError(Status));
789 return 0;
790 }
791
792 /* Prepare to copy file name */
793 Len =
794 OutSize = SectionName.SectionFileName.Length / sizeof(WCHAR);
795 if (OutSize + 1 > nSize)
796 {
797 Len = nSize - 1;
798 OutSize = nSize;
799 SetLastError(ERROR_INSUFFICIENT_BUFFER);
800 }
801 else
802 {
803 SetLastError(ERROR_SUCCESS);
804 }
805
806 /* Copy, zero and return */
807 memcpy(lpFilename, SectionName.SectionFileName.Buffer, Len * sizeof(WCHAR));
808 lpFilename[Len] = 0;
809
810 return OutSize;
811}
812
813
814/*
815 * @implemented
816 */
817DWORD
818WINAPI
819GetModuleBaseNameA(HANDLE hProcess,
820 HMODULE hModule,
821 LPSTR lpBaseName,
822 DWORD nSize)
823{
824 DWORD Len;
825 PWSTR BaseName;
826
827 /* Allocate internal buffer for conversion */
828 BaseName = LocalAlloc(LMEM_FIXED, nSize * sizeof(WCHAR));
829 if (BaseName == NULL)
830 {
831 return 0;
832 }
833
834 /* Call W API */
835 Len = GetModuleBaseNameW(hProcess, hModule, BaseName, nSize);
836 /* And convert output */
837 if (WideCharToMultiByte(CP_ACP, 0, BaseName, (Len < nSize) ? Len + 1 : Len, lpBaseName, nSize, NULL, NULL) == 0)
838 {
839 Len = 0;
840 }
841
842 LocalFree(BaseName);
843
844 return Len;
845}
846
847
848/*
849 * @implemented
850 */
851DWORD
852WINAPI
853GetModuleBaseNameW(HANDLE hProcess,
854 HMODULE hModule,
855 LPWSTR lpBaseName,
856 DWORD nSize)
857{
858 DWORD Len;
859 LDR_DATA_TABLE_ENTRY Module;
860
861 /* Get the matching module */
862 if (!FindModule(hProcess, hModule, &Module))
863 {
864 return 0;
865 }
866
867 /* Get the maximum len we have/can write in given size */
868 Len = Module.BaseDllName.Length + sizeof(UNICODE_NULL);
869 if (nSize * sizeof(WCHAR) < Len)
870 {
871 Len = nSize * sizeof(WCHAR);
872 }
873
874 /* Read string */
875 if (!ReadProcessMemory(hProcess, (&Module.BaseDllName)->Buffer, lpBaseName, Len, NULL))
876 {
877 return 0;
878 }
879
880 /* If we are at the end of the string, prepare to override to nullify string */
881 if (Len == Module.BaseDllName.Length + sizeof(UNICODE_NULL))
882 {
883 Len -= sizeof(UNICODE_NULL);
884 }
885
886 /* Nullify at the end if needed */
887 if (Len >= nSize * sizeof(WCHAR))
888 {
889 if (nSize)
890 {
891 ASSERT(nSize >= sizeof(UNICODE_NULL));
892 lpBaseName[nSize - 1] = UNICODE_NULL;
893 }
894 }
895 /* Otherwise, nullify at last written char */
896 else
897 {
898 ASSERT(Len + sizeof(UNICODE_NULL) <= nSize * sizeof(WCHAR));
899 lpBaseName[Len / sizeof(WCHAR)] = UNICODE_NULL;
900 }
901
902 return Len / sizeof(WCHAR);
903}
904
905
906/*
907 * @implemented
908 */
909DWORD
910WINAPI
911GetModuleFileNameExA(HANDLE hProcess,
912 HMODULE hModule,
913 LPSTR lpFilename,
914 DWORD nSize)
915{
916 DWORD Len;
917 PWSTR Filename;
918
919 /* Allocate internal buffer for conversion */
920 Filename = LocalAlloc(LMEM_FIXED, nSize * sizeof(WCHAR));
921 if (Filename == NULL)
922 {
923 return 0;
924 }
925
926 /* Call W API */
927 Len = GetModuleFileNameExW(hProcess, hModule, Filename, nSize);
928 /* And convert output */
929 if (WideCharToMultiByte(CP_ACP, 0, Filename, (Len < nSize) ? Len + 1 : Len, lpFilename, nSize, NULL, NULL) == 0)
930 {
931 Len = 0;
932 }
933
934 LocalFree(Filename);
935
936 return Len;
937}
938
939
940/*
941 * @implemented
942 */
943DWORD
944WINAPI
945GetModuleFileNameExW(HANDLE hProcess,
946 HMODULE hModule,
947 LPWSTR lpFilename,
948 DWORD nSize)
949{
950 DWORD Len;
951 LDR_DATA_TABLE_ENTRY Module;
952
953 /* Get the matching module */
954 if (!FindModule(hProcess, hModule, &Module))
955 {
956 return 0;
957 }
958
959 /* Get the maximum len we have/can write in given size */
960 Len = Module.FullDllName.Length + sizeof(UNICODE_NULL);
961 if (nSize * sizeof(WCHAR) < Len)
962 {
963 Len = nSize * sizeof(WCHAR);
964 }
965
966 /* Read string */
967 if (!ReadProcessMemory(hProcess, (&Module.FullDllName)->Buffer, lpFilename, Len, NULL))
968 {
969 return 0;
970 }
971
972 /* If we are at the end of the string, prepare to override to nullify string */
973 if (Len == Module.FullDllName.Length + sizeof(UNICODE_NULL))
974 {
975 Len -= sizeof(UNICODE_NULL);
976 }
977
978 /* Nullify at the end if needed */
979 if (Len >= nSize * sizeof(WCHAR))
980 {
981 if (nSize)
982 {
983 ASSERT(nSize >= sizeof(UNICODE_NULL));
984 lpFilename[nSize - 1] = UNICODE_NULL;
985 }
986 }
987 /* Otherwise, nullify at last written char */
988 else
989 {
990 ASSERT(Len + sizeof(UNICODE_NULL) <= nSize * sizeof(WCHAR));
991 lpFilename[Len / sizeof(WCHAR)] = UNICODE_NULL;
992 }
993
994 return Len / sizeof(WCHAR);
995}
996
997
998/*
999 * @implemented
1000 */
1001BOOL
1002WINAPI
1003GetModuleInformation(HANDLE hProcess,
1004 HMODULE hModule,
1005 LPMODULEINFO lpmodinfo,
1006 DWORD cb)
1007{
1008 MODULEINFO LocalInfo;
1009 LDR_DATA_TABLE_ENTRY Module;
1010
1011 /* Check output size */
1012 if (cb < sizeof(MODULEINFO))
1013 {
1014 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1015 return FALSE;
1016 }
1017
1018 /* Get the matching module */
1019 if (!FindModule(hProcess, hModule, &Module))
1020 {
1021 return FALSE;
1022 }
1023
1024 /* Get a local copy first, to check for valid pointer once */
1025 LocalInfo.lpBaseOfDll = hModule;
1026 LocalInfo.SizeOfImage = Module.SizeOfImage;
1027 LocalInfo.EntryPoint = Module.EntryPoint;
1028
1029 /* Attempt to copy to output */
1030 _SEH2_TRY
1031 {
1032 memcpy(lpmodinfo, &LocalInfo, sizeof(LocalInfo));
1033 }
1034 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1035 {
1036 SetLastError(RtlNtStatusToDosError(_SEH2_GetExceptionCode()));
1037 _SEH2_YIELD(return FALSE);
1038 }
1039 _SEH2_END;
1040
1041 return TRUE;
1042}
1043
1044
1045/*
1046 * @implemented
1047 */
1048BOOL
1049WINAPI
1050InitializeProcessForWsWatch(HANDLE hProcess)
1051{
1052 NTSTATUS Status;
1053
1054 /* Simply forward the call */
1055 Status = NtSetInformationProcess(hProcess,
1056 ProcessWorkingSetWatch,
1057 NULL,
1058 0);
1059 /* In case the function returns this, MS considers the call as a success */
1060 if (NT_SUCCESS(Status) || Status == STATUS_PORT_ALREADY_SET || Status == STATUS_ACCESS_DENIED)
1061 {
1062 return TRUE;
1063 }
1064
1065 SetLastError(RtlNtStatusToDosError(Status));
1066 return FALSE;
1067}
1068
1069
1070/*
1071 * @implemented
1072 */
1073BOOL
1074WINAPI
1075GetWsChanges(HANDLE hProcess,
1076 PPSAPI_WS_WATCH_INFORMATION lpWatchInfo,
1077 DWORD cb)
1078{
1079 NTSTATUS Status;
1080
1081 /* Simply forward the call */
1082 Status = NtQueryInformationProcess(hProcess,
1083 ProcessWorkingSetWatch,
1084 lpWatchInfo,
1085 cb,
1086 NULL);
1087 if(!NT_SUCCESS(Status))
1088 {
1089 SetLastError(RtlNtStatusToDosError(Status));
1090 return FALSE;
1091 }
1092
1093 return TRUE;
1094}
1095
1096
1097/*
1098 * @implemented
1099 */
1100DWORD
1101WINAPI
1102GetProcessImageFileNameW(HANDLE hProcess,
1103 LPWSTR lpImageFileName,
1104 DWORD nSize)
1105{
1106 PUNICODE_STRING ImageFileName;
1107 SIZE_T BufferSize;
1108 NTSTATUS Status;
1109 DWORD Len;
1110
1111 /* Allocate string big enough to hold name */
1112 BufferSize = sizeof(UNICODE_STRING) + (nSize * sizeof(WCHAR));
1113 ImageFileName = LocalAlloc(LMEM_FIXED, BufferSize);
1114 if (ImageFileName == NULL)
1115 {
1116 return 0;
1117 }
1118
1119 /* Query name */
1120 Status = NtQueryInformationProcess(hProcess,
1121 ProcessImageFileName,
1122 ImageFileName,
1123 BufferSize,
1124 NULL);
1125 /* Len mismatch => buffer too small */
1126 if (Status == STATUS_INFO_LENGTH_MISMATCH)
1127 {
1128 Status = STATUS_BUFFER_TOO_SMALL;
1129 }
1130 if (!NT_SUCCESS(Status))
1131 {
1132 SetLastError(RtlNtStatusToDosError(Status));
1133 LocalFree(ImageFileName);
1134 return 0;
1135 }
1136
1137 /* Copy name and null-terminate if possible */
1138 memcpy(lpImageFileName, ImageFileName->Buffer, ImageFileName->Length);
1139 Len = ImageFileName->Length / sizeof(WCHAR);
1140 if (Len < nSize)
1141 {
1142 lpImageFileName[Len] = UNICODE_NULL;
1143 }
1144
1145 LocalFree(ImageFileName);
1146 return Len;
1147}
1148
1149
1150/*
1151 * @implemented
1152 */
1153DWORD
1154WINAPI
1155GetProcessImageFileNameA(HANDLE hProcess,
1156 LPSTR lpImageFileName,
1157 DWORD nSize)
1158{
1159 PUNICODE_STRING ImageFileName;
1160 SIZE_T BufferSize;
1161 NTSTATUS Status;
1162 DWORD Len;
1163
1164 /* Allocate string big enough to hold name */
1165 BufferSize = sizeof(UNICODE_STRING) + (nSize * sizeof(WCHAR));
1166 ImageFileName = LocalAlloc(LMEM_FIXED, BufferSize);
1167 if (ImageFileName == NULL)
1168 {
1169 return 0;
1170 }
1171
1172 /* Query name */
1173 Status = NtQueryInformationProcess(hProcess,
1174 ProcessImageFileName,
1175 ImageFileName,
1176 BufferSize,
1177 NULL);
1178 /* Len mismatch => buffer too small */
1179 if (Status == STATUS_INFO_LENGTH_MISMATCH)
1180 {
1181 Status = STATUS_BUFFER_TOO_SMALL;
1182 }
1183 if (!NT_SUCCESS(Status))
1184 {
1185 SetLastError(RtlNtStatusToDosError(Status));
1186 LocalFree(ImageFileName);
1187 return 0;
1188 }
1189
1190 /* Copy name */
1191 Len = WideCharToMultiByte(CP_ACP, 0, ImageFileName->Buffer,
1192 ImageFileName->Length, lpImageFileName, nSize, NULL, NULL);
1193 /* If conversion was successful, don't return len with added \0 */
1194 if (Len != 0)
1195 {
1196 Len -= sizeof(ANSI_NULL);
1197 }
1198
1199 LocalFree(ImageFileName);
1200 return Len;
1201}
1202
1203
1204/*
1205 * @implemented
1206 */
1207BOOL
1208WINAPI
1209EnumPageFilesA(PENUM_PAGE_FILE_CALLBACKA pCallbackRoutine,
1210 LPVOID lpContext)
1211{
1212 BOOL Ret;
1213 INTERNAL_ENUM_PAGE_FILES_CONTEXT Context;
1214
1215 Context.dwErrCode = ERROR_SUCCESS;
1216 Context.lpContext = lpContext;
1217 Context.pCallbackRoutine = pCallbackRoutine;
1218
1219 /* Call W with our own callback for W -> A conversions */
1220 Ret = EnumPageFilesW(CallBackConvertToAscii, &Context);
1221 /* If we succeed but we have error code, fail and set error */
1222 if (Ret && Context.dwErrCode != ERROR_SUCCESS)
1223 {
1224 Ret = FALSE;
1225 SetLastError(Context.dwErrCode);
1226 }
1227
1228 return Ret;
1229}
1230
1231
1232/*
1233 * @implemented
1234 */
1235BOOL
1236WINAPI
1237EnumPageFilesW(PENUM_PAGE_FILE_CALLBACKW pCallbackRoutine,
1238 LPVOID lpContext)
1239{
1240 PWSTR Colon;
1241 NTSTATUS Status;
1242 DWORD Size = INIT_MEMORY_SIZE, Needed;
1243 ENUM_PAGE_FILE_INFORMATION Information;
1244 PSYSTEM_PAGEFILE_INFORMATION PageFileInfoArray, PageFileInfo;
1245
1246 /* First loop till we have all the information about page files */
1247 do
1248 {
1249 PageFileInfoArray = LocalAlloc(LMEM_FIXED, Size);
1250 if (PageFileInfoArray == NULL)
1251 {
1252 SetLastError(RtlNtStatusToDosError(STATUS_INSUFFICIENT_RESOURCES));
1253 return FALSE;
1254 }
1255
1256 Status = NtQuerySystemInformation(SystemPageFileInformation, PageFileInfoArray, Size, &Needed);
1257 if (NT_SUCCESS(Status))
1258 {
1259 break;
1260 }
1261
1262 LocalFree(PageFileInfoArray);
1263
1264 /* In case we have unexpected status, quit */
1265 if (Status != STATUS_INFO_LENGTH_MISMATCH)
1266 {
1267 SetLastError(RtlNtStatusToDosError(Status));
1268 return FALSE;
1269 }
1270
1271 /* If needed size is smaller than actual size, guess it's something to add to our current size */
1272 if (Needed <= Size)
1273 {
1274 Size += Needed;
1275 }
1276 /* Otherwise, take it as size to allocate */
1277 else
1278 {
1279 Size = Needed;
1280 }
1281 }
1282 while (TRUE);
1283
1284 /* Start browsing all our entries */
1285 PageFileInfo = PageFileInfoArray;
1286 do
1287 {
1288 /* Ensure we really have an entry */
1289 if (Needed < sizeof(SYSTEM_PAGEFILE_INFORMATION))
1290 {
1291 break;
1292 }
1293
1294 /* Prepare structure to hand to the user */
1295 Information.Reserved = 0;
1296 Information.cb = sizeof(Information);
1297 Information.TotalSize = PageFileInfo->TotalSize;
1298 Information.TotalInUse = PageFileInfo->TotalInUse;
1299 Information.PeakUsage = PageFileInfo->PeakUsage;
1300
1301 /* Search for colon */
1302 Colon = wcschr(PageFileInfo->PageFileName.Buffer, L':');
1303 /* If it's found and not at the begin of the string */
1304 if (Colon != 0 && Colon != PageFileInfo->PageFileName.Buffer)
1305 {
1306 /* We can call the user callback routine with the colon */
1307 --Colon;
1308 pCallbackRoutine(lpContext, &Information, Colon);
1309 }
1310
1311 /* If no next entry, then, it's over */
1312 if (PageFileInfo->NextEntryOffset == 0 || PageFileInfo->NextEntryOffset > Needed)
1313 {
1314 break;
1315 }
1316
1317 /* Jump to next entry while keeping accurate bytes left count */
1318 Needed -= PageFileInfo->NextEntryOffset;
1319 PageFileInfo = (PSYSTEM_PAGEFILE_INFORMATION)((ULONG_PTR)PageFileInfo + PageFileInfo->NextEntryOffset);
1320 }
1321 while (TRUE);
1322
1323 LocalFree(PageFileInfoArray);
1324 return TRUE;
1325}
1326
1327
1328/*
1329 * @implemented
1330 */
1331BOOL
1332WINAPI
1333GetPerformanceInfo(PPERFORMANCE_INFORMATION pPerformanceInformation,
1334 DWORD cb)
1335{
1336 NTSTATUS Status;
1337 SYSTEM_BASIC_INFORMATION SystemBasicInfo;
1338 SYSTEM_PERFORMANCE_INFORMATION SystemPerfInfo;
1339 SYSTEM_FILECACHE_INFORMATION SystemFileCacheInfo;
1340 PSYSTEM_PROCESS_INFORMATION ProcInfoArray, SystemProcInfo;
1341 DWORD Size = INIT_MEMORY_SIZE, Needed, ProcCount, ThreadsCount, HandleCount;
1342
1343 /* Validate output buffer */
1344 if (cb < sizeof(PERFORMANCE_INFORMATION))
1345 {
1346 SetLastError(RtlNtStatusToDosError(STATUS_INFO_LENGTH_MISMATCH));
1347 return FALSE;
1348 }
1349
1350 /* First, gather as many information about the system as possible */
1351 Status = NtQuerySystemInformation(SystemBasicInformation,
1352 &SystemBasicInfo,
1353 sizeof(SystemBasicInfo),
1354 NULL);
1355 if (!NT_SUCCESS(Status))
1356 {
1357 SetLastError(RtlNtStatusToDosError(Status));
1358 return FALSE;
1359 }
1360
1361 Status = NtQuerySystemInformation(SystemPerformanceInformation,
1362 &SystemPerfInfo,
1363 sizeof(SystemPerfInfo),
1364 NULL);
1365 if (!NT_SUCCESS(Status))
1366 {
1367 SetLastError(RtlNtStatusToDosError(Status));
1368 return FALSE;
1369 }
1370
1371 Status = NtQuerySystemInformation(SystemFileCacheInformation,
1372 &SystemFileCacheInfo,
1373 sizeof(SystemFileCacheInfo),
1374 NULL);
1375 if (!NT_SUCCESS(Status))
1376 {
1377 SetLastError(RtlNtStatusToDosError(Status));
1378 return FALSE;
1379 }
1380
1381 /* Then loop till we have all the information about processes */
1382 do
1383 {
1384 ProcInfoArray = LocalAlloc(LMEM_FIXED, Size);
1385 if (ProcInfoArray == NULL)
1386 {
1387 SetLastError(RtlNtStatusToDosError(STATUS_INSUFFICIENT_RESOURCES));
1388 return FALSE;
1389 }
1390
1391 Status = NtQuerySystemInformation(SystemProcessInformation,
1392 ProcInfoArray,
1393 Size,
1394 &Needed);
1395 if (NT_SUCCESS(Status))
1396 {
1397 break;
1398 }
1399
1400 LocalFree(ProcInfoArray);
1401
1402 /* In case we have unexpected status, quit */
1403 if (Status != STATUS_INFO_LENGTH_MISMATCH)
1404 {
1405 SetLastError(RtlNtStatusToDosError(Status));
1406 return FALSE;
1407 }
1408
1409 /* If needed size is smaller than actual size, guess it's something to add to our current size */
1410 if (Needed <= Size)
1411 {
1412 Size += Needed;
1413 }
1414 /* Otherwise, take it as size to allocate */
1415 else
1416 {
1417 Size = Needed;
1418 }
1419 } while (TRUE);
1420
1421 /* Start browsing all our entries */
1422 ProcCount = 0;
1423 HandleCount = 0;
1424 ThreadsCount = 0;
1425 SystemProcInfo = ProcInfoArray;
1426 do
1427 {
1428 /* Ensure we really have an entry */
1429 if (Needed < sizeof(SYSTEM_PROCESS_INFORMATION))
1430 {
1431 break;
1432 }
1433
1434 /* Sum procs, threads and handles */
1435 ++ProcCount;
1436 ThreadsCount += SystemProcInfo->NumberOfThreads;
1437 HandleCount += SystemProcInfo->HandleCount;
1438
1439 /* If no next entry, then, it's over */
1440 if (SystemProcInfo->NextEntryOffset == 0 || SystemProcInfo->NextEntryOffset > Needed)
1441 {
1442 break;
1443 }
1444
1445 /* Jump to next entry while keeping accurate bytes left count */
1446 Needed -= SystemProcInfo->NextEntryOffset;
1447 SystemProcInfo = (PSYSTEM_PROCESS_INFORMATION)((ULONG_PTR)SystemProcInfo + SystemProcInfo->NextEntryOffset);
1448 }
1449 while (TRUE);
1450
1451 LocalFree(ProcInfoArray);
1452
1453 /* Output data */
1454 pPerformanceInformation->CommitTotal = SystemPerfInfo.CommittedPages;
1455 pPerformanceInformation->CommitLimit = SystemPerfInfo.CommitLimit;
1456 pPerformanceInformation->CommitPeak = SystemPerfInfo.PeakCommitment;
1457 pPerformanceInformation->PhysicalTotal = SystemBasicInfo.NumberOfPhysicalPages;
1458 pPerformanceInformation->PhysicalAvailable = SystemPerfInfo.AvailablePages;
1459 pPerformanceInformation->SystemCache = SystemFileCacheInfo.CurrentSizeIncludingTransitionInPages;
1460 pPerformanceInformation->KernelNonpaged = SystemPerfInfo.NonPagedPoolPages;
1461 pPerformanceInformation->PageSize = SystemBasicInfo.PageSize;
1462 pPerformanceInformation->cb = sizeof(PERFORMANCE_INFORMATION);
1463 pPerformanceInformation->KernelTotal = SystemPerfInfo.PagedPoolPages + SystemPerfInfo.NonPagedPoolPages;
1464 pPerformanceInformation->KernelPaged = SystemPerfInfo.PagedPoolPages;
1465 pPerformanceInformation->HandleCount = HandleCount;
1466 pPerformanceInformation->ProcessCount = ProcCount;
1467 pPerformanceInformation->ThreadCount = ThreadsCount;
1468
1469 return TRUE;
1470}
1471
1472
1473/*
1474 * @implemented
1475 */
1476BOOL
1477WINAPI
1478GetProcessMemoryInfo(HANDLE Process,
1479 PPROCESS_MEMORY_COUNTERS ppsmemCounters,
1480 DWORD cb)
1481{
1482 NTSTATUS Status;
1483 VM_COUNTERS_EX Counters;
1484
1485 /* Validate output size
1486 * It can be either PROCESS_MEMORY_COUNTERS or PROCESS_MEMORY_COUNTERS_EX
1487 */
1488 if (cb < sizeof(PROCESS_MEMORY_COUNTERS))
1489 {
1490 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1491 return FALSE;
1492 }
1493
1494 _SEH2_TRY
1495 {
1496 ppsmemCounters->PeakPagefileUsage = 0;
1497
1498 /* Query counters */
1499 Status = NtQueryInformationProcess(Process,
1500 ProcessVmCounters,
1501 &Counters,
1502 sizeof(Counters),
1503 NULL);
1504 if (!NT_SUCCESS(Status))
1505 {
1506 SetLastError(RtlNtStatusToDosError(Status));
1507 _SEH2_YIELD(return FALSE);
1508 }
1509
1510 /* Properly set cb, according to what we received */
1511 if (cb >= sizeof(PROCESS_MEMORY_COUNTERS_EX))
1512 {
1513 ppsmemCounters->cb = sizeof(PROCESS_MEMORY_COUNTERS_EX);
1514 }
1515 else
1516 {
1517 ppsmemCounters->cb = sizeof(PROCESS_MEMORY_COUNTERS);
1518 }
1519
1520 /* Output data */
1521 ppsmemCounters->PageFaultCount = Counters.PageFaultCount;
1522 ppsmemCounters->PeakWorkingSetSize = Counters.PeakWorkingSetSize;
1523 ppsmemCounters->WorkingSetSize = Counters.WorkingSetSize;
1524 ppsmemCounters->QuotaPeakPagedPoolUsage = Counters.QuotaPeakPagedPoolUsage;
1525 ppsmemCounters->QuotaPagedPoolUsage = Counters.QuotaPagedPoolUsage;
1526 ppsmemCounters->QuotaPeakNonPagedPoolUsage = Counters.QuotaPeakNonPagedPoolUsage;
1527 ppsmemCounters->QuotaNonPagedPoolUsage = Counters.QuotaNonPagedPoolUsage;
1528 ppsmemCounters->PagefileUsage = Counters.PagefileUsage;
1529 ppsmemCounters->PeakPagefileUsage = Counters.PeakPagefileUsage;
1530 /* And if needed, additional field for _EX version */
1531 if (cb >= sizeof(PROCESS_MEMORY_COUNTERS_EX))
1532 {
1533 ((PPROCESS_MEMORY_COUNTERS_EX)ppsmemCounters)->PrivateUsage = Counters.PrivateUsage;
1534 }
1535 }
1536 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1537 {
1538 SetLastError(RtlNtStatusToDosError(_SEH2_GetExceptionCode()));
1539 _SEH2_YIELD(return FALSE);
1540 }
1541 _SEH2_END;
1542
1543 return TRUE;
1544}
1545
1546
1547/*
1548 * @implemented
1549 */
1550BOOL
1551WINAPI
1552QueryWorkingSet(HANDLE hProcess,
1553 PVOID pv,
1554 DWORD cb)
1555{
1556 NTSTATUS Status;
1557
1558 /* Simply forward the call */
1559 Status = NtQueryVirtualMemory(hProcess,
1560 NULL,
1561 MemoryWorkingSetList,
1562 pv,
1563 cb,
1564 NULL);
1565 if (!NT_SUCCESS(Status))
1566 {
1567 SetLastError(RtlNtStatusToDosError(Status));
1568 return FALSE;
1569 }
1570
1571 return TRUE;
1572}
1573
1574/*
1575 * @implemented
1576 */
1577BOOL
1578WINAPI
1579QueryWorkingSetEx(IN HANDLE hProcess,
1580 IN OUT PVOID pv,
1581 IN DWORD cb)
1582{
1583 NTSTATUS Status;
1584
1585 /* Simply forward the call */
1586 Status = NtQueryVirtualMemory(hProcess,
1587 NULL,
1588 MemoryWorkingSetExList,
1589 pv,
1590 cb,
1591 NULL);
1592 if (!NT_SUCCESS(Status))
1593 {
1594 SetLastError(RtlNtStatusToDosError(Status));
1595 return FALSE;
1596 }
1597
1598 return TRUE;
1599}
1600
1601/* EOF */