using System;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Security;
namespace Vanara.PInvoke
{
///
/// Formal replacement for the Windows NTStatus definition. In ntstatus.h, it is a defined UINT value. For .NET, this class strongly
/// types the value.
/// The 32-bit value is organized as follows:
///
/// -
/// Bit
/// 0 - 1
/// 2
/// 3
/// 4 - 15
/// 16 - 31
///
/// -
/// Field
/// Sev
/// Customer
/// Reserved
/// Facility
/// Code
///
///
///
///
///
///
[StructLayout(LayoutKind.Sequential)]
[TypeConverter(typeof(NTStatusTypeConverter))]
[PInvokeData("winerr.h")]
public partial struct NTStatus : IComparable, IComparable, IEquatable, IEquatable, IEquatable, IConvertible, IErrorProvider
{
internal readonly int _value;
private const int codeMask = 0xFFFF;
private const uint customerMask = 0x20000000;
private const int FACILITY_NT_BIT = 0x10000000;
private const uint facilityMask = 0x0FFF0000;
private const int facilityShift = 16;
private const uint severityMask = 0xC0000000;
private const int severityShift = 30;
/// Initializes a new instance of the structure.
/// The raw NTStatus value.
public NTStatus(int rawValue) => _value = rawValue;
/// Initializes a new instance of the structure.
/// The raw NTStatus value.
public NTStatus(uint rawValue) => _value = unchecked((int)rawValue);
/// Enumeration of facility codes
[PInvokeData("winerr.h")]
public enum FacilityCode : ushort
{
/// The default facility code.
FACILITY_NULL = 0,
/// The facility debugger
FACILITY_DEBUGGER = 0x1,
/// The facility RPC runtime
FACILITY_RPC_RUNTIME = 0x2,
/// The facility RPC stubs
FACILITY_RPC_STUBS = 0x3,
/// The facility io error code
FACILITY_IO_ERROR_CODE = 0x4,
/// The facility codclass error code
FACILITY_CODCLASS_ERROR_CODE = 0x6,
/// The facility ntwi N32
FACILITY_NTWIN32 = 0x7,
/// The facility ntcert
FACILITY_NTCERT = 0x8,
/// The facility ntsspi
FACILITY_NTSSPI = 0x9,
/// The facility terminal server
FACILITY_TERMINAL_SERVER = 0xA,
/// The faciltiy MUI error code
FACILTIY_MUI_ERROR_CODE = 0xB,
/// The facility usb error code
FACILITY_USB_ERROR_CODE = 0x10,
/// The facility hid error code
FACILITY_HID_ERROR_CODE = 0x11,
/// The facility firewire error code
FACILITY_FIREWIRE_ERROR_CODE = 0x12,
/// The facility cluster error code
FACILITY_CLUSTER_ERROR_CODE = 0x13,
/// The facility acpi error code
FACILITY_ACPI_ERROR_CODE = 0x14,
/// The facility SXS error code
FACILITY_SXS_ERROR_CODE = 0x15,
/// The facility transaction
FACILITY_TRANSACTION = 0x19,
/// The facility commonlog
FACILITY_COMMONLOG = 0x1A,
/// The facility video
FACILITY_VIDEO = 0x1B,
/// The facility filter manager
FACILITY_FILTER_MANAGER = 0x1C,
/// The facility monitor
FACILITY_MONITOR = 0x1D,
/// The facility graphics kernel
FACILITY_GRAPHICS_KERNEL = 0x1E,
/// The facility driver framework
FACILITY_DRIVER_FRAMEWORK = 0x20,
/// The facility fve error code
FACILITY_FVE_ERROR_CODE = 0x21,
/// The facility FWP error code
FACILITY_FWP_ERROR_CODE = 0x22,
/// The facility ndis error code
FACILITY_NDIS_ERROR_CODE = 0x23,
/// The facility TPM
FACILITY_TPM = 0x29,
/// The facility RTPM
FACILITY_RTPM = 0x2A,
/// The facility hypervisor
FACILITY_HYPERVISOR = 0x35,
/// The facility ipsec
FACILITY_IPSEC = 0x36,
/// The facility virtualization
FACILITY_VIRTUALIZATION = 0x37,
/// The facility volmgr
FACILITY_VOLMGR = 0x38,
/// The facility BCD error code
FACILITY_BCD_ERROR_CODE = 0x39,
/// The facility wi N32 k ntuser
FACILITY_WIN32K_NTUSER = 0x3E,
/// The facility wi N32 k ntgdi
FACILITY_WIN32K_NTGDI = 0x3F,
/// The facility resume key filter
FACILITY_RESUME_KEY_FILTER = 0x40,
/// The facility RDBSS
FACILITY_RDBSS = 0x41,
/// The facility BTH att
FACILITY_BTH_ATT = 0x42,
/// The facility secureboot
FACILITY_SECUREBOOT = 0x43,
/// The facility audio kernel
FACILITY_AUDIO_KERNEL = 0x44,
/// The facility VSM
FACILITY_VSM = 0x45,
/// The facility volsnap
FACILITY_VOLSNAP = 0x50,
/// The facility sdbus
FACILITY_SDBUS = 0x51,
/// The facility shared VHDX
FACILITY_SHARED_VHDX = 0x5C,
/// The facility SMB
FACILITY_SMB = 0x5D,
/// The facility interix
FACILITY_INTERIX = 0x99,
/// The facility spaces
FACILITY_SPACES = 0xE7,
/// The facility security core
FACILITY_SECURITY_CORE = 0xE8,
/// The facility system integrity
FACILITY_SYSTEM_INTEGRITY = 0xE9,
/// The facility licensing
FACILITY_LICENSING = 0xEA,
/// The facility platform manifest
FACILITY_PLATFORM_MANIFEST = 0xEB,
/// The facility maximum value
FACILITY_MAXIMUM_VALUE = 0xEC
}
/// A value indicating the severity of an value (bits 30-31).
[PInvokeData("winerr.h")]
public enum SeverityLevel : byte
{
///
/// Indicates a successful NTSTATUS value, such as STATUS_SUCCESS, or the value IO_ERR_RETRY_SUCCEEDED in error log packets.
///
STATUS_SEVERITY_SUCCESS = 0x0,
/// Indicates an informational NTSTATUS value, such as STATUS_SERIAL_MORE_WRITES.
STATUS_SEVERITY_INFORMATIONAL = 0x1,
/// Indicates a warning NTSTATUS value, such as STATUS_DEVICE_PAPER_EMPTY.
STATUS_SEVERITY_WARNING = 0x2,
///
/// Indicates an error NTSTATUS value, such as STATUS_INSUFFICIENT_RESOURCES for a FinalStatus value or
/// IO_ERR_CONFIGURATION_ERROR for an ErrorCode value in error log packets.
///
STATUS_SEVERITY_ERROR = 0x3
}
/// Gets the code portion of the .
/// The code value (bits 0-15).
public ushort Code => GetCode(_value);
/// Gets a value indicating whether this code is customer defined (true) or from Microsoft (false).
/// true if customer defined; otherwise, false.
public bool CustomerDefined => IsCustomerDefined(_value);
/// Gets the facility portion of the .
/// The facility value (bits 16-26).
public FacilityCode Facility => GetFacility(_value);
/// Gets a value indicating whether this is a failure (Severity bit 31 equals 1).
/// true if failed; otherwise, false.
public bool Failed => Severity == SeverityLevel.STATUS_SEVERITY_ERROR;
/// Gets the severity level of the .
/// The severity level.
public SeverityLevel Severity => GetSeverity(_value);
/// Gets a value indicating whether this is a success (Severity bit 31 equals 0).
/// true if succeeded; otherwise, false.
public bool Succeeded => !Failed;
/// Performs an explicit conversion from to .
/// The value.
/// The resulting instance from the conversion.
public static explicit operator HRESULT(NTStatus value) => value.ToHRESULT();
/// Performs an explicit conversion from to .
/// The value.
/// The result of the conversion.
public static explicit operator int(NTStatus value) => value._value;
/// Performs an explicit conversion from to .
/// The value.
/// The result of the conversion.
public static explicit operator uint(NTStatus value) => unchecked((uint)value._value);
/// Gets the code value from a 32-bit value.
/// The 32-bit raw NTStatus value.
/// The code value (bits 0-15).
public static ushort GetCode(int ntstatus) => (ushort)(ntstatus & codeMask);
/// Gets the facility value from a 32-bit value.
/// The 32-bit raw NTStatus value.
/// The facility value (bits 16-26).
public static FacilityCode GetFacility(int ntstatus) => (FacilityCode)((ntstatus & facilityMask) >> facilityShift);
/// Gets the severity value from a 32-bit value.
/// The 32-bit raw NTStatus value.
/// The severity value (bit 31).
public static SeverityLevel GetSeverity(int ntstatus) => (SeverityLevel)((ntstatus & severityMask) >> severityShift);
/// Performs an implicit conversion from to .
/// The value.
/// The result of the conversion.
public static implicit operator NTStatus(int value) => new NTStatus(value);
/// Performs an implicit conversion from to .
/// The value.
/// The result of the conversion.
public static implicit operator NTStatus(uint value) => new NTStatus(value);
/// Performs an implicit conversion from to .
/// The value.
/// The resulting instance from the conversion.
public static implicit operator NTStatus(Win32Error value) => NTSTATUS_FROM_WIN32((uint)value);
/// Gets the customer defined bit from a 32-bit value.
/// The 32-bit raw NTStatus value.
/// true if the customer defined bit is set; otherwise, false.
public static bool IsCustomerDefined(int ntstatus) => (ntstatus & customerMask) > 0;
/// Creates a new from provided values.
/// The severity level.
/// The bit is set for customer-defined values and clear for Microsoft-defined values.
/// The facility.
/// The code.
/// The resulting .
public static NTStatus Make(SeverityLevel severity, bool customerDefined, FacilityCode facility, ushort code) => Make(severity, customerDefined, (ushort)facility, code);
/// Creates a new from provided values.
/// The severity level.
/// The bit is set for customer-defined values and clear for Microsoft-defined values.
/// The facility.
/// The code.
/// The resulting .
public static NTStatus Make(SeverityLevel severity, bool customerDefined, ushort facility, ushort code) =>
new NTStatus(unchecked((int)(((uint)severity << severityShift) | (customerDefined ? customerMask : 0U) | ((uint)facility << facilityShift) | code)));
/// Converts a Win32 error to an NTSTATUS.
/// The Win32 error codex.
/// The equivalent NTSTATUS value.
public static NTStatus NTSTATUS_FROM_WIN32(uint x) => unchecked((int)x) <= 0 ? unchecked((int)x) : unchecked((int)(((x) & 0x0000FFFF) | ((uint)FacilityCode.FACILITY_NTWIN32 << 16) | 0xC0000000U));
/// Implements the operator !=.
/// The first .
/// The second .
/// The result of the operator.
public static bool operator !=(NTStatus hrLeft, NTStatus hrRight) => !(hrLeft == hrRight);
/// Implements the operator !=.
/// The first .
/// The second .
/// The result of the operator.
public static bool operator !=(NTStatus hrLeft, int hrRight) => !(hrLeft == hrRight);
/// Implements the operator !=.
/// The first .
/// The second .
/// The result of the operator.
public static bool operator !=(NTStatus hrLeft, uint hrRight) => !(hrLeft == hrRight);
/// Implements the operator ==.
/// The first .
/// The second .
/// The result of the operator.
public static bool operator ==(NTStatus hrLeft, NTStatus hrRight) => hrLeft.Equals(hrRight);
/// Implements the operator ==.
/// The first .
/// The second .
/// The result of the operator.
public static bool operator ==(NTStatus hrLeft, int hrRight) => hrLeft.Equals(hrRight);
/// Implements the operator ==.
/// The first .
/// The second .
/// The result of the operator.
public static bool operator ==(NTStatus hrLeft, uint hrRight) => hrLeft.Equals(hrRight);
/// Converts the specified NTSTATUS code to its equivalent system error code.
/// The NTSTATUS code to be converted.
///
/// The function returns the corresponding system error code. ERROR_MR_MID_NOT_FOUND is returned when the specified NTSTATUS code
/// does not have a corresponding system error code.
///
[DllImport(Lib.NtDll, ExactSpelling = true)]
[PInvokeData("Winternl.h", MSDNShortId = "ms680600")]
public static extern uint RtlNtStatusToDosError(int status);
///
/// If the supplied raw NTStatus value represents a failure, throw the associated with the optionally
/// supplied message.
///
/// The 32-bit raw NTStatus value.
/// The optional message to assign to the .
public static void ThrowIfFailed(int ntstatus, string message = null) => new NTStatus(ntstatus).ThrowIfFailed(message);
/// Compares the current object with another object of the same type.
/// An object to compare with this object.
///
/// A value that indicates the relative order of the objects being compared. The return value has the following
/// meanings: Value Meaning Less than zero This object is less than the parameter.Zero This object is equal
/// to . Greater than zero This object is greater than .
///
public int CompareTo(NTStatus other) => _value.CompareTo(other._value);
///
/// Compares the current instance with another object of the same type and returns an integer that indicates whether the current
/// instance precedes, follows, or occurs in the same position in the sort order as the other object.
///
/// An object to compare with this instance.
///
/// A value that indicates the relative order of the objects being compared. The return value has these meanings: Value Meaning Less
/// than zero This instance precedes in the sort order. Zero This instance occurs in the same position in the
/// sort order as . Greater than zero This instance follows in the sort order.
///
public int CompareTo(object obj)
{
var v = ValueFromObj(obj);
return v.HasValue
? _value.CompareTo(v.Value)
: throw new ArgumentException(@"Object cannot be converted to a UInt32 value for comparison.", nameof(obj));
}
/// Indicates whether the current object is equal to an .
/// An object to compare with this object.
/// true if the current object is equal to the parameter; otherwise, false.
public bool Equals(int other) => other == _value;
/// Indicates whether the current object is equal to an .
/// An object to compare with this object.
/// true if the current object is equal to the parameter; otherwise, false.
public bool Equals(uint other) => unchecked((int)other) == _value;
/// Determines whether the specified , is equal to this instance.
/// The to compare with this instance.
/// true if the specified is equal to this instance; otherwise, false.
public override bool Equals(object obj) => obj switch
{
null => false,
NTStatus n => Equals(n),
int i => Equals(i),
uint u => Equals(u),
_ => Equals(_value, ValueFromObj(obj)),
};
/// Indicates whether the current object is equal to another object of the same type.
/// An object to compare with this object.
/// true if the current object is equal to the parameter; otherwise, false.
public bool Equals(NTStatus other) => other._value == _value;
/// Gets the .NET associated with the NTStatus value and optionally adds the supplied message.
/// The optional message to assign to the .
/// The associated or null if this NTStatus is not a failure.
[SecurityCritical]
[SecuritySafeCritical]
public Exception GetException(string message = null) => !Failed ? null : ToHRESULT().GetException(message);
/// Returns a hash code for this instance.
/// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
public override int GetHashCode() => _value;
///
/// If this represents a failure, throw the associated with the optionally supplied message.
///
/// The optional message to assign to the .
[SecurityCritical]
[SecuritySafeCritical]
public void ThrowIfFailed(string message = null)
{
var exception = GetException(message);
if (exception != null)
throw exception;
}
/// Converts this error to an .
/// An equivalent .
public HRESULT ToHRESULT()
{
Win32Error werr = RtlNtStatusToDosError(_value);
return werr != Win32Error.ERROR_MR_MID_NOT_FOUND ? (HRESULT)werr : HRESULT_FROM_NT(_value);
}
/// Returns a that represents this instance.
/// A that represents this instance.
public override string ToString()
{
// Check for defined NTStatus value
StaticFieldValueHash.TryGetFieldName(_value, out var err);
var msg = HRESULT.FormatMessage(unchecked((uint)_value));
return (err ?? string.Format(CultureInfo.InvariantCulture, "0x{0:X8}", _value)) + (msg == null ? "" : ": " + msg);
}
TypeCode IConvertible.GetTypeCode() => _value.GetTypeCode();
bool IConvertible.ToBoolean(IFormatProvider provider) => Succeeded;
byte IConvertible.ToByte(IFormatProvider provider) => ((IConvertible)_value).ToByte(provider);
char IConvertible.ToChar(IFormatProvider provider) => throw new NotSupportedException();
DateTime IConvertible.ToDateTime(IFormatProvider provider) => throw new NotSupportedException();
decimal IConvertible.ToDecimal(IFormatProvider provider) => ((IConvertible)_value).ToDecimal(provider);
double IConvertible.ToDouble(IFormatProvider provider) => ((IConvertible)_value).ToDouble(provider);
short IConvertible.ToInt16(IFormatProvider provider) => ((IConvertible)_value).ToInt16(provider);
int IConvertible.ToInt32(IFormatProvider provider) => _value;
long IConvertible.ToInt64(IFormatProvider provider) => ((IConvertible)_value).ToInt64(provider);
sbyte IConvertible.ToSByte(IFormatProvider provider) => ((IConvertible)_value).ToSByte(provider);
float IConvertible.ToSingle(IFormatProvider provider) => ((IConvertible)_value).ToSingle(provider);
string IConvertible.ToString(IFormatProvider provider) => ToString();
object IConvertible.ToType(Type conversionType, IFormatProvider provider) =>
((IConvertible)_value).ToType(conversionType, provider);
ushort IConvertible.ToUInt16(IFormatProvider provider) => ((IConvertible)unchecked((uint)_value)).ToUInt16(provider);
uint IConvertible.ToUInt32(IFormatProvider provider) => unchecked((uint)_value);
ulong IConvertible.ToUInt64(IFormatProvider provider) => ((IConvertible)unchecked((uint)_value)).ToUInt64(provider);
[ExcludeFromCodeCoverage]
private static HRESULT HRESULT_FROM_NT(int ntStatus) => ntStatus | FACILITY_NT_BIT;
private static int? ValueFromObj(object obj)
{
switch (obj)
{
case null:
return null;
case int i:
return i;
case uint u:
return unchecked((int)u);
default:
var c = TypeDescriptor.GetConverter(obj);
return c.CanConvertTo(typeof(int)) ? (int?)c.ConvertTo(obj, typeof(int)) : null;
}
}
}
internal class NTStatusTypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType.IsPrimitive && sourceType != typeof(char))
return true;
return base.CanConvertFrom(context, sourceType);
}
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(string) || destinationType.IsPrimitive && destinationType != typeof(char))
return true;
return base.CanConvertTo(context, destinationType);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value != null && value.GetType().IsPrimitive)
{
if (value is bool b)
return b ? NTStatus.STATUS_SUCCESS : NTStatus.STATUS_UNSUCCESSFUL;
if (!(value is char))
return new NTStatus((int)Convert.ChangeType(value, TypeCode.Int32));
}
return base.ConvertFrom(context, culture, value);
}
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value,
Type destinationType)
{
if (!(value is NTStatus)) throw new NotSupportedException();
if (destinationType.IsPrimitive && destinationType != typeof(char))
return Convert.ChangeType((NTStatus)value, destinationType);
if (destinationType == typeof(string))
return ((NTStatus)value).ToString();
return base.ConvertTo(context, culture, value, destinationType);
}
}
}