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.
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.
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.
Related
I have an application (C# + WPF) that attempts to wrest control of the graphical interface of any process passed to it as an input and resize/reposition for my own purposes.
It does its job rather well, I think. Upon expected termination (the base class inherits from IDisposable) the "captured" process is released - its parent is set to the original, its windowstyle is reset, etc. etc.
In fact, on testing, I can capture, release, recapture, and so on, the same process as many times as I want with no issues.
However, upon unexpected termination (say another process forcefully kills it), the process never regains its graphical interface! I can tell its still running but I can never set that process back to its original state.
It almost seems like the process doesn't respond to window-based Win32 API calls that set specific window features anymore (for example, I can get information with GetParent, GetWindowThreadProcessId, etc but calling ShowWindow or related results in nothing).
Any suggestions on why this is happening? I'm guessing that since I set the parent of the process to my WPF application (which then unexpectedly closes) it causes some issue in trying to recover the initial interface?
This is why it's happening (or, at least, an indication of why I had so much difficulty finding the issue out on my own); can I recover from it? And, if so, how?
Edit -
IInspectable makes a good point in the comments, question adjusted to make better sense for this particular application.
It seems I've gotten my answer; so, for the sake of completeness I'll post what I've gotten here in case anyone else has a similar issue.
According to the information provided by IInspectable in here and here (with more context in the comments), it seems that what I'm trying to do here (assign a new parent cross-process) is essentially unsupported behavior.
My Solution:
Recovering (at least at the point that I'm talking about - i.e. unexpected crashes or exits) probably isn't feasible, as we've already gone off the end in undetermined/unknown behavior. So I've decided to go for the preventative route.
Our current project already makes use of the Nancy framework to communicate across servers/processes so I'm going to "refine" our shutdown procedure a bit for my portion of the program to allow it to exit more gracefully.
In the case of a truely unexpected termination, I'm still at a loss. I could just restart the processes (actually services with a console output, in our case, but w/e) but my application is just a GUI/Interface and isn't very important when compared to the function these processes serve. I may make some sort of semaphore file that indicates whether a successful shutdown occurs and branch my code off so that it indicates that the processes are no longer visible until the next time they're restarted.
(context: Windows 10 desktop, no UWP)
For handling Windows Action Center notification activation events I use a LocalServer32 C# console application, STA and Thread.CurrentThread.Join() calls*. This works just fine. The executable is started and I get Activate calls from COM.
You start getting these calls after calling RegisterTypeForComClients and they stop after calling UnregisterTypeForComClients. The problem is, even without real concurrency in my case (at least in my direct communication with the object -- I could be wrong as I'm no COM expert) I expect some final Activate call(s) might still come in just after I called UnregisterTypeForComClients. Missing Activate calls is bad and shouldn't happen. I need to handle events for just a bit longer -- but how much longer?
Is there a by-the-book method of making sure I get all the last COM events? Something of a WaitForComMessageLoopToShutDown method? I don't want to go with 'a one second wait should be enough'.
notes
RegisterTypeForComClients is the equivalent of CoRegisterClassObject in COM.
UnregisterTypeForComClients is the equivalent of CoDisconnectObject in COM.
(*) I know I could use MTA with some synchronization, but the question applies there as well. I don't use MTA because I'd just be serializing stuff with no real concurrency.
edit -- A more elaborate description
My executable application (an out-of-process server) gets started by OLE automation in Windows because 'things' happen for me to handle. I handle these 'events' (calls to the Activate method)
knowing there could me more than one
knowing there could be time between them
using an inactivity timeout of, say, 30 seconds before self terminating
(for the user within this time span clicking multiple items, or Windows processing delays -- the latter being very small)
Upon expiry of my inactivity timeout I stop the COM object with UnregisterTypeForComClients. Now, crux of my problem: I ended my loop handling events but a new event from Windows was sent to my server just before unregister. Windows says: this event (activation) was sent, I scratch it off my list. But - my application hasn't registered it because my handling loop exited already. Event lost! I hope for a solution in the form of:
The issue described never occurs, or
Something along the lines of you need to call xyz until it returns x
As a side note, I started out with the sample (titled 'Sending toast notifications from desktop apps sample' on MSDN) on Github linked to by Hans Passant in the comments. It doesn't address this issue.
Ok, long story short I have a Windows service that handles Win32_VolumeChangeEvent and logs USB disk device arrivals to the Event Log and to a SQL database. An additional component to this is a hidden UI (WinForms) which loads in the user session at login - this pops up a message box reminding users of company policy about USB keys etc. AFAIK, this was the best way to go since services can no longer run in interactive mode.
Anywho... architecturally, v1 of this little thing ran with the UI component handling WndProc messages for device insertion, then passed the device identifier through IPC (named pipes) to the service which would handle WMI methods / EventLog writing (as not all users have local admin rights). This had the downside of the UI element being process killed and no longer detecting device insertions.
So, current version is that the service handles Win32_VolumeChangeEvents and gets the needed details from the device, then logs to EventLog and SQL. All is outstanding and works perfectly. Except now I'm wondering what the best way to trigger the UI into displaying the popup is.
I've researched around Google and here, looking for ideas about eventing over IPC, so I can just subscribe to an event from the UI component and fire it within the service, but I'm not finding much that jumps out as being helpful. I'm also constrained to .net2, so WCF is out of the picture (although I'm not afraid of p/invoke if you want to go that way).
So. How would you do it? Links, thoughts, ramblings, pseudocode, actual code... all is appreciated. I'm trying to stick to what I believe is best practice, although I also think programming is a bit of an art form and my best practice may be someone else's horror story.
So SO - what would you do? Let me know if I need to clarify :)
Back in the bad old days of Windows API programming, we'd sometimes use RegisterWindowMessage to register a unique message ID that (presumably) only our window knew how to handle. We could then trigger that window from another application by calling PostMessage with a window handle of HWND_BROADCAST, and the msg parameter being that unique message value. That works great if everything you want to share between the processes can fit into two DWORD values (wparam and lparam). Sharing more data can be done if you allocate global memory and pass a reference as one of the parameters.
That should still be possible with .NET. Certainly there's no trouble calling PostMessage. As for handling the message in the UI code, you have to override the Form's WndProc. See How do I send/receive windows messages between VB6 and c#? for an example.
You could do something with named events, although that would only notify the UI that some change had occurred. It wouldn't actually tell you what happened. I suppose, if there's only a small set of possible events, you could have multiple events, but that gets complicated pretty quickly.
You could go the named event route and use shared memory (memory mapped file) to share the state.
Or, you could set up sockets, named pipes, TcpListener/TcpClient, or even a UdpClient. All should work, with varying degrees of complexity and/or reliability.
The only idea that comes to my mind is to have a service check the state of the UI application periodically and restart it if it has been killed. There seems to be no standard module that would run within user's session and let the service send notifications to this module. There exist third-party solutions but they can be killed (not saying that they should be installed in order to be used).
Update: after re-reading the question I think that maybe your UI doesn't receive windows messages, so you need another mechanism. Why not create a Semaphore synchronization object in service and wait for it in UI process (in a separate thread)?
I'm not sure if there is a proper term for what I want to because any I've tried in google haven't bought anything up.
Basically, on an application crash I would like to perform a final action to clean up database record locking.
I would also like to catch this when debugging is stopped using the stop button, as I understand it using the stop button is very different to exiting your application by a normal process in your application.
Is there a normal way for achieving what I'm trying to do? The application is a C#, .NET 3.5 Windows Forms Application written in VS2008.
Cheers
You can't do anything within a process after it's killed.
Your only way to achieve what you want would be to have a second process that watched for the first one dying, and then did the cleanup on its behalf.
You have to worry about the second process crashing, or being killed, and so on. Not easy to make it work in all conceivable cases, but a lot better than nothing.
Check if any of the solution on Handling end process of a windows app helps you.
I don't think its possible to catch when the user stops the process via the debugger, however, you can override the OnUnhandledException event to catch when any exceptions are raised and not caught by your application.
The answer to your first requirement is to have (at it's most basic):
try
{
// Main application
}
catch // Though you might not want this
{
}
finally
{
// This code always executed even if application crashes.
}
However there are other considerations when dealing with Windows applications as RichardOD indicates in his comments here - http://msdn.microsoft.com/en-us/library/system.appdomain.unhandledexception.aspx and here http://msdn.microsoft.com/en-us/library/system.windows.forms.application.threadexception.aspx
The answer to your second requirement is no you can't trap the application being stopped in the debugger (or at least there's not a way I've come across). It just kills the process.
For instance if you have stopped at a break point and then press stop the code doesn't carry on executing to termination - it just exits.
The same is true if the application stops due to some external factor like the power being turned off. In scenarios like this there's no way that the program can execute any code whether it's in a finally block or not!
However, I've just come across this question Visual Studio : executing clean up code when debugging stops which has an answer that states:
You can use the DTE (VisualStudio
Automation Model) to write a macro
that will be invoked when a stop debug
happens, below is a snippet of the
idea.
Private Sub DebuggerEvents_OnEnterDesignMode(ByVal Reason As EnvDTE.dbgEventReason, ByRef ExecutionAction As EnvDTE.dbgExecutionAction) Handles DebuggerEvents.OnEnterDesignMode
If (Reason = dbgEventReason.dbgEventReasonStopDebugging) Then
// DO YOUR CLEAN UP CODE HERE
End If
End Sub
So while you can't trap the stopping of the execution in your application you can do something about it in Visual Studio.
NOTE: Answer provided by Shay Erlichmen not me!
You could subscribe to the Application.ThreadException event when your program starts up, before you call Application.Run. This will give you a chance to do something if your application throws and exception. It will not do anything, however, for catching the debugger when you hit stop.
<SecurityPermission(SecurityAction.Demand, Flags:=SecurityPermissionFlag.ControlAppDomain)> _
Public Shared Sub Main()
AddHandler Application.ThreadException, AddressOf ErrorHandlerForm.Form1_UIThreadException
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException)
' Run the application.
Application.Run(New Form1())
End Sub
Private Shared Sub Form1_UIThreadException(ByVal sender As Object, ByVal t As ThreadExceptionEventArgs)
' Handle exception
End Sub
Your other option is to just surround your Application.Run in a Try...Catch block, which should give you similar results.
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 doesn't address the debugging scenario, but it does allow you to do something when your app is about to crash.
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.
A "normal way for achieving what you're trying" is to make sure your application never crashes.
You can also provide a standalone application which will let system administrator to release any file locks which might be left for whatever reason (power outage, ...). Such application could be used to fix this as well.
Is it possible in .NET to ascertain whether my application is closing due to Windows being given a shutdown command (as opposed to any old application closing) in order to either write out some temporary cache files or even block the shutdown long enough to prompt for user input?
Whilst my current scope involves a Winform app and a windows service, I am interested in understanding this in a generic way if possible
SystemEvents.SessionEnding looks like a good starting point for you. That article talks about the event sequence involved when a logout/shutdown is occurring.
In general, you will want to handle the WM_QUERYENDSESSION Windows message. This will give your application a chance to do cleanup, or to block the shutdown if it's really necessary.
Handle the SessionEnded event on the Microsoft.Win32.SystemEvents type.