我正在尝试将基本的 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 源代码很好地解释了如何正确执行操作,顺便说一句,我只是使用 CTRL_BREAK 并且效果很好。在创建过程中,我传递了 CREATE_NEW_PROCESS_GROUP 并为 showWindow 模式设置了 SW_SHOWDEFAULT,然后我以这种方式终止进程:
//Determine if lParam has for main window the hWnd, and send WM_CLOSE
int CALLBACK EnumChildWindowsHandler(HWND hWnd, LPARAM lParam)
{
//WORD type
unsigned long pid = 0;
GetWindowThreadProcessId(hWnd, &pid);
if (pid == (unsigned long) lParam) {
cout << "HANDLEWIN: " << hWnd << " Bwehe" << endl;
cout << "PID: " << pid << endl;
if (!GetParent(hWnd)) PostMessageA(hWnd, WM_CLOSE, 0, 0);
return 0;
}
return 1;
}
bool Process::KillGently( ) {
if (EnumThreadWindows(mProcInfo->dwThreadId, EnumChildWindowsHandler, mProcInfo->dwProcessId)) {
if (!GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, mProcInfo->dwProcessId))
cerr << "Error while sending CTRL_BREAK_EVENT: " << GetLastError() << endl;
}
此外,如果我们想在处理信号时以类似于 cmd 的方式进行操作,我们可以像这样注册一个 sighandler(我们仍然需要 WriteConsoleInput):
BOOL signal_handler(DWORD signum) {
INPUT_RECORD iRecord;
if (signum != CTRL_C_EVENT && signum != CTRL_BREAK_EVENT ) return FALSE;
if(!TryEnterCriticalSection(&mChildRunningLock)) {
GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, mChild.mProcInfo->dwProcessId);
mIsBreakHandled = true;
return TRUE;
}
else LeaveCriticalSection(&mChildRunningLock);
iRecord.EventType = KEY_EVENT;
iRecord.Event.KeyEvent.bKeyDown = TRUE;
iRecord.Event.KeyEvent.wRepeatCount = TRUE;
iRecord.Event.KeyEvent.wVirtualKeyCode = _T('C');
iRecord.Event.KeyEvent.wVirtualScanCode = _T('C') - 35;
iRecord.Event.KeyEvent.uChar.AsciiChar = _T('C');
iRecord.Event.KeyEvent.uChar.UnicodeChar = _T('C');
iRecord.Event.KeyEvent.dwControlKeyState = RIGHT_CTRL_PRESSED;
WriteConsoleInputA(GetStdHandle(STD_INPUT_HANDLE), &iRecord, 1, 0);
mIsBreakHandled = true;
return TRUE;
}
主线程在等待刚刚启动的进程终止时进入临界区。
顺便说一句,我仍然不知道为什么我的应用程序会因之前的代码而崩溃。
关于c++ - 子进程为 cmd 时 GenerateConsoleCtrlEvent 崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30800340/