2014年11月30日

C#で指定コマンドを別プロセスで起動

   このエントリーをはてなブックマークに追加 Clip to Evernote
どう書く?orgに感謝を込めて」シリーズ その52

■問題 (出題者 : todogzm さん)
与えられた文字列のコマンドを、別プロセスで実行してください。 異なるPIDのプロセスが立ち上がり、指定したコマンドを実行することが条件です。
あわせて、実行結果のリターンコードと、別プロセスが出力した標準出力を受け取る方法も記載してください。
今回投稿する上で、別プロセスとして実行するコマンドの与え方は自由ですが、実行した結果、何らかの損害を与えるようなコマンドは埋め込まないようにお願いします。

以前掲載した「外部の実行ファイルを呼び出し」と「標準入力と標準出力のリダイレクト」の知識があれば、難しくありませんね。
起動したコマンドが出力した標準出力の内容を取り込めるので、知っていれば役立つときがあるかもしれません。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace Doukaku.Org {
    class Program {
        static void Main() {

            // 標準出力をリダイレクトしてプロセスを起動
            string cmd = "help xcopy";
            int ix = cmd.IndexOf(' ');
            string pgm = (ix >= 0) ? cmd.Substring(0, ix) : cmd;
            string args = (ix >= 0) ? cmd.Substring(ix + 1) : "";
            Process p = new Process();
            ProcessStartInfo psi = new ProcessStartInfo(pgm);
            psi.Arguments = args;
            psi.RedirectStandardOutput = true;
            psi.UseShellExecute = false;
            p.StartInfo = psi;
            p.Start();

            // リダイレクトされた標準出力を読む
            string output = p.StandardOutput.ReadToEnd();

            // プロセス終了を待つ
            p.WaitForExit();

            // 結果を標準出力に表示する
            Console.WriteLine(output);

            // 終了コードの取得
            Console.WriteLine("終了コード={0}", p.ExitCode);

            Console.ReadLine();
        }
    }
}

  

Posted by gushwell at 21:46Comments(0)TrackBack(0)

2014年09月03日

C#で標準入力と標準出力のリダイレクト

   このエントリーをはてなブックマークに追加 Clip to Evernote
どう書く?orgに感謝を込めて」シリーズ その38

■問題 (出題者:にしお さん)
以下のようなプログラムを作ってください。

       * コマンドライン引数を二つ取り、引数で指定されたプログラムを起動する(以下A, B)
       * Aの標準出力をBの標準入力へ、Bの標準出力をAの標準入力へ中継する。
       * A, Bどちらかが終了した場合はもう片方を終了して自身も終了する。

この問題は、標準入力と標準出力のリダイレクトをどうやるかという問題ですね。
ただ、プログラムA,Bとも標準入力待ちから始まると、いつまでたっても待ち状態の ままになってしまうので、どんなプログラムでもOKというわけじゃないですね(たぶん)...
なので、ここでは起動するプログラムA,Bも自作することとしました。

Aは単に標準入力を()で囲んで標準出力に複写することを永遠に続けるだけのプログラム。
Bは最初に文字列を標準出力に出力後に、標準入力の文字列を加工をし、標準出力に出力することを3回繰り返すプログラム。
ただし、これだけだと、それぞれのの出力を食い合って、何をやっているかを確認できないので、 標準エラーにもその内容を出力するようにしています。
つまらない例ですみません m(_ _)m

C#では、プロセスを起動する際のオプションであるProcessStartInfo の RedirectStandardInput、RedirectStandardOutput を true にすることで、リダイレクトが可能になります。

■プログラムA
using System;

namespace Doukaku.Org {
    class ProgramA {
        static void Main(string[] args) {
            while (true) {
                string s = Console.ReadLine();
                var t = string.Format("({0})", s);
                Console.Error.WriteLine("A > " + t);
                Console.WriteLine(t);
            }
        }
    }
}

■プログラムB
using System;

namespace Doukaku.Org {
    class ProgramB {
        static void Main(string[] args) {
            string o = "文字数は?";
            Console.WriteLine(o);
            Console.Error.WriteLine("B > " + o);
            for (int i = 0; i < 3; i++) {
                string s = Console.ReadLine();
                o = string.Format("{0}:{1}文字", s , s.Length);
                Console.WriteLine(o);
                Console.Error.WriteLine("B > " + o);
             }
        }
    }
}

■C#で書いたA,Bを起動するプログラム
using System;
using System.Diagnostics;
using System.Threading;

namespace Doukaku.Org {
    class Program {
        static void Main(string[] args) {
            var pa = ProcessStart("A.exe");
            var pb = ProcessStart("B.exe");
            Relay(pa, pb);
            Relay(pb, pa);
            do {
                pa.WaitForExit(500);
                pb.WaitForExit(500);
            } while ((pa.HasExited & pb.HasExited) == true);
            if (pa.HasExited == true && pb.HasExited == false)
                pb.Kill();
            if (pa.HasExited == false && pb.HasExited == true)
                pa.Kill();
            Console.WriteLine("END");
        }

        static Thread Relay(Process outp, Process inp) {
            Thread thread = new Thread(() => {
                while (outp.StandardOutput.EndOfStream == false) {
                    inp.StandardInput.WriteLine(outp.StandardOutput.ReadLine());
                };
            });
            thread.Start();
            return thread;
        }

        static Process ProcessStart(string cmd) {
            Process process = new Process();
            ProcessStartInfo psi = new ProcessStartInfo(cmd);
            psi.UseShellExecute = false;
            psi.RedirectStandardInput = true;
            psi.RedirectStandardOutput = true;
            process.StartInfo = psi;
            process.Start();
            return process;
        }
    }
}

これを起動すると、以下のような結果が得られます。

B > 文字数は?
A > (文字数は?)
B > (文字数は?):7文字
A > ((文字数は?):7文字)
B > ((文字数は?):7文字):13文字
A > (((文字数は?):7文字):13文字)
B > (((文字数は?):7文字):13文字):20文字
A > ((((文字数は?):7文字):13文字):20文字)
END

  
Posted by gushwell at 22:30Comments(0)TrackBack(0)

2014年05月25日

C#で外部の実行ファイルを呼び出し

   このエントリーをはてなブックマークに追加 Clip to Evernote
どう書く?orgに感謝を込めて」シリーズ その10

■問題 (出題者:ところてん さん)
外部の実行ファイルを呼び出して実行してください。 ただし、実行中にプログラムの実行をブロックする版と、しない版の二つを作ってください。

Processクラスを使えばできますね。それほど難しくありませんね。
RunAndWaitと Runメソッドを作成。Runでは、パラメータ付きで呼び出す例としてみました。

■C#で書いたコード
using System.Diagnostics;
using System;

namespace Doukaku.Org {
    class Program {
        static void Main(string[] args) {
            // mspaint.exeを起動し、終わるまで待つ
            int code = RunAndWait("mspaint.exe");

            // 上のmspaint.exeが終わらないと、次のNotepad.exeは起動しない
            Process p = Run("notepad.exe","a.txt");

            // 直ぐに、Runメソッドから制御が戻る。このプログラムが終了しても、
            // notepad.exeは終わらない。
        }

        // ブロックする版 (終了するまで待って、制御を当プログラムに戻さない)
        static int RunAndWait(string cmd) {
            ProcessStartInfo psi = new ProcessStartInfo(cmd);
            Process process = Process.Start(psi);
            process.WaitForExit();
            return process.ExitCode;
        }

        // ブロックしない版
        static Process Run(string cmd, string param) {
            Process process = new Process();
            process.StartInfo.FileName = cmd;
            process.StartInfo.Arguments = param;
            process.Start();
            return process;
        }
    }
}
  
Posted by gushwell at 22:00Comments(0)TrackBack(0)

2010年06月30日

起動したプロセスの終了を検出する

   このエントリーをはてなブックマークに追加 Clip to Evernote

Processオブジェクトの EnableRaisingEvents を true にすると、 Exited イベントで、プロセスの終了を検出することができます。



イベントハンドラのsender引数には、そのプロセスの Processオブジェクトが 渡ってきますから、
そこから、各種情報を取得することが可能です。
ただ、プロセスは終了してしまっているので、参照できないものもあります。

  
Posted by gushwell at 23:31Comments(0)TrackBack(1)