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