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