版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
第6章對(duì)錯(cuò)誤的處理即使程序員最好的愿望,而且計(jì)劃工作做得非常周密,也無(wú)法避免代碼出現(xiàn)錯(cuò)誤。這些錯(cuò)誤可能是編程員的錯(cuò)誤(0錯(cuò)誤(比如想要保存的文件太大,磁盤(pán)上的空閑空間放不下,或者是時(shí)間上的錯(cuò)誤(比如試圖給尚未完全加載的窗體設(shè)置焦點(diǎn)。應(yīng)該努力編寫(xiě)沒(méi)有錯(cuò)誤的代碼,不過(guò)創(chuàng)建每個(gè)過(guò)程時(shí)也應(yīng)該假設(shè)它可能出現(xiàn)錯(cuò)誤。這意味著每個(gè)過(guò)程必須包含錯(cuò)誤處理程序。實(shí)際上可能出現(xiàn)的程序錯(cuò)誤的數(shù)量是很大的,但是它們基本上可以分為兩種類(lèi)型:一種是isualBacsic的編譯器無(wú)法對(duì)代碼進(jìn)行編,iualBaic將不執(zhí)行該過(guò)程,并且你也不能向用戶(hù)提供帶有編譯錯(cuò)誤的運(yùn)行期版本應(yīng)用程序。大多數(shù)編譯錯(cuò)誤是句法錯(cuò)誤造成的。PublicSubMyProcedure(intMyVariableAsCall語(yǔ)句中增加了CallMyProcedure(invVariable1,運(yùn)行期錯(cuò)誤是在程序運(yùn)行時(shí)產(chǎn)生的,并且通常是試圖對(duì)變量執(zhí)行無(wú)效操作而產(chǎn)生的結(jié)果。例如,下面這個(gè)代碼不會(huì)產(chǎn)生編譯錯(cuò)誤(如果intMyVariable是個(gè)已經(jīng)說(shuō)明的變量,那么它的句。Print10/intyVariable的值是0,VisualBacsic10不能被0除。如果在IDE中運(yùn)行一個(gè)項(xiàng)目時(shí)出現(xiàn)一個(gè)運(yùn)行期錯(cuò)誤,代碼就會(huì)在出錯(cuò)的代碼行上停止運(yùn)行,并顯示一條出錯(cuò)消息。在已經(jīng)編譯的程序中,處理的錯(cuò)誤是致命的,它會(huì)導(dǎo)致整個(gè)應(yīng)用程序運(yùn)行癱瘓。通過(guò)創(chuàng)建錯(cuò)VisualBasicVisualBasic有兩個(gè)設(shè)置在很大程度上影響你創(chuàng)建非常堅(jiān)實(shí)的代碼的能力。一個(gè)設(shè)置項(xiàng)是CompileOnDemand(按需要進(jìn)行編譯,另一個(gè)設(shè)置項(xiàng)是BackgroundCompile(編譯??梢源蜷_(kāi)Options框,選定General選項(xiàng)卡,然后對(duì)這兩個(gè)設(shè)置項(xiàng)進(jìn)行設(shè)置,如圖6-1所示。當(dāng)選定CompileOnDemand時(shí),如果單擊上的un按鈕,或者按F5鍵,ViualBaic并不全面編譯你的項(xiàng)目。相反,只在過(guò)程時(shí),才對(duì)這些過(guò)程進(jìn)行編譯。使用CompileOnDemand,通??墒贡容^大的項(xiàng)目或者速度較慢的計(jì)算機(jī)上的項(xiàng)目能夠更快地啟動(dòng)運(yùn)行,但是它也會(huì)產(chǎn)生某些不被注意的編譯錯(cuò)誤。 如果按Ctrl+F5鍵,或者從Run菜單中選擇StartWithFullCompile(啟動(dòng)全面編譯),那么不管你是否選定CompileOnDemand設(shè)置項(xiàng),都會(huì)使項(xiàng)目得到全面編譯。圖6-1進(jìn)行編程時(shí),CompileOnDemand和Background.exe或.dll選定CompileOnDemand并不能夠發(fā)布帶有編譯錯(cuò)誤的代碼。但是,選定CompileOnDemand后,會(huì)導(dǎo)致編譯錯(cuò)誤隨著時(shí)間的推移而不斷增加,從而在最后試圖進(jìn)行全面編譯時(shí),迫使你對(duì)代碼進(jìn)行大量的糾錯(cuò)。如果在IDE中調(diào)試項(xiàng)目,你會(huì)變得心煩意亂,因?yàn)閂isualBasic常常必須停止(不只是暫停)運(yùn)行,以便進(jìn)行糾錯(cuò)操作。這使得調(diào)試正在運(yùn)行的項(xiàng)目時(shí)對(duì)大量編譯錯(cuò)誤的糾正操作變得非常麻煩。如果你的計(jì)算機(jī)能夠在合理的時(shí)間內(nèi)全面編譯項(xiàng)目,那么可以考慮關(guān)閉CompileOn。也可以使pileOnDemand保持選定狀態(tài),但是要定期按Ctrl+F5便重新運(yùn)行你的項(xiàng)目。這使你在編程時(shí)能夠定期糾正編譯錯(cuò)誤,而不必糾正大量的編譯錯(cuò)誤。選定CompileOnDemand時(shí),也可以決定是否選定BackgroundCompile選項(xiàng)。如果選定BackgroundCompile,就可以在過(guò)程和模塊被時(shí)對(duì)它們進(jìn)行編譯,不過(guò)VisualBasic也使用空閑時(shí)間對(duì)尚未的模塊進(jìn)行編譯。隨著時(shí)間的推移,項(xiàng)目就可以得到全面編譯。使用BackgroundCompile選項(xiàng),可以更快地加載全面編譯的項(xiàng)目,并使編譯錯(cuò)誤保持在最低水平,因?yàn)槟銜?huì)隨時(shí)關(guān)注未被的模塊中的錯(cuò)誤。同樣,你應(yīng)該知道糾正編譯錯(cuò)誤常常會(huì)迫使在能夠編寫(xiě)有效的錯(cuò)誤處理代碼之前,你必須了解VisualBasic的Err對(duì)象,這是個(gè)運(yùn)行期對(duì)象,它包含了關(guān)于錯(cuò)誤的信息。當(dāng)程序運(yùn)行時(shí)遇到一個(gè)錯(cuò)誤,或者當(dāng)你使用Err對(duì)象的Raise方法故意一個(gè)錯(cuò)誤時(shí),便形成Err對(duì)象的屬性。當(dāng)遇到OnError語(yǔ)句(比如OnErrorResumeNext),并且在使用ExitSub、ExitFunction或ExitProperty語(yǔ)句退出一個(gè)過(guò)程后,Error對(duì)象的屬性值就被清除。若要顯式清除Err對(duì)象,可以表6- 用于標(biāo)識(shí)該錯(cuò)誤的號(hào) 當(dāng)前Visualbasic項(xiàng)目的名 與錯(cuò)誤相關(guān)的VisualBasic幫助文件所在的驅(qū)動(dòng)器、路徑和文件 VisualBasic幫助文件用于該錯(cuò)誤的上下文asDrr 在32位ndows操作系統(tǒng)上,上次調(diào)用動(dòng)態(tài)庫(kù)(D)的系統(tǒng)錯(cuò)誤代碼。asDlrror屬性是只讀屬性意,Err對(duì)象的屬性被設(shè)置為該錯(cuò)誤的相應(yīng)值。如果需要使用些值中的任何一個(gè)值,應(yīng)該立即對(duì)它們進(jìn)行操作,或者在執(zhí)行其他操作之前將它們存放在一個(gè)變量中,因?yàn)镋rrErr對(duì)象中的屬性值只能,Err象并不錯(cuò)誤史信息列表。將一個(gè)項(xiàng)目當(dāng)作已經(jīng)編譯的程序運(yùn)行時(shí),未捕獲的錯(cuò)誤會(huì)造成致命的,它們會(huì)導(dǎo)致程序終止運(yùn)行。必須盡一切努力防止發(fā)生這種情況。若要防止代碼中的錯(cuò)誤中碼的運(yùn)行(并終止已編譯程序的運(yùn)行iualBaic并不顯示出錯(cuò)消息,也不終止代碼的運(yùn)行。相反,你編寫(xiě)的專(zhuān)門(mén)用來(lái)處理錯(cuò)誤的代OnError代碼錯(cuò)誤會(huì)將過(guò)的錯(cuò)誤處理程序的調(diào)用?!疤嵘钡蕉褩V械妮^置(本章后面將詳細(xì)介紹。如果一個(gè)過(guò)程的錯(cuò)誤能夠以這種方式出現(xiàn),就應(yīng)該在過(guò)程的開(kāi)頭用突出的注釋來(lái)明確說(shuō)明這一行為特性。當(dāng)出現(xiàn)錯(cuò)誤時(shí),使用On 使用OnErrorResumeNext語(yǔ)句,不中碼的執(zhí)行,也不轉(zhuǎn)移到別的代碼上去執(zhí)行,而可以在一個(gè)過(guò)創(chuàng)建多個(gè)錯(cuò)誤處理程序,但每次只能激活一個(gè)錯(cuò)誤處理程序。isualBasic將的OnError語(yǔ)句中指明的處理程序視為已經(jīng)激活的錯(cuò)誤處理程序。切換一個(gè)過(guò)的不同位置上的錯(cuò)誤處理程序,往往是很有好處的,理解各個(gè)錯(cuò)誤處理程序如何運(yùn)行,是利用這能的關(guān)鍵。使用OnResumeNext對(duì)錯(cuò)誤進(jìn)行處理的最簡(jiǎn)(和最)的方法是使用OnErrorReumeext語(yǔ)句。OnErrorResumeNext語(yǔ)句規(guī)定,代碼中的錯(cuò)誤將完全被忽略,存在錯(cuò)誤的代碼行被跳過(guò),然后繼續(xù)執(zhí)例如,下面這個(gè)過(guò)程存在一個(gè)運(yùn)行期錯(cuò)誤(0除的錯(cuò)誤),它由OnErrorResumePrivateSub‘*Purpose:TestOnErrorResumeOnErrorResumeDebug.Prin10/EndDebug.print語(yǔ)句產(chǎn)生了一個(gè)被0除的錯(cuò)誤。但是,由于存在一個(gè)已經(jīng)激活的錯(cuò)(由OnErrorResumeNext指定),因此該錯(cuò)誤被忽略,并在下一個(gè)語(yǔ)句(即EndSub語(yǔ)句)上恢沒(méi)有顯示出錯(cuò)消息,Err對(duì)象仍然包含關(guān)于該錯(cuò)誤的信息。下面這個(gè)過(guò)程說(shuō)明了如何隨時(shí)測(cè)試11∶Divisionbyzero。PrivateSub‘*Purpose:DetectanerrorusingtheErrOnErrorResumeNextDebug.Print10/0‘*Ifanerroroccurred,displayitsnumberandIfErr.Number>0MsgBoxErr.Number&“:“&Err.Description,EndEnd這種方法有許多用處。例如,你想用輸入文本框的數(shù)據(jù)在數(shù)據(jù)庫(kù)中創(chuàng)建一個(gè)新記錄,但是創(chuàng)建記錄的表格中不允許相重的值。你可以設(shè)法找出與文本框中的輸入數(shù)據(jù)相一致的記錄,然Error3022(記錄),如下面的過(guò)程所示:PrivateSub‘*Purpose:Createarecordina fromthedataontheOnErrorResumeDimrstMyTableAsConstc_DuplicateRecordError=‘*CreateaRecordsetfromthemodule-levelDatabaseSetrstMyTable=m_dbMyDatabase.OpenRecordset(“MyTable",‘*Attempttoaddanewrecordtothedatabase.rstMyTable.AddNewrstMyTable![Name]=txtName.TextrstMyTable.Update‘*TestforduplicatevalueIfErr.Number=c_DuplicateRecordErrorMsgBox“Thisnameexistsinthedatabase,andduplicates“&“arenotallowed.”,EndSub注意nEroreuee象打交道后,檢查Err對(duì)象,你肯定能夠知道是哪個(gè)對(duì)象導(dǎo)致了錯(cuò)誤的發(fā)生,這個(gè)對(duì)象就是在Err.Source除非你捕獲了一個(gè)意料之外的錯(cuò)誤,比如前面代碼中的那種錯(cuò)誤,否則忽略代碼中的錯(cuò)誤是非常的,并且是一種不得已時(shí)采用的辦法。當(dāng)一個(gè)過(guò)出現(xiàn)了意料之外的錯(cuò)誤時(shí),該過(guò)程就會(huì)產(chǎn)生許多問(wèn)題。如果忽略該錯(cuò)誤,就會(huì)對(duì)用戶(hù)產(chǎn)生嚴(yán)重的影響,比如數(shù)據(jù)沒(méi)有保存,或者保存不正確。許多況下,當(dāng)出現(xiàn)代錯(cuò)誤時(shí),須執(zhí)行某些操作,將代的執(zhí)行轉(zhuǎn)移到OnErr oTo語(yǔ)句中指定的誤處理程序。語(yǔ)句的法如下:On oToli請(qǐng)注意,line必須是指與On 在這個(gè)句法中,line有兩個(gè)意思。首先它是現(xiàn)錯(cuò)誤時(shí)要轉(zhuǎn)移到的這個(gè)代碼行號(hào)。不過(guò)PrivateSub‘*Purpose:TesttheOn oTostatementby generatingarun-On oToDebug.Print“LineDebug.Print10/Debug.Print“LineDebug.Print“LineEnd你可能認(rèn)為,被0除的錯(cuò)誤會(huì)導(dǎo)致代碼在輸出文本line4這個(gè)語(yǔ)句上繼續(xù)執(zhí)行,因?yàn)檫@是代碼的第四個(gè)語(yǔ)句(不是計(jì)數(shù)注釋。不僅這種情況不會(huì)發(fā)生,而且該代碼實(shí)際上會(huì)導(dǎo)致產(chǎn)生一個(gè)編譯錯(cuò)誤,并且代碼根本不會(huì)執(zhí)行。當(dāng)指定一個(gè)行號(hào)時(shí),你必須用該行號(hào)作為某個(gè)特定語(yǔ)句的標(biāo)記,如下所示:PrivateSub‘*Purpose:TesttheOn oTostatementby generatingarun-timeOn oToDebug.Print“LineDebug.Print10/Debug.Print“Line4Debug.Print“LineEnd行的語(yǔ)句。你使用的實(shí)際號(hào)碼是不連貫的,它們不必對(duì)應(yīng)于實(shí)際行號(hào),也不必按任何順序來(lái)排列。注意不能使用0作為行號(hào)。0有它的特殊用處,在后面介紹line的第二個(gè)和更常見(jiàn)的用處是提供一個(gè)行標(biāo)注。行標(biāo)注是個(gè)文本串,用于標(biāo)識(shí)一個(gè)單行代碼。行標(biāo)注可以是任何字符的組合,它以一個(gè)字母開(kāi)始,以冒號(hào)()結(jié)尾。例如,下面這個(gè)過(guò)程包含一個(gè)標(biāo)記。當(dāng)出現(xiàn)被0OnErroTo語(yǔ)句轉(zhuǎn)移到標(biāo)注為PROC_ER的PrivateSub‘*Purpose:UsealinelabeltodivertcodeOn oToDebug.Print“LineDebug.Print10/Debug.Print“LineDebug.Print“LineEnd注意標(biāo)注應(yīng)該全部使用大寫(xiě)字母,使之更加醒目。另外,不應(yīng)該將多個(gè)語(yǔ)句放在一個(gè)代碼行上,這條規(guī)則也適用于標(biāo)注,因?yàn)闃?biāo)注也被視為代碼語(yǔ)句。當(dāng)控制轉(zhuǎn)移到標(biāo)注nErrorTo時(shí)才執(zhí)行錯(cuò)誤處理程序,應(yīng)該在錯(cuò)誤處理程序前面加上Extb、Eituntin或Eitroerty語(yǔ)句(如果遵守第2章中的編程說(shuō)明2.3.2,Eit語(yǔ)句將緊隨RCEIT標(biāo)注之后,并且將是過(guò)PrivateSub‘*PurposeOn oToExitEnd在這個(gè)代碼例子中,一個(gè)代碼錯(cuò)誤導(dǎo)致代碼的執(zhí)行跳到PROC_ERR標(biāo)注處,然后,代碼繼續(xù)執(zhí)行,直到它到達(dá)EndSub語(yǔ)句為止。不必讓代碼運(yùn)行通過(guò)該過(guò)程的剩余部分,直到它到達(dá)EndSub、EndFunction或EndProperty語(yǔ)句。也可以執(zhí)行下列操作:使用一個(gè)ExitSub、ExitFunction或ExitProperty語(yǔ)句,迫使代碼的執(zhí)行退出該過(guò)程(請(qǐng)使用GoToPROC_EXIT與ExitSub、ExitFunction或ExitProperty語(yǔ)句的組合,強(qiáng)制代碼的PrivateSub‘*Purpose:TestthebehaviorofGoToinanerrorOn oToDebug.Print10/0ExitMsgBoxMe.Name&“|MyProcedure”&vbCrLf&Err.Number&vbCrLf&_GoToEndPrivateSub‘*Purpose:TestthebehaviorofResumeNextin errorOn oTo‘*ErrorisgeneratedonthenextDebug.Print10/Debug.Print“CodeReturnsExitMsgBoxMe.Name&“|MyProcedure”&vbCrLf&Err.Number&vbCrLf&_ResumeEnd這個(gè)過(guò)的錯(cuò)誤使得代碼轉(zhuǎn)移到PROC_ERR塊中的代碼而繼續(xù)執(zhí)行。當(dāng)遇到Resume使用下面所示的Resume<line>,你可以轉(zhuǎn)移到產(chǎn)生錯(cuò)誤的過(guò)的某個(gè)代碼語(yǔ)句。line參數(shù)的作用與它在OnErrorResume<line>語(yǔ)句中的情況相同。PrivateSub‘*Purpose:DemonstrateResume<line>inanerrorOn oToDebug.Print“LineDebug.Print10/Debug.Print“LineDebug.Print“Line5"ExitResumeEnd錯(cuò)誤處理程序最擅長(zhǎng)的功能也許是它能糾正錯(cuò)誤。如果它能糾正錯(cuò)誤,將控制權(quán)返回給出錯(cuò)的語(yǔ)句,那么代碼幾乎就象從未發(fā)生過(guò)錯(cuò)誤一樣。雖然糾正錯(cuò)誤所用的方法取決于當(dāng)時(shí)的條件,但是返回到出錯(cuò)的代碼行是很簡(jiǎn)單的,并且是連貫一致的。若要使代碼返回到產(chǎn)生錯(cuò)誤的語(yǔ)句繼續(xù)執(zhí)行,請(qǐng)使用ResumePrivateSub‘*Purpose:DemonstratetheResumestatementin errorOn oToDimintFileNumberAsIntegerDim AsConstc_MaxRetries=Constc_LockedFileError=70intFileNumber=1Open“C:\Test.txt”ForOutputAsExit‘*Iftheerrorindicatesthatthefileislocked,attemptto‘*thefileagainuntilc_MaxRetriesattemptshavebeenIfErr.Number=c_LockedFileError‘*If umnumberofattemptshasbeen l‘*userthatthefileislockedandgetIfintRetries>c_MaxRetriesMsgBox“Fileislocked!",GoToEnd‘*CallacustomPauseprocedurethatpausesa‘*numberofCallintRetries=intRetries+EndIfEnd這個(gè)代碼例子設(shè)法打開(kāi)一個(gè)名叫:\est.txt的文件。如果該文件被另一個(gè)應(yīng)用程序鎖定了,就會(huì)出現(xiàn)一個(gè)錯(cuò)誤,代碼將轉(zhuǎn)到錯(cuò)誤處理程序繼續(xù)執(zhí)行。然后錯(cuò)誤處理程序負(fù)責(zé)執(zhí)行下列操作:如果錯(cuò)誤處理程序被調(diào)用的次數(shù)少 C_MaxRetries規(guī)定的最大次數(shù),它將調(diào)用一個(gè)自義的Pause(暫停)例程。然后intRetries的值遞增,并返回Open語(yǔ)句繼如果錯(cuò)誤處理程序調(diào)用的次數(shù)超過(guò)了允許的次數(shù),便向用戶(hù)顯示一條消息,同時(shí)退出該過(guò)程。有一個(gè)非常重要的問(wèn)題你必須了解,那就是錯(cuò)誤如何在調(diào)用棧中向上移動(dòng)。為了理解這個(gè)問(wèn)題,有兩個(gè)術(shù)語(yǔ)是必須介紹的。一個(gè)術(shù)語(yǔ)是“已激活的錯(cuò)誤處理程序”,指OnError語(yǔ)句中最近指定的錯(cuò)誤處理程序。另一個(gè)術(shù)語(yǔ)是“活動(dòng)的錯(cuò)誤處理程序”,指正在處理錯(cuò)誤的進(jìn)的錯(cuò)誤處理程序。請(qǐng)注意,可能存在這樣一種情況,即錯(cuò)誤處理程序已經(jīng)被激活,但它不是活動(dòng)的處理程序。一旦錯(cuò)誤處理程序被激活,它將保持激活狀態(tài),直到另一個(gè)錯(cuò)誤處理程序被激活,或者包含錯(cuò)誤處理程序的過(guò)程超出其作用域?yàn)橹?。?dāng)包含錯(cuò)誤處理程序的過(guò)程超出其作用域時(shí),便返回調(diào)用過(guò)程繼續(xù)執(zhí)行,同時(shí)上次被激活的錯(cuò)誤處理程序再次被激活。PrivateSub‘*Purpose:EnableanerrorhandlerandcallanotherOnErrorResumeNextCallTestSubEndPrivateSub‘*Purpose:DemonstrateerrorhandlersandthecallOn oToDebug.Print10/0ExitGoToEnd當(dāng)cmdCreateErrorHandler按鈕被點(diǎn)擊時(shí),OnErrorResumeNext語(yǔ)句便激活一個(gè)錯(cuò)誤處理程序。當(dāng)TestSub過(guò)程被調(diào)用時(shí),它的錯(cuò)誤處理程序就變?yōu)榧せ顮顟B(tài),在TestSub過(guò)遇到的任PrivateSubcmdCreat‘*Purpose:EnableanerrorhandlerandcallanotherOnErrorResumeNextCallTestSubEndPrivateSubTestEndClick事件中的OnErrorResumeNext語(yǔ)句就激活一個(gè)錯(cuò)誤處理程序。當(dāng)TestSub過(guò)程被調(diào)用時(shí),該過(guò)的錯(cuò)誤處理程序?qū)⒆兂杉せ顮顟B(tài)。由于TestSub過(guò)程不包含任何錯(cuò)誤處理程序,因此,在執(zhí)行TestSub過(guò)程的期間,激活的錯(cuò)誤處理程序(通過(guò)Click在TestSub過(guò)遇到一個(gè)錯(cuò)誤時(shí),將會(huì)發(fā)生什么情況呢?下面兩個(gè)過(guò)程說(shuō)明了這種情況PrivateSub‘*Purpose:DemonstrateerrorhandlersandthecallOnErrorResumeNextCallTestSubMsgBox“Statement procedure",EndPrivateSub‘*Generatearun-timeDebug.Print10/MsgBox“Statemenaftererror",End當(dāng)Click事件被時(shí),便使用OnErrorResumeNext激活一個(gè)錯(cuò)誤處理程序。當(dāng)代碼的執(zhí)行轉(zhuǎn)移到TestSub過(guò)程上時(shí),該錯(cuò)誤處理程序?qū)⒈3旨せ顮顟B(tài),因?yàn)樵赥estSub過(guò)沒(méi)有激活任何錯(cuò)誤處理程序。當(dāng)出現(xiàn)被0除的錯(cuò)誤時(shí),將會(huì)輸出什么呢?由于TestSub過(guò)不存在錯(cuò)誤處理程序,代碼的執(zhí)行便直接返回調(diào)用過(guò)程(即CmdCreateErrorHandler_Click過(guò)程),由它的已激活的錯(cuò)誤處理程序?qū)λM(jìn)行處理。由于該錯(cuò)誤處理程序是個(gè)ResumeNext錯(cuò)誤處理程序,因此,你可能認(rèn)為緊跟在錯(cuò)誤后面的語(yǔ)句(在TestSub過(guò))將是下一個(gè)要執(zhí)行的語(yǔ)句。實(shí)際上并非如此。緊跟在對(duì)TestSub調(diào)用的后面的語(yǔ)句將成為下一個(gè)執(zhí)行的語(yǔ)句,并輸出文本“Statementin procedure”。OnError語(yǔ)句不能將代碼的執(zhí)行引向它所在過(guò)程的外面。這個(gè)概念也適用于多個(gè)嵌套的過(guò)程。如果在一個(gè)過(guò)出現(xiàn)錯(cuò)誤,而該過(guò)程并沒(méi)有已激活的錯(cuò)誤處理程序,那么就要檢查調(diào)用帶有錯(cuò)誤的過(guò)程的那個(gè)過(guò)程,以便找出已經(jīng)激活但并不是活動(dòng)的錯(cuò)誤處理程序。這個(gè)檢查將在調(diào)用棧中連續(xù)向上進(jìn)行,直到找出一個(gè)已激活但并不是活動(dòng)的錯(cuò)誤處理程序,或者到達(dá)調(diào)用棧的頂部。如果到達(dá)了調(diào)用棧的頂部,該錯(cuò)誤即被視為未捕獲的錯(cuò)誤。如果遇到一個(gè)已被激活但不是活動(dòng)的錯(cuò)誤處理程序,便執(zhí)行該錯(cuò)誤,然后在包含該處理程序的過(guò)繼續(xù)行。使用On 有時(shí)需要在運(yùn)行時(shí)取消已激活的錯(cuò)誤處理程序的激活狀態(tài)。在本章的開(kāi)頭,講過(guò),當(dāng)使用OnErroTo語(yǔ)句時(shí),不能使用行號(hào)0。這是因?yàn)槭褂眯刑?hào)0會(huì)使當(dāng)前已激活的錯(cuò)誤處理PrivateSub‘*Purpose:Demonstratedisablinganerror arunOn oToOn oToDebug.Print10/0ExitCallShowError(Me.Name,“cmdDisableErrorHandler",Err.Number,_GoToEnd該過(guò)的第一個(gè)語(yǔ)句用于激活一個(gè)錯(cuò)誤處理程序。但是OnErrorGoTo0語(yǔ)句則用于取消錯(cuò)誤處理程序的激活狀態(tài)。因此,被0除的錯(cuò)誤就不能捕獲,同時(shí)VisualBasic將顯示一條出錯(cuò)注意OnErrorGoTo0只能使當(dāng)前過(guò)的錯(cuò)誤處理程序取消激活狀態(tài)。如果OnErroTo0語(yǔ)句后面遇到了一個(gè)錯(cuò)誤,該錯(cuò)誤將在調(diào)用棧中向上傳遞,就象該過(guò)程中根本沒(méi)有錯(cuò)誤處理程序一樣。如果在調(diào)用棧中的較置上找到一個(gè)已激活但不是讓VisualBasic中止代碼的執(zhí)行,這樣做常常是非常不利的。當(dāng)代碼的執(zhí)行中止時(shí),會(huì)看到一條相關(guān)的出錯(cuò)消息,并告訴你出現(xiàn)錯(cuò)誤的代碼行,這對(duì)于代碼的調(diào)試來(lái)說(shuō)是大有幫助的。VisualBasic為處理代碼設(shè)計(jì)時(shí)遇到的錯(cuò)誤而使用的方法取決于VisualBasicIDE的ErrorTrap屬圖6-2選定Options框中General選項(xiàng)卡上的一個(gè)選項(xiàng),就能改 ErrorTrap(捕獲錯(cuò)誤屬性是VisualBasic環(huán)境的一個(gè)屬性,不是某個(gè)項(xiàng)目的屬性。你操作的每個(gè)項(xiàng)目,即使在關(guān)閉和重新啟動(dòng)VisualBaic之后,均使用該設(shè)置值。若要為isualBasic的當(dāng)前會(huì)話設(shè)置ErrorTrap選項(xiàng),而不必為將來(lái)的會(huì)話修改默認(rèn)值,請(qǐng)使用代碼窗口的快捷菜單上的oggle命令(見(jiàn)圖6-3。圖6-3從任何代碼窗口的快捷菜單中選擇Toggle命令,就可以為BreakOnAllErrors(在所有錯(cuò)誤上中止BreakInClassModule(在類(lèi)模塊止BreakOnUnhandledErrors(在未處理的錯(cuò)誤上中止BreakOnAllErrors實(shí)際上可使所有錯(cuò)誤處理程序均取消激活狀態(tài)。當(dāng)出現(xiàn)一個(gè)錯(cuò)誤時(shí),VisualBasic顯示一條出調(diào)試ActiveX組件時(shí),BreakInClassModule設(shè)置值是最有用的。一般來(lái)說(shuō),調(diào)用ActiveX組件的方法的過(guò)的已激活錯(cuò)誤處理程序,將負(fù)責(zé)處理ActiveX組件的過(guò)尚未處理的任何錯(cuò)誤。BreakInClassModule設(shè)置值規(guī)定,不在ActiveX組件中處理的錯(cuò)誤,會(huì)使ActiveX項(xiàng)目在產(chǎn)生該錯(cuò)誤的語(yǔ)句上進(jìn)入中止方式。這將使不是在ActiveX組件中處理的錯(cuò)誤無(wú)法在調(diào)用棧BreakOnUnhandledError設(shè)置值能夠非常接近地模仿錯(cuò)誤在已編譯程序中被處理的情況。被已激活的錯(cuò)誤處理程序捕獲的錯(cuò)誤將由這些處理程序進(jìn)行處理,并且只有未處理的錯(cuò)誤才會(huì)將錯(cuò)誤處理功能添加給項(xiàng)目中的所有過(guò)程,這是件令人感到乏味的工作,但卻是必須做的一件事情。意料之外的所有錯(cuò)誤都必須以相同格式向用戶(hù)顯示,這需要編寫(xiě)相當(dāng)長(zhǎng)的代碼。如果增加一個(gè)錯(cuò)誤處理程序,事情就好辦了。錯(cuò)誤處理程序是在出現(xiàn)錯(cuò)誤時(shí)調(diào)用的一個(gè)過(guò)央錯(cuò)誤處理程序至少能夠向用戶(hù)顯示格式一致的出錯(cuò)消息。不過(guò)也可以在你認(rèn)為合適的時(shí)候給錯(cuò)誤處理程序增添一些功能。例如,每當(dāng)出現(xiàn)意料之外的錯(cuò)誤時(shí),可以讓你的錯(cuò)誤處理程序?qū)⒁粋€(gè)電子郵件發(fā)送給支持技術(shù),也可以增加一些代碼,對(duì)機(jī)器的運(yùn)行狀態(tài)制作一個(gè)瞬態(tài)圖,并將已加載的應(yīng)用程序和DLL及其版本記錄下來(lái)。FriendSubShowError(strModuleAsString,strProcedureAsString,_lngErrorNumberAsLong,strErrorDescriptionAsString)‘*Purpose:Provideacentralerror-handling‘*Accepts:strModule-themoduleinwhichtheerror encountered(form,class,standard,andso strProcedure-thenameoftheprocedurein theerrorwas lngErrorNumber-thenumericidentifierof strErrorDescription-thetextdescription theOnErr oToPROC_ERRDimstrMessageAsStringDimstrCaptionAs‘*BuildtheerrorstrMessage=“Error:“&strErrorDescription&vbCrLf&vbCrLf&“Module:“&strModule&vbCrLf&“Procedure:“&strProcedure&vbCrLf&vbCrLf&_“PleasenotifyMySoftware’stechsuppor“&_“at555-1213aboutthisissue.”&vbCrLf&_“Pleaseprovidethesupporttechnicianwith“&_“informationshownin“&vbCrLf&“thisdialog“&_“boxaswellasanexplanationofwhatyou“&_“were”&vbCrLf&“ ngwhenthis“&_“error‘*Buildthecaptionforthemessagebox.Thecaption‘*theversionnumberofheprogram.strCaption=“UnexpectedError!Version:“&_Str$(App.major)&“.”&Str$(App.minor)&“.”&Format(App.Revision,MsgBoxstrMessage,vbCritical,strCaptionExitResumeEndPrivateSub‘*Purpose:Generateanerrorbysettingthefocus aninvisibleOn oTo‘*Setthefocustoaninvisiblecontrol.txtCity.Visible=FalseExitCallShowError(Me.Name,“frmMain_Click",Err.Number,ResumeEnd當(dāng)出現(xiàn)上面這個(gè)代碼中所示的錯(cuò)誤時(shí),錯(cuò)誤處理程序即被調(diào)用,并且顯示圖6-4所示。到別的過(guò)。在窗體過(guò),只需要更改。
Me.Name不起作用,為此你必須使用原義類(lèi)名字。不過(guò),在這種情況下,最好創(chuàng)建一個(gè)模塊及常量,并使用該常量,這樣,當(dāng)模塊的名字被更改時(shí),可以非常容易地修改類(lèi)模塊中的錯(cuò)誤處理程序。如果使用通用常量名,可以拷貝一個(gè)模塊的Call語(yǔ)句,再將它們粘貼到另一個(gè)模塊中,而不必進(jìn)行重大的修改。雖然前面介紹的錯(cuò)誤處理程序能夠以的格式向用戶(hù)顯示出錯(cuò)消息,但是你必須確定除了調(diào)用ShowError過(guò)程外,每個(gè)錯(cuò)誤處理程序擁有什么代碼。例如,錯(cuò)誤處理程序究竟需要Resume還是Resumeext語(yǔ)句呢?也許它需要一個(gè)GooPROC_EXIT語(yǔ)句。應(yīng)該盡可能使你的錯(cuò)誤處理程序具備通用性,不過(guò)要確保每個(gè)處理程序適用于它所在的過(guò)程。將發(fā)生的所有錯(cuò)誤記錄在一個(gè)文件中,這常常是非常有用的。例如,在項(xiàng)目的測(cè)試階段,必須盡量全面地了解發(fā)生的錯(cuò)誤。你往往不能依賴(lài)用戶(hù)提供的報(bào)告。當(dāng)你非常需要了解程序中出現(xiàn)的每個(gè)錯(cuò)誤時(shí),應(yīng)該使用錯(cuò)誤處理程序創(chuàng)建一個(gè)出錯(cuò)日志文件。出錯(cuò)日志文件的創(chuàng)建很簡(jiǎn)單。首先創(chuàng)建一個(gè)前面介紹的錯(cuò)誤處理程序。然后,在錯(cuò)誤處理程序中建立一個(gè)機(jī)制,將錯(cuò)誤記錄到一個(gè)文本文件中。下面這個(gè)代碼展示了將錯(cuò)誤記錄在文本文件中所用的法。這個(gè)代碼顯示的情況與它面介紹的作為錯(cuò)誤處理程序的一部分的情況是一樣的。它的前提是,該過(guò)存在若干局部變量,并且在稱(chēng)為g_trErrorLogFileName的項(xiàng)目中有一個(gè)全局變量,它包含了出錯(cuò)日志文件的路徑和名字。Dim As‘*OLogFile=FreeFile‘*OpentheerrorlogtextfileinAppendmode.‘*Ifthefiledoesn’texist,theOpenstatement‘*createsit.Openg_strErrorLogFileNameForAppendAs‘*WritethePrint#intLogFile,“***ErrorEncountered“&VBA.Now&“***"‘*Writethepertinenterrorinformationtothelogfile.Print#intLogFile,“Error:“&Print#intLogFile,“Description:“&Print#intLogFile,“Procedure:“&Print#intLogFile,“Module:“&‘*WriteablanklinetothelogPrint#intLogFile,‘*ClosethelogClose這個(gè)代碼試圖打開(kāi)全局變量g_strErrorLogFileName中用Append方式設(shè)定的文本文件。如果該文件不存在,該代碼便自動(dòng)創(chuàng)建該文件,然后將它打開(kāi)。一旦文件被打開(kāi),便寫(xiě)入一個(gè)日志5行文本,各個(gè)日志項(xiàng)之間用一個(gè)空行隔開(kāi)。下面是用上面的代碼創(chuàng)建的一個(gè)文本文件舉例:***ErrorEncountered8/29/994:19:18PM***Error:5Description:InvalidprocedurecallorargumentProcedure:ShowCustomerModule:***ErrorEncountered8/29/994:20:08PM***Error:11Description:DivisionbyzeroModule:mdlScience***ErrorEncountered8/29/994:22:05PM***Error:6Description:OverflowModule:mdlScience***ErrorEncountered8/29/994:22:34PM***Error:11Description:DivisionbyzeroModule:mdlScience在這個(gè)錯(cuò)誤日志文件中,你可以看到一個(gè)趨勢(shì)。無(wú)論是誰(shuí)編寫(xiě)mdlScience模塊,都需要在列入的信息。例如,可以列入出現(xiàn)錯(cuò)誤時(shí)運(yùn)行程序的這個(gè)人的用戶(hù)名,也可以將機(jī)器名列入日志項(xiàng)??梢粤腥氲男畔⑹遣皇芟拗频?。無(wú)論選擇何種信息來(lái)列入日志文件,務(wù)必列入有助于查找和糾正錯(cuò)誤的相關(guān)信息。FriendSubShowError(strModuleAsString,strProcedureAsString,_lngErrorNumberAsLong,strErrorDescriptionAsString)‘*Purpose:Provideacentralerror-handling‘*Accepts:strModule-themoduleinwhichtheerror encountered(form,class,standard,andso strProcedure-thenameoftheprocedurein theerrorwas lngErrorNumber-thenumericidentifierof strErrorDescription-thetextdescription heOnErr oToPROC_ERRDimstrMessageAsStringDimstrCaptionAsStringDimintLogFileAsInteger‘*OLogFile=FreeFile‘*OpentheerrorlogtextfileinAppendmode.‘*Ifthefiledoesn’texist,theOpenstatement‘*createsit.Openg_strErrorLogFileNameForAppendAs‘*WritethePrint#inLogFile,“***ErrorEncountered“&VBA.Now&‘*WritethepertinenterrorinformationtothelogPrint#intLogFile,“Error:“&Print#intLogFile,“Description:“&Print#intLogFile,“Procedure:“&Print#intLogFile,“Module:“&‘*WriteablanklinetothelogPrint#intLogFile,‘*ClosetheerrorlogtextClose‘*BuildtheerrormessagefordisplaytothestrMessage=“Error:“&strErrorDescription&vbCrLf&vbCrLf&“Module:“&strModule&vbCrLf&“Procedure:“&strProcedure&vbCrLf&vbCrLf&_“PleasenotifyMySoftware’stechsupport“&_“at555-1213aboutthisissue.”&vbCrLf&_“Pleaseprovidethesupporttechnicianwith“&_“informationshownin“&vbCrLf&“thisdialog“&_“boxaswellasanexplanationofwhatyou“&_“were”&vbCrLf&“ ngwhenthis“&_“error‘*Buildthecaptionforthemessagebox.Thecaption‘*theversionnumberofthestrCaption=“UnexpectedError!Version:“&_Str$(App.major)&“.”&Str$(App.minor)&“.”&_Format(App.Revision,“0000”)MsgBoxstrMessage,vbCritical,ExitResumeEnd當(dāng)你的應(yīng)用程序?qū)⒁涗洺鲥e(cuò)消息時(shí),必須確定你想用這些日志信息來(lái)干什么。如果在程序運(yùn)行的現(xiàn)場(chǎng),你可以人工檢索出錯(cuò)日志的拷貝。也可以在用戶(hù)遇到問(wèn)題時(shí)讓他們用電子郵件將日志發(fā)送給你。甚至可以編寫(xiě)一個(gè)程序,讓它按照預(yù)定的計(jì)劃用電子郵件將日志發(fā)送給你。在查找特定的錯(cuò)誤和一般程序錯(cuò)誤方面,日志文件是非常有用的。而且日志文件的創(chuàng)建非常容易。你應(yīng)該認(rèn)真考慮將這個(gè)特性添加給你的程序。甚至可以選擇包含它的代碼但默認(rèn)關(guān)閉這個(gè)特性。后通你的序的面或通過(guò)表設(shè),激活取消活日文件生成能 使用On OnErroTo語(yǔ)句是指定要使用的錯(cuò)誤處理程序的最常用方法。除非有特定的理由來(lái)使用另法,否則在你的所有過(guò)都應(yīng)該將這種方法用作默認(rèn)方法:PrivateSubimgEditor_MouseUp(ButtonAsInteger,ShiftAsInteger,_XAsSingle,YAsSingle)‘*Purpose:Iftheeditorisinselect(marquee)mode, theEdit whentheuserright- theOnErrorResume‘*Displaythe onlyiftheuserclicked‘*therightmouseIfButton=vbRightButton‘*SeeiftheactivetooloftheCanvasobjectis‘*marqueeIfg_objCanvas.ToolIndex=bdMarquee‘*DisplaytheEdit usingthe‘*barcontrol.EndIf ltheCanvasobjecttostopitscurrentaction.g_objCanvas.ActionEndButton,Shift,X,YExitEndPrivateSubimgEditor_MouseUp(ButtonAsInteger,ShiftAsInteger,XAsSingle,YAs‘*Purpose:Iftheeditorisinselect(marquee)mode, theEdit whentheuserright- theOn oTo‘*Displaythe onlyiftheuserclicked‘*therightmouseIfButton=vbRightButton‘*SeeiftheactivetooloftheCanvasobjectis‘*marqueeIfg_objCanvas.ToolIndex=bdMarquee‘*DisplaytheEdit usingthe‘*barcontrol.EndIf lheCanvasobjecttostopitscurrentaction.g_objCanvas.ActionEndButton,Shift,X,YExitCallShowError(Me.Name,“imgEditor_MouseUp",Err.Number,_EndSub使用OnErrorResumeNext當(dāng)你估計(jì)會(huì)出現(xiàn)一個(gè)錯(cuò)誤時(shí),比如使用SetFocus將光標(biāo)移到?jīng)]有完全加載的窗體中的一個(gè)控件上時(shí)出現(xiàn)的Error5,或者數(shù)據(jù)庫(kù)操作產(chǎn)生的一個(gè)錯(cuò)誤,請(qǐng)使用OnErrorResumeext不過(guò)要注意,使用OnErrorResumeNext語(yǔ)句可能有一定的,因?yàn)樗鼤?huì)使你注意不到運(yùn)行期的錯(cuò)誤。不要將這個(gè)語(yǔ)句當(dāng)作萬(wàn)應(yīng)靈藥來(lái)使用,如果你估計(jì)不會(huì)出現(xiàn)錯(cuò)誤,則不要用它。另外,僅為估過(guò)能現(xiàn)誤也不著應(yīng)將OnErrorResumeNext句用于整個(gè)過(guò)程。使用OnErroTo語(yǔ)句可以捕獲意料之外的錯(cuò)誤,但是要修改緊靠可能產(chǎn)生預(yù)期錯(cuò)誤的代碼行前面的已激活錯(cuò)誤處理程序。當(dāng)你對(duì)預(yù)期的錯(cuò)誤進(jìn)行處理后,加上一個(gè)OnErroo語(yǔ)句,再次激活主要的錯(cuò)誤處理程序。OnErrorResumeNext語(yǔ)句,比如你預(yù)期出現(xiàn)什么錯(cuò)誤,為什么會(huì)出現(xiàn)這個(gè)錯(cuò)誤。PrivateSub‘*Purpose:Allowtheusertobrowseandselecta pageforOnErrorResumeConstc_CancelChosen=‘*Usethecommondialogcontroltoallowtheuser‘selectaWith.fileName=.DefaultExt=.DialogTitle=“SelectCover.Filter=“AllFiles(*.*)|*.*|CoverPages.FilterIndex=.InitDir= lthecontrolfogenerateanerrorifCancelis.CancelError=‘*ShowtheOpenFiledialogboxandwaitfortheuser‘*selectafileorclick‘*Seeifanerrorwasgeneratedastheresultof‘*userclickingIfErr.Number=c_CancelChosenThen‘*Cancelwasclicked;getout.GoToPROC_EXITEndtxtCoverpage.Text=EndExitEndPrivateSub‘*Purpose:Allowtheusertobrowseandselecta pageforOn oToConstc_CancelChosen=‘*Usethecommondialogcontroltoallowtheuser‘*selectaWith.fileName=.DefaultExt=.DialogTitle=“SelectCover.Filter=“AllFiles(*.*)|*.*|CoverPages.FilterIndex=.InitDir= lthecontroltogenerateanerrorifCancelis.CancelError=‘*IftheuserclicksCancel,arun-timeerror‘*TrapforthisOnErrorResume‘*ShowtheOpenFiledialogboxandwaitfortheuser‘*selectafileorclick‘*Seeifanerrorwasgeneratedastheresultof‘*userclickingIfErr.Number=c_CancelChosenThen‘*Cancelwasclicked;getout.GoToPROC_EXITEnd‘*Enablethemainerrorhandler.OnErr oToPROC_ERRtxtCoverpage.Text=.fileNameEndExitCallShowError(Me.Name,“cmdCoverLetter_Click”,Err.Number,_EndSub創(chuàng)建的錯(cuò)誤處理程序使用OnErroTo語(yǔ)句時(shí),很重要的一個(gè)問(wèn)題是要使用的錯(cuò)誤處理程序塊。最好使用一個(gè)錯(cuò)誤處理程序,不過(guò)如果不使用錯(cuò)誤處理程序,請(qǐng)創(chuàng)建類(lèi)似下面這個(gè)典型錯(cuò)誤塊MsgBox“ModuleName|ProcedureName”&vbcrlf&“Error:“&_Err.Number&vbCrLf&Err.Description,vbCritical‘cleanupcodesuchasaResume ‘*or oTo如果你想提醒用戶(hù)注意這個(gè)錯(cuò)誤(通常這是解決問(wèn)題的最佳辦法,MsgBox語(yǔ)句應(yīng)該是
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2024工業(yè)原料代理購(gòu)銷(xiāo)合同協(xié)議
- 2024的廣東省室內(nèi)環(huán)境質(zhì)量保證合同C款(家具購(gòu)買(mǎi))
- 2024建筑合同法全文
- 鋼結(jié)構(gòu)施工承包合同范本
- 2024個(gè)人住房裝修合同書(shū)協(xié)議
- 收藏品贈(zèng)送合同范本
- 面包店轉(zhuǎn)讓協(xié)議書(shū)模板
- 建筑工程監(jiān)理服務(wù)合同
- 建筑設(shè)備出租合同范本
- 普通合伙人合同協(xié)議書(shū)范文
- 承德永輝礦業(yè)集團(tuán)有限公司紅山咀鐵礦礦山地質(zhì)環(huán)境保護(hù)與土地復(fù)墾方案
- 餐廳食品安全保障
- 藥品經(jīng)營(yíng)與管理大學(xué)生職業(yè)規(guī)劃
- 懷孕的hcg驗(yàn)血報(bào)告單
- 病房管理護(hù)理服務(wù)
- 應(yīng)力的概念講解
- JF-2023-合同中小學(xué)校校外供餐合同示范文本
- 入團(tuán)答辯-演講模板
- 聶樹(shù)斌案-演講模板
- 只爭(zhēng)朝夕不負(fù)韶華崗位競(jìng)聘述職報(bào)告
- 配料個(gè)人述職報(bào)告
評(píng)論
0/150
提交評(píng)論