Introduction
Exception handling is the major activity in application life cycle and especially for VB6 platform which doesn't provide much support for exception handling natively. This article might help to focus on the best way to debug the deployment version of your applications and to find out the exact problem on client machines.
This article aims to provide you the following:
- Systematic method of error handling
- System exceptions (Ex Access Violation) handling
- Automatic creation of log information and
- Crash reporter including stack trace (Yes! :-)
Background
How Debugger Works?
Windows provides an API named DebugActiveProcess
to debug your applications. The debugger automatically receives the notifications from Windows for all exceptions of client process. Note that, debugging a process pauses all the threads of client application.
The client process can call OutputDebugString
API to communicate with debugger. Normally application debugger handles the string
s sent through OutputDebugString
. If the application has no debugger, the system debugger handles the string
. If the system debugger is also not active, string
will be discarded.
Using the Code
How to Call Debugger?
StartDebug
method of ClsErrorhandler
class calls debugger by passing current process id as a parameter.
StartDebug(sDebuggerPath, sLogFilePath, sCrashStartApplication)
Using ErrorHandler Class
LogEvent Method
The application can call LogEvent
method to pass the information to debugger. LogEvent
method supports the following four functionalities:
S.No | Type | Usage |
1 | LogMessage | Indicates as log message from application |
2 | vbError | Indicates problem with application, but application can continue to execute |
3 | ApplicationError | Indicates custom application error, but application can continue the operation |
4 | ApplicationCriticalError | Indicates severe error and debugger will call crash application |
Error Handling
Visual Basic provides On Error statement to handle the errors. Use this at the start of each procedure. TypeName
functions return the name of class module and Form modules. For standard modules, you have to pass the name manually.
Private Sub CmdErrorHandle_Click()
On Error GoTo Errorhandler
Dim Dummy As Integer
Dummy = 10 / Dummy
Exit Sub
Errorhandler: ObjErrorHandler.LogEvent TypeName(Me) & _
"::CmdErrorHandle_Click", Err, ApplicationCriticalError
End Sub
LogEvent
method automatically formats the error message from Error
object received from the application.
lLastDllError = LError.LastDllError
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
If LError.Number <> 0 Then
lsMessage = "Error (#" & Trim$(Str(LError.Number)) & "-" _
& lLastDllError & ")-" & LError.Description & ", " & vbNewLine
End If
If lsAPIError <> "" Then lsMessage = lsMessage & lsAPIError & ", " & vbNewLine
If LError.Source <> "" Then sSource = " (generated by " & LError.Source & " Module)"
Convert Windows Error Number to 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
Converting DLL Error Number to Error Message
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
hModule = GetModuleHandle("wininet.dll")
If hModule = 0 Then
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
End Function
Raising Custom Errors
To raise custom application errors, call LogEvent
method with your error description and pass ApplicationError
as log type.
ObjErrorHandler.LogEvent "Pass your custom error message here", , ApplicationError
Store Application Log
To raise custom application messages, call LogEvent
method with your message and pass LogMessage
as log type.
ObjErrorHandler.LogEvent "Sample Log Current Time : " & Now, , LogMessage
Crash Report
If debugger found crash in application, it will automatically execute the crash reporter provided by the application.
Error Handling in IDE
If you want to debug your code during the development phase, you can enable the ShowMessageBox
property.
ObjErrorHandler.ShowMessageBox = True
Stack Trace & Symbol File
The VB6 compiler provides the option to create symbol file (with extension PDB) through Create Symbol Debug info option of project properties window. By using this symbol file debugger maps the function address to names.
By default, address of functions are logged by debugger instead of function names on client machine to avoid security problems. After receiving report from the client, you can use Stack Converter tool to convert addresses to function names.
But if you prefer, you can deploy symbol file (.pdb) on your client machine and can call DebugSendTrace
method to log full stack trace with function name.
Points of Interest
There are no additional requirements to release this executable with your existing application. You can use this tool with Power basic and VC++ applications also. But this debugger has been designed and tested mainly for VB6 applications.
History
- Release version 1.0 on 02/02/2008