Vanara/PInvoke/Shared/WinError/NTStatus.cs

585 lines
25 KiB
C#

using System;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Security;
namespace Vanara.PInvoke
{
/// <summary>
/// Formal replacement for the Windows NTStatus definition. In ntstatus.h, it is a defined UINT value. For .NET, this class strongly
/// types the value.
/// <para>The 32-bit value is organized as follows:</para>
/// <list type="table">
/// <item>
/// <term>Bit</term>
/// <description>0 - 1</description>
/// <description>2</description>
/// <description>3</description>
/// <description>4 - 15</description>
/// <description>16 - 31</description>
/// </item>
/// <item>
/// <term>Field</term>
/// <description>Sev</description>
/// <description>Customer</description>
/// <description>Reserved</description>
/// <description>Facility</description>
/// <description>Code</description>
/// </item>
/// </list>
/// </summary>
/// <seealso cref="System.IComparable"/>
/// <seealso cref="System.IComparable{NTStatus}"/>
/// <seealso cref="System.IEquatable{NTStatus}"/>
[StructLayout(LayoutKind.Sequential)]
[TypeConverter(typeof(NTStatusTypeConverter))]
[PInvokeData("winerr.h")]
public partial struct NTStatus : IComparable, IComparable<NTStatus>, IEquatable<NTStatus>, IEquatable<int>, IEquatable<uint>, 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;
/// <summary>Initializes a new instance of the <see cref="NTStatus"/> structure.</summary>
/// <param name="rawValue">The raw NTStatus value.</param>
public NTStatus(int rawValue) => _value = rawValue;
/// <summary>Initializes a new instance of the <see cref="NTStatus"/> structure.</summary>
/// <param name="rawValue">The raw NTStatus value.</param>
public NTStatus(uint rawValue) => _value = unchecked((int)rawValue);
/// <summary>Enumeration of facility codes</summary>
[PInvokeData("winerr.h")]
public enum FacilityCode : ushort
{
/// <summary>The default facility code.</summary>
FACILITY_NULL = 0,
/// <summary>The facility debugger</summary>
FACILITY_DEBUGGER = 0x1,
/// <summary>The facility RPC runtime</summary>
FACILITY_RPC_RUNTIME = 0x2,
/// <summary>The facility RPC stubs</summary>
FACILITY_RPC_STUBS = 0x3,
/// <summary>The facility io error code</summary>
FACILITY_IO_ERROR_CODE = 0x4,
/// <summary>The facility codclass error code</summary>
FACILITY_CODCLASS_ERROR_CODE = 0x6,
/// <summary>The facility ntwi N32</summary>
FACILITY_NTWIN32 = 0x7,
/// <summary>The facility ntcert</summary>
FACILITY_NTCERT = 0x8,
/// <summary>The facility ntsspi</summary>
FACILITY_NTSSPI = 0x9,
/// <summary>The facility terminal server</summary>
FACILITY_TERMINAL_SERVER = 0xA,
/// <summary>The faciltiy MUI error code</summary>
FACILTIY_MUI_ERROR_CODE = 0xB,
/// <summary>The facility usb error code</summary>
FACILITY_USB_ERROR_CODE = 0x10,
/// <summary>The facility hid error code</summary>
FACILITY_HID_ERROR_CODE = 0x11,
/// <summary>The facility firewire error code</summary>
FACILITY_FIREWIRE_ERROR_CODE = 0x12,
/// <summary>The facility cluster error code</summary>
FACILITY_CLUSTER_ERROR_CODE = 0x13,
/// <summary>The facility acpi error code</summary>
FACILITY_ACPI_ERROR_CODE = 0x14,
/// <summary>The facility SXS error code</summary>
FACILITY_SXS_ERROR_CODE = 0x15,
/// <summary>The facility transaction</summary>
FACILITY_TRANSACTION = 0x19,
/// <summary>The facility commonlog</summary>
FACILITY_COMMONLOG = 0x1A,
/// <summary>The facility video</summary>
FACILITY_VIDEO = 0x1B,
/// <summary>The facility filter manager</summary>
FACILITY_FILTER_MANAGER = 0x1C,
/// <summary>The facility monitor</summary>
FACILITY_MONITOR = 0x1D,
/// <summary>The facility graphics kernel</summary>
FACILITY_GRAPHICS_KERNEL = 0x1E,
/// <summary>The facility driver framework</summary>
FACILITY_DRIVER_FRAMEWORK = 0x20,
/// <summary>The facility fve error code</summary>
FACILITY_FVE_ERROR_CODE = 0x21,
/// <summary>The facility FWP error code</summary>
FACILITY_FWP_ERROR_CODE = 0x22,
/// <summary>The facility ndis error code</summary>
FACILITY_NDIS_ERROR_CODE = 0x23,
/// <summary>The facility TPM</summary>
FACILITY_TPM = 0x29,
/// <summary>The facility RTPM</summary>
FACILITY_RTPM = 0x2A,
/// <summary>The facility hypervisor</summary>
FACILITY_HYPERVISOR = 0x35,
/// <summary>The facility ipsec</summary>
FACILITY_IPSEC = 0x36,
/// <summary>The facility virtualization</summary>
FACILITY_VIRTUALIZATION = 0x37,
/// <summary>The facility volmgr</summary>
FACILITY_VOLMGR = 0x38,
/// <summary>The facility BCD error code</summary>
FACILITY_BCD_ERROR_CODE = 0x39,
/// <summary>The facility wi N32 k ntuser</summary>
FACILITY_WIN32K_NTUSER = 0x3E,
/// <summary>The facility wi N32 k ntgdi</summary>
FACILITY_WIN32K_NTGDI = 0x3F,
/// <summary>The facility resume key filter</summary>
FACILITY_RESUME_KEY_FILTER = 0x40,
/// <summary>The facility RDBSS</summary>
FACILITY_RDBSS = 0x41,
/// <summary>The facility BTH att</summary>
FACILITY_BTH_ATT = 0x42,
/// <summary>The facility secureboot</summary>
FACILITY_SECUREBOOT = 0x43,
/// <summary>The facility audio kernel</summary>
FACILITY_AUDIO_KERNEL = 0x44,
/// <summary>The facility VSM</summary>
FACILITY_VSM = 0x45,
/// <summary>The facility volsnap</summary>
FACILITY_VOLSNAP = 0x50,
/// <summary>The facility sdbus</summary>
FACILITY_SDBUS = 0x51,
/// <summary>The facility shared VHDX</summary>
FACILITY_SHARED_VHDX = 0x5C,
/// <summary>The facility SMB</summary>
FACILITY_SMB = 0x5D,
/// <summary>The facility interix</summary>
FACILITY_INTERIX = 0x99,
/// <summary>The facility spaces</summary>
FACILITY_SPACES = 0xE7,
/// <summary>The facility security core</summary>
FACILITY_SECURITY_CORE = 0xE8,
/// <summary>The facility system integrity</summary>
FACILITY_SYSTEM_INTEGRITY = 0xE9,
/// <summary>The facility licensing</summary>
FACILITY_LICENSING = 0xEA,
/// <summary>The facility platform manifest</summary>
FACILITY_PLATFORM_MANIFEST = 0xEB,
/// <summary>The facility maximum value</summary>
FACILITY_MAXIMUM_VALUE = 0xEC
}
/// <summary>A value indicating the severity of an <see cref="NTStatus"/> value (bits 30-31).</summary>
[PInvokeData("winerr.h")]
public enum SeverityLevel : byte
{
/// <summary>
/// Indicates a successful NTSTATUS value, such as STATUS_SUCCESS, or the value IO_ERR_RETRY_SUCCEEDED in error log packets.
/// </summary>
STATUS_SEVERITY_SUCCESS = 0x0,
/// <summary>Indicates an informational NTSTATUS value, such as STATUS_SERIAL_MORE_WRITES.</summary>
STATUS_SEVERITY_INFORMATIONAL = 0x1,
/// <summary>Indicates a warning NTSTATUS value, such as STATUS_DEVICE_PAPER_EMPTY.</summary>
STATUS_SEVERITY_WARNING = 0x2,
/// <summary>
/// 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.
/// </summary>
STATUS_SEVERITY_ERROR = 0x3
}
/// <summary>Gets the code portion of the <see cref="NTStatus"/>.</summary>
/// <value>The code value (bits 0-15).</value>
public ushort Code => GetCode(_value);
/// <summary>Gets a value indicating whether this code is customer defined (true) or from Microsoft (false).</summary>
/// <value><c>true</c> if customer defined; otherwise, <c>false</c>.</value>
public bool CustomerDefined => IsCustomerDefined(_value);
/// <summary>Gets the facility portion of the <see cref="NTStatus"/>.</summary>
/// <value>The facility value (bits 16-26).</value>
public FacilityCode Facility => GetFacility(_value);
/// <summary>Gets a value indicating whether this <see cref="NTStatus"/> is a failure (Severity bit 31 equals 1).</summary>
/// <value><c>true</c> if failed; otherwise, <c>false</c>.</value>
public bool Failed => Severity == SeverityLevel.STATUS_SEVERITY_ERROR;
/// <summary>Gets the severity level of the <see cref="NTStatus"/>.</summary>
/// <value>The severity level.</value>
public SeverityLevel Severity => GetSeverity(_value);
/// <summary>Gets a value indicating whether this <see cref="NTStatus"/> is a success (Severity bit 31 equals 0).</summary>
/// <value><c>true</c> if succeeded; otherwise, <c>false</c>.</value>
public bool Succeeded => !Failed;
/// <summary>Performs an explicit conversion from <see cref="NTStatus"/> to <see cref="HRESULT"/>.</summary>
/// <param name="value">The value.</param>
/// <returns>The resulting <see cref="HRESULT"/> instance from the conversion.</returns>
public static explicit operator HRESULT(NTStatus value) => value.ToHRESULT();
/// <summary>Performs an explicit conversion from <see cref="NTStatus"/> to <see cref="System.Int32"/>.</summary>
/// <param name="value">The value.</param>
/// <returns>The result of the conversion.</returns>
public static explicit operator int(NTStatus value) => value._value;
/// <summary>Performs an explicit conversion from <see cref="NTStatus"/> to <see cref="System.UInt32"/>.</summary>
/// <param name="value">The value.</param>
/// <returns>The result of the conversion.</returns>
public static explicit operator uint(NTStatus value) => unchecked((uint)value._value);
/// <summary>Gets the code value from a 32-bit value.</summary>
/// <param name="ntstatus">The 32-bit raw NTStatus value.</param>
/// <returns>The code value (bits 0-15).</returns>
public static ushort GetCode(int ntstatus) => (ushort)(ntstatus & codeMask);
/// <summary>Gets the facility value from a 32-bit value.</summary>
/// <param name="ntstatus">The 32-bit raw NTStatus value.</param>
/// <returns>The facility value (bits 16-26).</returns>
public static FacilityCode GetFacility(int ntstatus) => (FacilityCode)((ntstatus & facilityMask) >> facilityShift);
/// <summary>Gets the severity value from a 32-bit value.</summary>
/// <param name="ntstatus">The 32-bit raw NTStatus value.</param>
/// <returns>The severity value (bit 31).</returns>
public static SeverityLevel GetSeverity(int ntstatus) => (SeverityLevel)((ntstatus & severityMask) >> severityShift);
/// <summary>Performs an implicit conversion from <see cref="System.Int32"/> to <see cref="NTStatus"/>.</summary>
/// <param name="value">The value.</param>
/// <returns>The result of the conversion.</returns>
public static implicit operator NTStatus(int value) => new NTStatus(value);
/// <summary>Performs an implicit conversion from <see cref="System.UInt32"/> to <see cref="NTStatus"/>.</summary>
/// <param name="value">The value.</param>
/// <returns>The result of the conversion.</returns>
public static implicit operator NTStatus(uint value) => new NTStatus(value);
/// <summary>Performs an implicit conversion from <see cref="Win32Error"/> to <see cref="NTStatus"/>.</summary>
/// <param name="value">The value.</param>
/// <returns>The resulting <see cref="NTStatus"/> instance from the conversion.</returns>
public static implicit operator NTStatus(Win32Error value) => NTSTATUS_FROM_WIN32((uint)value);
/// <summary>Gets the customer defined bit from a 32-bit value.</summary>
/// <param name="ntstatus">The 32-bit raw NTStatus value.</param>
/// <returns><c>true</c> if the customer defined bit is set; otherwise, <c>false</c>.</returns>
public static bool IsCustomerDefined(int ntstatus) => (ntstatus & customerMask) > 0;
/// <summary>Creates a new <see cref="NTStatus"/> from provided values.</summary>
/// <param name="severity">The severity level.</param>
/// <param name="customerDefined">The bit is set for customer-defined values and clear for Microsoft-defined values.</param>
/// <param name="facility">The facility.</param>
/// <param name="code">The code.</param>
/// <returns>The resulting <see cref="NTStatus"/>.</returns>
public static NTStatus Make(SeverityLevel severity, bool customerDefined, FacilityCode facility, ushort code) => Make(severity, customerDefined, (ushort)facility, code);
/// <summary>Creates a new <see cref="NTStatus"/> from provided values.</summary>
/// <param name="severity">The severity level.</param>
/// <param name="customerDefined">The bit is set for customer-defined values and clear for Microsoft-defined values.</param>
/// <param name="facility">The facility.</param>
/// <param name="code">The code.</param>
/// <returns>The resulting <see cref="NTStatus"/>.</returns>
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)));
/// <summary>Converts a Win32 error to an NTSTATUS.</summary>
/// <param name="x">The Win32 error codex.</param>
/// <returns>The equivalent NTSTATUS value.</returns>
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));
/// <summary>Implements the operator !=.</summary>
/// <param name="hrLeft">The first <see cref="NTStatus"/>.</param>
/// <param name="hrRight">The second <see cref="NTStatus"/>.</param>
/// <returns>The result of the operator.</returns>
public static bool operator !=(NTStatus hrLeft, NTStatus hrRight) => !(hrLeft == hrRight);
/// <summary>Implements the operator !=.</summary>
/// <param name="hrLeft">The first <see cref="NTStatus"/>.</param>
/// <param name="hrRight">The second <see cref="int"/>.</param>
/// <returns>The result of the operator.</returns>
public static bool operator !=(NTStatus hrLeft, int hrRight) => !(hrLeft == hrRight);
/// <summary>Implements the operator !=.</summary>
/// <param name="hrLeft">The first <see cref="NTStatus"/>.</param>
/// <param name="hrRight">The second <see cref="uint"/>.</param>
/// <returns>The result of the operator.</returns>
public static bool operator !=(NTStatus hrLeft, uint hrRight) => !(hrLeft == hrRight);
/// <summary>Implements the operator ==.</summary>
/// <param name="hrLeft">The first <see cref="NTStatus"/>.</param>
/// <param name="hrRight">The second <see cref="NTStatus"/>.</param>
/// <returns>The result of the operator.</returns>
public static bool operator ==(NTStatus hrLeft, NTStatus hrRight) => hrLeft.Equals(hrRight);
/// <summary>Implements the operator ==.</summary>
/// <param name="hrLeft">The first <see cref="NTStatus"/>.</param>
/// <param name="hrRight">The second <see cref="int"/>.</param>
/// <returns>The result of the operator.</returns>
public static bool operator ==(NTStatus hrLeft, int hrRight) => hrLeft.Equals(hrRight);
/// <summary>Implements the operator ==.</summary>
/// <param name="hrLeft">The first <see cref="NTStatus"/>.</param>
/// <param name="hrRight">The second <see cref="uint"/>.</param>
/// <returns>The result of the operator.</returns>
public static bool operator ==(NTStatus hrLeft, uint hrRight) => hrLeft.Equals(hrRight);
/// <summary>Converts the specified NTSTATUS code to its equivalent system error code.</summary>
/// <param name="status">The NTSTATUS code to be converted.</param>
/// <returns>
/// 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.
/// </returns>
[DllImport(Lib.NtDll, ExactSpelling = true)]
[PInvokeData("Winternl.h", MSDNShortId = "ms680600")]
public static extern uint RtlNtStatusToDosError(int status);
/// <summary>
/// If the supplied raw NTStatus value represents a failure, throw the associated <see cref="Exception"/> with the optionally
/// supplied message.
/// </summary>
/// <param name="ntstatus">The 32-bit raw NTStatus value.</param>
/// <param name="message">The optional message to assign to the <see cref="Exception"/>.</param>
public static void ThrowIfFailed(int ntstatus, string message = null) => new NTStatus(ntstatus).ThrowIfFailed(message);
/// <summary>Compares the current object with another object of the same type.</summary>
/// <param name="other">An object to compare with this object.</param>
/// <returns>
/// 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 <paramref name="other"/> parameter.Zero This object is equal
/// to <paramref name="other"/>. Greater than zero This object is greater than <paramref name="other"/>.
/// </returns>
public int CompareTo(NTStatus other) => _value.CompareTo(other._value);
/// <summary>
/// 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.
/// </summary>
/// <param name="obj">An object to compare with this instance.</param>
/// <returns>
/// 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 <paramref name="obj"/> in the sort order. Zero This instance occurs in the same position in the
/// sort order as <paramref name="obj"/> . Greater than zero This instance follows <paramref name="obj"/> in the sort order.
/// </returns>
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));
}
/// <summary>Indicates whether the current object is equal to an <see cref="int"/>.</summary>
/// <param name="other">An object to compare with this object.</param>
/// <returns>true if the current object is equal to the <paramref name="other"/> parameter; otherwise, false.</returns>
public bool Equals(int other) => other == _value;
/// <summary>Indicates whether the current object is equal to an <see cref="uint"/>.</summary>
/// <param name="other">An object to compare with this object.</param>
/// <returns>true if the current object is equal to the <paramref name="other"/> parameter; otherwise, false.</returns>
public bool Equals(uint other) => unchecked((int)other) == _value;
/// <summary>Determines whether the specified <see cref="object"/>, is equal to this instance.</summary>
/// <param name="obj">The <see cref="object"/> to compare with this instance.</param>
/// <returns><c>true</c> if the specified <see cref="object"/> is equal to this instance; otherwise, <c>false</c>.</returns>
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)),
};
/// <summary>Indicates whether the current object is equal to another object of the same type.</summary>
/// <param name="other">An object to compare with this object.</param>
/// <returns>true if the current object is equal to the <paramref name="other"/> parameter; otherwise, false.</returns>
public bool Equals(NTStatus other) => other._value == _value;
/// <summary>Gets the .NET <see cref="Exception"/> associated with the NTStatus value and optionally adds the supplied message.</summary>
/// <param name="message">The optional message to assign to the <see cref="Exception"/>.</param>
/// <returns>The associated <see cref="Exception"/> or <c>null</c> if this NTStatus is not a failure.</returns>
[SecurityCritical]
[SecuritySafeCritical]
public Exception GetException(string message = null) => !Failed ? null : ToHRESULT().GetException(message);
/// <summary>Returns a hash code for this instance.</summary>
/// <returns>A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.</returns>
public override int GetHashCode() => _value;
/// <summary>
/// If this <see cref="NTStatus"/> represents a failure, throw the associated <see cref="Exception"/> with the optionally supplied message.
/// </summary>
/// <param name="message">The optional message to assign to the <see cref="Exception"/>.</param>
[SecurityCritical]
[SecuritySafeCritical]
public void ThrowIfFailed(string message = null)
{
var exception = GetException(message);
if (exception != null)
throw exception;
}
/// <summary>Converts this error to an <see cref="T:Vanara.PInvoke.HRESULT"/>.</summary>
/// <returns>An equivalent <see cref="T:Vanara.PInvoke.HRESULT"/>.</returns>
public HRESULT ToHRESULT()
{
Win32Error werr = RtlNtStatusToDosError(_value);
return werr != Win32Error.ERROR_MR_MID_NOT_FOUND ? (HRESULT)werr : HRESULT_FROM_NT(_value);
}
/// <summary>Returns a <see cref="string"/> that represents this instance.</summary>
/// <returns>A <see cref="string"/> that represents this instance.</returns>
public override string ToString()
{
// Check for defined NTStatus value
StaticFieldValueHash.TryGetFieldName<NTStatus, int>(_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);
}
}
}