如何从后台进程的Windows任务pipe理器中处理“结束任务”?

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

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

2)当我打开一个命令提示符并启动TestProgram.exe时,它被列在“任务pipe理器”下的“后台进程”下,同样做一个“结束任务”不会导致CTRL_CLOSE_EVENT。

我的真实应用程序按照上面情况2)中的描述使用。 当用户对我的应用程序执行结束任务时(我在任务pipe理器中的后台进程下列出),我想做一些清理。

谢谢你,克里希纳

通常,当一个进程被列为“应用程序”时,这意味着任务管理器已经检测到该进程有一个GUI,并且GUI上的“结束任务”将首先尝试通过标准的WM_CLOSE和/或WM_QUIT然后再通过TerminateProcess()方法强制终止GUI的进程。 另一方面,在“后台进程”上执行“结束任务”将立即执行强力终止。

所以在你的情况下,双击.exe文件会产生一个新的专门的控制台进程,它本身只运行你的应用程序,所以控制台的GUI被标记为“应用程序”,但是当你首先打开一个控制台窗口,通过命令行执行.exe,你的应用程序在现有的控制台中运行,并共享控制台的原始GUI,所以你的应用程序没有自己的GUI,因此被标记为“后台进程”。

当一个进程被终止(不关闭)时,除非你开始做一些钩子,否则在任务管理器进程中钩住TerminateProcess或者NtTerminateProcess ,它是如何工作的:

 #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 hmodulee; 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中,并将它注入到Task Maneger进程中,而不是测试它。 但是这种方法过度而不安全,有些AV产品可能会将其视为有害的程序。

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

在下一次启动时,如果它仍然是0 ,则检查该值,这意味着程序没有正确关闭,请做清理,如果是1 ,则不需要清理,存储0并继续。

许多程序使用这种方法来检测程序是否被正确关闭。