16ビットアプリケーションの標準入出力をリダイレクト

FORTRANで書かれた古いMS-DOSプログラムを.NET/Linkを使ってMathematicaから操るパッケージを作っていたところ、 Process.StartInfo.RedirectStandardInputRedirectStandardOutputTrueを設定してもまったく標準入出力をリダイレクトできなかった。(※OSはVista 32bit)

いろいろ試してみたところ、16ビットのプログラムだとリダイレクトができないらしいということが分かった。 さてどうしたものかとさらにいろいろ打開策を探してみた結果、

  1. FileName"cmd.exe"を設定して、Process.Start()でプロセスを起動。
  2. 必要ならStandardInput.WriteLine("cd 16ビットプログラムのディレクトリ")としてカレントディレクトリを移動。
  3. StandardInput.WriteLine("***.EXE")として16ビットプログラムを起動。

とcmd.exeを間に挟むことにより、16ビットのプログラムに対しても標準入出力のリダイレクトが行えることが分かった。

以下はMathematica+.NET/Linkによるサンプル。 標準出力は書き出されるたびにイベントハンドラで捕捉してoutputsに追加するので、Dynamic[outputs]などとしておくと、本当のターミナルの挙動に近づく。 最初にcmd.exeの出力(“Microsoft Windows [Version …")が入るので、16ビットのプログラムの出力だけがほしい場合は16ビットプログラム起動後にフラグを立てれば大丈夫。

outputs = {};
outputhandler[o_, args_] := Module[
   {data = args@Data},
   AppendTo[outputs, data];
   ];
NETBlock[
  proc = NETNew["System.Diagnostics.Process"];
  LoadNETType["System.Environment"];
  proc@StartInfo@FileName = Environment`GetEnvironmentVariable["ComSpec"];
  proc@StartInfo@RedirectStandardInput = True;
  proc@StartInfo@RedirectStandardOutput = True;
  proc@StartInfo@UseShellExecute = False;
  proc@StartInfo@CreateNoWindow = True;
  proc@StartInfo@WorkingDirectory = DirectoryName[proc@StartInfo@FileName];
  AddEventHandler[proc@OutputDataReceived, outputhandler];
  proc@Start[];
  proc@BeginOutputReadLine[];
  proc@StandardInput@WriteLine["cd " <> "16ビットプログラムのディレクトリ"];
  proc@StandardInput@WriteLine["******.EXE(16ビットプログラム)"];
  
  proc@StandardInput@WriteLine["16ビットプログラムの標準入力に渡す内容"];
  proc@StandardInput@Close[];
  
  proc@WaitForExit[];
  proc@Close[];
  ];

とはいっても64bit版のWindowsだと16bitのプログラムがそもそも動かない。