C#のコード上から外部プログラムを起動したら、その処理の結果を受け取る方法を考えてみましょう。C#のコード上から起動した外部プログラムの出力を受け取る方法としては一時ファイルを経由して受け取る方法やクリップボードを経由して受け取る方法などが考えられますが、ここでは外部プログラムの標準出力をそのまま直接受け取る方法について説明します。
外部プログラムを起動してその結果を受け取ることができれば、その外部プログラムをアプリに組み込むことができます。この方法を使えばPythonスクリプトを実行形式(exeファイル)に変換した上で、C#で作成しているアプリに組み込むことも可能になります。
なお、C#コード上から外部プログラムを実行するにはProcessクラスのStartメソッドを用います。詳細については以下の記事をご覧ください。
[toc]プログラムの出力先:標準出力とは?
プログラムで何らかの処理を行った結果を出力する先としては
- 標準出力
- ファイル
- クリップボード
などが考えられます。
ファイルへの出力やクリップボードへの出力はイメージしやすいですが、標準出力とは何なんでしょうか?プログラムには標準出力と呼ばれるデフォルトの出力先が定められていて、通常はコンソール画面への出力が設定されているので、プログラム起動時に特に何も設定しなければ「標準出力=コンソール画面への出力」だと思っていただいて構いません。
標準出力への出力の仕方はプログラミング言語ごとに以下のようになっています。
C#
Console.WireLine("ここへの出力が標準出力");
Java
System.out.println("ここへの出力が標準出力");
Python
print('ここへの出力が標準出力')
ここまで見れば、標準出力がお馴染みのものだということが分かるのではないでしょうか?この標準出力は起動時に何も設定しなければコンソール画面に出力されますが、リダイレクトの設定を行うことでコンソール画面ではなくファイルへの出力としたり、他のプログラムの入力としたりすることができます。
外部プログラムの標準出力をリダイレクトして取得する
ここでは外部プログラムの標準出力をコンソール画面からそのプロセス(Processインスタンス)のStandardOutputへリダイレクトした上で、C#のコード上からその外部プログラムを起動してみましょう。起動する外部プログラムのリダイレクトは、プロセスの起動に用いるProcessStartInfoインスタンスのRedirectStandardOutputをtrueにすることで設定できます。
例:C#の自作プログラムからの標準出力を取得する
それでは例としてC#で作成した外部プログラムの標準出力を取得し、外部プログラムと連携する方法を説明します。
まずは、呼び出される外部プログラムとして単純な文字列を標準出力に出すSampleApp_Calledを作成します。
SampleApp_Called
using System;
class Program
{
static void Main(string[] args)
{
Console.WriteLine("この文字列はSampleApp_Calledから表示されました。");
}
}
この外部プログラム(SampleApp_Called.exe)を「C:\BioTech-Lab」フォルダに配置し、これを呼び出すプログラムを以下のように作成します。
SampleApp
using System;
using System.Diagnostics;
class Program
{
static void Main(string[] args)
{
ProcessStartInfo processInfo = new ProcessStartInfo
{
FileName = @"C:\BioTech-Lab\SampleApp_Called.exe",
CreateNoWindow = true,
RedirectStandardOutput = true,
UseShellExecute = false
};
Process process = Process.Start(processInfo);
process.WaitForExit();
string output = process.StandardOutput.ReadToEnd();
Console.WriteLine(output);
}
}
8-14行目でProcessStartInfo型のインスタンスに必要な情報を登録します。この時、RedirectStandardOutputプロパティをtrueに設定することで、呼び出す外部プログラムの標準出力をStartメソッドで取得できるProcessインスタンスのStandardOutputへリダイレクトすることができます。またここではCreateNoWindowをtrueに設定して外部プログラムを呼び出す際に新しいウィンドウを表示させないようにしています。さらに、UseShellExecuteをfalseに設定してOSのシェルを介さずに直接起動するように設定しています。実際にはUseShellExecuteはtrueでもfalseでもプログラムの動作に違いはありませんでしたが、「UseShellExecuteがtrueだとリダイレクトできなくなる」という情報もあったので、環境によって動作が異なるのかもしれません。
続いて、今設定したProcessStartInfoインスタンスを引数にしてProcessクラスのStartメソッドから外部プログラムを起動し、得られたProcessインスタンスのWaitForExitメソッドでプロセスの終了を待ってから、そのプロセスのStandardOutputを文字列として取得しています。
以上を実行すると、次のように外部プログラムの出力を取得することができます。
例:自作のPythonスクリプトをC#アプリに組み込む
同様のことは実行形式(exeファイル)であればどのようなプログラムであっても可能なので、例えばPythonのスクリプトを実行形式に変換することでC#のコードと連携することも可能です。
まずはPythonのスクリプトを以下のように作成します。
PythonApp
print('この文字列はPythonAppから表示されました。')
続いてこのスクリプトをexeファイルに変換しましょう。詳細は以下の記事をご覧ください。
このexeファイル化したPythonスクリプト(PythonApp.exe)を先ほどと同様に「C:\BioTech-Lab」フォルダに配置し、これを呼び出すプログラムを以下のように作成します。
SampleApp
using System;
using System.Diagnostics;
class Program
{
static void Main(string[] args)
{
ProcessStartInfo processInfo = new ProcessStartInfo
{
FileName = @"C:\BioTech-Lab\PythonApp.exe",
CreateNoWindow = true,
RedirectStandardOutput = true,
UseShellExecute = false
};
Process process = Process.Start(processInfo);
process.WaitForExit();
string output = process.StandardOutput.ReadToEnd();
Console.WriteLine(output);
}
}
以上を実行すると次のような出力を得ることができます。これでPythonスクリプトの標準出力をC#のプログラム上で取得することができ、C#アプリにPythonスクリプトを組み込むことができました。
なお、Python環境を構築できていれば、Pythonスクリプトをexe化せずにそのまま実行することもできます。例えば、「C:\BioTech-Lab\test.py」を実行して戻り値を受け取る場合は次のようにします。
ProcessStartInfo processInfo = new ProcessStartInfo
{
FileName = "python",
Arguments = @"C:\BioTech-Lab\test.py",
CreateNoWindow = true,
RedirectStandardOutput = true,
UseShellExecute = false
};
Process process = Process.Start(processInfo);
process.WaitForExit();
string output = process.StandardOutput.ReadToEnd();
コメント