.NET(C#):使用Win32Exception類型處理Win32錯誤代碼
此類型在System.ComponentModel命名空間內,而不是你可能認為的System.Runtime.InteropServices命名空間內。
Console.WriteLine(Marshal.GetLastWin32Error());
Console.WriteLine(new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()).Message);
但是他的父類:ExternalException,則是在System.Runtime.InteropServices命名空間內。
ExternalException的父類是SystemException(當然現在SystemException和ApplicationException該繼承哪個界限已經很模糊了)。注意ExternalException多了一個ErrorCode屬性返回的是父類Exception的HResult屬性,同時在ExternalException的構造函數中可以設置HResult屬性,但是Win32Exception並沒有使用這個HResult的,Win32Exception僅設置父類的Message屬性,也就是說Win32Exception中的ExternalException的ErrorCode始終是保持默認值的。
而Win32Exception自己定義了一個屬性值:NativeErrorCode,同樣是int類型。Win32Exception可以設置三個屬性,NativeErrorCode,Exception的Message,和Exception的InnerException屬性。InnerException沒有特殊的地方,前兩個屬性有這樣的特點:
1. 可以通過構造函數設置他們的值。
2. 如果只設置NativeErrorCode,那么Message會是相應Win32錯誤代碼的文字描述。
3. 如果只設置Message,那么NativeErrorCode會是Marshal.GetLastWin32Error方法的返回值。
4. 如果什么都不設置,那么2和3都會被應用。
這些都是非常有用的,尤其是第2項,這個可以代替另一個Win32 API:FormatMessage,開發人員就不需要再次平台調用FormatMessage API,直接使用Win32Exception則可以。
比如隨便舉一個Win32錯誤代碼:17,代表“無法將文件移動到不同的磁盤中”(可以參考:System Error Codes)
代碼:
Console.WriteLine(new System.ComponentModel.Win32Exception(17).Message);
輸出(我的系統是英文的,在中文系統會輸出中文):無法將文件移動到不同的磁盤中
接下來試試自動調用GetLastWin32Error方法,隨便試一個API比如DeleteFile API。這樣定義平台調用:
//+ using System.Runtime.InteropServices;
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool DeleteFile(string lpFileName);
如果出錯的話,可以一般是這樣處理錯誤:
//+ using System.Runtime.InteropServices;
if (!DeleteFile("123"))
{
//獲取錯誤代碼
int errorCode = Marshal.GetLastWin32Error();
//輸出錯誤信息
//使用FormatMessage或者Win32Exception.Message
}
其實還可以更快的,就是用Win32Exception的默認構造函數:
//+ using System.ComponentModel;
if (!DeleteFile("123"))
Console.WriteLine(new Win32Exception().Message);
此時Marshal.GetLastWin32Error和Win32錯誤代碼的描述都會被解決,於是代碼會輸出“文件未找到”的字樣:
The system cannot find the file specified