using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Vanara.InteropServices;

namespace Vanara.PInvoke
{
	public static partial class Kernel32
	{
		/// <summary>Used by HEAPENTRY32</summary>
		[PInvokeData("tlhelp32.h", MSDNShortId = "c5f1dc66-d44f-4491-b0b7-961b163d0f1f")]
		[Flags]
		public enum HEAPENTRY32_FLAGS
		{
			/// <summary>The memory block has a fixed (unmovable) location.</summary>
			LF32_FIXED = 0x00000001,

			/// <summary>The memory block is not used.</summary>
			LF32_FREE = 0x00000002,

			/// <summary>The memory block location can be moved.</summary>
			LF32_MOVEABLE = 0x00000004,
		}

		/// <summary>Used by HEAPLIST32</summary>
		[PInvokeData("tlhelp32.h", MSDNShortId = "61e01d23-9f15-44c5-9f6d-45df4809ccad")]
		[Flags]
		public enum HEAPLIST32_FLAGS
		{
			/// <summary>Process's default heap</summary>
			HF32_DEFAULT = 1,

			/// <summary>Process's shared heap</summary>
			HF32_SHARED = 2
		}

		/// <summary>Flags used by <see cref="CreateToolhelp32Snapshot"/>.</summary>
		[PInvokeData("tlhelp32.h", MSDNShortId = "df643c25-7558-424c-b187-b3f86ba51358")]
		public enum TH32CS : uint
		{
			/// <summary>Indicates that the snapshot handle is to be inheritable.</summary>
			TH32CS_INHERIT = 0x80000000,

			/// <summary>Includes all heaps of the process specified in th32ProcessID in the snapshot. To enumerate the heaps, see Heap32ListFirst.</summary>
			[CorrespondingType(typeof(HEAPLIST32))]
			TH32CS_SNAPHEAPLIST = 0x00000001,

			/// <summary>
			/// Includes all modules of the process specified in th32ProcessID in the snapshot. To enumerate the modules, see Module32First.
			/// If the function fails with ERROR_BAD_LENGTH, retry the function until it succeeds.
			/// <para>
			/// 64-bit Windows: Using this flag in a 32-bit process includes the 32-bit modules of the process specified in th32ProcessID,
			/// while using it in a 64-bit process includes the 64-bit modules. To include the 32-bit modules of the process specified in
			/// th32ProcessID from a 64-bit process, use the TH32CS_SNAPMODULE32 flag.
			/// </para>
			/// </summary>
			[CorrespondingType(typeof(MODULEENTRY32))]
			TH32CS_SNAPMODULE = 0x00000008,

			/// <summary>
			/// Includes all 32-bit modules of the process specified in th32ProcessID in the snapshot when called from a 64-bit process. This
			/// flag can be combined with TH32CS_SNAPMODULE or TH32CS_SNAPALL. If the function fails with ERROR_BAD_LENGTH, retry the
			/// function until it succeeds.
			/// </summary>
			[CorrespondingType(typeof(MODULEENTRY32))]
			TH32CS_SNAPMODULE32 = 0x00000010,

			/// <summary>Includes all processes in the system in the snapshot. To enumerate the processes, see Process32First.</summary>
			[CorrespondingType(typeof(PROCESSENTRY32))]
			TH32CS_SNAPPROCESS = 0x00000002,

			/// <summary>
			/// Includes all threads in the system in the snapshot. To enumerate the threads, see Thread32First.
			/// <para>
			/// To identify the threads that belong to a specific process, compare its process identifier to the th32OwnerProcessID member of
			/// the THREADENTRY32 structure when enumerating the threads.
			/// </para>
			/// </summary>
			[CorrespondingType(typeof(THREADENTRY32))]
			TH32CS_SNAPTHREAD = 0x00000004,

			/// <summary>
			/// Includes all processes and threads in the system, plus the heaps and modules of the process specified in th32ProcessID.
			/// Equivalent to specifying the TH32CS_SNAPHEAPLIST, TH32CS_SNAPMODULE, TH32CS_SNAPPROCESS, and TH32CS_SNAPTHREAD values
			/// combined using an OR operation ('|').
			/// </summary>
			TH32CS_SNAPALL = TH32CS_SNAPHEAPLIST | TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD | TH32CS_SNAPMODULE,
		}

		/// <summary>
		/// <para>Takes a snapshot of the specified processes, as well as the heaps, modules, and threads used by these processes.</para>
		/// </summary>
		/// <param name="dwFlags">
		/// <para>The portions of the system to be included in the snapshot. This parameter can be one or more of the following values.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>TH32CS_INHERIT 0x80000000</term>
		/// <term>Indicates that the snapshot handle is to be inheritable.</term>
		/// </item>
		/// <item>
		/// <term>TH32CS_SNAPALL</term>
		/// <term>
		/// Includes all processes and threads in the system, plus the heaps and modules of the process specified in . Equivalent to
		/// specifying the TH32CS_SNAPHEAPLIST, TH32CS_SNAPMODULE, TH32CS_SNAPPROCESS, and TH32CS_SNAPTHREAD values combined using an OR
		/// operation ('|').
		/// </term>
		/// </item>
		/// <item>
		/// <term>TH32CS_SNAPHEAPLIST 0x00000001</term>
		/// <term>Includes all heaps of the process specified in in the snapshot. To enumerate the heaps, see Heap32ListFirst.</term>
		/// </item>
		/// <item>
		/// <term>TH32CS_SNAPMODULE 0x00000008</term>
		/// <term>
		/// Includes all modules of the process specified in in the snapshot. To enumerate the modules, see Module32First. If the function
		/// fails with ERROR_BAD_LENGTH, retry the function until it succeeds. 64-bit Windows: Using this flag in a 32-bit process includes
		/// the 32-bit modules of the process specified in , while using it in a 64-bit process includes the 64-bit modules. To include the
		/// 32-bit modules of the process specified in from a 64-bit process, use the TH32CS_SNAPMODULE32 flag.
		/// </term>
		/// </item>
		/// <item>
		/// <term>TH32CS_SNAPMODULE32 0x00000010</term>
		/// <term>
		/// Includes all 32-bit modules of the process specified in in the snapshot when called from a 64-bit process. This flag can be
		/// combined with TH32CS_SNAPMODULE or TH32CS_SNAPALL. If the function fails with ERROR_BAD_LENGTH, retry the function until it succeeds.
		/// </term>
		/// </item>
		/// <item>
		/// <term>TH32CS_SNAPPROCESS 0x00000002</term>
		/// <term>Includes all processes in the system in the snapshot. To enumerate the processes, see Process32First.</term>
		/// </item>
		/// <item>
		/// <term>TH32CS_SNAPTHREAD 0x00000004</term>
		/// <term>
		/// Includes all threads in the system in the snapshot. To enumerate the threads, see Thread32First. To identify the threads that
		/// belong to a specific process, compare its process identifier to the th32OwnerProcessID member of the THREADENTRY32 structure when
		/// enumerating the threads.
		/// </term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="th32ProcessID">
		/// <para>
		/// The process identifier of the process to be included in the snapshot. This parameter can be zero to indicate the current process.
		/// This parameter is used when the <c>TH32CS_SNAPHEAPLIST</c>, <c>TH32CS_SNAPMODULE</c>, <c>TH32CS_SNAPMODULE32</c>, or
		/// <c>TH32CS_SNAPALL</c> value is specified. Otherwise, it is ignored and all processes are included in the snapshot.
		/// </para>
		/// <para>
		/// If the specified process is the Idle process or one of the CSRSS processes, this function fails and the last error code is
		/// <c>ERROR_ACCESS_DENIED</c> because their access restrictions prevent user-level code from opening them.
		/// </para>
		/// <para>
		/// If the specified process is a 64-bit process and the caller is a 32-bit process, this function fails and the last error code is
		/// <c>ERROR_PARTIAL_COPY</c> (299).
		/// </para>
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, it returns an open handle to the specified snapshot.</para>
		/// <para>
		/// If the function fails, it returns <c>INVALID_HANDLE_VALUE</c>. To get extended error information, call GetLastError. Possible
		/// error codes include <c>ERROR_BAD_LENGTH</c>.
		/// </para>
		/// </returns>
		/// <remarks>
		/// <para>
		/// The snapshot taken by this function is examined by the other tool help functions to provide their results. Access to the snapshot
		/// is read only. The snapshot handle acts as an object handle and is subject to the same rules regarding which processes and threads
		/// it is valid in.
		/// </para>
		/// <para>
		/// To enumerate the heap or module states for all processes, specify <c>TH32CS_SNAPALL</c> and set to zero. Then, for each
		/// additional process in the snapshot, call <c>CreateToolhelp32Snapshot</c> again, specifying its process identifier and the
		/// <c>TH32CS_SNAPHEAPLIST</c> or <c>TH32_SNAPMODULE</c> value.
		/// </para>
		/// <para>
		/// When taking snapshots that include heaps and modules for a process other than the current process, the
		/// <c>CreateToolhelp32Snapshot</c> function can fail or return incorrect information for a variety of reasons. For example, if the
		/// loader data table in the target process is corrupted or not initialized, or if the module list changes during the function call
		/// as a result of DLLs being loaded or unloaded, the function might fail with <c>ERROR_BAD_LENGTH</c> or other error code. Ensure
		/// that the target process was not started in a suspended state, and try calling the function again. If the function fails with
		/// <c>ERROR_BAD_LENGTH</c> when called with <c>TH32CS_SNAPMODULE</c> or <c>TH32CS_SNAPMODULE32</c>, call the function again until it succeeds.
		/// </para>
		/// <para>
		/// The <c>TH32CS_SNAPMODULE</c> and <c>TH32CS_SNAPMODULE32</c> flags do not retrieve handles for modules that were loaded with the
		/// <c>LOAD_LIBRARY_AS_DATAFILE</c> or similar flags. For more information, see LoadLibraryEx.
		/// </para>
		/// <para>To destroy the snapshot, use the CloseHandle function.</para>
		/// <para>
		/// Note that you can use the QueryFullProcessImageName function to retrieve the full name of an executable image for both 32- and
		/// 64-bit processes from a 32-bit process.
		/// </para>
		/// <para>Examples</para>
		/// <para>For an example, see Taking a Snapshot and Viewing Processes.</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/tlhelp32/nf-tlhelp32-createtoolhelp32snapshot HANDLE
		// CreateToolhelp32Snapshot( DWORD dwFlags, DWORD th32ProcessID );
		[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("tlhelp32.h", MSDNShortId = "df643c25-7558-424c-b187-b3f86ba51358")]
		public static extern SafeHSNAPSHOT CreateToolhelp32Snapshot(TH32CS dwFlags, [Optional] uint th32ProcessID);

		/// <summary>
		/// <para>Retrieves information about the first block of a heap that has been allocated by a process.</para>
		/// </summary>
		/// <param name="lphe">
		/// <para>A pointer to a HEAPENTRY32 structure.</para>
		/// </param>
		/// <param name="th32ProcessID">
		/// <para>The identifier of the process context that owns the heap.</para>
		/// </param>
		/// <param name="th32HeapID">
		/// <para>The identifier of the heap to be enumerated.</para>
		/// </param>
		/// <returns>
		/// <para>
		/// Returns <c>TRUE</c> if information for the first heap block has been copied to the buffer or <c>FALSE</c> otherwise. The
		/// <c>ERROR_NO_MORE_FILES</c> error value is returned by the GetLastError function if the heap is invalid or empty.
		/// </para>
		/// </returns>
		/// <remarks>
		/// <para>
		/// The calling application must set the <c>dwSize</c> member of HEAPENTRY32 to the size, in bytes, of the structure.
		/// <c>Heap32First</c> changes <c>dwSize</c> to the number of bytes written to the structure. This will never be greater than the
		/// initial value of <c>dwSize</c>, but it may be smaller. If the value is smaller, do not rely on the values of any members whose
		/// offsets are greater than this value.
		/// </para>
		/// <para>To access subsequent blocks of the same heap, use the Heap32Next function.</para>
		/// <para>Examples</para>
		/// <para>For an example, see Traversing the Heap List.</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/tlhelp32/nf-tlhelp32-heap32first BOOL Heap32First( LPHEAPENTRY32 lphe, DWORD
		// th32ProcessID, ULONG_PTR th32HeapID );
		[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("tlhelp32.h", MSDNShortId = "79d01e3a-b11b-46b5-99d0-b445000288a7")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool Heap32First(ref HEAPENTRY32 lphe, uint th32ProcessID, UIntPtr th32HeapID);

		/// <summary>
		/// <para>Retrieves information about the first heap that has been allocated by a specified process.</para>
		/// </summary>
		/// <param name="hSnapshot">
		/// <para>A handle to the snapshot returned from a previous call to the CreateToolhelp32Snapshot function.</para>
		/// </param>
		/// <param name="lphl">
		/// <para>A pointer to a HEAPLIST32 structure.</para>
		/// </param>
		/// <returns>
		/// <para>
		/// Returns <c>TRUE</c> if the first entry of the heap list has been copied to the buffer or <c>FALSE</c> otherwise. The
		/// <c>ERROR_NO_MORE_FILES</c> error value is returned by the GetLastError function when no heap list exists or the snapshot does not
		/// contain heap list information.
		/// </para>
		/// </returns>
		/// <remarks>
		/// <para>
		/// The calling application must set the <c>dwSize</c> member of HEAPLIST32 to the size, in bytes, of the structure.
		/// <c>Heap32ListFirst</c> changes <c>dwSize</c> to the number of bytes written to the structure. This will never be greater than the
		/// initial value of <c>dwSize</c>, but it may be smaller. If the value is smaller, do not rely on the values of any members whose
		/// offsets are greater than this value.
		/// </para>
		/// <para>To retrieve information about other heaps in the heap list, use the Heap32ListNext function.</para>
		/// <para>Examples</para>
		/// <para>For an example, see Traversing the Heap List.</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/tlhelp32/nf-tlhelp32-heap32listfirst BOOL Heap32ListFirst( HANDLE hSnapshot,
		// LPHEAPLIST32 lphl );
		[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("tlhelp32.h", MSDNShortId = "b9a2992b-0dc1-41c3-aa23-796def674831")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool Heap32ListFirst(HSNAPSHOT hSnapshot, ref HEAPLIST32 lphl);

		/// <summary>
		/// <para>Retrieves information about the next heap that has been allocated by a process.</para>
		/// </summary>
		/// <param name="hSnapshot">
		/// <para>A handle to the snapshot returned from a previous call to the CreateToolhelp32Snapshot function.</para>
		/// </param>
		/// <param name="lphl">
		/// <para>A pointer to a HEAPLIST32 structure.</para>
		/// </param>
		/// <returns>
		/// <para>
		/// Returns <c>TRUE</c> if the next entry of the heap list has been copied to the buffer or <c>FALSE</c> otherwise. The
		/// <c>ERROR_NO_MORE_FILES</c> error value is returned by the GetLastError function when no more entries in the heap list exist.
		/// </para>
		/// </returns>
		/// <remarks>
		/// <para>To retrieve information about the first heap in a heap list, use the Heap32ListFirst function.</para>
		/// <para>Examples</para>
		/// <para>For an example, see Traversing the Heap List.</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/tlhelp32/nf-tlhelp32-heap32listnext BOOL Heap32ListNext( HANDLE hSnapshot,
		// LPHEAPLIST32 lphl );
		[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("tlhelp32.h", MSDNShortId = "bb4d573c-a82f-48ac-be22-440d6a1d0c9c")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool Heap32ListNext(HSNAPSHOT hSnapshot, ref HEAPLIST32 lphl);

		/// <summary>
		/// <para>Retrieves information about the next block of a heap that has been allocated by a process.</para>
		/// </summary>
		/// <param name="lphe">
		/// <para>A pointer to a HEAPENTRY32 structure.</para>
		/// </param>
		/// <returns>
		/// <para>
		/// Returns <c>TRUE</c> if information about the next block in the heap has been copied to the buffer or <c>FALSE</c> otherwise. The
		/// GetLastError function returns <c>ERROR_NO_MORE_FILES</c> when no more objects in the heap exist and <c>ERROR_INVALID_DATA</c> if
		/// the heap appears to be corrupt or is modified during the walk in such a way that <c>Heap32Next</c> cannot continue.
		/// </para>
		/// </returns>
		/// <remarks>
		/// <para>To retrieve information for the first block of a heap, use the Heap32First function.</para>
		/// <para>
		/// The <c>Heap32Next</c> function does not maintain a reference to the target process. If the target process dies, the system may
		/// create a new process using the same process identifier. Therefore, the caller should maintain a reference to the target process
		/// as long as it is using <c>Heap32Next</c>.
		/// </para>
		/// <para>Examples</para>
		/// <para>For an example, see Traversing the Heap List.</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/tlhelp32/nf-tlhelp32-heap32next BOOL Heap32Next( LPHEAPENTRY32 lphe );
		[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("tlhelp32.h", MSDNShortId = "cc3becd0-edba-47cf-ac2d-26a5d98390e7")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool Heap32Next(ref HEAPENTRY32 lphe);

		/// <summary>
		/// <para>Retrieves information about the first module associated with a process.</para>
		/// </summary>
		/// <param name="hSnapshot">
		/// <para>A handle to the snapshot returned from a previous call to the CreateToolhelp32Snapshot function.</para>
		/// </param>
		/// <param name="lpme">
		/// <para>A pointer to a MODULEENTRY32 structure.</para>
		/// </param>
		/// <returns>
		/// <para>
		/// Returns <c>TRUE</c> if the first entry of the module list has been copied to the buffer or <c>FALSE</c> otherwise. The
		/// <c>ERROR_NO_MORE_FILES</c> error value is returned by the GetLastError function if no modules exist or the snapshot does not
		/// contain module information.
		/// </para>
		/// </returns>
		/// <remarks>
		/// <para>The calling application must set the <c>dwSize</c> member of MODULEENTRY32 to the size, in bytes, of the structure.</para>
		/// <para>To retrieve information about other modules associated with the specified process, use the Module32Next function.</para>
		/// <para>Examples</para>
		/// <para>For an example, see Traversing the Module List.</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/tlhelp32/nf-tlhelp32-module32first BOOL Module32First( HANDLE hSnapshot,
		// LPMODULEENTRY32 lpme );
		[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("tlhelp32.h", MSDNShortId = "bb41cab9-13a1-469d-bf76-68c172e982f6")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool Module32First(HSNAPSHOT hSnapshot, ref MODULEENTRY32 lpme);

		/// <summary>
		/// <para>Retrieves information about the next module associated with a process or thread.</para>
		/// </summary>
		/// <param name="hSnapshot">
		/// <para>A handle to the snapshot returned from a previous call to the CreateToolhelp32Snapshot function.</para>
		/// </param>
		/// <param name="lpme">
		/// <para>A pointer to a MODULEENTRY32 structure.</para>
		/// </param>
		/// <returns>
		/// <para>
		/// Returns <c>TRUE</c> if the next entry of the module list has been copied to the buffer or <c>FALSE</c> otherwise. The
		/// <c>ERROR_NO_MORE_FILES</c> error value is returned by the GetLastError function if no more modules exist.
		/// </para>
		/// </returns>
		/// <remarks>
		/// <para>To retrieve information about first module associated with a process, use the Module32First function.</para>
		/// <para>Examples</para>
		/// <para>For an example, see Traversing the Module List.</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/tlhelp32/nf-tlhelp32-module32next BOOL Module32Next( HANDLE hSnapshot,
		// LPMODULEENTRY32 lpme );
		[DllImport(Lib.Kernel32, SetLastError = true, CharSet = CharSet.Auto)]
		[PInvokeData("tlhelp32.h", MSDNShortId = "88ec1af4-bae7-4cd7-b830-97a98fb337f4")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool Module32Next(HSNAPSHOT hSnapshot, ref MODULEENTRY32 lpme);

		/// <summary>
		/// <para>Retrieves information about the first process encountered in a system snapshot.</para>
		/// </summary>
		/// <param name="hSnapshot">
		/// <para>A handle to the snapshot returned from a previous call to the CreateToolhelp32Snapshot function.</para>
		/// </param>
		/// <param name="lppe">
		/// <para>
		/// A pointer to a PROCESSENTRY32 structure. It contains process information such as the name of the executable file, the process
		/// identifier, and the process identifier of the parent process.
		/// </para>
		/// </param>
		/// <returns>
		/// <para>
		/// Returns <c>TRUE</c> if the first entry of the process list has been copied to the buffer or <c>FALSE</c> otherwise. The
		/// <c>ERROR_NO_MORE_FILES</c> error value is returned by the GetLastError function if no processes exist or the snapshot does not
		/// contain process information.
		/// </para>
		/// </returns>
		/// <remarks>
		/// <para>The calling application must set the <c>dwSize</c> member of PROCESSENTRY32 to the size, in bytes, of the structure.</para>
		/// <para>To retrieve information about other processes recorded in the same snapshot, use the Process32Next function.</para>
		/// <para>Examples</para>
		/// <para>For an example, see Taking a Snapshot and Viewing Processes.</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/tlhelp32/nf-tlhelp32-process32first BOOL Process32First( HANDLE hSnapshot,
		// LPPROCESSENTRY32 lppe );
		[DllImport(Lib.Kernel32, SetLastError = true, CharSet = CharSet.Auto)]
		[PInvokeData("tlhelp32.h", MSDNShortId = "097790e8-30c2-4b00-9256-fa26e2ceb893")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool Process32First(HSNAPSHOT hSnapshot, ref PROCESSENTRY32 lppe);

		/// <summary>
		/// <para>Retrieves information about the next process recorded in a system snapshot.</para>
		/// </summary>
		/// <param name="hSnapshot">
		/// <para>A handle to the snapshot returned from a previous call to the CreateToolhelp32Snapshot function.</para>
		/// </param>
		/// <param name="lppe">
		/// <para>A pointer to a PROCESSENTRY32 structure.</para>
		/// </param>
		/// <returns>
		/// <para>
		/// Returns <c>TRUE</c> if the next entry of the process list has been copied to the buffer or <c>FALSE</c> otherwise. The
		/// <c>ERROR_NO_MORE_FILES</c> error value is returned by the GetLastError function if no processes exist or the snapshot does not
		/// contain process information.
		/// </para>
		/// </returns>
		/// <remarks>
		/// <para>To retrieve information about the first process recorded in a snapshot, use the Process32First function.</para>
		/// <para>Examples</para>
		/// <para>For an example, see Taking a Snapshot and Viewing Processes.</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/tlhelp32/nf-tlhelp32-process32next BOOL Process32Next( HANDLE hSnapshot,
		// LPPROCESSENTRY32 lppe );
		[DllImport(Lib.Kernel32, SetLastError = true, CharSet = CharSet.Auto)]
		[PInvokeData("tlhelp32.h", MSDNShortId = "843a95fd-27ae-4215-83d0-82fc402b82b6")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool Process32Next(HSNAPSHOT hSnapshot, ref PROCESSENTRY32 lppe);

		/// <summary>
		/// <para>Retrieves information about the first thread of any process encountered in a system snapshot.</para>
		/// </summary>
		/// <param name="hSnapshot">
		/// <para>A handle to the snapshot returned from a previous call to the CreateToolhelp32Snapshot function.</para>
		/// </param>
		/// <param name="lpte">
		/// <para>A pointer to a THREADENTRY32 structure.</para>
		/// </param>
		/// <returns>
		/// <para>
		/// Returns <c>TRUE</c> if the first entry of the thread list has been copied to the buffer or <c>FALSE</c> otherwise. The
		/// <c>ERROR_NO_MORE_FILES</c> error value is returned by the GetLastError function if no threads exist or the snapshot does not
		/// contain thread information.
		/// </para>
		/// </returns>
		/// <remarks>
		/// <para>
		/// The calling application must set the <c>dwSize</c> member of THREADENTRY32 to the size, in bytes, of the structure.
		/// <c>Thread32First</c> changes <c>dwSize</c> to the number of bytes written to the structure. This will never be greater than the
		/// initial value of <c>dwSize</c>, but it may be smaller. If the value is smaller, do not rely on the values of any members whose
		/// offsets are greater than this value.
		/// </para>
		/// <para>To retrieve information about other threads recorded in the same snapshot, use the Thread32Next function.</para>
		/// <para>Examples</para>
		/// <para>For an example, see Traversing the Thread List.</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/tlhelp32/nf-tlhelp32-thread32first BOOL Thread32First( HANDLE hSnapshot,
		// LPTHREADENTRY32 lpte );
		[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("tlhelp32.h", MSDNShortId = "d4cb7a19-850e-43b5-bda5-91be48382d2a")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool Thread32First(HSNAPSHOT hSnapshot, ref THREADENTRY32 lpte);

		/// <summary>
		/// <para>Retrieves information about the next thread of any process encountered in the system memory snapshot.</para>
		/// </summary>
		/// <param name="hSnapshot">
		/// <para>A handle to the snapshot returned from a previous call to the CreateToolhelp32Snapshot function.</para>
		/// </param>
		/// <param name="lpte">
		/// <para>A pointer to a THREADENTRY32 structure.</para>
		/// </param>
		/// <returns>
		/// <para>
		/// Returns <c>TRUE</c> if the next entry of the thread list has been copied to the buffer or <c>FALSE</c> otherwise. The
		/// <c>ERROR_NO_MORE_FILES</c> error value is returned by the GetLastError function if no threads exist or the snapshot does not
		/// contain thread information.
		/// </para>
		/// </returns>
		/// <remarks>
		/// <para>To retrieve information about the first thread recorded in a snapshot, use the Thread32First function.</para>
		/// <para>Examples</para>
		/// <para>For an example, see Traversing the Thread List.</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/tlhelp32/nf-tlhelp32-thread32next BOOL Thread32Next( HANDLE hSnapshot,
		// LPTHREADENTRY32 lpte );
		[DllImport(Lib.Kernel32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("tlhelp32.h", MSDNShortId = "5efe514e-626c-4138-97a0-bdad217c424f")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool Thread32Next(HSNAPSHOT hSnapshot, ref THREADENTRY32 lpte);

		/// <summary>
		/// <para>Copies memory allocated to another process into an application-supplied buffer.</para>
		/// </summary>
		/// <param name="th32ProcessID">
		/// <para>
		/// The identifier of the process whose memory is being copied. This parameter can be zero to copy the memory of the current process.
		/// </para>
		/// </param>
		/// <param name="lpBaseAddress">
		/// <para>
		/// The base address in the specified process to read. Before transferring any data, the system verifies that all data in the base
		/// address and memory of the specified size is accessible for read access. If this is the case, the function proceeds. Otherwise,
		/// the function fails.
		/// </para>
		/// </param>
		/// <param name="lpBuffer">
		/// <para>A pointer to a buffer that receives the contents of the address space of the specified process.</para>
		/// </param>
		/// <param name="cbRead">
		/// <para>The number of bytes to read from the specified process.</para>
		/// </param>
		/// <param name="lpNumberOfBytesRead">
		/// <para>The number of bytes copied to the specified buffer. If this parameter is <c>NULL</c>, it is ignored.</para>
		/// </param>
		/// <returns>
		/// <para>Returns <c>TRUE</c> if successful.</para>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/desktop/api/tlhelp32/nf-tlhelp32-toolhelp32readprocessmemory BOOL
		// Toolhelp32ReadProcessMemory( DWORD th32ProcessID, LPCVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T cbRead, SIZE_T
		// *lpNumberOfBytesRead );
		[DllImport(Lib.Kernel32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("tlhelp32.h", MSDNShortId = "e579b813-32ef-481d-8dc6-f959ec9b6bad")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool Toolhelp32ReadProcessMemory(uint th32ProcessID, IntPtr lpBaseAddress, IntPtr lpBuffer, SizeT cbRead, out SizeT lpNumberOfBytesRead);

		/// <summary>
		/// <para>Describes one entry (block) of a heap that is being examined.</para>
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/tlhelp32/ns-tlhelp32-tagheapentry32 typedef struct tagHEAPENTRY32 { SIZE_T
		// dwSize; HANDLE hHandle; ULONG_PTR dwAddress; SIZE_T dwBlockSize; DWORD dwFlags; DWORD dwLockCount; DWORD dwResvd; DWORD
		// th32ProcessID; ULONG_PTR th32HeapID; } HEAPENTRY32;
		[PInvokeData("tlhelp32.h", MSDNShortId = "c5f1dc66-d44f-4491-b0b7-961b163d0f1f")]
		[StructLayout(LayoutKind.Sequential)]
		public struct HEAPENTRY32
		{
			/// <summary>
			/// <para>
			/// The size of the structure, in bytes. Before calling the Heap32First function, set this member to . If you do not initialize
			/// <c>dwSize</c>, <c>Heap32First</c> fails.
			/// </para>
			/// </summary>
			public SizeT dwSize;

			/// <summary>
			/// <para>A handle to the heap block.</para>
			/// </summary>
			public IntPtr hHandle;

			/// <summary>
			/// <para>The linear address of the start of the block.</para>
			/// </summary>
			public UIntPtr dwAddress;

			/// <summary>
			/// <para>The size of the heap block, in bytes.</para>
			/// </summary>
			public SizeT dwBlockSize;

			/// <summary>
			/// <para>This member can be one of the following values.</para>
			/// <list type="table">
			/// <listheader>
			/// <term>Value</term>
			/// <term>Meaning</term>
			/// </listheader>
			/// <item>
			/// <term>LF32_FIXED</term>
			/// <term>The memory block has a fixed (unmovable) location.</term>
			/// </item>
			/// <item>
			/// <term>LF32_FREE</term>
			/// <term>The memory block is not used.</term>
			/// </item>
			/// <item>
			/// <term>LF32_MOVEABLE</term>
			/// <term>The memory block location can be moved.</term>
			/// </item>
			/// </list>
			/// </summary>
			public uint dwFlags;

			/// <summary>
			/// <para>This member is no longer used and is always set to zero.</para>
			/// </summary>
			public uint dwLockCount;

			/// <summary>
			/// <para>Reserved; do not use or alter.</para>
			/// </summary>
			public uint dwResvd;

			/// <summary>
			/// <para>The identifier of the process that uses the heap.</para>
			/// </summary>
			public uint th32ProcessID;

			/// <summary>
			/// <para>The heap identifier. This is not a handle, and has meaning only to the tool help functions.</para>
			/// </summary>
			public UIntPtr th32HeapID;

			/// <summary>Gets an empty instance with the size value set.</summary>
			public static readonly HEAPENTRY32 Default = new HEAPENTRY32 { dwSize = (uint)Marshal.SizeOf(typeof(HEAPENTRY32)) };
		}

		/// <summary>
		/// <para>Describes an entry from a list that enumerates the heaps used by a specified process.</para>
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/tlhelp32/ns-tlhelp32-tagheaplist32 typedef struct tagHEAPLIST32 { SIZE_T
		// dwSize; DWORD th32ProcessID; ULONG_PTR th32HeapID; DWORD dwFlags; } HEAPLIST32;
		[PInvokeData("tlhelp32.h", MSDNShortId = "61e01d23-9f15-44c5-9f6d-45df4809ccad")]
		[StructLayout(LayoutKind.Sequential)]
		public struct HEAPLIST32
		{
			/// <summary>
			/// <para>
			/// The size of the structure, in bytes. Before calling the Heap32ListFirst function, set this member to . If you do not
			/// initialize <c>dwSize</c>, <c>Heap32ListFirst</c> will fail.
			/// </para>
			/// </summary>
			public SizeT dwSize;

			/// <summary>
			/// <para>The identifier of the process to be examined.</para>
			/// </summary>
			public uint th32ProcessID;

			/// <summary>
			/// <para>The heap identifier. This is not a handle, and has meaning only to the tool help functions.</para>
			/// </summary>
			public UIntPtr th32HeapID;

			/// <summary>
			/// <para>This member can be one of the following values.</para>
			/// <list type="table">
			/// <listheader>
			/// <term>Value</term>
			/// <term>Meaning</term>
			/// </listheader>
			/// <item>
			/// <term>HF32_DEFAULT</term>
			/// <term>Process's default heap</term>
			/// </item>
			/// </list>
			/// </summary>
			public HEAPLIST32_FLAGS dwFlags;

			/// <summary>Gets an empty instance with the size value set.</summary>
			public static readonly HEAPLIST32 Default = new HEAPLIST32 { dwSize = (uint)Marshal.SizeOf(typeof(HEAPLIST32)) };

			/// <summary>Retrieves information about the blocks of a heap that have been allocated by a process.</summary>
			/// <returns>A enumeration of <see cref="HEAPENTRY32"/> structures.</returns>
			public IEnumerable<HEAPENTRY32> EnumHeapEntries()
			{
				var pe = HEAPENTRY32.Default;
				if (!Heap32First(ref pe, th32ProcessID, th32HeapID))
					throw Win32Error.GetLastError().GetException();
				do { yield return pe; } while (Heap32Next(ref pe));
				var err = Win32Error.GetLastError();
				if (err != Win32Error.ERROR_NO_MORE_FILES)
					throw err.GetException();
			}
		}

		/// <summary>Provides a handle to a snapshot.</summary>
		[StructLayout(LayoutKind.Sequential)]
		public struct HSNAPSHOT : IKernelHandle
		{
			private IntPtr handle;

			/// <summary>Initializes a new instance of the <see cref="HSNAPSHOT"/> struct.</summary>
			/// <param name="preexistingHandle">An <see cref="IntPtr"/> object that represents the pre-existing handle to use.</param>
			public HSNAPSHOT(IntPtr preexistingHandle) => handle = preexistingHandle;

			/// <summary>Returns an invalid handle by instantiating a <see cref="HSNAPSHOT"/> object with <see cref="IntPtr.Zero"/>.</summary>
			public static HSNAPSHOT NULL => new HSNAPSHOT(IntPtr.Zero);

			/// <summary>Gets a value indicating whether this instance is a null handle.</summary>
			public bool IsNull => handle == IntPtr.Zero;

			/// <summary>Performs an explicit conversion from <see cref="HSNAPSHOT"/> to <see cref="IntPtr"/>.</summary>
			/// <param name="h">The handle.</param>
			/// <returns>The result of the conversion.</returns>
			public static explicit operator IntPtr(HSNAPSHOT h) => h.handle;

			/// <summary>Performs an implicit conversion from <see cref="IntPtr"/> to <see cref="HSNAPSHOT"/>.</summary>
			/// <param name="h">The pointer to a handle.</param>
			/// <returns>The result of the conversion.</returns>
			public static implicit operator HSNAPSHOT(IntPtr h) => new HSNAPSHOT(h);

			/// <summary>Implements the operator !=.</summary>
			/// <param name="h1">The first handle.</param>
			/// <param name="h2">The second handle.</param>
			/// <returns>The result of the operator.</returns>
			public static bool operator !=(HSNAPSHOT h1, HSNAPSHOT h2) => !(h1 == h2);

			/// <summary>Implements the operator ==.</summary>
			/// <param name="h1">The first handle.</param>
			/// <param name="h2">The second handle.</param>
			/// <returns>The result of the operator.</returns>
			public static bool operator ==(HSNAPSHOT h1, HSNAPSHOT h2) => h1.Equals(h2);

			/// <inheritdoc/>
			public override bool Equals(object obj) => obj is HSNAPSHOT h ? handle == h.handle : false;

			/// <inheritdoc/>
			public override int GetHashCode() => handle.GetHashCode();

			/// <inheritdoc/>
			public IntPtr DangerousGetHandle() => handle;
		}

		/// <summary>
		/// <para>Describes an entry from a list of the modules belonging to the specified process.</para>
		/// </summary>
		/// <remarks>
		/// <para>The <c>modBaseAddr</c> and <c>hModule</c> members are valid only in the context of the process specified by th32ProcessID.</para>
		/// <para>Examples</para>
		/// <para>For an example that uses <c>MODULEENTRY32</c>, see Traversing the Module List.</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/tlhelp32/ns-tlhelp32-tagmoduleentry32 typedef struct tagMODULEENTRY32 { DWORD
		// dwSize; DWORD th32ModuleID; DWORD th32ProcessID; DWORD GlblcntUsage; DWORD ProccntUsage; BYTE *modBaseAddr; DWORD modBaseSize;
		// HMODULE hModule; char szModule[MAX_MODULE_NAME32 + 1]; char szExePath[MAX_PATH]; } MODULEENTRY32;
		[PInvokeData("tlhelp32.h", MSDNShortId = "305fab35-625c-42e3-a434-e2513e4c8870")]
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public struct MODULEENTRY32
		{
			private const int MAX_MODULE_NAME32 = 255;

			/// <summary>
			/// <para>
			/// The size of the structure, in bytes. Before calling the Module32First function, set this member to . If you do not initialize
			/// <c>dwSize</c>, <c>Module32First</c> fails.
			/// </para>
			/// </summary>
			public uint dwSize;

			/// <summary>
			/// <para>This member is no longer used, and is always set to one.</para>
			/// </summary>
			public uint th32ModuleID;

			/// <summary>
			/// <para>The identifier of the process whose modules are to be examined.</para>
			/// </summary>
			public uint th32ProcessID;

			/// <summary>
			/// <para>The load count of the module, which is not generally meaningful, and usually equal to 0xFFFF.</para>
			/// </summary>
			public uint GlblcntUsage;

			/// <summary>
			/// <para>The load count of the module (same as GlblcntUsage), which is not generally meaningful, and usually equal to 0xFFFF.</para>
			/// </summary>
			public uint ProccntUsage;

			/// <summary>
			/// <para>The base address of the module in the context of the owning process.</para>
			/// </summary>
			public IntPtr modBaseAddr;

			/// <summary>
			/// <para>The size of the module, in bytes.</para>
			/// </summary>
			public uint modBaseSize;

			/// <summary>
			/// <para>A handle to the module in the context of the owning process.</para>
			/// </summary>
			public HINSTANCE hModule;

			/// <summary>
			/// <para>The module name.</para>
			/// </summary>
			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_MODULE_NAME32 + 1)]
			public string szModule;

			/// <summary>
			/// <para>The module path.</para>
			/// </summary>
			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)]
			public string szExePath;

			/// <summary>Gets an empty instance with the size value set.</summary>
			public static readonly MODULEENTRY32 Default = new MODULEENTRY32 { dwSize = (uint)Marshal.SizeOf(typeof(MODULEENTRY32)) };
		}

		/// <summary>
		/// <para>Describes an entry from a list of the processes residing in the system address space when a snapshot was taken.</para>
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/tlhelp32/ns-tlhelp32-tagprocessentry32 typedef struct tagPROCESSENTRY32 {
		// DWORD dwSize; DWORD cntUsage; DWORD th32ProcessID; ULONG_PTR th32DefaultHeapID; DWORD th32ModuleID; DWORD cntThreads; DWORD
		// th32ParentProcessID; LONG pcPriClassBase; DWORD dwFlags; CHAR szExeFile[MAX_PATH]; } PROCESSENTRY32;
		[PInvokeData("tlhelp32.h", MSDNShortId = "9e2f7345-52bf-4bfc-9761-90b0b374c727")]
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public struct PROCESSENTRY32
		{
			/// <summary>
			/// <para>
			/// The size of the structure, in bytes. Before calling the Process32First function, set this member to . If you do not
			/// initialize <c>dwSize</c>, <c>Process32First</c> fails.
			/// </para>
			/// </summary>
			public uint dwSize;

			/// <summary>
			/// <para>This member is no longer used and is always set to zero.</para>
			/// </summary>
			public uint cntUsage;

			/// <summary>
			/// <para>The process identifier.</para>
			/// </summary>
			public uint th32ProcessID;

			/// <summary>
			/// <para>This member is no longer used and is always set to zero.</para>
			/// </summary>
			public UIntPtr th32DefaultHeapID;

			/// <summary>
			/// <para>This member is no longer used and is always set to zero.</para>
			/// </summary>
			public uint th32ModuleID;

			/// <summary>
			/// <para>The number of execution threads started by the process.</para>
			/// </summary>
			public uint cntThreads;

			/// <summary>
			/// <para>The identifier of the process that created this process (its parent process).</para>
			/// </summary>
			public uint th32ParentProcessID;

			/// <summary>
			/// <para>The base priority of any threads created by this process.</para>
			/// </summary>
			public int pcPriClassBase;

			/// <summary>
			/// <para>This member is no longer used, and is always set to zero.</para>
			/// </summary>
			public uint dwFlags;

			/// <summary>
			/// <para>
			/// The name of the executable file for the process. To retrieve the full path to the executable file, call the Module32First
			/// function and check the <c>szExePath</c> member of the MODULEENTRY32 structure that is returned. However, if the calling
			/// process is a 32-bit process, you must call the QueryFullProcessImageName function to retrieve the full path of the executable
			/// file for a 64-bit process.
			/// </para>
			/// </summary>
			[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)]
			public string szExeFile;

			/// <summary>Gets an empty instance with the size value set.</summary>
			public static readonly PROCESSENTRY32 Default = new PROCESSENTRY32 { dwSize = (uint)Marshal.SizeOf(typeof(PROCESSENTRY32)) };
		}

		/// <summary>
		/// <para>Describes an entry from a list of the threads executing in the system when a snapshot was taken.</para>
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/tlhelp32/ns-tlhelp32-tagthreadentry32 typedef struct tagTHREADENTRY32 { DWORD
		// dwSize; DWORD cntUsage; DWORD th32ThreadID; DWORD th32OwnerProcessID; LONG tpBasePri; LONG tpDeltaPri; DWORD dwFlags; } THREADENTRY32;
		[PInvokeData("tlhelp32.h", MSDNShortId = "923feca1-8807-4752-8a5a-79075688aabd")]
		[StructLayout(LayoutKind.Sequential)]
		public struct THREADENTRY32
		{
			/// <summary>
			/// <para>
			/// The size of the structure, in bytes. Before calling the Thread32First function, set this member to . If you do not initialize
			/// <c>dwSize</c>, <c>Thread32First</c> fails.
			/// </para>
			/// </summary>
			public uint dwSize;

			/// <summary>
			/// <para>This member is no longer used and is always set to zero.</para>
			/// </summary>
			public uint cntUsage;

			/// <summary>
			/// <para>The thread identifier, compatible with the thread identifier returned by the CreateProcess function.</para>
			/// </summary>
			public uint th32ThreadID;

			/// <summary>
			/// <para>The identifier of the process that created the thread.</para>
			/// </summary>
			public uint th32OwnerProcessID;

			/// <summary>
			/// <para>
			/// The kernel base priority level assigned to the thread. The priority is a number from 0 to 31, with 0 representing the lowest
			/// possible thread priority. For more information, see <c>KeQueryPriorityThread</c>.
			/// </para>
			/// </summary>
			public int tpBasePri;

			/// <summary>
			/// <para>This member is no longer used and is always set to zero.</para>
			/// </summary>
			public int tpDeltaPri;

			/// <summary>
			/// <para>This member is no longer used and is always set to zero.</para>
			/// </summary>
			public uint dwFlags;

			/// <summary>Gets an empty instance with the size value set.</summary>
			public static readonly THREADENTRY32 Default = new THREADENTRY32 { dwSize = (uint)Marshal.SizeOf(typeof(THREADENTRY32)) };
		}

		/// <summary>Provides a <see cref="SafeHandle"/> to a snapshot that releases a created HSNAPSHOT instance at disposal using CloseHandle.</summary>
		public class SafeHSNAPSHOT : SafeKernelHandle
		{
			/// <summary>Initializes a new instance of the <see cref="HSNAPSHOT"/> class and assigns an existing handle.</summary>
			/// <param name="preexistingHandle">An <see cref="IntPtr"/> object that represents the pre-existing handle to use.</param>
			/// <param name="ownsHandle">
			/// <see langword="true"/> to reliably release the handle during the finalization phase; otherwise, <see langword="false"/> (not recommended).
			/// </param>
			public SafeHSNAPSHOT(IntPtr preexistingHandle, bool ownsHandle = true) : base(preexistingHandle, ownsHandle) { }

			private SafeHSNAPSHOT() : base()
			{
			}

			private delegate bool FirstNext<TStruct>(HSNAPSHOT h, ref TStruct str) where TStruct : struct;

			/// <summary>Performs an implicit conversion from <see cref="SafeHSNAPSHOT"/> to <see cref="HSNAPSHOT"/>.</summary>
			/// <param name="h">The safe handle instance.</param>
			/// <returns>The result of the conversion.</returns>
			public static implicit operator HSNAPSHOT(SafeHSNAPSHOT h) => h.handle;

			/// <summary>Retrieves information about the heaps that have been allocated by a specified process.</summary>
			/// <returns>A enumeration of <see cref="HEAPLIST32"/> structures.</returns>
			public IEnumerable<HEAPLIST32> EnumHeap32List() => EnumSnap<HEAPLIST32>(Heap32ListFirst, Heap32ListNext);

			/// <summary>Retrieves information about the modules that are associated with a process.</summary>
			/// <returns>A enumeration of <see cref="MODULEENTRY32"/> structures.</returns>
			public IEnumerable<MODULEENTRY32> EnumModule32() => EnumSnap<MODULEENTRY32>(Module32First, Module32Next);

			/// <summary>Retrieves information about the processes encountered in a system snapshot.</summary>
			/// <returns>A enumeration of <see cref="PROCESSENTRY32"/> structures.</returns>
			public IEnumerable<PROCESSENTRY32> EnumProcess32() => EnumSnap<PROCESSENTRY32>(Process32First, Process32Next);

			/// <summary>Retrieves information about the threads of any process encountered in a system snapshot.</summary>
			/// <returns>A enumeration of <see cref="THREADENTRY32"/> structures.</returns>
			public IEnumerable<THREADENTRY32> EnumThread32() => EnumSnap<THREADENTRY32>(Thread32First, Thread32Next);

			private IEnumerable<TStruct> EnumSnap<TStruct>(FirstNext<TStruct> first, FirstNext<TStruct> next) where TStruct : struct
			{
				var pe = Vanara.Extensions.ReflectionExtensions.GetStaticFieldValue<TStruct>("Default");
				if (!first(handle, ref pe))
					throw Win32Error.GetLastError().GetException();
				do { yield return pe; } while (next(handle, ref pe));
				var err = Win32Error.GetLastError();
				if (err != Win32Error.ERROR_NO_MORE_FILES)
					throw err.GetException();
			}
		}
	}
}