// 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.Generic; using System.Reflection; using System.Runtime.InteropServices; namespace SharpDX { /// /// Descriptor used to provide detailed message for a particular . /// public sealed class ResultDescriptor { private static readonly object LockDescriptor = new object(); private static readonly List RegisteredDescriptorProvider = new List(); private static readonly Dictionary Descriptors = new Dictionary(); 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; } /// /// Gets the result. /// public Result Result { get; private set; } /// /// Gets the HRESULT error code. /// /// The HRESULT error code. public int Code { get { return Result.Code; } } /// /// Gets the module (ex: SharpDX.Direct2D1) /// public string Module { get; private set; } /// /// Gets the native API code (ex: D2D1_ERR_ ...) /// public string NativeApiCode { get; private set; } /// /// Gets the API code (ex: DeviceRemoved ...) /// public string ApiCode { get; private set; } /// /// Gets the description of the result code if any. /// public string Description { get; set; } /// /// 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.GetType() != typeof(ResultDescriptor)) return false; return Equals((ResultDescriptor)obj); } /// public override int GetHashCode() { return this.Result.GetHashCode(); } /// public override string ToString() { return string.Format("HRESULT: [0x{0:X}], Module: [{1}], ApiCode: [{2}/{3}], Message: {4}", this.Result.Code, this.Module, this.NativeApiCode, this.ApiCode, this.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; } /// /// Registers a provider. /// /// Type of the descriptors provider. /// /// Providers are usually registered at module init when SharpDX assemblies are loaded. /// public static void RegisterProvider(Type descriptorsProviderType) { lock (LockDescriptor) { if (!RegisteredDescriptorProvider.Contains(descriptorsProviderType)) RegisteredDescriptorProvider.Add(descriptorsProviderType); } } /// /// Finds the specified result descriptor. /// /// The result code. /// A descriptor for the specified result public static ResultDescriptor Find(Result result) { ResultDescriptor descriptor; // Check also SharpDX registered result descriptors lock (LockDescriptor) { if (RegisteredDescriptorProvider.Count > 0) { foreach (var type in RegisteredDescriptorProvider) { AddDescriptorsFromType(type); } RegisteredDescriptorProvider.Clear(); } if (!Descriptors.TryGetValue(result, out descriptor)) { descriptor = new ResultDescriptor(result, UnknownText, UnknownText, UnknownText); } // If description is null, than we try to add description from Win32 GetDescriptionFromResultCode // Or we use unknown description if (descriptor.Description == null) { // Check if a Win32 description exist var description = GetDescriptionFromResultCode(result.Code); descriptor.Description = description ?? UnknownText; } } return descriptor; } private static void AddDescriptorsFromType(Type type) { #if BEFORE_NET45 foreach(var field in type.GetTypeInfo().GetFields()) #else foreach (var field in type.GetTypeInfo().DeclaredFields) #endif { if (field.FieldType == typeof(ResultDescriptor) && field.IsPublic && field.IsStatic) { var descriptor = (ResultDescriptor)field.GetValue(null); if (!Descriptors.ContainsKey(descriptor.Result)) { Descriptors.Add(descriptor.Result, descriptor); } } } } private static string GetDescriptionFromResultCode(int resultCode) { const int FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100; const int FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200; const int FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000; IntPtr 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; } #if WINDOWS_UWP [DllImport("api-ms-win-core-localization-l1-2-0.dll", EntryPoint = "FormatMessageW")] private static extern uint FormatMessageW(int dwFlags, IntPtr lpSource, int dwMessageId, int dwLanguageId, ref IntPtr lpBuffer, int nSize, IntPtr Arguments); #else [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); #endif } }