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>
16 #define WIN32_NO_STATUS
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>
28 #include <pseh/pseh2.h>
33 #define MAX_MODULES 0x2710 // Matches 10.000 modules
34 #define INIT_MEMORY_SIZE 0x1000 // Matches 4kB
36 /* INTERNAL *******************************************************************/
42 FindDeviceDriver(IN PVOID ImageBase
,
43 OUT PRTL_PROCESS_MODULE_INFORMATION MatchingModule
)
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
);
54 /* Allocate a buffer to hold modules information */
55 Information
= LocalAlloc(LMEM_FIXED
, Size
);
58 SetLastError(ERROR_NO_SYSTEM_RESOURCES
);
62 /* Query information */
63 Status
= NtQuerySystemInformation(SystemModuleInformation
, Information
, Size
, &Count
);
64 /* In case of an error */
65 if (!NT_SUCCESS(Status
))
67 /* Save the amount of output modules */
68 NewSize
= Information
->NumberOfModules
;
70 LocalFree(Information
);
72 /* If it was not a length mismatch (ie, buffer too small), just leave */
73 if (Status
!= STATUS_INFO_LENGTH_MISMATCH
)
75 SetLastError(RtlNtStatusToDosError(Status
));
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 */
87 ASSERT(NewSize
> Size
);
88 SetLastError(RtlNtStatusToDosError(STATUS_INFO_LENGTH_MISMATCH
));
92 /* Loop again with that new buffer */
97 /* No modules returned? Leave */
98 if (Information
->NumberOfModules
== 0)
103 /* Try to find which module matches the base address given */
104 for (Count
= 0; Count
< Information
->NumberOfModules
; ++Count
)
106 Module
= Information
->Modules
[Count
];
107 if (Module
.ImageBase
== ImageBase
)
109 /* Copy the matching module and leave */
110 memcpy(MatchingModule
, &Module
, sizeof(Module
));
111 LocalFree(Information
);
116 /* If we arrive here, it means we were not able to find matching base address */
120 /* Release and leave */
121 LocalFree(Information
);
122 SetLastError(ERROR_INVALID_HANDLE
);
131 FindModule(IN HANDLE hProcess
,
132 IN HMODULE hModule OPTIONAL
,
133 OUT PLDR_DATA_TABLE_ENTRY Module
)
137 PPEB_LDR_DATA LoaderData
;
138 PLIST_ENTRY ListHead
, ListEntry
;
139 PROCESS_BASIC_INFORMATION ProcInfo
;
141 /* Query the process information to get its PEB address */
142 Status
= NtQueryInformationProcess(hProcess
, ProcessBasicInformation
, &ProcInfo
, sizeof(ProcInfo
), NULL
);
143 if (!NT_SUCCESS(Status
))
145 SetLastError(RtlNtStatusToDosError(Status
));
149 /* If no module was provided, get base as module */
152 if (!ReadProcessMemory(hProcess
, &ProcInfo
.PebBaseAddress
->ImageBaseAddress
, &hModule
, sizeof(hModule
), NULL
))
158 /* Read loader data address from PEB */
159 if (!ReadProcessMemory(hProcess
, &ProcInfo
.PebBaseAddress
->Ldr
, &LoaderData
, sizeof(LoaderData
), NULL
))
164 if (LoaderData
== NULL
)
166 SetLastError(ERROR_INVALID_HANDLE
);
170 /* Store list head address */
171 ListHead
= &(LoaderData
->InMemoryOrderModuleList
);
173 /* Read first element in the modules list */
174 if (!ReadProcessMemory(hProcess
,
175 &(LoaderData
->InMemoryOrderModuleList
.Flink
),
185 /* Loop on the modules */
186 while (ListEntry
!= ListHead
)
188 /* Load module data */
189 if (!ReadProcessMemory(hProcess
,
190 CONTAINING_RECORD(ListEntry
, LDR_DATA_TABLE_ENTRY
, InMemoryOrderLinks
),
198 /* Does that match the module we're looking for? */
199 if (Module
->DllBase
== hModule
)
205 if (Count
> MAX_MODULES
)
210 /* Get to next listed module */
211 ListEntry
= Module
->InMemoryOrderLinks
.Flink
;
214 SetLastError(ERROR_INVALID_HANDLE
);
218 typedef struct _INTERNAL_ENUM_PAGE_FILES_CONTEXT
221 PENUM_PAGE_FILE_CALLBACKA pCallbackRoutine
;
223 } INTERNAL_ENUM_PAGE_FILES_CONTEXT
, *PINTERNAL_ENUM_PAGE_FILES_CONTEXT
;
229 CallBackConvertToAscii(LPVOID pContext
,
230 PENUM_PAGE_FILE_INFORMATION pPageFileInfo
,
236 PINTERNAL_ENUM_PAGE_FILES_CONTEXT Context
= (PINTERNAL_ENUM_PAGE_FILES_CONTEXT
)pContext
;
238 Len
= wcslen(lpFilename
);
240 /* Alloc space for the ANSI string */
241 AnsiFileName
= LocalAlloc(LMEM_FIXED
, (Len
* sizeof(CHAR
)) + sizeof(ANSI_NULL
));
242 if (AnsiFileName
== NULL
)
244 Context
->dwErrCode
= RtlNtStatusToDosError(STATUS_INSUFFICIENT_RESOURCES
);
248 /* Convert string to ANSI */
249 if (WideCharToMultiByte(CP_ACP
, 0, lpFilename
, -1, AnsiFileName
, (Len
* sizeof(CHAR
)) + sizeof(ANSI_NULL
), NULL
, NULL
) == 0)
251 Context
->dwErrCode
= GetLastError();
252 LocalFree(AnsiFileName
);
256 /* And finally call "real" callback */
257 Ret
= Context
->pCallbackRoutine(Context
->lpContext
, pPageFileInfo
, AnsiFileName
);
258 LocalFree(AnsiFileName
);
267 PsParseCommandLine(VOID
)
276 PsInitializeAndStartProfile(VOID
)
285 PsStopAndAnalyzeProfile(VOID
)
290 /* PUBLIC *********************************************************************/
297 DllMain(HINSTANCE hDllHandle
,
303 case DLL_PROCESS_ATTACH
:
304 DisableThreadLibraryCalls(hDllHandle
);
305 if (NtCurrentPeb()->ProcessParameters
->Flags
& RTL_USER_PROCESS_PARAMETERS_PROFILE_USER
)
307 PsParseCommandLine();
308 PsInitializeAndStartProfile();
312 case DLL_PROCESS_DETACH
:
313 if (NtCurrentPeb()->ProcessParameters
->Flags
& RTL_USER_PROCESS_PARAMETERS_PROFILE_USER
)
315 PsStopAndAnalyzeProfile();
329 EmptyWorkingSet(HANDLE hProcess
)
331 SYSTEM_INFO SystemInfo
;
332 QUOTA_LIMITS QuotaLimits
;
335 GetSystemInfo(&SystemInfo
);
337 /* Query the working set */
338 Status
= NtQueryInformationProcess(hProcess
,
344 if (!NT_SUCCESS(Status
))
346 SetLastError(RtlNtStatusToDosError(Status
));
350 /* Empty the working set */
351 QuotaLimits
.MinimumWorkingSetSize
= -1;
352 QuotaLimits
.MaximumWorkingSetSize
= -1;
354 /* Set the working set */
355 Status
= NtSetInformationProcess(hProcess
,
358 sizeof(QuotaLimits
));
359 if (!NT_SUCCESS(Status
) && Status
!= STATUS_PRIVILEGE_NOT_HELD
)
361 SetLastError(RtlNtStatusToDosError(Status
));
374 EnumDeviceDrivers(LPVOID
*lpImageBase
,
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
);
386 /* Allocate a buffer to hold modules information */
387 Information
= LocalAlloc(LMEM_FIXED
, Size
);
390 SetLastError(ERROR_NO_SYSTEM_RESOURCES
);
394 /* Query information */
395 Status
= NtQuerySystemInformation(SystemModuleInformation
, Information
, Size
, &Count
);
396 /* In case of an error */
397 if (!NT_SUCCESS(Status
))
399 /* Save the amount of output modules */
400 NewSize
= Information
->NumberOfModules
;
401 /* And free buffer */
402 LocalFree(Information
);
404 /* If it was not a length mismatch (ie, buffer too small), just leave */
405 if (Status
!= STATUS_INFO_LENGTH_MISMATCH
)
407 SetLastError(RtlNtStatusToDosError(Status
));
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 */
419 ASSERT(NewSize
> Size
);
420 SetLastError(RtlNtStatusToDosError(STATUS_INFO_LENGTH_MISMATCH
));
424 /* Loop again with that new buffer */
429 /* End of allocation loop */
435 for (Count
= 0; Count
< Information
->NumberOfModules
&& Count
< cb
/ sizeof(LPVOID
); ++Count
)
437 lpImageBase
[Count
] = Information
->Modules
[Count
].ImageBase
;
440 *lpcbNeeded
= Information
->NumberOfModules
* sizeof(LPVOID
);
442 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
444 SetLastError(RtlNtStatusToDosError(_SEH2_GetExceptionCode()));
445 _SEH2_YIELD(return FALSE
);
458 EnumProcesses(DWORD
*lpidProcess
,
463 DWORD Size
= MAXSHORT
, Count
;
464 PSYSTEM_PROCESS_INFORMATION ProcInfo
;
465 PSYSTEM_PROCESS_INFORMATION ProcInfoArray
;
467 /* First of all, query all the processes */
470 ProcInfoArray
= LocalAlloc(LMEM_FIXED
, Size
);
471 if (ProcInfoArray
== NULL
)
476 Status
= NtQuerySystemInformation(SystemProcessInformation
, ProcInfoArray
, Size
, NULL
);
477 if (Status
== STATUS_INFO_LENGTH_MISMATCH
)
479 LocalFree(ProcInfoArray
);
488 if (!NT_SUCCESS(Status
))
490 LocalFree(ProcInfoArray
);
491 SetLastError(RtlNtStatusToDosError(Status
));
495 /* Then, loop to output data */
497 ProcInfo
= ProcInfoArray
;
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.
507 if (Count
< cb
/ sizeof(DWORD
))
509 lpidProcess
[Count
] = HandleToUlong(ProcInfo
->UniqueProcessId
);
513 if (ProcInfo
->NextEntryOffset
== 0)
518 ProcInfo
= (PSYSTEM_PROCESS_INFORMATION
)((ULONG_PTR
)ProcInfo
+ ProcInfo
->NextEntryOffset
);
522 *lpcbNeeded
= Count
* sizeof(DWORD
);
524 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
526 SetLastError(RtlNtStatusToDosError(_SEH2_GetExceptionCode()));
527 LocalFree(ProcInfoArray
);
528 _SEH2_YIELD(return FALSE
);
532 LocalFree(ProcInfoArray
);
542 EnumProcessModules(HANDLE hProcess
,
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
;
554 /* Query the process information to get its PEB address */
555 Status
= NtQueryInformationProcess(hProcess
, ProcessBasicInformation
, &ProcInfo
, sizeof(ProcInfo
), NULL
);
556 if (!NT_SUCCESS(Status
))
558 SetLastError(RtlNtStatusToDosError(Status
));
562 if (ProcInfo
.PebBaseAddress
== NULL
)
564 SetLastError(RtlNtStatusToDosError(STATUS_PARTIAL_COPY
));
568 /* Read loader data address from PEB */
569 if (!ReadProcessMemory(hProcess
, &ProcInfo
.PebBaseAddress
->Ldr
, &LoaderData
, sizeof(LoaderData
), NULL
))
574 /* Store list head address */
575 ListHead
= &LoaderData
->InLoadOrderModuleList
;
577 /* Read first element in the modules list */
578 if (!ReadProcessMemory(hProcess
, &LoaderData
->InLoadOrderModuleList
.Flink
, &ListEntry
, sizeof(ListEntry
), NULL
))
583 NbOfModules
= cb
/ sizeof(HMODULE
);
586 /* Loop on the modules */
587 while (ListEntry
!= ListHead
)
589 /* Load module data */
590 if (!ReadProcessMemory(hProcess
,
591 CONTAINING_RECORD(ListEntry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
),
593 sizeof(CurrentModule
),
599 /* Check if we can output module, do it if so */
600 if (Count
< NbOfModules
)
604 lphModule
[Count
] = CurrentModule
.DllBase
;
606 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
608 SetLastError(RtlNtStatusToDosError(_SEH2_GetExceptionCode()));
609 _SEH2_YIELD(return FALSE
);
615 if (Count
> MAX_MODULES
)
617 SetLastError(ERROR_INVALID_HANDLE
);
621 /* Get to next listed module */
622 ListEntry
= CurrentModule
.InLoadOrderLinks
.Flink
;
627 *lpcbNeeded
= Count
* sizeof(HMODULE
);
629 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
631 SetLastError(RtlNtStatusToDosError(_SEH2_GetExceptionCode()));
632 _SEH2_YIELD(return FALSE
);
645 GetDeviceDriverBaseNameA(LPVOID ImageBase
,
649 DWORD Len
, LenWithNull
;
650 RTL_PROCESS_MODULE_INFORMATION Module
;
652 /* Get the associated device driver to the base address */
653 if (!FindDeviceDriver(ImageBase
, &Module
))
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.
662 LenWithNull
= strlen(&Module
.FullPathName
[Module
.OffsetToFileName
]) + 1;
668 memcpy(lpBaseName
, &Module
.FullPathName
[Module
.OffsetToFileName
], Len
);
669 /* In case we copied null char, remove it from final len */
670 if (Len
== LenWithNull
)
684 GetDeviceDriverFileNameA(LPVOID ImageBase
,
688 DWORD Len
, LenWithNull
;
689 RTL_PROCESS_MODULE_INFORMATION Module
;
691 /* Get the associated device driver to the base address */
692 if (!FindDeviceDriver(ImageBase
, &Module
))
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.
701 LenWithNull
= strlen(Module
.FullPathName
) + 1;
707 memcpy(lpFilename
, Module
.FullPathName
, Len
);
708 /* In case we copied null char, remove it from final len */
709 if (Len
== LenWithNull
)
723 GetDeviceDriverBaseNameW(LPVOID ImageBase
,
730 /* Allocate internal buffer for conversion */
731 BaseName
= LocalAlloc(LMEM_FIXED
, nSize
);
738 Len
= GetDeviceDriverBaseNameA(ImageBase
, BaseName
, nSize
);
745 /* And convert output */
746 if (MultiByteToWideChar(CP_ACP
, 0, BaseName
, (Len
< nSize
) ? Len
+ 1 : Len
, lpBaseName
, nSize
) == 0)
762 GetDeviceDriverFileNameW(LPVOID ImageBase
,
769 /* Allocate internal buffer for conversion */
770 FileName
= LocalAlloc(LMEM_FIXED
, nSize
);
777 Len
= GetDeviceDriverFileNameA(ImageBase
, FileName
, nSize
);
784 /* And convert output */
785 if (MultiByteToWideChar(CP_ACP
, 0, FileName
, (Len
< nSize
) ? Len
+ 1 : Len
, lpFilename
, nSize
) == 0)
801 GetMappedFileNameA(HANDLE hProcess
,
809 DPRINT("GetMappedFileNameA(%p, %p, %p, %lu)\n", hProcess
, lpv
, lpFilename
, nSize
);
811 /* Allocate internal buffer for conversion */
812 FileName
= LocalAlloc(LMEM_FIXED
, nSize
* sizeof(WCHAR
));
813 if (FileName
== NULL
)
819 Len
= GetMappedFileNameW(hProcess
, lpv
, FileName
, nSize
);
821 /* And convert output */
822 if (WideCharToMultiByte(CP_ACP
, 0, FileName
, (Len
< nSize
) ? Len
+ 1 : Len
, lpFilename
, nSize
, NULL
, NULL
) == 0)
837 GetMappedFileNameW(HANDLE hProcess
,
848 WCHAR CharBuffer
[MAX_PATH
];
851 DPRINT("GetMappedFileNameW(%p, %p, %p, %lu)\n", hProcess
, lpv
, lpFilename
, nSize
);
853 /* If no buffer, no need to keep going on */
856 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
860 /* Query section name */
861 Status
= NtQueryVirtualMemory(hProcess
, lpv
, MemorySectionName
,
862 &SectionName
, sizeof(SectionName
), &OutSize
);
863 if (!NT_SUCCESS(Status
))
865 SetLastError(RtlNtStatusToDosError(Status
));
869 /* Prepare to copy file name */
871 OutSize
= SectionName
.SectionFileName
.Length
/ sizeof(WCHAR
);
872 if (OutSize
+ 1 > nSize
)
876 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
880 SetLastError(ERROR_SUCCESS
);
883 /* Copy, zero and return */
884 memcpy(lpFilename
, SectionName
.SectionFileName
.Buffer
, Len
* sizeof(WCHAR
));
896 GetModuleBaseNameA(HANDLE hProcess
,
904 /* Allocate internal buffer for conversion */
905 BaseName
= LocalAlloc(LMEM_FIXED
, nSize
* sizeof(WCHAR
));
906 if (BaseName
== NULL
)
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)
930 GetModuleBaseNameW(HANDLE hProcess
,
936 LDR_DATA_TABLE_ENTRY Module
;
938 /* Get the matching module */
939 if (!FindModule(hProcess
, hModule
, &Module
))
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
)
948 Len
= nSize
* sizeof(WCHAR
);
952 if (!ReadProcessMemory(hProcess
, (&Module
.BaseDllName
)->Buffer
, lpBaseName
, Len
, NULL
))
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
))
960 Len
-= sizeof(UNICODE_NULL
);
963 /* Nullify at the end if needed */
964 if (Len
>= nSize
* sizeof(WCHAR
))
968 ASSERT(nSize
>= sizeof(UNICODE_NULL
));
969 lpBaseName
[nSize
- 1] = UNICODE_NULL
;
972 /* Otherwise, nullify at last written char */
975 ASSERT(Len
+ sizeof(UNICODE_NULL
) <= nSize
* sizeof(WCHAR
));
976 lpBaseName
[Len
/ sizeof(WCHAR
)] = UNICODE_NULL
;
979 return Len
/ sizeof(WCHAR
);
988 GetModuleFileNameExA(HANDLE hProcess
,
996 /* Allocate internal buffer for conversion */
997 Filename
= LocalAlloc(LMEM_FIXED
, nSize
* sizeof(WCHAR
));
998 if (Filename
== NULL
)
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)
1011 LocalFree(Filename
);
1022 GetModuleFileNameExW(HANDLE hProcess
,
1028 LDR_DATA_TABLE_ENTRY Module
;
1030 /* Get the matching module */
1031 if (!FindModule(hProcess
, hModule
, &Module
))
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
)
1040 Len
= nSize
* sizeof(WCHAR
);
1044 if (!ReadProcessMemory(hProcess
, (&Module
.FullDllName
)->Buffer
, lpFilename
, Len
, NULL
))
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
))
1052 Len
-= sizeof(UNICODE_NULL
);
1055 /* Nullify at the end if needed */
1056 if (Len
>= nSize
* sizeof(WCHAR
))
1060 ASSERT(nSize
>= sizeof(UNICODE_NULL
));
1061 lpFilename
[nSize
- 1] = UNICODE_NULL
;
1064 /* Otherwise, nullify at last written char */
1067 ASSERT(Len
+ sizeof(UNICODE_NULL
) <= nSize
* sizeof(WCHAR
));
1068 lpFilename
[Len
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1071 return Len
/ sizeof(WCHAR
);
1080 GetModuleInformation(HANDLE hProcess
,
1082 LPMODULEINFO lpmodinfo
,
1085 MODULEINFO LocalInfo
;
1086 LDR_DATA_TABLE_ENTRY Module
;
1088 /* Check output size */
1089 if (cb
< sizeof(MODULEINFO
))
1091 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1095 /* Get the matching module */
1096 if (!FindModule(hProcess
, hModule
, &Module
))
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
;
1106 /* Attempt to copy to output */
1109 memcpy(lpmodinfo
, &LocalInfo
, sizeof(LocalInfo
));
1111 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1113 SetLastError(RtlNtStatusToDosError(_SEH2_GetExceptionCode()));
1114 _SEH2_YIELD(return FALSE
);
1127 InitializeProcessForWsWatch(HANDLE hProcess
)
1131 /* Simply forward the call */
1132 Status
= NtSetInformationProcess(hProcess
,
1133 ProcessWorkingSetWatch
,
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
)
1142 SetLastError(RtlNtStatusToDosError(Status
));
1152 GetWsChanges(HANDLE hProcess
,
1153 PPSAPI_WS_WATCH_INFORMATION lpWatchInfo
,
1158 /* Simply forward the call */
1159 Status
= NtQueryInformationProcess(hProcess
,
1160 ProcessWorkingSetWatch
,
1164 if(!NT_SUCCESS(Status
))
1166 SetLastError(RtlNtStatusToDosError(Status
));
1179 GetProcessImageFileNameW(HANDLE hProcess
,
1180 LPWSTR lpImageFileName
,
1183 PUNICODE_STRING ImageFileName
;
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
)
1197 Status
= NtQueryInformationProcess(hProcess
,
1198 ProcessImageFileName
,
1202 /* Len mismatch => buffer too small */
1203 if (Status
== STATUS_INFO_LENGTH_MISMATCH
)
1205 Status
= STATUS_BUFFER_TOO_SMALL
;
1207 if (!NT_SUCCESS(Status
))
1209 SetLastError(RtlNtStatusToDosError(Status
));
1210 LocalFree(ImageFileName
);
1214 /* Copy name and null-terminate if possible */
1215 memcpy(lpImageFileName
, ImageFileName
->Buffer
, ImageFileName
->Length
);
1216 Len
= ImageFileName
->Length
/ sizeof(WCHAR
);
1219 lpImageFileName
[Len
] = UNICODE_NULL
;
1222 LocalFree(ImageFileName
);
1232 GetProcessImageFileNameA(HANDLE hProcess
,
1233 LPSTR lpImageFileName
,
1236 PUNICODE_STRING ImageFileName
;
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
)
1250 Status
= NtQueryInformationProcess(hProcess
,
1251 ProcessImageFileName
,
1255 /* Len mismatch => buffer too small */
1256 if (Status
== STATUS_INFO_LENGTH_MISMATCH
)
1258 Status
= STATUS_BUFFER_TOO_SMALL
;
1260 if (!NT_SUCCESS(Status
))
1262 SetLastError(RtlNtStatusToDosError(Status
));
1263 LocalFree(ImageFileName
);
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 */
1273 Len
-= sizeof(ANSI_NULL
);
1276 LocalFree(ImageFileName
);
1286 EnumPageFilesA(PENUM_PAGE_FILE_CALLBACKA pCallbackRoutine
,
1290 INTERNAL_ENUM_PAGE_FILES_CONTEXT Context
;
1292 Context
.dwErrCode
= ERROR_SUCCESS
;
1293 Context
.lpContext
= lpContext
;
1294 Context
.pCallbackRoutine
= pCallbackRoutine
;
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
)
1302 SetLastError(Context
.dwErrCode
);
1314 EnumPageFilesW(PENUM_PAGE_FILE_CALLBACKW pCallbackRoutine
,
1319 DWORD Size
= INIT_MEMORY_SIZE
, Needed
;
1320 ENUM_PAGE_FILE_INFORMATION Information
;
1321 PSYSTEM_PAGEFILE_INFORMATION PageFileInfoArray
, PageFileInfo
;
1323 /* First loop till we have all the information about page files */
1326 PageFileInfoArray
= LocalAlloc(LMEM_FIXED
, Size
);
1327 if (PageFileInfoArray
== NULL
)
1329 SetLastError(RtlNtStatusToDosError(STATUS_INSUFFICIENT_RESOURCES
));
1333 Status
= NtQuerySystemInformation(SystemPageFileInformation
, PageFileInfoArray
, Size
, &Needed
);
1334 if (NT_SUCCESS(Status
))
1339 LocalFree(PageFileInfoArray
);
1341 /* In case we have unexpected status, quit */
1342 if (Status
!= STATUS_INFO_LENGTH_MISMATCH
)
1344 SetLastError(RtlNtStatusToDosError(Status
));
1348 /* If needed size is smaller than actual size, guess it's something to add to our current size */
1353 /* Otherwise, take it as size to allocate */
1361 /* Start browsing all our entries */
1362 PageFileInfo
= PageFileInfoArray
;
1365 /* Ensure we really have an entry */
1366 if (Needed
< sizeof(SYSTEM_PAGEFILE_INFORMATION
))
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
;
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
)
1383 /* We can call the user callback routine with the colon */
1385 pCallbackRoutine(lpContext
, &Information
, Colon
);
1388 /* If no next entry, then, it's over */
1389 if (PageFileInfo
->NextEntryOffset
== 0 || PageFileInfo
->NextEntryOffset
> Needed
)
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
);
1400 LocalFree(PageFileInfoArray
);
1410 GetPerformanceInfo(PPERFORMANCE_INFORMATION pPerformanceInformation
,
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
;
1420 /* Validate output buffer */
1421 if (cb
< sizeof(PERFORMANCE_INFORMATION
))
1423 SetLastError(RtlNtStatusToDosError(STATUS_INFO_LENGTH_MISMATCH
));
1427 /* First, gather as many information about the system as possible */
1428 Status
= NtQuerySystemInformation(SystemBasicInformation
,
1430 sizeof(SystemBasicInfo
),
1432 if (!NT_SUCCESS(Status
))
1434 SetLastError(RtlNtStatusToDosError(Status
));
1438 Status
= NtQuerySystemInformation(SystemPerformanceInformation
,
1440 sizeof(SystemPerfInfo
),
1442 if (!NT_SUCCESS(Status
))
1444 SetLastError(RtlNtStatusToDosError(Status
));
1448 Status
= NtQuerySystemInformation(SystemFileCacheInformation
,
1449 &SystemFileCacheInfo
,
1450 sizeof(SystemFileCacheInfo
),
1452 if (!NT_SUCCESS(Status
))
1454 SetLastError(RtlNtStatusToDosError(Status
));
1458 /* Then loop till we have all the information about processes */
1461 ProcInfoArray
= LocalAlloc(LMEM_FIXED
, Size
);
1462 if (ProcInfoArray
== NULL
)
1464 SetLastError(RtlNtStatusToDosError(STATUS_INSUFFICIENT_RESOURCES
));
1468 Status
= NtQuerySystemInformation(SystemProcessInformation
,
1472 if (NT_SUCCESS(Status
))
1477 LocalFree(ProcInfoArray
);
1479 /* In case we have unexpected status, quit */
1480 if (Status
!= STATUS_INFO_LENGTH_MISMATCH
)
1482 SetLastError(RtlNtStatusToDosError(Status
));
1486 /* If needed size is smaller than actual size, guess it's something to add to our current size */
1491 /* Otherwise, take it as size to allocate */
1498 /* Start browsing all our entries */
1502 SystemProcInfo
= ProcInfoArray
;
1505 /* Ensure we really have an entry */
1506 if (Needed
< sizeof(SYSTEM_PROCESS_INFORMATION
))
1511 /* Sum procs, threads and handles */
1513 ThreadsCount
+= SystemProcInfo
->NumberOfThreads
;
1514 HandleCount
+= SystemProcInfo
->HandleCount
;
1516 /* If no next entry, then, it's over */
1517 if (SystemProcInfo
->NextEntryOffset
== 0 || SystemProcInfo
->NextEntryOffset
> Needed
)
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
);
1528 LocalFree(ProcInfoArray
);
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
;
1555 GetProcessMemoryInfo(HANDLE Process
,
1556 PPROCESS_MEMORY_COUNTERS ppsmemCounters
,
1560 VM_COUNTERS_EX Counters
;
1562 /* Validate output size
1563 * It can be either PROCESS_MEMORY_COUNTERS or PROCESS_MEMORY_COUNTERS_EX
1565 if (cb
< sizeof(PROCESS_MEMORY_COUNTERS
))
1567 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1573 ppsmemCounters
->PeakPagefileUsage
= 0;
1575 /* Query counters */
1576 Status
= NtQueryInformationProcess(Process
,
1581 if (!NT_SUCCESS(Status
))
1583 SetLastError(RtlNtStatusToDosError(Status
));
1584 _SEH2_YIELD(return FALSE
);
1587 /* Properly set cb, according to what we received */
1588 if (cb
>= sizeof(PROCESS_MEMORY_COUNTERS_EX
))
1590 ppsmemCounters
->cb
= sizeof(PROCESS_MEMORY_COUNTERS_EX
);
1594 ppsmemCounters
->cb
= sizeof(PROCESS_MEMORY_COUNTERS
);
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
))
1610 ((PPROCESS_MEMORY_COUNTERS_EX
)ppsmemCounters
)->PrivateUsage
= Counters
.PrivateUsage
;
1613 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1615 SetLastError(RtlNtStatusToDosError(_SEH2_GetExceptionCode()));
1616 _SEH2_YIELD(return FALSE
);
1629 QueryWorkingSet(HANDLE hProcess
,
1635 /* Simply forward the call */
1636 Status
= NtQueryVirtualMemory(hProcess
,
1638 MemoryWorkingSetList
,
1642 if (!NT_SUCCESS(Status
))
1644 SetLastError(RtlNtStatusToDosError(Status
));
1656 QueryWorkingSetEx(IN HANDLE hProcess
,
1662 /* Simply forward the call */
1663 Status
= NtQueryVirtualMemory(hProcess
,
1665 MemoryWorkingSetExList
,
1669 if (!NT_SUCCESS(Status
))
1671 SetLastError(RtlNtStatusToDosError(Status
));