NativeError.cs 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. #region Apache License
  2. //
  3. // Licensed to the Apache Software Foundation (ASF) under one or more
  4. // contributor license agreements. See the NOTICE file distributed with
  5. // this work for additional information regarding copyright ownership.
  6. // The ASF licenses this file to you under the Apache License, Version 2.0
  7. // (the "License"); you may not use this file except in compliance with
  8. // the License. You may obtain a copy of the License at
  9. //
  10. // http://www.apache.org/licenses/LICENSE-2.0
  11. //
  12. // Unless required by applicable law or agreed to in writing, software
  13. // distributed under the License is distributed on an "AS IS" BASIS,
  14. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. // See the License for the specific language governing permissions and
  16. // limitations under the License.
  17. //
  18. #endregion
  19. // MONO 1.0 has no support for Win32 Error APIs
  20. #if !MONO
  21. // SSCLI 1.0 has no support for Win32 Error APIs
  22. #if !SSCLI
  23. // We don't want framework or platform specific code in the CLI version of log4net
  24. #if !CLI_1_0
  25. using System;
  26. using System.Globalization;
  27. using System.Runtime.InteropServices;
  28. namespace log4net.Util
  29. {
  30. /// <summary>
  31. /// Represents a native error code and message.
  32. /// </summary>
  33. /// <remarks>
  34. /// <para>
  35. /// Represents a Win32 platform native error.
  36. /// </para>
  37. /// </remarks>
  38. /// <author>Nicko Cadell</author>
  39. /// <author>Gert Driesen</author>
  40. public sealed class NativeError
  41. {
  42. #region Protected Instance Constructors
  43. /// <summary>
  44. /// Create an instance of the <see cref="NativeError" /> class with the specified
  45. /// error number and message.
  46. /// </summary>
  47. /// <param name="number">The number of the native error.</param>
  48. /// <param name="message">The message of the native error.</param>
  49. /// <remarks>
  50. /// <para>
  51. /// Create an instance of the <see cref="NativeError" /> class with the specified
  52. /// error number and message.
  53. /// </para>
  54. /// </remarks>
  55. private NativeError(int number, string message)
  56. {
  57. m_number = number;
  58. m_message = message;
  59. }
  60. #endregion // Protected Instance Constructors
  61. #region Public Instance Properties
  62. /// <summary>
  63. /// Gets the number of the native error.
  64. /// </summary>
  65. /// <value>
  66. /// The number of the native error.
  67. /// </value>
  68. /// <remarks>
  69. /// <para>
  70. /// Gets the number of the native error.
  71. /// </para>
  72. /// </remarks>
  73. public int Number
  74. {
  75. get { return m_number; }
  76. }
  77. /// <summary>
  78. /// Gets the message of the native error.
  79. /// </summary>
  80. /// <value>
  81. /// The message of the native error.
  82. /// </value>
  83. /// <remarks>
  84. /// <para>
  85. /// </para>
  86. /// Gets the message of the native error.
  87. /// </remarks>
  88. public string Message
  89. {
  90. get { return m_message; }
  91. }
  92. #endregion // Public Instance Properties
  93. #region Public Static Methods
  94. /// <summary>
  95. /// Create a new instance of the <see cref="NativeError" /> class for the last Windows error.
  96. /// </summary>
  97. /// <returns>
  98. /// An instance of the <see cref="NativeError" /> class for the last windows error.
  99. /// </returns>
  100. /// <remarks>
  101. /// <para>
  102. /// The message for the <see cref="Marshal.GetLastWin32Error"/> error number is lookup up using the
  103. /// native Win32 <c>FormatMessage</c> function.
  104. /// </para>
  105. /// </remarks>
  106. #if NET_4_0 || MONO_4_0 || NETSTANDARD1_3
  107. [System.Security.SecuritySafeCritical]
  108. #elif !NETCF
  109. [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand, UnmanagedCode=true)]
  110. #endif
  111. public static NativeError GetLastError()
  112. {
  113. int number = Marshal.GetLastWin32Error();
  114. return new NativeError(number, NativeError.GetErrorMessage(number));
  115. }
  116. /// <summary>
  117. /// Create a new instance of the <see cref="NativeError" /> class.
  118. /// </summary>
  119. /// <param name="number">the error number for the native error</param>
  120. /// <returns>
  121. /// An instance of the <see cref="NativeError" /> class for the specified
  122. /// error number.
  123. /// </returns>
  124. /// <remarks>
  125. /// <para>
  126. /// The message for the specified error number is lookup up using the
  127. /// native Win32 <c>FormatMessage</c> function.
  128. /// </para>
  129. /// </remarks>
  130. public static NativeError GetError(int number)
  131. {
  132. return new NativeError(number, NativeError.GetErrorMessage(number));
  133. }
  134. /// <summary>
  135. /// Retrieves the message corresponding with a Win32 message identifier.
  136. /// </summary>
  137. /// <param name="messageId">Message identifier for the requested message.</param>
  138. /// <returns>
  139. /// The message corresponding with the specified message identifier.
  140. /// </returns>
  141. /// <remarks>
  142. /// <para>
  143. /// The message will be searched for in system message-table resource(s)
  144. /// using the native <c>FormatMessage</c> function.
  145. /// </para>
  146. /// </remarks>
  147. #if NET_4_0 || MONO_4_0 || NETSTANDARD1_3
  148. [System.Security.SecuritySafeCritical]
  149. #elif !NETCF
  150. [System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand, UnmanagedCode = true)]
  151. #endif
  152. public static string GetErrorMessage(int messageId)
  153. {
  154. // Win32 constants
  155. int FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100; // The function should allocates a buffer large enough to hold the formatted message
  156. int FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200; // Insert sequences in the message definition are to be ignored
  157. int FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000; // The function should search the system message-table resource(s) for the requested message
  158. string msgBuf = ""; // buffer that will receive the message
  159. IntPtr sourcePtr = new IntPtr(); // Location of the message definition, will be ignored
  160. IntPtr argumentsPtr = new IntPtr(); // Pointer to array of values to insert, not supported as it requires unsafe code
  161. if (messageId != 0)
  162. {
  163. // If the function succeeds, the return value is the number of TCHARs stored in the output buffer, excluding the terminating null character
  164. int messageSize = FormatMessage(
  165. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
  166. ref sourcePtr,
  167. messageId,
  168. 0,
  169. ref msgBuf,
  170. 255,
  171. argumentsPtr);
  172. if (messageSize > 0)
  173. {
  174. // Remove trailing null-terminating characters (\r\n) from the message
  175. msgBuf = msgBuf.TrimEnd(new char[] {'\r', '\n'});
  176. }
  177. else
  178. {
  179. // A message could not be located.
  180. msgBuf = null;
  181. }
  182. }
  183. else
  184. {
  185. msgBuf = null;
  186. }
  187. return msgBuf;
  188. }
  189. #endregion // Public Static Methods
  190. #region Override Object Implementation
  191. /// <summary>
  192. /// Return error information string
  193. /// </summary>
  194. /// <returns>error information string</returns>
  195. /// <remarks>
  196. /// <para>
  197. /// Return error information string
  198. /// </para>
  199. /// </remarks>
  200. public override string ToString()
  201. {
  202. return string.Format(CultureInfo.InvariantCulture, "0x{0:x8}", this.Number) + (this.Message != null ? ": " + this.Message : "");
  203. }
  204. #endregion // Override Object Implementation
  205. #region Stubs For Native Function Calls
  206. /// <summary>
  207. /// Formats a message string.
  208. /// </summary>
  209. /// <param name="dwFlags">Formatting options, and how to interpret the <paramref name="lpSource" /> parameter.</param>
  210. /// <param name="lpSource">Location of the message definition.</param>
  211. /// <param name="dwMessageId">Message identifier for the requested message.</param>
  212. /// <param name="dwLanguageId">Language identifier for the requested message.</param>
  213. /// <param name="lpBuffer">If <paramref name="dwFlags" /> includes FORMAT_MESSAGE_ALLOCATE_BUFFER, the function allocates a buffer using the <c>LocalAlloc</c> function, and places the pointer to the buffer at the address specified in <paramref name="lpBuffer" />.</param>
  214. /// <param name="nSize">If the FORMAT_MESSAGE_ALLOCATE_BUFFER flag is not set, this parameter specifies the maximum number of TCHARs that can be stored in the output buffer. If FORMAT_MESSAGE_ALLOCATE_BUFFER is set, this parameter specifies the minimum number of TCHARs to allocate for an output buffer.</param>
  215. /// <param name="Arguments">Pointer to an array of values that are used as insert values in the formatted message.</param>
  216. /// <remarks>
  217. /// <para>
  218. /// The function requires a message definition as input. The message definition can come from a
  219. /// buffer passed into the function. It can come from a message table resource in an
  220. /// already-loaded module. Or the caller can ask the function to search the system's message
  221. /// table resource(s) for the message definition. The function finds the message definition
  222. /// in a message table resource based on a message identifier and a language identifier.
  223. /// The function copies the formatted message text to an output buffer, processing any embedded
  224. /// insert sequences if requested.
  225. /// </para>
  226. /// <para>
  227. /// To prevent the usage of unsafe code, this stub does not support inserting values in the formatted message.
  228. /// </para>
  229. /// </remarks>
  230. /// <returns>
  231. /// <para>
  232. /// If the function succeeds, the return value is the number of TCHARs stored in the output
  233. /// buffer, excluding the terminating null character.
  234. /// </para>
  235. /// <para>
  236. /// If the function fails, the return value is zero. To get extended error information,
  237. /// call <see cref="M:Marshal.GetLastWin32Error()" />.
  238. /// </para>
  239. /// </returns>
  240. #if NETCF
  241. [DllImport("CoreDll.dll", SetLastError=true, CharSet=CharSet.Unicode)]
  242. #else
  243. [DllImport("Kernel32.dll", SetLastError=true, CharSet=CharSet.Auto)]
  244. #endif
  245. private static extern int FormatMessage(
  246. int dwFlags,
  247. ref IntPtr lpSource,
  248. int dwMessageId,
  249. int dwLanguageId,
  250. ref String lpBuffer,
  251. int nSize,
  252. IntPtr Arguments);
  253. #endregion // Stubs For Native Function Calls
  254. #region Private Instance Fields
  255. private int m_number;
  256. private string m_message;
  257. #endregion
  258. }
  259. }
  260. #endif // !CLI_1_0
  261. #endif // !SSCLI
  262. #endif // !MONO