C# Programming

Image

Processの使い方

開発環境: Visual Studio 2003 

目次

  1. 目次
  2. プロセスの起動方法(その1) 
  3. プロセスの起動方法(その2)
  4. プロセスの起動方法(その3) 標準入力、標準出力の使い方

プロセスの起動方法(その1) 
System.Diagnostics.Process.Start( string filename);
System.Diagnostics.Process.Start( string filename, string args);

System.Diagnostics.Process.Start("cmd.exe");
注意:
このとき渡す文字列には、実行形式のファイルを表す必要はありません。
システムにインストールされているアプリケーションに関連付けられている拡張子を持つ任意のファイルの種類を使用できます。
次の例を参照。
起動例 結果
System.Diagnostics.Process.Start
     ("mailto: xyz@yahoo.co.jp");
新規メイルメッセージを開く。
System.Diagnostics.Process.Start
     ("http://uchukamen.com/");
標準ブラウザーで開く。
System.Diagnostics.Process.Start
     (".../abc.jpg");
WebShotsTray.exe で開く。
System.Diagnostics.Process.Start
     (".../abc.wma");
WMPlayer で開く。

プロセスの起動方法(その2) 
System.Diagnostics.Process.Start( ProcessStartInfo );

System.Diagnostics.Process.Start( ProcessStartInfo );
を使うことにより、もう少し凝ったプロセスの起動が可能になります。
System.Diagnostics.ProcessStartInfo pInfo = new System.Diagnostics.ProcessStartInfo(string filename);
System.Diagnostics.Process process = System.Diagnostics.Process.Start(pInfo);
注意1:
ProcessStartInfo プロパティが有効なのは、プロセスを起動するまでです。
プロセスを開始した後で、これらの値を変更しても影響はありません。

注意2:
pInfo.UseShellExecute = false;
とすることにより、シェルを使用せずにプロセスを起動することができます。
しかし、この場合実行可能形式でないファイルは、起動できません。指定した場合は、次の例外が上がります。
'System.ComponentModel.Win32Exception' のハンドルされていない例外が system.dll で発生しました。
追加情報 : %1 は有効な Win32 アプリケーションではありません。

プロセスの起動方法(その3) 標準入力、標準出力の使い方

次のような機能のForm アプリケーションを作る。
  • cmd.exe をバックグラウンドで起動する。
  • textBox1 の入力を cmd.exe の標準入力へインプットする。
  • cmd.exe の標準出力を、textBox2へ出力する。
Image

スレッドを使わなくても、デッドロックは発生しないので問題ないのは確認しました。

このサンプルコードでは、入力、出力に1つづつのスレッドを起こして cmd.exe 読み書きしています。

textBox1.Text --> WriteThread --> stdin -->
                                                                  cmd.exe
textBox2.Text <-- ReadThread <-- stdout <--

詳細は、ソースコード参照。

注意1: StandardInput を使用する場合は、UseShellExecute が false にする必要があります。

疑問1: TextBox の文字列を受け渡しするのに、メンバーを使っていますが、ちょっとかっこ悪い。
疑問2: lock はしていませんが、問題にはならないと思います。でも、自信がない。。。。
疑問3: ここで作っているスレッドも STA(Single Thread Apartment です。これでいいのかなぁ。。
      間違いや、もっといい方法があったら、だれか教えてください!
日付修正履歴
5/10初期バージョン作成

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

namespace Process
{
        /// <summary>
        /// Form1 の概要の説明です。
        /// </summary>
        public class Form1 : System.Windows.Forms.Form
        {
                private System.Windows.Forms.Button button1;
                private System.Windows.Forms.OpenFileDialog openFileDialog1;
                public System.Windows.Forms.TextBox textBox1;
                public System.Windows.Forms.TextBox textBox2;
                /// <summary>
                /// 必要なデザイナ変数です。
                /// </summary>
                private System.ComponentModel.Container components = null;

                public Form1()
                {
                        //
                        // Windows フォーム デザイナ サポートに必要です。
                        //
                        InitializeComponent();

                        //
                        // TODO: InitializeComponent 呼び出しの後に、コンストラクタ コードを追加してください。
                        //
                }

                /// <summary>
                /// 使用されているリソースに後処理を実行します。
                /// </summary>
                protected override void Dispose( bool disposing )
                {
                        if( disposing )
                        {
                                if (components != null) 
                                {
                                        components.Dispose();
                                }
                        }
                        base.Dispose( disposing );
                }

                #region Windows Form Designer generated code
                /// <summary>
                /// デザイナ サポートに必要なメソッドです。このメソッドの内容を
                /// コード エディタで変更しないでください。
                /// </summary>
                private void InitializeComponent()
                {
                        this.button1 = new System.Windows.Forms.Button();
                        this.openFileDialog1 = new System.Windows.Forms.OpenFileDialog();
                        this.textBox1 = new System.Windows.Forms.TextBox();
                        this.textBox2 = new System.Windows.Forms.TextBox();
                        this.SuspendLayout();
                        // 
                        // button1
                        // 
                        this.button1.Location = new System.Drawing.Point(464, 16);
                        this.button1.Name = "button1";
                        this.button1.TabIndex = 0;
                        this.button1.Text = "Execute";
                        this.button1.Click += new System.EventHandler(this.OnClick);
                        // 
                        // textBox1
                        // 
                        this.textBox1.Location = new System.Drawing.Point(24, 16);
                        this.textBox1.Name = "textBox1";
                        this.textBox1.Size = new System.Drawing.Size(368, 19);
                        this.textBox1.TabIndex = 1;
                        this.textBox1.Text = "";
                        // 
                        // textBox2
                        // 
                        this.textBox2.Location = new System.Drawing.Point(24, 56);
                        this.textBox2.Multiline = true;
                        this.textBox2.Name = "textBox2";
                        this.textBox2.ReadOnly = true;
                        this.textBox2.ScrollBars = System.Windows.Forms.ScrollBars.Both;
                        this.textBox2.Size = new System.Drawing.Size(520, 216);
                        this.textBox2.TabIndex = 2;
                        this.textBox2.Text = "";
                        // 
                        // Form1
                        // 
                        this.AutoScaleBaseSize = new System.Drawing.Size(5, 12);
                        this.ClientSize = new System.Drawing.Size(568, 286);
                        this.Controls.AddRange(new System.Windows.Forms.Control[] {
                                                                                                                                                  this.textBox2,
                                                                                                                                                  this.textBox1,
                                                                                                                                                  this.button1});
                        this.Name = "Form1";
                        this.Text = "Test Process";
                        this.ResumeLayout(false);

                }
                #endregion

                /// <summary>
                /// アプリケーションのメイン エントリ ポイントです。
                /// </summary>
                [STAThread]
                static void Main() 
                {
                        Application.Run(new Form1());
                }

                string result;

                private void ReadThread()
                {
                        result = p.StandardOutput.ReadToEnd();
                }

                string command;

                private void WriteThread()
                {
                        p.StandardInput.WriteLine(command);
                        p.StandardInput.WriteLine("exit");
                }

                public void StartThread()
                {
                        System.Threading.ThreadStart readThread = new System.Threading.ThreadStart (ReadThread);
                        System.Threading.ThreadStart writeThread = new System.Threading.ThreadStart (WriteThread);
                        System.Threading.Thread rThread = new System.Threading.Thread (readThread);
                        System.Threading.Thread wThread = new System.Threading.Thread (writeThread);
                        rThread.Name = "ReadThread";
                        wThread.Name = "WriteThread";
                        rThread.Start ();       //starting the read thread
                        wThread.Start ();       //starting the write thread
                        wThread.Join();
                        rThread.Join();
                }

                System.Diagnostics.Process p;

                private void OnClick(object sender, System.EventArgs e)
                {
                        // プロセスのインスタンスを作る。
                        p = new System.Diagnostics.Process();
                        // プロセスの StartInfo を設定する。
                        // 実行ファイル名。
                        p.StartInfo.FileName = "cmd.exe";
                        // 子プロセスのウィンドウを表示しない。
                        p.StartInfo.CreateNoWindow = true;
                        //  StandardInput を使用する場合は、
                        // UseShellExecute が false になっている必要があります。
                        p.StartInfo.UseShellExecute = false; 
                        // 標準入力、標準出力を使用します。
                        p.StartInfo.RedirectStandardInput = true;
                        p.StartInfo.RedirectStandardOutput = true;
                        // cmd.exe を起動します。
                        p.Start();
                        // cmd.exe で実行するコマンドを取得します。
                        command = this.textBox1.Text;
                        // 標準入出力からリードライトするためのスレッドを起動します。
                        this.StartThread();
                        // cmd.exe が終了するのを待ちます。
                        p.WaitForExit();
                        // 結果を textBox2 へ書き出します。
                        this.textBox2.Text = result;
                }
        }
}