Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在进程中调用robocopy的批处理脚本不会终止_C#_.net_Windows_Batch File_Robocopy - Fatal编程技术网

C# 在进程中调用robocopy的批处理脚本不会终止

C# 在进程中调用robocopy的批处理脚本不会终止,c#,.net,windows,batch-file,robocopy,C#,.net,Windows,Batch File,Robocopy,如果process.Kill是从另一个线程或甚至是另一个程序调用的,那么如果批处理脚本使用robocy.exe,则该进程永远不会从WaitForExit中出来,直到它完成,就像它没有被终止一样 从批处理脚本调用Robocopy.exe。其他每一个脚本或程序都会像您预期的那样结束 ProcessStartInfo startInfo = new ProcessStartInfo(); startInfo.FileName = "batch.bat"; startInfo.U

如果process.Kill是从另一个线程或甚至是另一个程序调用的,那么如果批处理脚本使用robocy.exe,则该进程永远不会从WaitForExit中出来,直到它完成,就像它没有被终止一样

从批处理脚本调用Robocopy.exe。其他每一个脚本或程序都会像您预期的那样结束

    ProcessStartInfo startInfo = new ProcessStartInfo();
    startInfo.FileName = "batch.bat";
    startInfo.UseShellExecute = false;
    startInfo.CreateNoWindow = true;
    startInfo.RedirectStandardOutput = true;
    startInfo.OutputDataReceived += CaptureHandler;
    startInfo.RedirectStandardError = true;
    startInfo.ErrorDataReceived += CaptureHandler;
    process.Start();
    process.BeginOutputReadLine();
    process.BeginErrorReadLine();
    process.WaitForExit(); 
批处理脚本如下所示:

@echo off
call "robocopy.exe" "somedir" "somedest" /mir /fp /ndl /njh /njs /ns
我觉得这与输出处理程序有关。 我尝试在Kill调用之后和之前使用process.CancelErrorRead和process.CancelOutputRead,但没有成功

奇怪的是,如果使用process.WaitForExittimeout重载,它将在另一个线程终止后立即返回true。然而,这是在撒谎。进程仍在运行!根据MSDN文档,如果您再次尝试process.WaitForExit,它仍将等待流程完成,尽管haseExit说true

要确保异步事件处理已完成,请调用WaitForExit重载,该重载在接收到此重载的true后不接受任何参数


您正在成功终止批处理程序cmd.exe,但这样做不会终止robocopy,这是一个单独的进程

但是事实证明,Process.WaitForExit方法不仅仅等待进程退出,它还等待标准输出和标准错误流上的文件结束。在这个场景中,这意味着即使在批处理处理器被杀死之后,它也会等待robocy完成

带有超时的Process.WaitForExit重载没有此额外逻辑

我认为这构成了.NET框架中的一个bug。至少,它应该被记录下来


作为一种解决方法,您可以使用.hasExit和/或带有超时的WaitForExit版本来确定进程是否已退出。当然,在您的场景中,您可能更愿意等待孙进程,在这种情况下,您的代码已经按照预期的方式运行。

现在看来,在应用程序不知道终止robocy.exe的情况下执行此操作的唯一方法是先杀死脚本进程的子进程,然后再杀死脚本本身:


我遇到了同样的问题。在我的例子中,从RoboCopy参数列表中删除/mt开关似乎可以解决这个问题。

在继续之后,我发现当您避免重定向StandardOutput=true时,该过程正常完成。如果这不是一个可接受的解决方案,我发现使用robocy的/LOG:C:\logs\robocopy.txt开关将其标准输出发送到外部日志文件也可以工作,尽管您无法从流程对象本身获取文件/目录日志输出

您可以在最后尝试process.Close,或者如果您不需要重定向输出和错误,以防robocopy.exe处理它,您可以简单地使用System.Diagnostics.process。Start@c:\batch.bat;根据需要更正路径,因为它只会打开批处理文件并退出进程。关闭也不起作用。我需要等待它。那么,在不知道robocopy正在使用的情况下,是否有必要从应用程序中杀死robocopy?应用程序不必知道批处理脚本正在启动另一个进程,我希望kill能够锁定所有子进程。我想也许我可以先穿过这些小树,把它从下到上干掉?不是很简单;默认情况下,Windows不会跟踪该信息。最健壮的方法是启动批处理脚本,尽管我不知道.NET是否支持该方法,但您可能需要P/Invoke。一个更混乱但更简单的选择是在一个具有唯一标题的单独控制台中启动它。应用程序不必知道批处理脚本正在启动另一个进程-Windows并不是专门为这种方法设计的;启动一个批处理脚本来代表您完成工作是非常困难的。当然,你可以做到,Windows并没有刻意让它变得简单;它可能会杀死不相关的进程。这样更好。
    /// <summary>
    /// Kill a process, and all of its children, grandchildren, etc.
    /// </summary>
    /// <param name="pid">Process ID.</param>
    private static void KillProcessAndChildren(int pid)
    {
        ManagementObjectSearcher searcher = new ManagementObjectSearcher
          ("Select * From Win32_Process Where ParentProcessID=" + pid);
        ManagementObjectCollection moc = searcher.Get();
        foreach (ManagementObject mo in moc)
        {
            KillProcessAndChildren(Convert.ToInt32(mo["ProcessID"]));
        }
        try
        {
            Process proc = Process.GetProcessById(pid);
            proc.Kill();
        }
        catch (ArgumentException)
        {
            // Process already exited.
        }
    }