VB6 - How to catch exception or error during runtime - vb6

I developed an application in VB6. In client's environment it raises runtime errors which I can't reproduce under debugger. Is there any way to get the stacktrace or location of error?
I created log file and
I used
Err.Description,Err.Source
but it gives blank values.
Please help me.
my method(......
On Error GoTo Error_Handler
.........
Error_Handler :
writeToLogFile(Err.Source,Err.Description)

You've probably done something to clear the Err object before writing to the log file. This is very, very easy to do. What you'll want to do is as soon as you detect an error has occurred, grab the error message before doing anything else. Then pass the error message to whatever logging routine you're using. E.g.:
Dim sMsg As String
On Error Goto ErrHandler
' ...code here...
Exit Function
ErrHandler:
sMsg = "Error #" & Err.Number & ": '" & Err.Description & "' from '" & Err.Source & "'"
GoLogTheError sMsg

BTW, thanks for your guys' answers helping me. I'm about half a decade late to the game of VB6. I don't do windows unless forced to. ;)
Anyhow, when doing your error checking, say among 3000 individual record query insertions, I learned a couple tricks. Consider this block of code:
'----- order number 1246-------
On Error Goto EH1246:
sSql="insert into SalesReceiptLine ( CustomerRefListID,TemplateRe..."
oConnection.Execute sSQL
sSql="SELECT TxnID FROM SalesReceiptLine WHERE RefNumber='1246'..."
oRecordset.Open sSQL, oConnection
sTxnId = oRecordset(0)
oRecordset.Close
sSql="INSERT INTO SalesReceiptLine (TxnId,SalesReceiptLineDesc,Sal..."
oConnection.Execute sSQL
EH1246:
IF Err.Number<>0 THEN
sMsg = sMsg & "Order # 1246; sTxnId = " & sTxnId & _
vbCrLf & Err.Number & ": " & Err.Description & vbCrLf
sErrOrders = sErrOrders & "1246,"
End If
On Error GoTo -1
'----- order number 1247-------
On Error Goto EH1247:
When not testing for Err.Number, you'll get a 0: on every order handled. (maybe you don't want that). The On Error GoTo -1 resets the error so that it will work again. Apparently, Err only works "once".
I wrote a php script to build the VB6 source code to run some 8000 odbc queries... :P

Do you definitely, positively have an Exit Function just above the Error_Handler:?

my method(......
On Error GoTo Error_Handler
........
Exit Sub
Error_Handler :
writeToLogFile(Err.Source,Err.Description)
"Exit Sub" should be added before you handle the Error_Handler function.....

Related

Issues in Error handling sub in VB Script

I have written an error handling sub in my vb script
errorNumber = DoAllWork
Sub ErrorHandling (Number, Description, i)
If Number <> 0 Then
WriteLogFileLine logfile, "Error No : " & Number & " - " & Description & " has occurred !"
Else
WriteLogFileLine logfile, "Success copying files as Err.Number : " & Err.Number & "Total " & i & " files were copied ! " & vbcrlf
End If
Err.Clear
End Sub
And I am calling it in my vb script like this
Function DoAllWork
On Error Resume Next
Err.Clear
Do Until CopyFiles.AtEndOfStream
line = CopyFiles.ReadLine
For Each line In CopyFiles
If objFSO.GetFolder(line).Files.Count <> 0 then
WriteLogFileLine logfile, "Copying files FromLocation " & Chr(34) & line & Chr(34) & " to ToLocation " & Chr(34) & ToLocation & Chr(34)
Else
WriteLogFileLine logfile, "No files present in the folder " & Chr(34) & line & Chr(34) & vbcrlf
End if
i=0
For Each File In objFSO.GetFolder(line).Files
objFSO.GetFile(File).Copy ToLocation & "\" & objFSO.GetFileName(File),True
i=i+1
Next
ErrorHandling Err.Number, Err.Description, i
Next
Loop
End Function
Now the log file which is getting created has this error messages logged in it even though the files has got copied successfully. Can someone please suggest what is wrong with this error handling technique ??
2015-12-15 15:03:47 - Copying files FromLocation "\\srv10219\archive\Article\20151116_073104" to ToLocation "C:\Users\TEMPPAHIR\LearnVB\ICCdata\Article"
2015-12-15 15:03:47 - Error No : 438 - Object doesn't support this property or method has occurred !
when I place this error handling directly after the File.copy statement, it gives me such log..
2015-12-15 16:31:55 - Error No : 438 - Object doesn't support this property or method has occurred !
2015-12-15 16:31:55 - Success copying files as Err.Number : 0
2015-12-15 16:31:55 - Total 2 files were copied !
that means for the first file which is being copied it throws an error and for the second one it gives success even though both the files has been copied successfully
I implemented this to do pretty much what you asked. What the script needed to do was take a folder and its contents that was dropped into a directory, and then copy the contents to a new folder formatted correctly where there was a poller that picked up the files and entered them in our system. I needed the script to quit on any error, especially for the last thing to do. That was to delete the folder from the source directory, but I had to make sure it got copied correctly. (You could clear the error and continue as well.)
So after each important line like a folder create or a file copy I did this check. This worked for me to do error handling. Passing the Err object itself is the best way to go.
Set FolderCreate = FSO.CreateFolder(PreStagingDirectory + "\" + FolderCreateName)
ReportErrors Err,"Error creating folder: " + PreStagingDirectory + "\" + FolderCreateName
FSO.CopyFile objFile.Path, FolderCreate.Path + "\", true
ReportErrors Err,"Error copying file: " + objFile.Path + " to location: " + FolderCreate.Path
Sub ReportErrors(ErrorObject, strExtraInformation)
'This will log any errors if they happen and the script will then quit
If ErrorObject.Number <> 0 Then
OutPutFile.WriteLine(DateTimeString + " Error Number: " & ErrorObject.Number)
OutPutFile.WriteLine(DateTimeString + " Error (Hex): " & Hex(ErrorObject.Number))
OutPutFile.WriteLine(DateTimeString + " Source: " & ErrorObject.Source)
OutPutFile.WriteLine(DateTimeString + " Description: " & ErrorObject.Description)
OutPutFile.WriteLine(DateTimeString + " Other Information: " + strExtraInformation)
OutPutFile.WriteLine(DateTimeString + " Script is quitting due to the Error Condition.")
wscript.quit
End If
End Sub
I have also done code like this. In this case I needed to catch if null was returned from a SQL query to the database. If null was returned and I try to cast the value, it caused an error.
To answer the question of should you check for errors in a sub and clear them, or check for errors all through your script really depends what you need to accomplish.
First I have to say error handling in vbscipt just sucks. Using 'On Error Resume Next', is absolutely needed but be careful where you place it. I found it is not best to place it in main, at the top, just within each function. Most important is to remember the scope, if you put it in a function, you catch the error there, and can handle it. If you only have it at as the first line of your script, you can only handle an error in main. It is needed in main, sometimes.
Also to debug any vbscript, comment out any call to that, or you will never know the problem.
ExecutionString = "select Sum(cast(Frame_Count as int)) from Sop_Instance_T"
Set objRecordSet = objConnection.Execute(ExecutionString)
TotalFrames = cdbl(objRecordSet(0))
'In case null is returned catch the exception
'that happens on the above line
If Err.Number <> 0 Then
TotalFrames = 0
Err.Clear ()
End If

HTTP Status 443 on Server.CreateObject in VBScript under Classic ASP IIS 6.0

This is old legacy code that has been running at least 5 years. The DLL happens to relate to Paypal's PayFlowPro merchant processing service, but I think this is a Windows scenario causing the issue.
Suddenly, based on the code below, I'm seeing this error in the browser:
> Error with new credit card processing software, please call Neal at xxx-xxx-xxxx
> Error Ref102: client = Server.CreateObject returned Null
> (Detailed error: Object doesn't support this property or method)
> (Detailed error: 438)
The IIS log shows me the 443:
2013-12-19 00:57:24 W3SVC4 173.45.87.10 POST /myapps/adm_settle.asp - 443 - 76.187.77.159 Mozilla/5.0+(Windows+NT+6.2;+WOW64;+rv:26.0)+Gecko/20100101+Firefox/26.0 200 0 0
Since I saw the 433 above, I'm thinking there must be some security error. Just as a test, I tried putting the app-pool user in the Administrator group, restarted IIS, and still get exact same error. I have also given that user specific access to read the .DLL on disk.
I did run REGASM to try to re-register the .DLL. I also tried REGSRV32, but I guess that fails on .NET DLLs. It's been a few years since I've dealt with software this old.
The ASP/VBScript Code:
Err.Clear
On Error Resume Next
set client = Server.CreateObject("PayPal.Payments.Communication.PayflowNETAPI")
If Err.number > 0 Then
response.write "Error with new credit card processing software, please call Neal at xxx-xxx-xxxx"
response.write "</br>(Detailed error: " & Err.Description & ")"
response.write "</br>(Detailed error: " & Err.Number & ")"
response.End
End If
If client Is Nothing Then
Response.write "Error with new credit card processing software, please call Neal at xxx-xxx-xxxx"
Response.Write "</br>Error Ref101: client = Server.CreateObject returned 'nothing' "
response.write "</br>(Detailed error: " & Err.Description & ")"
response.write "</br>(Detailed error: " & Err.Number & ")"
Response.End
End If
If client = null Then
Response.write "Error with new credit card processing software, please call Neal at xxx-xxx-xxxx"
Response.Write "</br>Error Ref102: client = Server.CreateObject returned Null "
response.write "</br>(Detailed error: " & Err.Description & ")"
response.write "</br>(Detailed error: " & Err.Number & ")"
Response.End
End If
Also, I'm not sure how the 443 http status gets changed to a 438 Err.Number.
Thanks everyone. I wish I had saved my original error. I've been doing C# so long, I was forgetting how to code VBScript. I tried to add error handling which may have been giving me false results.
If some of the guys who had commented would have put answers, I would have accepted them.
The 443 was another false trail and bad assumption on my part that it was an error, not a port #.
Unfortunately now, I didn't save the original error. I had added code to my original code to give supposedly better or tighter error handling, and adding the "= null" test was a bad idea.
This was a pretty good explanation of VBScript's use of empty vs nothing vs isNull: http://evolt.org/node/346/
I removed that, and the corrected code is:
Err.Clear
On Error Resume Next
'set client = Server.CreateObject("PFProCOMControl.PFProCOMControl.1")
set client = Server.CreateObject("PayPal.Payments.Communication.PayflowNETAPI")
If Err.number > 0 Then
response.write "Error with new credit card processing software, please call Neal at 214-455-8060"
response.write "</br>(Detailed error: " & Err.Description & ")"
response.write "</br>(Detailed error: " & Err.Number & ")"
response.End
End If
If client Is Nothing Then
Response.write "Error with new credit card processing software, please call Neal at 214-455-8060"
Response.Write "</br>Error Ref101: client = Server.CreateObject returned 'nothing' "
response.write "</br>(Detailed error: " & Err.Description & ")"
response.write "</br>(Detailed error: " & Err.Number & ")"
Response.End
End If

Hide error message in vb6

Is theres a way to hide a vb6 error? I have a program that prompt an error but everything goes fine. Any help will be highly appreciated. Thanks.
UPD the code:
Set WshShell = CreateObject("WScript.Shell") 'passing the values to program2
strCommand = """" & App.Path & "\Prog2.exe """ & strArgs(0) & ";" & Trim$(.cFileName) & ";" & strArgs(1) WshShell.Run strCommand
you may suppress exception raising in vb in the following way:
on error resume next
doSomeDangerousStuff
if err.Number <> 0 then
'here is some optional error handling code
MsgBox "Exception occured: " & Err.Description
end if
on error goto 0
after the declaration of your function/sub put
on error goto error_filter
'your code is here'
before the ending of your sub/function put this
error_filter:
if err.description = (the error description you want to eliminate) then
exit sub
end if

What does the "On Error Resume Next" statement do?

I came to some VBScript examples, and I saw the statement On Error Resume Next basically at the beginning of the script.
What does it do?
It basically tells the program when you encounter an error just continue at the next line.
It's worth noting that even when On Error Resume Next is in effect, the Err object is still populated when an error occurs, so you can still do C-style error handling.
On Error Resume Next
DangerousOperationThatCouldCauseErrors
If Err Then
WScript.StdErr.WriteLine "error " & Err.Number
WScript.Quit 1
End If
On Error GoTo 0
When an error occurs, the execution will continue on the next line without interrupting the script.
It means, when an error happens on the line, it is telling vbscript to continue execution without aborting the script. Sometimes, the On Error follows the Goto label to alter the flow of execution, something like this in a Sub code block, now you know why and how the usage of GOTO can result in spaghetti code:
Sub MySubRoutine()
On Error Goto ErrorHandler
REM VB code...
REM More VB Code...
Exit_MySubRoutine:
REM Disable the Error Handler!
On Error Goto 0
REM Leave....
Exit Sub
ErrorHandler:
REM Do something about the Error
Goto Exit_MySubRoutine
End Sub
It enables error handling. The following is partly from https://msdn.microsoft.com/en-us/library/5hsw66as.aspx
' Enable error handling. When a run-time error occurs, control goes to the statement
' immediately following the statement where the error occurred, and execution
' continues from that point.
On Error Resume Next
SomeCodeHere
If Err.Number = 0 Then
WScript.Echo "No Error in SomeCodeHere."
Else
WScript.Echo "Error in SomeCodeHere: " & Err.Number & ", " & Err.Source & ", " & Err.Description
' Clear the error or you'll see it again when you test Err.Number
Err.Clear
End If
SomeMoreCodeHere
If Err.Number <> 0 Then
WScript.Echo "Error in SomeMoreCodeHere:" & Err.Number & ", " & Err.Source & ", " & Err.Description
' Clear the error or you'll see it again when you test Err.Number
Err.Clear
End If
' Disables enabled error handler in the current procedure and resets it to Nothing.
On Error Goto 0
' There are also `On Error Goto -1`, which disables the enabled exception in the current
' procedure and resets it to Nothing, and `On Error Goto line`,
' which enables the error-handling routine that starts at the line specified in the
' required line argument. The line argument is any line label or line number. If a run-time
' error occurs, control branches to the specified line, making the error handler active.
' The specified line must be in the same procedure as the On Error statement,
' or a compile-time error will occur.
On Error Statement - Specifies that when a run-time error occurs, control goes to the statement immediately following the statement. How ever Err object got populated.(Err.Number, Err.Count etc)
On Error Resume Next means that On Error, It will resume to the next line to resume.
e.g. if you try the Try block, That will stop the script if a error occurred

what is the better way to handle errors in VB6

I have VB6 application , I want to put some good error handling finction in it which can tell me what was the error and exact place when it happened , can anyone suggest the good way to do this
First of all, go get MZTools for Visual Basic 6, its free and invaluable. Second add a custom error handler on every function (yes, every function). The error handler we use looks something like this:
On Error GoTo {PROCEDURE_NAME}_Error
{PROCEDURE_BODY}
On Error GoTo 0
Exit {PROCEDURE_TYPE}
{PROCEDURE_NAME}_Error:
LogError "Error " & Err.Number & " (" & Err.Description & ") in line " & Erl & _
", in procedure {PROCEDURE_NAME} of {MODULE_TYPE} {MODULE_NAME}"
Then create a LogError function that logs the error to disc. Next, before you release code add Line Numbers to every function (this is also built into MZTools). From now on you will know from the Error Logs everything that happens. If possible, also, upload the error logs and actually examine them live from the field.
This is about the best you can do for unexpected global error handling in VB6 (one of its many defects), and really this should only be used to find unexpected errors. If you know that if there is the possibility of an error occurring in a certain situation, you should catch that particular error and handle for it. If you know that an error occurring in a certain section is going to cause instability (File IO, Memory Issues, etc) warn the user and know that you are in an "unknown state" and that "bad things" are probably going happen. Obviously use friendly terms to keep the user informed, but not frightened.
a simple way without additional modules, useful for class modules:
pre-empt each function/subs:
On Error Goto Handler
handler/bubbleup:
Handler:
Err.Raise Err.Number, "(function_name)->" & Err.source, Err.Description
voila, ghetto stack trace.
I use a home-grown Error.bas module to make reporting and re-raising less cumbersome.
Here's its contents (edited for length):
Option Explicit
Public Sub ReportFrom(Source As Variant, Optional Procedure As String)
If Err.Number Then
'Backup Error Contents'
Dim ErrNumber As Long: ErrNumber = Err.Number
Dim ErrSource As String: ErrSource = Err.Source
Dim ErrDescription As String: ErrDescription = Err.Description
Dim ErrHelpFile As String: ErrHelpFile = Err.HelpFile
Dim ErrHelpContext As Long: ErrHelpContext = Err.HelpContext
Dim ErrLastDllError As Long: ErrLastDllError = Err.LastDllError
On Error Resume Next
'Retrieve Source Name'
Dim SourceName As String
If VarType(Source) = vbObject Then
SourceName = TypeName(Source)
Else
SourceName = CStr(Source)
End If
If LenB(Procedure) Then
SourceName = SourceName & "." & Procedure
End If
Err.Clear
'Do your normal error reporting including logging, etc'
MsgBox "Error " & CStr(ErrNumber) & vbLf & "Source: " & ErrSource & vbCrLf & "Procedure: " & SourceName & vbLf & "Description: " & ErrDescription & vbLf & "Last DLL Error: " & Hex$(ErrLastDllError)
'Report failure in logging'
If Err.Number Then
MsgBox "Additionally, the error failed to be logged properly"
Err.Clear
End If
End If
End Sub
Public Sub Reraise(Optional ByVal NewSource As String)
If LenB(NewSource) Then
NewSource = NewSource & " -> " & Err.Source
Else
NewSource = Err.Source
End If
Err.Raise Err.Number, NewSource, Err.Description, Err.HelpFile, Err.HelpContext
End Sub
Reporting an error is as simple as:
Public Sub Form_Load()
On Error Goto HError
MsgBox 1/0
Exit Sub
HError:
Error.ReportFrom Me, "Form_Load"
End Sub
Reraising an error is as simple as calling Error.Reraise with the new source.
Although it is possible to retrieve the Source and Procedure parameters from the call stack if you compile with symbolic debug info, it's not reliable enough to use in production applications
ON ERROR GOTO
and the
Err
object.
There is a tutorial here.
Yes, take Kris's advice and get MZTools.
You can add line numbers to section off areas of complex procedures, which ERL will report in the error handler, to track down which area is causing the error.
10
...group of statements
20
...group of statements
30
...and so on
Use on
dim errhndl as string
on error goto errhndl
errhndl:
msgbox "Error"
Use the On Error statement and the Err object.

Resources