[[20160925093025]] 『ブレークポイントを設定する/しないの動作の違いax(ラビット) ページの最後に飛ぶ

[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]

 

『ブレークポイントを設定する/しないの動作の違いについて』(ラビット)

初めまして。
先週からExcel VBAを始めて2週目の初心者です(^^;

現在、ちょっとしたツールを作っているのですが、
ある所で分からないところがありまして、調べても分からなかったので、
ご存知の方がいらっしゃたらと思い、表題の件で、質問致します。

先ず、実現したい機能が
(1)シートに挿入されている、コマンドボタンクリック時のみ

  ツールを終了する。
(2)開いているBookが自分のみの場合は、Excel本体を終了し、
  他にBookを開いている場合は、自分のBookのみ閉じる。
(3)編集内容を破棄するかどうか、
  Excelの保存確認メッセージを表示させない。
です。

自ら調べつつ、(ほぼ)実現出来たのですが、
ある状況下では、意図した結果になりません。

ソースコードを以下に示します。

'*************
' Module1
'*************

' CloseFlag
Public ShouldClose As Boolean

'************
' Sheet1
'************

Private Sub BTN_Close_Click()

    If Not MsgBox("Are you Sure?", vbYesNo) = vbYes Then
        GoTo End_Proc
    End If

    ' CloseFlag On
    Let ShouldClose = True

    If Application.Workbooks.Count = 1 Then
●        Call Application.Quit
    End If
    Call ThisWorkbook.Close

End_Proc:
End Sub

'******************
' ThisWorkbook
'******************

Private Sub Workbook_Open()

    ' Initialize global variables
    Let ShouldClose = False

End Sub

Private Sub Workbook_BeforeClose(Cancel As Boolean)

    ThisWorkbook.Saved = True
    If Not ShouldClose Then
★        Call MsgBox("Click [Close] Button!", vbCritical)
        Let Cancel = True
    Else
        Let Cancel = False
    End If

End Sub

上記を自分のブックのみ開いて、
Sheet1の[Close]ボタンをクリックすると、
(1)〜(3)を満たすように動作するのですが、
Call Application.Quitにブレークポイント(●の箇所)を
設定して、同様にクリックして実行して、
止まった●から、ステップイン実行すると、
Workbook_BeforeCloseイベントの
Call MsgBox("Click [Close] Button!", vbCritical)(★の箇所)
以下が実行されてしまいます。

★が通ったということは、グローバル変数の[ShouldClose]の値が
Falseになっているということなので、
・Application.Quitが実行されることで、グローバル変数の値が破棄された
と考えました。

そうすると、
ブレークポイントを設定しないで実行したときに、
★を通らなかったのは、実現機能的には正常ですが、
コード的には、異常なのではないかと思いました。
(たまたま、自分の環境下ではこうなるのではないかということ)

質問が後回しになり申し訳ありませんが、
「皆様の環境下でも、同様のことが起きるでしょうか?」また、
「今回のような、ブレークポイントを設定した場合と、しない場合の
動作の違いは、何故起こるのでしょうか?」

以上、宜しくお願い致します。

補足:
確実な対策として、グローバル変数を使用せず、
セルに、終了フラグのOn,Offを書き込むようにすれば、
解決ですが、上記のことが気になります。

< 使用 アプリ:Excel2007 & Excel2010、使用 OS:Windows7 >


 >今回のような、ブレークポイントを設定した場合と、しない場合の 
 >動作の違いは、何故起こるのでしょうか?」  

 深く読んでいませんが、これじゃないですか?

  [VBA] Public 宣言された変数の有効期間
http://support.microsoft.com/kb/408871/ja

(半平太) 2016/09/25(日) 11:04


半平太 さん

ご回答ありがとうございます。
リンク先の記事を読みました。
こちらが答えだと思います。

原因はさておき、
「Public 変数がアプリケーション終了時まで有効であることを期待する VBA マクロの実装は、
推奨されません。」ということですから、解決方法に示される、
「非表示にしたワークシートに値を記述します。」にコード変更するようにします。

意図しないことが想定される非推奨の話を、
これ以上追究するのはやめようと思います。

これからも、勉強して参ります。
ありがとうございました。
(ラビット) 2016/09/25(日) 11:29


  あれ? ちょっと私の認識と違うのですけど、

  ブレークポイントで一旦マクロの動作を止めると、
  予期しない初期化が起こるかも知れない、と言うだけなんですけど。

  途中で止めたりしなければ、普通に動かないとおかしいです。

 (そう言う質問じゃないのかもよく分からないです)

(半平太) 2016/09/25(日) 16:10


半平太さん

私の書き方が悪かったですね。すみません。

表題に設定した、
『ブレークポイントを設定する/しないの動作の違いについて』
は解決致しました。

>ブレークポイントで一旦マクロの動作を止めると、
>予期しない初期化が起こるかも知れない
ということなのだと思います。

その意味を込めて、「こちらが答えだと思います。 」
と書きました。

一方で、プロシージャの先頭にキャレットを置いて、
[F8]を叩いて確かめるような場合でも、意図しない
ことが起きてしまうことは、作法として良いのかと思った次第です。

====================
(
この"意図しない"ことが起きる組み合わせが、
「デバッグモードとApplication.Quit」の気がしています。
試しに、Workbook_BeforeCloseイベントには何も記述せず、
以下のプログラムを
(1)ステップインで1行ずつ実行すると、2番目のMsgBoxは表示されず
(2)一気(F5等)実行させると、2番目のMsgBoxは表示される。ただ、
第1パラメータのBookのパスは取得出来ない。
Private Sub CommandButton1_Click()

    Call MsgBox(ThisWorkbook.Path, vbSystemModal)
    Call Application.Quit
    Call MsgBox(ThisWorkbook.Path, vbSystemModal)

End Sub
このようなことがあり、また、
リファレンスも殆ど無いので、
今後、同様の質問が挙がったときのために
備忘録として書いておきます。
)
(ラビット) 2016/09/25(日) 18:06


  今度は、もう少し真面目に読んでみました m(__)m

  >この"意図しない"ことが起きる組み合わせが、 
  >「デバッグモードとApplication.Quit」の気がしています。 

  試しにこんなコードでテストしてみると

  Public ShouldClose As String

  Sub ボタン1_Click()
      Call MsgBox(ThisWorkbook.Path, vbSystemModal, ShouldClose)
      Call Application.Quit
      Call MsgBox(ThisWorkbook.Path, vbSystemModal, ShouldClose)
  End Sub

  Private Sub Workbook_Open()
      Let ShouldClose = "死んでないよ"
  End Sub

  >2番目のMsgBoxは表示される。ただ、 
  >第1パラメータのBookのパスは取得出来ない。 
  でも、オープンして、直ぐ ボタン1をクリックすれば、
  2番目のMsbBoxのタイトルでも、 "死んでないよ" と出ます。

  つまり、グローバル変数は保持されます。
  ・・けど「確実ではないですよ」と言う意味で推奨されないレベルになっている話だと思います。

  一方、Call Application.Quit は、そんなグローバル変数の値保持とか言う
 レベルの話ではないと思われます。

  もともと、自分自身が動いている存在基盤をQuitしても、まだその先のステートメントが
  実行されることの方が、よっぼど不思議と言える仕様です。

  多分、実際のニーズに合わせるために、何とかそれを成立させる奥の手を使っているんでしょうが、
  デバッグモードにされると、その奇策も通じなくなるということだと思います。

  あと、ちょっとした感想なんですけども

 >Private Sub Workbook_Open() 
 >    Let ShouldClose = False
 >End Sub 
 自然体の(手操作による)ブックオープンを想定するなら、
 わざわざFalseを設定する必要はないと思います。初期値がFalseのハズですから。

 >    If Not ShouldClose Then
 >★        Call MsgBox("Click [Close] Button!", vbCritical)
 >        Let Cancel = True
 >    Else
 >        Let Cancel = False
 >    End If
 これもCancelは、元々Falseですから、Elseは必要ないと思います。

(半平太) 2016/09/25(日) 19:51


半平太さん

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

Let Cancel = Falseの方は、明らかに無駄ですね(^^;

ご提示頂いたサンプルを、私も実行しましたが、
同様の結果が得られました。

>自然体の(手操作による)ブックオープン
という表現が気になったので、調べてみたら、
他のブックからマクロを使って、Workbook_Openが
記述されたブックを開くと、自動実行され、
Auto_Openの場合は、自動実行されないんですね。

また一つ勉強になりました。

ここの学校は参考になる情報が多いので、
今後も利用させて頂きますゆえ、宜しくお願い致します。
(ラビット) 2016/09/25(日) 22:11


コメント返信:

[ 一覧(最新更新順) ]


YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki. Modified by kazu.