1c82f505edadfa0aac2c1dc29c9f2daa13102320
[reactos.git] / dll / win32 / psapi / psapi.c
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 */