我有一个程序正在运行(我们称之为 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:我尝试分配一个处理程序,而不是一个处理程序,但这也不起作用。
CTRL+C
信号由终端发送,并由所有进程同时接收A
B
C
和D
连接到该终端。
您应该使用
TerminateProcess通过其句柄来终止子进程
C
,而不是通过发送 CTRL+C
事件,这样您的进程 A
不会受到影响,不用说这会阻止 C
执行此操作任何资源清理,所以要小心。
另一种选择是在单独的新终端中启动
B
和 C
,这样 CTRL+C
会被发送到仅包含 B
和 C
的终端,因此 A
将不受影响。