2

I have a VB.NET WinForms application running from an executable stored on a network share. In that application, I have defined the UnhandledException handler in the ApplicationEvents (Private Sub MyApplication_UnhandledException(sender As Object, e As UnhandledExceptionEventArgs) Handles Me.UnhandledException). In my handler, I have a method that logs the exception details to a text file before prompting the user to confirm exiting the application.

However, this application "randomly" crashes and exits completely without any log created or message box displayed. This behavior happens at different executable points in the application and I'm trying desperately to track down the cause. I'm guessing that the problem may be due to either a temporary loss of network connectivity or some other issue communicating with the PostgreSQL database, but I can't confirm the source since there's no stack trace or message detail provided before the application disappears from the user's screen.

This should be "simple", but I'm at a loss as I've tried several things, including wrapping massive blocks of code in Try...Catch blocks and adding additional logging features to my error handler. I've tried rearranging the code in my UnhandledException handler to avoid any issues with new object instantiation (for my ErrorHandler object). I added a check in the error handling for logging the error locally if the network is unavailable. I've even added a simple message box to the FormClosing event of my main form if the closing wasn't directly initiated by the user to try to at least have the application do something before shutting down completely.

No matter what I've tried so far, the application still forcibly exits during seemingly random times. The user will be pressing a button to execute any of a number of methods that usually work normally. If the user relaunches the application after being kicked out and performs the exact same action again, it works without a problem. What I need to accomplish is some form of "idiot-proofing" the error handling so that whatever is causing the application's exit is caught and logged. I'm sure there are things I'm not thinking of at this point, so let me know if any further clarification is needed.


CODE

The application's Startup event handler:

Private Sub MyApplication_Startup(sender As Object, e As StartupEventArgs) Handles Me.Startup
    Try
        Common.ApplicationStartup(ApplicationSettings.CurrentUser)
    Catch ex As Exception
        Dim StartupException As New ErrorHandler(ex)

        StartupException.LogException()
        MessageBox.Show("You do not have permission to access this resource." & vbCrLf & vbCrLf &
                    "The application will now exit.")
        System.Environment.Exit(1)
    End Try

    ' *********************************************************************
    ' ** Notify the user if the application is running in test mode.     **
    ' *********************************************************************
    If ApplicationSettings.TestMode Then
        MessageBox.Show("This application is currently running in Test Mode, and will use " &
                        "local paths for data and configuration information." & vbCrLf & vbCrLf &
                        "If you are trying to use this application with live data and see " &
                        "this message, please contact the IT HelpDesk for assistance.", "TEST MODE",
                        MessageBoxButtons.OK, MessageBoxIcon.Exclamation)

        If ApplicationSettings.CurrentUser.Department = Users.Employee.Department.IS Then
            If MessageBox.Show("Do you want to continue in Test Mode?", "TEST MODE", MessageBoxButtons.YesNo,
                               MessageBoxIcon.Question, MessageBoxDefaultButton.Button1) = DialogResult.No Then
                ApplicationSettings.TestMode = False
            End If
        End If
    End If

    ' *********************************************************************
    ' ** Initialize any application-specific settings here.              **
    ' *********************************************************************
    Try
        'If ApplicationSettings.TestMode AndAlso ApplicationSettings.CurrentUser.Department = Users.Employee.Department.IS Then
        '    MessageBox.Show("If you have any additional parameters/settings to configure for this application, " &
        '                    "please do so before commenting out this message.",
        '                    "DEVELOPMENT WARNING", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
        'End If
    Catch ex As Exception
        Dim ExHandling As New Common.ErrorHandler(ex)

        ExHandling.LogException()

        MessageBox.Show("There was a problem with initializing the application's configuration." & vbCrLf & vbCrLf &
                    "The application will now exit.")
        System.Environment.Exit(2)
    End Try
End Sub

The ApplicationStartup method:

Public Sub ApplicationStartup(ByRef CurrentUser As Users.Employee)
    ' *********************************************************************
    ' ** Default the TestMode variable to False.  If the check for       **
    ' ** whether or not the application is running from the IDE fails,   **
    ' ** the application should assume that it's running live.           **
    ' *********************************************************************
    ApplicationSettings.TestMode = False

    ' *********************************************************************
    ' ** Perform a check of whether or not the application is running    **
    ' ** from the IDE or the Debug folder.                               **
    ' *********************************************************************
    SetTestMode()

    ' *********************************************************************
    ' ** Retrieve any parameters sent to the executable from the command **
    ' ** line and determine if the application is running from the task  **
    ' ** scheduler.                                                      **
    ' *********************************************************************
    ApplicationSettings.ScheduledTask = False
    ApplicationSettings.RuntimeParameters = System.Environment.GetCommandLineArgs().ToList

    If Not ApplicationSettings.RuntimeParameters Is Nothing AndAlso ApplicationSettings.RuntimeParameters.Count > 0 Then
        For Each Parameter As String In ApplicationSettings.RuntimeParameters
            If Parameter.ToUpper.Contains("SCHEDTASK") Then
                ApplicationSettings.ScheduledTask = True
                Exit For
            End If
        Next
    End If

    ' *********************************************************************
    ' ** Set up the CurrentUser object by querying Active Directory and  **
    ' ** the PostgreSQL database for details.                            **
    ' *********************************************************************
    Try
        If CurrentUser.ADUserName Is Nothing OrElse String.IsNullOrEmpty(CurrentUser.ADUserName) Then
            CurrentUser = New Users.Employee(Environment.UserName)
        End If
    Catch UserEx As Exception
        Dim ExHandler As New ErrorHandler(UserEx)

        ExHandler.LogException()
        Throw UserEx
    End Try

    If CurrentUser Is Nothing Then
        Throw New Exception("Username " & Environment.UserName & " was not found in Active Directory.")
    ElseIf CurrentUser.Enabled = False Then
        Throw New Exception("Username " & Environment.UserName & " is not a currently active employee.")
    End If

    ' *********************************************************************
    ' ** Default the DBCommandTimeout variable to 30.                    **
    ' *********************************************************************
    ApplicationSettings.DBCommandTimeout = 30
End Sub

Private Sub SetTestMode()
    ' *********************************************************************
    ' ** Use the Debug.Assert to call the InTestMode function, which     **
    ' ** will set the TestMode variable to True.  Debug.Assert will only **
    ' ** execute if the program is running from a debugging version of   **
    ' ** the code (in Design-Time, or from the Debug folder).  When the  **
    ' ** code is running from a compiled executable, the Debug.Assert    **
    ' ** statement will be ignored.                                      **
    ' *********************************************************************
    Debug.Assert(InTestMode)
End Sub

Private Function InTestMode() As Boolean
    ' *********************************************************************
    ' ** Set the global TestMode variable to True.  This function is     **
    ' ** only called in debug mode using the Debug.Assert method in the  **
    ' ** SetTestMode Sub.  It will not be called if the application is   **
    ' ** running from a compiled executable.                             **
    ' *********************************************************************
    Common.ApplicationSettings.TestMode = True
    Return True
End Function

The UnhandledException event handler:

Private Sub MyApplication_UnhandledException(sender As Object, e As UnhandledExceptionEventArgs) Handles Me.UnhandledException
    Dim Response As DialogResult = DialogResult.Yes

    Response = MessageBox.Show("An unknown error occurred in the application." & vbCrLf & vbCrLf &
                               "Do you want to exit the application?", "UNHANDLED EXCEPTION",
                               MessageBoxButtons.YesNo, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1)

    Dim UnhandledError As New ErrorHandler(e.Exception)

    UnhandledError.LogException()

    If Response = DialogResult.Yes Then
        e.ExitApplication = True
    Else
        e.ExitApplication = False
    End If
End Sub

The main form's FormClosing event:

Private Sub frmMain_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
    If Not e.CloseReason = CloseReason.UserClosing Then
        MessageBox.Show("The application has encountered some sort of problem and is closing.")
    End If
End Sub

Let me know if you want/need to see more code. As I said, the error occurs at seemingly random points in the application's execution and are inconsistent between one try or another.


UPDATE 7/1/2020


I haven't come back to this topic for a while because I moved a copy of the executable (and the supporting libraries) to the user's local drive and had her run the application from there. While she was using that copy, she wasn't "booted" from the program as described above (she had a few errors here and there, but those were all handled by my exception handling routine as expected).

Here we are a few months later and I've had cause to switch the user back to using the copy of the executable from the network share. I just received a report from the user that she's once again experiencing the issue with being randomly kicked out of the application without any warning or error and I'm not getting any of my exception "reports". Luckily for me, she's done a decent job of documenting the occurrences.

The strange thing is that sometimes these crashes occur when she's not doing anything "special". A couple of times they've happened when she simply clicks on one of the toolstrip menus to display a drop-down list of submenus. I've checked and there isn't any event handling code for these parent toolstrip menus, so it isn't like there are any queries or other instructions being executed. It should simply be displaying the submenu.

FWIW, a couple of weeks ago, we had a serious connectivity issue between our office and the server on which these executables are being stored (hosted VM's accessed via site-to-site VPN). I was getting around 10% packet loss across the VPN, even though I didn't see any packet loss anywhere else. I never found out what was causing the packet loss, but it appears to have been resolved and I can only assume that one of the ISP's between here and there had a faulty piece of equipment that they repaired/replaced. When I run a PING test to the server across the VPN, I'm not seeing any significant packet loss (maybe 1 packet out of several thousand) and response times of 15-35ms.

At this point, I'm only guessing (obviously), but I'm thinking that perhaps there's some sort of "time-out" occurring on the VPN connection that's causing a loss of connection to the code base. It's a total pS.W.A.G. ((pseudo) Scientific Wild-@$$ Guess), but I'm trying to come up with a viable solution to address the issue.


MY IDEAS

One thought is this: All of my in-house applications are run from this server and all of the supporting libraries for each are stored in the executable folder. Yes, this means that I've got multiple copies of many libraries stored on the server in various folders. I've been wanting to reduce this duplication, but I haven't really had/taken the time to figure out the best way to do so. At this point, I'm considering some sort of "installer" package for each of the workstations to drop the necessary libraries into each user's GAC (Global Assembly Cache) instead of accessing them through the VPN.

The only problem with this (that I can think of) is that there are several legacy systems that use different versions of the same libraries. For example, my current development is using Npgsql v4.1.3.1, but there are some applications that are still using v2.x and I don't really have time to go through every application to find which ones are/aren't using the current version and implement a version upgrade. That's just one of the many libraries where such an issue would arise, so I suppose I'd need to try to install all of the in-use versions to each GAC.

Another thought: Bring all of the executables back to a local server (not over the VPN) and change all of the shortcuts to point to that version instead of the one that requires the VPN. This, obviously, would have the benefit of less dependency on things like Internet connectivity and 3rd-party systems, as well as reduced latency.

The issue with this option, however, is that it's completely "unsupported" by my bosses. Their response when I've suggested something similar in the past is along the lines of "we're paying for a hosted server and they should support it..." Well, we all know that something like this may well be beyond the scope of any reasonable support request for a 3rd-party server host.

I'm really leaning towards the GAC option - at least as a first step - but I'll need to do a bit of research before I start traipsing down that road. Does anyone else have other suggestions for ways I might be able to deal with this? I'm really running out of ideas and I've got to find a real, workable and sustainable solution.

MORE INFO


I've implemented the suggestion below from @djv of wrapping the application's launch in a "startup" form that starts a new thread, but that still hasn't been able to catch whatever is causing the crash. The application still just periodically dies with absolutely no logging that I've been able to find so far.

I've also included, in the ApplicationEvents, a very simple handler for the NetworkAvailabilityChanged event to try to catch something happening there.

        Private Sub MyApplication_NetworkAvailabilityChanged(sender As Object, e As NetworkAvailableEventArgs) Handles Me.NetworkAvailabilityChanged
            If Not My.Computer.Network.IsAvailable Then
                MessageBox.Show("Network connection has been lost.", "NETWORK CONNECTION TESTING", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
            End If
        End Sub

Unfortunately, even that hasn't given me any additional insights as the user hasn't ever seen that MessageBox.

I have found an error in the user's Windows Event Logs that seems to correspond to the most recent event, but I'm not sure what it means, exactly:

EVENT ID 1000
---
Faulting application name: <EXECUTABLE_NAME>.exe, version: 1.0.0.0, time stamp: 0x9d491d36
Faulting module name: clr.dll, version: 4.8.4180.0, time stamp: 0x5e7d1ed7
Exception code: 0xc0000006
Fault offset: 0x000cc756
Faulting process id: 0xe570
Faulting application start time: 0x01d64fc245d7d922
Faulting application path: \\<SERVER_NAME>\<SHARE_PATH>\<EXECUTABLE_NAME>.exe
Faulting module path: C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll
Report Id: 7016e3cc-7406-4854-95be-dbe3231447e7
Faulting package full name: 
Faulting package-relative application ID: 

This seems to indicate something in the CLR crapping out, but that really doesn't seem to give me any more information than I had before.

FURTHER DIAGNOSTICS/RESEARCH FOR SPECIFIC ISSUE


After digging around in the Event Logs some more, I found a couple more errors from around the time of the aforementioned event:

EVENT ID 1005
---
Windows cannot access the file  for one of the following reasons: there is a problem with the network connection, the disk that the file is stored on, or the storage drivers installed on this computer; or the disk is missing. Windows closed the program <EXECUTABLE_NAME> because of this error.

Program: <EXECUTABLE_NAME>
File: 

The error value is listed in the Additional Data section.
User Action
1. Open the file again. This situation might be a temporary problem that corrects itself when the program runs again.
2. If the file still cannot be accessed and
    - It is on the network, your network administrator should verify that there is not a problem with the network and that the server can be contacted.
    - It is on a removable disk, for example, a floppy disk or CD-ROM, verify that the disk is fully inserted into the computer.
3. Check and repair the file system by running CHKDSK. To run CHKDSK, click Start, click Run, type CMD, and then click OK. At the command prompt, type CHKDSK /F, and then press ENTER.
4. If the problem persists, restore the file from a backup copy.
5. Determine whether other files on the same disk can be opened. If not, the disk might be damaged. If it is a hard disk, contact your administrator or computer hardware vendor for further assistance.

Additional Data
Error value: C00000C4
Disk type: 0

And this:

EVENT ID 1026
---
Application: <EXECUTABLE_NAME>.exe
Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.Runtime.InteropServices.SEHException
   at <ROOT_NAMESPACE>.frmPayments.get_instance()
   at <ROOT_NAMESPACE>.frmMain.tsmiProcessPayments_Click(System.Object, System.EventArgs)
   at System.Windows.Forms.ToolStripItem.RaiseEvent(System.Object, System.EventArgs)
   at System.Windows.Forms.ToolStripMenuItem.OnClick(System.EventArgs)
   at System.Windows.Forms.ToolStripItem.HandleClick(System.EventArgs)
   at System.Windows.Forms.ToolStripItem.HandleMouseUp(System.Windows.Forms.MouseEventArgs)
   at System.Windows.Forms.ToolStripItem.FireEventInteractive(System.EventArgs, System.Windows.Forms.ToolStripItemEventType)
   at System.Windows.Forms.ToolStripItem.FireEvent(System.EventArgs, System.Windows.Forms.ToolStripItemEventType)
   at System.Windows.Forms.ToolStrip.OnMouseUp(System.Windows.Forms.MouseEventArgs)
   at System.Windows.Forms.ToolStripDropDown.OnMouseUp(System.Windows.Forms.MouseEventArgs)
   at System.Windows.Forms.Control.WmMouseUp(System.Windows.Forms.Message ByRef, System.Windows.Forms.MouseButtons, Int32)
   at System.Windows.Forms.Control.WndProc(System.Windows.Forms.Message ByRef)
   at System.Windows.Forms.ScrollableControl.WndProc(System.Windows.Forms.Message ByRef)
   at System.Windows.Forms.ToolStrip.WndProc(System.Windows.Forms.Message ByRef)
   at System.Windows.Forms.ToolStripDropDown.WndProc(System.Windows.Forms.Message ByRef)
   at System.Windows.Forms.Control+ControlNativeWindow.OnMessage(System.Windows.Forms.Message ByRef)
   at System.Windows.Forms.Control+ControlNativeWindow.WndProc(System.Windows.Forms.Message ByRef)
   at System.Windows.Forms.NativeWindow.Callback(IntPtr, Int32, IntPtr, IntPtr)
   at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG ByRef)
   at System.Windows.Forms.Application+ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr, Int32, Int32)
   at System.Windows.Forms.Application+ThreadContext.RunMessageLoopInner(Int32, System.Windows.Forms.ApplicationContext)
   at System.Windows.Forms.Application+ThreadContext.RunMessageLoop(Int32, System.Windows.Forms.ApplicationContext)
   at System.Windows.Forms.Application.Run(System.Windows.Forms.Form)
   at <ROOT_NAMESPACE>.StartupForm.Main()
   at System.Threading.ThreadHelper.ThreadStart_Context(System.Object)
   at System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
   at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
   at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
   at System.Threading.ThreadHelper.ThreadStart()

Doing some further research on the error code and exception information, it would seem that the problems are, in fact, due to the executable being loaded from the network share across the VPN.

Some of the information I found:

This last one had me doing some research on PE file options and how to set them for a VB.NET application, but I wasn't finding enough to feel like pursuing that line of thought would provide enough benefit.

I guess this means that I need to do something to bring everything back across the VPN for execution. Perhaps I'll do some sort of actual local installation for the application (now I need to figure out how to actually do that, but that's well beyond the scope of this question). I'm not particularly happy about it, but at least I have an idea of what direction to take this from here.

BACK TO THE ORIGINAL QUESTION


However, this still doesn't answer my original question about how to catch and handle these app-killer exceptions. I'd be "fine" with the application crashing if it had at least given me some indication as to what happened at the time. I thought that the UnhandledException handler in the ApplicationEvents would catch even these, but further research into the SEHException at least helps me to get an idea of why it doesn't - see SEHException not caught by Try/Catch. I know it'd be a nightmare to try to define rules to handle or ignore every single type of exception that could possibly crop up in the UnhandledException event handler, but it would've been a whole lot nicer and more helpful for troubleshooting to at least see something.

G_Hosa_Phat
  • 976
  • 2
  • 18
  • 38
  • 1
    It would be helpful to have some more information about your application. VB? C#? Console app? WinForms? WPF? – DWRoelands Jan 17 '20 at 16:00
  • 2
    Also, consider looking in the Windows Event log to see if the error is being reported there. – DWRoelands Jan 17 '20 at 16:00
  • 1
    There are a few ways to do this. How do you start your application? Can you show some code? – djv Jan 17 '20 at 16:03
  • @DWRoelands - Thanks. I was in a rush to post and forgot some of those important details. I'll try to take a look at the event log as well. – G_Hosa_Phat Jan 17 '20 at 17:17
  • @djv - The application is launched from a shortcut to the executable stored on a network share. There are several bits that happen as the application launches and it "usually" works fine, but I'll add some of the startup code to hopefully provide some additional insight. – G_Hosa_Phat Jan 17 '20 at 17:20
  • 1
    @G_Hosa_Phat have you tried running it from the local machine instead of a network share? – the_lotus Jan 17 '20 at 19:47
  • @the_lotus - I've considered that as my next step in trying to eliminate the problem. I'm just trying to figure out a way to catch *whatever* it is that's actually causing the application to drop dead so I can handle it properly. If it *is* a network issue, I'll probably have to look into some hardware upgrades... – G_Hosa_Phat Jan 17 '20 at 19:58
  • 1
    @G_Hosa_Phat does windows provide a dialog box that the application crashed? If so, can you generate a dump before clicking ok on that dialog box? If yes, that can be used to look into why the crash happened. You might also be use registry settings to have a dump file created for the crash: https://stackoverflow.com/questions/30121822/how-to-generate-windows-memory-dump-when-application-crashes – alhalama Jan 18 '20 at 00:19
  • @alhalama - Thanks for the suggestion. Unfortunately, no. There's no dialog, no warning, no "spinning"... The application just closes out completely. I've tried throwing message boxes into different sections of the code to at least get *something* before the application closes, but none of those appear either. I'll take a look at the registry settings as well. I just need to find anything that can at least point me in the right direction for resolving the issue. – G_Hosa_Phat Jan 18 '20 at 16:12
  • @G_Hosa_Phat are you able to reproduce the issue yourself where you can run the application with a debugger attached or is it only end users that can reproduce this? If end users, is it all users or specific users? Do you have logging around the actions users are taking where you know the series of actions that led to a crash? If not maybe you can add some as that might allow you to identify a pattern if you can't reproduce with a debugger. – alhalama Jan 19 '20 at 15:48
  • @alhalama - Unfortunately, I've not been able to reproduce the issue myself during any debugging, especially because it happens so randomly - at different execution points each time. Even more frustrating, only one user ever really uses this application as a regular part of her job (we're a very small company). It doesn't happen more than once, maybe twice in a day, then some days it doesn't happen at all. After the crash, she will go back and try to reproduce the issue herself, but everything goes through normally at that point (never had it *not* work twice in a row). – G_Hosa_Phat Jan 21 '20 at 14:52
  • @G_Hosa_Phat If the issue only happens after the application has been running for a while, maybe there is a leak in the application causing the random crash. Maybe profiling the actions taken and see if there are unexpected resources being consumed. Or even just check the resources used by the application at various parts of the day if it is kept open for the one user. Also if the WER dialog isn't showing, maybe DontShowUI is set to 1 instead of 0 and setting it back might let you get a dump while the dialog is present: https://docs.microsoft.com/en-us/windows/win32/wer/wer-settings – alhalama Jan 21 '20 at 19:57
  • @alhalama - I'll see what I can do about checking resources. The WER `DontShowUI` setting doesn't exist in the registry (not sure if they removed that option in Windows 10). The biggest problem is that it's so inconsistent. There's no apparent rhyme or reason to when the user experiences the problem. Sometimes it's early in the morning, late in the afternoon, or any time in between. It's happened at one time or another with a wide variety of different functions/blocks of code but I just don't know which *actual* code is breaking. – G_Hosa_Phat Jan 22 '20 at 20:19
  • The randomness makes it seem more like it would be a resource isn't available and that could happen if the application is leaking some resource. On the WER settings, if they are missing they are probably just set to the default which is to show the UI so it is unusual that it wouldn't show. You could try manually adding the relevant settings and set DontShowUI to 0 and see if that changes anything on that machine. – alhalama Jan 23 '20 at 00:56

2 Answers2

1

Here's an idea. It looks like it might require some rewrite of how your application is started. But consider adding another "startup form" with an Application.Run à la C# void Main() { Application.Run(Form); }. You can wrap that in a Try-Catch and handle otherwise unhandled exceptions.

Add a form called StartupForm, and make that your application's entry point

enter image description here

And the StartupForm code

Imports System.Threading

Public Class StartupForm
    Protected Sub StartupForm_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
        Dim applicationThread = New Thread(AddressOf Main)
        applicationThread.SetApartmentState(ApartmentState.STA)
        applicationThread.Start()
        Dispose()
    End Sub
    Protected Shared Sub Main()
        Using myForm As New MainForm()
            AddHandler AppDomain.CurrentDomain.UnhandledException, AddressOf UnhandledExceptionHandler
            AddHandler Application.ThreadException, AddressOf UIThreadExceptionHandler
            Application.EnableVisualStyles()
            Try
                Application.Run(myForm)
            Catch ex As Exception
                UnhandledExceptionHandler(myForm, New UnhandledExceptionEventArgs(ex, True))
            End Try
        End Using
    End Sub
End Class

Module ExceptionHandlers
    Public Sub UIThreadExceptionHandler(ByVal sender As Object, ByVal args As ThreadExceptionEventArgs)
        MessageBox.Show(args.Exception.Message, NameOf(UIThreadExceptionHandler))
    End Sub
    Public Sub UnhandledExceptionHandler(ByVal sender As Object, ByVal args As UnhandledExceptionEventArgs)
        MessageBox.Show(args.ExceptionObject.Message, NameOf(UnhandledExceptionHandler))
    End Sub
End Module

StartupForm will set off a new thread before it disposes itself. The new thread starts a UI thread with your MainForm (whatever it's called - this is your current startup form).

To test it, you can throw an exception from a button press

Public Class MainForm
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Throw New Exception("Unhandled, from button on Form")
    End Sub
End Class

and see that it's handled in initial Try-Catch

enter image description here

We add additional handlers in case the Try-Catch doesn't catch everything

AddHandler AppDomain.CurrentDomain.UnhandledException, AddressOf UnhandledExceptionHandler
AddHandler Application.ThreadException, AddressOf UIThreadExceptionHandler

but I find that managed* exceptions are all caught.

*Of course, we won't be catching exceptions from unmanaged sources

djv
  • 15,168
  • 7
  • 48
  • 72
  • I'll take a look at implementing something like this. Yes, it'll require some work, but if I can use this to find the actual source of the issue, that work will be well worth it. Of course, I don't know that it would require *that much*... Most of that startup code is executed in the `MyApplication_Startup` event, so it *should* still work... – G_Hosa_Phat Jan 17 '20 at 20:00
  • I implemented this suggestion and had my user run the recompiled version. It did fine the first day, but this morning the application completely crashed out again without warning and without any message box or log. The application window just disappeared. She went back in and was able to perform the exact same thing without a problem. I haven't been able to find anything in the Event Viewer, but perhaps I'm just not looking in the right place. My only *guess* at a possible cause at this point would be a temporary loss of network connection, but I'm not even sure about that. – G_Hosa_Phat Jan 24 '20 at 15:38
  • I suppose my next troubleshooting step is going to be putting the executable on her local machine and have her run it from there, but I really wish I could catch *something* - ***ANYthing*** - from the application before it shuts down like this. – G_Hosa_Phat Jan 24 '20 at 15:42
  • @G_Hosa_Phat if you have any unmanaged code running, this will not catch exceptions originating from it. It sounds like that's what is happening, but it's unclear. Do you use any unmanaged libraries? – djv Jan 29 '20 at 15:41
  • I'm not using any COM components, but some of the libraries are likely implementing some unmanaged code (Office Interop and Crystal Reports would be most likely). I copied the entire executable folder to the user's local machine and was finally able to get an error to pop up in the UIThread handler while generating a report. That report uses the Microsoft ReportViewer instead of Crystal (this application is a mish-mash of legacy code written by different people which I've been trying to "clean up" for a while now). The "good" thing is that it didn't shut down the application this time. – G_Hosa_Phat Jan 30 '20 at 15:47
0

I would make log file which is a txt file in your application host (debug folder) of the app so you could as developer check on it from time or send these log files to you remotely which is data collection from time to time to view code errors on client side and have general overview of what is crashing using the stack strace you can view code line that had error and have detailed describtion of the error, also

tutorial to using stream writer https://www.c-sharpcorner.com/article/csharp-streamwriter-example/ so you would make it like to so for every code block that is prone to having error

    Try
    'Here your code is written for example dim a as integer=12
    Catch ex as exception
' Here stream writer takes your ex.Message & ex.Stack Trace  and adds it to the log file
'After that show message box saying
MessageBox.Show("Oops something crashed please try again ")
'That way you are handling both the user and developer
  End Try

'For user you don't want the app to crash on him for you as developer you need the log 'file to trace errors and prevent them for future iterations of your program 'also at your assembly with each version make sure you have also make sure your log file has utc date time for when the error occured and include user that did it as well if available

Community
  • 1
  • 1
Rosh
  • 11
  • 2
  • Thank you for the suggestion, but I've already got a fairly robust error-handling routine that creates a log file (includes stack trace, message details, and several other bits of info) for exceptions that I explicitly handle and I've even got a call to that logging in the application's `UnhandledException` handler (as indicated in the code listing above). That handler then saves that log data to a text file before e-mailing it to me. This error handling works great most of the time, but these situations seem to be bypassing it completely no matter what I've tried. – G_Hosa_Phat Jan 22 '20 at 20:07