none
[Excel VBA] Workbooks.Open の処理中は Application.EnableCancelKey の設定が無効になるのでしょうか RRS feed

  • 質問

  • Application.EnableCancelKey = xlDisabled を設定していてもずっと
    Esc キーを押しっぱなしにしていると Workbooks.Open の処理の
    ところで止まってしまいます。
    (以下はただのテスト用のコードなので特定のワークブックを開いて
    閉じるという非常に無駄な処理を繰り返しているだけですが)

    Sub test()
        Dim i As Long
        Dim j As Long
    
        Application.EnableCancelKey = xlDisabled
        For i = 0 To 5
            For j = 0 To 5
                Workbooks.Open("<開くワークブック>", , True).Close
            Next
        Next
    End Sub
    

    Workbooks.Open の処理中は Application.EnableCancelKey の
    設定が無効なのでしょうか。

    さらに、一度中断すると Application.EnableCancelKey の値が
    勝手に xlInterrupt (1) に戻ってしまいます。
    また、イミディエイトウィンドウやウォッチリストから
    変更しようとしても xlInterrupt 以外の値に変更できません。

    Application.EnableCancelKey のヘルプには

    実行中のプロシージャがなく、Excel が待機状態にある場合は、常に EnableCancelKey プロパティの値は xlInterrupt になります。 取り消しキーをトラップしたり、無効にしたりするには、プロシージャの実行のたびに明示的に EnableCancelKey プロパティに設定する必要があります。

    のように書かれていますが、これはブレークポイントなどによる
    一時停止も対象なのでしょうか。

    2019年6月27日 6:34

すべての返信

  • infadeさん、こんばんは。

    ご質問に対する回答にはなりませんが、次のようなサイトを見つけました。画面の日付を見ると、もう10年近く前からそのような動作になっているようですね。
    QVBAでESCキーを無効にしたいのですが、うまくいきません。

    2019年7月3日 13:16
  • > Workbooks.Open の処理中は Application.EnableCancelKey の
    > 設定が無効なのでしょうか。

    Excel2010で検証しましたが、確かにそのようですね。
    過去にリンク先のような記事がありますので、Openメソッド廻りに不安定要素が内在しているのかもしれません。

    https://support.microsoft.com/ja-jp/help/2701220

    回避策としては、On Error Resume Next で エラー番号 1004 をチェックするような仕組みを導入するとか。
    あと、Openメソッドの前に DoEvents を入れておくと、ややマシになるようです。(とはいえ、ときおり1004エラーが発生します。)


        On Error Resume Next
        
        For i = 0 To 5
            For j = 0 To 5
                Do
                    Err.Clear
                    DoEvents
                    Workbooks.Open("<開くワークブック>", , True).Close
                    If Err <> 1004 Then Exit Do
                Loop
            Next
        Next


    > 一度中断すると Application.EnableCancelKey の値が
    > 勝手に xlInterrupt (1) に戻ってしまいます。
    > (中略)
    > ブレークポイントなどによる
    > 一時停止も対象なのでしょうか。

    ブレークポイントで一時停止状態になると確実に xlInterrupt に戻ります。
    このことから判断して、「ブレークポイントで一時停止状態=Excelが待機状態」とみなしていいと思います。

    2019年7月4日 23:53
  • infadeさん、こんにちは。

    いろいろ試しましたが、ESCキーを押されたときにOpen文でエラーが生じないようにする予防策は、見つかりませんでした。そこで、エラー処理について、いろいろ試行錯誤して、一応、ストレスを感じないで済むと思われるものになりましたので、得られた情報をご紹介します。infadeさんには、無用の話かとは思うのですが、ちょっと奇妙な点がありますので、投稿します。なお、動作確認は、Windows7+Excel2013 及びWindows10+Excel2016で行いました。
    提示されたコードを元に追加部分を斜体字で記します。

    Sub test()
       
    Dim i As Long
       
    Dim j As Long

        Application
    .EnableCancelKey = xlDisabled
       
    For i = 0 To 5
           
    For j = 0 To 5
                on error goto ERROPE
                Workbooks.Open("<開くワークブック>", , True).Close
                on error goto 0       
            Next
       
    Next
        Exit Sub

    ERROPE:
        SendKeys "{ESC}"
        MsgBox "hoge"
        Application.EnableCancelKey =xlDisabled
        Resume

    End Sub

    SendKeys"{ESC}" と MsgBox"hoge" は、これがないと、エラーが相当回数繰り返されて時間がかかるので、入れたものです。MsgBox"hoge"は、表示されませんし、エスケープキーのSendKeysの処理も無効となるようで、動作は止まりませし、しかし、エラーの繰り返しがカットされます。たまたまそういう動作現象にぶち当たったものであって、ハチャメチャな話で、正当なものとは思えませんが、現実にそのように動作します。エラー処理部分でなくても、SendKeysとMsgBoxを組み合わせるとそのようになるようです。間にDoEventsを記すと、MsgBoxが表示されますが、止まりません。

    なお、しつこく何回もESCキーを押すと、何回か後のときは、復帰にちょっと時間がかかる場合があるようです。

    Resume についてですが、Resume Next とすると、1回ファイルのオープンがスキップされてしまうので、それを避けるためにNextは記さずに、エラーが生じたOpen文に処理が戻るようにしたものです。

    aのバグに対処するのにbのバグを利用するような感じで、気持ち悪い点は残りますが、ご参考まで。

    2019年7月5日 3:08
  • KokemomoYamamomo さん

    > MsgBox "hoge"は、表示されませんし

    「ESCを押しっぱなし」 or 「SendKeys"{ESC}"」 によってMsgBoxが即座に閉じられているだけで、一瞬表示されているのでは?

    いずれにしても、MsgBox が一瞬表示されることにより、 DoEventsの代わりの作用となっている気がします。

    2019年7月5日 7:34
  • minmin312さん、こんばんは。

    ご指摘、ありがとうございます。

    まず、SendKeys"{ESC}" とMsgBox”hoge"でも、特にMsgBoxが一瞬でも表示されてちらつく、という様なことはありませんでした。

    SendKeys"{ESC}" とMsgBox”hoge" の2行を DoEvents の1行に置き換えてみたところ、同じように動作しました。

    どうやらminmin312さんのお見立ての通りのようです。

    DoEvents の機能は、発生したイベントがオペレーティングシステムによって処理されるように制御をオペレーティングシステムに戻す、ということですが、それで、なぜ、エラー処理の堂々巡りがカットされてすっきり動くようになるのか、今一、理解しがたいところです。しかし、何はともあれ、SendKeys"{ESC}" とMsgBox”hoge" という訳の分からないコードより、DoEventsの方がすっきりしますね。ご指摘、ありがとうございました。

    2019年7月5日 11:27
  • KokemomoYamamomoさん。


    > 特にMsgBoxが一瞬でも表示されてちらつく、という様なことはありませんでした。

    私のところで一瞬見えることがあるのは、PCスペックが非力だからかも・・・


    > DoEvents の機能は、発生したイベントがオペレーティングシステムによって
    > 処理されるように制御をオペレーティングシステムに戻す、
    > ということですが、それで、なぜ、エラー処理の堂々巡りがカットされて
    > すっきり動くようになるのか、今一、理解しがたいところです。

    先述のとおり、私が試した限りにおいては、DoEvents で必ずカット=回避)される訳ではないようです。
    とはいえ、発生頻度が減るのは確かなようです。
    前回提示したURLにおいても、回避策の一環として DoEvents 関数の実行が提唱されていますし、その原因が調査中ともありますので、不具合かどうかの議論はさておき、事実として受け入れています。


    2019年7月5日 15:51
  • minmin312さん、こんにちは。

    ちょっと説明不足な点があったので、補足します。

    1.DoEventsでエラー処理の堂々巡りがカットできるという点について

    Workbooks.Openの直前に記したDoEventsについて、minmin312さんのおっしゃる通りだと思います。

    エラー処理については、処理のコード中にDoEventsを書かないと、ESCキーの1ヒットだけでも、どうしてなのかわかりませんが、Workbooks.Openのエラーが数十回以上繰り返されて、しばらく、処理が止まります。それは、エラー処理コード中にDebub.Print Err.Number などのコードを記して書き出させると確認できます。DoEventsをエラー処理中に記しておくと、余計なエラー処理が繰り返されることが回避されます。

    2.MsgBoxの表示について

    MsgBoxが一旦表示されているとの貴重な情報、ありがとうございます。残念ながら、当方、Corei3ですが、MsgBoxを現認できませんでした。
    確かに、SendKeys"{ESC}"だけ、または、DoEventsだけ、のマクロでは、ThisWorkbookのワークシートがアクティブになることはありませんでした。SendKes"{ESC}":MsgBox"hoge"の2行のマクロでは、同ワークシートが一瞬アクティブになりますました。これが、MsgBoxが表示されただちに取り消される、という動作故なのでしょう。

    コメント、ありがとうございました。

    2019年7月8日 5:09
  • > 残念ながら、当方、Corei3ですが、MsgBoxを現認できませんでした。

    下記のようにすると視認できるかもしれませんよ。

    SendKeys "{ESC}"
    MsgBox "hoge", vbYesNo

    ※はい、いいえ ボタンが表示されるので、ESCキーを押しても閉じません。

    2019年7月10日 5:25
  • minmin312さん、こんにちは。

    コメントありがとうございます。

    おっしゃる通り、vbYesNoでメッセージが表示され、処理が中断しました。なぜ、vbOkOnlyでは表示されずに処理が中断しないのに、vbYesNoでは表示されて中断するのか、不思議です。

    で、中断してどうなるかを、直後にDeBug.Print Err.Number を記して観察したところ、やはり、ESCキーを押し続けても、1回ごとにMsgBoが表示されエラー処理が繰り返されますが、ESCキーを放すとMsgBox表示後はエラー処理からメインの処理に戻って正常にOpne処理が行われることが観察できました。やはり、エラー処理の中に、ESCキー処理やEoEventsを記すると、無駄なエラー処理の堂々巡りが回避できるということだと思います。しかし、なぜ、ESCキー処理やDoEventsを記さないと、エラー処理の堂々巡りがしばらく続いてしまうのか、不思議です。

    2019年7月10日 5:49
  • > なぜ、vbOkOnlyでは表示されずに処理が中断しないのに、vbYesNoでは表示されて中断するのか、不思議です。

    vbOkOnlyのメッセージボックスは、ESCキーで閉じるからです。


    2019年7月10日 6:01
  • minmin312さん、こんにちは。

    早速のコメント、ありがとうございます。

    MsgBoxのESCキーによる動作に違いがあるとは、認識しておりませんでした。ご教示ありがとうございます。

    もともと、エラー処理の行程が堂々巡りでしばらく時間が空費される中、ESCキーを押したところ、エラー処理からメインの処理に復帰するという動作が見られたので、エラー処理の中にSendKeys"{ESC}"を記したらどうなるか、DebugPrintの代わりにMsgBoxを表示させて確認してみようか、という素朴な発想の試行錯誤から、いろいろ御厄介をお掛けする話になってしまいました。勉強させていただき、ありがとうございました。

    2019年7月10日 6:11