当子进程为cmd

时间:2015-06-12 10:00:20

标签: c++ windows process console signals

我试图在Process Class中包装基本的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

1 个答案:

答案 0 :(得分:1)

cmd源代码很好地解释了如何正确操作,顺便说一句,我只是使用CTRL_BREAK并且像魅力一样工作。在创建过程中,我传递CREATE_NEW_PROCESS_GROUP并为showWindow模式设置SW_SHOWDEFAULT,然后以这种方式终止进程:

private <T extends Instantiable> List<T> getEntityList(Class<T> entityType, int numberOfItems) throws Exception {
    List<T> entities = new ArrayList<T>();

    for (int i = 0; i < numberOfItems; i++) {
        Constructor<T> ctor = entityType.getConstructor();
        entities.add(ctor.newInstance());
    }

    return entities;
}

另外,如果我们想在处理信号时以类似方式执行操作,我们可以像这样注册一个sighandler(我们仍然需要WriteConsoleInput):

//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;
  }

主线程在等待刚刚开始的进程终止时进入临界区。

BTW我仍然不知道为什么我的应用程序崩溃了之前的代码。