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