VBAで外部プログラムを非表示で実行する方法

このQ&Aのポイント
  • Excel2010のVBAから、外部プログラム(test.exe)を非表示で実行する方法について教えてください。
  • test1のプログラムでエラーを回避する方法、または、test2のプログラムでコマンドプロンプトのウィンドウを非表示にする方法を教えてください。
  • VBAとVBScriptを混同しているかもしれませんが、Excel2010のVBAからtest.exeを非表示で実行し、終了を待ってから次の処理を行いたいです。
回答を見る
  • ベストアンサー

VBAで外部プログラムを非表示で実行するには

VBAとVBScriptを混同しているのかもしれませんがよく分からないので教えてください。 Excel2010のVBAから、外部プログラム(test.exe)をコマンドプロンプトを非表示の状態で実行して、外部プログラムの実行が終了するのを待ってから、次の処理をさせたいのですが、test1のプログラムでは(A)の部分でエラーになってしまいます。また、test2のプログラムでは正しく実行されるのですがコマンドプロンプトのウインドウを非表示にする方法がよく分かりません。 test1のプログラムでエラーをでなくする方法、または、test2のプログラムでコマンドプロンプトのウインドウを非表示にする方法がありましたら教えてください。 ------------------------------------------------------- Sub test1()  Dim ws As Object  Dim we As Object  Dim command As String  command = "C:\test.exe"  Set ws = CreateObject("WScript.Shell")  Set we = ws.Run("%ComSpec% /c " & command, 0, False) '<===(A)  Set we = Nothing  Set ws = Nothing End Sub ------------------------------------------------------- Sub test2()  Dim ws As Object  Dim we As Object  Dim command As String  command = "C:\test.exe"  Set ws = CreateObject("WScript.Shell")  Set we = ws.exec("%ComSpec% /c " & command)  Do Until we.Status   DoEvents  Loop  Set we = Nothing  Set ws = Nothing End Sub -------------------------------------------------------

質問者が選んだベストアンサー

  • ベストアンサー
  • nda23
  • ベストアンサー率54% (777/1415)
回答No.2

Runメソッドを何処で調べましたか? 詳しくはこちらを見てください。 http://msdn.microsoft.com/ja-jp/library/cc364421.aspx 先ず、Aで失敗する理由ですが、Runメソッドの戻り値は何型ですか? 説明を見れば分かると思いますが、整数です。オブジェクトでは ありません。従って、戻り値の型が違うし、Set文を使うのもオカシイ 次に、プログラムの終了を待つなら、Runメソッドの第3引数は 省略するか、Trueを指定すべきです。 test2のExecメソッドはオブジェクトを返しますが、この中には 標準入出力やエラー出力用の出し入れ口があり、人に代わって データを送り込んだり、出力結果を見て、処理を変更するなどを 行う場合に使いますので、今回の仕様では使いません。 尚、DoEventsでグルグル回る処理は絶対にすべきではありません。 必ずSleepを入れるべきだし、DoEventsの使用そのものを避ける べきだからです。この文がどのような効果をもたらすかを理解しており、 それを制御できるだけの技術があれば別ですが・・・

yam2012
質問者

お礼

教えて頂きました間違いの箇所を修正しましたらコンドプロンプトのウインドウが非表示のままで正しく実行することができました。ありがとうございました。 なお、回答の中で、「DoEventsでグルグル回る処理は絶対にすべきではありません。必ずSleepを入れるべきだし、DoEventsの使用そのものを避けるべきだからです。」ということが書かれていて、なぜなのかがよく分かりませんでしたので、いろいろ調べていましたが結局よく分かりませんでした。ネット上でもこのような処理をしているのをよく見かけるのですが(http://officetanaka.net/excel/vba/tips/tips27.htmなど)、どのような問題が起こり得るのでよろしくないのかがよく分からないので教えて頂けないでしょうか。よろしくお願いします。

その他の回答 (2)

  • nda23
  • ベストアンサー率54% (777/1415)
回答No.3

#2です。 DoEvents文を実行すると、溜まっていた各種イベントが実行されます。 これに伴い、イベントプロシージャ(VBA)が実行されたり、セルの 内容が変化することもあります。極端な例ではプロセスの終了も 起こり得ます。本来の処理が中途で終わってしまったり、実行条件の 共通変数の内容が変化する可能性があります。このような事象が発生 することを承知の上で使うなら良いのです。 「何でDoEventsがいけないの?」と質問されるということはこの辺の 事情をご存じないのではないでしょうか? 故に「勧めない」と申し上げたのです。 尚、Sleepを入れないと、CPUタイムスライスを浪費して全体の パフォーマンスに甚大な悪影響が出ます。 SleepはVBAではDeclarationsで以下のように定義します。 Declare Sub Sleep Lib "kernel32" (ByVal 休止時間 As Long) 【使用例】 Do Until we.Status   DoEvents   Sleep 1 '1ミリ秒休止 Loop Sleepを入れないと、CPU使用率は100%近くになるはずです。 Sleepを入れると、CPU使用率はほぼ0です。 尚、Runメソッドで待機をTrueにすれば、上記の問題は起きません。

yam2012
質問者

お礼

DoEventsだけだと少なくとも60%以上には上がっていましたがSleep 1を入れるとほぼ0%に下がっていました。このあたりのことはVBAの書籍ではあまり触れられていないのでとても参考になりました。 これからはSleep 1を入れるようにします。 ありがとうございました。

  • rinkun
  • ベストアンサー率44% (706/1571)
回答No.1

良く分かってないので勘違いがあるかもしれないけど。 test.exeはGUIアプリ? それともコンソールアプリ? GUIアプリならRunに "%ComSpec% /c " は不要で、それで上手くいくかも。 コンソールアプリなら完全に非表示にするのは多分無理なのでウィンドウを7(最小化)にしてみる。

yam2012
質問者

お礼

実行したいのはコンソールアプリの方です。 nda23さんの回答の対策をしましたらコマンドプロンプトのウインドウが非表示のまま実行できました。 また、ウィンドウを7(最小化)でも確認してみましたら、タスクバーにアイコンは表示されますが、コマンドプロンプトのウインドウは非表示で実行できました。 ありがとうございした。

関連するQ&A

  • VBAでdosのcompコマンドの実行結果を得たい

    Excel2010のVBAで、 MS-DOSのcompコマンドの実行結果を取得したいのですが、 以下の方法ではうまくいきませんでした。 どのようにすればよいでしょうか。(Windows7) ------------------------------------------------------------ Sub test()  Dim wshShell As Object  Dim wshExec As Object  Dim command As String  Dim file1 As String  Dim file2 As String  Dim result As String  file1 = "C:\test\0128\test.xlsx"  file2 = "C:\test\0129\test.xlsx"  'command = "dir /d " & file1 & " " & file2     '(OK)  'command = "fc /b " & file1 & " " & file2      '(OK)  command = "comp " & file1 & " " & file2      '(NG)  'command = "echo n | comp " & file1 & " " & file2  '(NG)  Debug.Print command  Set wshShell = CreateObject("WScript.Shell")  Set wshExec = wshShell.exec("%ComSpec% /c " & command)  Do Until wshExec.Status   DoEvents  Loop  If wshExec.StdErr.AtEndOfStream = False Then   'エラー   result = wshExec.StdErr.ReadAll  Else   '正常   result = wshExec.StdOut.ReadAll  End If  Set wshExec = Nothing  Set wshShell = Nothing  MsgBox result End Sub ------------------------------------------------------------

  • VBA 実行時エラーで、"プロパティまたはメソッド

    ・Sheet1(コード) Private Sub CommandButton1_Click() Call aaa End Sub ・Module1(コード) Sub aaa() Dim wb As Workbook Dim ws As Worksheet Workbooks.Open ("c:\test.xls") Set wb = Workbooks("test.xls") Set ws = wb.Worksheets("Sheet1") wb.ws.Range("A2").Value = "CCC" End Sub wb.ws.Range("A2").Value = "CCC"の部分で 以下の実行エラーが出ます。 ------------------------------------------------------------------------ 実行時エラー'438': オブジェクトは、このプロパティまたはメソッドをサポートしていません。 ------------------------------------------------------------------------ Set wb = Workbooks("test.xls") Set ws = wb.Worksheets("Sheet1") の部分で特にエラーも出ないので、オブジェクトの取得は成功していると 思うのですが、WorkSheetオブジェクトのwsからRangeメソッドを呼ぶことが できません。 動かない原因と対策を教えてください!!

  • VBAがとまります。

    フォルダ内の全てのエクセルデータを一つにまとめたいのですが、 下記を実行すると、『実行時エラー1004 アプリケーション定義またはオブジェクト定義のエラーです。』のメッセージが出て先に進みません。対象のデータを開いて実行しても同様でした。 調べましたがよくわかりませんので、ご教示いただけませんでしょうか。 基本的なところかもしれませんが、よくわかりません。 どうぞよろしくお願いいたします。 ------------------------------------------------------- 'プログラム1|プログラム開始 Sub GetExcelDataInFolder() 'プログラム2|シート設定 Dim ws1 As Worksheet Set ws1 = ThisWorkbook.Worksheets("Sheet1") 'プログラム3|FileSystemObjectの設定 Dim fs As FileSystemObject Set fs = New FileSystemObject 'プログラム4|対象フォルダを取得 Dim myfolder As Folder Set myfolder = fs.GetFolder(ThisWorkbook.Path) 'プログラム5|対象フォルダ内の全ファイルを処理 Dim myfile As File For Each myfile In myfolder.Files 'プログラム6|拡張子が「xlsx」のファイルのみを処理 If fs.GetExtensionName(myfile) = "xlsx" Then 'プログラム7|フォルダ内のエクセルを開いてシートを設定 Dim wb As Workbook Set wb = Workbooks.Open(Filename:=myfile) Dim ws2 As Worksheet Set ws2 = wb.Worksheets(1) 'プログラム8|開いたエクセルの最終行を取得 Dim cmax As Long cmax = ws2.Range("A65536").End(xlUp).Row Debug.Print myfile.Name & "のcmax=" & cmax 'プログラム9|開いたエクセルのデータを転記 Dim i As Long For i = 2 To cmax Dim cmax1 As Long cmax1 = ws1.Range("A65536").End(xlUp).Row ws1.Range("A" & cmax1 + 1 & ":E" & cmax1 + 1).Value = ws2.Range("A" & i & ":E" & i).Value Next 'プログラム10|エクセルを閉じる wb.Close 'プログラム11|オブジェクト解放 Set ws2 = Nothing Set wb = Nothing End If Next 'プログラム12|エクセルを保存 ThisWorkbook.Save 'プログラム13|オブジェクト解放 Set myfolder = Nothing Set fs = Nothing 'プログラム14|プログラム終了

  • VBAが止まります。

    フォルダ内の全てのエクセルデータを一つにまとめたいのですが、 下記を実行すると、添付ファイルのメッセージが出て先に進みません。 調べましたがよくわかりませんので、ご教示いただけませんでしょうか。 画像の最上部の『'プログラム0|変数設定の指定Option Explicit』が欄外に はみだしていて直せません、こちらが原因でしょうか。 ------------------------------------------------------- 'プログラム1|プログラム開始 Sub GetExcelDataInFolder() 'プログラム2|シート設定 Dim ws1 As Worksheet Set ws1 = ThisWorkbook.Worksheets("Sheet1") 'プログラム3|FileSystemObjectの設定 Dim fs As FileSystemObject Set fs = New FileSystemObject 'プログラム4|対象フォルダを取得 Dim myfolder As Folder Set myfolder = fs.GetFolder(ThisWorkbook.Path) 'プログラム5|対象フォルダ内の全ファイルを処理 Dim myfile As File For Each myfile In myfolder.Files 'プログラム6|拡張子が「xlsx」のファイルのみを処理 If fs.GetExtensionName(myfile) = "xlsx" Then 'プログラム7|フォルダ内のエクセルを開いてシートを設定 Dim wb As Workbook Set wb = Workbooks.Open(Filename:=myfile) Dim ws2 As Worksheet Set ws2 = wb.Worksheets(1) 'プログラム8|開いたエクセルの最終行を取得 Dim cmax As Long cmax = ws2.Range("A65536").End(xlUp).Row Debug.Print myfile.Name & "のcmax=" & cmax 'プログラム9|開いたエクセルのデータを転記 Dim i As Long For i = 2 To cmax Dim cmax1 As Long cmax1 = ws1.Range("A65536").End(xlUp).Row ws1.Range("A" & cmax1 + 1 & ":E" & cmax1 + 1).Value = ws2.Range("A" & i & ":E" & i).Value Next 'プログラム10|エクセルを閉じる wb.Close 'プログラム11|オブジェクト解放 Set ws2 = Nothing Set wb = Nothing End If Next 'プログラム12|エクセルを保存 ThisWorkbook.Save 'プログラム13|オブジェクト解放 Set myfolder = Nothing Set fs = Nothing 'プログラム14|プログラム終了

  • 【Excel VBA】 WorksheetやRangeオブジェクトとして宣言した変数の開放は必要でしょうか?

    こんばんは。 プロシージャレベルで宣言したWorksheetやRangeなどのオブジェクト変数に対し、 プロシージャを終了する直前に、 Set ○=Nothing を実行して、変数(オブジェクトへの参照)を開放する処理を習慣的行っていました。 これは、絶対に必要な処理なのでしょうか? 開放しないことで不具合が出るケースとはどういう場合なのでしょうか? どなたか、ご教示いただけないでしょうか。 よろしくお願いいたします。 <例> Sub test()   Dim Ws1 As Worksheet      Set Ws1 = Worksheets("Sheet1")   '処理内容      Set Ws1 = Nothing End Sub 尚、CreateObject関数で作成したオブジェクトへの参照などではなく、 あくまでもWorksheetやRangeなどの話です。

  • エクセルvba

    エクセルvbaなのですが Sub test() Dim xlApp As Object Dim xlBook As Object Set xlApp = CreateObject("Excel.Application") Set xlBook = xlApp.Workbooks.Open(ActiveWorkbook.FullName) 'コード・・・ Set xlApp = Nothing Set xlBook = Nothing End Sub これだと Set xlBook = xlApp.Workbooks.Open(ActiveWorkbook.FullName) の部分で、エラーになります。 実行時エラー1004です。 自身ファイルをオブジェクトに格納して操作したいのですがどうすればいいでしょうか?

  • VBAを始めたばかりです。

    VBAを始めたばかりです。 下記でエラー「オブジェクトが必要です」が出ます。 何故ですか。 Sub A_Sample048() Dim mySht1 As Object Dim mySht2 As Worksheet '準備ここまで Set mySht1 = ActiveSheet If mySht1.Type = xlWorksheet Then Set mySht2 = mySht1 MsgBox mySht2.Name Else MsgBox "最前面のシートはワークシートではありません" End If Set mySht1 = Nothing 'オブジェクトの解放 Set mySht2 = Nothing End Sub よろしくお願いします。

  • 表示プログラムについて

    テキストの中の”あいうえお”のような文章を表示させるプログラムを作りたいんですが Private Sub Command1_Click() Open "c:\mydata\test.txt" For Input As #1 End Sub Private Sub Command2_Click() Close #1 End Sub では表示されませんでした。何がおかしいかとかどうすればいいか教えてください。お願いします。

  • VBAでDOS プロンプトを使いたいのですが・・・

    デスクトップの\dataフォルダに、名前を付け替えたいファイルが多数あります。 それらのファイル名(旧名)と、変更したい名前(新名)は、エクセル上の2列に 入力済みです。VBAを使って、dosプロンプトのRENを実行しようとしましたが、 多くのファイル名にスペースが含まれるせいか、大半が変更できませんでした。 良い方法があれば、教えてください。どうかよろしくお願いします。 ※作成したプロシージャは以下の通りです。 Sub ファイル名変更() Dim カウンタ As Integer For カウンタ = 2 To 1000 Dim wsh As Object, wexec As Object, cmd As String Dim 旧名 As String, 新名 As String Set wsh = CreateObject("wscript.shell") 旧名 = Cells(カウンタ, 1).Value     '旧名はA列にある 新名 = Cells(カウンタ, 2).Value    '新名はB列にある cmd = "ren c:\users\me\desktop\data\" & 旧名 & " " & 新名 Set wexec = wsh.Exec("%comspec% /c " & cmd) Set wexec = Nothing Set wsh = Nothing Next End Sub

  • エクセルVBE実行時のエラーの意味とその対処方法

    Windows Vistaでエクセル2007を使用しています。 添付の画像のエクセルファイルのVBEに 本文最後のコードを記述して実行させようとすると 下記のようなエラーが出ます。 (実行内容はsheet1の表の内容を sheet2で円グラフとして作成することです) 『実行時エラー'91' オブジェクト変数またはWithブロック変数が設定されてません』 ○質問 1.上記のメッセージの意味を教えてください 2.デバックすると10行目の 『Set Grp1 = WS2.ChartObjects.Add(50, 50, 320, 200)』 がデバックされます。この記述のどこがおかしかったのでしょうか? エクセルVBAにお詳しい方、何とぞご教示お願いします。 なお、コードの内容は以下の通りです。 Sub グラフ作成() Dim WS1 As Worksheet Dim WS2 As Worksheet Dim Grp1 As ChartObject Set WS = Worksheets("sheet1") Set WS = Worksheets("sheet2") Set Grp1 = WS2.ChartObjects.Add(50, 50, 320, 200) Grp1.Chart.ChartType = xl3DPieExploded Grp1.Chart.SetSourceData Source:=WS1.Range("C3:D14"), PlotBy:=xlColumns Worksheets("sheet2").Activate Set WS1 = Nothing Set WS2 = Nothing Set Grp1 = Nothing End Sub