对程序错误的处理——Windows核心编程学习手札之一
對程序錯誤的處理
——Windows核心編程學習手札之一
函數被調用執行時,先檢驗傳遞給它的各個參數的有效性,后執行任務。函數執行中若因參數無效或因某種原因導致無法正常完成函數任務,那么操作系統會返回一個值,以提示函數運行失敗。這個思想可歸納為:函數錯誤提示的透明,同樣適用于個人編寫的函數,在函數執行任務的每個關鍵點設置錯誤提示并返回。對所返回的錯誤代碼或提示對于正確定位和調試函數失敗點是非常有用的。
Microsoft給出了一個所有可能的錯誤代碼列表,并為每個錯誤代碼分配一個32位的號碼。Windows函數常用的返回值類型有VOID/BOOL/HANDLE/PVOID/LONG/DWORD,基于此,個人編寫的程序也可以維護一張自己的錯誤代碼列表,并設定返回類型。
當函數檢測到錯誤時,會使用線程本地存儲器(thread-local storage)機制,將相應的錯誤代碼號碼與調用的線程關聯起來,這使線程能夠互相獨立地運行,而不影響各自的錯誤代碼。Windows函數返回時,其返回值就能指明一個錯誤已經發生。若要確定發生的錯誤是什么,可調用函數:
DWORD GetLastError();
該函數返回線程的32位錯誤代碼。有了32位錯誤代碼的號碼,便可以將該號碼轉換成更有用的信息。WinError.h頭文件包含了Microsoft定義的錯誤代碼列表。當函數運行失敗時,應立即調用GetLastError函數,因為如果調用另一個Windows函數,它的值很可能被改寫。
有些函數可能返回了正確的代碼,但并不表明函數實際運行成功,其中有很多原因。如,創建指明的事件內核對象之所以成功,是因為實際上已經創建了該對象或已經存在帶有相同名字的事件內核對象。
程序調試中,對線程的最后錯誤代碼進行提取和分析是非常有用的。在Microsoft Visual studio6.0中,Microsoft的調試程序可以配置Watch窗口,以便始終顯示線程的最后錯誤代碼及其英文描述。操作是在Watch窗口中的一行輸入“@err,hr”即可。Visual studio還提供一個實用程序Error Lookup可以將錯誤代碼的號碼轉換成相應的文本描述。個人在用Microsoft Visual C++6.0開發的單元調試中經常用到Watch窗口和Error Lookup來查看最后錯誤代碼,當然Watch窗口的作用還不僅僅是查看錯誤代碼及其描述。
同時Windows提供一個函數FormatMessage可以將錯誤代碼轉換成它的文字描述。
DWORD FormatMessage(
??????????? DWORD dwFlags,
??????????? LPCVOID pSource,
??????????? DWORD dwMessageID,
??????????? DWORD dwLanguageID,
??????????? PTSTR pszBuffer,
??????????? DWORD nSize,
??????????? va_list *Arguments);
FormatMessage函數能夠檢測出用戶首選的語言,并返回相應的文本。對于Microsoft是否應該建立一個主控列表,以顯示每個Windows函數可能返回的所有錯誤代碼,可從下面兩方面來否定:一是創建新系統版本時,建立和維護該主控列表太困難;二是函數在內部調用另一函數,而這一函數同樣內部調用其他函數,如此類推,其中任何一個函數運行失敗,調用函數都可能恢復并執行工作,而Microsoft需要跟蹤每個函數的運行路徑,并建立所有可能的錯誤代碼列表。
實際上我們在使用Win32的開發環境中,調用Windows函數可以利用GetLastError函數來知道所調用的Windows函數錯誤所指,而對自己的函數則需要自己編寫錯誤代碼,或說維護自己的錯誤代碼列表,以便與Windows函數一樣可以定位錯誤。換句話說,可以將Windows函數告訴調用者指明發生的錯誤的機制用于自己的函數體系。一方面可以利用Windows已有的錯誤代碼,在某個函數可能出現錯誤的地方設置最后錯誤代碼并返回,可采用Windows函數:
VOID SetLastError(DWORD dwErrCode);
那么可以用WinError.h中代碼,只要該代碼可能說明錯誤思想并讓調用者理解即可,如想反映句柄無效,可以設置錯誤代碼為6,錯誤代碼是32位的數字。
另一方面你認為有必要維護自己的錯誤列表,或WinError.h中的錯誤不足以反映你程序的錯誤性質,可以創建自己的代碼,Microsoft規定,該公司建立的所有錯誤代碼在第29位的信息位使用0,用戶自己創建的使1,可以確保自己的錯誤代碼與Microsoft不沖突。具體錯誤代碼域可如下:
? 位??? 31~30??????? 29?????????????? ?28?????? ???27~16????????? 15~0
內容??? 嚴重性?????? Microsoft/客戶????? 保留??????? 設備代碼??????? 異常代碼
含義??? 0=成功?????? 0=Microsoft公司??? 必須是0??? 由Microsoft???? 由Microsoft
公司定義????? 公司定義
定義的代碼??????????????????
??????? 1=供參考???? 1=客戶定義代碼
??????? 2=警告
??????? 3=錯誤
這里模擬了Microsoft Visual C6.0中Error Lookup程序,利用MFC基于對話框的程序實現,主要實現代碼如下:
?
void CErrorShowDlg::OnBtnLookUp()
{
?????? // TODO: Add your control notification handler code here
?????? //Get the error code
?????? BOOL bRetErrorCode;
?????? DWORD dwErrorCode=GetDlgItemInt(IDC_EdtErrorCode,&bRetErrorCode,FALSE);
?????? if(!bRetErrorCode)//無值
?????? {
????????????? AfxMessageBox("輸入錯誤的代碼!");
????????????? return;
?????? }
?????? //Get the error code's textual description
?????? HLOCAL hLocal=NULL;
?????? BOOL bRetErrorText=FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
????????????? ??????????? ?????????????????NULL,dwErrorCode,MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),
?????????????????????????????????????????????????????????????? ?(LPTSTR)&hLocal,0,NULL);
?????? if(hLocal != NULL)
?????? {
????????????? SetDlgItemText(IDC_EdtErrorShow,(LPCTSTR)LocalLock(hLocal));
????????????? LocalFree(hLocal);
?????? }else
????????????? SetDlgItemText(IDC_EdtErrorShow,TEXT("Error Number not found!"));
}
?
????????????????????? 如非? 2008-11-22
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的对程序错误的处理——Windows核心编程学习手札之一的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Unicode——Windows核心编程
- 下一篇: 进程——Windows核心编程学习手札系