Re: I finally found the wooden stake to drive through my program's still beating heart!

Tech-Archive recommends: Repair Windows Errors & Optimize Windows Performance



Michael,

Doesn't Raise do substantially the same thing as Resume to the statement that caused the problem, as then both simply send the same error up the same chain of error handling? Hmmm, not really, as explained further down in this email.

... but I can now get back to the EXACT STATEMENT that caused the problem, and with no re-execution of other statements!

Me too. I just set Break On All Errors and it stops right on the line that has the error.

Not with MY code it sure won't! There are a bunch of cases where I can't tell in advance whether something will work, so I just try it and handle the errors. Also, I get LOTS of transitory errors with several subsystems simultaneously hitting the same database and other subsystems. I probably do this every second or few. Further, unnecessary breaks are often catastrophic to debugging because they steal the focus from where the speech recognition output is going which has nasty ripple effects. Hence, my code simply won't run with Break On All Errors.

Mine doesn't do anything in the IDE, I just debug as normal.

There is a bunch of information that you can display in advance of debugging to help. Often this just tells you more about a problem that you already know about, so you can better pick and choose what you want to debug and what you want to skip over for now. Unfortunately, I know of NO way to dump the call stack in advance of this sort of debugging, other than building this code into every subroutine (which I HAVE seen done in one commercially available product).

and there is NO re-executing other statements in the routine to get there, other than the second execution of just the offending statement!

I never re-execute statements (unless it is a special case eg retry inside a loop).

Hmmm, Now I FINALLY think I "got it". Raise in a HIGHER level routine than actually encountered the error works quite differently than Resume, because it doesn't re-execute the code between the Call and the error. Of course it would be best to have both worlds, which should be possible by recognizing a re-occurrence of the same error, which would be trivial by marking the Err object in some obvious way, e.g. plugging in a phony ..Description into it like "Simulated Error".

Yea, your method is probably better once it goes out the door, while mine is better at getting it to the door. For hypercomplex AI stuff, just getting it to the door is the bigger challenge.

Whenever I demonstrate my stuff at AI conferences, people's first remark is usually that there is obviously SO much work invested to make such things work, like more than a university or corporation would ever invest into a research project. Yea, I do put in a lot of work, but my real secret is a combination of coding and debugging methods that make it possible to make really large systems that don't then just fall over of their own weight. Debugging generally goes as the SQUARE of complexity because it involves addressing interactions, so the countless pieces must each stand alone and interact with the rest of the world with as few interactions as possible. Still, I sometimes get "sucked in" to month-long debugging efforts, as in the present case. However, in defense of my present project, its whole job is to present a SIMPLE interface to AI programs to operate very complex speech recognition and synthesis subsystems while completely avoiding all of the nasty real-time programming and environmental issues (except that they must be sure not to hog the CPU).

Hmmm, there may be a way to have it *BOTH* ways, by using the following method. Instead of saying On Error GoTo 0 before all of my subroutine calls as I now do, I could say:

If IsExecutingFromIDE() Then On Error GoTo 0

so that when running from an EXE I would rattle back through the error handling routines in every routine in the call stack as you now do, yet in the IDE I could still stop on THE statement with the problem with no re-execution of other statements.

That's what "break on all errors" does.

Not really as explained above. Still, my question stands. I want it BOTH ways!

Note also here that for higher level routines to accurately recognize that they are indeed higher level, you must Raise rather than Resume at the lower level to mark the Err object. This decision should probably be made on the basis of whether you are in the IDE or running from an EXE.

I pass the name of the procedure to my error handler, and also display the Err.Source field that is surprisingly often DIFFERENT! For example, I may be in a subroutine where an ActiveX control throws an error when I do something with it, so the Err.Source field will contain the name of the ActiveX control and NOT the name of the form, module, or subroutine.

I just use TypeName(Me)

But doesn't this only work in routines that are in the form, and not those in modules where Me is undefined?

to get the name of the form and hard code the name of the routine. I have an addin that does all this for me which also works out whether to raise (for procedures) or log (for events) the error. It all works quite well, is very simple, doesn't get in the way of debugging and requires no code is executed until after an error occurs. Code in a routine looks like this:

Private Sub cmdApply_Click()
On Error GoTo Fail

DoStuffHere

Exit Sub
Fail:
ErrReport.AddToStackLogError TypeName(Me), "cmdApply_Click"
End Sub

For a procedure the only difference would be "LogError" would say "RaiseError"

Much like what I am doing. Here is the same for my error handler, lifted out of the end of my DLookup routine that simulates that same Access function but in VB:

Fail:

If Locking_Error("DLookup") Then
Sleep 0&
Resume
End If

If Error_Handler%("DLookup") = acDataErrDisplay Then
On Error GoTo 0
Resume
End If

End Function 'DLookup

As you can see, there are other things that need doing besides just Raise. After several tries, Locking_Error puts up an announcement as to why it is waiting, which then goes away if it isn't frequently refreshed. I have a LONG list of errors that are transitory, and I discover new ones every week or two as the ActiveX controls continue to discover new ways to get tied into knots.

Steve Richfie1d
.



Relevant Pages

  • SSI experience
    ... in either LPA or the LNKLST [while debugging, ... requires LOAD-TO-GLOBAL option on the SSVTI entry which causes the routine ... If during CLOSE you'd like to reuse the working storage acquired by OPEN, ... various entry points, so I am also preserving its pointer ...
    (bit.listserv.ibm-main)
  • Re: ASP.NET 2.0: Page loaded twice on debug.
    ... had any problem using VS 2003 but today, debugging a page, I get ... false and teh Load event handler was bound in a generated ... autowire events (in the PAGE directive in the aspx ... the page_load routine TWICE as the routine is bound to the event twice ...
    (microsoft.public.dotnet.general)
  • Re: Recommend a debugger
    ... Originally it was just saying " Setup has encountered a problem and will now terminate") ... This part of the setup program appears not to be using Microsoft Windows Installer, but is using InstallShield 11.0 in some other manner. ... I looked at the .dll routine being called with PE Explorer ... I have "Debugging Tools for Windows" which has WinDbg.exe, ...
    (microsoft.public.vc.mfc)
  • Re: Stepping through MFC source code
    ... > routine that you are debugging? ... It will load the disassembler for code for ...
    (microsoft.public.vc.mfc)
  • What are you suggestions for raising exceptions
    ... My application has a common routine to format error messages: ... raise ArgumentError ... Should I call the routine to format the message and return to the ... caller and raise the exception, ...
    (comp.lang.ruby)