如何在后台进程上从Windows任务管理器处理“结束任务”?

时间:2013-08-26 23:39:51

标签: c++ c windows

我写了一个简单的测试程序(TestProgram.exe)来学习如何处理CTRL_CLOSE_EVENT,这是我的观察和我的问题:

1)当我双击TestProgram.exe启动它时,如果我现在转到任务管理器,TestProgram.exe列在“应用程序”下。当我在TestProgram.exe上执行“结束任务”时,我的CTRL_CLOSE_EVENT处理程序被调用。

BUT

2)当我打开命令提示符并启动TestProgram.exe时,它在“任务管理器”下的“后台进程”下列出,并且对其执行“结束任务”不会产生CTRL_CLOSE_EVENT。

我的真实应用程序如上面的案例2)中所述使用。当用户在我的应用程序上执行结束任务时(我在任务管理器中的后台进程下列出),我想做一些清理工作。

谢谢, 克里希纳

2 个答案:

答案 0 :(得分:7)

通常,当一个进程被列为“应用程序”时,它意味着任务管理器已检测到该进程具有GUI,并且GUI上的“结束任务”将首先尝试通过标准{{优雅地关闭GUI 1}}和/或WM_CLOSE消息之前通过WM_QUIT求助于GUI进程的暴力终止。另一方面,在“后台进程”上执行“结束任务”将立即执行暴力终止。

因此,在您的情况下,双击.exe文件会导致新的专用控制台进程自动运行您的应用程序,因此控制台的GUI会被标记为“应用程序”,但是当您打开控制台时首先是窗口并通过命令行执行.exe,您的应用程序在现有控制台中运行并共享控制台的原始GUI,因此您的应用程序没有自己的GUI,因此被标记为“后台进程”。

答案 1 :(得分:2)

当一个进程终止(未关闭)时,除非你通过在任务管理器进程中挂钩TerminateProcessNtTerminateProcess开始做一些挂钩,否则无法进行任何操作,例如它是如何工作的:

#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;
}

这在同一进程中挂钩TerminateProcess,你需要在DLL中发送它,并在任务Maneger进程中inject,没有测试它。但是这种方法过度劳累并且不安全,有些AV产品可能会将其视为有害程序。

一个简单的解决方案是清理程序启动,正如@Martin James建议的那样。在程序启动时创建文件或使用注册表存储一些值,如0,如果程序已关闭,如果是GUI则收到WM_CLOSE,如果关闭命令则收到CTRL_CLOSE_EVENT提示,您进行清理并存储1

在下次启动时,你会检查该值是否仍为0,这意味着程序未正确关闭,请进行清理,如果1没有必要清理,存储0并继续前进。

许多程序使用此方法来检测程序是否已正确关闭。