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 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 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 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 251 PsParseCommandLine(VOID) 252 { 253 UNIMPLEMENTED; 254 } 255 256 /* 257 * @unimplemented 258 */ 259 static VOID NTAPI 260 PsInitializeAndStartProfile(VOID) 261 { 262 UNIMPLEMENTED; 263 } 264 265 /* 266 * @unimplemented 267 */ 268 static VOID NTAPI 269 PsStopAndAnalyzeProfile(VOID) 270 { 271 UNIMPLEMENTED; 272 } 273 274 /* PUBLIC *********************************************************************/ 275 276 /* 277 * @implemented 278 */ 279 BOOLEAN 280 WINAPI 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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