【发布时间】:2015-06-12 10:00:19
【问题描述】:
我正在尝试将基本的 Windows 进程功能包装在进程类中。 我希望进程在父进程的同一个进程组和同一个控制台中运行,并且我想在调用 Process::Kill(); 时轻轻地杀死它们;
从各种来源阅读,我最终得到了这段代码,它首先检查进程是否是 GUI,如果是则发送 WM_CLOSE(EnumChildWindowsHandler 执行),如果不是,并且进程有控制台,则发送CTRL_C 事件。它可以工作,但是当子进程是“cmd.exe”时,该过程在 GenerateConsoleCtrlEvent 函数上崩溃,并且调试器说发生了写入访问冲突。
有什么意义?我在阅读中没有理解什么?
bool Process::Kill( ) {
// Here I check if the process is a GUI app
if (!EnumThreadWindows(mChildInfo->dwThreadId, EnumChildWindowsHandler, mChildInfo->dwProcessId)) {
if (WaitForSingleObject(mChildInfo->hProcess, 2000) == WAIT_TIMEOUT) {
{ TerminateProcess(mChildInfo->hProcess, 0); } }
//If not, test if it's a CUI then send CTRL_C
else {
int minPid = 10;
int els;
unsigned long *pids = new unsigned long(minPid);
els = GetConsoleProcessList( pids, minPid );
if (els > minPid) {
free (pids);
pids = new unsigned long(els);
els = GetConsoleProcessList(pids, els);
}
if (find(pids, pids+els, mChildInfo->dwProcessId)) {
cout << "Sending CTRL_C_EVENT.." << endl;
SetConsoleCtrlHandler(NULL, TRUE);
GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
if (WaitForSingleObject(mChildInfo->hProcess, 2000) == WAIT_TIMEOUT) { TerminateProcess(mChildInfo->hProcess, 0); }
SetConsoleCtrlHandler(NULL, FALSE);
CloseHandle(mChildInfo->hProcess);
CloseHandle(mChildInfo->hThread);
}
return true;
}
编辑:我找到了 ReactOS cmd.exe 源代码,它是这类事情的黄金。我将发布我最终学到的更新。 网址:http://doxygen.reactos.org/db/d4f/base_2shell_2cmd_2cmd_8c_source.html
【问题讨论】:
-
我无法重现该错误,但 cmd.exe 控制处理程序
cmd!Handler通常会忽略CTRL+C和CTRL+BREAK,除非在运行批处理文件时。在后一种情况下,它会显示提示符"Terminate batch job (Y/N)?"。在您的情况下,cmd 是使用交互式命令提示符、单个/c命令运行还是执行批处理文件?顺便说一句,除非手动启用,否则进程组(即CREATE_NEW_PROCESS_GROUP)已禁用CTRL+C,因此使用CTRL_BREAK_EVENT会更可靠。但是您需要在自己的进程中设置一个忽略CTRL+BREAK的实际处理程序。 -
如果您确实使用
CREATE_NEW_PROCESS_GROUP创建子进程,您应该只为子进程的 PID 生成事件,它兼作进程组 ID。这样,只有子进程及其创建的任何控制台进程才能看到该事件。如果它连接到同一个控制台,则为组 0 生成事件甚至会将其发送到您自己的父进程。这可能会产生意想不到的后果。 -
子进程只是在父控制台中运行的“cmd.exe”的一个实例,不会创建新组(因为组阻止发送 CTRL_C)。也许我应该看看 GenerateConsoleInput。或者我可以在新控制台中运行每个程序,将流重定向到我的控制台,然后将 CTRL_C 发送到分离的进程。顺便说一句,我没有找到关于 CTRL_C 和 CTRL_BREAK 差异的很好解释,最后一个应用程序是否也会轻轻终止?
-
一个进程有一个默认的控制事件处理程序
kernel32!DefaultHandler,它调用ExitProcess。在这种情况下,将使用DLL_PROCESS_DETACH调用 DLL 入口点,因此例如,将调用 CRTatexit函数。也就是说,一个进程可以链接多个事件处理程序,而不必链接到默认处理程序。例如,CRT 安装一个处理程序,用于为CTRL+C和CTRL+BREAK事件引发SIGINT和SIGBREAK。
标签: c++ windows process console signals