私は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 general errors)
を与えます
何がおかしいのですか?
これでうまくいくはずです。何が起こっているのかを調べるために、出力ストリームとエラーストリームの内容をダンプしようとすることができます。
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 *
下記のあなたのコメントに追加情報があれば、私は問題を再現することができました。この動作につながるセキュリティ設定がいくつかあるようです(詳細は調べていません)。
バッチファイルがC:\Windows\System32
にない場合、これは機能します。他の場所に移動してみてください。実行ファイルの場所カスタムバッチファイルまたは実行可能ファイルをWindowsディレクトリに保存するのは、とにかく悪い習慣です。
* EDIT 2 *それは 判明 ストリームが同期的に読み込まれた場合、デッドロックが発生する可能性があるということです。 WaitForExit
、またはstderr
とstdout
の両方を同期して次々に読み取ることによって。
次の例のように、非同期のreadメソッドを代わりに使用しても、これは発生しません。
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();
}
System.Diagnostics.Process.Start("c:\\batchfilename.bat");
この単純な行はバッチファイルを実行します。
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();
}
それはうまくいきます。私はこれを次のようにテストしました:
String command = @"C:\Doit.bat";
ProcessInfo = new ProcessStartInfo("cmd.exe", "/c " + command);
// ProcessInfo.CreateNoWindow = true;
私はそれが走るのを見ることができるように窓を消すことをコメントした。
以下のコードは私のためにうまくいきました
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...");
}
管理者として起動してみましたか? .bat
ファイルを操作するにはそれらの特権が必要なので、使用する場合は管理者としてVisual Studioを起動してください。
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());
}
}
System.Diagnostics.Process.Start(BatchFileName, Parameters);
これはバッチファイルとパラメーターで機能することはわかっていますが、C#で結果を取得する方法はわかりません。通常、出力はバッチファイルで定義されます。
組織固有のハードコードされた文字列値が含まれていなくても、もっと直接的に使えるものが欲しいと思いました。私は直接再利用可能なコードの塊として以下を提供します。マイナーな欠点は、電話をかけるときに作業フォルダを決定して渡す必要があることです。
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ファイルを手動で実行するための追加の手順にうんざりして、C#テストセットアップコードの一部としてbatファイルを実行したいだけでした。環境リセットバッチファイルは、テストケースファイルを入力フォルダに戻したり、出力フォルダをクリーンアップしたりして、テストのための適切なテスト開始状態にします。 QuotesAroundメソッドは、フォルダ名にスペースが含まれている場合にコマンドラインを引用符で囲むだけです( "Program Files"、だれでもか。)。その中にあるのはこれだけです:private string QuotesAround(string input){return "\" "+ input +"\"";}
あなたのシナリオが私のものと似ているならば、何人かがこれが役に立つと思って、数分を節約することを願っています。