2

I wrote a simple test program (TestProgram.exe) to learn how to handle the CTRL_CLOSE_EVENT and here are my observations and my question:

1) When I double click TestProgram.exe to launch it, and if I now go to Task Manager, TestProgram.exe is listed under "Apps". When I do "End Task" on TestProgram.exe, my handler for CTRL_CLOSE_EVENT is getting called.

BUT

2) When I open a command prompt and launch TestProgram.exe, it is listed under "Background Processes" under Task Manager and doing an "End Task" on the same doesn't result in a CTRL_CLOSE_EVENT.

My real application is used as described in case 2) above. I want to do some cleanup when users do an End Task on my app (which is listed under Background processes in Task Manager).

Thanks, Krishna

Krishna
  • 145
  • 1
  • 11
  • 1
    Which version of Windows? – Preet Sangha Aug 26 '13 at 23:46
  • 2
    Can you do the cleanup on app restart? In general, if the user kills your app from the task manager, it's dead. Nothing else is acceptable for security - users with sufficient privelege MUST be able to stop apps without notification. – Martin James Aug 27 '13 at 00:13
  • I understand. But I read somewhere that apps were given some time, ~10 seconds to do any necessary cleanup. Also, as I originally mentioned, why am I able to handle it in case 1 but not case 2 above? – Krishna Aug 27 '13 at 00:39

2 Answers2

7

In general, when a process is listed as an "Application", it means Task Manger has detected the process has a GUI, and an "End Task" on a GUI will first attempt to graceful close the GUI via standard WM_CLOSE and/or WM_QUIT messages before then resorting to a brute-force termination of the GUI's process via TerminateProcess(). On the other hand, doing an "End Task" on a "Background Process" will perform a brute-force termination immediately.

So in your situation, double-clicking on the .exe file results in a new dedicated console process that is running just your app by itself, so the console's GUI gets flagged as an "Application", but when you open a console window first and execute your .exe via the command-line, your app is running within the existing console and is sharing the console's original GUI, so your app does not have its own GUI and thus gets flagged as a "Background Process" instead.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
2

When a process is terminated (not closed) nothing realy can be done unless you start do some hooking, either by hooking TerminateProcess or NtTerminateProcess in the Task Manger process, example of how it works:

#include <windows.h>
#include <assert.h>

BOOL WINAPI MyTerminateProcess(HANDLE hProcess, UINT uExitCode ) {
    MessageBox(NULL, TEXT("Do some cleanup"), NULL, MB_OK);
    ExitProcess(0);
    return TRUE;
}

#pragma pack(1)
typedef struct __PATCHDATA {
    BYTE push;
    DWORD address;
    BYTE ret;
} PATCHDATA;
#pragma pack()

int main(int argc, char **argv) {
    HMODULE hModule;
    DWORD written;
    // This struct contains assembly instruction that do:
    //  push address ; 0x68 MyTerminateProcess
    //  ret          ; 0xc3
    // so the execution will return to our hook
    PATCHDATA patch = {0x68, (DWORD) MyTerminateProcess, 0xc3};

    // remove this code, the program will terminate itself.
    // TODO: check the memory protection and modify it.
    WriteProcessMemory(GetCurrentProcess(),
                       TerminateProcess,
                       &patch,
                       sizeof(PATCHDATA),
                       &written);

    TerminateProcess(NULL, 0);

    return 0;
}

This hooks TerminateProcess in the same process, you need to ship it in a DLL and inject it in the Task Maneger process, didn't test it. But this method is overwork and not safe, some AV products may detect it as harmful program.

A simple solution is to clean up on the program start-up as @Martin James suggested. On your program start-up create a file or use the registry to store some value like 0, if the program was closed, received WM_CLOSE if it's GUI or CTRL_CLOSE_EVENT if you closed the command prompt, you do the clean-up and store 1.

On the next start-up you you check back that value if it stills 0, this mean do the program was not closed properly, do do the clean up, if it's 1 no need to the clean-up, store 0 and move on.

Many programs use this method to detect if the program was closed properly.

  • Thanks so much! Very useful response. One question though about your code to hook TerminateProcess. How did you choose the addresses 0x68 and 0xc3? – Krishna Aug 27 '13 at 04:51
  • @KrisRetroVirus These are not address, they opcode of assembly instructions, spicily [push imm = 0x68](http://ref.x86asm.net/coder32.html#x68) and [retn = 0xc3](http://ref.x86asm.net/coder32.html#xC3). –  Aug 27 '13 at 05:23
  • Aah! Please excuse my ignorance. – Krishna Aug 27 '13 at 22:20
  • Interesting. Unfortunately, the handler is not invoked when ending the task via task manager. At least not in my little console test application. Apparently something other than TerminateProcess is used in that case. – Simpleton Jan 16 '20 at 12:11