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