質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.37%
VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

VBScript

VBScript(Visual Basic Scripting Edition)はMicrosftが開発したスクリプト言語であり、Visual Basicのサブセットです。

WSH

WSH(Windows Script Host)とは、Windows上でテキストファイルに記述したJavaScriptやVBScriptなどのスクリプトを実行するホスト環境のことです。COMを通じたレジストリ操作やWMIへのアクセスが可能で、複雑な処理も行うことができます。

Q&A

解決済

1回答

10727閲覧

VBA or VBSでウィンドウを表示しないでコマンドの結果を取得

xail2222

総合スコア1508

VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

VBScript

VBScript(Visual Basic Scripting Edition)はMicrosftが開発したスクリプト言語であり、Visual Basicのサブセットです。

WSH

WSH(Windows Script Host)とは、Windows上でテキストファイルに記述したJavaScriptやVBScriptなどのスクリプトを実行するホスト環境のことです。COMを通じたレジストリ操作やWMIへのアクセスが可能で、複雑な処理も行うことができます。

0グッド

0クリップ

投稿2021/04/14 14:11

編集2021/04/16 21:36

前提・実現したいこと

VBA or VBSでウィンドウを表示しないでコマンドの標準出力の結果を取得する方法はあるのでしょうか。
何か関連する情報があれば教えてください。
※タイトル変えました。HTA→VBA or VBS

試したこととか

(1)
以下は、ウィンドウが表示されるパターンのHTAです。
WScript.ShellでExecを使って終了を待ってから標準出力の結果を取得しています。
※VBScriptの処理の部分をVBAにコピーして少し修正すればVBAでも動作します。

HTA

1<html> 2<head> 3 <title>Ping</title> 4<body> 5<input type="button" name="button1" value="Ping実行"> 6<br> 7<label id='result'></label> 8 9<script language="VBScript"> 10 sub button1_onClick 11 Dim t_Wsh 12 Set t_Wsh = CreateObject("WScript.Shell") 13 Dim t_Exex 14 Set t_Exex = t_wsh.Exec("ping www.yahoo.co.jp") 15 Do While t_Exex.Status = 0 16 t_Wsh.Run "Timeout.exe /t 1", 0, True 17 Loop 18 result.innerHtml=Replace(t_Exex.StdOut.ReadAll,vbcrlf,"<BR>") 19 Set t_Exex = Nothing 20 Set t_Wsh = Nothing 21 22 End sub 23</script> 24</body> 25</html>

(2)
runで実行してクリップボードに結果を入れて、それを取得
というやり方がネットに記載してありましたが、クリップボードって
Excelに握られてたりする時も問題ないのでしょうか…
どの程度信頼性があるのかよくわかりません。
ファイルへリダイレクトした方が信頼性は高い気がします。

クリップボード経由の方法

(追記 2021/04/15)
APIでパイプから取得ってのを試しています。
radianさんに紹介されたリンク先のコードに少し手を入れて
stdoutとstderrを受け取れるようにしたコードで試している「つもり」です

結果がいまいちしっくりこない。なぜurlだとpingが飛ばないのか
なぜipでpingした場合、一部情報が欠落しているのか。謎です。
結果が以下の通りです。

ping www.yahoo.co.jpの結果 STDOUT ping 要求ではホスト www.yahoo.co.jp が見つかりませんでした。ホスト名を確認してもう一度実行してください。 STDERR RESULT 1 ping 183.79.217.124の結果 STDOUT に ping を送信しています 32 バイトのデータ: 183.79.217.124 からの応答: バイト数 =32 時間 =5ms TTL=55 183.79.217.124 からの応答: バイト数 =32 時間 =4ms TTL=55 183.79.217.124 からの応答: バイト数 =32 時間 =4ms TTL=55 183.79.217.124 からの応答: バイト数 =32 時間 =4ms TTL=55 ?? の ping 統計: パケット数: 送信 = 4、受信 = 4、損失 = 0 (0% の損失)、 ラウンド トリップの概算時間 (ミリ秒): 最小 = 4ms、最大 = 5ms、平均 = 4ms STDERR RESULT 0

上記はwindows8,office 2016(64bit)にてテストしています。

補足情報(FW/ツールのバージョンなど)

os windows10

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

WScript.ShellのExec()で、コンソールアプリを非表示で実行するラッパー
これで行けるんじゃないですかね。(試してません)

(追記)
ExcelVBAでパイプ処理を行う
これだとVBAだけで行けそうですね。

投稿2021/04/15 00:58

編集2021/04/15 11:35
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

xail2222

2021/04/15 01:06

回答ありがとうございます テンポラリファイルにリダイレクトして、その結果を読み込むという手法ですね。行けると思います ただ他の方法はないかも探りたいので、もう少し探ります
退会済みユーザー

退会済みユーザー

2021/04/15 01:27

他言語だと割と簡単に出来そうな処理なので、それをVBAからキックするのが楽そうな気がしないでもないです。(DLL書くとか)
xail2222

2021/04/15 01:37

やるとしたら.netでcom参照可能にするにして、でしょうか。 comとして作ればvbsでも使えそうですし、勉強のためにも1度やってみます
xail2222

2021/04/15 12:17

追記の情報ありがとうございます。 apiでパイプから読み込む方法ですね どうなるか試してみます。
xail2222

2021/04/15 21:53 編集

教えてもらったリンクのコードをコピペしてから、コマンド実行するだけにして あと結果を取得できるようにしたテストコードを作ってみました。 文字数オーバーで質問の箇所に記述出来なかったので記載してませんが。 ※次のコメントでリンク張りました。 pingはなぜだかコマンドで実行したのと結果が違ってます。なぜだろう… 上手く行くコマンドもあります。まだ要検証な感じです。
xail2222

2021/04/15 22:48 編集

以下にモジュールをエクスポートしたものをアップロードしてみました。 ※office 2016 32bit版でテストしてます。 https://heroku-test2222.herokuapp.com/callexecvba/basAPI.bas https://heroku-test2222.herokuapp.com/callexecvba/clsMyShell.cls https://heroku-test2222.herokuapp.com/callexecvba/basTest.bas とりあえずコマンドは実行されます。ただ、前述の通り結果が謎な部分があります。 で、コードの中身についてですが 取得した標準出力を日本語で表示するために1バイトずつ取得してバイト配列に格納してから 最後にStrConv(tmp, vbUnicode)とやって日本語にしてます。 これってもう少しうまくやる方法とかあるのでしょうか。 とりあえず、これで行こうとは思ってはいますが。 なぜStrConv(tmp, vbUnicode)で日本語になるのかは、ちゃんと理解してません。 やってみたら出来ました。と言う感じです…
退会済みユーザー

退会済みユーザー

2021/04/15 23:25 編集

> 取得した標準出力を日本語で表示するために1バイトずつ取得してバイト配列に格納してから > 最後にStrConv(tmp, vbUnicode)とやって日本語にしてます。 > これってもう少しうまくやる方法とかあるのでしょうか。 StrConv関数の説明に、ANSI 形式の Byte 配列を文字列に変換する場合は StrConv 関数を使用します。 と書いてあるし、多分問題ないのではないでしょうか。 ANSIは日本語Windowsのコンソールの標準の文字コードだとCP932(いわゆるShift_JIS)で、VBAは内部的にUnicodeで文字を扱うので、変換すると正しい日本語になったのかもしれません。(多分) 謎な部分については、ちょっと良く判りません。 URLで実行するとホスト見つからないのは不思議ですね。
xail2222

2021/04/15 23:34 編集

バイト配列のままファイル出力してShift_JISで開いてみればわかりますね。 試してみます 1バイトずつ読み込むと言う部分についてはどう思いますか? 元のコードは1024ずつがばっと取ってきてましたが、日本語にしにくかったので1バイトずつに修正しました 謎な部分はとりあえずpingする事が実際の目的ではないので今は置いておくことにします
退会済みユーザー

退会済みユーザー

2021/04/16 01:48 編集

1バイトづつはあまり効率良くないですね。出力大きくなければ問題はないんでしょうけど。
xail2222

2021/04/16 22:52

読み込み方法の改善は色々試している所です。 バイト配列をファイル出力したのをsjisで開いたら日本語で読めました。 StrConvでそこからunicodeにしているという仕組みは理解出来ました。 あと、ファイルへリダイレクトする方法ではきちんとUrlでも動作しログも完全に表示されますね。 こちらの方が安全ですね。
退会済みユーザー

退会済みユーザー

2021/04/17 02:13 編集

パイプ処理のコードを試しにVB.NETに移植してみたら、URLでも普通に出力されたので、何かExcelVBA特有の問題があるのかもしれませんね。安定した方法を採用した方がよいでしょう。
xail2222

2021/04/17 03:28

移植ってAPIを.Netでそのまま使う方法ですか? APIをVB.Netを使う方法をいまいち理解できていないです。というか、多分さっぱりわからない。 「Windows API 呼び出しは、過去においては Visual Basic プログラミングの重要な部分でしたが、Visual Basic .NET ではほとんど必要ありません。 」 https://docs.microsoft.com/ja-jp/dotnet/visual-basic/programming-guide/com-interop/walkthrough-calling-windows-apis って書いてあるから勉強しなくていいや。と思ってたのですが、どうしたものか… 勉強した方が良いのでしょうか。ネットの情報をあまりしらないですが。。 質問と話がそれてきてますね。。。すみません。 回答の内容に戻りまして、ラッパーはごちゃごちゃしているので その肝だと思うファイルへのリダイレクトだけ Dim WScript As IWshRuntimeLibrary.WshShell Set WScript = New IWshRuntimeLibrary.WshShell WScript.Run "cmd /c ping www.yahoo.co.jp 1>出力ファイルパス" って感じで、自分でクラスでも作ってやることにします。
退会済みユーザー

退会済みユーザー

2021/04/17 04:32 編集

> 勉強した方が良いのでしょうか。ネットの情報をあまりしらないですが。。 今回は動作確認用に直接APIを使用してみましたが、実際のところ.NETではAPIのかなりの機能が標準クラスでカバーされているので、殆どAPIを使う必要はないです。 たまにカバーされていない機能の実現や、C・C++のDLLとかを呼び出す必要性があるときに使う事もあるという感じですね。
xail2222

2021/04/17 05:00

Vb.netでAPIを呼ぶ形で移植してちゃんと動くなら、VBAの問題ではなく私のコードの問題な気がします… あと、今回の例であればSystem.Diagnostics.Processを使えば出来そうなので APIを使ってどうやればいいのかというのを質問を投稿すると 「System.Diagnostics.Process」を使いましょうというのが回答になる気がして質問出来ないんですよね。。。
退会済みユーザー

退会済みユーザー

2021/04/17 09:41 編集

まあ.NETでやるならそうなりますね。ちなみに、.NETのProcessクラスの標準入出力リダイレクト処理も内部ではCreatePipeを使用しているようです。 Excelのアドイン作成について触れてるブログがあったので、一応紹介しときます。 https://www.wareko.jp/blog/explanation-of-excels-add-in-vba-com-excel-dna-xll
xail2222

2021/04/17 11:12

紹介ありがとうございます。excelのアドインはxlamアドインしか作ったことがなかったです。 Excelのアドイン作るときに参考にします。 情報としてはありがたいのですが、今回の事例との関連はどういうところなのでしょうか。 COMアドインで関数を作って、それを使うってことでしょうか。
退会済みユーザー

退会済みユーザー

2021/04/17 11:32

最初の方にコメントした、DLL書くの延長線上的な話として紹介しておきました。 VBAの壁をぶち破るのに使えるかもしれません。
xail2222

2021/04/17 12:05

なるほど。DLLの延長線と言えば普通のCOMかなと思ってました。 WScript.Shellだとコマンドの標準出力をファイルへリダイレクトする形でしか取得できないので WScript.Shellの代わりののものをCOMで作ればよいという感じです。 ただのCOMとアドインの違いと言えば COMだとVBA+COMの形になりますが アドインだとVBAが無くても動き、実行しているExcelへのアクセスがやりやすい という事かなと感じています。 Excelのアドインの認識がまだ足りないので正確にはわかってません。
xail2222

2021/04/17 18:21

と、すみません。 そもそもDLLがCOMのことだったでしょうか。 それなら、延長線上的な話ですね。失礼しました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.37%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問