20861


VisualBasic（.NetFramework4.0）Windows10でプログラミングをしております。

system.diagnostics.process.startでDOSプロンプト（CMD.EXE）を起動しその画面に表示されているテキストを取得（範囲選択＆コピーでクリップボード保存）したく思いますが、WindowsAPIでどのような関数を使用すれば良いのか検討が付きません。

起動したプロセスから取得したMainWindowHandleを対象とした、もしくは引数に取る関数ではないかと想像しているのですがご存知の方おられましたらお助けお願いできますでしょうか？

よろしくお願いします。


CC BY-SA 3.0
2016-01-12T05:30:31.143
20847
2017-02-09T13:14:52.040
2016-01-12T07:22:40.533
8000
10607
question
vb.net winapi
VBで起動したDOSプロンプトに表示されているテキスト（表示内容）の取得方法


まず、テキストをどう保持してどう描画するかはアプリケーションによって様々ですから、「ウィンドウハンドルを渡せばウィンドウに表示されているテキストを取り出せる」といった汎用的なAPIは存在しません。

cmd.exe
をはじめとするコンソールアプリケーションの場合、例のウィンドウはWindowsが管理しているのでコンソールに表示されている文字を読み取るAPIもあります。ただし「現在のプロセスのコンソールウィンドウから読み取る」という形になるので、

  * `AttachConsole()` で対象のプロセス（cmd.exeなど）のコンソールウィンドウにアタッチし、
  * `GetStdHandle()` でスクリーンバッファのハンドルを取得し、
  * `GetConsoleScreenBufferInfo()` でスクリーンバッファの大きさを調べ、
  * `ReadConsoleOutputCharacter()` で任意の範囲の文字を読み取る

という流れになります。別のプロセスから読み取る際には `FreeConsole()` で切り離したうえで、上記と同じことを繰り返します。

参考： [コンソールへのアタッチ -
EternalWindows](http://eternalwindows.jp/windevelop/console/console06.html)

* * *

ただこの場合、出力されたという通知は受けられないので定期的に確認する必要がありますし、どこからどこまでが新しい出力なのかも自分で判別する必要があります。改行と折り返しの区別もつきません。

「ボタンを押したらその時点での画面を取り込む」程度ならいいかもしれませんが、次のようなことをしたいなら標準入出力のリダイレクトの方が簡単かと思います。

  * 自作のアプリからコンソールアプリとやり取りしたい  
⇒ `process.StandardInput` に書き込んで `process.StandardOutput` から読みだす

  * やり取りが画面に表示されるようにしたい  
⇒ `StandardInput` `StandardOutput` を通る内容をテキストボックスなどに表示する

  * ユーザーがコマンドを打てるようにしたい  
⇒ テキストボックスにでも入力させて、 `StandardInput` に書き込む

（コンソールAPIを直接叩くアプリや、[出力がリダイレクトされているかどうかで挙動を変えるアプリ](https://superuser.com/q/352490/423291)の場合は別ですが。）


CC BY-SA 3.0
2016-01-12T12:08:51.283
20861
2016-01-12T12:08:51.283
2017-03-20T10:04:44.677
-1
8000
20847
answer


ちょっと脱線しますが、こちらも参考になるかもしれません。

>
[code]

>     Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
> System.EventArgs) Handles Button1.Click
>       Dim results As String
>       Dim psi As New System.Diagnostics.ProcessStartInfo()
>  
>       'ComSpecのパスを取得する
>       psi.FileName = System.Environment.GetEnvironmentVariable("ComSpec")
>       '出力を読み取れるようにする
>       psi.RedirectStandardInput = False
>       psi.RedirectStandardOutput = True
>       psi.UseShellExecute = False
>       'ウィンドウを表示しないようにする
>       psi.CreateNoWindow = True
>       'コマンドラインを指定（"/c"は実行後閉じるために必要）
>       psi.Arguments = "/c ping 192.168.1.1"
>       '起動
>       Dim p As System.Diagnostics.Process =
> System.Diagnostics.Process.Start(psi)
>       '出力を読み取る
>       results = p.StandardOutput.ReadToEnd
>       '出力された結果を表示
>       TextBox1.Text = results
>  
>       'WaitForExitはReadToEndの後である必要がある
>       '(親プロセス、子プロセスでブロック防止のため)
>       p.WaitForExit()
>     End Sub
>  
[/code]

ここから引用しました。  
<http://soudan1.biglobe.ne.jp/qa5873147.html>

参考になりそうなページ  
<http://dobon.net/vb/dotnet/process/standardoutput.html>


CC BY-SA 3.0
2017-02-09T11:42:41.930
32531
2017-02-09T13:14:52.040
2017-02-09T13:14:52.040
4765
20585
20847
answer