// Copyright (c) 2010-2014 SharpDX - Alexandre Mutel // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Reflection; using System.Runtime.InteropServices; namespace SharpGen.Runtime { /// /// Descriptor used to provide detailed message for a particular . /// public sealed class ResultDescriptor { private static readonly ConcurrentDictionary Descriptors = new(); private const string UnknownText = "Unknown"; /// /// Initializes a new instance of the class. /// /// The HRESULT error code. /// The module (ex: SharpDX.Direct2D1). /// The API code (ex: D2D1_ERR_...). /// The description of the result code if any. public ResultDescriptor(Result code, string module, string nativeApiCode, string apiCode, string description = null) { Result = code; Module = module; NativeApiCode = nativeApiCode; ApiCode = apiCode; Description = description ?? GetDescriptionFromResultCode(Code) ?? UnknownText; Descriptors.TryAdd(code, this); } /// /// Gets the result. /// public Result Result { get; } /// /// Gets the HRESULT error code. /// /// The HRESULT error code. public int Code => Result.Code; /// /// Gets the module /// public string Module { get; } /// /// Gets the native API code /// public string NativeApiCode { get; } /// /// Gets the API code /// public string ApiCode { get; } /// /// Gets the description of the result code if any. /// public string Description { get; } /// /// 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 bool Equals(ResultDescriptor other) { if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; return other.Result.Equals(this.Result); } /// /// 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) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; if (obj is ResultDescriptor descriptor) return Equals(descriptor); return false; } /// public override int GetHashCode() { return Result.GetHashCode(); } /// public override string ToString() => $"HRESULT: [0x{Result.Code:X}], Module: [{Module}], ApiCode: [{NativeApiCode}/{ApiCode}], Message: {Description}"; /// /// Performs an implicit conversion from to . /// /// The result. /// /// The result of the conversion. /// public static implicit operator Result(ResultDescriptor result) { return result.Result; } /// /// Performs an implicit conversion from to . /// /// The result. /// The result of the conversion. public static explicit operator int(ResultDescriptor result) { return result.Result.Code; } /// /// Performs an implicit conversion from to . /// /// The result. /// The result of the conversion. public static explicit operator uint(ResultDescriptor result) { return unchecked((uint)result.Result.Code); } /// /// Implements the operator ==. /// /// The left. /// The right. /// The result of the operator. public static bool operator ==(ResultDescriptor left, Result right) { if (left == null) return false; return left.Result.Code == right.Code; } /// /// Implements the operator !=. /// /// The left. /// The right. /// The result of the operator. public static bool operator !=(ResultDescriptor left, Result right) { if (left == null) return false; return left.Result.Code != right.Code; } /// /// Finds the specified result descriptor. /// /// The result code. /// A descriptor for the specified result public static ResultDescriptor Find(Result result) { if (!Descriptors.TryGetValue(result, out var descriptor)) { descriptor = new ResultDescriptor(result, UnknownText, UnknownText, UnknownText); } return descriptor; } private static string GetDescriptionFromResultCode(int resultCode) { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { const int FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100; const int FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200; const int FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000; var buffer = IntPtr.Zero; FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, IntPtr.Zero, resultCode, 0, ref buffer, 0, IntPtr.Zero); var description = Marshal.PtrToStringUni(buffer); Marshal.FreeHGlobal(buffer); return description; } return null; } [DllImport("kernel32.dll", EntryPoint = "FormatMessageW")] private static extern uint FormatMessageW(int dwFlags, IntPtr lpSource, int dwMessageId, int dwLanguageId, ref IntPtr lpBuffer, int nSize, IntPtr Arguments); } }