尽管使用GenerateConsoleCtrlEvent()
for 发送Ctrl+C信号是正确的答案,但需要大量澄清才能使其在不同的 .NET 应用程序类型中工作。
如果您的 .NET 应用程序不使用自己的控制台(Windows Forms/WPF/Windows Service/ASP.NET),则基本流程是:
- 将主 .NET 进程附加到要使用Ctrl+发出信号的进程的控制台C。
- 通过禁用对信号的处理,防止主 .NET 进程因Ctrl+C事件而停止
SetConsoleCtrlHandler()
。
- 为当前控制台生成控制台事件
GenerateConsoleCtrlEvent()
(processGroupId
应该为零!发送代码的答案p.SessionId
将不起作用并且不正确)。
- 等待发出信号的进程响应(例如,等待它退出)
- 通过主进程恢复Ctrl+C处理并断开与控制台的连接。
以下代码片段说明了如何做到这一点:
Process p;
if (AttachConsole((uint)p.Id)) {
SetConsoleCtrlHandler(null, true);
try {
if (!GenerateConsoleCtrlEvent(CTRL_C_EVENT,p.SessionId))
return false;
p.WaitForExit();
} finally {
SetConsoleCtrlHandler(null, false);
FreeConsole();
}
return true;
}
其中SetConsoleCtrlHandler()
、FreeConsole()
和是本AttachConsole()
机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);
请注意,等待目标进程响应(通常是等待进程退出)是至关重要的。否则,Ctrl+C信号将保留在当前进程的输入队列中,当第二次调用恢复处理时SetConsoleCtrlHandler()
,该信号将终止当前进程,而不是目标进程。
如果您需要从 .NET 控制台应用程序发送Ctrl+ ,事情会变得更加复杂。C上述方法将不起作用,因为在这种情况下AttachConsole()
返回false
(主控制台应用程序已经有一个控制台)。可以先调用FreeConsole()
再AttachConsole()
调用,但这样做会导致原始 .NET 应用程序控制台丢失,这在大多数情况下是不可接受的。
这是我对这种情况的解决方案;它可以工作并且对 .NET 主进程控制台没有副作用:
- 创建小型支持 .NET 控制台程序,该程序接受来自命令行参数的进程 ID,在调用
FreeConsole()
之前丢失自己的控制台,并使用上述代码将+发送到目标进程。AttachConsole()
CtrlC
- 主 .NET 控制台进程只是在需要向另一个控制台进程发送Ctrl+时在新进程中调用此实用程序。C