在 C# 中执行批处理文件

发布于 2024-10-29 03:26:08 字数 796 浏览 2 评论 0原文

我正在尝试用 C# 执行批处理文件,但没有成功。

我在互联网上找到了多个这样做的例子,但它对我不起作用。

public void ExecuteCommand(string command)
{
    int ExitCode;
    ProcessStartInfo ProcessInfo;
    Process Process;

    ProcessInfo = new ProcessStartInfo("cmd.exe", "/c " + command);
    ProcessInfo.CreateNoWindow = true;
    ProcessInfo.UseShellExecute = false;

    Process = Process.Start(ProcessInfo);
    Process.WaitForExit();

    ExitCode = Process.ExitCode;
    Process.Close();

    MessageBox.Show("ExitCode: " + ExitCode.ToString(), "ExecuteCommand");
}

命令字符串包含批处理文件的名称(存储在 system32 中)以及它应该操作的一些文件。 (示例:txtmanipulator file1.txt file2.txt file3.txt)。当我手动执行批处理文件时,它可以正常工作。

执行代码时,它给我一个 **ExitCode: 1** (Catch all for genericErrors)

我做错了什么?

I'm trying to execute a batch file in C#, but I'm not getting any luck doing it.

I've found multiple examples on the Internet doing it, but it is not working for me.

public void ExecuteCommand(string command)
{
    int ExitCode;
    ProcessStartInfo ProcessInfo;
    Process Process;

    ProcessInfo = new ProcessStartInfo("cmd.exe", "/c " + command);
    ProcessInfo.CreateNoWindow = true;
    ProcessInfo.UseShellExecute = false;

    Process = Process.Start(ProcessInfo);
    Process.WaitForExit();

    ExitCode = Process.ExitCode;
    Process.Close();

    MessageBox.Show("ExitCode: " + ExitCode.ToString(), "ExecuteCommand");
}

The command string contains the name of the batch file (stored in system32) and some files it should manipulate. (Example: txtmanipulator file1.txt file2.txt file3.txt). When I execute the batch file manually, it works correctly.

When executing the code, it gives me an **ExitCode: 1** (Catch all for general errors)

What am I doing wrong?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

浊酒尽余欢 2024-11-05 03:26:09

经过 steinar 的大力帮助后,这对我有用:

public void ExecuteCommand(string command)
{
    int ExitCode;
    ProcessStartInfo ProcessInfo;
    Process process;

    ProcessInfo = new ProcessStartInfo(Application.StartupPath + "\\txtmanipulator\\txtmanipulator.bat", command);
    ProcessInfo.CreateNoWindow = true;
    ProcessInfo.UseShellExecute = false;
    ProcessInfo.WorkingDirectory = Application.StartupPath + "\\txtmanipulator";
    // *** Redirect the output ***
    ProcessInfo.RedirectStandardError = true;
    ProcessInfo.RedirectStandardOutput = true;

    process = Process.Start(ProcessInfo);
    process.WaitForExit();

    // *** Read the streams ***
    string output = process.StandardOutput.ReadToEnd();
    string error = process.StandardError.ReadToEnd();

    ExitCode = process.ExitCode;

    MessageBox.Show("output>>" + (String.IsNullOrEmpty(output) ? "(none)" : output));
    MessageBox.Show("error>>" + (String.IsNullOrEmpty(error) ? "(none)" : error));
    MessageBox.Show("ExitCode: " + ExitCode.ToString(), "ExecuteCommand");
    process.Close();
}

After some great help from steinar this is what worked for me:

public void ExecuteCommand(string command)
{
    int ExitCode;
    ProcessStartInfo ProcessInfo;
    Process process;

    ProcessInfo = new ProcessStartInfo(Application.StartupPath + "\\txtmanipulator\\txtmanipulator.bat", command);
    ProcessInfo.CreateNoWindow = true;
    ProcessInfo.UseShellExecute = false;
    ProcessInfo.WorkingDirectory = Application.StartupPath + "\\txtmanipulator";
    // *** Redirect the output ***
    ProcessInfo.RedirectStandardError = true;
    ProcessInfo.RedirectStandardOutput = true;

    process = Process.Start(ProcessInfo);
    process.WaitForExit();

    // *** Read the streams ***
    string output = process.StandardOutput.ReadToEnd();
    string error = process.StandardError.ReadToEnd();

    ExitCode = process.ExitCode;

    MessageBox.Show("output>>" + (String.IsNullOrEmpty(output) ? "(none)" : output));
    MessageBox.Show("error>>" + (String.IsNullOrEmpty(error) ? "(none)" : error));
    MessageBox.Show("ExitCode: " + ExitCode.ToString(), "ExecuteCommand");
    process.Close();
}
星軌x 2024-11-05 03:26:09

效果很好。我像这样测试了它:

String command = @"C:\Doit.bat";

ProcessInfo = new ProcessStartInfo("cmd.exe", "/c " + command);
// ProcessInfo.CreateNoWindow = true;

我注释掉了关闭窗口,这样我就可以看到它运行。

It works fine. I tested it like this:

String command = @"C:\Doit.bat";

ProcessInfo = new ProcessStartInfo("cmd.exe", "/c " + command);
// ProcessInfo.CreateNoWindow = true;

I commented out turning off the window so I could SEE it run.

嘿看小鸭子会跑 2024-11-05 03:26:09

这是示例C#代码,它们将2个参数发送到bat/cmd文件以进行答案,以 问题

评论:如何传递参数并读取命令执行的结果?

/by @贾纳特别克·沙谢耶夫

选项 1:不隐藏控制台窗口、传递参数且不获取输出

  • 的情况下,这是答案/by < a href =“ https://stackoverflow.com/users/38206/brian-rasmussen”> @brian rasmussen

using System;
using System.Diagnostics;


namespace ConsoleApplication
{
    class Program
    { 
        static void Main(string[] args)
        {
         System.Diagnostics.Process.Start(@"c:\batchfilename.bat", "\"1st\" \"2nd\"");
        }
    }
}

选项2:隐藏控制台窗口,通过参数并进行输出


using System;
using System.Diagnostics;

namespace ConsoleApplication
{
    class Program
    { 
        static void Main(string[] args)
        {
         var process = new Process();
         var startinfo = new ProcessStartInfo(@"c:\batchfilename.bat", "\"1st_arg\" \"2nd_arg\" \"3rd_arg\"");
         startinfo.RedirectStandardOutput = true;
         startinfo.UseShellExecute = false;
         process.StartInfo = startinfo;
         process.OutputDataReceived += (sender, argsx) => Console.WriteLine(argsx.Data); // do whatever processing you need to do in this handler
         process.Start();
         process.BeginOutputReadLine();
         process.WaitForExit();
        }
    }
}

// c#解码蝙蝠文件并传递参数: //编辑01/2022


using System;
using System.IO;
using System.Text;
using System.Diagnostics;

namespace ConsoleApplication
{
   class Program
   {
      static void Main(string[] args)
      {
        String encodedString = @"QGVjaG8gb2ZmIAoKc2V0ICJ4PUZvbGRlciIKeGNvcHkgL3kgL3YgL2UgLlw
                                 iJXglIlwqIFxcMTAuMC4wLjIwMFxkXAoKZm9yICUleSBpbiAoMjAyLDIwMy
                                 wyMDQsMjA1KWRvICgKICAgICBuZXQgdXNlIFxcMTAuMC4wLiUlfnlcZSAiJ
                                 X4xIiAvdXNlcjoiJX4yIgogICAgIGVjaG9cQ29weWluZyBmaWxlcyB0byBc
                                 XDEwLjAuMC4lJX55XGVcCiAgICAgeGNvcHkgL3kgL3YgL2UgLlwiJXglIlw
                                 qIFxcMTAuMC4wLiUlfnlcZVwKICAgICk=";
                                 
        File.WriteAllBytes(@"z:\batchfilename.bat", Convert.FromBase64String(encodedString));
        System.Diagnostics.Process.Start(@"z:\batchfilename.bat", "\"PassWord1\" \"User1\"");
      }
   }
}

/* bat file decoded:

@echo off 

set "x=Folder"
xcopy /y /v /e .\"%x%"\* \\10.0.0.200\d\

for %%y in (202,203,204,205)do (
     net use \\10.0.0.%%~y\e "%~1" /user:"%~2"
     echo\Copying files to \\10.0.0.%%~y\e\
     xcopy /y /v /e .\"%x%"\* \\10.0.0.%%~y\e\
    )


Execute bat: 
@"z:\batchfilename.bat", "\"PassWord1\" \"User1\""

Bat argument:
Argument %1 == PassWord1   Argument %2 == User1
*/ 

1. << /strong>创建蝙蝠并尽可能多地对其进行测试

2。将代码转换为base64

定义代码中的变量

3。用base64 strings 4 。

​通过您的论点



Here is sample c# code that are sending 2 parameters to a bat/cmd file for answer this question.

Comment: how can I pass parameters and read a result of command execution?

/by @Janatbek Sharsheyev

Option 1 : Without hiding the console window, passing arguments and without getting the outputs


using System;
using System.Diagnostics;


namespace ConsoleApplication
{
    class Program
    { 
        static void Main(string[] args)
        {
         System.Diagnostics.Process.Start(@"c:\batchfilename.bat", "\"1st\" \"2nd\"");
        }
    }
}

Option 2 : Hiding the console window, passing arguments and taking outputs


using System;
using System.Diagnostics;

namespace ConsoleApplication
{
    class Program
    { 
        static void Main(string[] args)
        {
         var process = new Process();
         var startinfo = new ProcessStartInfo(@"c:\batchfilename.bat", "\"1st_arg\" \"2nd_arg\" \"3rd_arg\"");
         startinfo.RedirectStandardOutput = true;
         startinfo.UseShellExecute = false;
         process.StartInfo = startinfo;
         process.OutputDataReceived += (sender, argsx) => Console.WriteLine(argsx.Data); // do whatever processing you need to do in this handler
         process.Start();
         process.BeginOutputReadLine();
         process.WaitForExit();
        }
    }
}

// C# decode bat file and run passing arguments: // edit 01/2022


using System;
using System.IO;
using System.Text;
using System.Diagnostics;

namespace ConsoleApplication
{
   class Program
   {
      static void Main(string[] args)
      {
        String encodedString = @"QGVjaG8gb2ZmIAoKc2V0ICJ4PUZvbGRlciIKeGNvcHkgL3kgL3YgL2UgLlw
                                 iJXglIlwqIFxcMTAuMC4wLjIwMFxkXAoKZm9yICUleSBpbiAoMjAyLDIwMy
                                 wyMDQsMjA1KWRvICgKICAgICBuZXQgdXNlIFxcMTAuMC4wLiUlfnlcZSAiJ
                                 X4xIiAvdXNlcjoiJX4yIgogICAgIGVjaG9cQ29weWluZyBmaWxlcyB0byBc
                                 XDEwLjAuMC4lJX55XGVcCiAgICAgeGNvcHkgL3kgL3YgL2UgLlwiJXglIlw
                                 qIFxcMTAuMC4wLiUlfnlcZVwKICAgICk=";
                                 
        File.WriteAllBytes(@"z:\batchfilename.bat", Convert.FromBase64String(encodedString));
        System.Diagnostics.Process.Start(@"z:\batchfilename.bat", "\"PassWord1\" \"User1\"");
      }
   }
}

/* bat file decoded:

@echo off 

set "x=Folder"
xcopy /y /v /e .\"%x%"\* \\10.0.0.200\d\

for %%y in (202,203,204,205)do (
     net use \\10.0.0.%%~y\e "%~1" /user:"%~2"
     echo\Copying files to \\10.0.0.%%~y\e\
     xcopy /y /v /e .\"%x%"\* \\10.0.0.%%~y\e\
    )


Execute bat: 
@"z:\batchfilename.bat", "\"PassWord1\" \"User1\""

Bat argument:
Argument %1 == PassWord1   Argument %2 == User1
*/ 

1. Create your bat and test it as much as possible

2. Convert the code to base64

3. Defines a variable in your code with the base64 strings

4. Decode at runtime to a pre-defined and proper location for execution

5. Call the bat execution on the path where it was decodes

6. If necessary, pass your arguments



寂寞笑我太脆弱 2024-11-05 03:26:09

下面的代码对我来说效果很好

using System.Diagnostics;

public void ExecuteBatFile()
{
    Process proc = null;

    string _batDir = string.Format(@"C:\");
    proc = new Process();
    proc.StartInfo.WorkingDirectory = _batDir;
    proc.StartInfo.FileName = "myfile.bat";
    proc.StartInfo.CreateNoWindow = false;
    proc.Start();
    proc.WaitForExit();
    ExitCode = proc.ExitCode;
    proc.Close();
    MessageBox.Show("Bat file executed...");
}

Below code worked fine for me

using System.Diagnostics;

public void ExecuteBatFile()
{
    Process proc = null;

    string _batDir = string.Format(@"C:\");
    proc = new Process();
    proc.StartInfo.WorkingDirectory = _batDir;
    proc.StartInfo.FileName = "myfile.bat";
    proc.StartInfo.CreateNoWindow = false;
    proc.Start();
    proc.WaitForExit();
    ExitCode = proc.ExitCode;
    proc.Close();
    MessageBox.Show("Bat file executed...");
}
热风软妹 2024-11-05 03:26:09
using System.Diagnostics;

private void ExecuteBatFile()
{
    Process proc = null;
    try
    {
        string targetDir = string.Format(@"D:\mydir");   //this is where mybatch.bat lies
        proc = new Process();
        proc.StartInfo.WorkingDirectory = targetDir;
        proc.StartInfo.FileName = "lorenzo.bat";
        proc.StartInfo.Arguments = string.Format("10");  //this is argument
        proc.StartInfo.CreateNoWindow = false;
        proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;  //this is for hiding the cmd window...so execution will happen in back ground.
        proc.Start();
        proc.WaitForExit();
    }
    catch (Exception ex)
    {
        Console.WriteLine("Exception Occurred :{0},{1}", ex.Message, ex.StackTrace.ToString());
    }
}
using System.Diagnostics;

private void ExecuteBatFile()
{
    Process proc = null;
    try
    {
        string targetDir = string.Format(@"D:\mydir");   //this is where mybatch.bat lies
        proc = new Process();
        proc.StartInfo.WorkingDirectory = targetDir;
        proc.StartInfo.FileName = "lorenzo.bat";
        proc.StartInfo.Arguments = string.Format("10");  //this is argument
        proc.StartInfo.CreateNoWindow = false;
        proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;  //this is for hiding the cmd window...so execution will happen in back ground.
        proc.Start();
        proc.WaitForExit();
    }
    catch (Exception ex)
    {
        Console.WriteLine("Exception Occurred :{0},{1}", ex.Message, ex.StackTrace.ToString());
    }
}
浪推晚风 2024-11-05 03:26:09

您是否尝试过以管理员身份启动它?如果您使用 Visual Studio,请以管理员身份启动它,因为使用 .bat 文件需要这些权限。

Have you tried starting it as an administrator? Start Visual Studio as an administrator if you use it, because working with .bat files requires those privileges.

深海夜未眠 2024-11-05 03:26:09

对于之前提出的解决方案,我一直在努力让多个 npm 命令在循环中执行并在控制台窗口上获取所有输出。

在我结合了之前评论中的所有内容,但重新安排了代码执行流程后,它终于开始工作了。

我注意到事件订阅完成得太晚(在进程已经开始之后),因此未捕获一些输出。

下面的代码现在执行以下操作:

  1. 在进程开始之前订阅事件,
    因此确保不会丢失任何输出。
  2. 进程启动后立即开始读取输出。

该代码已经针对死锁进行了测试,尽管它是同步的(同时执行一个进程),因此我无法保证如果并行运行会发生什么。

    static void RunCommand(string command, string workingDirectory)
    {
        Process process = new Process
        {
            StartInfo = new ProcessStartInfo("cmd.exe", $"/c {command}")
            {
                WorkingDirectory = workingDirectory,
                CreateNoWindow = true,
                UseShellExecute = false,
                RedirectStandardError = true,
                RedirectStandardOutput = true
            }
        };

        process.OutputDataReceived += (object sender, DataReceivedEventArgs e) => Console.WriteLine("output :: " + e.Data);

        process.ErrorDataReceived += (object sender, DataReceivedEventArgs e) => Console.WriteLine("error :: " + e.Data);

        process.Start();
        process.BeginOutputReadLine();
        process.BeginErrorReadLine();
        process.WaitForExit();

        Console.WriteLine("ExitCode: {0}", process.ExitCode);
        process.Close();
    }

With previously proposed solutions, I have struggled to get multiple npm commands executed in a loop and get all outputs on the console window.

It finally started to work after I have combined everything from the previous comments, but rearranged the code execution flow.

What I have noticed is that event subscribing was done too late (after the process has already started) and therefore some outputs were not captured.

The code below now does the following:

  1. Subscribes to the events, before the process has started,
    therefore ensuring that no output is missed.
  2. Begins reading from outputs as soon as the process is started.

The code has been tested against the deadlocks, although it is synchronous (one process execution at the time) so I cannot guarantee what would happen if this was run in parallel.

    static void RunCommand(string command, string workingDirectory)
    {
        Process process = new Process
        {
            StartInfo = new ProcessStartInfo("cmd.exe", $"/c {command}")
            {
                WorkingDirectory = workingDirectory,
                CreateNoWindow = true,
                UseShellExecute = false,
                RedirectStandardError = true,
                RedirectStandardOutput = true
            }
        };

        process.OutputDataReceived += (object sender, DataReceivedEventArgs e) => Console.WriteLine("output :: " + e.Data);

        process.ErrorDataReceived += (object sender, DataReceivedEventArgs e) => Console.WriteLine("error :: " + e.Data);

        process.Start();
        process.BeginOutputReadLine();
        process.BeginErrorReadLine();
        process.WaitForExit();

        Console.WriteLine("ExitCode: {0}", process.ExitCode);
        process.Close();
    }
慈悲佛祖 2024-11-05 03:26:09

我想要一些更直接可用的东西,而不需要组织特定的硬编码字符串值。我提供以下内容作为可直接重用的代码块。较小的缺点是在进行调用时需要确定并传递工作文件夹。

public static void ExecuteCommand(string command, string workingFolder)
        {
            int ExitCode;
            ProcessStartInfo ProcessInfo;
            Process process;

            ProcessInfo = new ProcessStartInfo("cmd.exe", "/c " + command);
            ProcessInfo.CreateNoWindow = true;
            ProcessInfo.UseShellExecute = false;
            ProcessInfo.WorkingDirectory = workingFolder;
            // *** Redirect the output ***
            ProcessInfo.RedirectStandardError = true;
            ProcessInfo.RedirectStandardOutput = true;

            process = Process.Start(ProcessInfo);
            process.WaitForExit();

            // *** Read the streams ***
            string output = process.StandardOutput.ReadToEnd();
            string error = process.StandardError.ReadToEnd();

            ExitCode = process.ExitCode;

            MessageBox.Show("output>>" + (String.IsNullOrEmpty(output) ? "(none)" : output));
            MessageBox.Show("error>>" + (String.IsNullOrEmpty(error) ? "(none)" : error));
            MessageBox.Show("ExitCode: " + ExitCode.ToString(), "ExecuteCommand");
            process.Close();
        }

调用方式如下:

    // This will get the current WORKING directory (i.e. \bin\Debug)
    string workingDirectory = Environment.CurrentDirectory;
    // This will get the current PROJECT directory
    string projectDirectory = Directory.GetParent(workingDirectory).Parent.FullName;
    string commandToExecute = Path.Combine(projectDirectory, "TestSetup", "WreckersTestSetupQA.bat");
    string workingFolder = Path.GetDirectoryName(commandToExecute);
    commandToExecute = QuotesAround(commandToExecute);
    ExecuteCommand(commandToExecute, workingFolder);

在此示例中,在 Visual Studio 2017 中,作为测试运行的一部分,我想在执行某些测试之前运行环境重置批处理文件。 (SpecFlow+xUnit)。我厌倦了单独手动运行 bat 文件的额外步骤,只想将 bat 文件作为 C# 测试设置代码的一部分运行。环境重置批处理文件将测试用例文件移回输入文件夹,清理输出文件夹等,以达到正确的测试开始状态进行测试。 QuotesAround 方法只是在命令行周围加上引号,以防文件夹名称中存在空格(“Program Files”,有人吗?)。其中的内容就是: private string QuotesAround(string input) {return "\"" + input + "\"";}

如果您的情况与我的情况类似,希望有人发现这很有用并节省几分钟。

I wanted something that was more directly usable without organization-specific hard-coded string values in it. I offer the following as a directly reusable chunk of code. The minor downside is needing to determine and pass the working folder when making the call.

public static void ExecuteCommand(string command, string workingFolder)
        {
            int ExitCode;
            ProcessStartInfo ProcessInfo;
            Process process;

            ProcessInfo = new ProcessStartInfo("cmd.exe", "/c " + command);
            ProcessInfo.CreateNoWindow = true;
            ProcessInfo.UseShellExecute = false;
            ProcessInfo.WorkingDirectory = workingFolder;
            // *** Redirect the output ***
            ProcessInfo.RedirectStandardError = true;
            ProcessInfo.RedirectStandardOutput = true;

            process = Process.Start(ProcessInfo);
            process.WaitForExit();

            // *** Read the streams ***
            string output = process.StandardOutput.ReadToEnd();
            string error = process.StandardError.ReadToEnd();

            ExitCode = process.ExitCode;

            MessageBox.Show("output>>" + (String.IsNullOrEmpty(output) ? "(none)" : output));
            MessageBox.Show("error>>" + (String.IsNullOrEmpty(error) ? "(none)" : error));
            MessageBox.Show("ExitCode: " + ExitCode.ToString(), "ExecuteCommand");
            process.Close();
        }

Called like this:

    // This will get the current WORKING directory (i.e. \bin\Debug)
    string workingDirectory = Environment.CurrentDirectory;
    // This will get the current PROJECT directory
    string projectDirectory = Directory.GetParent(workingDirectory).Parent.FullName;
    string commandToExecute = Path.Combine(projectDirectory, "TestSetup", "WreckersTestSetupQA.bat");
    string workingFolder = Path.GetDirectoryName(commandToExecute);
    commandToExecute = QuotesAround(commandToExecute);
    ExecuteCommand(commandToExecute, workingFolder);

In this example, from within Visual Studio 2017, as part of a test run, I want to run an environment reset batch file before executing some tests. (SpecFlow+xUnit). I got tired of extra steps for manually running the bat file separately, and wanted to just run the bat file as part of the C# test setup code. The environment reset batch file moves test case files back into the input folder, cleans up output folders, etc. to get to the proper test starting state for testing. The QuotesAround method simply puts quotes around the command line in case there are spaces in folder names ("Program Files", anyone?). All that's in it is this: private string QuotesAround(string input) {return "\"" + input + "\"";}

Hope some find this useful and save a few minutes if your scenario is similar to mine.

稀香 2024-11-05 03:26:09

System.Diagnostics.Process.Start(BatchFileName,Parameters);

我知道这适用于批处理文件和参数,但不知道如何在 C# 中获取结果。
通常,输出在批处理文件中定义。

System.Diagnostics.Process.Start(BatchFileName, Parameters);

I know this will work for batch file and parameters, but no ideas how to get the results in C#.
Usually, the outputs are defined in the batch file.

初与友歌 2024-11-05 03:26:08

这应该有效。您可以尝试转储输出和错误流的内容,以找出发生的情况:

static void ExecuteCommand(string command)
{
    int exitCode;
    ProcessStartInfo processInfo;
    Process process;

    processInfo = new ProcessStartInfo("cmd.exe", "/c " + command);
    processInfo.CreateNoWindow = true;
    processInfo.UseShellExecute = false;
    // *** Redirect the output ***
    processInfo.RedirectStandardError = true;
    processInfo.RedirectStandardOutput = true;

    process = Process.Start(processInfo);
    process.WaitForExit();

    // *** Read the streams ***
    // Warning: This approach can lead to deadlocks, see Edit #2
    string output = process.StandardOutput.ReadToEnd();
    string error = process.StandardError.ReadToEnd();

    exitCode = process.ExitCode;

    Console.WriteLine("output>>" + (String.IsNullOrEmpty(output) ? "(none)" : output));
    Console.WriteLine("error>>" + (String.IsNullOrEmpty(error) ? "(none)" : error));
    Console.WriteLine("ExitCode: " + exitCode.ToString(), "ExecuteCommand");
    process.Close();
}

static void Main()
{
    ExecuteCommand("echo testing");
}   

* 编辑*

鉴于下面评论中的额外信息,我能够重新创建问题。似乎有一些安全设置导致了这种行为(尚未详细调查)。

如果批处理文件不在 C:\Windows\System32 中,此确实可以工作。尝试将其移动到其他位置,例如可执行文件的位置。请注意,将自定义批处理文件或可执行文件保留在 Windows 目录中无论如何都是不好的做法。

* 编辑 2 *
事实证明 如果同步读取流,可能会发生死锁,无论是在 WaitForExit 之前同步读取,还是同时读取 stderrstdout一个接一个。

如果使用异步读取方法,则不应发生这种情况,如下例所示:

static void ExecuteCommand(string command)
{
    var processInfo = new ProcessStartInfo("cmd.exe", "/c " + command);
    processInfo.CreateNoWindow = true;
    processInfo.UseShellExecute = false;
    processInfo.RedirectStandardError = true;
    processInfo.RedirectStandardOutput = true;

    var process = Process.Start(processInfo);

    process.OutputDataReceived += (object sender, DataReceivedEventArgs e) =>
        Console.WriteLine("output>>" + e.Data);
    process.BeginOutputReadLine();

    process.ErrorDataReceived += (object sender, DataReceivedEventArgs e) =>
        Console.WriteLine("error>>" + e.Data);
    process.BeginErrorReadLine();

    process.WaitForExit();

    Console.WriteLine("ExitCode: {0}", process.ExitCode);
    process.Close();
}

This should work. You could try to dump out the contents of the output and error streams in order to find out what's happening:

static void ExecuteCommand(string command)
{
    int exitCode;
    ProcessStartInfo processInfo;
    Process process;

    processInfo = new ProcessStartInfo("cmd.exe", "/c " + command);
    processInfo.CreateNoWindow = true;
    processInfo.UseShellExecute = false;
    // *** Redirect the output ***
    processInfo.RedirectStandardError = true;
    processInfo.RedirectStandardOutput = true;

    process = Process.Start(processInfo);
    process.WaitForExit();

    // *** Read the streams ***
    // Warning: This approach can lead to deadlocks, see Edit #2
    string output = process.StandardOutput.ReadToEnd();
    string error = process.StandardError.ReadToEnd();

    exitCode = process.ExitCode;

    Console.WriteLine("output>>" + (String.IsNullOrEmpty(output) ? "(none)" : output));
    Console.WriteLine("error>>" + (String.IsNullOrEmpty(error) ? "(none)" : error));
    Console.WriteLine("ExitCode: " + exitCode.ToString(), "ExecuteCommand");
    process.Close();
}

static void Main()
{
    ExecuteCommand("echo testing");
}   

* EDIT *

Given the extra information in your comment below, I was able to recreate the problem. There seems to be some security setting that results in this behaviour (haven't investigated that in detail).

This does work if the batch file is not located in C:\Windows\System32. Try moving it to some other location, e.g. the location of your executable. Note that keeping custom batch files or executables in the Windows directory is bad practice anyway.

* EDIT 2 *
It turns out that if the streams are read synchronously, a deadlock can occur, either by reading synchronously before WaitForExit or by reading both stderr and stdout synchronously one after the other.

This should not happen if using the asynchronous read methods instead, as in the following example:

static void ExecuteCommand(string command)
{
    var processInfo = new ProcessStartInfo("cmd.exe", "/c " + command);
    processInfo.CreateNoWindow = true;
    processInfo.UseShellExecute = false;
    processInfo.RedirectStandardError = true;
    processInfo.RedirectStandardOutput = true;

    var process = Process.Start(processInfo);

    process.OutputDataReceived += (object sender, DataReceivedEventArgs e) =>
        Console.WriteLine("output>>" + e.Data);
    process.BeginOutputReadLine();

    process.ErrorDataReceived += (object sender, DataReceivedEventArgs e) =>
        Console.WriteLine("error>>" + e.Data);
    process.BeginErrorReadLine();

    process.WaitForExit();

    Console.WriteLine("ExitCode: {0}", process.ExitCode);
    process.Close();
}
爱情眠于流年 2024-11-05 03:26:08
System.Diagnostics.Process.Start("c:\\batchfilename.bat");

这个简单的行将执行批处理文件。

System.Diagnostics.Process.Start("c:\\batchfilename.bat");

this simple line will execute the batch file.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文