Let's go over that again, but more slowly. Visual Basic handles local errors. By this, I mean that whenever an error handler is called it always thinks it's acting upon an error produced locally within the routine the error handler is in. (Indeed, a bit of obscure syntax, normally unused because it's implied, On Local Error GoTo, gives this little secret away.) So if we write some functions named SubA, SubB, and SubC and arrange for SubA to call SubB and SubB in turn to call SubC, we can spot the potential problem. (See Figure 1-3.) If SubC generates an error, who handles it? Well, it all depends. If we don't handle it, Visual Basic will. Visual Basic looks up Err.Number in its list of error strings, produces a message box with the string, and then executes an End for you. If, as in Figure 1-3, SubA handles errors, Visual Basic will search up through the call chain until it finds SubA (and its error handler) and use that error handler instead of its own default error handler. Our error handler in SubA, however, now thinks that the error happened locally to it; that is, any Resume clause we might ultimately execute in the error handler works entirely within the local SubA routine.
Figure 1-3 The call chain in action
Your code always runs in the context of some event handler; that is, any entry point into your code must ultimately be in the form of an event handler. So substituting SubA with, say, Form_Load, you could now write a catchall error handler by providing an error handler in Form_Load. Now, when SubC generates its error (I'm assuming here that these functions are only ever called from Form_Load), Visual Basic will find the local error handler in Form_Load and execute it. Ultimately, this error handler will execute a Resume statement. For argument's sake, let's say that it's Resume Next.
The Next here means after the call to SubB. OK, so what's the problem? If a problem exists, it's buried inside SubB and SubC-we don't know what they did! Imagine this scenario. Maybe SubC opened some files or perhaps a database or two, and somewhere within SubC, it was also going to close them. What happens if the erroring code happened somewhere in between these two operations-say, the files or databases got opened but were never closed? Again it depends, but loosely speaking, it means trouble.
The situation described above could be worse, however. Maybe instead of Resume Next we simply used Resume, that is, try again. This will result in an attempt to open the same files again; and as we all know, this attempt may fail for many reasons-perhaps instead of using FreeFile, you used hard-coded file handle IDs, or maybe you opened the files last time with exclusive access.
Unfortunately, when Visual Basic executes an error handler, there's no easy way of telling whether the error handler was really local to the error. So there's no way to guarantee that you handled it properly. And of course, there's no way to install a global error handler that's called automatically by Visual Basic whenever an error occurs. There's no way around it: to write professional and robust applications, we must have error handlers absolutely everywhere!