プロが教えるわが家の防犯対策術!

終了時に独自で保存をしたいのですが、
下記のコードだと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

A 回答 (4件)

こんにちは。



> ですが、vbYesとvbNoのとき、なぜかMsgBoxの表示後にExcelの保存確認
> ダイアログまで表示されてしまい、有効に機能していないようなのです。
> 他の何かがまずいのでしょうか。
最初の処理では、イベント機能が有効になっていてWorkbook_BeforeClose
により処理されますが、WriteFileを行ったことにより、イベント機能が
無効になってしまって、Workbook_BeforeCloseではなく、通常の閉じる処理
になっている、ということはないですか?

もしそうなら、WriteFileの処理の方で
ThisWorkbook.Saved = True
Application.EnableEvents = True
というような処理を追加されてみては如何でしょうか?

という事であれば、
もし、ThisWorkbook.Saved = Trueならメッセージを出さずにブックを閉じる
という処理も必要になるかもしれませんね。
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。

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

この度はどうもありがとうございました。
おかげさまで解決できました。

お礼日時:2009/09/16 22:25

>ですが、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
意図した通り動作すると思います。

本番コードに関しては、ブレイクポイント設定してデバッグしてみてください。
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。

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

お礼日時:2009/09/16 22:32

こんにちは。



書いていたらすでに回答が……(^_^;)

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、って使い分ける
ことはしたことがありません。(混乱してしまいますから。)

この回答への補足

>MmsgBoxの引数Buttonsが指定されていないので
すみません・・・簡略化している際に誤って省いてしまったようです。
実際にはvbYesNoCancelが付いていました。

end-uさんにも回答していることですが、
ThisWorkbook.Saved = True
にしてもそれが有効化していないことに頭を悩ませている状態です。
何か思い当たることがあればご教示お願いいたします。


>Auto_OpenやAuto_Closeは、そのブックを自分で開いた時のみ実行されます。
>WorkbookOpenやBeforeCloseは、他のブックから操作された時にも実行されます。
解りやすいご説明ありがとうございます。
今回のケースではどちらでも問題ないことを知り、安心しました。

>私自身、単一のUserFormを使う場合は、Meキーワードを使う事がありますが、
>ThisWorkbookモジュールではMe、標準モジュールではThisWorkbook、って使い分ける
>ことはしたことがありません。(混乱してしまいますから。)
たしかにあちこち眺めてたら混乱しそうですね。
ThisWorkbookはMeであまり代用しないほうが統一されて良さそうです。

補足日時:2009/09/16 15:32
    • good
    • 0

>...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

この回答への補足

ご回答ありがとうございます。

>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モジュール内のプロシージャ内で書くと
>それぞれのクラス、インスタンスを指します。
個々のインスタンス自体を指すのですね。ありがとうございます。

補足日時:2009/09/16 15:19
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています