停止 Ctrl + C 向上传播

问题描述 投票:0回答:1

我有一个程序正在运行(我们称之为 A),在这个程序中,我从 NodeJs 调用

child_process
来运行另一个应用程序(我们称之为 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

欢迎提供任何解决方案或建议。

NB:我尝试分配一个处理程序,而不是一个处理程序,但这也不起作用。

c++ node.js windows winapi nt
1个回答
0
投票

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

您应该使用

TerminateProcess
通过其句柄来终止子进程 C,而不是通过发送
CTRL+C
事件,这样您的进程
A
不会受到影响,不用说这会阻止
C
执行此操作任何资源清理,所以要小心。

另一种选择是在单独的新终端中启动

B
C
,这样
CTRL+C
会被发送到仅包含
B
C
的终端,因此
A
将不受影响。

© www.soinside.com 2019 - 2024. All rights reserved.