diff --git a/PInvoke/NtDll/Winternl.cs b/PInvoke/NtDll/Winternl.cs
new file mode 100644
index 00000000..56321a6c
--- /dev/null
+++ b/PInvoke/NtDll/Winternl.cs
@@ -0,0 +1,438 @@
+using System;
+using System.Runtime.InteropServices;
+using Vanara.InteropServices;
+
+namespace Vanara.PInvoke
+{
+ /// Platform invokable enumerated types, constants and functions from ntdll.h
+ public static partial class NtDll
+ {
+ /// The type of process information to be retrieved.
+ [PInvokeData("winternl.h", MSDNShortId = "0eae7899-c40b-4a5f-9e9c-adae021885e7")]
+ public enum PROCESSINFOCLASS
+ {
+ ///
+ /// Retrieves a pointer to a PEB structure that can be used to determine whether the specified process is being debugged, and a
+ /// unique value used by the system to identify the specified process.
+ /// Use the CheckRemoteDebuggerPresent and GetProcessId functions to obtain this information.
+ ///
+ [CorrespondingType(typeof(PROCESS_BASIC_INFORMATION), CorrespondingAction.Get)]
+ ProcessBasicInformation = 0,
+
+ ///
+ /// Retrieves a DWORD_PTR value that is the port number of the debugger for the process. A nonzero value indicates that the
+ /// process is being run under the control of a ring 3 debugger.
+ /// Use the CheckRemoteDebuggerPresent or IsDebuggerPresent function.
+ ///
+ [CorrespondingType(typeof(IntPtr), CorrespondingAction.Get)]
+ ProcessDebugPort = 7,
+
+ ///
+ /// Determines whether the process is running in the WOW64 environment (WOW64 is the x86 emulator that allows Win32-based
+ /// applications to run on 64-bit Windows).
+ /// Use the IsWow64Process2 function to obtain this information.
+ ///
+ [CorrespondingType(typeof(BOOL), CorrespondingAction.Get)]
+ ProcessWow64Information = 26,
+
+ ///
+ /// Retrieves a UNICODE_STRING value containing the name of the image file for the process.
+ /// Use the QueryFullProcessImageName or GetProcessImageFileName function to obtain this information.
+ ///
+ [CorrespondingType(typeof(UNICODE_STRING), CorrespondingAction.Get)]
+ ProcessImageFileName = 27,
+
+ ///
+ /// Retrieves a ULONG value indicating whether the process is considered critical.
+ ///
+ /// Note This value can be used starting in Windows XP with SP3. Starting in Windows 8.1, IsProcessCritical should be used instead.
+ ///
+ ///
+ [CorrespondingType(typeof(BOOL), CorrespondingAction.Get)]
+ ProcessBreakOnTermination = 29,
+
+ ///
+ /// Retrieves a SUBSYSTEM_INFORMATION_TYPE value indicating the subsystem type of the process. The buffer pointed to by the
+ /// ProcessInformation parameter should be large enough to hold a single SUBSYSTEM_INFORMATION_TYPE enumeration.
+ ///
+ [CorrespondingType(typeof(SUBSYSTEM_INFORMATION_TYPE), CorrespondingAction.Get)]
+ ProcessSubsystemInformation = 75,
+ }
+
+ ///
+ /// Indicates the type of subsystem for a process or thread. This enumeration is used in NtQueryInformationProcess and
+ /// NtQueryInformationThread calls.
+ ///
+ // https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ne-ntddk-_subsystem_information_type typedef enum
+ // _SUBSYSTEM_INFORMATION_TYPE { SubsystemInformationTypeWin32, SubsystemInformationTypeWSL, MaxSubsystemInformationType }
+ // SUBSYSTEM_INFORMATION_TYPE, *PSUBSYSTEM_INFORMATION_TYPE;
+ [PInvokeData("ntddk.h", MSDNShortId = "B1E334BF-AAB3-410D-8D10-A750E8459E42")]
+ public enum SUBSYSTEM_INFORMATION_TYPE
+ {
+ /// The subsystem type for the process or thread is Win32.
+ SubsystemInformationTypeWin32,
+
+ ///
+ /// The subsystem type for the process or thread is Windows Subsystem for Linux (WSL). For this process, these members of the
+ /// PS_CREATE_NOTIFY_INFO structure are set as follows: The preceding member values may be NULL.
+ ///
+ SubsystemInformationTypeWSL,
+
+ /// Reserved.
+ MaxSubsystemInformationType,
+ }
+
+ ///
+ ///
+ /// [ NtQueryInformationProcess may be altered or unavailable in future versions of Windows. Applications should use the
+ /// alternate functions listed in this topic.]
+ ///
+ /// Retrieves information about the specified process.
+ ///
+ /// A handle to the process for which information is to be retrieved.
+ ///
+ ///
+ /// The type of process information to be retrieved. This parameter can be one of the following values from the
+ /// PROCESSINFOCLASS enumeration.
+ ///
+ ///
+ ///
+ /// Value
+ /// Meaning
+ ///
+ /// -
+ /// ProcessBasicInformation
0
+ ///
+ /// Retrieves a pointer to a PEB structure that can be used to determine whether the specified process is being debugged, and a
+ /// unique value used by the system to identify the specified process. Use the CheckRemoteDebuggerPresent and GetProcessId functions
+ /// to obtain this information.
+ ///
+ ///
+ /// -
+ /// ProcessDebugPort
7
+ ///
+ /// Retrieves a DWORD_PTR value that is the port number of the debugger for the process. A nonzero value indicates that the process
+ /// is being run under the control of a ring 3 debugger. Use the CheckRemoteDebuggerPresent or IsDebuggerPresent function.
+ ///
+ ///
+ /// -
+ /// ProcessWow64Information
26
+ ///
+ /// Determines whether the process is running in the WOW64 environment (WOW64 is the x86 emulator that allows Win32-based
+ /// applications to run on 64-bit Windows). Use the IsWow64Process2 function to obtain this information.
+ ///
+ ///
+ /// -
+ /// ProcessImageFileName
27
+ ///
+ /// Retrieves a UNICODE_STRING value containing the name of the image file for the process. Use the QueryFullProcessImageName or
+ /// GetProcessImageFileName function to obtain this information.
+ ///
+ ///
+ /// -
+ /// ProcessBreakOnTermination
29
+ /// Retrieves a ULONG value indicating whether the process is considered critical.
+ ///
+ /// -
+ /// ProcessSubsystemInformation
75
+ ///
+ /// Retrieves a SUBSYSTEM_INFORMATION_TYPE value indicating the subsystem type of the process. The buffer pointed to by the
+ /// ProcessInformation parameter should be large enough to hold a single SUBSYSTEM_INFORMATION_TYPE enumeration.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// A pointer to a buffer supplied by the calling application into which the function writes the requested information. The size of
+ /// the information written varies depending on the data type of the ProcessInformationClass parameter:
+ ///
+ /// PROCESS_BASIC_INFORMATION
+ ///
+ /// When the ProcessInformationClass parameter is ProcessBasicInformation, the buffer pointed to by the ProcessInformation
+ /// parameter should be large enough to hold a single PROCESS_BASIC_INFORMATION structure having the following layout:
+ ///
+ ///
+ ///
+ /// The UniqueProcessId member points to the system's unique identifier for this process. Use the GetProcessId function to
+ /// retrieve this information.
+ ///
+ /// The PebBaseAddress member points to a PEB structure.
+ /// The other members of this structure are reserved for internal use by the operating system.
+ /// ULONG_PTR
+ ///
+ /// When the ProcessInformationClass parameter is ProcessWow64Information, the buffer pointed to by the ProcessInformation
+ /// parameter should be large enough to hold a ULONG_PTR. If this value is nonzero, the process is running in a WOW64
+ /// environment; otherwise, if the value is equal to zero, the process is not running in a WOW64 environment.
+ ///
+ /// Use the IsWow64Process2 function to determine whether a process is running in the WOW64 environment.
+ /// UNICODE_STRING
+ ///
+ /// When the ProcessInformationClass parameter is ProcessImageFileName, the buffer pointed to by the ProcessInformation
+ /// parameter should be large enough to hold a UNICODE_STRING structure as well as the string itself. The string stored in
+ /// the Buffer member is the name of the image file.
+ ///
+ ///
+ /// If the buffer is too small, the function fails with the STATUS_INFO_LENGTH_MISMATCH error code and the ReturnLength parameter is
+ /// set to the required buffer size.
+ ///
+ ///
+ /// The size of the buffer pointed to by the ProcessInformation parameter, in bytes.
+ ///
+ /// A pointer to a variable in which the function returns the size of the requested information. If the function was successful,
+ /// this is the size of the information written to the buffer pointed to by the ProcessInformation parameter, but if the buffer was
+ /// too small, this is the minimum size of buffer needed to receive the information successfully.
+ ///
+ ///
+ /// The function returns an NTSTATUS success or error code.
+ ///
+ /// The forms and significance of NTSTATUS error codes are listed in the Ntstatus.h header file available in the DDK, and are
+ /// described in the DDK documentation under Kernel-Mode Driver Architecture / Design Guide / Driver Programming Techniques /
+ /// Logging Errors.
+ ///
+ ///
+ ///
+ ///
+ /// The NtQueryInformationProcess function and the structures that it returns are internal to the operating system and
+ /// subject to change from one release of Windows to another. To maintain the compatibility of your application, it is better to use
+ /// public functions mentioned in the description of the ProcessInformationClass parameter instead.
+ ///
+ ///
+ /// If you do use NtQueryInformationProcess, access the function through run-time dynamic linking. This gives your code an
+ /// opportunity to respond gracefully if the function has been changed or removed from the operating system. Signature changes,
+ /// however, may not be detectable.
+ ///
+ ///
+ /// This function has no associated import library. You must use the LoadLibrary and GetProcAddress functions to dynamically link to Ntdll.dll.
+ ///
+ ///
+ // https://docs.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntqueryinformationprocess __kernel_entry NTSTATUS
+ // NtQueryInformationProcess( IN HANDLE ProcessHandle, IN PROCESSINFOCLASS ProcessInformationClass, OUT PVOID ProcessInformation, IN
+ // ULONG ProcessInformationLength, OUT PULONG ReturnLength );
+ [DllImport(Lib.NtDll, SetLastError = false, ExactSpelling = true)]
+ [PInvokeData("winternl.h", MSDNShortId = "0eae7899-c40b-4a5f-9e9c-adae021885e7")]
+ public static extern NTStatus NtQueryInformationProcess([In] HPROCESS ProcessHandle, PROCESSINFOCLASS ProcessInformationClass, [Out] IntPtr ProcessInformation, uint ProcessInformationLength, out uint ReturnLength);
+
+ ///
+ /// Retrieves information about the specified process.
+ ///
+ /// The type of the structure to retrieve.
+ /// A handle to the process for which information is to be retrieved.
+ ///
+ ///
+ /// The type of process information to be retrieved. This parameter can be one of the following values from the
+ /// PROCESSINFOCLASS enumeration.
+ ///
+ ///
+ ///
+ /// Value
+ /// Meaning
+ ///
+ /// -
+ /// ProcessBasicInformation
0
+ ///
+ /// Retrieves a pointer to a PEB structure that can be used to determine whether the specified process is being debugged, and a
+ /// unique value used by the system to identify the specified process. Use the CheckRemoteDebuggerPresent and GetProcessId functions
+ /// to obtain this information.
+ ///
+ ///
+ /// -
+ /// ProcessDebugPort
7
+ ///
+ /// Retrieves a DWORD_PTR value that is the port number of the debugger for the process. A nonzero value indicates that the process
+ /// is being run under the control of a ring 3 debugger. Use the CheckRemoteDebuggerPresent or IsDebuggerPresent function.
+ ///
+ ///
+ /// -
+ /// ProcessWow64Information
26
+ ///
+ /// Determines whether the process is running in the WOW64 environment (WOW64 is the x86 emulator that allows Win32-based
+ /// applications to run on 64-bit Windows). Use the IsWow64Process2 function to obtain this information.
+ ///
+ ///
+ /// -
+ /// ProcessImageFileName
27
+ ///
+ /// Retrieves a UNICODE_STRING value containing the name of the image file for the process. Use the QueryFullProcessImageName or
+ /// GetProcessImageFileName function to obtain this information.
+ ///
+ ///
+ /// -
+ /// ProcessBreakOnTermination
29
+ /// Retrieves a ULONG value indicating whether the process is considered critical.
+ ///
+ /// -
+ /// ProcessSubsystemInformation
75
+ ///
+ /// Retrieves a SUBSYSTEM_INFORMATION_TYPE value indicating the subsystem type of the process. The buffer pointed to by the
+ /// ProcessInformation parameter should be large enough to hold a single SUBSYSTEM_INFORMATION_TYPE enumeration.
+ ///
+ ///
+ ///
+ ///
+ /// The structure and associated memory for any allocated sub-types.
+ /// Mismatch between requested type and class.
+ public static NtQueryResult NtQueryInformationProcess([In] HPROCESS ProcessHandle, PROCESSINFOCLASS ProcessInformationClass) where T : struct
+ {
+ if (!CorrespondingTypeAttribute.CanGet(ProcessInformationClass, typeof(T))) throw new ArgumentException("Mismatch between requested type and class.");
+ var mem = new NtQueryResult();
+ var status = NtQueryInformationProcess(ProcessHandle, ProcessInformationClass, mem, mem.Size, out var sz);
+ if (status.Succeeded) return mem;
+ if (status != NTStatus.STATUS_INFO_LENGTH_MISMATCH || sz == 0) throw status.GetException();
+ mem.Size = sz;
+ NtQueryInformationProcess(ProcessHandle, ProcessInformationClass, mem, mem.Size, out _).ThrowIfFailed();
+ return mem;
+ }
+
+ ///
+ /// [This structure may be altered in future versions of Windows.]
+ /// Contains process information.
+ ///
+ /// The syntax for this structure on 64-bit Windows is as follows:
+ // https://docs.microsoft.com/en-us/windows/win32/api/winternl/ns-winternl-peb typedef struct _PEB { BYTE Reserved1[2]; BYTE
+ // BeingDebugged; BYTE Reserved2[1]; PVOID Reserved3[2]; PPEB_LDR_DATA Ldr; PRTL_USER_PROCESS_PARAMETERS ProcessParameters; PVOID
+ // Reserved4[3]; PVOID AtlThunkSListPtr; PVOID Reserved5; ULONG Reserved6; PVOID Reserved7; ULONG Reserved8; ULONG
+ // AtlThunkSListPtr32; PVOID Reserved9[45]; BYTE Reserved10[96]; PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine; BYTE
+ // Reserved11[128]; PVOID Reserved12[1]; ULONG SessionId; } PEB, *PPEB;
+ [PInvokeData("winternl.h", MSDNShortId = "836a6b82-d3e8-4de6-808d-5476dfb51356")]
+ [StructLayout(LayoutKind.Sequential)]
+ public struct PEB
+ {
+ /// Reserved for internal use by the operating system.
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
+ private readonly byte[] Reserved_1;
+
+ /// Indicates whether the specified process is currently being debugged.
+ public byte BeingDebugged;
+
+ /// Reserved for internal use by the operating system.
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
+ private readonly byte[] Reserved2;
+
+ /// Reserved for internal use by the operating system.
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
+ private readonly IntPtr[] Reserved3;
+
+ /// A pointer to a PEB_LDR_DATA structure that contains information about the loaded modules for the process.
+ public IntPtr Ldr;
+
+ ///
+ /// A pointer to an RTL_USER_PROCESS_PARAMETERS structure that contains process parameter information such as the command line.
+ ///
+ public IntPtr ProcessParameters;
+
+ /// Reserved for internal use by the operating system.
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
+ private readonly IntPtr[] Reserved4;
+
+ private readonly IntPtr AtlThunkSListPtr;
+
+ /// Reserved for internal use by the operating system.
+ private readonly IntPtr Reserved5;
+
+ /// Reserved for internal use by the operating system.
+ private readonly uint Reserved6;
+
+ /// Reserved for internal use by the operating system.
+ private readonly IntPtr Reserved7;
+
+ /// Reserved for internal use by the operating system.
+ private readonly uint Reserved8;
+
+ ///
+ private readonly uint AtlThunkSListPtr32;
+
+ /// Reserved for internal use by the operating system.
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 45)]
+ private readonly IntPtr[] Reserved9;
+
+ /// Reserved for internal use by the operating system.
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 96)]
+ private readonly byte[] Reserved10;
+
+ ///
+ private readonly IntPtr PostProcessInitRoutine;
+
+ /// Reserved for internal use by the operating system.
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
+ private readonly byte[] Reserved11;
+
+ /// Reserved for internal use by the operating system.
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
+ private readonly IntPtr[] Reserved12;
+
+ /// The Terminal Services session identifier associated with the current process.
+ public uint SessionId;
+ }
+
+ /// Contains information for basic process information.
+ /// https://msdn.microsoft.com/en-us/library/windows/desktop/ms684280(v=vs.85).aspx
+ [StructLayout(LayoutKind.Sequential)]
+ public struct PROCESS_BASIC_INFORMATION
+ {
+ /// Reserved for internal use by the operating system.
+ private readonly IntPtr Reserved1;
+
+ /// Pointer to a PEB structure.
+ public IntPtr PebBaseAddress;
+
+ /// Reserved for internal use by the operating system.
+ private readonly IntPtr Reserved2_1;
+
+ /// Reserved for internal use by the operating system.
+ private readonly IntPtr Reserved2_2;
+
+ /// System's unique identifier for this process.
+ public IntPtr UniqueProcessId;
+
+ /// Reserved for internal use by the operating system.
+ private readonly IntPtr Reserved3;
+ }
+
+ ///
+ /// [This structure may be altered in future versions of Windows.]
+ /// Contains process parameter information.
+ ///
+ // https://docs.microsoft.com/en-us/windows/win32/api/winternl/ns-winternl-rtl_user_process_parameters typedef struct
+ // _RTL_USER_PROCESS_PARAMETERS { BYTE Reserved1[16]; PVOID Reserved2[10]; UNICODE_STRING ImagePathName; UNICODE_STRING CommandLine;
+ // } RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS;
+ [PInvokeData("winternl.h", MSDNShortId = "e736aefa-9945-4526-84d8-adb6e82b9991")]
+ [StructLayout(LayoutKind.Sequential)]
+ public struct RTL_USER_PROCESS_PARAMETERS
+ {
+ /// Reserved for internal use by the operating system.
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
+ private readonly byte[] Reserved1;
+
+ /// Reserved for internal use by the operating system.
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
+ private readonly IntPtr[] Reserved2;
+
+ /// The path of the image file for the process.
+ public UNICODE_STRING ImagePathName;
+
+ /// The command-line string passed to the process.
+ public UNICODE_STRING CommandLine;
+ }
+
+ ///
+ /// Represents the structure and associated memory returned by NtQueryXX functions. The memory associate with this structure
+ /// will be disposed when this variable goes out of scope or is disposed.
+ ///
+ /// The type of the retrieved structure.
+ public class NtQueryResult : SafeMemStruct where T : struct
+ {
+ internal NtQueryResult(uint sz = 0) : base(sz)
+ {
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/UnitTests/PInvoke/NtDll/NtDll.csproj b/UnitTests/PInvoke/NtDll/NtDll.csproj
index f506606c..3362bba2 100644
--- a/UnitTests/PInvoke/NtDll/NtDll.csproj
+++ b/UnitTests/PInvoke/NtDll/NtDll.csproj
@@ -32,6 +32,7 @@
+
@@ -41,6 +42,9 @@
3.15.1
+
+ 4.5.4
+
@@ -55,6 +59,10 @@
{a5e519e9-feba-4fe3-93a5-b8269bef72f4}
Vanara.PInvoke.Shared
+
+ {a96cff10-0967-429a-8700-4a86c97c5603}
+ Shared
+