Despite the fact that using GenerateConsoleCtrlEvent()
for sending Ctrl+C signal is the right answer, it needs significant clarification to get it to work in different .NET application types.
如果您的 .NET 应用程序不使用自己的控制台(Windows Forms/WPF/Windows Service/ASP.NET),则基本流程是:
- Attach the main .NET process to the console of the process that you want to signal with Ctrl+C.
- Prevent the main .NET process from stopping because of Ctrl+C event by disabling handling of the signal with
SetConsoleCtrlHandler()
.
- 生成控制台事件current控制台与
GenerateConsoleCtrlEvent()
(processGroupId
应该为零!带有发送代码的答案p.SessionId
将不起作用并且不正确)。
- 等待发出信号的进程响应(例如等待它退出)
- Restore Ctrl+C handling by main process and disconnect from console.
以下代码片段说明了如何执行此操作:
Process p;
if (AttachConsole((uint)p.Id)) {
SetConsoleCtrlHandler(null, true);
try {
if (!GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0))
return false;
p.WaitForExit();
} finally {
SetConsoleCtrlHandler(null, false);
FreeConsole();
}
return true;
}
where SetConsoleCtrlHandler()
, FreeConsole()
, AttachConsole()
and GenerateConsoleCtrlEvent()
是本机 WinAPI 方法:
internal const int CTRL_C_EVENT = 0;
[DllImport("kernel32.dll")]
internal static extern bool GenerateConsoleCtrlEvent(uint dwCtrlEvent, uint dwProcessGroupId);
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern bool AttachConsole(uint dwProcessId);
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
internal static extern bool FreeConsole();
[DllImport("kernel32.dll")]
static extern bool SetConsoleCtrlHandler(ConsoleCtrlDelegate HandlerRoutine, bool Add);
// Delegate type to be used as the Handler Routine for SCCH
delegate Boolean ConsoleCtrlDelegate(uint CtrlType);
Note that waiting for the targeted process to respond, typically by waiting for the process to exit, is critical. Otherwise, the Ctrl+C signal will remain in the current process's input queue and when handling is restored by the second call to SetConsoleCtrlHandler()
, that signal will terminate the current process, rather than the targeted one.
Things become more complex if you need to send Ctrl+C from .NET console application. The above approach will not work because AttachConsole()
returns false
in this case (the main console app already has a console). It is possible to call FreeConsole()
before AttachConsole()
call, but doing so will result in the original .NET app console being lost, which is not acceptable in most cases.
这是我针对这种情况的解决方案;它可以工作并且对 .NET 主进程控制台没有副作用:
- Create small supporting .NET console program that accepts process ID from command line arguments, loses its own console with
FreeConsole()
before the AttachConsole()
call and sends Ctrl+C to the target process with code mentioned above.
- The main .NET console process just invokes this utility in a new process when it needs to send Ctrl+C to another console process.
- In the main .NET console process call
SetConsoleCtrlHandler(null, true)
before spawning the "killer"-process (from step 1) and SetConsoleCtrlHandler(null, false)
after. Else your main process will also receive Ctrl+C and die