Keeping an Application Alive

I recently was working on a project in which, among other things, there needed to be a process that would restart the application should it ever be terminated for no reason. This isn’t unusual for kiosk applications where the only UI that the user will be able to get to is a single application running on the system. This isn’t an unusual need and something for which we had a utility that could do this; we generally refer to these as “Kiosk Application Monitors.”  But I decided not to use it. Why not? Because when developing it is a pain to deal with an app that isn’t easily killed. If I manually terminated the application it would almost immediately restart; this was a behaviour that was by design. When I really wanted the application to terminate and stay that way things were more challenging. This had to be done from the task manager and the task manager wasn’t easily accessible since the KIOSK app ran as always on top. To see the task manager I would first have to kill the app. But if the app were killed it would just restart.

Not wanting to deal with the difficulty of this I made a new a Kiosk Application Monitor (hereon referred to as KAM). While I would generally prefer to make utilities in C# I used C for this; I was going to be using Win32 APIs and it is easier to have direct access to them instead of  writing P/Invoking declarations for them.

The key difference in this KAM and the other ones that we had used was that this KAM could be terminated through keystrokes. It adds a keyboard hook that receives every keystroke that a user makes no matter what application.

Termination on Detecting Safe Word

I’ve got a variable named SafeWord that contains the word that when typed will kill all of the child processes and shut down the KAM. To better insulate the app from an accidental activation I’ve mandated that the escape key be pressed before the safe word and the enter key be pressed immediately after the safe word.  The keyboard hook receives the virtual key codes for the keys pressed. The code for escape (0x1b) and enter (0x0d) are both used directly within the source code.   Any other key press will be will be ignored until the escape key has been pressed, and will be checked for a match to the safe word. At the first mismatch the procedure will stop comparing until the escape key is pressed again. When the enter key is pressed the routine checks if the end of the safe word has been reached. If it has then the user has typed the same word; the routine to terminate the child processes is called.

keyboardHook

They keyboard routine is a small part in what this does, but a real time saver for me.

Allowing Only One Instance

I didn’t want more than one instance of this program ever running on the same machine. The way I managed that is pretty usual for Win32 programs; I used a named event to ensure there is a single instance. Named events are shared across programs. After creating one (with CreateEvent ) calling the GetLastError() function afterwords indicates whether or not this is the only instance of an application that has access to the event or if another program already has an instance of an event by the same name. When another instance has already created one GetLastError returns ERROR_ALREADY_EXISTS.

SingleInstance

Process Description and Start-Up

Moving from the ancillary functionality to the core functionality, I decided to use JSON for specifying information on the processes that should be started and watched. The C++ libraries do no intrinsically support JSON data handling. I used a third party library for this. The data in the JSON is used to populate a structure that gives very basic information on the process to be monitored.

Structure

Most of these values are passed directly to the Win32 function CreateFunction. Ignore is there so that I could disable a process without completely removing it from my configuration file. For each process that I’m going to start I create a new thread to monitor it.

CreateThreads

Most of the code within the CreateWatchedProcess function will run within an infinite loop. The process is created and information about it is populated into a PROCESS_INFORMATION variable (which I have named pi). The value of interest for the KAM is pi.hProcess. This is the process handle. The wait functions in the Win32 API can accept handles processes. In the case of WaitForSingleObject passing a process handle will block the calling thread until the process terminates.  There is nothing that my program has to do for detecting the termination of the process. When the next line after WaitForSingleObject executes we know the process has been terminated. The only question is if it was terminated because there was a request for the KAM to shut down or if this were an unexpected .

processLoop

How Did it Perform

In testing things worked fine. I’d intentionally put a bug in the program of interest that would cause it to crash and the KAM restarted it. The app I was using it with also remembered it’s state and could restore the UI to what it was before. From the perspective of the user the screen flashed but was otherwise normal. When I tried the same utility in the production environment I’m happy to say that its full functionality was not exercised; the program it was monitoring never crashed.

I’ve found the program to be useful and see some opportunities to increase it’s utility. I plan to make updates to it to support things such as starting processes in a specific order, monitoring the message pump of another process to detect lock conditions, and allowing the utility to accept or transmit process information over a network connection.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.