views:

845

answers:

6

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.

A: 

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.

Shoban
hey Shoban, i can capture an external app end process (iexplorem notepad, etc) using your code. But what should I do to capture the end task on the same app (the one tht contains Form1 in ur code above)
Rashmi Pandit
He said, "within the same windows application itself".
Matthew Flaschen
You can't do it in the same app, so Shoban's idea is as close as you can get.
RichieHindle
i cud create an app1 to monitor end process on app2, but i need the userid in app2 to change the db entry
Rashmi Pandit
Just noticed tht "end task" gets captured by the Application.ApplicationExit eventhandler, but "end process" does not.Thanks though, Shoban and Richie
Rashmi Pandit
+1  A: 

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.

jhamm
+3  A: 

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:

  1. 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.
  2. 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.

Also, I addressed a similar StackOverflow question here.

Foredecker
Yes, I can do event handling. However, if the user does an end process from the task manager, he will still be flagged as "logged in" in the database and when he tries to login again, he won't be allowed to.Now I know why the end process message says 'You cant save any unsaved data ... etc etc"
Rashmi Pandit
Right - this is by design. Imagine if Windows let an app hook the call to TerminateProcess() which is what task manger uses. Task scheduler is not designed to be used to normal end a process - its a gun - it is intended to kill processes, not end them in an orderly way. Your intent is noble! All processes should try to clean up and persist data reliably, but if the user wants your process stopped, TerminateProcess() will do it right then and there.
Foredecker
This all sounds like Rashmi P. doesn't see forest from the trees. DB connection needs to timeout server-side. New process will create new connection, ergo no problem-o.
GregC
Foredecker I understand your point now. That's also y we get a pop-up sayin 'process will not get a chance to save state or data' when an end process is done.
Rashmi Pandit
A: 

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.

Bork Blatt
A: 

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:

  1. 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.

  2. 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").

Mark
+1  A: 

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.

Martin
hey thank Martin ... i'll have a look into this one :)
Rashmi Pandit