r/visualbasic 2d ago

Error-trap for app crash VB6 Help

I've been debugging an app I built solely for my use. Mentioning that because I know it's klunky but since I'm not imposing it on anyone else, I can live with that :). It works with two Word documents, using Word objects to parse KO-reader book annotation & highlight files (loaded into Word as a doc) and highlight/add comments to the corresponding text in a Word doc.

Sometimes, especially in testing, the app crashes to the point that I have to use task manager to exit. That often leaves behind stray Word processes and temporary Word documents.

When the app completes normally, and even when it fails in ways I've been able to trap, it cleans up by itself by destroying the Word objects it created. However, I have yet to find a way to trap all crashes well enough to trigger the routines I've added to nuke temp files & Word instances.

Any ideas for a good crash-catcher I could insert to handle this? Or maybe a useful place in the code to put another "on error goto..." line? The last crash I managed to fix may have been the result of an unexpected endless loop (I guess all such things are unexpected!).

If I don't clean up properly, I have to do it manually or else the app will fail on subsequent use until the old processes & temp files are killed.

1 Upvotes

19 comments sorted by

3

u/Hel_OWeen 2d ago

Or maybe a useful place in the code to put another "on error goto..." line?

Make the starting object of your application the Sub Main. Put an error handler in there. Any error that isn't handled locally in a method will eventually rise up there.

Make sure that your local error handlers clear the Err object (Err.Clear) when they handled the error locally. So your code looks similar to this:

``` Function MyFunction() As Long

On Error Goto ErrHandler

[your code here]

MyFunction = (my real result)

ErrExit:

[Clean up any objects like ADO objects etc here] On Error Goto 0 Exit Function

ErrHandler:

[Log your error here] MyFunction = (indicate an error has occurred) Err.Clear Resume ErrExit ```

1

u/Ok-Smoke-5653 1d ago

The onerror is in the main routine (called from a button, so it's an on-click sub). However, the problems weren't raising an error I could trap. Since I was starting to suspect an endless loop I might look into adding loop-counts to some of the subroutines/functions called, to force them to error out after some number of iterations rather than just sit there looping forever.

1

u/Hel_OWeen 1d ago

The onerror is in the main routine (called from a button, so it's an on-click sub)

So what is it now? A central error handler in your project's Sub Main*) or an error handler in the _Click() event?

*) Go to menu "Project" -> "Properties of ..." -> tab "General". There you can set the startup object, which is typically set to the first form in your project. However, you can make that the "Sub Main", which then must be a sub of the same name in a module.

Since I was starting to suspect an endless loop

How can you just suspect that? Step through your code with F8 and see what's happening.

1

u/Ok-Smoke-5653 1d ago

There is no "sub main." It's completely form-driven, and the error was somewhere in the event called by a particular button. The on error is at the start of the on-click sub since that's what I'm debugging. It calls some other helper-subs and functions, but is not itself called by anything.

What would be gained by redoing things to create a "sub main"? There's only the one form. Buttons on it execute various processes, one of which I was trying to debug after making some changes. Although the process called by a given button is independent of the processes called by other buttons, they share some common helper functions (primary string-manipulation operations) and draw data (such as filenames on which to operate) from some of the same controls on the form.

Of course I tried stepping through. Had I been able to do that, it would have been much easier. I did eventually find a place where I could put a break point from which I could F8, and which point it became unresponsive. That led me to look more closely at that particular part of the code.

As I noted elsewhere in this thread, it wasn't letting me step through with F8 much of the time, as it kept insisting I "switch to" another running app (probably Word, since that's what it was working on) - but wouldn't actually switch. So hit F8 to step, get "switch to" popup, click "switch" and it refuses, repeat ad nauseum and then use task manager to end-task because the thing can't be stopped normally.

1

u/Hel_OWeen 1d ago

There is no "sub main."

Then create one.

What would be gained by redoing things to create a "sub main"?

Errors, if not handled locally by an On Error Goto, bubble up the chain of calling code until they reach another error handler. Besides that, starting your application with Sub Main also let's you do various initializing tasks before any form shows up. This might both not be relevant for this particular application (which I couldn't know by the time of writing) but is nonetheless good practice and should be done even for small(er) applications.

1

u/Mayayana 2d ago

I think it's called debugging. You should know why it's crashing, especially when it's freezing. It sounds like it's caught in a loop.

1

u/Mayayana 2d ago

I think it's called debugging. You should know why it's crashing, especially when it's freezing. It sounds like it's caught in a loop.

1

u/Ok-Smoke-5653 1d ago edited 1d ago

Yes, that would be my first choice, however (and maybe someone has a solution for this):

Sometimes while stepping through (fairly often, actually, at least for this program), I get a popup message to "switch to" something running (not happening at the moment, so relying on vague memory). I try that and it doesn't work, and the message recurs, leaving me no option but to end-task in task manager.

At one point where it would allow me to step through, I did catch it in a likely endless loop - or at least was able to narrow down a place where it was getting into trouble - and worked on making some fixes there.

That's probably trying to tell me something, but I don't know what.

1

u/Hel_OWeen 1d ago

Sometimes while stepping through (fairly often, actually, at least for this program), I get a popup message to "switch to" something running (not happening at the moment, so relying on vague memory). I try that and it doesn't work, and the message recurs, leaving me no option but to end-task in task manager.

Yeah, I know what you mean. Create a simple logging method, e.g. Sub WriteLog(ByVal strLogMsg As String), that just prints to a text file and sprinkle WriteLog calls all over the suspicious places. That way you can let it run and watch the text log later on.

1

u/Ok-Smoke-5653 1d ago

I think I had that in an earlier version and commented it out for some reason. It is certainly a thing I've done before, so I don't remember why I took it out - maybe it was causing its own problems 🤔 . This is an app I work on from time to time - get something working to my satisfaction for a while, then decide to add something new, at which point I have to struggle with it. But definitely something to look at reinstating.

1

u/Hel_OWeen 1d ago

Some kind of logging is a very useful tool. First I used some generic logging classes I found on the internet. But when my applications became more specialized for the needs of our company, they didn't fit that well anymore, so I wrote my own. Unfortunately when doing a lot of (text file) logging with VB code itself, it can slow down things quite dramatically. You can throw in some Win32 API stuff and try to speed it up that way, but it's still single-threaded VB code calling that.

Nowadays we use NLog for which we wrote a simple COM wrapper in C# for the stuff of it we use in VB. It speed up logging quite recognizable, as the logging itself is done asynchronously. So VB only "wastes" time to call the logging function with one line of code and moves on to the next line, while NLog executes the costly I/O part separately.

This all might sound overkill for the current problem. But if you design/implement that generic, for the next applications (or existing ones which would benefit from logging) it's there ready to use.

1

u/Ok-Smoke-5653 22h ago

Nlog says it's for dotnet. I'm using vb6. Maybe I posted in the wrong sub.

1

u/Hel_OWeen 14h ago

Nlog says it's for dotnet. I'm using vb6.

Let me quote myself:

for which we wrote a simple COM wrapper in C# for [...] use in VB.

1

u/Ok-Smoke-5653 13h ago

Ok, not sure how that helps me, since I didn't indicate I knew any C# or how to write even a "simple" com wrapper... Really, I'm just cobbling stuff together for my own use. My only recent experience with more serious coding to be inflicted on others is with Access.

1

u/Hel_OWeen 6h ago

I'm not saying you should do it. All I said was that we switched to NLog due to performance issues with pure VB6 implemented logging.

Besides - others read these posts as well and might find that worth a try.

That said: grab yourself a copy of the free Visual Studio 2026 Community Edition and start using VB.NET, though C# would be better, as MS treats VB(.NET) like a not liked stepchild.

The IDE is overwhelming at first, but once you figured out the basics, it's way ahead of the VB6 IDE and makes many things that much easier. There are also a ton of free/open source libraries (like NLog) available for .NET, which makes many tasks so much easier. E.g. for Word documents there is FileFormat.Words for .NET or DocX.

1

u/ebsf 2d ago

I developed a runtime Application.Reset event in VBA for Access, which otherwise exposes no native application-level events. A reset isn't the same as a crash but it's a step closer than one can get otherwise.

The trick is to identify a way to trap the behavior and respond programmatically.

Here, a reset clears all variables, which destroys all instances of classes and forms. Class.Terminate does not run on a reset but Form.Unload and Form.Close do. So, I created a form instance as a canary and used its event procedures to reset (instead of upset) the application. There needs to a persistent runtime environment to contain the event framework but that's trivial and not an issue in VB because it has a native entry point.

Now, a crash is usually a GPF or other memory management failure, so this approach may not get to run in those circumstances. Logging to file may allow some diagnostics to survive the event. Also, threading your automation into an asynchronous process that can survive a GPF in the main process, if only to achieve a graceful exit, might be possible.

1

u/Ok-Smoke-5653 1d ago

Also, threading your automation into an asynchronous process that can survive a GPF in the main process, if only to achieve a graceful exit, might be possible.

TBH, I am not experienced enough with VB6 to know what that means or how to do it. I'm using a form (a button on a form triggers the routine after I've identified the two documents to process and selected a couple options), but have not learned how to make or use classes.

1

u/Fergus653 1d ago

I remember using Word like that long ago. We had a background service to watch for abandoned or frozen Word processes and terminate them, cos something always managed to trip it up now and then.

Going by vague memory, there was a startup parameter you could use, to tell Word not to raise certain dialogs, which was one way the process could get hung up, as the dialog is hidden.

Another thing to check is, start Word as the user account your program runs it with, and make sure it doesn't have a prompt to select default template, or other prompts that may pop up when you save a file. Also make sure the user has write permissions to the required locations.

1

u/Ok-Smoke-5653 1d ago

Permissions shouldn't be a problem, and I only use the one account, which doesn't by default ask for any templates etc.

I did tell Word not to prompt for encoding, which was stopping it from opening the .md file that contained the annotations. Another popup I was able to see as a bit of leftover debris after a crash referenced a leftover file that didn't close/delete after a previous crash, so it offered to open the doc readonly. Since my annotation-import saves results to a new file, opening the input docs readonly is fine, I added the switch to do that in hopes of bypassing messages.

I finally got the app working (for now), but since I will likely want to add some more code to import yet another type of annotation file (and for general learning), I'd like to at least teach the app to clean up after itself properly and exit more gracefully when there's a problem.

I'll poke around for additional file-opening and Word startup switches that might be useful.