C# からbatファイルを呼ぶには、System.Diagnostics.Process
を使う。
コマンドラインで動作するプログラムをRuby等で書いたはいいものの、いちいちcmdから呼ぶのは鬱陶しい。引数も与えなきゃいけないし、GUI作ってもいいじゃない、と思う。既存のこいつをそのまま使いたいし、楽に済ませたい。
先ずはそのコマンドラインプログラムを呼ぶbatファイルを書く。例えば、
cd C:\User\username ( pik use 1.9.3 bundle exec ruby somescript.rb %1 )
の様にやる。
次にVisualStudioを立ち上げ、適当にXAMLでGUIを作る。batを呼び出すには以下の様にする。
using System.Diagnostics; using System.Windows; namespace SomeApp { public partial class Window1 : Window { public Window1() { InitializeComponent(); } private void buttonAction_Click(object sender, RoutedEventArgs e) { labelStatus.Content = "Wait..."; string param = textBoxParam.Text; int exitCode = CallBatch(param); if (exitCode == 0) labelStatus.Content = "Done!"; else labelStatus.Content = "Failed."; } private int CallBatch(string param) { var startInfo = new ProcessStartInfo(); startInfo.FileName = System.Environment.GetEnvironmentVariable("ComSpec"); startInfo.CreateNoWindow = true; startInfo.UseShellExecute = false; startInfo.Arguments = string.Format(@"/c somebat.bat {0}", param); Process process = Process.Start(startInfo); process.WaitForExit(); return process.ExitCode; } } }
System.Diagnostics.Process
でcmd.exeを立ち上げてやる。Process
の引数にはSystem.Diagnostics.ProcessStartInfo
を与えてやる。ProcessStartInfo
のFileName
にcmd.exeを与えてやり、Arguments
に/c
オプションを付けてbatファイルのpathを入れる。
batの呼び出しを非同期にしてなくて悲しい。
追記 20120729
非同期にした。.NET Framework 4ならasync
, await
が使える筈だが、.NET Framework 3.5なのでThreadを書く。
using System; using System.Diagnostics; using System.Threading; using System.Windows; namespace SomeApp { public partial class Window1 : Window { private string Param; public Window1() { InitializeComponent(); } private void buttonAction_Click(object sender, RoutedEventArgs e) { labelStatus.Content = "Wait..."; Param = textBoxParam.Text; var thread = new Thread(new ThreadStart(ThreadEntry)); thread.IsBackground = true; thread.Start(); } private void ThreadEntry() { int exitCode = CallBatch(Param); Dispatcher.BeginInvoke((Action)delegate() { if (exitCode == 0) labelStatus.Content = "Done!"; else labelStatus.Content = "Failed."; }); } /// <summary> /// This may take while. /// </summary> /// <param name="param"></param> /// <returns>Exit code.</returns> private int CallBatch(string param) { var startInfo = new ProcessStartInfo(); startInfo.FileName = System.Environment.GetEnvironmentVariable("ComSpec"); startInfo.CreateNoWindow = true; startInfo.UseShellExecute = false; startInfo.Arguments = string.Format(@"/c somebat.bat {0}", param); Process process = Process.Start(startInfo); process.WaitForExit(); return process.ExitCode; } } }
呼び出されたthreadからは、Window側のthis
を見れない事に注意。compileは通るが、実行時errorに成る。依ってDispatcher.BeginInvoke(Delegate action, object[] param)
を使い非同期に実行する。行って (Thread) 戻る (Invoke) ので、二重の非同期。