1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System.Globalization;
6 using System.Runtime.InteropServices;
7 using System.Runtime.Serialization;
8 using System.Text;
9 
10 namespace System.ComponentModel
11 {
12     /// <summary>
13     /// The exception that is thrown for a Win32 error code.
14     /// </summary>
15     [Serializable]
16     [System.Runtime.CompilerServices.TypeForwardedFrom("System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
17     public partial class Win32Exception : ExternalException, ISerializable
18     {
19         private const int E_FAIL = unchecked((int)0x80004005);
20 
21         /// <summary>
22         /// Initializes a new instance of the <see cref='System.ComponentModel.Win32Exception'/> class with the last Win32 error
23         /// that occurred.
24         /// </summary>
Win32Exception()25         public Win32Exception() : this(Marshal.GetLastWin32Error())
26         {
27         }
28 
29         /// <summary>
30         /// Initializes a new instance of the <see cref='System.ComponentModel.Win32Exception'/> class with the specified error.
31         /// </summary>
Win32Exception(int error)32         public Win32Exception(int error) : this(error, GetErrorMessage(error))
33         {
34         }
35         /// <summary>
36         /// Initializes a new instance of the <see cref='System.ComponentModel.Win32Exception'/> class with the specified error and the
37         /// specified detailed description.
38         /// </summary>
Win32Exception(int error, string message)39         public Win32Exception(int error, string message) : base(message)
40         {
41             NativeErrorCode = error;
42         }
43 
44         /// <summary>
45         /// Initializes a new instance of the Exception class with a specified error message.
46         /// </summary>
Win32Exception(string message)47         public Win32Exception(string message) : this(Marshal.GetLastWin32Error(), message)
48         {
49         }
50 
51         /// <summary>
52         /// Initializes a new instance of the Exception class with a specified error message and a
53         /// reference to the inner exception that is the cause of this exception.
54         /// </summary>
Win32Exception(string message, Exception innerException)55         public Win32Exception(string message, Exception innerException) : base(message, innerException)
56         {
57             NativeErrorCode = Marshal.GetLastWin32Error();
58         }
59 
Win32Exception(SerializationInfo info, StreamingContext context)60         protected Win32Exception(SerializationInfo info, StreamingContext context) : base(info, context)
61         {
62             NativeErrorCode = info.GetInt32(nameof(NativeErrorCode));
63         }
64 
GetObjectData(SerializationInfo info, StreamingContext context)65         public override void GetObjectData(SerializationInfo info, StreamingContext context)
66         {
67             base.GetObjectData(info, context);
68             info.AddValue(nameof(NativeErrorCode), NativeErrorCode);
69         }
70 
71         /// <summary>
72         /// Represents the Win32 error code associated with this exception. This field is read-only.
73         /// </summary>
74         public int NativeErrorCode { get; }
75 
76         /// <summary>
77         /// Returns a string that contains the <see cref="NativeErrorCode"/>, or <see cref="Exception.HResult"/>, or both.
78         /// </summary>
79         /// <returns>A string that represents the <see cref="NativeErrorCode"/>, or <see cref="Exception.HResult"/>, or both.</returns>
ToString()80         public override string ToString()
81         {
82             if (NativeErrorCode == 0 || NativeErrorCode == HResult)
83             {
84                 return base.ToString();
85             }
86 
87             string message = Message;
88             string className = GetType().ToString();
89             StringBuilder s = new StringBuilder(className);
90             string nativeErrorString = NativeErrorCode < 0
91                 ? string.Format(CultureInfo.InvariantCulture, "0x{0:X8}", NativeErrorCode)
92                 : NativeErrorCode.ToString(CultureInfo.InvariantCulture);
93             if (HResult == E_FAIL)
94             {
95                 s.AppendFormat(CultureInfo.InvariantCulture, " ({0})", nativeErrorString);
96             }
97             else
98             {
99                 s.AppendFormat(CultureInfo.InvariantCulture, " ({0:X8}, {1})", HResult, nativeErrorString);
100             }
101 
102             if (!(String.IsNullOrEmpty(message)))
103             {
104                 s.Append(": ");
105                 s.Append(message);
106             }
107 
108             Exception innerException = InnerException;
109             if (innerException != null)
110             {
111                 s.Append(" ---> ");
112                 s.Append(innerException.ToString());
113             }
114 
115             string stackTrace = StackTrace;
116             if (stackTrace != null)
117             {
118                 s.AppendLine();
119                 s.Append(stackTrace);
120             }
121 
122             return s.ToString();
123         }
124     }
125 }
126