代码之家  ›  专栏  ›  技术社区  ›  Maifee Ul Asad

停止Ctrl+C向上传播

  •  -1
  • Maifee Ul Asad  · 技术社区  · 1 年前

    我有一个程序正在运行( 我们称之为A ),在里面,我打电话 child_process 从NodeJ运行另一个应用程序( 让我们称之为C )。现在我不能改变它的结构,因为我们已经在这个模式中实现了很多功能。因此,任何调整都可能导致管道破裂。

    现在我想使用CTRL+C终止那个C应用程序。由于这是一个二进制文件,我无法修改源代码,所以我需要向该程序发送Ctrl+C。我正在做这件事,它很高兴地结束了。

    现在的问题是,它正在杀死C 以及A。 所以这是目前的主要问题。我尝试创建另一个中间程序 B 。但是它终止了C,然后终止了B,最后终止了A。所以Ctrl+C向上传播。如何防止Ctrl+C向上传播?

    伪代码如下:

    FUNCTION SigintWindows(args):
    
            INITIALIZE isolate from args
            Create new handle scope with isolate
    
            GET processId from args[0]
    
            OPEN process with processId If fails:
                THROW Error("Failed to open process Error code: " + error code)
                EXIT
    
            TRY attaching to console If fails:
                THROW Error("Failed to attach to console Error code: " + error code)
                TRY sending Ctrl-C event directly If fails:
                    THROW Error("Failed to send Ctrl-C event Error code: " + error code)
                    CLOSE process handle
                    EXIT
                ELSE:
                    SET return value to true
                    EXIT
            ELSE:
                DISABLE Ctrl-C handling for our program If fails:
                    THROW Error("Failed to disable Ctrl-C handling Error code: " + error code)
                    CLOSE process handle
                    EXIT
    
                SEND Ctrl-C event If fails:
                    THROW Error("Failed to send Ctrl-C event Error code: " + error code)
    
                    RE-ENABLE Ctrl-C handling If fails:
                        THROW Error("Failed to re-enable Ctrl-C handling Error code: " + error code)
    
                    FREE the console
                    CLOSE process handle
                    EXIT
    
                ELSE:
                    WAIT for the process to exit (max 2 seconds) If process doesn't exit:
                        THROW Error("Process did not exit within 2 seconds")
    
                    RE-ENABLE Ctrl-C handling If fails:
                        THROW Error("Failed to re-enable Ctrl-C handling Error code: " + error code)
    
                    FREE the console
                    CLOSE process handle
                    EXIT
    
            END IF
    
            RE-ENABLE Ctrl-C handling If fails:
                THROW Error("Failed to re-enable Ctrl-C handling")
                CLOSE process handle
                EXIT
    
            FREE the console
            CLOSE process handle
            SET return value to true
    

    下面是整个C++实现:

    #include <node.h>
    #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
      #include <windows.h>
    #endif
    
    namespace ctrlc {
    
      using v8::FunctionCallbackInfo;
      using v8::Isolate;
      using v8::Local;
      using v8::Object;
      using v8::String;
      using v8::Value;
    
      void SigintWindows(const v8::FunctionCallbackInfo < v8::Value > & args) {
        #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
          v8::Isolate * isolate = args.GetIsolate();
          v8::HandleScope scope(isolate);
    
          // Check the number of arguments passed
          if (args.Length() != 1) {
            v8::Local < v8::String > v8String = v8::String::NewFromUtf8(isolate, "Invalid arguments").ToLocalChecked();
            isolate -> ThrowException(v8::Exception::TypeError(v8String));
    
            return;
          }
    
          // Check the argument types
          if (!args[0] -> IsUint32()) {
            v8::Local < v8::String > v8String = v8::String::NewFromUtf8(isolate, "Argument must be a number").ToLocalChecked();
            isolate -> ThrowException(v8::Exception::TypeError(v8String));
    
            return;
          }
    
          DWORD processId = args[0] -> Uint32Value(isolate -> GetCurrentContext()).ToChecked();
    
          HANDLE hProcess = OpenProcess(SYNCHRONIZE | PROCESS_TERMINATE, FALSE, processId);
          if (hProcess == NULL) {
            v8::Local<v8::String> v8String = v8::String::NewFromUtf8(isolate, ("Failed to open process. Error code: " + std::to_string(GetLastError())).c_str()).ToLocalChecked();
            isolate->ThrowException(v8::Exception::Error(v8String));
    
            return;
          }
    
          // Try to attach to console
          if (!AttachConsole(processId)) {
            v8::Local<v8::String> v8String = v8::String::NewFromUtf8(isolate, ("Failed to attach to console. Error code: " + std::to_string(GetLastError())).c_str()).ToLocalChecked();
            isolate->ThrowException(v8::Exception::Error(v8String));
    
            // If attaching to console fails, try sending Ctrl-C event directly
            if (!GenerateConsoleCtrlEvent(CTRL_C_EVENT, processId)) {
              v8::Local<v8::String> v8String = v8::String::NewFromUtf8(isolate, ("Failed to send Ctrl-C event. Error code: " + std::to_string(GetLastError())).c_str()).ToLocalChecked();
              isolate->ThrowException(v8::Exception::Error(v8String));
    
              CloseHandle(hProcess);
    
              return;
            } else {
              args.GetReturnValue().Set(true);
              return;
            }
          } else {
            // Disable Ctrl-C handling for our program
            if (!SetConsoleCtrlHandler(NULL, TRUE)) {
              v8::Local<v8::String> v8String = v8::String::NewFromUtf8(isolate, ("Failed to disable Ctrl-C handling. Error code: " + std::to_string(GetLastError())).c_str()).ToLocalChecked();
              isolate->ThrowException(v8::Exception::Error(v8String));
    
              CloseHandle(hProcess);
    
              return;
            }
    
            // Send Ctrl-C event
            if (!GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0)) {
              v8::Local<v8::String> v8String = v8::String::NewFromUtf8(isolate, ("Failed to send Ctrl-C event. Error code: " + std::to_string(GetLastError())).c_str()).ToLocalChecked();
              isolate->ThrowException(v8::Exception::Error(v8String));
    
              // Re-enable Ctrl-C handling
              if (!SetConsoleCtrlHandler(NULL, FALSE)) {
                v8::Local<v8::String> v8String = v8::String::NewFromUtf8(isolate, ("Failed to re-enable Ctrl-C handling. Error code: " + std::to_string(GetLastError())).c_str()).ToLocalChecked();
                isolate->ThrowException(v8::Exception::Error(v8String));
              }
    
              FreeConsole();
              CloseHandle(hProcess);
              return;
            } else {
              // Wait for process to exit
              if (WaitForSingleObject(hProcess, 2000) != WAIT_OBJECT_0) {
                v8::Local<v8::String> v8String = v8::String::NewFromUtf8(isolate, "Process did not exit within 2 seconds.").ToLocalChecked();
                isolate->ThrowException(v8::Exception::Error(v8String));
              }
    
              // Re-enable Ctrl-C handling
              if (!SetConsoleCtrlHandler(NULL, FALSE)) {
                v8::Local<v8::String> v8String = v8::String::NewFromUtf8(isolate, ("Failed to re-enable Ctrl-C handling. Error code: " + std::to_string(GetLastError())).c_str()).ToLocalChecked();
                isolate->ThrowException(v8::Exception::Error(v8String));
              }
    
              FreeConsole();
              CloseHandle(hProcess);
              return;
            }
          }
    
          // Re-enable Ctrl-C handling
          if (!SetConsoleCtrlHandler(NULL, FALSE)) {
            v8::Local<v8::String> v8String = v8::String::NewFromUtf8(isolate, "Failed to re-enable Ctrl-C handling").ToLocalChecked();
            isolate->ThrowException(v8::Exception::Error(v8String));
    
            CloseHandle(hProcess);
            
            return;
          }
    
          FreeConsole();
          CloseHandle(hProcess);
          args.GetReturnValue().Set(True(isolate));
        #endif
      }
    
      void Init(Local < Object > exports) {
        NODE_SET_METHOD(exports, "sigintWindows", SigintWindows);
      }
    
      NODE_MODULE(ctrlc, Init)
    
    } // namespace ctrlc
    

    请随时提供任何解决方案或建议。

    注意:我试过分配一个处理程序,而不是“无”,但这也不起作用。

    1 回复  |  直到 1 年前
        1
  •  0
  •   Ahmed AEK    1 年前

    CTRL+C 信号由终端发送,并由所有进程接收 A B C D 同时连接到该终端。

    你应该终止子进程 C 通过其手柄使用 TerminateProcess ,而不是通过发送 CTRL+C 事件,这样您的流程 A. 不受影响,不用说这会阻止 C 不要做任何资源清理,所以要小心。

    另一种选择是启动 B C 在一个单独的新终端中,通过这种方式 CTRL+C 发送到仅包含 B C 因此 A. 将不受影响。

        2
  •  0
  •   YangXiaoPo-MSFT    1 年前

    HandlerRoutine 说,

    因为系统在进程中创建了一个新线程来执行 处理程序函数,。。。

    每个控制台进程都有自己的HandlerRouine函数列表。 最初,此列表只包含一个默认的处理程序函数 调用ExitProcess。控制台进程添加或删除附加 处理程序函数,方法是调用SetConsoleCtrlHandler函数 不会影响其他进程的处理程序函数列表。

    一般来说,您需要目标进程执行一段特定的代码 ExitProcess 在这种情况下。在 HandlerRoutine , @RbMm indicated a way 打电话 CreateRemoteThread 在目标进程中,入口点位于 CtrlRoutine CTRL_C_EVENT 作为参数。

    推荐文章