EXEからDOSコマンドを実行、結果(DOSプロンプトに表示される内容)を取得するには

解決


すー  2004-07-20 23:15:53  No: 114924  IP: [192.*.*.*]

こんばんは、すーです。
表題の通りのご質問です。

例えば、pingコマンドをDOS画面で打つと
============================
C:\>ping 192.168.0.3

Pinging 192.168.0.3 with 32 bytes of data:

Reply from 192.168.0.3: bytes=32 time<1ms TTL=30
Reply from 192.168.0.3: bytes=32 time=1ms TTL=30
Reply from 192.168.0.3: bytes=32 time=1ms TTL=30
Reply from 192.168.0.3: bytes=32 time=1ms TTL=30

Ping statistics for 192.168.0.3:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 0ms, Maximum = 1ms, Average = 0ms
============================
となりますが、EXEからpingコマンドを実行し
上記のような結果をそのままStringとして取得し、
プログラム側で、処理したいのです。
普通のshell関数だと、このような結果は取得できないようなのですが、
なにかよい方法はありませんでしょうか。

よろしくお願いします。

環境:
VB.NET 
WIN2000

編集 削除
魔界の仮面弁士  2004-07-21 00:04:45  No: 114925  IP: [192.*.*.*]

Pingが目的なら、WMI の Ping Provider を使って、

 Dim Searcher As New Management.ManagementObjectSearcher( _
   "SELECT * FROM Win32_PingStatus WHERE Address='192.168.0.3'")
 For Each Mng As Management.ManagementObject In Searcher.Get()
   Dim U As UInt32 = CType(Mng("StatusCode"), UInt32)
   If U.Equals(U.Parse("0")) Then
     MessageBox.Show("Success")
   ElseIf U.Equals(U.Parse("11010")) Then
     MessageBox.Show("Request Timed Out")
   Else
     MessageBox.Show("その他のエラー")
   End If
 Next
 Searcher.Dispose()

とか。

標準出力の取得が目的であれば、Processクラスを使って、

 Dim p As New Process
 With p.StartInfo
   .WindowStyle = ProcessWindowStyle.Normal
   .FileName = "PING"
   .Arguments = "192.168.0.3"
   .RedirectStandardOutput = True
   .UseShellExecute = False
 End With
 p.Start()
 p.WaitForExit(1000)
 Trace.WriteLine(p.StandardOutput.ReadToEnd())
 p.Dispose()

とか。

編集 削除
すー  2004-07-21 00:30:37  No: 114926  IP: [192.*.*.*]

魔界の仮面弁士さん、早速のご返事ありがとうございます。
実行したいコマンドはPINGだけに限らないです。
出来れば、実行結果をテキストボックス内に表示したいです。
また、問題がひとつあります。。。

現在、フォーム上のボタンを押したらpingを実行して、その出力結果をテキストボックスに返そうとしていますが、ボタンを押したとたんに、フォームがもうひとつ立ち上がってしまいます。
たぶん、プロセスに関係していることなのでしょうが、原因がわかりません。


併せてお教え願えないでしょうか。

編集 削除
Say  2004-07-21 09:40:54  No: 114927  IP: [192.*.*.*]

時間にシビアな処理でないなら、
DOSコマンドの標準出力をファイルにリダイレクトして、
そのファイルを読んで解析する、という手もあります。

>フォームがもうひとつ立ち上がってしまいます。
フォーム?コマンドプロンプトウィンドウ(通称DOS窓)でなくて?
だとすればどこかでNewしているのでは?

編集 削除
すー  2004-07-21 21:38:40  No: 114928  IP: [192.*.*.*]

sayさん
>時間にシビアな処理でないなら、
実行結果を取得したいだけなので、時間は特に問題にしていません。
が、ファイルには出力したくありません。
メモリ上で処理してしまいたいです。
イメージとしては、通常の関数のように

  戻り値(実行結果)= 何らかの関数(DOSコマンド実行)

となればよいんですが。。。

>フォーム?コマンドプロンプトウィンドウ(通称DOS窓)でなくて?
どこでもNewしていません。
上記でいただいたソースの
  p.Start()
で、プロセスをスタートさせると新しいフォーム(同じ物)が出現してしまいます。

編集 削除
mone  2004-07-21 23:37:04  No: 114929  IP: [192.*.*.*]

StartupInfo構造体がどういうものか調べればすぐに分かると思いますが、
StartupInfo.CreateNoWindow = Trueとすれば画面に別ウィンドウは出ないと思います。

編集 削除
すー  2004-07-21 23:54:29  No: 114930  IP: [192.*.*.*]

mone さん
>StartupInfo.CreateNoWindow = Trueとすれば
下記のようにプロパティを設定してみましたが、
やはりフォームが立ち上がってしまいます。
また、pingの結果も取得できません。。。
====================================================================
Private Sub cmdPing_Click(ByVal sender As System.Object, _
                             ByVal e As System.EventArgs) Handles cmdPing.Click

        Dim p As New Process()
        With p.StartInfo
            .WindowStyle = ProcessWindowStyle.Hidden
            .FileName = "PING"
            .Arguments = Me.ip.Text
            .RedirectStandardOutput = True
            .UseShellExecute = False
            .CreateNoWindow = True
        End With
        p.Start()
        p.WaitForExit(1000)
        Trace.WriteLine(Me.txtPingRslt.Text)
        p.Dispose()

    End Sub


ip         :IPアドレス入力テキストボックス
txtPingRslt:ping結果出力テキストボックス
====================================================================

編集 削除
特攻隊長まるるう  2004-07-22 09:10:09  No: 114931  IP: [192.*.*.*]

>また、pingの結果も取得できません。。。
>        Trace.WriteLine(Me.txtPingRslt.Text)
>txtPingRslt:ping結果出力テキストボックス
…って関数の意味が全く違うじゃないですか(汗)。勘でプログラミング
しないで、ちゃんとヘルプなり何なりで調べてからプログラムに変更
を加えて下さい。教えられたコードに勝手な改造をして『動かない』なんて
言うのは失礼な話だと思いますよ。やるなら…
[VB.NET2003]
        Me.txtPingRslt.Text = p.StandardOutput.ReadToEnd()
でしょうか?

>やはりフォームが立ち上がってしまいます。
       .CreateNoWindow = True
と設定された回答のプログラムだけではフォームは立ち上がりません
でした。もう一度、新規プロジェクトで上記コードだけ実行してみては
どうでしょうか?何かの設定が悪いか、やっぱり Form を  New  してる
筈だと思います。(でないと Form は実体化出来ない筈ですので)

編集 削除
特攻隊長まるるう  2004-07-22 09:28:00  No: 114932  IP: [192.*.*.*]

あ。もう一度確認しますが
>フォーム?コマンドプロンプトウィンドウ(通称DOS窓)でなくて?
      .CreateNoWindow = True
で設定できるのはプロセスが作成するコマンドプロンプトウィンドウ(通称DOS窓)
です。立ち上がるのはフォーム(VB.NETのデザイン画面でボタンを
貼り付けたりできる)ですか?コマンドプロンプトウィンドウ(バック
が黒くてコマンドプロンプトが表示されてて DOS コマンドを入力できる)
ですか?
どちらが立ち上がるのかで全く意味が違います。[VB.NET]のフォームなら
プロセスは関係ないと思います。

編集 削除
すー  2004-07-23 02:50:34  No: 114933  IP: [192.*.*.*]

特攻隊長まるるうさん
ありがとうございます。

立ち上がるのは、コマンドプロンプトではなくフォームです。
プロセスをスタートさせると立ち上がってしまいます。

編集 削除
特攻隊長まるるう  2004-07-23 09:46:24  No: 114934  IP: [192.*.*.*]

フォームは必ず誰かが New しないと実体化できません。
ただし、この『誰か』がプログラマ(彼方)とは限りません。
場合によっては、設定の変更などのタイミングで[VB.NET]が
自動で作成することもあると思います。

新規プロジェクトで試して頂けましたか?デフォルトで作成される
Form1 に
ip              :IPアドレス入力テキストボックス
txtPingRslt :ping結果出力テキストボックス
cmdPing      :実行ボタン
のみを配置し、デザイン画面で cmdPing をダブルクリックして
cmdPing_Click 関数を自動生成し、以下のコードのみ実行しても
フォームは表示されますか?また、表示されるのは部品(ボタンや
テキストボックス)の無い新規フォームですか?フォームのタイトル
(フォームの Name プロパティ。Form1 のデフォルトは Form1 のはず
です)には何と表示されていますか?

    Private Sub cmdPing_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdPing.Click
        Dim p As New Diagnostics.Process
        With p.StartInfo
            .WindowStyle = ProcessWindowStyle.Hidden    ' プロセスを起動するときに使用するウィンドウの状態
            .FileName = "PING"                          ' 起動するアプリケーションまたはドキュメント
            .Arguments = Me.ip.Text                     ' コマンド ライン引数のセット
            .RedirectStandardOutput = True              ' StandardOutput メンバに書き込むかどうか?
            .UseShellExecute = False                    ' プロセスの起動にオペレーティング システムのシェルを使用するかどうか?
            .CreateNoWindow = True                      ' プロセスを新しいウィンドウで起動するかどうか?
        End With
        p.Start()
        p.WaitForExit(1000)
        ' 標準出力
        'Trace.WriteLine(p.StandardOutput.ReadToEnd())
        With Me.txtPingRslt
            .Multiline = True
            .Text = p.StandardOutput.ReadToEnd()
        End With

        ' プロセス破棄
        p.Dispose()
    End Sub

編集 削除
特攻隊長まるるう  2004-07-23 09:58:58  No: 114935  IP: [192.*.*.*]

ああ、ごめんなさい。よく読むと
>プロセスをスタートさせると新しいフォーム(同じ物)が出現してしまいます。

って書いてありますね。やっぱり Form1 が立ち上がりますか?

編集 削除
特攻隊長まるるう  2004-07-23 10:08:34  No: 114936  IP: [192.*.*.*]

追加で質問。プロジェクトの名前(作成されるEXEの名前)
は何にしてます?(新規だと WindowsApplication1 に
なってると思いますが)

編集 削除
すー  2004-07-24 01:39:43  No: 114937  IP: [192.*.*.*]

>特攻隊長まるるうさん
Form1が立ち上がります。
EXEの名前は「ping」です。

編集 削除
特攻隊長まるるう  2004-07-24 08:40:16  No: 114938  IP: [192.*.*.*]

>EXEの名前は「ping」です
もしかしてそれってプロセスで自分の作ったEXE起動してない?(^^;)
…だから自分のフォームが立ち上がるんじゃ?
詳しい回避方法は調べてませんが、とりあえず新規の別プロジェクトで
試してみて下さい。

編集 削除
すー  2004-07-25 21:44:01  No: 114939  IP: [192.*.*.*]

>特攻隊長まるるう さん
ありがとうございました。
ご推測の通り、プロジェクト名(生成されるEXE名)がpingであったため、
フォームが立ち上がってしまっていたようです。

上記でいただいたサンプルで、
  ①pTest
  ②ping
というまったく同様の内容で、プロジェクト名が異なる物を作成し、
結果は
  ①フォームが立ち上がらず、pingの結果が取得できた。
  ②フォームが立ち上がり、pingの結果も取得できない。
でした。

プロセスを立ち上げるようなプログラムを作成するときには、
作成するアプリケーション名にも気をつけなければならないという事を
勉強させていただきました。
皆様には、ご尽力いただき感謝いたします。
自分の調査の甘さが、教えていただく方々にご迷惑をおかけしました。
次回利用させていただくときは、もう少しよい質問の仕方が出来るよう、
努力します。

ありがとうございました。

編集 削除
すー  2004-07-27 01:32:10  No: 114940  IP: [192.*.*.*]

解決つけるの忘れてました。

編集 削除