How to gracefully terminate a process? - winapi

I want to terminate a number of processes, but I want to give each process the chance to save its data, ask the user about saving a file and even ignore the close request.
So TerminateProcess is out of the question, because it kills the process instantly. Another way would be to use SendMessage/PostMessage to send a WM_CLOSE to the main window, unfortunately I don't know anything about the windows of the processes, I only have the process id, so FindWindow doesn't help either. Is there any other way to find the main windows of a process?
In other words:
Is there any way to terminate any process gracefully just like the Windows 7 task manager did when you clicked on "End Task"? (and not "End Process")

EnumWindows enumerates all the top level windows in a process. GetWindowThreadProcessId gets the process and Id of each thread.
You now have enough information to gracefully close any GUI application.
You can send WM_CLOSE messages to any window you wish to close. Many windows handle WM_CLOSE to prompt the user to save documents.You can send a WM_QUIT message using PostThreadMessage to the discovered threads to cause the message loop to terminate.
User code is not allowed to call DestroyWindow from a different app or thread to the windows... if the app does not respond to WM_CLOSE or WM_QUIT requests you're back in TerminateProcess land.
This will not close console applications as the application process, and process that owns the window, are different.
Refer to T.s. Arun's answer below for the correct method for dealing with console applications.

I'm not too sure about the win32 apis but you could shell execute the taskkill command line function.
taskkill /?
taskkill /pid 1230
taskkill /im notepad.exe
The /f switch would force the kill but not using it just sends the termination signal so the application closes gracefully.

See MSKB Q178893 How To Terminate an Application "Cleanly" in Win32. Basically send send WM_CLOSE to all windows of the target app to allow a grace shutdown, before force kill the app with TerminateProcess

To add to Chris Becke answer about terminating gracefully terminating console process.
AttachConsole() to attach to the console application and send control break event, similar to that of pressing CTRL+C in command prompt.
Using GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT,processID).
This control event should be handled in console application for graceful termination.

Use the EndTask API function. It is the same function that is used by task manager.
BOOL EndTask(
HWND hWnd,
BOOL fShutDown,
BOOL fForce
);
http://msdn.microsoft.com/en-us/library/ms633492(VS.85).aspx

You can use taskkill /im your_program.exe to send a termination signal to the application. It will trigger a WM_CLOSE to windows message queue. You can use
Either
https://msdn.microsoft.com/en-us/library/windows/desktop/ms633573(v=vs.85).aspx
or
https://learn.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-getmessage
to process the message.
Please refer a similar answer Win32 API analog of sending/catching SIGTERM

Related

How to keep a user process running until Windows logoff is definite?

I have an application that is running on Windows, in the user's session, that I don't want the user to be able to close by accident.
One way the user can close it is by having unsaved data (e.g. in notepad) and start the process of logging off. Notepad rejects the WM_QUERYSESSION message; Windows prompts the user that there is unsaved data; and the user gets to cancel the logoff.
Other applications (including mine), get the WM_QUERYSESSION, respond with TRUE, then get WM_ENDSESSION, and quit. Importantly, they quit before Windows has even decided to prompt the user about unsaved data in notepad.
If the user cancels the logoff, the end result is that the user's session continues without all the processes that honoured the end session messages.
What I'm trying to find a way of doing is keeping my process running until we're past the point that the user could cancel the logoff. Looking at the microsoft docs on this, I don't see an obvious way of doing that - each process goes through its own WM_QUERYSESSION > WM_ENDSESSION, and the docs are explicit that this happens for each application independently.
I don't want to reply to WM_QUERYSESSION with FALSE, as I don't want to block the logoff myself, just stay running if something else blocks it.
Are there any other ways of finding out when Windows has decided that all the WM_QUERYSESSION messages were replied to with TRUE, and the logoff is inevitable?
(I think this is a Windows question, rather than a question specific to the language I'm using, but in case it matters, it's PureBasic. Any Win32 API approach should be workable though.)
If any app returns FALSE to WM_QUERYENDSESSION, apps that had already returned TRUE will receive WM_ENDSESSION with wParam=FALSE to indicate shutdown has been canceled.
If all apps return TRUE to WM_QUERYENDSESSION, only then will they receive WM_ENDSESSION with wParam=TRUE to indicate shutdown is proceeding.
See Application Shutdown Changes in Windows Vista and Restart Manager: Guidelines for Applications for more details of how WM_QUERYENDSESSION and WM_ENDSESSION work.
Is your app paying attention to the wParam value given by WM_ENDSESSION? Or does it just blindly exit unconditionally when it receives WM_ENDSESSION? Not all apps pay attention like they should be. Make sure yours does.
Update: Per the WM_QUERYENDSESSION documentation, and the Logging Off documentation:
When an application returns TRUE for WM_QUERYENDSESSION, it receives the WM_ENDSESSION message and it is terminated, regardless of how the other applications respond to the WM_QUERYENDSESSION message.
So, there is really nothing your app can do here. Once it responds TRUE to WM_QUERYENDSESSION, that is it, game over. Your app will receive WM_ENDSESSION and be forcibly terminated if it does not exit within a few seconds, regardless of how other apps respond to the shutdown.
So, the only way I can think of to really detect when the session is actually ending is to use a service instead, as a service can receive SERVICE_CONTROL_SHUTDOWN and SERVICE_CONTROL_SESSIONCHANGE notifications.

What is the difference between closing an application and ending the process from Task Manager?

What is the difference between killing an application using the close button and ending the process from the Task Manager?
I am aware of the fact that hitting the close button posts a WM_CLOSE message in the message queue, but I don't know what happens when we kill a process from Task Manager (or any similar application like Killbox or Process Explorer).
When you click the "X" button in the title bar of an application's window, that sends the window a WM_CLOSE message. This is a "graceful" shutdown—the application processes the message, handles any necessary cleanup tasks, and can even refuse to shut down if it so desires (by returning zero in response to the message). WM_CLOSE is simply a request that the window or application terminate; the window is not destroyed until the application itself calls the DestroyWindow function.
When you press the "End Task" button in Task Manager, Windows will first try to send the application (if it is a GUI application) a WM_CLOSE message. In other words, it first asks nicely and gives the app a chance to terminate itself cleanly.*
If you fail to close in response to that initial WM_CLOSE message, the Task Manager will follow up by calling the TerminateProcess function. This function is a little bit different because it forcefully terminates the application's process and all of its threads without asking for permission from the app. This is a very harsh method of closing something, and should be used as a last resort—such as when an application is hung and is no longer responding to messages.
TerminateProcess is a very low-level function that essentially rips the user-mode part of a process from memory, forcing it to terminate unconditionally. Calling TerminateProcess bypasses such niceties as close notifications and DLL_PROCESS_DETACH. Your application does not have the ability to refuse to close, and there is no way to catch/trap/hook calls to TerminateProcess. All user-mode code in the process simply stops running for good. This is a very unclean shut down procedure, somewhat akin to jerking the computer's power plug out of the wall.
* Note that this only true if you use the "Applications" tab of Task Manager to kill the application. If you use the "Processes" tab, this step is skipped and the TerminateProcess function is called immediately. This distinction is reflected in the caption on the respective buttons. For the "Applications" tab, the button is lableled "End Task"; for the "Processes" tab, the button is labeled "End Process".
Killing the process with WM_CLOSE simply signals the process with the message and allows the target to handle the message and exit gracefully. Alternatively, the process could choose not to exit in its WM_CLOSE handler.
Killing the process via task manager will do so with TerminateProcess which is far harsher:
The TerminateProcess function is used to unconditionally cause a
process to exit. The state of global data maintained by dynamic-link
libraries (DLLs) may be compromised if TerminateProcess is used rather
than ExitProcess.
This function stops execution of all threads within
the process and requests cancellation of all pending I/O. The
terminated process cannot exit until all pending I/O has been
completed or canceled. When a process terminates, its kernel object is
not destroyed until all processes that have open handles to the
process have released those handles.
TerminateProcess is asynchronous;
it initiates termination and returns immediately. If you need to be
sure the process has terminated, call the WaitForSingleObject function
with a handle to the process. A process cannot prevent itself from
being terminated.
If you close an application using the close button you let the application to perform necessary closing tasks if any. If you kill a process from task manager there is no chance for application to perform those tasks, you just terminate the application without informing.

Can I handle the killing of my windows process through the Task Manager?

I have a windows C++ application (app.exe). When the app is closed, I need to perform some cleanup tasks specific to my application. What happens when this process (app.exe) is killed through the Task Manager. Assuming that the application is still responsive, can I somehow handle this situation in my app.exe?
I am looking for something similar to how kill <pid> in Linux will send the SIGTERM signal to the process indicated by pid. I could then register my own signal handler for SIGTERM and perform the cleanup.
There are two ways to kill application in Task Manager.
Killing through Applications tab would roughly be equivalent of SIGTERM. Application may intercept it and do more processing, since it's basically sending a "close window" message. Message to catch is WM_CLOSE.
Killing through Processes tab would roughly be equivalent of SIGKILL. There is nothing you can do to intercept that, short of monitoring user's actions in Task Manager's listbox and End Process button, or having a watchdog process that will see when the first one is killed.
Alternatively, design the application in a way that does not require cleanup, or in a way that it will perform cleanup at startup.
I think you will need another PID that is monitoring the PID of your app.exe and does the necessary work at the time.
That depends, if the user chooses to "End Task" your application you will be notified and you can handle it see this.
but if the user chooses to end the process, you have no way to handle it in your application. the easiest way would be a second process or you can inject into process manager and hook the TerminateProcess API.

How would I handle a close request for in a non-windowed application?

I'm working on a C++ Windows application, that runs as a process but not a windowed application (does not have WndProc). It has it's own message loop, which is used to process a quit message, and that's how we safely exit the application from within it's self.
What I want to do is somehow send a message to the process from another process, in order to tell the process to exit safely.
In Linux, we would do this by trapping signals, but I'm not sure how it's done on Windows.
PostThreadMessage can post messages to threads without requiring a window proc.
In the first process, do a GetCurrentThreadId to get a system wide id for the current thread. And somehow get that id to the second app.
In the second app, OpenThread will convert to a thread handle, that you can then use with PostThreadMessage.
Do note that if your 'windowprocless' application ever pops up a message box, the message box enters its own modal message loop, which will silently destroy any thread messages. If any kind of window is ever created on the thread you would be far better off creating an invisible message window that messages can be sent to to control the app.
Do you have the control over both processes i.e., do you have the code of both processes? If yes I suggest to expose a API to exit safely.

How to abort shutdown in Windows (XP|Vista) programatically?

I want to be able to 1. detect (and, if needed 2. abort) OS shutdown from my application, preferably by using the Windows API.
I know that it is possible to abort shutdown manually using the command shutdown -a In the worst case, I could ShellExecute this, but I was wondering if there was a better way to prevent the shutdown programatically.
Maybe it would be enough to be notified programatically that the OS is about to shut down - how to do this?
From MSDN:
The WM_QUERYENDSESSION message is sent when the user chooses to end the session or when an application calls one of the system shutdown functions. If any application returns zero, the session is not ended. The system stops sending WM_QUERYENDSESSION messages as soon as one application returns zero.
So, my application's WindowProc now processes the WM_QUERYENDSESSION message and returns 0.
Didn't expect it to be this simple; as a bonus, it also works on Windows 2000.
In regards to 'simply' returning 0 to block a shutdown, it isn't as simple as that if you want to do it in the proper way. Especially on Vista. For example please also read http://msdn.microsoft.com/en-us/library/ms700677(VS.85).aspx

Resources