トップ回答者
コマンドプロンプト用プログラムのGUIフロントエンドを作る際の標準入出力の取り扱い方について質問です。

質問
-
GPGのフロントエンドを作りたいと思ってます。
Processのヘルプを参考に下のプログラムのようにしてみましたが、行き詰まりました。
すみませんが助言をお願いします。下のテストプログラムは、コマンドライン用のGPG.exeを使ったものです。
GPGのヘルプのオプション(-help)では、TextBox2に出力できました。
しかし、暗号化のための引数(-r name -es TextBox1.Text(暗号化対象のフルパス付きファイル))
で実行しようとすると、コマンドプロンプトが立ち上がり、パスフレーズ入力待ちになります。
コマンドプロンプトでパスフレーズを入力すれば、暗号化はできますが、GUIのフロントエンド
を作ろうとしているので、パスフレーズは入力値を使いたいと思います。
テストプログラムではプログラム中に埋め込んでます。
myProcessStartInfo.CreateNoWindow = True
とすると、コマンドプロンプトが出ない代わりに、バックグラウンドでパスフレーズ入力待ちになっているようで固まります。
StandardInputが使えてなさそうです。このような場合、StandardInputとStandardOutputの使い方をどうすればよいでしょうか?
パスフレーズを入力後、既に暗号化したファイルが存在していたら、上書きするかどうかを
聞いてくるので、また入力待ちになったら、yを入力する処理というものも必要そうです。<テストプログラム>
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
Dim TMP As String
TMP = """-r name"" ""-es"" """ & TextBox1.Text & """"
'TMP = " -help"
Dim myProcess As New Process()
Dim myProcessStartInfo As New ProcessStartInfo(GPG_PATH)
myProcessStartInfo.Arguments = TMP
myProcessStartInfo.UseShellExecute = False
myProcessStartInfo.WindowStyle = ProcessWindowStyle.Minimized
myProcessStartInfo.RedirectStandardOutput = True
myProcessStartInfo.RedirectStandardInput = True
myProcessStartInfo.UseShellExecute = False
'myProcessStartInfo.CreateNoWindow = True '<---これを有効にするとコマンドプロンプトが出ない。
myProcess.StartInfo = myProcessStartInfo
myProcess.Start()
Dim myStreamReader As StreamReader = myProcess.StandardOutput
' Read the standard output of the spawned process.
Dim myString As String = myStreamReader.ReadToEnd
Dim myInputStrm As StreamWriter = myProcess.StandardInput
myInputStrm.WriteLine("パスフレーズ")
myProcess.Close()
TextBox2.Text = myString
End Subコマンドプロンプトを表示すると以下のような文字が画面に出ます。
-------------------------------
次のユーザーの秘密鍵のロックを解除するには
パスフレーズがいります:“name <e-mailaddress>”
1024ビットDSA鍵, ID XXXXXXXX作成日付は200X-XX-XXパスフレーズを入力:<---ここで入力待ち
-------------------------------
回答
-
StandardInputが使えてないわけではなく、プログラムがそこまで進んでいません。
「Dim myString As String = myStreamReader.ReadToEnd」はStreamの終端まで読みます。StandardOutputの終端とは一般的に子プロセスの終了まで待つことを指します。
(例外的に、子プロセスが明示的にstdoutを閉じることでも終端に達しますが、そのようなプログラムはほとんどありません。)
そして子プロセスGPGはstdinに入力があるまで待つ、典型的なデッドロックです。
ちなみにProcess.StandardOutputプロパティにはその可能性を指摘する記述があります。同期読み取り操作により、StandardOutput ストリームから読み取る呼び出し元と、そのストリームに書き込む子プロセスの間に依存関係が発生します。この依存関係によってデッドロック状態が発生する場合があります。~
OutputDataReceivedイベントを使うことになるでしょう。サンプルも記載されています。
ReadToEnd()を非同期呼び出しするのもありなのかなぁ…? ちょっとわかりません。- 回答としてマーク (^_^;) 2009年3月30日 14:50
すべての返信
-
StandardInputが使えてないわけではなく、プログラムがそこまで進んでいません。
「Dim myString As String = myStreamReader.ReadToEnd」はStreamの終端まで読みます。StandardOutputの終端とは一般的に子プロセスの終了まで待つことを指します。
(例外的に、子プロセスが明示的にstdoutを閉じることでも終端に達しますが、そのようなプログラムはほとんどありません。)
そして子プロセスGPGはstdinに入力があるまで待つ、典型的なデッドロックです。
ちなみにProcess.StandardOutputプロパティにはその可能性を指摘する記述があります。同期読み取り操作により、StandardOutput ストリームから読み取る呼び出し元と、そのストリームに書き込む子プロセスの間に依存関係が発生します。この依存関係によってデッドロック状態が発生する場合があります。~
OutputDataReceivedイベントを使うことになるでしょう。サンプルも記載されています。
ReadToEnd()を非同期呼び出しするのもありなのかなぁ…? ちょっとわかりません。- 回答としてマーク (^_^;) 2009年3月30日 14:50
-
助言ありがとうございます。
> 「Dim myString As String = myStreamReader.ReadToEnd」はStreamの終端まで読みます。
> StandardOutputの終端とは一般的に子プロセスの終了まで待つことを指します。
私もそうかと思ったので、一度「Dim myStreamReader As StreamReader = myProcess.StandardOutput」とそれに関係した部分をコメントかしてみたのですが、それでもパスフレーズの自動入力ができなかったので、困り果てて質問しました。
OutputDataReceivedイベントのリンク先を見ましたが、どうやらプロセス間通信ということでそちらのプログラミング知識が必要そうですね。
原理はなんとなくわかるつもりでもプログラミングの仕方はまだわかってないので、サンプルを実行してみようとしましたが、同ページのサンプルはそのままでは実行できなさそうなので、実行できずでまた行き詰ってしまいました。
スレッド、プロセス関係のプログラミングの勉強してからGUIフロントエンドを検討しなおした方がよさそう、という自分なりの結論になりました。- 編集済み (^_^;) 2009年3月26日 14:09 一部間違いを修正