mirror of https://github.com/dahall/Vanara.git
Added unit tests for psapi.h
Fixed functions that were broken or incomplete Added helper methods for enumerationspull/83/head
parent
0905e01329
commit
6404870776
|
@ -1,6 +1,9 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Vanara.Extensions;
|
||||
using Vanara.InteropServices;
|
||||
|
||||
namespace Vanara.PInvoke
|
||||
{
|
||||
|
@ -13,15 +16,9 @@ namespace Vanara.PInvoke
|
|||
/// for the application-defined function name.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <param name="pContext">
|
||||
/// <para>The user-defined data passed from EnumPageFiles.</para>
|
||||
/// </param>
|
||||
/// <param name="pPageFileInfo">
|
||||
/// <para>A pointer to an ENUM_PAGE_FILE_INFORMATION structure.</para>
|
||||
/// </param>
|
||||
/// <param name="lpFilename">
|
||||
/// <para>The name of the pagefile.</para>
|
||||
/// </param>
|
||||
/// <param name="pContext">The user-defined data passed from EnumPageFiles.</param>
|
||||
/// <param name="pPageFileInfo">A pointer to an ENUM_PAGE_FILE_INFORMATION structure.</param>
|
||||
/// <param name="lpFilename">The name of the pagefile.</param>
|
||||
/// <returns>
|
||||
/// <para>To continue enumeration, the callback function must return TRUE.</para>
|
||||
/// <para>To stop enumeration, the callback function must return FALSE.</para>
|
||||
|
@ -32,7 +29,7 @@ namespace Vanara.PInvoke
|
|||
[UnmanagedFunctionPointer(CallingConvention.Winapi, CharSet = CharSet.Auto)]
|
||||
[PInvokeData("psapi.h", MSDNShortId = "eb3610fb-2c95-4f7b-973d-8dc41d2829f1")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public delegate bool PenumPageFileCallback(IntPtr pContext, ref ENUM_PAGE_FILE_INFORMATION pPageFileInfo, string lpFilename);
|
||||
public delegate bool EnumPageFilesProc(IntPtr pContext, in ENUM_PAGE_FILE_INFORMATION pPageFileInfo, string lpFilename);
|
||||
|
||||
/// <summary>Used by <see cref="EnumProcessModulesEx"/>.</summary>
|
||||
[PInvokeData("psapi.h", MSDNShortId = "0f982f32-31f4-47b6-85d2-d6e17aa4eeb9")]
|
||||
|
@ -85,7 +82,7 @@ namespace Vanara.PInvoke
|
|||
/// </para>
|
||||
/// </remarks>
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/api/psapi/nf-psapi-emptyworkingset BOOL EmptyWorkingSet( HANDLE hProcess );
|
||||
[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
|
||||
[DllImport(Lib.KernelBase, SetLastError = true, ExactSpelling = true)]
|
||||
[PInvokeData("psapi.h", MSDNShortId = "76f2252e-7305-46b0-b1af-40ac084e6696")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool EmptyWorkingSet(HPROCESS hProcess);
|
||||
|
@ -133,11 +130,22 @@ namespace Vanara.PInvoke
|
|||
/// </remarks>
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/api/psapi/nf-psapi-enumdevicedrivers BOOL EnumDeviceDrivers( LPVOID *lpImageBase,
|
||||
// DWORD cb, LPDWORD lpcbNeeded );
|
||||
[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
|
||||
[DllImport(Lib.KernelBase, SetLastError = true, ExactSpelling = true)]
|
||||
[PInvokeData("psapi.h", MSDNShortId = "55925741-da23-44b1-93e8-0e9468434a61")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool EnumDeviceDrivers([In, Out, MarshalAs(UnmanagedType.LPArray)] IntPtr[] lpImageBase, uint cb, out uint lpcbNeeded);
|
||||
|
||||
/// <summary>Retrieves the load address for each device driver in the system.</summary>
|
||||
/// <returns>An array that receives the list of load addresses for the device drivers.</returns>
|
||||
[PInvokeData("psapi.h", MSDNShortId = "55925741-da23-44b1-93e8-0e9468434a61")]
|
||||
public static IntPtr[] EnumDeviceDrivers()
|
||||
{
|
||||
if (!EnumDeviceDrivers(null, 0, out var sz) && sz == 0) Win32Error.ThrowLastError();
|
||||
var ret = new IntPtr[sz / IntPtr.Size];
|
||||
if (!EnumDeviceDrivers(ret, sz, out _)) Win32Error.ThrowLastError();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <para>Calls the callback routine for each installed pagefile in the system.</para>
|
||||
/// </summary>
|
||||
|
@ -171,10 +179,27 @@ namespace Vanara.PInvoke
|
|||
/// </remarks>
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/api/psapi/nf-psapi-enumpagefilesa BOOL EnumPageFilesA( PENUM_PAGE_FILE_CALLBACKA
|
||||
// pCallBackRoutine, LPVOID pContext );
|
||||
[DllImport(Lib.Kernel32, SetLastError = true, CharSet = CharSet.Auto)]
|
||||
[DllImport(Lib.KernelBase, SetLastError = true, CharSet = CharSet.Auto)]
|
||||
[PInvokeData("psapi.h", MSDNShortId = "9289fe3c-a7d9-4acb-aeb6-a50de65db0a2")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool EnumPageFiles(PenumPageFileCallback pCallBackRoutine, IntPtr pContext);
|
||||
public static extern bool EnumPageFiles(EnumPageFilesProc pCallBackRoutine, IntPtr pContext);
|
||||
|
||||
/// <summary>Enumerates the pagefiles in the system.</summary>
|
||||
/// <param name="pContext">The user-defined data passed to the callback routine.</param>
|
||||
/// <returns>A list of ENUM_PAGE_FILE_INFORMATION structures with the associated filename.</returns>
|
||||
[PInvokeData("psapi.h", MSDNShortId = "9289fe3c-a7d9-4acb-aeb6-a50de65db0a2")]
|
||||
public static IEnumerable<(ENUM_PAGE_FILE_INFORMATION pageInfo, string filename)> EnumPageFiles()
|
||||
{
|
||||
var l = new List<(ENUM_PAGE_FILE_INFORMATION pageInfo, string filename)>();
|
||||
if (!EnumPageFiles(callback, default)) Win32Error.ThrowLastError();
|
||||
return l;
|
||||
|
||||
bool callback(IntPtr _, in ENUM_PAGE_FILE_INFORMATION pPageFileInfo, string lpFilename)
|
||||
{
|
||||
l.Add((pPageFileInfo, lpFilename));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <para>Retrieves the process identifier for each process object in the system.</para>
|
||||
|
@ -221,11 +246,27 @@ namespace Vanara.PInvoke
|
|||
/// </remarks>
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/api/psapi/nf-psapi-enumprocesses BOOL EnumProcesses( DWORD *lpidProcess, DWORD
|
||||
// cb, LPDWORD lpcbNeeded );
|
||||
[DllImport(Lib.Kernel32, SetLastError = true, CharSet = CharSet.Auto)]
|
||||
[DllImport(Lib.KernelBase, SetLastError = true, CharSet = CharSet.Auto)]
|
||||
[PInvokeData("psapi.h", MSDNShortId = "0c0445cb-27d2-4857-a4a5-7a4c180b068b")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool EnumProcesses([In, Out, MarshalAs(UnmanagedType.LPArray)] uint[] lpidProcess, uint cb, out uint lpcbNeeded);
|
||||
|
||||
/// <summary>Retrieves the process identifier for each process object in the system.</summary>
|
||||
/// <returns>An array that receives the list of process identifiers.</returns>
|
||||
[PInvokeData("psapi.h", MSDNShortId = "0c0445cb-27d2-4857-a4a5-7a4c180b068b")]
|
||||
public static uint[] EnumProcesses()
|
||||
{
|
||||
uint rsz = 1024, sz;
|
||||
uint[] ret;
|
||||
do
|
||||
{
|
||||
sz = rsz * 2;
|
||||
ret = new uint[sz / sizeof(uint)];
|
||||
if (!EnumProcesses(ret, sz, out rsz)) Win32Error.ThrowLastError();
|
||||
} while (sz == rsz);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <para>Retrieves a handle for each module in the specified process.</para>
|
||||
/// <para>
|
||||
|
@ -301,26 +342,34 @@ namespace Vanara.PInvoke
|
|||
/// </remarks>
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/api/psapi/nf-psapi-enumprocessmodules BOOL EnumProcessModules( HANDLE hProcess,
|
||||
// HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded );
|
||||
[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
|
||||
[DllImport(Lib.KernelBase, SetLastError = true, ExactSpelling = true)]
|
||||
[PInvokeData("psapi.h", MSDNShortId = "b4088506-2f69-4cf0-9bab-3e6a7185f5b2")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool EnumProcessModules(HPROCESS hProcess, [In, Out, MarshalAs(UnmanagedType.LPArray)] IntPtr[] lphModule, uint cb, out uint lpcbNeeded);
|
||||
public static extern bool EnumProcessModules(HPROCESS hProcess, [In, Out, MarshalAs(UnmanagedType.LPArray)] HINSTANCE[] lphModule, uint cb, out uint lpcbNeeded);
|
||||
|
||||
/// <summary>
|
||||
/// <para>Retrieves a handle for each module in the specified process that meets the specified filter criteria.</para>
|
||||
/// <para>Retrieves a handle for each module in the specified process.</para>
|
||||
/// <para>
|
||||
/// To control whether a 64-bit application enumerates 32-bit modules, 64-bit modules, or both types of modules, use the
|
||||
/// EnumProcessModulesEx function.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <param name="hProcess">
|
||||
/// <para>A handle to the process.</para>
|
||||
/// </param>
|
||||
/// <param name="lphModule">
|
||||
/// <para>An array that receives the list of module handles.</para>
|
||||
/// </param>
|
||||
/// <param name="cb">
|
||||
/// <para>The size of the lphModule array, in bytes.</para>
|
||||
/// </param>
|
||||
/// <param name="lpcbNeeded">
|
||||
/// <para>The number of bytes required to store all module handles in the lphModule array.</para>
|
||||
/// </param>
|
||||
/// <param name="hProcess">A handle to the process.</param>
|
||||
/// <returns>An array that receives the list of module handles.</returns>
|
||||
[PInvokeData("psapi.h", MSDNShortId = "b4088506-2f69-4cf0-9bab-3e6a7185f5b2")]
|
||||
public static HINSTANCE[] EnumProcessModules(HPROCESS hProcess)
|
||||
{
|
||||
if (!EnumProcessModules(hProcess, null, 0, out var sz) && sz == 0) Win32Error.ThrowLastError();
|
||||
var ret = new HINSTANCE[sz / IntPtr.Size];
|
||||
if (!EnumProcessModules(hProcess, ret, sz, out _)) Win32Error.ThrowLastError();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// <summary>Retrieves a handle for each module in the specified process that meets the specified filter criteria.</summary>
|
||||
/// <param name="hProcess">A handle to the process.</param>
|
||||
/// <param name="lphModule">An array that receives the list of module handles.</param>
|
||||
/// <param name="cb">The size of the lphModule array, in bytes.</param>
|
||||
/// <param name="lpcbNeeded">The number of bytes required to store all module handles in the lphModule array.</param>
|
||||
/// <param name="dwFilterFlag">
|
||||
/// <para>The filter criteria. This parameter can be one of the following values.</para>
|
||||
/// <list type="table">
|
||||
|
@ -398,12 +447,73 @@ namespace Vanara.PInvoke
|
|||
/// program with –DPSAPI_VERSION=1. To use run-time dynamic linking, load Psapi.dll.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/api/psapi/nf-psapi-enumprocessmodulesex BOOL EnumProcessModulesEx( HANDLE
|
||||
// hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded, DWORD dwFilterFlag );
|
||||
[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-enumprocessmodulesex
|
||||
// BOOL EnumProcessModulesEx( HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded, DWORD dwFilterFlag );
|
||||
[DllImport(Lib.KernelBase, SetLastError = true, CharSet = CharSet.Auto)]
|
||||
[PInvokeData("psapi.h", MSDNShortId = "0f982f32-31f4-47b6-85d2-d6e17aa4eeb9")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool EnumProcessModulesEx(HPROCESS hProcess, [In, Out, MarshalAs(UnmanagedType.LPArray)] IntPtr[] lphModule, uint cb, out uint lpcbNeeded, LIST_MODULES dwFilterFlag);
|
||||
public static extern bool EnumProcessModulesEx(HPROCESS hProcess, [In, Out, MarshalAs(UnmanagedType.LPArray)] HINSTANCE[] lphModule, uint cb, out uint lpcbNeeded, LIST_MODULES dwFilterFlag);
|
||||
|
||||
/// <summary>Retrieves a handle for each module in the specified process that meets the specified filter criteria.</summary>
|
||||
/// <param name="hProcess">A handle to the process.</param>
|
||||
/// <param name="dwFilterFlag">
|
||||
/// <para>The filter criteria. This parameter can be one of the following values.</para>
|
||||
/// <list type="table">
|
||||
/// <listheader>
|
||||
/// <term>Value</term>
|
||||
/// <term>Meaning</term>
|
||||
/// </listheader>
|
||||
/// <item>
|
||||
/// <term>LIST_MODULES_32BIT 0x01</term>
|
||||
/// <term>List the 32-bit modules.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>LIST_MODULES_64BIT 0x02</term>
|
||||
/// <term>List the 64-bit modules.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>LIST_MODULES_ALL 0x03</term>
|
||||
/// <term>List all modules.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>LIST_MODULES_DEFAULT 0x0</term>
|
||||
/// <term>Use the default behavior.</term>
|
||||
/// </item>
|
||||
/// </list>
|
||||
/// </param>
|
||||
/// <returns>An array that receives the list of module handles.</returns>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The <c>EnumProcessModulesEx</c> function is primarily designed for use by debuggers and similar applications that must extract
|
||||
/// module information from another process. If the module list in the target process is corrupted or not yet initialized, or if the
|
||||
/// module list changes during the function call as a result of DLLs being loaded or unloaded, <c>EnumProcessModulesEx</c> may fail
|
||||
/// or return incorrect information.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// This function is intended primarily for 64-bit applications. If the function is called by a 32-bit application running under
|
||||
/// WOW64, the dwFilterFlag option is ignored and the function provides the same results as the EnumProcessModules function.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The <c>EnumProcessModulesEx</c> function does not retrieve handles for modules that were loaded with the
|
||||
/// <c>LOAD_LIBRARY_AS_DATAFILE</c> flag. For more information, see LoadLibraryEx.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Do not call CloseHandle on any of the handles returned by this function. The information comes from a snapshot, so there are no
|
||||
/// resources to be freed.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// To take a snapshot of specified processes and the heaps, modules, and threads used by these processes, use the
|
||||
/// CreateToolhelp32Snapshot function.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
[PInvokeData("psapi.h", MSDNShortId = "0f982f32-31f4-47b6-85d2-d6e17aa4eeb9")]
|
||||
public static HINSTANCE[] EnumProcessModulesEx(HPROCESS hProcess, LIST_MODULES dwFilterFlag = LIST_MODULES.LIST_MODULES_ALL)
|
||||
{
|
||||
if (!EnumProcessModulesEx(hProcess, null, 0, out var sz, dwFilterFlag) && sz == 0) Win32Error.ThrowLastError();
|
||||
var ret = new HINSTANCE[sz / IntPtr.Size];
|
||||
if (!EnumProcessModulesEx(hProcess, ret, sz, out _, dwFilterFlag)) Win32Error.ThrowLastError();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <para>Retrieves the base name of the specified device driver.</para>
|
||||
|
@ -447,7 +557,7 @@ namespace Vanara.PInvoke
|
|||
/// </remarks>
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/api/psapi/nf-psapi-getdevicedriverbasenamea DWORD GetDeviceDriverBaseNameA(
|
||||
// LPVOID ImageBase, LPSTR lpFilename, DWORD nSize );
|
||||
[DllImport(Lib.Kernel32, SetLastError = true, CharSet = CharSet.Auto)]
|
||||
[DllImport(Lib.KernelBase, SetLastError = true, CharSet = CharSet.Auto)]
|
||||
[PInvokeData("psapi.h", MSDNShortId = "a19a927d-4669-4d4c-951e-43f294a8fb40")]
|
||||
public static extern uint GetDeviceDriverBaseName(IntPtr ImageBase, StringBuilder lpFilename, uint nSize);
|
||||
|
||||
|
@ -491,7 +601,7 @@ namespace Vanara.PInvoke
|
|||
/// </remarks>
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/api/psapi/nf-psapi-getdevicedriverfilenamea DWORD GetDeviceDriverFileNameA(
|
||||
// LPVOID ImageBase, LPSTR lpFilename, DWORD nSize );
|
||||
[DllImport(Lib.Kernel32, SetLastError = true, CharSet = CharSet.Auto)]
|
||||
[DllImport(Lib.KernelBase, SetLastError = true, CharSet = CharSet.Auto)]
|
||||
[PInvokeData("psapi.h", MSDNShortId = "6ddbcf7e-e41c-4ea7-b60a-01ed5c98c530")]
|
||||
public static extern uint GetDeviceDriverFileName(IntPtr ImageBase, StringBuilder lpFilename, uint nSize);
|
||||
|
||||
|
@ -567,7 +677,7 @@ namespace Vanara.PInvoke
|
|||
/// </remarks>
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/api/psapi/nf-psapi-getmappedfilenamea DWORD GetMappedFileNameA( HANDLE hProcess,
|
||||
// LPVOID lpv, LPSTR lpFilename, DWORD nSize );
|
||||
[DllImport(Lib.Kernel32, SetLastError = true, CharSet = CharSet.Auto)]
|
||||
[DllImport(Lib.KernelBase, SetLastError = true, CharSet = CharSet.Auto)]
|
||||
[PInvokeData("psapi.h", MSDNShortId = "10a2e5ab-f495-486d-8ef7-ef763716afd1")]
|
||||
public static extern uint GetMappedFileName(HPROCESS hProcess, IntPtr lpv, StringBuilder lpFilename, uint nSize);
|
||||
|
||||
|
@ -639,7 +749,7 @@ namespace Vanara.PInvoke
|
|||
/// </remarks>
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/api/psapi/nf-psapi-getmodulebasenamea DWORD GetModuleBaseNameA( HANDLE hProcess,
|
||||
// HMODULE hModule, LPSTR lpBaseName, DWORD nSize );
|
||||
[DllImport(Lib.Kernel32, SetLastError = true, CharSet = CharSet.Auto)]
|
||||
[DllImport(Lib.KernelBase, SetLastError = true, CharSet = CharSet.Auto)]
|
||||
[PInvokeData("psapi.h", MSDNShortId = "31a9eb69-95f0-4dd7-8fd5-296f2cff0b8a")]
|
||||
public static extern uint GetModuleBaseName(HPROCESS hProcess, [Optional] HINSTANCE hModule, StringBuilder lpBaseName, uint nSize);
|
||||
|
||||
|
@ -689,7 +799,7 @@ namespace Vanara.PInvoke
|
|||
/// </remarks>
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/api/psapi/nf-psapi-getmoduleinformation BOOL GetModuleInformation( HANDLE
|
||||
// hProcess, HMODULE hModule, LPMODULEINFO lpmodinfo, DWORD cb );
|
||||
[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
|
||||
[DllImport(Lib.KernelBase, SetLastError = true, ExactSpelling = true)]
|
||||
[PInvokeData("psapi.h", MSDNShortId = "afb9f4c8-c8ae-4497-96c1-b559cfa2cedf")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool GetModuleInformation(HPROCESS hProcess, HINSTANCE hModule, out MODULEINFO lpmodinfo, uint cb);
|
||||
|
@ -727,10 +837,10 @@ namespace Vanara.PInvoke
|
|||
/// </remarks>
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/api/psapi/nf-psapi-getperformanceinfo BOOL GetPerformanceInfo(
|
||||
// PPERFORMANCE_INFORMATION pPerformanceInformation, DWORD cb );
|
||||
[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
|
||||
[DllImport(Lib.KernelBase, SetLastError = true, ExactSpelling = true)]
|
||||
[PInvokeData("psapi.h", MSDNShortId = "21655278-49da-4e63-a4f9-0ee9f6179f4a")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool GetPerformanceInfo(ref PERFORMANCE_INFORMATION pPerformanceInformation, uint cb);
|
||||
public static extern bool GetPerformanceInfo(out PERFORMANCE_INFORMATION pPerformanceInformation, uint cb);
|
||||
|
||||
/// <summary>
|
||||
/// <para>Retrieves the name of the executable file for the specified process.</para>
|
||||
|
@ -788,7 +898,7 @@ namespace Vanara.PInvoke
|
|||
/// </remarks>
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/api/psapi/nf-psapi-getprocessimagefilenamea DWORD GetProcessImageFileNameA(
|
||||
// HANDLE hProcess, LPSTR lpImageFileName, DWORD nSize );
|
||||
[DllImport(Lib.Kernel32, SetLastError = true, CharSet = CharSet.Auto)]
|
||||
[DllImport(Lib.KernelBase, SetLastError = true, CharSet = CharSet.Auto)]
|
||||
[PInvokeData("psapi.h", MSDNShortId = "819fc2f4-0801-417b-9cbb-d7fd2894634e")]
|
||||
public static extern uint GetProcessImageFileName(HPROCESS hProcess, StringBuilder lpImageFileName, uint nSize);
|
||||
|
||||
|
@ -838,10 +948,10 @@ namespace Vanara.PInvoke
|
|||
/// </remarks>
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/api/psapi/nf-psapi-getprocessmemoryinfo BOOL GetProcessMemoryInfo( HANDLE
|
||||
// Process, PPROCESS_MEMORY_COUNTERS ppsmemCounters, DWORD cb );
|
||||
[DllImport(Lib.Kernel32, SetLastError = true, CharSet = CharSet.Auto)]
|
||||
[DllImport(Lib.KernelBase, SetLastError = true, CharSet = CharSet.Auto)]
|
||||
[PInvokeData("psapi.h", MSDNShortId = "12990e8d-6097-4502-824e-db6c3f76c715")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool GetProcessMemoryInfo(HPROCESS Process, ref PROCESS_MEMORY_COUNTERS ppsmemCounters, uint cb);
|
||||
public static extern bool GetProcessMemoryInfo(HPROCESS Process, out PROCESS_MEMORY_COUNTERS ppsmemCounters, uint cb);
|
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
|
@ -910,11 +1020,53 @@ namespace Vanara.PInvoke
|
|||
/// </remarks>
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/api/psapi/nf-psapi-getwschanges BOOL GetWsChanges( HANDLE hProcess,
|
||||
// PPSAPI_WS_WATCH_INFORMATION lpWatchInfo, DWORD cb );
|
||||
[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
|
||||
[DllImport(Lib.KernelBase, SetLastError = true, ExactSpelling = true)]
|
||||
[PInvokeData("psapi.h", MSDNShortId = "ace5106c-9c7b-4d5f-a69a-c3a8bff0bb2d")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool GetWsChanges(HPROCESS hProcess, IntPtr lpWatchInfo, uint cb);
|
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// Retrieves information about the pages that have been added to the working set of the specified process since the last time this
|
||||
/// function or the InitializeProcessForWsWatch function was called.
|
||||
/// </para>
|
||||
/// <para>To retrieve extended information, use the GetWsChangesEx function.</para>
|
||||
/// </summary>
|
||||
/// <param name="hProcess">A handle to the process. The handle must have the <c>PROCESS_QUERY_INFORMATION</c> access right. For more information, see
|
||||
/// Process Security and Access Rights.</param>
|
||||
/// <param name="sizeHint">The size at which to initially allocate the buffer. The default is 16KB.</param>
|
||||
/// <returns>
|
||||
/// An array of PSAPI_WS_WATCH_INFORMATION structures.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The operating system uses one buffer per process to maintain working set change records. If more than one application (or
|
||||
/// multiple threads in the same application) calls this function with the same process handle, neither application will have a
|
||||
/// complete accounting of the working set changes because each call empties the buffer.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The operating system does not record new change records while it is processing the query (and emptying the buffer). The function
|
||||
/// sets the error code to <c>NO_MORE_ENTRIES</c> if a concurrent query is received while it is processing another query.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
[PInvokeData("psapi.h", MSDNShortId = "ace5106c-9c7b-4d5f-a69a-c3a8bff0bb2d")]
|
||||
public static PSAPI_WS_WATCH_INFORMATION[] GetWsChanges(HPROCESS hProcess, int sizeHint = 1024 * 16)
|
||||
{
|
||||
using (var mem = new SafeHGlobalHandle(sizeHint))
|
||||
{
|
||||
while (!GetWsChanges(hProcess, (IntPtr)mem, (uint)mem.Size))
|
||||
{
|
||||
var err = Win32Error.GetLastError();
|
||||
if (err != Win32Error.ERROR_INSUFFICIENT_BUFFER) throw err.GetException();
|
||||
mem.Size *= 2;
|
||||
}
|
||||
var cb = Marshal.SizeOf(typeof(PSAPI_WS_WATCH_INFORMATION));
|
||||
var c = 0;
|
||||
for (int i = 0; i < mem.Size && Marshal.ReadIntPtr((IntPtr)mem, i) != IntPtr.Zero; c++, i += cb) ;
|
||||
return mem.ToArray<PSAPI_WS_WATCH_INFORMATION>(c);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// Retrieves extended information about the pages that have been added to the working set of the specified process since the last
|
||||
|
@ -977,11 +1129,60 @@ namespace Vanara.PInvoke
|
|||
/// </remarks>
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/api/psapi/nf-psapi-getwschangesex BOOL GetWsChangesEx( HANDLE hProcess,
|
||||
// PPSAPI_WS_WATCH_INFORMATION_EX lpWatchInfoEx, PDWORD cb );
|
||||
[DllImport(Lib.Kernel32, SetLastError = true, CharSet = CharSet.Auto)]
|
||||
[DllImport(Lib.KernelBase, SetLastError = true, CharSet = CharSet.Auto)]
|
||||
[PInvokeData("psapi.h", MSDNShortId = "8572db5c-2ffc-424f-8cec-b6a6902fed62")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool GetWsChangesEx(HPROCESS hProcess, IntPtr lpWatchInfoEx, ref uint cb);
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves extended information about the pages that have been added to the working set of the specified process since the last
|
||||
/// time this function or the InitializeProcessForWsWatch function was called.
|
||||
/// </summary>
|
||||
/// <param name="hProcess">
|
||||
/// A handle to the process. The handle must have the <c>PROCESS_QUERY_INFORMATION</c> access right. For more information, see
|
||||
/// Process Security and Access Rights.
|
||||
/// </param>
|
||||
/// <returns>An array of PSAPI_WS_WATCH_INFORMATION_EX structures.</returns>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The operating system uses one buffer per process to maintain working set change records. If more than one application (or
|
||||
/// multiple threads in the same application) calls this function with the same process handle, neither application will have a
|
||||
/// complete accounting of the working set changes because each call empties the buffer.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The operating system does not record new change records while it is processing the query (and emptying the buffer). This function
|
||||
/// sets the error code to <c>NO_MORE_ENTRIES</c> if a concurrent query is received while it is processing another query.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// If the buffer becomes full, no new records are added to the buffer until this function or the InitializeProcessForWsWatch
|
||||
/// function is called. You should call <c>GetWsChangesEx</c> with enough frequency to prevent possible data loss. If records are
|
||||
/// lost, the array is terminated with a structure whose <c>FaultingPc</c> member is NULL and whose <c>FaultingVa</c> member is set
|
||||
/// to the number of records that were lost.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
[PInvokeData("psapi.h", MSDNShortId = "8572db5c-2ffc-424f-8cec-b6a6902fed62")]
|
||||
public static PSAPI_WS_WATCH_INFORMATION_EX[] GetWsChangesEx(HPROCESS hProcess)
|
||||
{
|
||||
var sz = 0U;
|
||||
if (!GetWsChangesEx(hProcess, IntPtr.Zero, ref sz))
|
||||
{
|
||||
var err = Win32Error.GetLastError();
|
||||
if (err != Win32Error.ERROR_INSUFFICIENT_BUFFER) throw err.GetException();
|
||||
}
|
||||
using (var mem = new SafeHGlobalHandle((int)sz))
|
||||
{
|
||||
if (!GetWsChangesEx(hProcess, (IntPtr)mem, ref sz))
|
||||
{
|
||||
var err = Win32Error.GetLastError();
|
||||
if (err != Win32Error.ERROR_INSUFFICIENT_BUFFER) throw err.GetException();
|
||||
}
|
||||
var cb = Marshal.SizeOf(typeof(PSAPI_WS_WATCH_INFORMATION_EX));
|
||||
var c = 0;
|
||||
for (int i = 0; i < mem.Size && Marshal.ReadIntPtr((IntPtr)mem, i) != IntPtr.Zero; c++, i += cb) ;
|
||||
return mem.ToArray<PSAPI_WS_WATCH_INFORMATION_EX>(c);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// Initiates monitoring of the working set of the specified process. You must call this function before calling the GetWsChanges function.
|
||||
|
@ -1015,7 +1216,7 @@ namespace Vanara.PInvoke
|
|||
/// </remarks>
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/api/psapi/nf-psapi-initializeprocessforwswatch BOOL InitializeProcessForWsWatch(
|
||||
// HANDLE hProcess );
|
||||
[DllImport(Lib.Kernel32, SetLastError = true, CharSet = CharSet.Auto)]
|
||||
[DllImport(Lib.KernelBase, SetLastError = true, CharSet = CharSet.Auto)]
|
||||
[PInvokeData("psapi.h", MSDNShortId = "c928656c-a59d-41b5-9434-911329b0278e")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool InitializeProcessForWsWatch(HPROCESS hProcess);
|
||||
|
@ -1066,11 +1267,43 @@ namespace Vanara.PInvoke
|
|||
/// </remarks>
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/api/psapi/nf-psapi-queryworkingset BOOL QueryWorkingSet( HANDLE hProcess, PVOID
|
||||
// pv, DWORD cb );
|
||||
[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
|
||||
[DllImport(Lib.KernelBase, SetLastError = true, ExactSpelling = true)]
|
||||
[PInvokeData("psapi.h", MSDNShortId = "b932153f-2bbd-460e-8ff7-b3e493c397bb")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool QueryWorkingSet(HPROCESS hProcess, IntPtr pv, uint cb);
|
||||
|
||||
/// <summary>
|
||||
/// <para>Retrieves information about the pages currently added to the working set of the specified process.</para>
|
||||
/// <para>
|
||||
/// To retrieve working set information for a subset of virtual addresses, or to retrieve information about pages that are not part
|
||||
/// of the working set (such as AWE or large pages), use the QueryWorkingSetEx function.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <param name="hProcess">
|
||||
/// <para>
|
||||
/// A handle to the process. The handle must have the <c>PROCESS_QUERY_INFORMATION</c> and <c>PROCESS_VM_READ</c> access rights. For
|
||||
/// more information, see Process Security and Access Rights.
|
||||
/// </para>
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A list of <see cref="PSAPI_WORKING_SET_BLOCK"/> entires.
|
||||
/// </returns>
|
||||
[PInvokeData("psapi.h", MSDNShortId = "b932153f-2bbd-460e-8ff7-b3e493c397bb")]
|
||||
public static PSAPI_WORKING_SET_BLOCK[] QueryWorkingSet(HPROCESS hProcess)
|
||||
{
|
||||
using (var mem = SafeHGlobalHandle.CreateFromStructure<PSAPI_WORKING_SET_INFORMATION>())
|
||||
{
|
||||
var entries = 0;
|
||||
while (!QueryWorkingSet(GetCurrentProcess(), (IntPtr)mem, (uint)mem.Size))
|
||||
{
|
||||
entries = (int)mem.ToStructure<UIntPtr>().ToUInt64();
|
||||
mem.Size = (entries + 1) * UIntPtr.Size + 1024;
|
||||
}
|
||||
entries = (int)mem.ToStructure<UIntPtr>().ToUInt64();
|
||||
return mem.ToArray<PSAPI_WORKING_SET_BLOCK>(entries, UIntPtr.Size);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <para>Retrieves extended information about the pages at specific virtual addresses in the address space of the specified process.</para>
|
||||
/// </summary>
|
||||
|
@ -1118,44 +1351,60 @@ namespace Vanara.PInvoke
|
|||
/// </remarks>
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/api/psapi/nf-psapi-queryworkingsetex BOOL QueryWorkingSetEx( HANDLE hProcess,
|
||||
// PVOID pv, DWORD cb );
|
||||
[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
|
||||
[DllImport(Lib.KernelBase, SetLastError = true, ExactSpelling = true)]
|
||||
[PInvokeData("psapi.h", MSDNShortId = "59ae76c9-e954-4648-9c9f-787136375b02")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool QueryWorkingSetEx(HPROCESS hProcess, IntPtr pv, uint cb);
|
||||
public static extern bool QueryWorkingSetEx(HPROCESS hProcess, [In, Out] PSAPI_WORKING_SET_EX_INFORMATION[] pv, uint cb);
|
||||
|
||||
/// <summary>
|
||||
/// <para>Contains information about a pagefile.</para>
|
||||
/// Retrieves extended information about the pages at specific virtual addresses in the address space of the specified process.
|
||||
/// </summary>
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/api/psapi/ns-psapi-_enum_page_file_information typedef struct
|
||||
// _ENUM_PAGE_FILE_INFORMATION { DWORD cb; DWORD Reserved; SIZE_T TotalSize; SIZE_T TotalInUse; SIZE_T PeakUsage; }
|
||||
// ENUM_PAGE_FILE_INFORMATION, *PENUM_PAGE_FILE_INFORMATION;
|
||||
/// <param name="hProcess">
|
||||
/// A handle to the process. The handle must have the <c>PROCESS_QUERY_INFORMATION</c> and <c>PROCESS_VM_READ</c> access rights. For
|
||||
/// more information, see Process Security and Access Rights.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// An array of PSAPI_WORKING_SET_EX_INFORMATION structures. On input, each item in the array specifies a virtual address of
|
||||
/// interest. On output, each item in the array receives information about the corresponding virtual page.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Unlike the QueryWorkingSet function, which is limited to the working set of the target process, the <c>QueryWorkingSetEx</c>
|
||||
/// function can be used to query addresses that are not in the process working set but are still part of the process, such as AWE
|
||||
/// and large pages.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
[PInvokeData("psapi.h", MSDNShortId = "59ae76c9-e954-4648-9c9f-787136375b02")]
|
||||
public static PSAPI_WORKING_SET_EX_INFORMATION[] QueryWorkingSetEx(HPROCESS hProcess, [Optional] params IntPtr[] virtualAddresses)
|
||||
{
|
||||
var info = virtualAddresses == null || virtualAddresses.Length == 0 ?
|
||||
Array.ConvertAll(QueryWorkingSet(hProcess), b => new PSAPI_WORKING_SET_EX_INFORMATION() { VirtualAddress = b.VirtualPage }) :
|
||||
Array.ConvertAll(virtualAddresses, p => new PSAPI_WORKING_SET_EX_INFORMATION() { VirtualAddress = p });
|
||||
|
||||
var cb = (uint)Marshal.SizeOf(typeof(PSAPI_WORKING_SET_EX_INFORMATION));
|
||||
return QueryWorkingSetEx(hProcess, info, (uint)info.Length * cb) ? info : throw Win32Error.GetLastError().GetException();
|
||||
}
|
||||
|
||||
/// <summary>Contains information about a pagefile.</summary>
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/psapi/ns-psapi-_enum_page_file_information
|
||||
// typedef struct _ENUM_PAGE_FILE_INFORMATION { DWORD cb; DWORD Reserved; SIZE_T TotalSize; SIZE_T TotalInUse; SIZE_T PeakUsage; } ENUM_PAGE_FILE_INFORMATION, *PENUM_PAGE_FILE_INFORMATION;
|
||||
[PInvokeData("psapi.h", MSDNShortId = "020f3be8-f624-4788-8079-0f7679c9bef0")]
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||||
public struct ENUM_PAGE_FILE_INFORMATION
|
||||
{
|
||||
/// <summary>
|
||||
/// <para>The size of this structure, in bytes.</para>
|
||||
/// </summary>
|
||||
/// <summary>The size of this structure, in bytes.</summary>
|
||||
public uint cb;
|
||||
|
||||
/// <summary>
|
||||
/// <para>This member is reserved.</para>
|
||||
/// </summary>
|
||||
/// <summary>This member is reserved.</summary>
|
||||
public uint Reserved;
|
||||
|
||||
/// <summary>
|
||||
/// <para>The total size of the pagefile, in pages.</para>
|
||||
/// </summary>
|
||||
/// <summary>The total size of the pagefile, in pages.</summary>
|
||||
public SizeT TotalSize;
|
||||
|
||||
/// <summary>
|
||||
/// <para>The current pagefile usage, in pages.</para>
|
||||
/// </summary>
|
||||
/// <summary>The current pagefile usage, in pages.</summary>
|
||||
public SizeT TotalInUse;
|
||||
|
||||
/// <summary>
|
||||
/// <para>The peak pagefile usage, in pages.</para>
|
||||
/// </summary>
|
||||
/// <summary>The peak pagefile usage, in pages.</summary>
|
||||
public SizeT PeakUsage;
|
||||
}
|
||||
|
||||
|
@ -1282,6 +1531,9 @@ namespace Vanara.PInvoke
|
|||
/// <para>The current number of threads.</para>
|
||||
/// </summary>
|
||||
public uint ThreadCount;
|
||||
|
||||
/// <summary>A default initialized instance.</summary>
|
||||
public static readonly PERFORMANCE_INFORMATION Default = new PERFORMANCE_INFORMATION { cb = (uint)Marshal.SizeOf(typeof(PERFORMANCE_INFORMATION)) };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -1347,6 +1599,381 @@ namespace Vanara.PInvoke
|
|||
/// <para>The peak value in bytes of the Commit Charge during the lifetime of this process.</para>
|
||||
/// </summary>
|
||||
public SizeT PeakPagefileUsage;
|
||||
|
||||
/// <summary>A default initialized instance.</summary>
|
||||
public static readonly PROCESS_MEMORY_COUNTERS Default = new PROCESS_MEMORY_COUNTERS { cb = (uint)Marshal.SizeOf(typeof(PROCESS_MEMORY_COUNTERS)) };
|
||||
}
|
||||
|
||||
/// <summary>Contains working set information for a page.</summary>
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/psapi/ns-psapi-psapi_working_set_block
|
||||
// typedef union _PSAPI_WORKING_SET_BLOCK { ULONG_PTR Flags; struct { ULONG_PTR Protection : 5; ULONG_PTR ShareCount : 3; ULONG_PTR Shared : 1; ULONG_PTR Reserved : 3; #if ... ULONG_PTR VirtualPage : 52; #elif ULONG_PTR VirtualPage : 52; #elif ULONG_PTR VirtualPage : 20; #else ULONG_PTR VirtualPage : 20; #endif }; } PSAPI_WORKING_SET_BLOCK, *PPSAPI_WORKING_SET_BLOCK;
|
||||
[PInvokeData("psapi.h", MSDNShortId = "feb64235-1003-4595-a6a9-aca1f94f94b8")]
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct PSAPI_WORKING_SET_BLOCK
|
||||
{
|
||||
/// <summary>
|
||||
/// The working set information. See the description of the structure members for information about the layout of this variable.
|
||||
/// </summary>
|
||||
public UIntPtr Flags;
|
||||
|
||||
/// <summary>If <see langword="true"/>, the page is sharable; otherwise, the page is not sharable.</summary>
|
||||
public bool Shared => Flags.ToUInt32().GetBit(9);
|
||||
|
||||
/// <summary>The number of processes that share this page. The maximum value of this member is 7.</summary>
|
||||
public uint ShareCount => Flags.ToUInt32().GetBits(5, 3);
|
||||
|
||||
/// <summary>
|
||||
/// <para>The protection attributes of the page. This member can be one of the following values.</para>
|
||||
/// <list type="table">
|
||||
/// <listheader>
|
||||
/// <term>Value</term>
|
||||
/// <term>Meaning</term>
|
||||
/// </listheader>
|
||||
/// <item>
|
||||
/// <term>0</term>
|
||||
/// <term>The page is not accessed.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>1</term>
|
||||
/// <term>Read-only.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>2</term>
|
||||
/// <term>Executable.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>3</term>
|
||||
/// <term>Executable and read-only.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>4</term>
|
||||
/// <term>Read/write.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>5</term>
|
||||
/// <term>Copy-on-write.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>6</term>
|
||||
/// <term>Executable and read/write.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>7</term>
|
||||
/// <term>Executable and copy-on-write.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>8</term>
|
||||
/// <term>The page is not accessed.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>9</term>
|
||||
/// <term>Non-cacheable and read-only.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>10</term>
|
||||
/// <term>Non-cacheable and executable.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>11</term>
|
||||
/// <term>Non-cacheable, executable, and read-only.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>12</term>
|
||||
/// <term>Non-cacheable and read/write.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>13</term>
|
||||
/// <term>Non-cacheable and copy-on-write.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>14</term>
|
||||
/// <term>Non-cacheable, executable, and read/write.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>15</term>
|
||||
/// <term>Non-cacheable, executable, and copy-on-write.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>16</term>
|
||||
/// <term>The page is not accessed.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>17</term>
|
||||
/// <term>Guard page and read-only.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>18</term>
|
||||
/// <term>Guard page and executable.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>19</term>
|
||||
/// <term>Guard page, executable, and read-only.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>20</term>
|
||||
/// <term>Guard page and read/write.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>21</term>
|
||||
/// <term>Guard page and copy-on-write.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>22</term>
|
||||
/// <term>Guard page, executable, and read/write.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>23</term>
|
||||
/// <term>Guard page, executable, and copy-on-write.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>24</term>
|
||||
/// <term>The page is not accessed.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>25</term>
|
||||
/// <term>Non-cacheable, guard page, and read-only.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>26</term>
|
||||
/// <term>Non-cacheable, guard page, and executable.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>27</term>
|
||||
/// <term>Non-cacheable, guard page, executable, and read-only.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>28</term>
|
||||
/// <term>Non-cacheable, guard page, and read/write.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>29</term>
|
||||
/// <term>Non-cacheable, guard page, and copy-on-write.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>30</term>
|
||||
/// <term>Non-cacheable, guard page, executable, and read/write.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>31</term>
|
||||
/// <term>Non-cacheable, guard page, executable, and copy-on-write.</term>
|
||||
/// </item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
public uint Protection => Flags.ToUInt32().GetBits(0, 5);
|
||||
|
||||
public IntPtr VirtualPage => new IntPtr((long)Flags.ToUInt64() & ~0xFFFL);
|
||||
}
|
||||
|
||||
/// <summary>Contains extended working set information for a page.</summary>
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/psapi/ns-psapi-_psapi_working_set_ex_block
|
||||
// typedef union _PSAPI_WORKING_SET_EX_BLOCK { ULONG_PTR Flags; union { struct { ULONG_PTR Valid : 1; ULONG_PTR ShareCount : 3; ULONG_PTR Win32Protection : 11; ULONG_PTR Shared : 1; ULONG_PTR Node : 6; ULONG_PTR Locked : 1; ULONG_PTR LargePage : 1; ULONG_PTR Reserved : 7; ULONG_PTR Bad : 1; ULONG_PTR ReservedUlong : 32; }; struct { ULONG_PTR Valid : 1; ULONG_PTR Reserved0 : 14; ULONG_PTR Shared : 1; ULONG_PTR Reserved1 : 15; ULONG_PTR Bad : 1; ULONG_PTR ReservedUlong : 32; } Invalid; }; } PSAPI_WORKING_SET_EX_BLOCK, *PPSAPI_WORKING_SET_EX_BLOCK;
|
||||
[PInvokeData("psapi.h", MSDNShortId = "4ba17fa0-2aed-4099-9380-fc13f1b826ca")]
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct PSAPI_WORKING_SET_EX_BLOCK
|
||||
{
|
||||
/// <summary>The working set information. See the description of the structure members for information about the layout of this variable.</summary>
|
||||
public UIntPtr Flags;
|
||||
|
||||
/// <summary>If <see langword="true"/>, the page is valid; otherwise, the page is not valid.</summary>
|
||||
public bool Valid => Flags.ToUInt32().GetBit(0);
|
||||
|
||||
public bool Locked => Valid ? Flags.ToUInt32().GetBit(22) : false;
|
||||
|
||||
public bool LargePage => Valid ? Flags.ToUInt32().GetBit(23) : false;
|
||||
|
||||
public bool Bad => Flags.ToUInt32().GetBit(31);
|
||||
|
||||
/// <summary>If <see langword="true"/>, the page is sharable; otherwise, the page is not sharable.</summary>
|
||||
public bool Shared => Flags.ToUInt32().GetBit(15);
|
||||
|
||||
/// <summary>The number of processes that share this page. The maximum value of this member is 7.</summary>
|
||||
public uint ShareCount => Valid ? Flags.ToUInt32().GetBits(1, 3) : 0U;
|
||||
|
||||
/// <summary>
|
||||
/// <para>The protection attributes of the page. This member can be one of the following values.</para>
|
||||
/// <list type="table">
|
||||
/// <listheader>
|
||||
/// <term>Value</term>
|
||||
/// <term>Meaning</term>
|
||||
/// </listheader>
|
||||
/// <item>
|
||||
/// <term>0</term>
|
||||
/// <term>The page is not accessed.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>1</term>
|
||||
/// <term>Read-only.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>2</term>
|
||||
/// <term>Executable.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>3</term>
|
||||
/// <term>Executable and read-only.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>4</term>
|
||||
/// <term>Read/write.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>5</term>
|
||||
/// <term>Copy-on-write.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>6</term>
|
||||
/// <term>Executable and read/write.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>7</term>
|
||||
/// <term>Executable and copy-on-write.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>8</term>
|
||||
/// <term>The page is not accessed.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>9</term>
|
||||
/// <term>Non-cacheable and read-only.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>10</term>
|
||||
/// <term>Non-cacheable and executable.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>11</term>
|
||||
/// <term>Non-cacheable, executable, and read-only.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>12</term>
|
||||
/// <term>Non-cacheable and read/write.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>13</term>
|
||||
/// <term>Non-cacheable and copy-on-write.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>14</term>
|
||||
/// <term>Non-cacheable, executable, and read/write.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>15</term>
|
||||
/// <term>Non-cacheable, executable, and copy-on-write.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>16</term>
|
||||
/// <term>The page is not accessed.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>17</term>
|
||||
/// <term>Guard page and read-only.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>18</term>
|
||||
/// <term>Guard page and executable.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>19</term>
|
||||
/// <term>Guard page, executable, and read-only.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>20</term>
|
||||
/// <term>Guard page and read/write.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>21</term>
|
||||
/// <term>Guard page and copy-on-write.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>22</term>
|
||||
/// <term>Guard page, executable, and read/write.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>23</term>
|
||||
/// <term>Guard page, executable, and copy-on-write.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>24</term>
|
||||
/// <term>The page is not accessed.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>25</term>
|
||||
/// <term>Non-cacheable, guard page, and read-only.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>26</term>
|
||||
/// <term>Non-cacheable, guard page, and executable.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>27</term>
|
||||
/// <term>Non-cacheable, guard page, executable, and read-only.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>28</term>
|
||||
/// <term>Non-cacheable, guard page, and read/write.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>29</term>
|
||||
/// <term>Non-cacheable, guard page, and copy-on-write.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>30</term>
|
||||
/// <term>Non-cacheable, guard page, executable, and read/write.</term>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>31</term>
|
||||
/// <term>Non-cacheable, guard page, executable, and copy-on-write.</term>
|
||||
/// </item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
public uint Protection => Valid ? Flags.ToUInt32().GetBits(4, 11) : 0U;
|
||||
|
||||
public uint Node => Valid ? Flags.ToUInt32().GetBits(0, 5) : 0U;
|
||||
}
|
||||
|
||||
/// <summary>Contains working set information for a process.</summary>
|
||||
// https://docs.microsoft.com/zh-cn/windows/win32/api/psapi/ns-psapi-psapi_working_set_information typedef struct
|
||||
// _PSAPI_WORKING_SET_INFORMATION { ULONG_PTR NumberOfEntries; PSAPI_WORKING_SET_BLOCK WorkingSetInfo[1]; }
|
||||
// PSAPI_WORKING_SET_INFORMATION, *PPSAPI_WORKING_SET_INFORMATION;
|
||||
[PInvokeData("psapi.h", MSDNShortId = "59ca42c0-ca88-4153-b061-980d961a8ca2")]
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct PSAPI_WORKING_SET_INFORMATION
|
||||
{
|
||||
/// <summary>The number of entries in the <c>WorkingSetInfo</c> array.</summary>
|
||||
public UIntPtr NumberOfEntries;
|
||||
|
||||
/// <summary>An array of PSAPI_WORKING_SET_BLOCK elements, one for each page in the process working set.</summary>
|
||||
public PSAPI_WORKING_SET_BLOCK[] WorkingSetInfo
|
||||
{
|
||||
get
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
fixed (PSAPI_WORKING_SET_INFORMATION* ptr = &this)
|
||||
{
|
||||
var ret = new PSAPI_WORKING_SET_BLOCK[NumberOfEntries.ToUInt64()];
|
||||
var pblk = (PSAPI_WORKING_SET_BLOCK*)(ptr + 1);
|
||||
for (ulong i = 0; i < NumberOfEntries.ToUInt64(); i++)
|
||||
ret[i] = pblk[i];
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Contains extended working set information for a process.</summary>
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/psapi/ns-psapi-_psapi_working_set_ex_information
|
||||
// typedef struct _PSAPI_WORKING_SET_EX_INFORMATION { PVOID VirtualAddress; PSAPI_WORKING_SET_EX_BLOCK VirtualAttributes; } PSAPI_WORKING_SET_EX_INFORMATION, *PPSAPI_WORKING_SET_EX_INFORMATION;
|
||||
[PInvokeData("psapi.h", MSDNShortId = "d3500737-b9af-41a8-bf69-61d0bfbd6ce4")]
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct PSAPI_WORKING_SET_EX_INFORMATION
|
||||
{
|
||||
/// <summary>The virtual address.</summary>
|
||||
public IntPtr VirtualAddress;
|
||||
|
||||
/// <summary>A PSAPI_WORKING_SET_EX_BLOCK union that indicates the attributes of the page at <c>VirtualAddress</c>.</summary>
|
||||
public PSAPI_WORKING_SET_EX_BLOCK VirtualAttributes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
using NUnit.Framework;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using static Vanara.PInvoke.Kernel32;
|
||||
|
||||
namespace Vanara.PInvoke.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class PsApiTests
|
||||
{
|
||||
[Test]
|
||||
public void EmptyWorkingSetTest()
|
||||
{
|
||||
Assert.That(EmptyWorkingSet(GetCurrentProcess()), Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EnumDeviceDriversTest()
|
||||
{
|
||||
Assert.That(EnumDeviceDrivers(), Is.Not.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EnumPageFilesTest()
|
||||
{
|
||||
Assert.That(EnumPageFiles(), Is.Not.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EnumProcessesTest()
|
||||
{
|
||||
Assert.That(EnumProcesses(), Is.Not.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EnumProcessModulesExTest()
|
||||
{
|
||||
Assert.That(EnumProcessModulesEx(GetCurrentProcess()), Is.Not.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EnumProcessModulesTest()
|
||||
{
|
||||
Assert.That(EnumProcessModules(GetCurrentProcess()), Is.Not.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetDeviceDriverBaseFileNameTest()
|
||||
{
|
||||
var imgBase = EnumDeviceDrivers()[0];
|
||||
var sb = new StringBuilder(MAX_PATH);
|
||||
Assert.That(GetDeviceDriverBaseName(imgBase, sb, (uint)sb.Capacity), Is.Not.Zero);
|
||||
TestContext.Write(sb + " : ");
|
||||
sb.Clear();
|
||||
Assert.That(GetDeviceDriverFileName(imgBase, sb, (uint)sb.Capacity), Is.Not.Zero);
|
||||
TestContext.WriteLine(sb);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetModuleInformationTest()
|
||||
{
|
||||
var hMod = EnumProcessModules(GetCurrentProcess())[0];
|
||||
var sb = new StringBuilder(MAX_PATH);
|
||||
Assert.That(GetModuleBaseName(GetCurrentProcess(), hMod, sb, (uint)sb.Capacity), Is.Not.Zero);
|
||||
TestContext.WriteLine(sb);
|
||||
Assert.That(GetModuleInformation(GetCurrentProcess(), hMod, out var modInfo, (uint)Marshal.SizeOf<MODULEINFO>()), Is.True);
|
||||
TestContext.WriteLine(modInfo.SizeOfImage);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetPerformanceInfoTest()
|
||||
{
|
||||
Assert.That(GetPerformanceInfo(out var pi, PERFORMANCE_INFORMATION.Default.cb), Is.True);
|
||||
TestContext.WriteLine($"PgSz = {pi.PageSize}");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetProcessImageFileNameTest()
|
||||
{
|
||||
var sb = new StringBuilder(MAX_PATH);
|
||||
Assert.That(GetProcessImageFileName(GetCurrentProcess(), sb, (uint)sb.Capacity), Is.Not.Zero);
|
||||
TestContext.WriteLine(sb);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetProcessMemoryInfoTest()
|
||||
{
|
||||
Assert.That(GetProcessMemoryInfo(GetCurrentProcess(), out var cnt, PROCESS_MEMORY_COUNTERS.Default.cb), Is.True);
|
||||
TestContext.WriteLine($"PgUse = {cnt.PeakPagefileUsage}");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void QueryWorkingSetTest()
|
||||
{
|
||||
Assert.That(QueryWorkingSet(GetCurrentProcess()), Is.Not.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void QueryWorkingSetExTest()
|
||||
{
|
||||
Assert.That(() =>
|
||||
{
|
||||
var info = QueryWorkingSetEx(GetCurrentProcess());
|
||||
Assert.That(info, Is.Not.Empty);
|
||||
var i1 = QueryWorkingSetEx(GetCurrentProcess(), info[0].VirtualAddress)[0];
|
||||
Assert.That(i1.VirtualAddress, Is.EqualTo(info[0].VirtualAddress));
|
||||
Assert.That(i1.VirtualAttributes.Valid, Is.True);
|
||||
}, Throws.Nothing);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WsWatchExTest()
|
||||
{
|
||||
Assert.That(InitializeProcessForWsWatch(GetCurrentProcess()), Is.True);
|
||||
Assert.That(GetWsChangesEx(GetCurrentProcess()), Is.Not.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void WsWatchTest()
|
||||
{
|
||||
Assert.That(InitializeProcessForWsWatch(GetCurrentProcess()), Is.True);
|
||||
Assert.That(GetWsChanges(GetCurrentProcess()), Is.Not.Empty);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue