65.9K
CodeProject 正在变化。 阅读更多。
Home

实时异常处理带堆栈跟踪

starIconstarIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIcon

2.33/5 (5投票s)

2008年2月2日

Ms-PL

3分钟阅读

viewsIcon

51214

downloadIcon

397

轻松处理所有异常

引言

异常处理是应用程序生命周期中的主要活动,特别是对于 VB6 平台,它本身对异常处理的支持不多。本文可能有助于您专注于调试应用程序部署版本的最佳方法,并找出客户端计算机上的确切问题。

本文旨在为您提供以下内容:

  1. 系统的错误处理方法
  2. 系统异常(例如访问冲突)处理
  3. 自动创建日志信息,以及
  4. 崩溃报告器,包括堆栈跟踪(是的!:-)

背景

调试器如何工作?

Windows 提供了一个名为 DebugActiveProcess 的 API 来调试您的应用程序。调试器会自动从 Windows 接收来自客户端进程的所有异常通知。请注意,调试进程会暂停客户端应用程序的所有线程。

客户端进程可以调用 OutputDebugString API 来与调试器通信。通常,应用程序调试器处理通过 OutputDebugString 发送的 string。如果应用程序没有调试器,则系统调试器处理 string。如果系统调试器也未激活,则 string 将被丢弃。

Flow.jpg

Using the Code

如何调用调试器?

ClsErrorhandler 类的 StartDebug 方法通过传递当前进程 ID 作为参数来调用调试器。

StartDebug(sDebuggerPath, sLogFilePath, sCrashStartApplication)

使用 ErrorHandler 类

LogEvent 方法

应用程序可以调用 LogEvent 方法将信息传递给调试器。 LogEvent 方法支持以下四个功能:

序号 类型 用法
1 LogMessage 表示来自应用程序的日志消息
2 vbError 表示应用程序存在问题,但应用程序可以继续执行
3 ApplicationError 表示自定义应用程序错误,但应用程序可以继续运行
4 ApplicationCriticalError 表示严重错误,调试器将调用崩溃应用程序

错误处理

Visual Basic 提供了 On Error 语句来处理错误。在每个过程的开始使用它。 TypeName 函数返回类模块和窗体模块的名称。对于标准模块,您必须手动传递名称。

Private Sub CmdErrorHandle_Click()
On Error GoTo Errorhandler

Dim Dummy As Integer
'Raise Division by zero error
Dummy = 10 / Dummy

Exit Sub
Errorhandler: ObjErrorHandler.LogEvent TypeName(Me) & _
	"::CmdErrorHandle_Click", Err, ApplicationCriticalError
End Sub

LogEvent 方法自动格式化从应用程序收到的 Error 对象中的错误消息。

lLastDllError = LError.LastDllError
'Call appropriate Module to get the error message from error number
If lLastDllError > 12000 Then
sDLLMessage = DebugErrorDescriptionWininet(lLastDllError)
If sDLLMessage <> "" Then lsAPIError = "WinInet Error _
		(" & lLastDllError & ") " & sDLLMessage
ElseIf lLastDllError > 0 Then
sDLLMessage = DebugErrorDescriptionWindows(lLastDllError)
If sDLLMessage <> "" Then lsAPIError = "Windows Error _
		(" & lLastDllError & ") " & sDLLMessage
End If

'Get VB error message
If LError.Number <> 0 Then
lsMessage = "Error (#" & Trim$(Str(LError.Number)) & "-" _
	& lLastDllError & ")-" & LError.Description & ", " & vbNewLine
End If
If lsAPIError <> "" Then lsMessage = lsMessage & lsAPIError & ", " & vbNewLine

'Get the module which generates error
If LError.Source <> "" Then sSource = " (generated by " & LError.Source & " Module)"

将 Windows 错误代码转换为错误消息

'Convert the Windows error number to meaningful error message.
Public Function DebugErrorDescriptionWindows_
	(Optional ByVal lErrNumber As Long = -1) As String
Dim strBuffer As String * 257
Dim dwLength As Long

If lErrNumber = -1 Then lErrNumber = GetLastError
dwLength = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM Or FORMAT_MESSAGE_IGNORE_INSERTS _
Or FORMAT_MESSAGE_MAX_WIDTH_MASK, ByVal 0&, lErrNumber, LANG_ENGLISH, _
ByVal strBuffer, 256&, 0&)
If dwLength > 0 Then DebugErrorDescriptionWindows = Left$(strBuffer, dwLength)
End Function

将 DLL 错误代码转换为错误消息

Public Function DebugErrorDescriptionWininet(lErrNumber As Long) As String
 Dim strBuffer As String * 257
 Dim dwLength As Long
 Dim hModule As Long
 Dim bLoadLib As Boolean
    
 'Get the handle if dll is already loaded by current process
 hModule = GetModuleHandle("wininet.dll")
 If hModule = 0 Then
  'if DLL is not loaded already, load it now
  hModule = LoadLibrary("wininet.dll")
  bLoadLib = True
 End If
 dwLength = FormatMessage(FORMAT_MESSAGE_FROM_HMODULE, _
	ByVal hModule, lErrNumber, 0&, ByVal strBuffer, 256&, 0&)
 If dwLength > 0 Then DebugErrorDescriptionWininet = Left$(strBuffer, dwLength - 2)
 If bLoadLib Then FreeLibrary hModule
 'if DLL is loaded for this function then unload it
End Function

引发自定义错误

要引发自定义应用程序错误,请使用您的错误描述调用 LogEvent 方法,并将 ApplicationError 作为日志类型传递。

ObjErrorHandler.LogEvent "Pass your custom error message here", , ApplicationError 

存储应用程序日志

要引发自定义应用程序消息,请使用您的消息调用 LogEvent 方法,并将 LogMessage 作为日志类型传递。

ObjErrorHandler.LogEvent "Sample Log Current Time : " & Now, , LogMessage 

崩溃报告

如果调试器在应用程序中发现崩溃,它将自动执行应用程序提供的崩溃报告器。

crash.jpg

IDE 中的错误处理

如果您想在开发阶段调试代码,您可以启用 ShowMessageBox 属性。

ObjErrorHandler.ShowMessageBox = True
Error.jpg

堆栈跟踪 & 符号文件

VB6 编译器提供了通过项目属性窗口的“创建符号调试信息”选项来创建符号文件(扩展名为 PDB)的选项。通过使用此符号文件,调试器将函数地址映射到名称。

Project_properties_symbol.jpg

默认情况下,为了避免安全问题,调试器记录的是客户端计算机上的函数地址,而不是函数名称。收到客户端的报告后,您可以使用 Stack Converter 工具将地址转换为函数名称。

stack.jpg

但是,如果您愿意,您可以在客户端计算机上部署符号文件 (.pdb),并可以调用 DebugSendTrace 方法来记录带有函数名称的完整堆栈跟踪。

关注点

没有其他要求可以将此可执行文件与您现有的应用程序一起发布。您也可以将此工具与 Power Basic 和 VC++ 应用程序一起使用。但是,此调试器主要针对 VB6 应用程序进行了设计和测试。

历史

  • 2008 年 2 月 2 日发布版本 1.0
© . All rights reserved.