简体   繁体   English

将ctrl + c发送到c#中的cmd.exe进程

[英]Send ctrl+c to a cmd.exe process in c#

I'm currently writing myself a little C# back up program. 我现在正在给自己编写一个C#备份程序。 I'm using a standard windows form for the interface, and am calling cmd.exe as a new process, and then using XCOPY from within this new process. 我正在为接口使用标准的Windows窗体,并将cmd.exe作为一个新进程调用,然后在此新进程中使用XCOPY。 Every thing's working great, except for this last feature I want to add in, which is the ability to break the operation. 除了我想要添加的最后一个功能外,每个东西都运行良好,这是打破操作的能力。

From a native command prompt, I can do this cleanly with ctrl+c, but try as I might, I can't replicate this functionality using the winforms and process approach. 从本机命令提示符,我可以使用ctrl + c干净利落地完成此操作,但尽可能尝试,我无法使用winforms和process方法复制此功能。 I've tried redirecting the standardinput and using that to send consolespecialkeys.ControlC to the process, I've also tried sending 0x03 and "/x03", both of which I've read on other forum posts are hex code for ctrl+c. 我已经尝试重定向standardinput并使用它来发送consolespecialkeys.ControlC到进程,我也尝试发送0x03和“/ x03”,我在其他论坛帖子上读到的都是ctrl + c的十六进制代码。 Nothing I'm sending is registered though, and exiting the process kills the user interface, but leaves the xcopy.exe working in the background. 我发送的任何内容都没有注册,退出进程会终止用户界面,但会让xcopy.exe在后台运行。 Killing xcopy.exe manually results in it leaving the file it was copying half copied and corrupted, not something that happens using the ctrl+c in a command prompt. 手动杀死xcopy.exe导致它将复制的文件保留为半复制和损坏,而不是在命令提示符中使用ctrl + c发生的事情。

Am I missing something blindingly obvious? 我错过了一些非常明显的东西吗? I'm new-ish to C#, so I'll hold my hands up and admit this is most likely me being slow, or misunderstanding how the process is working with cmd.exe. 我是C#的新手,所以我会举起手来承认这很可能是我很慢,或误解了进程如何使用cmd.exe。 However, since processes support standard input redirection, it seems like something that should work... to me at least. 但是,由于进程支持标准输入重定向,所以至少应该对我起作用。 I've put the basic outline of my code below, in case it helps identify where I'm messing up. 我已经将我的代码的基本轮廓放在下面,以防它有助于确定我在哪里弄乱。

string XCopyArguments = "\"" + dir.FullName + "\" \"" + destination + "\" /D /S /I /E";  
Process XCopyProcess = new Process();  
ProcessStartInfo XCopyStartInfo = new ProcessStartInfo(); 
XCopyStartInfo.FileName = "CMD.exe ";  
XCopyStartInfo.RedirectStandardError = true;
XCopyStartInfo.RedirectStandardOutput = true;
XCopyStartInfo.RedirectStandardInput = true;
XCopyStartInfo.UseShellExecute = false;
XCopyStartInfo.CreateNoWindow = true;
XCopyStartInfo.Arguments = " /D /c XCOPY " + XCopyArguments;
XCopyProcess.EnableRaisingEvents = true;
XCopyProcess.StartInfo = XCopyStartInfo;
XCopyProcess.Start();                
XCopyProcess.WaitForExit(15000);
int ExitCode = XCopyProcess.ExitCode;
if (ExitCode > 0 & !XCopyProcess.HasExited)
{
XCopyProcess.Kill();
}
XCopyProcess.Dispose();

Many thanks in advance for any help anyone can offer. 非常感谢任何人提供的任何帮助。

I don't want to be a besserwisser, but I think you'd be much better off doing the copying inside your program. 我不想成为besserwisser,但我认为你在程序中进行复制要好得多。 Using File, Directory and the other classes in the System.IO namespace, it's really simple, and leaves you in full control to report progress, cancel operations etc. 使用System.IO命名空间中的File,Directory和其他类,它非常简单,让您完全控制报告进度,取消操作等。

Yes, doing the operation in .NET would be easier. 是的,在.NET中进行操作会更容易。 BUT, I need to send ctrl-c to a process also and I don't have that option. 但是,我还需要将ctrl-c发送到进程,我没有那个选项。

So can we please get an answer to this question? 那么我们能否回答这个问题呢?

EDIT: Do I have to post a duplicate to get an answer? 编辑:我是否必须发布副本才能得到答案? And no, @j0rd4n didn't answer the question. 不,@ j0rd4n没有回答这个问题。

Like the others said, there are better ways to accomplish that particular task. 像其他人所说的那样,有更好的方法来完成这项特定任务。 However, that doesn't answer your question. 但是,这不能回答你的问题。 I use a similar technique to what you have shown here for automating various tasks and find it quite useful. 我使用了类似于此处所示的技术来自动执行各种任务并发现它非常有用。 Sometimes things go very badly though and you want the process to bail out before things get worse. 有时事情会非常糟糕,你希望在事情变得更糟之前保住这个过程。 ;p ,p

Here is the problem with your example: 以下是您的示例的问题:

XCopyStartInfo.CreateNoWindow = true; XCopyStartInfo.CreateNoWindow = true;

Set it to false and it will then process XCopyProcess.CloseMainWindow() and XCopyProcess.Close(). 将其设置为false,然后它将处理XCopyProcess.CloseMainWindow()和XCopyProcess.Close()。 Much cleaner than using Kill(). 比使用Kill()更清洁。

它需要更少的代码行来循环遍历子目录和文件并逐个复制它们然后您不必担心控制另一个进程...

Sorry it's in VB.NET. 对不起,这是在VB.NET中。

Declare Function GenerateConsoleCtrlEvent Lib "kernel32" ( _
                    ByVal dwCtrlEvent As Integer, _
                    ByVal dwProcessGroupId As Integer _
                    ) As Integer

Private Const CTRL_C_EVENT As Integer = 0

Private Sub SendCtrlC()
    GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0)

    ' send a Ctrl-C to this process
    GenerateConsoleCtrlEvent(CTRL_C_EVENT, currentpid)

    ' send a Ctrl-C to the cmd process
    GenerateConsoleCtrlEvent(CTRL_C_EVENT, cmdpid)
End Sub

I've successfully sent a CTRL-C combination to an cmd.exe process created with SW_HIDE--ie, a hidden cmd.exe window. 我已成功将CTRL-C组合发送到使用SW_HIDE创建的cmd.exe进程 - 即隐藏的cmd.exe窗口。

The technique was to use EnumWindows to identify the process and get it's window handle (it still has a handle to process messages even if its not visible). 该技术是使用EnumWindows来识别进程并获取它的窗口句柄(它仍然有一个处理消息的句柄,即使它不可见)。

Next, I used PostMessage to post a ctrl-c combination to the process. 接下来,我使用PostMessage将ctrl-c组合发布到进程。 This had the same effect as if a user had hit 'ctrl-c' while the window was active. 这与用户在窗口处于活动状态时点击“ctrl-c”的效果相同。

To do this from C#, you would want to probably visit http://pinvoke.net/ - a lifesaver when it comes to writing Win32 API function prototypes in C#. 要从C#执行此操作,您可能希望访问http://pinvoke.net/ - 在C#中编写Win32 API函数原型时的救星。

You'll have to manually kill the process if you want to handle the copying this way. 如果要以这种方式处理复制,则必须手动终止进程。 In your code above, you are calling XCopyProcess.WaitForExit(...). 在上面的代码中,您正在调用XCopyProcess.WaitForExit(...)。 This is a blocking call so the parent C# process will halt at that point until the child process has finished or the time-interval has elapsed. 这是一个阻塞调用,因此父C#进程将在此时停止,直到子进程完成或时间间隔已经过去。

What you could do is instead of blocking, you can sleep in a loop routinely checking if the user has requested to kill the process via your C# UI. 您可以做的不是阻塞,而是可以定期检查用户是否已经请求通过C#UI终止进程。 If you receive this event, you explicitly kill the process. 如果您收到此事件,则明确终止该进程。 Otherwise, you wait for another interval until the process is finished. 否则,您将等待另一个间隔,直到该过程完成。

EDIT: I do agree with the other comments, though. 编辑:我同意其他评论。 Copy directly from the .NET framework instead of using xcopy. 直接从.NET框架复制而不是使用xcopy。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM