LoginSignup
9
11

More than 3 years have passed since last update.

[C#] コンソールアプリの標準入出力を奪ってゴニョゴニョする

Last updated at Posted at 2017-11-11

やりたいこと

既存のコンソールアプリケーションについて、その標準入出力を非同期で制御してゴニョゴニョしてみる!

ただし、完全なる自由は手に入らない。
深く制御したい場合は、ソースを直接いじってライブラリ化しよう。

要は、「コンソールアプリの機能を自前のアプリケーションに使いたい、でもソースコードいじる程でもない」って時にやること!

環境

Windows10、Visual Studio 2017

すること

例えばFormsアプリケーションにおいて、XXX.exeの標準出力を監視しつつ標準入力してみる
ちなみに、実際に作ったツールは https://github.com/sensuikan1973/Edax_AutoLearning_Tool です

コード


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Sample_Asynchronous
{
    public partial class Form1 : Form
    {
        // 同ディレクトリにあるXXX.exeのパスを取得
        string XXX_Path = Path.GetDirectoryName(Application.ExecutablePath) + "XXX.exe";

        // イベントハンドラ
        public delegate void MyEventHandler(object sender, DataReceivedEventArgs e);
        public event MyEventHandler myEvent = null;

        // 外部プロセス(XXX.exe)を宣言
        Process xxx_process = null;

         /**
         * @brief コンストラクタ
         *        XXX.exeを起動する
         */
        public Form1()
        {
            //イベントハンドラを作成
            myEvent = new MyEventHandler(event_DataReceived);

            xxx_process = new Process();
            // パス指定
            xxx_process.StartInfo.FileName = XXX_Path;

            // 非同期処理のために、ShellExecuteを使わない設定にする
            // BeginOutputReadLine()を利用するための条件
            xxx_process.StartInfo.UseShellExecute        = false;

            // 非同期読込での完了イベントとなるイベントハンドラを設定
            // BeginOutputReadLine()を利用するための条件
            xxx_process.OutputDataReceived += new DataReceivedEventHandler(process_DataReceived);

            // 標準入出力をリダイレクト
            xxx_process.StartInfo.RedirectStandardOutput = true;
            xxx_process.StartInfo.RedirectStandardInput  = true;

            // XXX.exeのコンソールは邪魔なので開かない
            xxx_process.StartInfo.CreateNoWindow         = true; 

            // ついにプロセス起動!
            xxx_process.Start();

            // 標準出力の非同期読込を開始
            xxx_process.BeginOutputReadLine();
        }

        /**
         * @brief 非同期で出力を読み込む
         *        メインスレッドにアクセスする場合は、Invokeメソッドを利用し、スレッドの同期をとる必要がある
         */
        void process_DataReceived(object sender, DataReceivedEventArgs e)
        {
            this.Invoke(myEvent, new object[2] { sender, e });
        }

        /**
         * @brief XXX.exeの標準出力を見て、その内容に応じて処理をしてみる     
         */
        void event_DataReceived(object sender, DataReceivedEventArgs e)
        {
          // --------------------
          // e.Dataの中身を見て、色々処理できる!
          // --------------------

         // 例えば、"星"という文字が出力に含まれていたら、"Starだね"という文字を標準入力してみる
          if (e.Data.Contains("星"))
          {
              xxx_process.StandardInput.WriteLine("Starだね");
          }
        }

        /**
         * @brief Formロード時
         */
        private void Form1_Load(object sender, EventArgs e)
        {
            // Formが閉じられた時のイベントを登録
            this.FormClosed  += new FormClosedEventHandler(Form1_Closed);
        }

        /**
         * @brief Formが閉じられた時の処理
         *        外部プロセス(xxx.exe)をkillする
         */
        private void Form1_Closed(object sender, FormClosedEventArgs e)
        {
            Properties.Settings.Default.Save();
            try
            {
                if (xxx_process != null)
                {
                    xxx_process.Kill();
                    xxx_process.Close();
                    xxx_process.Dispose();
                }
            }
            catch (InvalidOperationException exc) { }
        }

    }
}
9
11
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
11