日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

windows核心编程-第一章 对程序错误的处理

發布時間:2025/6/17 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 windows核心编程-第一章 对程序错误的处理 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

第一章-對程序錯誤的處理

? ? 在開始介紹Microsoft Windows 的特性之前,必須首先了解 Wi n d o w s的各個函數是如何進行錯誤處理的。

當調用一個Wi n d o w s函數時,它首先要檢驗傳遞給它的的各個參數的有效性,然后再設法執行任務。如果傳遞了一個無效參數,或者由于某種原因無法執行這項操作,那么操作系統就會返回一個值,指明該函數在某種程度上運行失敗了。表 1 - 1列出了大多數Wi n d o w s函數使用的返回值的數據類型。

?

? ? 一個Wi n d o w s函數返回的錯誤代碼對了解該函數為什么會運行失敗常常很有用。 M i c r o s o f t公司編譯了一個所有可能的錯誤代碼的列表,并且為每個錯誤代碼分配了一個 3 2位的號碼。

從系統內部來講,當一個Wi n d o w s函數檢測到一個錯誤時,它會使用一個稱為線程本地存儲器(thread-local storage) 的機制,將相應的錯誤代碼號碼與調用的線程關聯起來( 線程本地存儲器將在第2 1章中介紹) 。這將使線程能夠互相獨立地運行,而不會影響各自的錯誤代碼。當函數返回時,它的返回值就能指明一個錯誤已經發生。若要確定這是個什么錯誤,請調用G e t L a s t E r r o r函數:

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? DWORD GetLastError();

? ? 該函數只返回線程的3 2位錯誤代碼。當你擁有3 2位錯誤代碼的號碼時,必須將該號碼轉換成更有用的某種對象。 Wi n E r r o r. h頭文件包含了M i c r o s o f t公司定義的錯誤代碼的列表。下面顯示了該列表的某些內容,使你能夠看到它的大概樣子:


? ? ?如你所見,每個錯誤都有3種表示法:一個消息I D(這是你可以在源代碼中使用的一個宏,以便與G e t L a s t E r r o r的返回值進行比較) ,消息文本(對錯誤的英文描述)和一個號碼(應該避免使用這個號碼,可使用消息I D) 。請記住,這里只顯示了Wi n E r r o r. h頭文件中的很少一部分內容,整個文件的長度超過2 1 0 0 0行。

? ? 當Wi n d o w s函數運行失敗時,應該立即調用G e t L a s t E r r o r函數。如果調用另一個Wi n d o w s函數,它的值很可能被改寫。

? ? 注意 G e t L a s t E r r o r能返回線程產生的最后一個錯誤。如果該線程調用的Wi n d o w s函數運行成功,那么最后一個錯誤代碼就不被改寫,并且不指明運行成功。有少數Wi n d o w s函數并不遵循這一規則,它會更改最后的錯誤代碼;但是 Platform SDK文檔通常指明,當函數運行成功時,該函數會更改最后的錯誤代碼。

Wi n d o w s 9 8 許多Windows 98的函數實際上是用M i c r o s o f t公司的1 6Windows 3.1產品產生的1 6位代碼來實現的。這種比較老的代碼并不通過 G e t L a s t E r r o r之類的函數來報告錯誤,而且M i c r o s o f t公司并沒有在Windows 98中修改1 6位代碼,以支持這種錯誤處理方式。對于我們來說,這意味著Windows 98中的許多Wi n 3 2函數在運行失敗時不能設置最后的錯誤代碼。該函數將返回一個值,指明運行失敗,這樣你就能夠發現該函數確實已經運行失敗,但是你無法確定運行失敗的原因。

? ? 有些Wi n d o w s函數之所以能夠成功運行,其中有許多原因。例如,創建指明的事件內核對象之所以能夠取得成功,是因為你實際上創建了該對象,或者因為已經存在帶有相同名字的事件內核對象。你應搞清楚成功的原因。為了將該信息返回, M i c r o s o f t公司選擇使用最后錯誤代碼機制。這樣,當某些函數運行成功時,就能夠通過調用 G e t L a d t E r r o r函數來確定其他的一些信息。對于具有這種行為特性的函數來說, Platform SDK文檔清楚地說明了G e t L a s t E r r o r函數可以這樣使用。請參見該文檔,找出C r e a t e E v e n t函數的例子。

? ? 進行調試的時候,監控線程的最后錯誤代碼是非常有用的。 在Microsoft Visual studio 6.0中,M i c r o s o f t的調試程序支持一個非常有用的特性,即可以配置 Wa t c h窗口,以便始終都能顯示線程的最后錯誤代碼的號碼和該錯誤的英文描述。通過選定 Wa t c h窗口中的一行,并鍵入“@ e r r, h r” ,就能夠做到這一點。觀察圖1 - 1,你會看到已經調用了C r e a t e F i l e函數。該函數返回I N VA L I D _ H A N D L E _ VA L U E- 1)的H A N D L E,表示它未能打開指定的文件。但是Wa t c h窗口向我們顯示最后錯誤代碼(即如果調用 G e t L a s t E r r o r函數,該函數返回的錯誤代碼)是0 x 0 0 0 0 0 0 0 2。該Wa t c h窗口又進一步指明錯誤代碼2是指“系統不能找到指定的文件。 ”你會發現它與Wi n E r r o r. h頭文件中的錯誤代碼2所指的字符串是相同的。

?

OK,然后我就照著做,但是發現了一個尷尬的事情,我在vs2012上找不大watch窗口,搜索了下,說是在調試->窗口->監視(Debug->Window->Watch,然后我就去找,但是并沒有找到,一開始看到的是這個:

?

...后來無意中發現了,其實是當你點擊運行的時候,那個地方才會出現Watch的選項:

?

然后就是我在vs2012中寫了下上面說的那個:

?

然后又在網上找了一些常用技巧:

1.eg: int *p = new int[100];

如果只查看p的話,只能看到一個結果。可以使用:p,n 查看n個結果。

?

2.格式化數據和表達式賦值語句.

常用變量格式化符(表達式的值后跟逗號,接格式化符,如”(int)0xFFFF,d):

d,I:有符號的十進制數.

u ?:無符號的十進制數.

o ?:無符號的八

x,X:十六進制數.

l,h:d,i,u,o,x,X的長前綴或短前綴.

f ?:有符號浮點數.

e ?:有符號的科學計數法.

g ?:有符號的浮點或有符號的科學計數法,用其中較短的一個.

c ?:單字符.

s ?:字符串.

su :雙字節字符串.

st :雙字節字符串或ANSI字符串,取決于AUTOEXP.DAT中的Unicode String設置.

hr :Windows類標記.

wm :Windows消息碼.

?

常用內存轉儲對象的格式化符(用法同變量格式化符):

ma :64ASCII碼字符.

m ?:16進制書寫的16字節,后跟16ASCII字符.

mb :16進制書寫的16字節,后跟16ASCII字符.

mw :8個字長.

md :4個雙精度字.

mq :4個四倍字長的字.

mu :2字節字符(Unicode標準).

# ?:將指針擴展到指定的數值數目的內存存儲單元上.(#代表一個數字)

?

WATCH窗口允許重新設置數據變量的格式,

:可用BY,DW表達式來定位指針的偏移量;

可用&*運算符,且兩運算符都可直接操作內存地址;

甚至可用上下說明符明確指定變量的上下文.

總之,所有格式化方法和指定方法在WATCH窗口都有效

?

WATCH窗口是一個完整的表達式求值程序,可以在其中查看任何條件語句.

?

表達式中可用的偽寄存器(可當普通變量進行查看):

@ERR:最后一個錯誤值,GetLastError API返回相同的值.

@TIB:當前線程的線程信息塊.(調試器不能處理”FS:0″格式).

@CLK:時鐘寄存器.

@EAX,@EBX,@ECX,@EDX,@ESI,@EDI,@DIP,@ESP,@EBP,@EFL

????:Intel CPU寄存器.

@CS,@DS,@ES,@SS,@FS,@GS

????:Intel CPU段寄存器.

@ST0,@ST1,@ST2,@ST3,@ST4,@ST5,@ST6,@ST7

????:Intel CPU浮點寄存器.

?

3.適時編碼

?

許多時候只想對兩斷點間的執行時間有個大致印象,可用@CLK得出兩斷點間所需執行時間(包括調試器占用的時間).

需要輸入兩個@CLK觀察符,第一個是@CLK,第二個是@CLK=0.第二個的目的是重新運行時將定時器清0.

時間以微秒為單位,大多數情況下需要格式化為毫秒:@CLK/1000,d.

?

4.WATCH窗口中調用函數

?

大多數情況下用于執行專門編寫的校驗數據結構,保證數據的相關性的函數.在釋放構件中,從未調用過的函數不會被鏈接,因此不必擔

?

心這類函數會對影響發布構件.

如函數沒有參數,也要求使用括號”(),調用時像用普通函數一樣傳送參數.WATCH右邊將顯示函數返回值.

這里有些限制:

1.只能在一個單線程上下文中執行函數.如是多線程程序,將函數輸入到WATCH窗口中檢查結果后應立即從WATCH窗口清除,否則,如調

?

試函數在第二個線程上下文中執行,會立即終止第二個線程的運行.

2.調試函數必須在20秒內執行.如執行過程中出現異常,程序會在調試器中中止.

3.(常識)只對數據驗證進行內存讀取,如有問題,調用OutputDebugString類的函數.如更改內存或調用API函數—-盡管這是可能的,

?

無法預知可能會發生什么.

只要在WATCH窗口中重新計算表達式,已輸入WATCH窗口的調試函數就會執行:

.程序處于運行狀態并觸發某一斷點時.

.單步調試某一代碼行或某一指令時.

.WATCH窗口左邊編輯完成調試函數的文本并按下回車時.

.在運行程序時出現異常情況,并讓你返回調試器中時.

使用調試函數的建議:輸入調試函數并查看值后,立即從WATCH窗口清除;只為最關鍵的數據結構編寫調試函數;不要更改個別結構的轉

?

儲內像.

?

5.自動擴展自己的類型

?

常見的自動擴展是RECT,輸入RECT型的變量后直接顯示其中的某些數據成員的值.

自定義類型擴展時,只需將自己的類型入口加入<VS Common>\MSDev98\Bin目錄的AUTOEXP.DAT文件中.

:

擴展CreateProcess()所用到的PROCESS_INFORMATION結構

1.檢查調試器將該類型識別為什么.PROCESS_INFORMATION變量輸入WATCH窗口,右擊變量,選擇Properties,在這里它被標注為

?

_PROCESS_INFORMATION類型.

2.打開AUTOEXP.DAT文本文件,加入擴展入口.語法如下:

Type=[text]<member[format]>

本例中要查看hProcesshThread,故輸入:

_PROCESS_INFORMATION=hProcess=<hProcess,X> hThread=<hThread,X>

其中X表示以16進制查看.有個特殊的格式化符<,t>,用于通知調試器輸入最易派生類型的類型名.B派生至A,只有B有自動擴展規則,

?

B的自動擴展將會是后面跟隨著類A的自動擴展規則的類型名B.

?

6.Set Next Statement命令

?

可以在調試時從菜單運行,但也可在WATCH窗口中直接設置EIP寄存器—-小心,可能很容易摧毀程序.在最優化的釋放構件中,最安全的

?

方法是在Disassembly窗口中使用該命令.如代碼在堆棧上創建了臨時變量,更要多加小心.

最常用的情況是:在出問題的函數前設置一個斷點,檢查進入的參數,單步調試整個函數;如問題不是重復的,使用Set Next Statement

?

設置返回到斷點的執行點,并更改參數.這樣可在一個調試會話中測試多個假設,節省測試時間,但它不能用于所有場合,因為函數執行

?

會破壞其狀態.另一個常用地點是測試時填充數據結構,如表和數組,可用它輸入額外的數據并查看代碼如何處理–當某些數據條件難于復制時更為方便.

????Visual studio還配有一個小的實用程序,稱為Error Lookup。可以使用Error Lookup

將錯誤代碼的號碼轉換成相應文本描述(見圖1 - 2) 。如果在編寫的應用程序中發現一個錯誤,可能想要向用戶顯示該錯誤的文本描述。Wi n d o w s提供了一個函數,可以將錯誤代碼轉換成它的文本描述。該函數稱為 F o r m a t -M e s s a g e,顯示如下:


? ? F o r m a t M e s s a g e函數的功能實際上是非常豐富的,在創建向用戶顯示的字符串信息時,它是首選函數。該函數之所以有這樣大的作用,原因之一是它很容易用多種語言進行操作。該函數能夠檢測出用戶首選的語言(在Regional Settings Control Panel小應用程序中設定) ,并返回相應的文本。當然,首先必須自己轉換字符串,然后將已轉換的消息表資源嵌入你的 . e x e文件或D L L模塊中,然后該函數會選定正確的嵌入對象。 E r r o r S h o w示例應用程序(本章后面將加以介紹)展示了如何調用該函數,以便將M i c r o s o f t公司定義的錯誤代碼轉換成它的文本描述。

? ? 有些人常常問我,M i c r o s o f t公司是否建立了一個主控列表,以顯示每個 Wi n d o w s函數可能返回的所有錯誤代碼。可惜,回答是沒有這樣的列表,而且 M i c r o s o f t公司將永遠不會建立這樣的一個列表。因為在創建系統的新版本時,建立和維護該列表實在太困難了。建立這樣一個列表存在的問題是,你可以調用一個 Wi n d o w s函數,但是該函數能夠在內部調用另一個函數,而這另一個函數又可以調用另一個函數,如此類推。由于各種不同的原因,這些函數中的任何一個函數都可能運行失敗。有時,當一個函數運行失敗時,較高級的函數對它進行恢復,并且仍然可以執行你想執行的操作。為了創建該主控列表, M i c r o s o f t公司必須跟蹤每個函數的運行路徑,并建立所有可能的錯誤代碼的列表。這項工作很困難。而且,當創建系統的新版本時,這些函數的運行路徑還會改變。

1.1 定義自己的錯誤代碼

前面已經說明 Wi n d o w s函數是如何向函數的調用者指明發生的錯誤,你也能夠將該機制用于自己的函數。比如說,你編寫了一個希望其他人調用的函數,你的函數可能因為這樣或那樣的原因而運行失敗,你必須向函數的調用者說明它已經運行失敗。

若要指明函數運行失敗,只需要設定線程的最后的錯誤代碼,然后讓你的函數返回FA L S EI N VA L I D _ H A N D L E _ VA L U EN U L L或者返回任何合適的信息。若要設定線程的最后錯誤代碼,只需調用下面的代碼:

?

請將你認為合適的任何 3 2位號碼傳遞給該函數。嘗試使用 Wi n E r r o r. h中已經存在的代碼,圖1-2 Error Lookup窗口只要該代碼能夠正確地指明想要報告的錯誤即可。如果你認為 Wi n E r r o r. h中的任何代碼都不能正確地反映該錯誤的性質,那么可以創建你自己的代碼。錯誤代碼是個 3 2位的數字,劃分成表

1-2 所示的各個域。

1-2 錯誤代碼的域

?

這些域將在第2 4章中詳細講述。現在,需要知道的重要域是第 2 9位。M i c r o s o f t公司規定,他們建立的所有錯誤代碼的這個信息位均使用 0。如果創建自己的錯誤代碼,必須使 2 9位為1。這樣,就可以確保你的錯誤代碼與M i c r o s o f t公司目前或者將來定義的錯誤代碼不會發生沖突。

來一個自定義的例子:SetLastError((1<<29) + (1<<30) * 0 + 1);

1.2 ErrorShow示例應用程序

????E r r o r S h o w應用程序“01 ErrorShow. e x e”(在清單1 - 1中列出)展示了如何獲取錯誤代碼的文本描述的方法。該應用程序的源代碼和資源文件位于本書所附光盤上的 0 1 - E r r o r S h o w目錄下。一般來說,該應用程序用于顯示調試程序的 Wa t c h窗口和Error Lookup程序是如何運行的。當啟動該程序時,就會出現

如圖1 - 3所示的窗口。

?

可以將任何錯誤代碼鍵入該編輯控件。當單擊 Look up按鈕時,在底部的滾動窗口中就會顯示該錯誤的文本描述。該應用程序唯一令人感興趣的特性是如何調用F o r m a t M e s s a g e函數。下面是使用該函數的方法:

?

????第一個代碼行用于從編輯控件中檢索錯誤代碼的號碼。然后,建立一個內存塊的句柄并將它初始化為N U L LF o r m a t M e s s a g e函數在內部對內存塊進行分配,并將它的句柄返回給我們。當調用F o r m a t M e s s a g e函數時,傳遞了F O R M AT _ M E S S A G E _ F R O M _ S Y S T E M標志。該標志告訴F o r m a t M e s s a g e函數,我們想要系統定義的錯誤代碼的字符串。還傳遞了 F O R M AT _M E S S A G E _ A L L O C AT E _ B U F F E R標志,告訴該函數為錯誤代碼的文本描述分配足夠大的內存塊。該內存塊的句柄將在 h l o c a l變量中返回。第三個參數指明想要查找的錯誤代碼的號碼,第四個參數指明想要文本描述使用什么語言。

? ? 如果F o r m a t M e s s a g e函數運行成功,那么錯誤代碼的文本描述就位于內存塊中,將它拷貝到對話框底部的滾動窗口中。如果F o r m a t M e s s a g e函數運行失敗,設法查看N e t M s g . d l l模塊中的消息代碼,以了解該錯誤是否與網絡有關。使用 N e t M s g . d l l模塊的句柄,再次調用F o r m a t M e s s a g e函數。你會看到,每個 D L L(或. e x e)都有它自己的一組錯誤代碼,可以使用Message CompilerM C . e x e)將這組錯誤代碼添加給該模塊,并將一個資源添加給該模塊。這就是Visual StudioError Lookup工具允許你用M o d u l e s對話框進行的操作。

總結

以上是生活随笔為你收集整理的windows核心编程-第一章 对程序错误的处理的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。