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

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

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

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

マクロ

定義された処理手続きに応じて、どのような一連の処理を行うのかを特定させるルールをマクロと呼びます。

Q&A

解決済

4回答

19714閲覧

マクロでメッセージボックスの操作(クリック)

4n5

総合スコア16

VBA

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

マクロ

定義された処理手続きに応じて、どのような一連の処理を行うのかを特定させるルールをマクロと呼びます。

0グッド

0クリップ

投稿2018/10/12 17:58

マクロで別Bookのマクロを実行したいです。
Book1→Book2→Book3...
その際に各Bookのマクロは全部同じです。
マクロは3種類あり、全てを順に実行していきます。
また全てのマクロにメッセージボックスが表示されています。
(完了後の確認ボタンやマクロ途中での選択ボタン有り)
現在ここで躓いておりまして、マクロでメッセージボックスのボタンをクリックすることは可能でしょうか?
お分かりになる方、ご教授のほどよろしくお願い致します。

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

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

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

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

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

guest

回答4

0

ベストアンサー

細かい単位での強引な解決はできますが、現実的には難しいでしょう。

他のマクロの処理を以下のように分割し、「実行したい処理本体」を呼び出すのがあるべき姿です。

  • 実行したい処理本体
  • MsgBoxでユーザーから情報を受け取って「実行したい処理本体」に渡して実行する、「実行したい処理本体」を実行し最後に情報を見せる処理

一応。MsgBoxの操作の強引な解決方法の案です。

VBAのほとんどの処理は、「ある命令が完了したら次の命令へ進む」という同期処理です。
そのため、MsgBoxが表示された時点で、Excel上のVBAは入力待ちとなり動作が止まります。
入力待ちの間は、Excel.Application.OnTimeメソッドなどによる予約実行も行われません。

ただし、動けないのはExcelであって、「他のプログラムからMsgBoxを操作する」というアプローチであれば操作は可能です。
また、VBAのShell関数を使うと、任意の外部プログラムを非同期で実行出来ます。

これらを踏まえたサンプルが以下になります。Excel上の「マクロ」(Alt+F8)から実行してください。

vba

1'Excel上の「マクロ」から実行すること(VBAのエディタから実行しないこと) 2Public Sub SendKeysToMsgBoxSample() 3 4 Const PsCmd = _ 5 "powershell.exe -Sta -Command " & _ 6 "<# SendKeysを使うためのライブラリ読み込み #>" & _ 7 "Add-Type -AssemblyName System.Windows.Forms;" & _ 8 "<# ちょっと待機(要調整) #>" & _ 9 "Start-Sleep -Milliseconds 1000;" & _ 10 "<# Enterキー送信(VBAのSendKeysと同じ構文 #>" & _ 11 "[Windows.Forms.SendKeys]::SendWait('{ENTER}');" 12 13 Call VBA.Shell(PsCmd, vbHide) 'PowerShell で非同期実行 14 Call VBA.AppActivate(Excel.Application.Caption) 15 16 Debug.Print MsgBox("Sample") 17 18End Sub

上記の例ではWindows 7 以降プリインストールのPowerShellというプログラムを使ってMsgBoxを操作しています。

以下の処理を実行しています。

powershell

1<# SendKeysを使うためのライブラリ読み込み #> 2Add-Type -AssemblyName System.Windows.Forms; 3<# ちょっと待機(要調整) #> 4Start-Sleep -Milliseconds 1000; 5<# Enterキー送信(VBAのSendKeysと同じ構文 #> 6[Windows.Forms.SendKeys]::SendWait('{ENTER}');

この方法を使った場合の問題は、外部のマクロの処理時間がどの程度かかるのかわからない点です。

外部のマクロを実行する前に上記のサンプルを実行する必要がありますが、どの程度待てば良いのかがわからないため、ちゃんと処理できる保証がありません。


181016追記:汎用化

vba

1'やっていることは`SendKeysToMsgBoxSample`とほぼ同じ 2Public Sub SendKeysToMsgBoxSample2() 3 'Enterキー送信、1000ミリ秒(1秒)待機、Excelを対象 4 AsyncSendKeys "{ENTER}", 1000, Excel.Application.Caption 5 Call MsgBox("Sample") 6 7End Sub 8 9 10'非同期SendKeys 11 'keyStroke:送るキー文字列 12 'delayMilliSec:待機ミリ秒 13 'appCaption:対象のウィンドウのタイトル 14Public Sub AsyncSendKeys( _ 15 keyStroke As String, _ 16 delayMilliSec As Long, _ 17 appCaption As String) 18 19 'デバッグ時は -NoExit スイッチを付けるとPowerShell側の状態を確認しやすい 20 '"powershell.exe -Sta -NoExit -Command " & ~ 21 Const PsCmd = _ 22 "powershell.exe -Sta -Command """ & _ 23 "<# SendKeysなどを使うためのライブラリ読み込み #>" & _ 24 "Add-Type -AssemblyName Microsoft.VisualBasic;" & _ 25 "<# ちょっと待機(要調整) #>" & _ 26 "Start-Sleep -Milliseconds $WaitMilliSec;" & _ 27 "[Microsoft.VisualBasic.Interaction]::AppActivate('$Caption');" & _ 28 "<# キー送信(VBAのSendKeysと同じ構文 #>" & _ 29 "(New-Object -TypeName Microsoft.VisualBasic.Devices.Keyboard).SendKeys('$KeyStroke', $true);""" 30 31 Dim execCmd As String 32 execCmd = VBA.Replace(VBA.Replace(VBA.Replace(PsCmd, _ 33 "$WaitMilliSec", delayMilliSec), _ 34 "$Caption", appCaption), _ 35 "$KeyStroke", keyStroke) 36 37 'PowerShell で非同期実行 38 'デバッグ時はvbHideを他のものにして、PowerShellのウィンドウが見えるようにする 39 Call VBA.Shell(execCmd, vbHide) 40End Sub

powershell

1<# SendKeysを使うためのライブラリ読み込み #> 2Add-Type -AssemblyName Microsoft.VisualBasic; 3<# ちょっと待機(要調整) #> 4Start-Sleep -Milliseconds $WaitSec; 5[Microsoft.VisualBasic.Interaction]::AppActivate('$Caption'); 6<# キー送信(VBAのSendKeysと同じ構文 #> 7(New-Object -TypeName Microsoft.VisualBasic.Devices.Keyboard).SendKeys('$KeyStroke', $true);

投稿2018/10/13 01:48

編集2018/10/16 11:26
imihito

総合スコア2166

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

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

TanakaHiroaki

2018/10/13 02:52 編集

これはすごいです。 イベントプロシージャを使って同じようなことにトライしたことが ありますが、「ある命令が完了したら次の命令へ進む」という同期 処理であるため、VBAで実現できない処理だと思っていました。
4n5

2018/10/15 22:23

遅くなりすいません。 助言いただきありがとうございます。 こちらのマクロ単体ですとすぐ完了しましたが、外部マクロのメッセージボックスが表示されてからは結構時間がかかるみたいで完了に至る目途が立たずでした。。。 powershellの設定などはございますか? またVBAの参照設定も何か必要でしょうか? 質問ばかりで申し訳ありませんがご教授のほど宜しくお願い致します。
imihito

2018/10/16 11:37 編集

改めて前提として、 あるべき姿から外れた方法のため、外乱に弱く非常に不安定な処理です。 そのため、これを使わずに済むのがベストです。 上手くいかない可能性として - 待ち時間が足りないのでMsgBoxが出る前にPowerShellが終了している - Excelからフォーカスが外れて、他のウィンドウにキーが送信されている などがあります。 条件を指定しやすくした`AsyncSendKeys`プロシージャを追記しましたので、そちらで試してみてください。 また、プロシージャ内部のコメントを参考にPowerShellの実行状況も確認してみてください。
4n5

2018/10/18 18:30

ありがとうございます! たぶん私のやり方が間違っていると思うのですが、なぜかPowerShellの実行状況は確認できずでしたが、MsgBoxのOKを送信できました。 しかし、この後に出てくる選択ボタンですが、2つ目のマクロの処理途中で出てくるのでBookによって処理するデータ量が違うためタイミングが違います。 これだと待機時間を指定して・・・というよりMsgBoxが出てきたタイミングで、とした方が現実的かと思うのですが可能でしょうか? 質問ばかりで申し訳ありませんが宜しくお願い致します。
TanakaHiroaki

2018/10/18 20:19 編集

VBAからPowerShell非同期実行できるだけで十分ではないでしょうか。非同期実行を開始した時点で予測制御しているので、タイミングコントロールできないと理解しました。
imihito

2018/10/18 22:09

> 処理するデータ量が違うためタイミングが違います その可能性が予測されたため、回答の最初に「現実的には難しいでしょう」としています。 PowerShell側の処理を作り込めば不可能では無いでしょうが…
4n5

2018/10/18 22:51

>回答の最初に「現実的には難しいでしょう」としています。 そうでした。。。 VBAだけでなくPowerShellを使用するという初心者の私には発想出来なかったことを教えていただけただけでもかなり大きい収穫となりました。 何とか別の策を考えるなどして試行錯誤してみます。 ありがとうございました!
TanakaHiroaki

2018/10/18 22:55

素人の直感で恐縮ですが、  imihitoさまのPowerShell非同期実行  iruyasさまのVBAによるSendKeys の合わせ技で実現できそうな気がします。
ExcelVBAer

2018/10/19 00:15

感覚が伝わってなさそう。。。 技術的に不可能ではないけど、 仕事で採用されるレベルではないかと。 自分なら、外から実行した時に何か引数を渡して、 メッセージボックスを出さない分岐をしますね。 あえてイバラの道を進みたくないので。
TanakaHiroaki

2018/10/19 01:34 編集

いつもありがとうございます。 レベルは違えどVBAを愛するものとして、ExcelVBerさまの書き込みを心強く思っています。 最近はやりのRPAは、正にこのレベル(不安定なアプリケーション自動操作)であっても、VBAを凌駕しているよう誤解されているのではないでしょうか。(話題が横道にそれ、すみません。)
ExcelVBAer

2018/10/20 13:37

コメントありがとうございます! なんか嬉しいものですね! RPAについてはもマクロの記録に近いものから、 プログラミングレベルのものまであるように感じています。 IT化が進むのはいいと思うのですが、 使う側がシステマチックな考え方でないと、 結局はスパゲッティなコードが増えるだけでしょうねぇ... 1行でも多く、よいコードを残せるよう 頑張っていきたいものです。
guest

0

メッセージボックスを表示させる目的はなんでしょうか。
そして、それをマクロでクリックする目的はなんでしょうか。

(完了後の確認ボタンやマクロ途中での選択ボタン有り)

から推測するに、
ユーザーに確認や選択させるためのメッセージを表示させて、
一定時間経過しても、ユーザーからの操作がなかったら既定の処理を実行する、
ということかと思いますが、どうですか。

だとするなら、下記のリンク先の方法が使えます。

Office TANAKA - Excel VBA Tips[自動的に閉じるMsgBox]

あるいは、
「処理実行中」というメッセージを表示させて、バックグランドで処理を実行して、処理が終了したら、メッセージを閉じる、
というのか目的なら、ユーザーフォームをモードレスで表示させて、処理終了後に閉じるれはいいでしょう。

投稿2018/10/18 10:48

hatena19

総合スコア33699

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

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

4n5

2018/10/18 22:48

回答ありがとうございます。 しかしながらmattuwan様にも返答いたしましたが、別Bookのマクロのコードはこちらでイジらずやらなければいけないため、難しいかもしれません。 もし別のマクロを修正できる場合は参考にさせていただきます。
guest

0

別ブックから実行したときはフラグを立てて条件分岐してはいかがでしょうか?

Book1のマクロ>>

Excel

1Sub test1() 2 Application.Run "Book2!test2", True 3End Sub

Book2のマクロ>>

Excel

1Sub Main() 2 test2 False 3End Sub 4 5Sub test2(ByVal flg As Variant) 6 If flg = False Then 7 MsgBox "???" 8 End If 9End Sub

投稿2018/10/18 07:59

mattuwan

総合スコア2136

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

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

4n5

2018/10/18 22:45

回答ありがとうございます。 しかしながら別Bookのマクロのコードはこちらでイジらずやらなければいけないため、難しいかもしれません。。。
guest

0

キーボード操作のみで実行可能なものなら、
SendKeys ステートメントを使って操作できる可能性はあります。
実際の所は、やってみないと分かりませんが...

投稿2018/10/13 00:34

iruyas

総合スコア1067

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

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

4n5

2018/10/15 22:17

sendkeysの手がありましたか。 思い通りに動いてくれればいいのですが。 助言いただきありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問