From a51a9e7f17fa3f7ff5901f75eca94e294adbce6c Mon Sep 17 00:00:00 2001 From: dahall Date: Mon, 4 Oct 2021 21:20:07 -0600 Subject: [PATCH] Added GetInfo, SetInfo, ReadMemeory and WriteMemory process extension methods. Fixed PROCESS_INFORMATION_CLASS values and types. --- PInvoke/Kernel32/ProcessThreadsApi.cs | 275 ++++++++++++++++++++++++++++------ System/Extensions/ProcessExtension.cs | 115 ++++++++++++++ 2 files changed, 345 insertions(+), 45 deletions(-) diff --git a/PInvoke/Kernel32/ProcessThreadsApi.cs b/PInvoke/Kernel32/ProcessThreadsApi.cs index 5986858a..f2e25eeb 100644 --- a/PInvoke/Kernel32/ProcessThreadsApi.cs +++ b/PInvoke/Kernel32/ProcessThreadsApi.cs @@ -265,6 +265,29 @@ namespace Vanara.PInvoke DYNAMIC_EH_CONTINUATION_TARGET_PROCESSED = 0x00000002 } + /// + /// Specifies the ways in which an architecture of code can run on a host operating system. More than one bit may be set. + /// + // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ne-processthreadsapi-machine_attributes typedef enum + // _MACHINE_ATTRIBUTES { UserEnabled, KernelEnabled, Wow64Container } MACHINE_ATTRIBUTES; + [PInvokeData("processthreadsapi.h", MSDNShortId = "NE:processthreadsapi._MACHINE_ATTRIBUTES")] + public enum MACHINE_ATTRIBUTES + { + /// The specified architecture of code can run in user mode. + UserEnabled, + + /// The specified architecture of code can run in kernel mode. + KernelEnabled, + + /// + /// The specified architecture of code runs by relying on WOW64's namespace File System Redirector and Registry + /// Redirector. This bit will be set, for example, on x86 code running on a host operating system that is x64 or ARM64. When + /// the compatibility layer does not use WOW64 style filesystem and registry namespaces, like x64 on ARM64 which runs on the + /// root namespace of the OS, this bit will be reset. + /// + Wow64Container, + } + /// The memory priority for the thread or process. public enum MEMORY_PRIORITY { @@ -297,37 +320,90 @@ namespace Vanara.PInvoke PROCESS_AFFINITY_ENABLE_AUTO_UPDATE } - /// Indicates type of structure used in GetProcessInformation and SetProcessInformation calls. + /// + /// Indicates a specific class of process information. Values from this enumeration are passed into the GetProcessInformation and + /// SetProcessInformation functions to specify the type of process information passed in the void pointer argument of the function call. + /// + // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ne-processthreadsapi-process_information_class typedef enum + // _PROCESS_INFORMATION_CLASS { ProcessMemoryPriority, ProcessMemoryExhaustionInfo, ProcessAppMemoryInfo, ProcessInPrivateInfo, + // ProcessPowerThrottling, ProcessReservedValue1, ProcessTelemetryCoverageInfo, ProcessProtectionLevelInfo, ProcessLeapSecondInfo, + // ProcessMachineTypeInfo, ProcessInformationClassMax } PROCESS_INFORMATION_CLASS; + [PInvokeData("processthreadsapi.h", MSDNShortId = "NE:processthreadsapi._PROCESS_INFORMATION_CLASS")] public enum PROCESS_INFORMATION_CLASS { - /// Indicates that a MEMORY_PRIORITY_INFORMATION structure is specified for the operation. - [CorrespondingType(typeof(MEMORY_PRIORITY_INFORMATION))] + /// + /// The process information is represented by a MEMORY_PRIORITY_INFORMATION structure. Allows applications to lower the default + /// memory priority of threads that perform background operations or access files and data that are not expected to be accessed + /// again soon. + /// + [CorrespondingType(typeof(MEMORY_PRIORITY_INFORMATION), CorrespondingAction.GetSet)] ProcessMemoryPriority, - /// Indicates that a PROCESS_MEMORY_EXHAUSTION_INFO structure is specified for the operation. - [CorrespondingType(typeof(PROCESS_MEMORY_EXHAUSTION_INFO))] + /// + /// The process information is represented by a PROCESS_MEMORY_EXHAUSTION_INFO structure. Allows applications to configure a + /// process to terminate if an allocation fails to commit memory. + /// + [CorrespondingType(typeof(PROCESS_MEMORY_EXHAUSTION_INFO), CorrespondingAction.Set)] ProcessMemoryExhaustionInfo, - /// Indicates that a APP_MEMORY_INFORMATION structure is specified for the operation. - [CorrespondingType(typeof(APP_MEMORY_INFORMATION))] + /// + /// The process information is represented by a APP_MEMORY_INFORMATION structure. Allows applications to query the commit usage + /// and the additional commit available to this process. Does not allow the caller to actually get a commit limit. + /// + [CorrespondingType(typeof(APP_MEMORY_INFORMATION), CorrespondingAction.Get)] ProcessAppMemoryInfo, - /// Undocumented. + /// + /// If a process is set to ProcessInPrivate mode, and a trace session has set the EVENT_ENABLE_PROPERTY_EXCLUDE_INPRIVATE + /// flag, then the trace session will drop all events from that process. + /// ProcessInPrivateInfo, - /// Indicates that a PROCESS_POWER_THROTTLING_STATE structure is specified for the operation. - [CorrespondingType(typeof(PROCESS_POWER_THROTTLING_STATE))] + /// + /// The process information is represented by a PROCESS_POWER_THROTTLING_STATE structure. Allows applications to configure how + /// the system should throttle the target process’s activity when managing power. + /// + [CorrespondingType(typeof(PROCESS_POWER_THROTTLING_STATE), CorrespondingAction.GetSet)] ProcessPowerThrottling, - /// Undocumented. + /// Reserved. ProcessReservedValue1, - /// Undocumented. + /// Reserved. ProcessTelemetryCoverageInfo, - /// Indicates that a PROCESS_PROTECTION_LEVEL_INFORMATION structure is specified for the operation. - [CorrespondingType(typeof(PROCESS_PROTECTION_LEVEL_INFORMATION))] + /// The process information is represented by a PROCESS_PROTECTION_LEVEL_INFORMATION structure. + [CorrespondingType(typeof(PROCESS_PROTECTION_LEVEL_INFORMATION), CorrespondingAction.Get)] ProcessProtectionLevelInfo, + + /// The process information is represented by a PROCESS_LEAP_SECOND_INFO structure. + [CorrespondingType(typeof(PROCESS_LEAP_SECOND_INFO), CorrespondingAction.GetSet)] + ProcessLeapSecondInfo, + + /// The process is represented by a PROCESS_MACHINE_INFORMATION structure. + [CorrespondingType(typeof(PROCESS_MACHINE_INFORMATION), CorrespondingAction.Get)] + ProcessMachineTypeInfo, + } + + /// Flags for . + [PInvokeData("processthreadsapi.h")] + [Flags] + public enum PROCESS_LEAP_SECOND_INFO_FLAGS + { + /// + /// This value changes the way positive leap seconds are handled by system. Specifically, it changes how the seconds field + /// during a positive leap second is handled by the system. If this value is used, then the positive leap second will be shown + /// (For example: 23:59:59 -> 23:59:60 -> 00:00:00. If this value is not used, then "sixty seconds" is disabled, and the + /// 59th second preceding a positive leap second will be shown for 2 seconds with the milliseconds value ticking twice as slow. + /// So 23:59:59 -> 23:59:59.500 -> 00:00:00, which takes 2 seconds in wall clock time. Disabling "sixty second" can help + /// with legacy apps that do not support seeing the seconds value as 60 during the positive leap second. Such apps may crash or + /// misbehave. Therefore, in these cases, we display the 59th second for twice as long during the positive leap second. Note + /// that this setting is per-process, and does not persist if the process is restarted. Developers should test their app for + /// compatibility with seeing the system return "60", and add a call to their app startup routines to either enable or disable + /// "sixty seconds". "Sixty seconds" is disabled by default for each process. Obviously, this setting has no effect if leap + /// seconds are disabled system-wide, because then the system will never even encounter a leap second. + /// + PROCESS_LEAP_SECOND_INFO_FLAG = 1 } /// Represents the different memory exhaustion types. @@ -2667,67 +2743,110 @@ namespace Vanara.PInvoke /// Retrieves information about the specified process. /// - /// A handle to the process. This handle must have the PROCESS_SET_INFORMATION access right. For more information, see Process - /// Security and Access Rights. + /// A handle to the process. This handle must have the PROCESS_SET_INFORMATION access right. For more information, see + /// Process Security and Access Rights. + /// + /// + /// A member of the PROCESS_INFORMATION_CLASS enumeration specifying the kind of information to retrieve. /// - /// The kind of information to retrieve. The only supported value is ProcessMemoryPriority /// /// Pointer to an object to receive the type of information specified by the ProcessInformationClass parameter. /// /// If the ProcessInformationClass parameter is ProcessMemoryPriority, this parameter must point to a - /// MEMORY_PRIORITY_INFORMATION structure. + /// MEMORY_PRIORITY_INFORMATION structure. /// /// /// If the ProcessInformationClass parameter is ProcessPowerThrottling, this parameter must point to a - /// PROCESS_POWER_THROTTLING_STATE structure. + /// PROCESS_POWER_THROTTLING_STATE structure. /// /// /// If the ProcessInformationClass parameter is ProcessProtectionLevelInfo, this parameter must point to a - /// PROCESS_PROTECTION_LEVEL_INFORMATION structure. + /// PROCESS_PROTECTION_LEVEL_INFORMATION structure. /// /// - /// If the ProcessInformationClass parameter is ProcessAppMemoryInfo, this parameter must point to a - /// APP_MEMORY_INFORMATION structure. + /// If the ProcessInformationClass parameter is ProcessLeapSecondInfo, this parameter must point to a + /// PROCESS_LEAP_SECOND_INFO structure. + /// + /// + /// If the ProcessInformationClass parameter is ProcessAppMemoryInfo, this parameter must point to a APP_MEMORY_INFORMATION structure. /// /// /// /// The size in bytes of the structure specified by the ProcessInformation parameter. - /// If the ProcessInformationClass parameter is ProcessMemoryPriority, this parameter must be . - /// If the ProcessInformationClass parameter is ProcessPowerThrottling, this parameter must be . - /// If the ProcessInformationClass parameter is ProcessProtectionLevelInfo, this parameter must be . - /// If the ProcessInformationClass parameter is ProcessAppMemoryInfo, this parameter must be . + /// If the ProcessInformationClass parameter is ProcessMemoryPriority, this parameter must be + /// sizeof(MEMORY_PRIORITY_INFORMATION) + /// . + /// + /// If the ProcessInformationClass parameter is ProcessPowerThrottling, this parameter must be + /// sizeof(PROCESS_POWER_THROTTLING_STATE) + /// . + /// + /// If the ProcessInformationClass parameter is ProcessProtectionLevelInfo, this parameter must be + /// sizeof(PROCESS_PROTECTION_LEVEL_INFORMATION) + /// . + /// + /// If the ProcessInformationClass parameter is ProcessLeapSecondInfo, this parameter must be + /// sizeof(PROCESS_LEAP_SECOND_INFO) + /// . + /// + /// If the ProcessInformationClass parameter is ProcessAppMemoryInfo, this parameter must be + /// sizeof(APP_MEMORY_INFORMATION) + /// . + /// /// /// /// If the function succeeds, the return value is nonzero. - /// If the function fails, the return value is zero. To get extended error information, call GetLastError. + /// If the function fails, the return value is zero. To get extended error information, call GetLastError. /// - // BOOL WINAPI GetProcessInformation( _In_ HANDLE hProcess, _In_ PROCESS_INFORMATION_CLASS ProcessInformationClass, - // _Out_writes_bytes_(ProcessInformationSize) ProcessInformation, _In_ DWORD ProcessInformationSize); https://msdn.microsoft.com/en-us/library/windows/desktop/hh448381(v=vs.85).aspx + // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getprocessinformation + // BOOL GetProcessInformation( HANDLE hProcess, PROCESS_INFORMATION_CLASS ProcessInformationClass, LPVOID ProcessInformation, DWORD ProcessInformationSize ); + [PInvokeData("processthreadsapi.h", MSDNShortId = "NF:processthreadsapi.GetProcessInformation")] [DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)] - [PInvokeData("WinBase.h", MSDNShortId = "hh448381")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool GetProcessInformation(HPROCESS hProcess, PROCESS_INFORMATION_CLASS ProcessInformationClass, IntPtr ProcessInformation, uint ProcessInformationSize); /// Retrieves information about the specified process. - /// The type of information associated with . + /// The type to retrive. /// - /// A handle to the process. This handle must have the PROCESS_SET_INFORMATION access right. For more information, see Process - /// Security and Access Rights. + /// A handle to the process. This handle must have the PROCESS_SET_INFORMATION access right. For more information, see + /// Process Security and Access Rights. /// - /// The kind of information to retrieve. The only supported value is ProcessMemoryPriority - /// An object containing the type of information specified by the ProcessInformationClass parameter. - /// Type mismatch. - [PInvokeData("WinBase.h", MSDNShortId = "hh448381")] - public static T GetProcessInformation(HPROCESS hProcess, PROCESS_INFORMATION_CLASS ProcessInformationClass) where T : struct + /// + /// A member of the PROCESS_INFORMATION_CLASS enumeration specifying the kind of information to retrieve. + /// + /// + /// Pointer to an object to receive the type of information specified by the ProcessInformationClass parameter. + /// + /// If the ProcessInformationClass parameter is ProcessMemoryPriority, this parameter must point to a + /// MEMORY_PRIORITY_INFORMATION structure. + /// + /// + /// If the ProcessInformationClass parameter is ProcessPowerThrottling, this parameter must point to a + /// PROCESS_POWER_THROTTLING_STATE structure. + /// + /// + /// If the ProcessInformationClass parameter is ProcessProtectionLevelInfo, this parameter must point to a + /// PROCESS_PROTECTION_LEVEL_INFORMATION structure. + /// + /// + /// If the ProcessInformationClass parameter is ProcessLeapSecondInfo, this parameter must point to a + /// PROCESS_LEAP_SECOND_INFO structure. + /// + /// + /// If the ProcessInformationClass parameter is ProcessAppMemoryInfo, this parameter must point to a APP_MEMORY_INFORMATION structure. + /// + /// + public static T GetProcessInformation(HPROCESS hProcess, PROCESS_INFORMATION_CLASS ProcessInformationClass = (PROCESS_INFORMATION_CLASS)(-1)) where T : struct { - if (!CorrespondingTypeAttribute.CanGet(ProcessInformationClass, typeof(T))) throw new ArgumentException("Type mismatch."); - using (var mem = SafeHGlobalHandle.CreateFromStructure()) - { - if (!GetProcessInformation(hProcess, ProcessInformationClass, (IntPtr)mem, (uint)mem.Size)) - Win32Error.ThrowLastError(); - return mem.ToStructure(); - } + if (!ProcessInformationClass.IsValid() && !CorrespondingTypeAttribute.CanGet(out ProcessInformationClass)) + throw new ArgumentException("The type specified by the type parameter cannot be retrieved for a process.", nameof(T)); + else if (!CorrespondingTypeAttribute.CanGet(ProcessInformationClass, typeof(T))) + throw new ArgumentException("Type mismatch."); + using var mem = new SafeCoTaskMemStruct(); + if (!GetProcessInformation(hProcess, ProcessInformationClass, mem, mem.Size)) + Win32Error.ThrowLastError(); + return mem.Value; } /// Retrieves mitigation policy settings for the calling process. @@ -6151,6 +6270,72 @@ namespace Vanara.PInvoke public uint dwThreadId; } + /// Specifies how the system handles positive leap seconds. + // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-process_leap_second_info + // typedef struct _PROCESS_LEAP_SECOND_INFO { ULONG Flags; ULONG Reserved; } PROCESS_LEAP_SECOND_INFO, *PPROCESS_LEAP_SECOND_INFO; + [PInvokeData("processthreadsapi.h", MSDNShortId = "NS:processthreadsapi._PROCESS_LEAP_SECOND_INFO")] + [StructLayout(LayoutKind.Sequential)] + public struct PROCESS_LEAP_SECOND_INFO + { + /// + /// + /// Currently, the only valid flag is PROCESS_LEAP_SECOND_INFO_FLAG_ENABLE_SIXTY_SECOND. That flag is described below. + /// + /// + /// + /// Value + /// Meaning + /// + /// + /// PROCESS_LEAP_SECOND_INFO_FLAG_ENABLE_SIXTY_SECOND + /// + /// This value changes the way positive leap seconds are handled by system. Specifically, it changes how the seconds field + /// during a positive leap second is handled by the system. If this value is used, then the positive leap second will be shown + /// (For example: 23:59:59 -> 23:59:60 -> 00:00:00. If this value is not used, then "sixty seconds" is disabled, and the + /// 59th second preceding a positive leap second will be shown for 2 seconds with the milliseconds value ticking twice as slow. + /// So 23:59:59 -> 23:59:59.500 -> 00:00:00, which takes 2 seconds in wall clock time. Disabling "sixty second" can help + /// with legacy apps that do not support seeing the seconds value as 60 during the positive leap second. Such apps may crash or + /// misbehave. Therefore, in these cases, we display the 59th second for twice as long during the positive leap second. Note + /// that this setting is per-process, and does not persist if the process is restarted. Developers should test their app for + /// compatibility with seeing the system return "60", and add a call to their app startup routines to either enable or disable + /// "sixty seconds". "Sixty seconds" is disabled by default for each process. Obviously, this setting has no effect if leap + /// seconds are disabled system-wide, because then the system will never even encounter a leap second. + /// + /// + /// + /// + public PROCESS_LEAP_SECOND_INFO_FLAGS Flags; + + /// Reserved for future use + public uint Reserved; + } + + /// + /// Specifies the architecture of a process and if that architecture of code can run in user mode, kernel mode, and/or under WoW64 + /// on the host operating system. + /// + // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-process_machine_information typedef + // struct _PROCESS_MACHINE_INFORMATION { USHORT ProcessMachine; USHORT Res0; MACHINE_ATTRIBUTES MachineAttributes; } PROCESS_MACHINE_INFORMATION; + [PInvokeData("processthreadsapi.h", MSDNShortId = "NS:processthreadsapi._PROCESS_MACHINE_INFORMATION")] + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + public struct PROCESS_MACHINE_INFORMATION + { + /// + /// An IMAGE_FILE_MACHINE_* value indicating the architecture of the associated process. See the list of architecture values in + /// Image File Machine Constants. + /// + public IMAGE_FILE_MACHINE ProcessMachine; + + /// Reserved. + public ushort Res0; + + /// + /// A value from the MACHINE_ATTRIBUTES enumeration indicating if the process’s architecture can run in user mode, kernel mode, + /// and/or under WOW64 on the host operating system. + /// + public MACHINE_ATTRIBUTES MachineAttributes; + } + /// /// Allows applications to configure a process to terminate if an allocation fails to commit memory. This structure is used by the /// PROCESS_INFORMATION_CLASS class. diff --git a/System/Extensions/ProcessExtension.cs b/System/Extensions/ProcessExtension.cs index 608ff972..eb29a0a8 100644 --- a/System/Extensions/ProcessExtension.cs +++ b/System/Extensions/ProcessExtension.cs @@ -83,6 +83,16 @@ namespace Vanara.Extensions } #endif + /// Retrieves information about the specified process. + /// The type of information to retrieve. + /// + /// A handle to the process. This handle must have the PROCESS_SET_INFORMATION access right. For more information, see Process + /// Security and Access Rights. + /// + /// An object containing the type of information specified by the ProcessInformationClass parameter. + /// Type mismatch. + public static T GetInformation(this Process process) where T : struct => GetProcessInformation(process); + /// /// The function gets the integrity level of the current process. Integrity level is only available on Windows Vista and newer operating systems, thus /// GetProcessIntegrityLevel throws an exception if it is called on systems prior to Windows Vista. @@ -217,6 +227,46 @@ namespace Vanara.Extensions /// public static bool IsRunningAsAdmin(this Process proc) => UAC.IsRunningAsAdmin(proc); + /// + /// Reads data from an area of memory in a specified process. The entire area to be read must be accessible or the operation fails. + /// + /// The type of the structure to read. + /// + /// A handle to the process with memory that is being read. The handle must have PROCESS_VM_READ access to the process. + /// + /// + /// A pointer to the base address in the specified process from which to read. Before any data transfer occurs, the system verifies + /// that all data in the base address and memory of the specified size is accessible for read access, and if it is not accessible + /// the function fails. + /// + /// A value of with the contents from the address space of the specified process. + public static T ReadMemory(this Process process, IntPtr baseAddress) where T : struct + { + using var mem = new SafeCoTaskMemStruct(); + SizeT req = ReadToMem(process, baseAddress, mem); + return mem.Value; + } + + /// + /// Reads data from an area of memory in a specified process. The entire area to be read must be accessible or the operation fails. + /// + /// + /// A handle to the process with memory that is being read. The handle must have PROCESS_VM_READ access to the process. + /// + /// + /// A pointer to the base address in the specified process from which to read. Before any data transfer occurs, the system verifies + /// that all data in the base address and memory of the specified size is accessible for read access, and if it is not accessible + /// the function fails. + /// + /// The number of bytes to be read from the specified process. + /// A buffer with the contents from the address space of the specified process. + public static byte[] ReadMemory(this Process process, IntPtr baseAddress, SizeT size) + { + using var mem = new SafeCoTaskMemHandle(size); + SizeT req = ReadToMem(process, baseAddress, mem); + return mem.GetBytes(0, req); + } + /// Removes a specified system privilege from a process. /// The process from which to remove the privilege. /// The privilege to remove. @@ -234,6 +284,24 @@ namespace Vanara.Extensions ResumeThread(hTh); } + /// Sets information for the specified process. + /// Type of the value to set. + /// + /// A handle to the process. This handle must have the PROCESS_SET_INFORMATION access right. For more information, see + /// Process Security and Access Rights. + /// + /// An object used to set information. + /// + /// If the function succeeds, the return value is nonzero. + /// If the function fails, the return value is zero. To get extended error information, call GetLastError. + /// + public static bool SetInformation(this Process process, in T value) where T : struct + { + if (!CorrespondingTypeAttribute.CanSet(out var ProcessInformationClass)) + throw new ArgumentException("The type specified by the type parameter cannot be retrieved for a process.", nameof(T)); + return SetProcessInformation(process, ProcessInformationClass, value); + } + /// Extension method to start a process with extra flags. /// The process to start. /// The process flags. @@ -410,6 +478,41 @@ namespace Vanara.Extensions return false; } + /// + /// Writes data to an area of memory in a specified process. The entire area to be written to must be accessible or the operation fails. + /// + /// The process memory to be modified. + /// + /// The base address in the specified process to which data is written. Before data transfer occurs, the system verifies that all + /// data in the base address and memory of the specified size is accessible for write access, and if it is not accessible, the + /// function fails. + /// + /// A pointer to the buffer that contains data to be written in the address space of the specified process. + /// The number of bytes to be written to the specified process. + /// The number of bytes transferred into the specified process. + public static SizeT WriteMemory(this Process process, IntPtr baseAddress, IntPtr buffer, SizeT bufferSize) + { + Win32Error.ThrowLastErrorIfFalse(WriteProcessMemory(process, baseAddress, buffer, bufferSize, out var written)); + return written; + } + + /// + /// Writes data to an area of memory in a specified process. The entire area to be written to must be accessible or the operation fails. + /// + /// The process memory to be modified. + /// + /// The base address in the specified process to which data is written. Before data transfer occurs, the system verifies that all + /// data in the base address and memory of the specified size is accessible for write access, and if it is not accessible, the + /// function fails. + /// + /// A pointer to the buffer that contains data to be written in the address space of the specified process. + /// The number of bytes transferred into the specified process. + public static SizeT WriteMemory(this Process process, IntPtr baseAddress, byte[] buffer) + { + Win32Error.ThrowLastErrorIfFalse(WriteProcessMemory(process, baseAddress, buffer, buffer.Length, out var written)); + return written; + } + private static IEnumerable GetChildProcesses(int pid, Dictionary>> allProcs, string machineName, bool allChildren = true) { if (allProcs == null) throw new ArgumentNullException(nameof(allProcs)); @@ -424,5 +527,17 @@ namespace Vanara.Extensions if (retProc != null) yield return retProc; } } + + private static SizeT ReadToMem(Process proc, IntPtr baseAddress, SafeMemoryHandle mem) + { + bool ret; + if ((ret = ReadProcessMemory(proc, baseAddress, mem, mem.Size, out var req)) == false && req > mem.Size) + { + mem.Size = req; + ret = ReadProcessMemory(proc, baseAddress, mem, mem.Size, out req); + } + if (!ret) Win32Error.ThrowLastError(); + return req; + } } }