ProcessでCygwinを操作したい!!(2)
今まであれこれと試した結果、ReadLine()の同期処理では、
出力がくるまで、ブロックしてしまい、結果プロセスに残ったりと
不具合がでていたので、それならば、非同期通信でエラーと出力を取ってしまおうという方針に方向転換。
下のテキストボックスにコマンドを改行コードで区切って定義して
あげれば、コマンド実行でcygwin上で実行する。
ちなみにデフォルトでは、ホームフォルダに移動し、main.cをコンパイル&実行&出力を取得する。
以下、コード。
非同期通信でそのままテキストに出力せず、いったんリストに
格納し、lockを使ってスレッドで常に監視しながら出力している。
あと、ここにサンプルコードをアーカイブしたもの。
⇒※ダウンロード
これを使えば色々おもしろいことが出来ると思います。
1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Data; 5 using System.Drawing; 6 using System.Text; 7 using System.Text.RegularExpressions; 8 using System.Windows.Forms; 9 using System.Diagnostics; 10 using System.IO; 11 using System.Threading; 12 13 namespace PipeSample1 14 { 15 public partial class Form1 : Form 16 { 17 private bool processStart_ = false; 18 private Process process_ = null; 19 private List<string> cmdData = new List<string>(); 20 private const string cygwinPath = @"C:\\cygwin\\bin\\bash.exe"; 21 22 public Form1() 23 { 24 InitializeComponent(); 25 } 26 private void processStart() 27 { 28 if (processStart_ == false) 29 { 30 process_ = new Process(); 31 // プロセス実行して、パイプで出力内容を取得したいときは、これ実行パスを指定してください 32 ProcessStartInfo pifo = new ProcessStartInfo(cygwinPath); 33 34 // ストリーム設定 35 pifo.UseShellExecute = false; 36 pifo.RedirectStandardOutput = true; 37 pifo.RedirectStandardInput = true; 38 pifo.RedirectStandardError = true; 39 // ログイン情報 40 pifo.Arguments = "--login -i"; 41 // ワーキングディレクトリ 42 //pifo.WorkingDirectory = Directory.GetCurrentDirectory(); 43 // ウィンドウを表示しない 44 pifo.CreateNoWindow = true; 45 pifo.WindowStyle = ProcessWindowStyle.Hidden; 46 process_.StartInfo = pifo; 47 // ハンドラを設定 48 process_.ErrorDataReceived += new DataReceivedEventHandler(CProcessOutputer.IOErrorDataHandler); 49 process_.OutputDataReceived += new DataReceivedEventHandler(CProcessOutputer.IOOutDataHandler); 50 CProcessOutputer.OutputTextBox = CmdOutputText; 51 CProcessOutputer.OutputThreadStart(); 52 // プロセススタート(bash.exe) 53 processStart_ = true; 54 process_.Start(); 55 // 非同期通信開始 -----> プロセスを起動してから呼ぶ 56 process_.BeginErrorReadLine(); 57 process_.BeginOutputReadLine(); 58 } 59 } 60 /// <summary> 61 /// プロセスを終了する 62 /// </summary> 63 /// <remarks>Disposeでコールしてください</remarks> 64 private void Exit() 65 { 66 // 出力スレッド終了 67 CProcessOutputer.Abort(); 68 // プロセス終了 69 if (process_ != null) 70 { 71 process_.Close(); 72 process_ = null; 73 } 74 } 75 /// <summary> 76 /// コマンド実行 77 /// </summary> 78 /// <param name="sender"></param> 79 /// <param name="e"></param> 80 private void CmdExec_Click(object sender, EventArgs e) 81 { 82 // コマンド実行 83 if( processStart_ == true ) 84 { 85 // コマンドパケットを生成 86 foreach( string cmd in CmdText.Lines ) 87 { 88 cmdData.Add( cmd ); 89 } 90 CmdOutputText.Clear(); 91 // コマンドを実行 92 foreach (string cmd in cmdData) 93 { 94 process_.StandardInput.WriteLine(cmd); 95 } 96 cmdData.Clear(); 97 } 98 } 99 /// <summary> 100 /// ビルドパス 101 /// </summary> 102 /// <param name="sender"></param> 103 /// <param name="e"></param> 104 /// <remarks>今は、機能していない</remarks> 105 private void buildpath_Click(object sender, EventArgs e) 106 { 107 FolderBrowserDialog fd = new FolderBrowserDialog(); 108 109 if (fd.ShowDialog() == DialogResult.OK) 110 { 111 textBox2.Text = fd.SelectedPath; 112 } 113 } 114 /// <summary> 115 /// フォームロード時 116 /// </summary> 117 /// <param name="sender"></param> 118 /// <param name="e"></param> 119 private void Form1_Load(object sender, EventArgs e) 120 { 121 processStart_ = false; 122 processStart(); 123 } 124 125 } 126 /// <summary> 127 /// プロセスアウトプッター 128 /// </summary> 129 class CProcessOutputer 130 { 131 /// <summary> 132 /// 受信パケットリスト 133 /// </summary> 134 private static List<string> outputData_ = new List<string>(); 135 /// <summary> 136 /// 出力テキストボックス 137 /// </summary> 138 private static TextBox outputTextBox_ = null; 139 /// <summary> 140 /// プロセス終了フラグ 141 /// </summary> 142 private static bool processAbort_ = false; 143 /// <summary> 144 /// 出力管理スレッド 145 /// </summary> 146 private static Thread outThread_ = null; 147 /// <summary> 148 /// スケープシーケンスの出力をマッチしないで取得 149 /// そのままデータを受信すると、エスケープシーケンスまで取得するので 150 /// それを省いて受信するため 151 /// </summary> 152 private static Regex outPutRegex = new Regex(@"^[-_\w/)]+.+"); 153 154 /// <summary> 155 /// 出力スレッド開始 156 /// </summary> 157 public static void OutputThreadStart() 158 { 159 outThread_ = new Thread(new ThreadStart(processOutputThread)); 160 outThread_.Start(); 161 } 162 /// <summary> 163 /// 出力テキストボックス設定用 164 /// </summary> 165 public static TextBox OutputTextBox 166 { 167 set{ 168 outputTextBox_ = value; 169 } 170 get 171 { 172 return outputTextBox_; 173 } 174 } 175 /// <summary> 176 /// エラー時出力イベント 177 /// </summary> 178 /// <param name="sendingProcess">プロセス</param> 179 /// <param name="errLine">エラー出力文字列</param> 180 public static void IOErrorDataHandler(object sendingProcess, DataReceivedEventArgs errLine) 181 { 182 if (!String.IsNullOrEmpty(errLine.Data)) 183 { 184 setOutputPacket(errLine); 185 } 186 } 187 /// <summary> 188 /// 標準出力時のイベント 189 /// </summary> 190 /// <param name="sendingProcess">プロセス</param> 191 /// <param name="errLine">エラー出力文字列</param> 192 public static void IOOutDataHandler(object sendingProcess, DataReceivedEventArgs outLine) 193 { 194 if (!String.IsNullOrEmpty(outLine.Data)) 195 { 196 setOutputPacket(outLine); 197 } 198 } 199 /// <summary> 200 /// 出力パケットセット 201 /// </summary> 202 /// <param name="outLine">出力データ</param> 203 private static void setOutputPacket(DataReceivedEventArgs outLine) 204 { 205 if (outPutRegex.IsMatch(outLine.Data)) 206 { 207 lock (outputData_) 208 { 209 outputData_.Add(outLine.Data); 210 } 211 } 212 } 213 /// <summary> 214 /// スレッド終了 215 /// </summary> 216 public static void Abort() 217 { 218 if (outThread_ == null) 219 return; 220 221 if (outThread_.IsAlive) 222 { 223 processAbort_ = true; 224 outThread_.Join(); 225 } 226 } 227 /// <summary> 228 /// データ出力管理スレッド 229 /// </summary> 230 private static void processOutputThread() 231 { 232 while (true) 233 { 234 Thread.Sleep(10); 235 236 // 終了 237 if (processAbort_ == true) 238 { 239 break; 240 } 241 // テキストボックスがnull 242 if (outputTextBox_ == null) 243 { 244 continue; 245 } 246 lock (outputData_) 247 { 248 // セットされているデータを全て出力 249 foreach( string text in outputData_ ) 250 { 251 outputTextBox_.AppendText(text+"\n"); 252 } 253 // クリアにする 254 outputData_.Clear(); 255 } 256 } 257 } 258 } 259 260 }