44

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

Daniel Rikowski
  • 68,943
  • 56
  • 245
  • 321
  • I assume that "Tasks" are top level (visible) windows. So, the `WM_CLOSE` will be sent (probably) on terminate task. – Nick Dandoulakis Jan 13 '10 at 10:45
  • 1
    If you're not a software developer — just a Windows user — see [the related Super User question on how to gracefully ask a running application to terminate](http://superuser.com/questions/959364/on-windows-how-can-i-gracefully-ask-a-process-to-terminate). – unforgettableidSupportsMonica Aug 19 '15 at 02:33
  • 1
    Note that, as of Windows 8.1, Task Manager's "End Task" button now forcibly terminates the chosen application and causes you to lose any unsaved work. You might want to edit your question in order to reflect this. – unforgettableidSupportsMonica Aug 20 '15 at 12:44

6 Answers6

30

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.

Chris Becke
  • 32,340
  • 12
  • 75
  • 142
  • When I have all the windows of the process, do I send a `WM_CLOSE` to each top-level window? – Daniel Rikowski Jan 13 '10 at 10:08
  • Exactly what I was about to say. +1. – j_random_hacker Jan 13 '10 at 10:09
  • 2
    Yes - TaskManager sends a `WM_CLOSE` message to the app. Actually I think it might send a `WM_SYSCOMMAND`, `SC_CLOSE` message. – Chris Becke Jan 13 '10 at 13:13
  • 5
    Does this work to close the process without windows i.e. console ones? – rpattabi Feb 06 '12 at 14:10
  • 3
    What if process doesn't have any window? Let's say it is background driver monitoring task, having an icon in the tray. What if we develop that process ourselves, which means other than sending WM_CLOSE to a window do we have in Windows API? Is the only way to use Windows Sockets? – blackbada_cpp Mar 29 '16 at 08:54
  • FarManager (which is a popular console app) apparently has a special window to handle such events: https://github.com/FarGroup/FarManager/blob/0871bcdcbb7ca8dcbb6155edfbd5a5d426e5cccd/far/wm_listener.cpp#L53 Windows Sockets is a bad idea, use named events - https://docs.microsoft.com/en-us/windows/desktop/api/synchapi/nf-synchapi-createeventw (with a non-null lpname). Commonly a GUID is used for such event names. – nponeccop Jun 29 '18 at 15:30
21

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.

Andy E
  • 326,646
  • 82
  • 467
  • 441
  • 5
    Unfortunately this is only available on Windows XP Professional or newer. (Not even XP home), but I need that functionality for Windows 2000 and XP Home, too. But I'd love to see the source code of that tool :) – Daniel Rikowski Jan 13 '10 at 10:09
14

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

Sheng Jiang 蒋晟
  • 14,937
  • 2
  • 27
  • 45
  • +1. Overlaps a lot with Chris Becke's solution, plus describes handling corner cases with 16-bit apps. Nice. – j_random_hacker Jan 15 '10 at 02:57
  • 12
    You should also write some of the content here in case the page will be down/moved. – MasterMastic Apr 02 '13 at 14:58
  • Link only answers are not good answers. Please do as MasterMastic suggested and put the substantive content in this answer. – rory.ap Jan 08 '18 at 17:17
  • 3
    Link is currently down. – owacoder Jan 22 '20 at 19:51
  • I believe the license on MSKB code is unclear, so you wouldn't be allowed to post it here. (because SO posts are licensed under CC BY-SA 4.0 currently) However here is an archive link of the content that works: https://web.archive.org/web/20150221153350/https://support.microsoft.com/kb/178893 – WebFreak001 May 05 '21 at 06:22
6

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.

Developer Guy
  • 2,198
  • 6
  • 18
  • 34
T.s. Arun
  • 179
  • 3
  • 15
  • Here is an example of a practical implementation for this technique (C#): https://github.com/gapotchenko/Gapotchenko.FX/blob/1accd5c03a310a925939ee55a9bd3055dadb4baa/Source/Gapotchenko.FX.Diagnostics.Process/ProcessExtensions.End.cs#L247-L328 – ogggre Mar 29 '19 at 05:34
3

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

Jason
  • 2,301
  • 17
  • 14
  • 11
    The very first line of text in that page says: *[This function is not intended for general use. It may be altered or unavailable in subsequent versions of Windows.]*. Maybe the upvoters didn't click through? – Jon Jun 26 '11 at 22:59
  • 4
    @Jon many api's have that hint but many problems cannot be resolved without using them. The same applies to "undocumented" ones. (i'm not saying this is one of such cases) – Mauro H. Leggieri Oct 17 '14 at 12:02
  • Task manager does not use EndTask. Instead it's a rather complicated code that try first to close process gracefully by sending messages, and later call TerminateProcess() as last resort. – tigrou May 05 '22 at 20:06
0

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://docs.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

amilamad
  • 452
  • 6
  • 9