2

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

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

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

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

谢谢,克里希纳

4

2 回答 2

7

一般来说,当一个进程被列为“应用程序”时,这意味着任务管理器已经检测到该进程有一个 GUI,GUI 上的“结束任务”将首先尝试通过标准WM_CLOSE和/或WM_QUIT消息优雅地关闭 GUI然后通过TerminateProcess(). 另一方面,对“后台进程”执行“结束任务”将立即执行蛮力终止。

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

于 2013-08-27T01:34:21.807 回答
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中并注入到Task Maneger进程中,没有测试它。但这种方法过于繁琐且不安全,某些 AV 产品可能会将其检测为有害程序。

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

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

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

于 2013-08-27T03:40:30.500 回答