EndItAll 2: A True Killer App
ARTICLE DATE:  10.16.01

By  Neil J. Rubenking 
Install utilities often tell you to shut down all other tasks before running the install. There are also programs that demand so much computing power that any concurrently running tasks will adversely affect their performance. On today's powerful systems, you easily can have a dozen or more programs loaded at any given time. Shutting them down manually is tedious and time-consuming.

ADVERTISEMENT This issue's utility, EndItAll 2, lists all the programs running on your system and lets you decide which ones to close down. The processes necessary for basic system operation are protected from termination, though. From the remaining processes, you can choose which to close, which to kill (close down forcibly), and which to protect. Once you know which files you want to shut down, you can configure EndItAll for automatic action via a script or a batch file. This is useful for backups and defrags during off-hours. Options let you block power-management utilities and screen savers during operation.


Version 2 is a major update to EndItAll, which was originally published on the PC Magazine Extra Web site. EndItAll 2 runs under Microsoft Windows 95, Windows 98, Windows 2000, Windows Me, and Windows NT 4.0, and requires version 4.7 or later of the system library Comctl32.dll. If you're running Windows 95 or NT 4.0, you may need to download an update. You can get it here: http://www.microsoft.com/msdownload/
ieplatform/ie/comctrlx86.asp. Choose the latest version number of the x86 download. EndItAll was written with Delphi 6. The source code is provided with the utility for those interested in seeing how the program works. Note that PC Magazine programs are copyrighted and cannot be distributed, whether modified or unmodified. Use is subject to the terms and conditions of the license agreement distributed with the programs.

Understanding EndItAll
EndItAll has the power to shut down almost any program, and that power can be dangerous. Closing a visible application like your word processor is usually harmless, but killing the wrong invisible background process can crash Windows or make it unstable. You must understand EndItAll's two ways of shutting down programs, which we call close and kill.

The safest way to shut down any program is to choose Exit or Close from its File menu, or to click the close (X) button in its top right corner. This gives the program a chance to perform any special shut-down tasks like recording configuration settings or asking if you want to save changes. Whenever possible, EndItAll tries to close a program using the programmatic equivalent of clicking the close button. EndItAll sends a message asking the program to close, and then waits up to 30 seconds for the program to finish up. If the program asks whether you want to save changes, you must answer within 30 seconds; otherwise EndItAll will decide that the close action failed. When EndItAll closes a program in this way, all of the memory and other resources the program was using are returned to the system so other programs can use them.

To close an application programmatically, a message is sent to the application's main window. If there is no main window, then the application cannot be closed. Some programs, particularly those that are activated from an icon in the system tray, may have a main window that's hidden. As long as a window exists, hidden or not, EndItAll can send it a message asking it to close.

If you can't close a program by clicking the close button, either because there isn't one or because the program doesn't respond, your only recourse is to kill the program by pressing Ctrl-Alt-Del to invoke the Windows Task Manager and then choosing End Task. Likewise, if EndItAll can't close a program normally, it can try to kill the program. Killing a program, whether through Task Manager or EndItAll, can cause problems. The program doesn't get the opportunity to record its configuration or save changed data. Under Windows 9x, memory and other resources may not be freed for use by other programs. And killing some essential programs can crash Windows. Thus, you should never kill a program if you can close it normally. EndItAll will try to close rather than kill a program whenever possible.

After you have killed one or more programs under Windows 9x, there's a chance that some of the system's memory and other resources are tied up and unavailable to other programs. The most cautious course is to restart Windows as soon as doing so is convenient. Under Windows NT and 2000, EndItAll can effectively force a program to close itself, which avoids the problem of tied up resources. Even so, you may want to log off or restart in order to regain the use of programs that are launched at start-up but were shut down by EndItAll.

EndItAll categorizes each program as one of four types: Application, Hidden, Explorer, or Process. Application means the program has at least one visible window. In most cases, you can close such a program yourself. Hidden means the program has only hidden windows; you might be able to close it yourself by activating the hidden window and then closing it. Explorer gets special treatment, in that EndItAll will close folder windows only, not Explorer itself. The last program type, Process, is a background process with no windows, hidden or visible. Because there are no windows to receive the close message, this last type must be killed.

Killing a process can be dangerous--and background processes can't be closed--so by default, EndItAll excludes (or protects) background processes from close or kill attempts. This protection is optional; you can remove it (more on this later). If you discover that killing a particular process causes problems, you can restore its protection. By default, visible and hidden applications are not protected; both the close action and the kill action are allowed. You can, however, choose to protect any program you like.

Certain programs are permanently protected; EndItAll will never close or kill itself, Kernel32.dll under Windows 9x, and Lsass.exe under Windows 2000, among others. Protection for these programs is hard-coded inside EndItAll, because terminating them causes spectacular problems. EndItAll will never kill Windows Explorer, but you can choose whether to let EndItAll close Explorer's folder windows.

Getting Started
To install EndItAll, run the supplied installation program, Install.exe. To uninstall the program, use the Add/Remove Programs applet in the Windows Control Panel.

EndItAll's main window (Figure 1) contains a list of all the programs running on your system, along with information about each one. The first column, Status, contains an icon that represents each program's protection status. No icon means that the program can be closed or killed. In this case, EndItAll will first attempt to close the program, only killing it if that attempt fails.

A standard close button (X) with a green border around it means that closing is permitted but killing is not. A skull-and-crossbones symbol with a green border means that the program cannot be closed but can be killed. A yellow padlock means the program is protected--it can't be closed or killed--but this protection is optional and can be turned off. A red padlock is used to mark programs that are permanently protected and the text describing them is boldfaced. As you move the mouse over the program list, a description of the item's status appears in the status bar.

Allowing EndItAll to close a program but not kill it is a way to avoid data loss when choosing the Kill all action (discussed in the next section). If the program closes normally, all is well. If it won't close because it's asking whether to save changed data and you're not there to answer, EndItAll will refrain from killing it. Allowing EndItAll to kill a program but not close it may seem odd, but in particular cases it can make sense. Suppose you have determined that EndItAll can't close a particular application or hidden application. Any time you try to kill that program, EndItAll will wait 30 seconds for a response. If you disallow closing for that program, EndItAll can save those 30 seconds and proceed directly to killing the program.

The EndItAll toolbar contains three buttons related to protecting individual programs: Allow close, Allow kill, and Protect. These display the same icons used in the Status column. If Allow close is selected (the button appears depressed and has a bright green border), EndItAll is allowed to close the selected program. If it's not selected (the button appears flat, and has a dark green border), EndItAll will not try to close the selected program. The Allow kill button works the same way. The Action menu equivalents for these two commands use check marks rather than icons. Pressing the Protect button, with its padlock icon, simply unchecks both Allow close and Allow kill, giving the selected program full protection. These three commands are also available on the context menus for each running program.

The main program window lists four other columns after Status Program, Type, Description, and Title. Program is just the program's filename, Description is drawn from the program's version information (if available), and Title is the caption of the program's main window (if available). This is useful when you have more than one instance of a program running--for example, two copies of Notepad with different files loaded. The Type column contains one of four icons corresponding to the four process types described above: Application, Hidden, Explorer, and Process. Applications with visible windows have a window icon; those with hidden windows have a half-window icon. Windows Explorer uses its own icon, and a gear icon represents background processes. As you move the mouse over the program list, the process type appears in the status bar.

The Refresh button at the far left of the toolbar instructs EndItAll to query the system and get a new list of programs. This can be useful if you've left EndItAll running while launching or closing other programs. Also, refreshing the list will clear the references to those programs you've closed or killed. The Refresh command is also available from the File menu.

The two right-most toolbar buttons aren't directly related to shutting down programs. If the Block screen saver button is checked, EndItAll will prevent Windows from starting the screen saver. If the Block power management button is checked, EndItAll will prevent the system from turning off components or going into standby mode. That way, when EndItAll has cleared out unwanted programs, your install program or other process won't be interrupted. Note that both of these options function only while EndItAll is running. Also, depending on your Windows platform and power-management configuration, the Block power management feature may block the screen saver as well.

Closing and Killing Programs
To close a specific program, highlight it in EndItAll's main list and choose the Close program command. This command, represented by a standard close button, is available from the Action menu, the toolbar, and each running program's context menu. If Allow close isn't checked, the Close program command will be disabled.

To kill a specific program, highlight it and select the Kill program command. Kill program is represented by a skull and crossbones and, like Close program, is available from the Action menu, the toolbar, and each running program's context menu. If Allow kill isn't checked, this command is disabled.

The first time you try to kill a background process, EndItAll will give you a warning (Figure 2) and ask for confirmation. You can choose Yes to proceed, No to back off, or Yes - don't ask again to avoid seeing this message in the future. To bring these warning messages back after you've clicked Yes - don't ask again, open the file Enditall.ini in Notepad and delete the lines that have the form NoXxxWarn=0.

To close or kill many programs at once, use the Close all or Kill all commands. These commands are represented by doubled-up versions of the icons for Close program and Kill program and are available from the toolbar and the Action menu. These actions will be enabled any time there's at least one program in the list for which the action is permitted.

The first time you use the Close all or Kill all button, EndItAll will describe the action and ask for confirmation. Here again, you can tell EndItAll not to ask again. After you confirm the action, EndItAll will attempt the specified action on all programs for which it is permitted. When the process is complete, EndItAll will display a report of what it did. In addition, each Close all or Kill all action is recorded in a file named Enditall.log, which is stored in the same folder as the program. You'll want to review this log from time to time. If a Kill all operation crashes Windows, the last line of the log file will reveal which program was the culprit.

If EndItAll successfully closes or kills a program, its Status icon will change to the icon of the action that was performed, and its text fields will be drawn with strikeout lines. If EndItAll fails to close or kill a program, the Status icon shows the attempted action with a question mark overlaid, and the text fields are displayed in italics. When you refresh the list after either action, the closed or killed items will disappear, and the icons for the failed items will return to their former state. Each possible status except the rarely seen Kill failed is represented in Figure 3.

Experiment First!
We strongly recommend that you experiment carefully with the close and kill actions when you first start using EndItAll. Before you start, make sure that no critical applications are running and that all data has been saved.

EndItAll maintains a list of processes whose protection has been removed, and it will not attempt to kill a background process that isn't on this list. The utility also maintains a list of applications for which close or kill is not allowed (or neither is allowed). The program will attempt to close or kill any application that isn't on this list. These lists are saved when you exit EndItAll. To save your settings as you experiment, select Save settings from the file menu.

First try out the Close program action on some visible applications. This should never cause problems for Windows, but never is a strong word. If something goes wrong, protect the program, save your settings, and keep experimenting.

Next try Kill program on visible applications. In most cases, EndItAll will succeed in closing the program and won't have to kill it. To see what happens if a program won't close, launch Notepad, type a few words, and try to kill it with EndItAll. Notepad will ask if you want to save changes, and EndItAll will begin a 30-second countdown displayed on a button at the left of the status bar (Figure 4). Ignore Notepad's request and wait for the countdown to pass, or click the button on the status bar to cancel the countdown. EndItAll will kill the program.

The last experiment is to try killing a background process. There's some risk of crashing Windows or making the system unstable, so you may want to skip this. As before, make sure that nothing critical is running, then select your target, check Allow kill,and click Kill program. If all goes well, you've found a background process that can be safely killed. Save your settings--in case the next attempt causes problems--and try another target.

After experimenting in this way, you can eventually try Close all and Kill all. Conduct these tests under controlled circumstances so you don't risk encountering a problem later.


Automatic Operation
Once you've got EndItAll working smoothly on your system, and you have the proper protections in place, you can use command-line switches to automate the utility's operation in a script, batch file, or shortcut. To invoke the Close all or Kill all command, add /C or /K to the command line. To close or kill all instances of a particular program, append a colon followed by the program name without any path information. If the program name contains spaces, enclose it in quotes. For example:

"C:\\EndItAll" /C:filename.exe

"C:\\EndItAll" /K:"file name.exe"

Here C:\\EndItAll represents the full pathname of the EndItAll program.

When launching EndItAll in a batch file or from a command prompt, you can omit the full pathname and invoke the program using the START command, for example:

START enditall /K

Launch EndItAll with /? on the command line to display the syntax window (Figure 5).

If EndItAll is already running when you launch it in automatic mode, a second instance of the program will handle the automatic operation. When finished, the second instance will notify the first instance to refresh its list. Always refer to the log file after an automatic operation to see a report of the results. The log file is named Enditall.log and is stored in the same folder as the program.

Inside EndItAll
EndItAll uses two entirely different techniques to get the list of active programs, one for Windows 9x and the other for Windows NT and 2000. It also needs a more elaborate technique to kill programs under Windows NT and 2000 than under Windows 9x. Closing a program is a simpler proposition, but even then EndItAll has to handle the possibility that the program may be hung or may need user input. EndItAll resorts to a bit of chicanery to clear out the tray icons of killed programs. And to minimize other interruptions, EndItAll suppresses both the screen saver and power management while it's running. All these issues will be discussed in the sections that follow.

Taking a Program Census
Under Windows 9x, EndItAll uses functions from the Toolhelp.dll library to list all running programs. Windows NT 4.0 relies on a different set of functions from the Psapi.dll library. Windows 9x doesn't support Psapi.dll and Windows NT 4.0 doesn't support Toolhelp.dll. Windows 2000 offers both, but its implementation of Toolhelp.dll doesn't return as much information as the Windows 9x version. So for Windows 9x, EndItAll uses the Toolhelp.dll functions, and for Windows NT 4.0 and 2000, it uses the Psapi.dll functions.

EndItAll's GetListOfProcs9x() function, defined in the module Endfuncu.pas, uses the Toolhelp.dll functions to enumerate all running programs. The process is a lot like enumerating files that match a template. A call to the CreateToolHelp32Snapshot() API function returns a handle to a snapshot of the system. The other Toolhelp.dll functions work from the data in this static snapshot, which avoids problems that could be caused if processes appeared or disappeared during the enumeration. The API functions Process32First() and Process32Next() fill a PROCESSENTRY32 data structure with information about each process in turn, including the process ID and executable name.

The GetListOfProcsNT() function, also defined in the module Endfuncu.pas, accomplishes the same thing using the Psapi.dll functions EnumProcesses(), EnumProcessModules(), and GetModuleFilenameExW(). A call to EnumProcesses()fills an array with the process IDs of all active processes. GetListOfProcsNT() obtains a process handle for each process by calling the API function OpenProcess(). It passes that handle to EnumProcessModules(), which fills an array with handles to each module of the process. The first handle in the array is the main program itself, and passing this handle to GetModuleFilenameExW() yields the desired executable name.

Regardless of which technique was used, for each process with a non-zero ID, EndItAll records the process ID and filename in an object of type TProcWinObj, defined in the module Reobjs.pas, and adds that object to a standard Delphi TStringList. EndItAll then calls the API function EnumWindows(), passing this list as the user-defined lParam argument. Windows calls the function ListWinProc(), defined in Endfuncu.pas, passing it each top-level window handle in turn. ListWinProc() calls the GetWindowThreadProcessID() API function to get the process ID associated with the window handle GetWindowThreadProcessID() locates the object holding data about that particular ID and adds the window's handle to a list maintained by that object. The result is a list of objects representing all running processes, each containing a list of all windows belonging to that process.

Program Extermination
Killing a program in Windows 9x is as easy as 1-2-3:

1. Obtain a process handle from the process ID by calling the OpenProcess() API function.
2. Pass that handle to the TerminateProcess() API function.
3. Check to be sure the process was killed.

That's what the Exterminate() function (defined in Endfuncu.pas) does under Windows 9x.

Killing a process under Windows NT and 2000 isn't quite so simple. The Exterminate() function first gives itself debug access to the process, using a technique detailed in Microsoft Knowledge Base article Q131065 (http://support.microsoft.com/support/kb/articles/Q131/0/65.asp). The function then attempts to terminate the program from within (closing instead of killing) by forcing a call to the kernel32 function ExitProcess().

Specifically, the Exterminate() function calls the API function DuplicateHandle() to create a duplicate of the process handle with all necessary privileges, and uses the CreateRemoteThread() API function to launch the ExitProcess() function within the process. I first ran across this technique in Windows Developer's Journal magazine, July 1999 (http://www.wdj.com/articles/1999/9907/9907c/9907c.htm). Calling ExitProcess() from within the program allows the program to shut down in an orderly fashion, freeing all resources. In the event that this technique fails, Exterminate() will call TerminateProcess() to kill the program.

Closing Time
I thought at first that closing a program would be a simple matter of sending a WM_CLOSE message to its main window. The two API functions most often used to send Windows messages are SendMessage(), which waits for and returns a response, and PostMessage(), which doesn't wait. Unfortunately, neither of them suits EndItAll's needs. If the program is hung, using SendMessage() will cause EndItAll to hang as well. And PostMessage() is out, because EndItAll needs to get that response if the program is not hung.

The solution begins with the less-commonly used SendMessageTimeout() API function. This function sends a message and waits until it gets a response or a specified number of milliseconds pass. The function will return immediately if the receiving program is hung. That ties in well with EndItAll's need to wait up to 30 seconds for a program to finish. The thread that makes the SendMessageTimeout() call, however, is completely stopped until the call returns. EndItAll wouldn't even be able to repaint its main window, much less display a countdown. And there's no way to cancel the operation when the main program is tied up this way.

In the end, I needed not one but two worker threads to handle closing programs, both of which are defined in the module Clothdu.pas. The constructor for TCloThread takes as its arguments the window handle and process ID of the program to be closed, the number of seconds to wait, and a pair of notification functions fRet and fNote. The fRet function is automatically called when the thread terminates, and the fNote function is used to pass the countdown back to the main program. Also, in its initialization section, the Clothdu.pas unit creates a standard Windows event object called StopEv. The main program signals the thread to stop by passing this event to the API function PulseEvent().

As always in a TThread descendant, the real work occurs in the Execute() method. TCloThread.Execute() opens a process handle from the passed process ID and passes the window handle to a new instance of the TSMTOThread object (more about that object shortly). Then TCloThread.Execute() enters a loop in which it repeatedly calls the API function WaitForMultipleObjects(). TCloThread.Execute() passes the process handle, the thread handle, and the StopEv object to this function, with a timeout value of 1000 (1 second). WaitForMultipleObjects() will return when the process terminates, the thread finishes, the event is signaled, or the timeout period elapses. If the return value is anything but WAIT_TIMEOUT, the TCloThread's work is done. Otherwise, it calls the notification method fNote to update the countdown and tries again, for as many seconds as were requested.

The TSMTOThread object's Execute() method handles the actual sending of the WM_CLOSE message and related tasks. It first checks for a hung program by sending an innocuous WM_GETTEXTLENGTH message using SendMessageTimeout(). If that is successful, the Execute() method calls the API functions SetForegroundWindow() and BringWindowToTop() to bring the window into view. If not, the program was probably hung, and trying to bring the window into view would cause the thread to hang. Either way, Execute() method next sends the WM_CLOSE message using SendMessageTimeout() and waits until it gets a response or the specified timeout period ends.

All this seems an elaborate bunch of code just to close a window, but any other method would either risk EndItAll hanging or would not retrieve the necessary information.

Washing Out the Tray, and More
When a program that has a system tray icon ends, that program must specifically call the Shell_NotifyIcon() Windows function to remove the tray icon. If the tray-based program crashes, the orphaned icon will hang around until the mouse cursor passes over it. The same is true if EndItAll kills the program. And there is no function call that will force the system tray to refresh its icons. EndItAll's RedrawSystray()function, found in Endfuncu.pas, fakes the necessary mouse movement. It finds the window handle of the system tray, gets its bounding rectangle, and programmatically moves the mouse cursor back and forth across it in 8-pixel increments. It only pauses 2 milliseconds between moves, so you're not likely to see it in action.

Initially, I thought EndItAll's screensaver blocking would be very simple. Windows sends out a WM_SYSCOMMAND message with a wParam of SC_SCREENSAVE before activating the screen saver. If a program returns 0 in response to this message, the screen saver doesn't activate. I found out, though, that this message goes only to the active window. My next try was a system-wide WH_GETMESSAGE hook that would convert the screen saver message to WM_NULL, forcing the receiving window to return 0. This failed if the receiving window was a command prompt or if the platform was Win NT 4.0. Using SetCursorPos() to twitch the mouse cursor's position from time to time worked in all platforms except NT 4.0, but caused a visible jerk in the cursor location if the twitch occurred while the user was moving the mouse rapidly.

If you're gazing at a computer's display and want to avoid interruption by the screen saver, you probably just tap a Shift key. Doing so doesn't produce unwanted input, but it's enough activity to stave off the screen saver. On modern platforms (Win 98, Win ME, and Win 2000) EndItAll periodically simulates a tap on the Shift key using the keybd_event() API function. Under Win 95 and Win NT 4.0, however, the simulation doesn't have the same effect as an actual keystroke; the internal no-activity timer is not reset. On those platforms, EndItAll temporarily turns the screen saver off using the SystemParametersInfo() API function with the SPI_SETSCREENSAVEACTIVE flag, restoring the original state when EndItAll terminates. This is slightly less desirable, because a system crash would deprive EndItAll of the chance to re-enable the screen saver.

Blocking power management is a bit easier. The BlockPower() function, defined in Endfuncu.pas, turns blocking on and off. To block, it passes the flags ES_SYSTEM_REQUIRED, ES_DISPLAY_REQUIRED, and ES_CONTINUOUS to the API function SetThreadExecutionState(). This combination of flags tells Windows that the calling program needs the system and the display to be continually available, thereby preventing Windows from shutting down system components or going into standby mode. To turn off the blocking, the function makes the same call with only the ES_CONTINUOUS flag. The SetThreadExecutionState() function isn't present in Windows 95 or NT 4.0, so EndItAll loads that function dynamically and disables the blocking function if dynamic loading fails.

Killing or safely closing a running program takes a surprising amount of code. But when you need to automate these tasks, you'll find that EndItAll is a true killer app.

Neil J. Rubenking, the author of EndItAll, is the contributing technical editor of PC Magazine. Sheryl Canter is the editor of the Utilities column and a contributing editor of PC Magazine.

EndItAll 2: Download It Here
ARTICLE DATE:  10.16.01

By  Neil J. Rubenking 
First Published on the PC Magazine Extra Web site, October 16, 2001, v20n17
EndItAll, Version 2.0
Platforms: Windows 95, 98, ME, NT 4, 2000, XP 
License Information:
PC Magazine programs are copyrighted and cannot be distributed, whether modified or unmodified. Use is subject to the terms and conditions of the license agreement distributed with the programs.

Description:
Install utilities usually tell you to shut down all other tasks while they're operating. Other programs demand so much of your system's computing power that any concurrently running tasks will impact their performance. On today's powerful systems, you easily can have a dozen or more programs loaded at any given time. Shutting them down manually is tedious and time-consuming.

EndItAll 2 lists all the programs running on your system, and lets you decide which ones to close down. The processes necessary for basic system operation are protected from termination. From the remaining processes, you can choose which to close, which to kill (close down forcibly), and which to protect. Once you know which files you want to shut down, you can configure EndItAll for automatic action via script or batch file. This is useful for backups and defrags during off-hours. Options let you block power management and the screen saver during operation.

Version 2 is a major update to EndItAll, which was originally published on the PC Magazine Extra Web site. EndItAll 2 was written by Neil J. Rubenking, and first appeared in PC Magazine October 16, 2001 (v20n17). Source code is included.

Copyright (c) 2005 Ziff Davis Media Inc. All Rights Reserved. 
