はじめに
Unityからexe
を起動して、標準入出力によりやり取りを行う処理を書く必要がありました。
その手法について簡単の書き残しておきたいと思います。
exeを準備する
まずは実験を行うにあたってexe
を用意します。
using System; namespace ConsoleApp { static class Program { private const string ExitLine = "exit"; private static void Main(string[] args) { while(true) { var line = Console.ReadLine(); if (line is null or ExitLine) break; Console.WriteLine(line); } } } }
標準入力で与えられた文字列をそのまま標準出力するコンソールアプリを作成してみました。
これをUnityに入れて、UnityからExeを起動、標準入出力でやり取りを行い、使い終わったらExeを終了する処理を書いていきたいと思います。
UnityにExeを取り込む
UnityプロジェクトのAsset/
以下にStreamingAssets
というフォルダを作成してその中にexeファイル
を入れます。
なぜStreamingAssets
に入れるのかというと、UnityではStreamingAssets
フォルダは特殊なフォルダになっていて、今回の利用にあたって都合がいいからです。
- アセットをそのままの状態でアプリに格納される
- プラットフォームが異なっても、パスを指定するコードを書き換えなくてよい
標準入出力を用いてやり取りする
public class ConsoleClient : MonoBehaviour { // StreamingAssetsフォルダ内なので、プラットフォームが違っても以下のパス指定で大丈夫 private static readonly string FolderPath = Application.streamingAssetsPath + "/ConsoleApp"; private static readonly string FilePath = FolderPath + "/ConsoleApp.exe"; private Process _process; private void Awake() { _process = new Process(); // プロセスを起動するときに使用する値のセットを指定 _process.StartInfo = new ProcessStartInfo { FileName = FilePath, // 起動するファイルのパスを指定する UseShellExecute = false, // プロセスの起動にオペレーティング システムのシェルを使用するかどうか(既定値:true) WorkingDirectory = FolderPath, // 開始するプロセスの作業ディレクトリを取得または設定する(既定値:"") RedirectStandardInput = true, // StandardInput から入力を読み取る(既定値:false) RedirectStandardOutput = true, // 出力を StandardOutput に書き込むかどうか(既定値:false) CreateNoWindow = true, // プロセス用の新しいウィンドウを作成せずにプロセスを起動するかどうか(既定値:false) }; // 外部プロセスのStandardOutput ストリームに行を書き込む度に発火されるイベント _process.OutputDataReceived += OnStandardOut; //外部プロセスの終了を検知する _process.EnableRaisingEvents = true; _process.Exited += DisposeProcess; // プロセスを起動する _process.Start(); _process.BeginOutputReadLine(); } private void Update() { if (Input.GetKeyDown(KeyCode.Z)) { _process?.StandardInput.WriteLine("Hello, World!"); } if (Input.GetKeyDown(KeyCode.X)) { _process?.StandardInput.WriteLine("Onaka suita."); } } private void OnDestroy() => DisposeProcess(); private static void OnStandardOut(object sender, DataReceivedEventArgs e) => UnityEngine.Debug.Log($"外部プロセスの標準出力 : {e.Data}"); private void DisposeProcess(object sender, EventArgs e) => DisposeProcess(); private void DisposeProcess() { if (_process == null || _process.HasExited) return; _process.StandardInput.Close(); _process.CloseMainWindow(); _process.Dispose(); _process = null; } }
コードの説明はコメントを見てもらえればと思うのですが、まず???となりやすいのはProcessStartInfo
の箇所だと思います。
こちらはプロセス起動のときに用いる設定のことになります。設定できる項目は二十数個ありますので、以下の公式ドキュメントのプロパティの箇所を閲覧してみるとそれぞれの仕様を把握することができます。
docs.microsoft.com
後気を付けなければいけないのは以下の点くらいでしょうか。
RedirectStandardInput
がtrue
なら、UseShellExecute
はfalse
でなければならないRedirectStandardOutput
がtrue
なら、UseShellExecute
はfalse
でなければならないProcess.StandardInput
を利用するなら、RedirectStandardInput
がtrue
でなければならないProcess.BeginOutputReadLine
を利用するなら、RedirectStandardOutput
がtrue
でなければならない