在使用控制台应用程序的 C# 中卡在GenerateConsoleCtrlEvent 上
我正经历着最困难的时期,希望你们中有人曾经这样做过。
我有一个 C# 控制台应用程序,它正在运行一个继承其控制台的子进程。 我希望将外部应用程序捕获的 ctrl-c 传递到内部应用程序,以便它有机会很好地关闭。
我有一些非常简单的代码。 我启动一个进程,然后使用 WaitForExit(10) 轮询它。 我还注册了一个 CancelKeyPress 处理程序,它在触发时将 bool 设置为 true。 轮询循环也会检查这一点,当它为真时,它会调用GenerateConsoleCtrlEvent()(我已通过pinvoke映射它)。
我已经尝试了很多GenerateConsoleCtrlEvent() 的参数组合。 第一个参数为 0 或 1,第二个参数为 0 或子进程的 ID。 似乎没什么作用。 有时我会得到错误的返回值,Marshal.GetLastWin32Error() 返回 0,有时我会得到正确的返回值。 但没有一个会导致子应用程序收到 ctrl-c。
为了绝对确定,我编写了一个测试 C# 应用程序作为子应用程序,它会打印出它所发生的情况,并验证在它运行时手动键入 ctrl-c 确实会导致它退出。
我已经为此绞尽脑汁几个小时了。 谁能给我一些关于该去哪里的指示?
I'm having the hardest time trying to get this to work, hoping one of you has done this before.
I have a C# console app that is running a child process which inherits its console. I want a ctrl-c caught by the outer app to be passed along to the inner app so that it can have a chance to shut down nicely.
I have some very simple code. I start a Process, then poll it with WaitForExit(10). I also have a CancelKeyPress handler registered, which sets a bool to true when it fires. The polling loop also checks this, and when it's true, it calls GenerateConsoleCtrlEvent() (which I have mapped through pinvoke).
I've tried a lot of combinations of params to GenerateConsoleCtrlEvent(). 0 or 1 for the first param, and either 0 or the child process's ID for the second param. Nothing seems to work. Sometimes I get a false back and Marshal.GetLastWin32Error() returns 0, and sometimes I get true back. But none cause the child app to receive a ctrl-c.
To be absolutely sure, I wrote a test C# app to be the child app which prints out what's going on with it and verified that manually typing ctrl-c when it runs does properly cause it to quit.
I've been banging my head against this for a couple hours. Can anyone give me some pointers on where to go with this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
不太确定这是一个好方法。 仅当子进程是使用
CreateProcess()
的 CREATE_NEW_PROCESS_GROUP 标志创建时才有效。 然而,System.Diagnostics.Process 类不支持这一点。考虑使用 Main() 方法的返回值。 Windows SDK 中已为 Ctrl+C 中止定义了一个唯一值:STATUS_CONTROL_C_EXIT 或 0xC000013A。 父进程可以从 Process.ExitCode 属性获取返回代码。
Not so sure this is a good approach. This only works if the child process is created with the CREATE_NEW_PROCESS_GROUP flag for
CreateProcess()
. The System.Diagnostics.Process class however does not support this.Consider using the return value from the Main() method. There is already a unique value defined in the Windows SDK for Ctrl+C aborts, STATUS_CONTROL_C_EXIT or 0xC000013A. The parent process can get that return code from the
Process.ExitCode
property.你有这样的运气吗? 我的理解是,当您在控制台中按 CTRL+C 时,默认情况下连接到控制台的所有进程都会收到它,而不仅仅是父进程。 这是一个示例:
Child.cs:
Parent.cs:
Output:
所以我不认为您需要做任何特别的事情。 但是,如果您确实需要自己生成 CTRL+C 事件,事情可能就不那么容易了。 我不确定您描述的问题,但据我所知,您只能将 CTRL+C 事件发送到附加到控制台窗口的所有进程。 如果分离进程,则无法向其发送 CTRL+C 事件。 如果您想选择在哪些进程中发送 CTRL+C 事件,则似乎需要为每个进程创建新的控制台窗口。 我不知道是否有某种方法可以在没有可见窗口的情况下执行此操作,或者当您想使用管道重定向 I/O 时。
Did you have any luck with this? My understanding is that when you press CTRL+C in a console, by default all the processes attached to the console receive it, not just the parent one. Here's an example:
Child.cs:
Parent.cs:
Output:
So I wouldn't have thought you'd need to do anything special. However, if you really need to generate CTRL+C events yourself, things might not be so easy. I'm not sure about the problems you describe, but as far as I can tell you can only send CTRL+C events to all the processes attached to a console window. If you detach a process, you can't send it CTRL+C events. If you want to be selective in which processes to send the CTRL+C events, you seem to need to create new console windows for every one. I've no idea if there's some way to do it without visible windows or when you want to redirect I/O using pipes.
这是我将 ctrl-c 发送到进程的解决方案。 仅供参考,我从来没有让
GenerateConsoleCtrlEvent
工作。下面是我发现的将 CTRL-C 发送到进程的方法,而不是使用GenerateConsoleCtrlEvent。 仅供参考,在这种情况下,我不需要查找组进程 ID。
然后,在实际运行该进程并在我的主应用程序中发送 CTRL-C 时:
有关详细信息,请参阅 重定向控制台应用程序的标准输入和Windows如何获取已经运行的进程的进程组?
Here is my solution for sending ctrl-c to a process. FYI, I never got
GenerateConsoleCtrlEvent
to work.Rather than using GenerateConsoleCtrlEvent, here is how I have found to send CTRL-C to a process. FYI, in this case, I didn't ever need to find the group process ID.
Then, in actually running the process and sending the CTRL-C in my main app:
For details, please see Redirecting standard input of console application and Windows how to get the process group of a process that is already running?