c++ - 子进程为 cmd 时 GenerateConsoleCtrlEvent 崩溃

标签 c++ windows process console signals

我正在尝试将基本的 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/

相关文章:

c++ - 模板转换函数到 const-reference

c# - 如何判断 X.509 证书是否可导出?

c - RPC windows获取客户端IP地址

objective-c - 使用 getrusage

c++ - 在 C++ 中迭代对象数组

c++ - 我想用迭代器的方式做一个循环,但是有一个错误

c++ - 连接两个 Box2d 实体

windows - 系统找不到指定的路径 - 批处理文件

java - 按进程划分的浏览器关闭事件

python - 如何在twisted python中获取spawn进程的状态?