Difference between form.close and application.exit - vb.net

I am recently out of school, working my first job as a programmer. We have a user-reported bug that is occurring when our application timeout timer closes the application. I'm pretty sure I've narrowed it down, but am curious as to why the original programmer would have done this, if it's good coding practice, and if so, I am curious if anyone has a way to handle this. We are getting a post-closing system error, as it occurs after the main form closes, so we don't get any exception log input.
The close functionality of the timeoutTimer_tick handler does the following:
For iCount As Int16 = Application.OpenForms.Count - 1 To 0 Step -1
Try
Application.OpenForms(iCount).Close()
Catch
End Try
Next
Try
Application.Exit()
Catch ex As Exception
End Try
The program is set with the application property to close when the main form closes (not ALL open forms are closed). This makes me wonder why we're looping through each form and closing them individually, and then calling Application.Exit()
I'm pretty sure our error is because of the Application.Exit call after all open forms are closed. It doesn't see the main form, as it was closed during the loop, and throws an error. I feel like we should be using one or the other, but not both.
Any input or advice? Which is better, or are either better (or should this code work without error, and I am simply wrong).
Thanks

In WinForms you have a Shutdown Mode setting (Project Properties>Application Tab)
This allows you to specify When startup form closes or When last form closes
So logically you should not need Application.Exit .If you do then there is some other object hanging around in memory that you need to dispose of (something started on a thread / background worker etc)
So If you have the startup form setting:
[StartupFormName].Close
or if you have the last form setting:
Do While My.Application.OpenForms.Count > 0
My.Application.OpenForms(0).Close()
Loop

Related

Universal Exception Handler

Is there a simple way to catch all exceptions in your VB.NET applications? I'm interested in making it so that instead of my users seeing a runtime error, they just are told that an error occurred and to contact tech support, then the relevant error information is logged so our support team can look at it afterwards.
You can use the OnUnhandledException application event to catch (almost) every exception that wasn't handled by the code.
On the Project Properties window (double-click project file on the solution explorer or Project Menu -> [Project name] properties), the Application page has a "View Application Events" button that creates a new file in your project.
In that file there are some events that are fired at application level; one of those is the UnhandledException. Whatever you put there will be executed instead of the classic JIT dialog. The UnhandledExceptionEventArgs object has an Exception property with the unhandled exception object, and a ExitApplication property that decides if the application should exit or continue executing.
Namespace My
' The following events are available for MyApplication:
'
' Startup: Raised when the application starts, before the startup form is created.
' Shutdown: Raised after all application forms are closed. This event is not raised if the application terminates abnormally.
' UnhandledException: Raised if the application encounters an unhandled exception.
' StartupNextInstance: Raised when launching a single-instance application and the application is already active.
' NetworkAvailabilityChanged: Raised when the network connection is connected or disconnected.
Partial Friend Class MyApplication
Private Sub MyApplication_UnhandledException(sender As Object, e As Microsoft.VisualBasic.ApplicationServices.UnhandledExceptionEventArgs) Handles Me.UnhandledException
MessageBox.Show(e.Exception.ToString) '<-- the exception object
e.ExitApplication = True '<-- True if you want the application to close; false to continue - if it can
End Sub
End Class
End Namespace
Note that there are still some "über-exceptions" that can't be caught even with this method (out of memory for example), but this way you can log what exceptions are not being correctly handled on your code, or what scenarios are actualy happening that weren't considered at the beggining.
More info here
As a side note: don't rely too much on this event. This has to be for extremely exceptional cases, as what is caught here should be treated ASAP in the corresponding class/module/method. This is a helpful tool for debugging and test cases but having too much exceptions being handled by this event would be a sign of something wrong in your code.
It depends on what environment your application is running in. If you are using WPF or WinForms, you would launch your application using a main method instead of directly launching a form or page. Your main method should then wrap the calls to instantiate the UI in a try catch block.
So, for a WinForms Application, you could do something like this:
Sub Main
Try
Dim MainUI As New Form1
MainUI.Show()
Application.Run
Catch ex As Exception
'Do that fancy exception processing
End Try
End Sub
You can do something similar with WPF. But, WPF also supports an event model where you are notified of exceptions, very similar to the one that ASP.Net uses.
You will never be able to catch the StackOverflowException.
All the others for sure yes. I'm not familiar with VB, but it is easy to achieve in C#. For VB, I think the generic exeption handler could be
Try
...
Catch e As Exception
...
End Try
Of course this has to wrap all your code. You can find more for examples here.
If you have forms application, it is not practical to have the handler around Application.Run() as the only event handler. Keep it there, but add also two others:
When inside the form, and exception occurs, you want to keep execution in that context – keep the form open etc. For this purpose, use ThreadExceptionEventHandler.
And also, for case when application is irrepairably crashing on some problem, add handler to Dispatcher.UnhandledException event. It is last thing executed before the application ends. You can log the exception to disk for later investigation etc. Very useful.
Let's see some good resource how they are applied.

Abort running code on form when form is disposed?

I have a large, complex client application I am now maintaining. For security purposes, it requires a constant connection to the server. It has a thread that is handling all the socket communication between itself and the server.
The way it's currently written, if there is any communication issue with the server, the communications thread fires off an event that closes and disposes all open forms and returns the user back to the initial connection/logon screen.
The problem I'm having is that sometimes this communication issue can happen in the middle of the execution of a function (such as one that is blocked by a modal form). When the modal form and parent form are disposed of, the function still finishes running, often leading to exceptions and errors.
For example, the report form has a function that opens a dialog, accepts input, and then runs a report based on that input:
'Inside the class for the ReportForm:
Private Sub RunReport()
'Run code that requests list of reports from server
_ReportSelectionForm = New frmReportSelection(reportList)
_ReportSelectionForm.ShowInTaskbar = False
Me.AddOwnedForm(_ReportSelectionForm)
_ReportSelectionForm.ShowDialog(Me)
'the following code will still execute when ReportForm (Me) is disposed:
username = _ReportSelectionForm.txtUsername
If (_ReportSelectionForm.DialogResult = Windows.Forms.DialogResult.Ok) Then
'Run code
ElseIf (_ReportSelectionForm.DialogResult = Windows.Forms.DialogResult.Cancel) Then
'Run different code
End If
'etc
End Sub
So, if the Report Selection Form is open and the communications thread times out communications with the server, the communications error event fires which closes and disposes the ReportForm. This, in turn, closes the _ReportSelectionForm Dialog. When this happens, even though the parent form has been disposed, finishes running the code after "_ReportSelectionForm.ShowDialog(Me)". This throws an exception on "_ReportSelectionForm.DialogResult" or "_ReportSelectionForm.txtUsername" because _ReportSelectionForm is Nothing.
If this was one isolated place, I could handle this with a few extra checks before continuing to run the function, but it's all over this large program.
What's the best way to handle this? Can I abort code execution on a form that I'm closing?
Hopefully I explained it adequately. My Google-Fu is failing me. Thanks in advance.
Change your code to:
Dim result as DialogResult = _ReportSelectionForm.ShowDialog(Me)
If (result = Windows.Forms.DialogResult.Ok) Then
'Run code
ElseIf (result = Windows.Forms.DialogResult.Cancel) Then
'Run different code
End If
That way you're not referencing the ReportSelectionForm.

My application won't terminate

VB.NET program.
While developing on Visual Studio Express 2010, there are two buttons: Start Debugging, and Stop Debugging.
Well, while debugging, I close my application (the red X button). However, when I look back at Visual Studio, it seems to still be in debugging mode (the Start button is disabled, and the Stop button is enabled). So I have to manually press the Stop button.
I remember it was not like this before.
Perhaps it is because my application uses multiple forms or something? Then I am probably missing something rather important... Any ideas?
You've got something open somewhere. You can force the entire app to quit by adding
End
in the form's FormClosed event:
Private Sub Form1_FormClosed(sender As Object, e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
End
End Sub
Are you doing any threading? Shutting down your primary app leaving threads running will cause what you are seeing. Also app design can cause what you are seeing. You can start your vb.net app running a "main" procedure, but if you don't provide an exit for it, the app will continue to run.
Ensure that all hidden forms (if any) are closed, properly dispose all objects.
If you are hiding any form and forgot to close it in your application this scenario may happen. Or if you are using threading in your application and they are not terminating properly then also it happens.

Application process stays loaded after exit

We have an application that allows custom UI and interaction via SDK.
A DLL is developed for this purpose using VB.Net and the SDK.
An object variable refers to the application and there are some other object variables for components within the application.
Application allows assigning VBScript code to button(s) displayed in toolbar. The VBScript code is:
Dim Utility_Main
Set Utility_Main = CreateObject("Utility.Application")
Utility_Main.Launch()
This launches a form (custom UI) and users can interact with the application via this form.
Although application itself has its own UI, this utility form is created for database lookup, preserving certain attributes of application objects etc.
In just about every exit point of the form, a procedure is called to unset object variables for application and its components using following code:
========================================
Try
Marshal.ReleaseComObject(objX)
Catch
End Try
Try
objX = Nothing
GC.Collect()
Catch
End Try
Note1: ReleaseComObject and setting object variable to Nothing was wrapped in "If (Not objX is Nothing) Then". But it was changed to above format to make sure it gets called.
Note2: GC.Collect was added later to force GC.
========================================
This is done for each object in reverse order of object hierarchy.
Application's executable (Application.exe) remains loaded in both of the following cases:
Application is closed first and then Utility form is closed
Utility form is closed first and then the application is closed
The only time "Application.exe" goes away is if Application is closed first and then Utility form is closed by clicking on "End Task" in Task Manager.
Any help will be greatly appreciated.
I realize you say that it was split up for some reason, but this should be:
Try
If objX IsNot Nothing Then
Marshal.ReleaseComObject(objX)
End If
Catch e As ArgumentException
' hopefully you have some debug output here
Finally
objX = Nothing
GC.Collect() ' really doubt this is necessary
End Try
This guarantees that objX is released if it is not Nothing, and if that throws an exception (note the list of exceptions), then you can catch it and figure out what happened. Whether or not an exception is thrown, objX will be set to Nothing and the GC will be invoked.
It's probably not this code that is causing your program to stay open. You will need to show more code (how they interact, or any non-daemon threads that you may manually start will also be to blame). It sounds like Utility is forcing the Application to stay alive with a non-daemon, background thread, but it really could be the other way around, and it could be the case that doing that in both directions.

Can not get Process to die in VB.net

I've inherited some VB.net code. My task is to find out why it isn't working. I have 2 applications. The first one
is run as a service, infinitely checking a table to see if there are any tasks to be handled. If it finds one, its supposed to fire off the second application to handle the task then returns to the loop and checks for another. Both these applications are forms but they do not show any windows. The problem I'm having is after the second application is finished, the first application never gets a signal it is done so it is waiting forever, thus it can't move onto the next task. If I go into TaskManager and kill the second application, the first one gets that notification and proceeds as it should. Below is how I am creating the process and waiting for it. I've tried several different ways of creating and waiting for the process (using a Shell/OpenProcess, WaitForSingleObject,etc) and I can't get it to work. I've searched all over the internet, StackOverflow and the MSDN site but nothing I've tried works. I've been messing with this for 2 days!!
Form 1 Load:
Dim ProcessProperties As New ProcessStartInfo
ProcessProperties.FileName = strExeFullPath
ProcessProperties.Arguments = " /project " & l_project
ProcessProperties.CreateNoWindow = True
Dim myProcess As Process = Process.Start(ProcessProperties)
myProcess.WaitForExit()
When Form2 is finished, it does a Me.Close() and Exit Sub in the load subroutine but the process is still showing in the TaskManager and never returns to Form1 so Form1 is in WaitForExit forever. I've tried closing every open file and connection and setting them to Nothing in Form2, Me.Dispose,etc. I've tried Application.Exit as the last line of Form2. That stupid thing will not die!! Why won't it DIE!!??!!
What am I missing?
If I go into TaskManager and kill the second application, the first one gets that notification
Keep your eyes on the ball, the real problem is that this second application is not exiting by itself. And thus myProcess.WaitForExit() isn't going to return. So this is not a problem in your code snippet.
Why the 2nd app doesn't want to quit is completely unclear from your question. Given that it is a Windows Forms app, do keep in mind that there is nobody to click the Close button of the form. Application.Exit() should make it stop, Environment.Exit() is a rude abort that cannot be veto-ed by a FormClosing event handler.
Anyway use this:
ProcessProperties.Arguments = String.Format("/project {0}", 1_project)
No leading space is required and code becomes more readable.
Cheers!
I suspect Form2 is trying to show some modal dialog (maybe a message box, maybe an unhandled exception box) before quitting. Since App2 is launched by App1, which is a service, Form2 cannot interact with the desktop and just sits there waiting for a button click that will never happen.
Try to allow the App1 service to interact with the desktop (you can find that option on the Log On tab of the service properties dialog box) and check if Form2 actually pops up a dialog before quitting.