日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

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

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

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

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

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

?

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

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

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

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


? ? ?如你所見,每個錯誤都有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頭文件中的很少一部分內(nèi)容,整個文件的長度超過2 1 0 0 0行。

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

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

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

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

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

?

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

?

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

?

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

?

然后又在網(wǎng)上找了一些常用技巧:

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

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

?

2.格式化數(shù)據(jù)和表達式賦值語句.

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

d,I:有符號的十進制數(shù).

u ?:無符號的十進制數(shù).

o ?:無符號的八

x,X:十六進制數(shù).

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

f ?:有符號浮點數(shù).

e ?:有符號的科學計數(shù)法.

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

c ?:單字符.

s ?:字符串.

su :雙字節(jié)字符串.

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

hr :Windows類標記.

wm :Windows消息碼.

?

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

ma :64ASCII碼字符.

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

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

mw :8個字長.

md :4個雙精度字.

mq :4個四倍字長的字.

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

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

?

WATCH窗口允許重新設置數(shù)據(jù)變量的格式,

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

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

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

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

?

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

?

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

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

@TIB:當前線程的線程信息塊.(調(diào)試器不能處理”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.適時編碼

?

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

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

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

?

4.WATCH窗口中調(diào)用函數(shù)

?

大多數(shù)情況下用于執(zhí)行專門編寫的校驗數(shù)據(jù)結(jié)構(gòu),保證數(shù)據(jù)的相關(guān)性的函數(shù).在釋放構(gòu)件中,從未調(diào)用過的函數(shù)不會被鏈接,因此不必擔

?

心這類函數(shù)會對影響發(fā)布構(gòu)件.

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

這里有些限制:

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

?

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

2.調(diào)試函數(shù)必須在20秒內(nèi)執(zhí)行.如執(zhí)行過程中出現(xiàn)異常,程序會在調(diào)試器中中止.

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

?

無法預知可能會發(fā)生什么.

只要在WATCH窗口中重新計算表達式,已輸入WATCH窗口的調(diào)試函數(shù)就會執(zhí)行:

.程序處于運行狀態(tài)并觸發(fā)某一斷點時.

.單步調(diào)試某一代碼行或某一指令時.

.WATCH窗口左邊編輯完成調(diào)試函數(shù)的文本并按下回車時.

.在運行程序時出現(xiàn)異常情況,并讓你返回調(diào)試器中時.

使用調(diào)試函數(shù)的建議:輸入調(diào)試函數(shù)并查看值后,立即從WATCH窗口清除;只為最關(guān)鍵的數(shù)據(jù)結(jié)構(gòu)編寫調(diào)試函數(shù);不要更改個別結(jié)構(gòu)的轉(zhuǎn)

?

儲內(nèi)像.

?

5.自動擴展自己的類型

?

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

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

:

擴展CreateProcess()所用到的PROCESS_INFORMATION結(jié)構(gòu)

1.檢查調(diào)試器將該類型識別為什么.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>,用于通知調(diào)試器輸入最易派生類型的類型名.B派生至A,只有B有自動擴展規(guī)則,

?

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

?

6.Set Next Statement命令

?

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

?

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

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

?

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

?

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

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

將錯誤代碼的號碼轉(zhuǎn)換成相應文本描述(見圖1 - 2) 。如果在編寫的應用程序中發(fā)現(xiàn)一個錯誤,可能想要向用戶顯示該錯誤的文本描述。Wi n d o w s提供了一個函數(shù),可以將錯誤代碼轉(zhuǎn)換成它的文本描述。該函數(shù)稱為 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函數(shù)的功能實際上是非常豐富的,在創(chuàng)建向用戶顯示的字符串信息時,它是首選函數(shù)。該函數(shù)之所以有這樣大的作用,原因之一是它很容易用多種語言進行操作。該函數(shù)能夠檢測出用戶首選的語言(在Regional Settings Control Panel小應用程序中設定) ,并返回相應的文本。當然,首先必須自己轉(zhuǎn)換字符串,然后將已轉(zhuǎn)換的消息表資源嵌入你的 . e x e文件或D L L模塊中,然后該函數(shù)會選定正確的嵌入對象。 E r r o r S h o w示例應用程序(本章后面將加以介紹)展示了如何調(diào)用該函數(shù),以便將M i c r o s o f t公司定義的錯誤代碼轉(zhuǎn)換成它的文本描述。

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

1.1 定義自己的錯誤代碼

前面已經(jīng)說明 Wi n d o w s函數(shù)是如何向函數(shù)的調(diào)用者指明發(fā)生的錯誤,你也能夠?qū)⒃摍C制用于自己的函數(shù)。比如說,你編寫了一個希望其他人調(diào)用的函數(shù),你的函數(shù)可能因為這樣或那樣的原因而運行失敗,你必須向函數(shù)的調(diào)用者說明它已經(jīng)運行失敗。

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

?

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

1-2 所示的各個域。

1-2 錯誤代碼的域

?

這些域?qū)⒃诘?span style="font-family:Calibri">2 4章中詳細講述。現(xiàn)在,需要知道的重要域是第 2 9位。M i c r o s o f t公司規(guī)定,他們建立的所有錯誤代碼的這個信息位均使用 0。如果創(chuàng)建自己的錯誤代碼,必須使 2 9位為1。這樣,就可以確保你的錯誤代碼與M i c r o s o f t公司目前或者將來定義的錯誤代碼不會發(fā)生沖突。

來一個自定義的例子: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目錄下。一般來說,該應用程序用于顯示調(diào)試程序的 Wa t c h窗口和Error Lookup程序是如何運行的。當啟動該程序時,就會出現(xiàn)

如圖1 - 3所示的窗口。

?

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

?

????第一個代碼行用于從編輯控件中檢索錯誤代碼的號碼。然后,建立一個內(nèi)存塊的句柄并將它初始化為N U L LF o r m a t M e s s a g e函數(shù)在內(nèi)部對內(nèi)存塊進行分配,并將它的句柄返回給我們。當調(diào)用F o r m a t M e s s a g e函數(shù)時,傳遞了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函數(shù),我們想要系統(tǒng)定義的錯誤代碼的字符串。還傳遞了 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標志,告訴該函數(shù)為錯誤代碼的文本描述分配足夠大的內(nèi)存塊。該內(nèi)存塊的句柄將在 h l o c a l變量中返回。第三個參數(shù)指明想要查找的錯誤代碼的號碼,第四個參數(shù)指明想要文本描述使用什么語言。

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

總結(jié)

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

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。