ページ 11

マルチプロセスとパイプ

Posted: 2011年2月04日(金) 02:12
by あま
マルチプロセスでcmd.exeを起動し、
親プロセスの方で
fgets(command,256,stdin);
command[strlen(command)-1] = '\0'; //改行が含まれるのでNULLで削除
という入力をパイプを介し、子プロセスのcmd.exeへ入力。
その後、cmd.exeの結果をパイプを介し、親プロセスで出力結果を受け取り
printf("%s",buf);
というようにやりたいです。

子プロセスの作成はCreateProcess()でいいとして、
パイプは匿名と名前付きのどちらになるのでしょうか?

匿名パイプは送信か受信のどちらか一つしか選べない。(あやふやです。もしかしたらできる?)
逆に名前付きパイプなら送受信両方できるけど子プロセスは標準のcmdなので名前付きパイプは使えない。(こっちもあやふやです。もしかしたらできる?)

別にcmd.exeだけでなくVC++2010コマンドプロンプトを子プロセスにするのでもいいんですけど。。。

「どうせ結果はまったく同じだからこんなの作っても無意味。」
「普通にcmd.exe起動した方が早い。」
などの回答はごもっともで正論ですが、とりあえずこの回答はなしの方向で。。。

とりあえず、今やってみたことは、
最初に匿名パイプを作成し、次に子プロセスを作成しています。
そこまで出来たら、
WriteFile()でコマンドを送信。という形です。
受け取りはまだ作っていません。
というか作れないから質問しています。

それから子プロセスを作成したあとはcmdを開いたときと同じようなコンソール画面になります(CreateProcess()をやっているので当然です)。
そこでためしに入力してみるとコンソールにMore?と言う文字が返ってくるだけで結果が表示されません。
これはなぜでしょうか?
パイプを通さないでただ単に子プロセスだけを作成した場合はちゃんとコマンドを打つと結果が返ってきます。

開発環境
VC++ 2010
WinXP

Re: マルチプロセスとパイプ

Posted: 2011年2月04日(金) 14:54
by shiro4ao
返信が遅くなりすみません。
パイプは匿名パイプを使ってみました。
コンパイルはWinVista Borland C++ Compilerにて行いました
親がコンソールアプリケーションではないですが、参考になれば幸いです。
親からのコマンドを子プロセス(cmd.exe)に送り、その応答を親に送ってもらいます。
よくわかっていないので何かまずいことをしていたら、すみません。

開始ボタンを押し、送信メッセージのエディットボックスにコマンドを書き込み(改行も書きこんでください)
受信メッセージのエディットボックスに子プロセスからの応答が出てくるはずです。

途中でアンチウイルスソフトが警告するかもしれません(シェル設定変更等)
実験する場合は許可してあげてください。
(ちなみにウイルスバスター2009では反応しませんでしたが、2008は反応しました)

開始ボタンで、パイプを作り、子プロセス、子プロセスからのデータ受信用のスレッドを起こしています
送信ボタンで子プロセスにデータを送信しています
子プロセスからの受信は別スレッドをおこしてそちらで処理しています

受信ができなかったのは、cmd.exeからのデータがいつ来るかがまちまちだったからなのかと考えますが
確証がありません、詳しい方のご意見をお伺いしたいです。

More?についてはよくわかりませんでした、すみません。

参考になれば幸いです。


/*ソース内のコメントの修正をしました*/

Re: マルチプロセスとパイプ

Posted: 2011年2月05日(土) 07:07
by あま
shiro4aoさん。
わざわざサンプルまで作っていただいてありがとうございます。
参考にさせていただき現在はコンソールで動作せています。
とてもよく動いてくれてるので助かってるのですが、
cmdで動作しないコマンド(不明なコマンド)を入力すると
処理が止まってしまいます。(止まるというか本来なら「'~' は、内部コマンドまたは外部コマンド、操作可能なプログラムまたはバッチ ファイルとして認識されていません」というのがcmdで表示されるはずですがそれが返ってきません。)
コンソールに書き直したときに処理がおかしくなり誤動作なのかと思ったので
いただいたサンプルの方で同じようにしてみたところ、やはり止まってしまいました。
これはなぜエラー文は返ってこないのでしょうか?
仕様と捉えるしかないのでしょうか?

Re: マルチプロセスとパイプ

Posted: 2011年2月05日(土) 12:26
by shiro4ao
>あまさん
コンソールに移植していただいたのですね、ありがとうございます。
存在しないコマンドのエラーについて検証していませんでした。すみません。
標準エラー出力にパイプを渡していなかったのが原因のようです。
ソース内の以下の部分を

コード:

	    SI.hStdInput   = pfd_in;          //パイプを指定
	    SI.hStdOutput  = pfd_out;          //パイプを指定
	    SI.hStdError   = NULL;               //標準エラー出力はわかりませんでした。
下記のように変更していただければ

コード:

	    SI.hStdInput   = pfd_in;          //パイプを指定
	    SI.hStdOutput  = pfd_out;          //パイプを指定
	    SI.hStdError   = pfd_out;               //標準エラー出力は同じくpfd_outにする。
動くと思います。
バッファが狭いせいか、一瞬だけ
'hogehoge' は、内部コマンドまたは外部コマンド、
操作可能なプログラムまたはバッチ ファイルとして認識されていません。
というのが出てくると思います。

1つのハンドルでも複数に使えるのでしょうか、確証はありませんが、これで一応動きました。

DuplicateHandle()というAPIがあり、本来はそれを使って読み取り用ハンドルか、書き込み用ハンドル
のどちらかを子プロセスに継承できないようにしておく必要があるようです。

Re: マルチプロセスとパイプ

Posted: 2011年2月05日(土) 14:24
by あま
shiro4aoさん。
できました。
telnetとかまだ使えないのありますけど、その辺は自分でいろいろやってみます。
最悪、Winsockでどうにかします(笑)
今回はありがとうございました。
とても参考になり、助かりました。