Is it possible to capture the task manager end process of a windows application within the same windows application itself? I am using a C# 2.0 win app and I would like to do some database processing (change a flag from 'Y' to 'N' in the DB) when an end process happens.
What you can do is get the Process ID and monitor the process and you can use HasExited property to check whether the process has end or not. Below is a quick VB code (Excuse me I dont have VS now. This was written by me in another forum)
Public Class Form1
Dim p As ProcessStartInfo
Dim process As Process
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
p = New ProcessStartInfo("iexplore.exe")
process = process.Start(p)
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
MsgBox(process.Id)
If process.HasExited Then
MsgBox("yes")
Else
MsgBox("no")
End If
End Sub
End Class
Above code starts Internetexplorer and the button checks whether the process has end or not. You can use a similar process to get all running process and use the processID.
I do not think this is possible to do from within the application. The purpose of End Task is to immediately stop the process. This does not allow any clean up code to execute.
Shoban pointed out another way to accomplish your goal. Another application or service would need to look for the main process. When the other process cannot find the main process, you could do the database processing at that point.
No, it is not possible to hook the operating system's decision to end a process. Note, this is not done by task manger, ending a process is the responsibility of the kernel.
You will need to do two things here:
- Connect event handlers to the normal user interface messages that tell a application to exit. Use these events to persist data, free resources, and otherwise exit cleanly.
- Handle exceptions as appropriate to catch errors and clean up and save data if possible.
Here are a three links to Raymond's blog explaining why you cannot do what you are asking.
- Why can't you trap TerminateProcess?
- Why do some process stay in Task Manager after they've been killed?
- The arms race between programs and users
Also, I addressed a similar StackOverflow question here.
How about a slightly different approach:
Have your application update a date time field e.g. LastPollDate every so often while it is running, and have a separate field e.g. "AppTerminatedNormally" which you set to N, and change to Y if you get a form close event.
If the app is killed via Task Manager, the date will not be updated any more, and your AppTerminatedNormally will still be no.
This way you could run a query that finds all rows where LastPollDate is older than 10 minutes and AppTerminatedNormally is N, and you would have all the sessions that were abnormally terminated.
You're all gonna spit at this post, but here goes...
You're trying to solve the problem at the wrong level (i.e. running code in your app when the kernal is killing the app). The real problem is about ensuring that the database correctly reflect the presence (or absence) of it's client application/s.
To solve this, avoid allowing applications to be in an "incongruent state" between user interactions. In other words, don't start transactions that you can't commit quickly, don't write data to files that leaves the file in a half-written or unreadable state, and don't hold resources in external to your application an incongruent state outside of user interactions. Put differently, if your app isn't busy responding to an event handler, it should be ready to close immediately.
If you follow the above practise, you'll find very few scenarios where you need to "quickly clean up" before terminating. Outside of interactions where a user clicks "OK" or "Save", etc. a well written application should be able to survive immediate termination without any lasting damage or corruption of it's data stores.
If you absolutely have to set a flag in the database upon exit (which sounds typical of a pattern used to detect whether a user is logged in or not), then consider either of the following alternatives:
Periodically (perhaps once every 30 seconds) insert/update a timestamp-like field in the database, to indicate how recently an application was online. Other applications can inspect these timestamps to determine how recently another application was online... if the value is within the last 30 seconds, the other app is still opnline.
As Woodhenge rightly suggested, create a seperate process (ideally a service) to monitor the status of the main application. Windows services can be configured to automatically restart in the event of a failure of the service. This monitoring process will then issue timestamps to the database.
Notice that both of the above suggestions solve the real problem (detecting whether applications are accessing the database) without ever leaving the database in an "incongruent state" (the aforementioned flag is "Y" when the application is actualy dead and the flag should be "N").
If you're targeting Windows Vista (or above) you might be interested in the RegisterApplicationRecoveryCallback API...
http://msdn.microsoft.com/en-us/library/aa373345.aspx
It allows you to specify a callback routine in your app that will be invoked when the process is about to crash. N.B. it is only for crashes, and won't automatically be called if the process is killed deliberately.
You can p/invoke to this API from C# (I have done it), but bear in mind that when your callback is invoked your app is already in a very bad state, and you can make very few assumptions about the state of your memory. If you have any in-memory data that you want to use in this routine, I would put it in a static at a very general scope so that you have the best possible chance of it not having been "tidied up" when your callback routine runs.
There are some other interesting APIs, related to this one, that allow you automatically restart your app after a failure, etc.