I need to stop the execution of a program in VB.net. Within a repeating structure the program checks whether a variable is true or false. When the variable is false I need to stop the program execution. I do not want to close the program but simply stop it. One way I found was raising an exception, but I would not want to display the error message to the user. What is the best way to do it ?
Do
If myvariable=false then
throw new exception... 'Silent exception
end if
Loop until ….
Davis
Edit Based on below comment.
In that case I would use something like.
Do
If myvariable=false then
Return
end if
Loop until ….
I am really not sure what you are wanting to do.
You can close the application by using Application.Exit()
Informs all message pumps that they must terminate, and then closes all application windows after the messages have been processed.
If you want to be really abrupt you can call the End Statement.
Terminates execution immediately.
and
The End statement stops code execution abruptly, and does not invoke the Dispose or Finalize method, or any other Visual Basic code. Object references held by other programs are invalidated. If an End statement is encountered within a Try or Catch block, control does not pass to the corresponding Finally block.
You can use the Stop Statement to suspend execution but it will invoke the debugger.
If the Stop statement is encountered in code that is running outside of the integrated development environment (IDE), the debugger is invoked. This is true regardless of whether the code was compiled in debug or retail mode.
Or if you are just wanting to exit out of your Do Statement you can try this
Do
If myvariable=false then
Exit Do
end if
Loop until ….
You can exit a loop with an exit statement. Alternatively, you can use your method of throwing an exception and surround the loop in a Try/Catch block which catches that specific exception and ignores it.
If you really want to stop then you can use the Stop keyword. However, I'm not confident from your question that this is what you actually want as it has different outcomes depending on whether it's running as a exe or in the IDE.
Some more context to your question would be useful in finding the best answer for your problem.
Related
I am currently writing an AHK script that reads and writes files.
I would like to handle the possible I/O errors,
but the doc isn't clear to me regarding wether I should use Try/Catch or OnError().
What is the difference between the two? And when to use one or the other?
So, after some more research, here is my understanding:
Try/Catch: Use it to:
Specifically identify certain lines of code over which it will be applied.
Then, if you would like, proceed with the execution.
A Try/Catch allows to proceed with the execution of the command after the Try block that failed.
(But, a Try/Catch does not allow to proceed with the execution of the command after the one that failed within the Try block. For example if 5 commands are wrapped, then if the 2nd one threw, it will not be possible to proceed with the execution from the 3rd after doing something in the Catch-block.)
OnError(): Use it to
Deal with any unhandled error.
Block (or not) the default error dialog.
In any cases the thread execution is stopped after you handled the error.
There can be multiple OnError() handlers active at a time,
and you can decide, in which order they will be executed (or to stop the execution after any one of them) when an error occurs.
If all handlers return 0 all handlers are called one after the other, then the default error message is displayed, then the thread exits.
If any handler returns a non-zero integer, the thread exits without calling the following handlers and without displaying the default error dialog.
I have a function in vb.net that is shared. At one point it throws an error that says an 'open datareader already exists'. But this function is called from several different places in the program. How can I find out which part of the program called the function when it errors out?
You go to the Debug menu, show the Exceptions window, put a tick next to CLR exceptions and then run your program until it errors. As soon as the exception is raised VS will break, you will be able to see the call stack, and find out where the code was before. Note that this causes VS to stop on every exception, handled or not; it can become tedious to get to where you want to be - untick the "always break when this type of exception is thrown" in the exception helper if you just keep getting irrelevant exceptions breaking before this error you're trying to chase
It sounds like you're perhaps not creating/disposing of your DB access resources properly, especially if this is a static/shared context. Are you trying to reuse one DB connection? It wouldn't hurt to post the code of the faulting module
In the past I've usually added the following line to the KeyDown sub in order to end my applications:
If e.KeyCode = Keys.Escape Then End
However, upon reading the documentation on what End actually does, it turns out that it probably is one of the worst ways to end the application in terms of releasing resources, etc.
So now I'm trying to find the recommended way to terminate the application which will properly handle all resources, etc. I've found these two questions on SO (here and
here) but I can't conclude what the right answer actually is.
The accepted answer on the first link says that applying Close() to all forms is the correct way and will release all resources used correctly. This isn't convenient in applications with multiple forms, and further down Application.Exit() is suggested, and even:
Application.Exit()
End
which will definitely make sure the program ends even if the first line fails.
On the other hand, the accepted answer on the second link says "you should never have to call Application.Exit() in a properly-designed application", contradicting the above and an answer further down which says Application.Exit() calls Close() on all forms in later versions of .Net.
This has lead me to confusion — what is wrong with Application.Exit()?
If there is no problem with it, then am I right in thinking the best one to go with is:
Application.Exit()
End
or is that overdoing it? Otherwise, when does Application.Exit() fail to work (except when I write code which cancels it)?
Note: Although this question applies to all programs I make, including ones with multiple forms, I recently have started using Sockets (with the TcpClient/Listener classes) to make connections between computers and would appreciate any additional information relating to this when terminating the program in the middle of a connection. A comment in my recent question assures me that calling Socket.Close() isn't even necessary, but now I realise that this may not be completely true since I was using End to terminate before.
Application.Exit posts an exit message to all message loops for that application.
It's a perfectly acceptable way of closing an application and will cause all forms to attempt to shutdown. Individual forms can override this behaviour, for instance if they have unsaved work. This will leave your application running afterward so you need to decide if that needs to be handled.
Saying that I only use it if an external actor needs to shutdown my application. Otherwise I leave the app to exit when its main form closes.
You also need to consider the state of any foreground threads you have as these can allow all your forms to close but leave the thread processing in the background.
End is a very brute force technique and should be used as a last resot. A well designed application should be able to shutdown by closing the forms or by calling application.exit. I have used the approach in the past of launching a timer which will call End just before I call Application.Exit ... at least I give it a chance to complete gracefully.
Note: Application.Exit doesn't block. So Application.Exit : End might as well be End which is not ideal.
Here's the timer I use:
Dim forceExitTimer = New Threading.Timer(Sub() End, Nothing, 2500, Timeout.Infinite)
Application.Exit()
Edit:
To all answerers and commenters: Please focus on providing the solution I request rather than offer ways to refactor it. The code provided below is a very condensed example for the sake of brevity. I've already stated below that this type of code exists in 20 or 30 places throughout the app and that I am choosing not to move/merge/refactor any of that code if a simpler solution exists.
Original Question:
First, here's brief run-down: We have an app that was developed by an offshore team. The purpose of this application is to run nightly maintenance on various database tables. It is a WinForms app, but it acts more like a console app as all it does is 1) execute a single method in Form1_Load and then 2) call End to shut down the program.
The problem is that the error email notification doesn't work, so I have been charged with the task of fixing it. Consider this code:
Try
'This inner Try/Catch is actually code in another method
Try
'Run some code here
Catch ex As Exception
'Errors are logged silently to text file here
End Try
Catch ex As Exception
'Code to email exception details is here
End Try
The problem is that an exception is thrown and handled in the inner Try/Catch. Because of this, there's no exception to be handled in the outer Try/Catch, hence why no email notification is being sent.
Someone might say to just add Throw ex in the inner Catch, but keep in mind that there are about 20 or 30 places in the code where exceptions are handled like this. The decision I am making is to just get it working for now and not undergo that kind of development effort. Therefore, I seek a way to somehow acquire the last exception thrown by the application. This way, I can add a Finally block to the outer Try/Catch and do something like this:
Finally
If Not Application.GetLastException() is Nothing Then
SendErrorEmail(Application.GetLastException())
End If
End Try
So if I understand this correctly, your application catches all exceptions and logs them silently to a file.
You want to change the behavior so that when the program ends you get the last exception thrown, if any, and send an email with that exception detail. But the last exception thrown isn't stored anywhere.
And you want to change this behavior without modifying the code that handles the exceptions.
That can't be done. How do you expect to change the program's behavior without changing the program's behavior? What you ask is impossible. (And, no, not even Yoda would be able to pull this particular X-wing out of the swamp.)
There is no runtime property that automatically saves the last exception thrown.
You will have to make some modification to the code that catches the exceptions. You say that the code takes this general format:
Try
'This inner Try/Catch is actually code in another method
Try
'Run some code here
Catch ex As Exception
'Errors are logged silently to text file here
End Try
Catch ex As Exception
'Code to email exception details is here
End Try
I take it that the problem is in the inner Catch block. Seems to me that if there's common code to log the errors to a text file, that code should be in a separate method. If it is, then modify that method to save the last exception in a property that can be accessed by your GetLastException method. If there isn't a common method that handles the exception logging then you'll have to make the change at every place.
The commenters are correct: A general "catch all exceptions" is almost always a bad idea. Especially when the "handling" consists of logging and continuing. When you catch some random exception, you have no idea what the state of your program is. It's very likely that the data is corrupt and the program's state is unstable. "Log and continue" just makes the problem worse, and can lead to all kinds of interesting side effects like data corruption, infinite loops, deadlock, etc.
Your best course of action here is to refactor the code. Actually, the best course would be to send it back to the offshore developers and tell them to do it right. But that's probably too much to ask.
I'm quite late to this party but you could try this rather ugly way of doing things.
Firstly extend the Application class by adding a LastException property and a GetLastException function, see here for details.
Secondly add a line to each of the inner Catch blocks and set the LastExcepotion property:
Application.LastException = ex
There you go, no need to refactor all that offshore code.
OK guys, what's going on here?
In this VB code:
Module Module1
Sub Main()
If MsgBox("Restart?", MsgBoxStyle.OkCancel) = MsgBoxResult.Ok Then
Application.Restart()
MsgBox("restarting")
Else
MsgBox("Cancel")
End If
End Sub
End Module
If this code is contained within a module, Application.Restart does not end the running application till the End Sub is hit. Any code that appears before then is executed - eg the 'Restarting' messagebox appears.
However, if the equivalent code is run within a form then Application.Restart terminates the running application immediately.
(Both cases correctly start a new instance). This behaviour does not appear to be documented anywhere - the implication in the docs is that it's synonymous with 'End' as far as the termination of the running instance is concerned. Am I missing something?
The best way to answer these questions it to look at the code itself using Reflector (or Microsoft's free for debugging code, when it is available).
With Reflector, you can see (in .NET Framework 4.0) System.Windows.Forms.Application.Restart looks for four different types of applications:
the initial check that Assembly.GetEntryAssembly is Nothing, throwing a NotSupportedException if it is;
the Process.GetCurrentProcess.MainModule.FileName is ieexec.exe in the same folder as the current .NET Framework (specifically the folder where the module defining Object is);
ApplicationDeployment.IsNetworkDeployed is True; and
the general case.
All three supported cases determine the method to start the process again, calls Application.ExitInternal and starts the process again.
Application.ExitInternal closes open forms, including the check for a form attempting to abort the close by setting FormClosingEventArgs.Cancel to True. If no form attempts to cancel, the forms are closed and, using ThreadContext.ExitApplication, all ThreadConnexts are cleaned up (Disposed or their ApplicationContext.ExitThread is called).
NB No Thread.Abort is called, so threads are NOT explicitly ended in any way. Also the Windows.Forms ModalApplicationContext, does not even call the ThreadExit "event" that a normal ApplicationContext does.
(Note that all three supported cases in Application.Restart ignore the result of Application.ExitInternal, so if a form does attempt to abort all that happens is any other forms don't get a chance to close, and the ThreadContexts are not cleaned up!)
Importantly for your question, it does NOT attempt to actually exit the current threads or the entire application (other than closing open forms and thread contexts).
However, by the time your MsgBox("restarting") executes the new application has been started.
You need to manually exit the application after calling Application.Restart. In the case of "run[ing] within a form" (you don't show the code where you tested this) either the form is closed and that is what you considered as the current application ending, or extra stuff that Windows.Forms (or VB) sets up means the application is exited by one of the "events" that throw when the clean up that does occur runs.
In other words, before testing it I expected the MsgBox to appear even when this code is in say the Click event of a form, with the form disappearing first, and the application restarting at the same time.
Having tested it, the MsgBox tries to appear, as I hear the beep that corresponds to it, and if I comment it out the beep does not occur. So something causes the application to exit even though it should have a message box open, and even putting a MsgBox in a Finally outside of the Application.Run does not appear on a Restart. (Note a similar effect is seen if you call MsgBox after Application.Exit.)
So something set up by Windows.Forms (or VB) does actually call something like Environment.Exit which calls the Win32Api ExitProcess and does not regard Finally or call Dispose or Finalize.
Note the Application.Restart documentation implies it is not for Console Applications though it currently works fine (except for the not quitting straight away, which is not implied by Application.Exit).
I am able to restart the application by closing and disposing all open forms, except the one that is calling.
For j As Integer = Application.OpenForms.Count - 1 To 0 Step -1
Dim frm = Application.OpenForms(j)
If frm.Text <> callingForm.Text Then
frm.Close()
frm.Dispose()
End If
Next
Application.Restart()
This is going to be, admittedly, a bit of a guess based on some fairly top-level reading I've done about Application.Restart(), but I think this is occurring due to the way Restart operates internally.
I think Restart() tries to do as much "intelligent" cleanup as it can for a process that is being terminated, and in what may be considered a fairly simplistic implementation, tracks certain of the things to be "cleaned up," possibly calling Dispose() on them (if applicable), which normally is a reasonable step to take. In your case, I'm going to make the guess that a background thread, or form, holds a reference to something - can't say what - that prevents the code from shutting down. It may become aware that it is executing inside a method, and wants to give that method a chance to complete before killing it - waiting on the completion of that sub/method.
I've seen other instances of Restart actually causing a really strange "Collection was Modified" error when no collection was involved. That's suggesting to me, probably naively, that the internal cleanup Restart is trying to achieve is reposed in a simple list, but in certain circumstances, the cleanup modifies the element in an unexpected way, a way that modifies the collection, causes the exception to be thrown, and aborts the exit/restart.