• ベストアンサー

【Excel】BeforeCloseを毎回呼び出すには?

終了時に独自で保存をしたいのですが、 下記のコードだと1回目でキャンセルすると 2回目以降の呼び出し時に全く実行されません。 どこか悪いのかご教示ください。 また、もしご存じであれば BeforeClose() と Auto_Close() の違い ThisWorkbook と Me の違い を教えてください。 よろしくお願いいたします。 Private Sub Workbook_BeforeClose(Cancel As Boolean)   Dim iAns As VbMsgBoxResult   iAns = MsgBox("'" & Me.Name & "' への変更を保存しますか?")   Select Case iAns   Case vbYes     Call WriteFile     ThisWorkbook.Close savechanges:=False   Case vbNo     ThisWorkbook.Close savechanges:=False   Case vbCancel     Cancel = True   End Select End Sub

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

  • ベストアンサー
  • OtenkiAme
  • ベストアンサー率77% (69/89)
回答No.4

こんにちは。 > ですが、vbYesとvbNoのとき、なぜかMsgBoxの表示後にExcelの保存確認 > ダイアログまで表示されてしまい、有効に機能していないようなのです。 > 他の何かがまずいのでしょうか。 最初の処理では、イベント機能が有効になっていてWorkbook_BeforeClose により処理されますが、WriteFileを行ったことにより、イベント機能が 無効になってしまって、Workbook_BeforeCloseではなく、通常の閉じる処理 になっている、ということはないですか? もしそうなら、WriteFileの処理の方で ThisWorkbook.Saved = True Application.EnableEvents = True というような処理を追加されてみては如何でしょうか? という事であれば、 もし、ThisWorkbook.Saved = Trueならメッセージを出さずにブックを閉じる という処理も必要になるかもしれませんね。

saotome210
質問者

お礼

ご回答ありがとうございます。 原因はご指摘のイベント機能関連のようでした。 流れとしては Application.EnableEvents = False 中略 ThisWorkbook.Saved = True 中略 Application.EnableEvents = True となっていました。コメントアウトすることで正常に動作しました。 イベント内部でこのようなことをするべきでないということでしょうか。 イベント等についてもっと勉強する必要があるようです。 この度はどうもありがとうございました。 おかげさまで解決できました。

その他の回答 (3)

  • end-u
  • ベストアンサー率79% (496/625)
回答No.3

>ですが、vbYesとvbNoのとき、なぜかMsgBoxの表示後にExcelの保存確認ダイアログまで表示されてしまい、 >有効に機能していないようなのです。 >他の何かがまずいのでしょうか。 vbNoの時もとなると、正直に言って解りませんm(_ _)m #Sub Auto_Cose()に何か書いてたりしないですよね。 新規Book&シンプルなコードで試してみると 'ThisWorkbookModule Option Explicit Private Sub Workbook_BeforeClose(Cancel As Boolean)   Dim iAns As VbMsgBoxResult      Debug.Print Me.Saved   iAns = MsgBox("'" & Me.Name & "' への変更を保存しますか?", vbYesNoCancel)   Select Case iAns   Case vbYes     Call test     Me.Saved = True   Case vbNo     Me.Saved = True   Case vbCancel     Cancel = True   End Select   Debug.Print iAns, Cancel, Me.Saved End Sub Private Sub test()   MsgBox "test"   Me.Save End Sub (結果) False 6      False     True False 7      False     True False 2      True     False 意図した通り動作すると思います。 本番コードに関しては、ブレイクポイント設定してデバッグしてみてください。

saotome210
質問者

お礼

ご回答ありがとうございます。 原因はイベント機能関連のようでした。 検証用のコードまで載せていただいて、ありがとうございました。 おそらくend-uさんの思いもよらないようなヘマをしてたんでしょうね、私。 ^^; また機会がありましたらよろしくお願いいたします。

  • OtenkiAme
  • ベストアンサー率77% (69/89)
回答No.2

こんにちは。 書いていたらすでに回答が……(^_^;) MmsgBoxの引数Buttonsが指定されていないので Select Case でiAnsを場合分けできないのと、 BeforeCloseイベントの中にCloseメソッドを入れたら またイベントが発生してしまうというところが修正ポイントです。 Private Sub Workbook_BeforeClose(Cancel As Boolean)   Dim iAns As VbMsgBoxResult   iAns = MsgBox("'" & Me.Name & "' への変更を保存しますか?", vbYesNoCancel)   If iAns = vbYes Then Call WriteFie   Select Case iAns     Case vbYes, vbNo       Cancel = False     Case vbCancel       Cancel = True   End Select End Sub こっちもだらだらと書いてしまいました……。 > BeforeClose() と Auto_Close() の違い ですが、記述されたブックが他のブックから操作されたかによって 動作が違います。 Auto_OpenやAuto_Closeは、そのブックを自分で開いた時のみ実行されます。 WorkbookOpenやBeforeCloseは、他のブックから操作された時にも実行されます。 例えば、A、B、Cのブックがあって、BにAuto_Closeによる処理を記述し、 CにBeforeCloseによる処理を記述していたとします。 その時、AからBを閉じる命令を実行してもBのAuto_Closeは実行されません。 しかし、AからCを閉じる命令を実行するとCのBeforeCloseが実行されます。 他のブックのマクロを操作する方法としてRunメソッドがありますが、使うのなら ヘルプで調べてみてください。 > ThisWorkbook と Me の違い ですが、私もあまり詳しくありませんが、プロパティとキーワードである、というの がまず違いますね。 ThisWorkbookは、マクロコードが書かれたそのブックを指すプロパティです。 Meは、そのコードが実行されているクラスや構造体を参照するためのキーワードです。 マクロを記述する時、前者はどこでも使用できますが、後者は、クラスとして成り 立っているThisWorkbookモジュールやUserForm1モジュール内では使用できますが、 標準モジュールでは使えません。 つまり、Meキーワードは、ThisWorkbookモジュール内では、Thisworkbookクラスを 参照している、UserForm1モジュールでは、UserForm1クラスを参照している、とい うことぐらいしかわかりません。 私自身、単一のUserFormを使う場合は、Meキーワードを使う事がありますが、 ThisWorkbookモジュールではMe、標準モジュールではThisWorkbook、って使い分ける ことはしたことがありません。(混乱してしまいますから。)

saotome210
質問者

補足

>MmsgBoxの引数Buttonsが指定されていないので すみません・・・簡略化している際に誤って省いてしまったようです。 実際にはvbYesNoCancelが付いていました。 end-uさんにも回答していることですが、 ThisWorkbook.Saved = True にしてもそれが有効化していないことに頭を悩ませている状態です。 何か思い当たることがあればご教示お願いいたします。 >Auto_OpenやAuto_Closeは、そのブックを自分で開いた時のみ実行されます。 >WorkbookOpenやBeforeCloseは、他のブックから操作された時にも実行されます。 解りやすいご説明ありがとうございます。 今回のケースではどちらでも問題ないことを知り、安心しました。 >私自身、単一のUserFormを使う場合は、Meキーワードを使う事がありますが、 >ThisWorkbookモジュールではMe、標準モジュールではThisWorkbook、って使い分ける >ことはしたことがありません。(混乱してしまいますから。) たしかにあちこち眺めてたら混乱しそうですね。 ThisWorkbookはMeであまり代用しないほうが統一されて良さそうです。

  • end-u
  • ベストアンサー率79% (496/625)
回答No.1

>...1回目でキャンセルすると >2回目以降の呼び出し時に全く実行されません。 状況が今ひとつ掴めませんが、そのコードでは上手くいかないのは確かです。 Workbook_BeforeCloseは文字通り、Close前処理ですから コード内でCancel = Trueしなければ、処理が終わればCloseします。 BeforeClose内でCloseメソッドを書く必要はありません。 と、いうよりCloseメソッドを書くとイベント連鎖が発生する事になりますので書きません。 こういう場合、 Private Sub Workbook_BeforeClose(Cancel As Boolean)   Dim iAns As VbMsgBoxResult      iAns = MsgBox("'" & Me.Name & "' への変更を保存しますか?", vbYesNoCancel)   Select Case iAns   Case vbYes     Call WriteFile     Me.Saved = True   Case vbNo     Me.Saved = True   Case vbCancel     Cancel = True   End Select End Sub このように書きます。 SavedプロパティをTrueに変更すれば、そのBookは変更なしと判定されて 保存せずに閉じる事(ThisWorkbook.Close savechanges:=False)ができます。 #余談かもしれませんが、今回のケースではBeforeSaveイベントでCall WriteFileを利用すれば #Close時は既定の動作で対応できるような気がします。 #(Sub WriteFileの中身と運用がわからないので確実ではないです。深追いするつもりもありません) >BeforeClose() と Auto_Close() の違い BeforeCloseはイベントプロシージャで、Auto_Closeは自動実行マクロです。 Excel95以前からある自動実行マクロに対して、BeforeCloseイベントは97から追加されたものです。(多分) 違いなどは↓など参考にしてみてください。 『■ イベントプロシージャを活用しよう!』 http://home.att.ne.jp/zeta/gen/excel/c04p59.htm >ThisWorkbook と Me の違い 半分パス。(専門家の方のレスをお待ちください) ThisWorkbookはThisWorkbookプロパティでMeはMeキーワード。 ThisWorkbookはThisWorkbookを指しますが MeはThisWorkBookモジュールやFormモジュール、Classモジュール内のプロシージャ内で書くと それぞれのクラス、インスタンスを指します。 #これ以上うまく伝える自信なしm(_ _)m

saotome210
質問者

補足

ご回答ありがとうございます。 >BeforeClose内でCloseメソッドを書く必要はありません。 >と、いうよりCloseメソッドを書くとイベント連鎖が発生する事になりますので書きません。 言われてみるとその通りですね。。 Me.Saved = True に直したら、2回目以降もうまくいきました。 ですが、vbYesとvbNoのとき、なぜかMsgBoxの表示後にExcelの保存確認ダイアログまで表示されてしまい、 有効に機能していないようなのです。 他の何かがまずいのでしょうか。 >『■ イベントプロシージャを活用しよう!』 ​>http://home.att.ne.jp/zeta/gen/excel/c04p59.htm 違いが分かりました。単独で使用する際には特に違いはないようですね。 >MeはThisWorkBookモジュールやFormモジュール、Classモジュール内のプロシージャ内で書くと >それぞれのクラス、インスタンスを指します。 個々のインスタンス自体を指すのですね。ありがとうございます。

関連するQ&A