【先着1,000名様!】1,000円分をプレゼント!

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

このQ&Aに関連する最新のQ&A

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に関連する人気のQ&A

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

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

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

Q【Excel VBA】マクロでExcel自体を終了させたい

環境:WindowsXP、Excel2003

マクロでエクセルを終了(ブックを閉じて、アプリケーション自体も終了)させたいのですが、以下のコードではアプリケーションが閉じてくれません。

ThisWorkbook.Close
ExcObj.Quit
Application.Quit

どこか悪いところはありますでしょうか?

よろしくお願いします。

Aベストアンサー

普通に考えれば質問者のコードで上手くいきそうですが
hana-hana3さんの回答にもあるようにThisWorkBook.Closeでコード終了となりますので
Application.QuitをThisWorkBook.Closeの前にもってこないといけません。
Application.Quitはそれがあるプロシージャのコードが全て終わるまで
その実行を保留するちょと特別動作をします。

'-------------------------------------
 Application.Quit
 ThisWorkbook.Close
'-------------------------------------
 
 

QEXCEL VBA で現在開いているブックのファイル名を取得する方法

EXCEL2003 VBAで業務を簡素化するために、現在開いているブックのファイル名を取得する方法が分かりません。
作業手順をマクロを使って処理していますが、オリジナルのワークブックをファイル名を変えて保存し、以後、このワークブックを読み込んで使用しています。
このときのVBAは、オリジナルのファイル名を使っているため、ファイル名を変更するとエラーになり、以後の業務に使用できません。
常にファイル名を取得出来るVBAをどなたか、教えて下さい。

Aベストアンサー

>現在開いているブックのファイル名
 ちょっと曖昧な表現かなぁという気もいたしますが、VBAが書いてあるブックのブック名は
ThisWorkbook.Name
で、現在 "アクティブにして" 操作対象になっているブックの名前は
ActiveWorkbook.Name
ですね。

 しかし、
>VBAは、オリジナルのファイル名を使っているため、ファイル名を変更するとエラーになり
というような文脈からすると、
ThisWorkbook.Name
の方ですかね。

QエクセルVBA ブックを閉じる前に確認メッセージを表示したい

エクセルでブックを右上の×を押して閉じる場合、「○○の入力は済みましたか?」というメッセージを表示して「はい・いいえ」のうち、はいを押すと閉じることができて、いいえを押すと閉じるのをやめるようにしたいのですが、どのようなコードになるか教えてください。よろしくお願いします。

Aベストアンサー

ThisWorkbookのBeforeCloseイベントに
Private Sub Workbook_BeforeClose(Cancel As Boolean)
MsgBox "AAA"
End Sub
を入れると
Xでクローズしても、メッセージが出ましたが。

Qエクセル:マクロ「Application.CutCopyMode = False」って?

エクセルのマクロを記録していると

「Application.CutCopyMode = False」

というものがよく出てきますが、これは何でしょう?
どういう意味のものかわかりません。
削除しても差し支えないのもでしょうか?

Aベストアンサー

「Application.CutCopyMode = False」の前で
セルのコピー、または切り取りを行っていると思います。
これは、その操作(セルのコピー、または切り取り)を無効にしているだけです。
------------
Range("A1").Select
Selection.Copy ← これを無効にしている
Range("A2").Select
ActiveSheet.Paste
Application.CutCopyMode = False
------------
上記の場合であれば、「Application.CutCopyMode = False」を削除しても問題ありませんが、
以下の場合、貼り付け処理でエラーになります。
------------
Range("A1").Select
Selection.Copy
Range("A2").Select
Application.CutCopyMode = False
ActiveSheet.Paste ← ココでエラー
------------
ご自分で、セルをコピーしてみると分かると思いますが、コピーした範囲が点線で点滅されます。
「Application.CutCopyMode = False」をすると、
その点滅がなくなります。

「Application.CutCopyMode = False」の前で
セルのコピー、または切り取りを行っていると思います。
これは、その操作(セルのコピー、または切り取り)を無効にしているだけです。
------------
Range("A1").Select
Selection.Copy ← これを無効にしている
Range("A2").Select
ActiveSheet.Paste
Application.CutCopyMode = False
------------
上記の場合であれば、「Application.CutCopyMode = False」を削除しても問題ありませんが、
以下の場合、貼り付け処理でエラーになります。
------------
...続きを読む

QEXCELファイルのカレントフォルダを取得するには?

EXCELファイルのカレントフォルダを取得するには?

C:\経理\予算.xls

D:\2005年度\予算.xls

EXCEL97ファイルがあります。

VBAで
  カレントフォルダ名
(C:\経理\,D:\2005年度\)
を取得する事は可能でしょうか?

CURDIRでは上手い方法が見つかりませんでした。

Aベストアンサー

こんばんは。
Excel97 でも、同じですね。以下で試してみてください。

Sub test()
'このブックのパス
a = ThisWorkbook.Path
'アクティブブックのパス
b = ActiveWorkbook.Path
'Excelで設定されたデフォルトパス
c = Application.DefaultFilePath
'カレントディレクトリ
d = CurDir
MsgBox "このブックのパス   : " & a & Chr(13) & _
   "アクティブブックのパス: " & b & Chr(13) & _
   "デフォルトパス    : " & c & Chr(13) & _
   "カレントディレクトリ : " & d & Chr(13)
End Sub

QSub ***( ) と Private Sub ***( ) の違い

初歩的な質問で申し訳ありませんが・・・

自分でコードを書いていても、イベントが発生したりした時の処理で、コードのウィンドウで上のドロップダウンリストで選択できる時の処理などは自動的に[Private Sub Command1_Click( )]などと出てくるのでそのまま使っています。自分で別途プロシージャーを作成する時は[Sub ****( )]としています。
ですがその違いを理解しないまま、自分で作成する時は[Private Sub]ではなくて[Sub]を使っています。

Sub ***( ) と Private Sub ***( ) の違いは何なんでしょうか?
どなたか説明頂けませんか?
よろしくお願いします。

Aベストアンサー

「Sub」の部分にカーソルを置いて[F1]を押せばヘルプが起動します。
「指定項目」のところに「Public」と「Private」の説明がありますよ。
省略して「Sub hogehoge()」とした場合は「Public」とみなされます。

Publicは「すべてのモジュールから呼び出せるプロシージャ」ということになります。
Privateとすると「同じモジュールの中からしか呼び出せないプロシージャ」となります。

もしExcelをお持ちでしたらExcelのVBEで標準モジュールを追加し、「Sub Test1()」と「Private Sub Test2()」を作成してみてください。
そしてExcelの[ツール]-[マクロ]-[マクロ(Alt+F8)]でマクロ実行のダイアログを表示させてみるとわかります。
ここには実行できるプロシージャの一覧が表示されますが、Test1は表示されているけれどTest2は表示されません。
Test1はPublicで、Test2はPrivateだからです。

Q[Excel2000]auto_closeを止めさせるには

Excel2000で、
特定のボタンを押した場合以外の閉じる処理を
キャンセルさせたいのですがうまくいきません

sub ボタン押()
flg = true
end sub

sub auto_close()
if flg <> true then
msgbox "AAA"
exit sub
end if
end sub

これでは、どーやってもそのまま終了してしまいます。
なにか良い方法はないでしょうか・・・

よろしくおねがいします。

Aベストアンサー

こんにちは。maruru01です。

閉じる処理をキャンセルするなら、WorkbookオブジェクトのBeforeCloseイベントに記述してはどうですか。
引数のCancelにTrueを代入することで、閉じる操作をキャンセル出来ます。
記述する場所は、VBE画面のプロジェクトエクスプローラ(ツリー上のもの)の「ThisWorkbook」モジュールをダブルクリックして開きます。
そこに以下のように記述します。


Private Sub Workbook_BeforeClose(Cancel As Boolean)

  If Not flg Then
    MsgBox "AAA"
    Cancel = True
  End If

End Sub

QExel VBA 別ブックから該当データを検索し、必要なデータを取得する方法について

部品表というブックがあります
A列に商品名、B列に商品番号が入力してあります。C列のコードは未入力です。
A列     B列     C列      
商品名  商品番号  コード
モータ  U-1325-L  
ホルダ  R-134256

また、コード一覧表という別のブックには、A列に商品番号と、B列にコードが、何千件も入力されています。

やりたいことは
部品表のC列のコード欄に、コード一覧表ブックから商品番号と一致するコードを貼り付けしたいのです。

部品表は、何百種類もありますので、関数ではなく、マクロで処理を希望します。

自分では、部品表の商品番号をコピーして、コード一覧表で検索し、検索結果の右隣のセル(B列のコード)の値を部品表のC列に貼り付ければよいかと思い、書いてみたんですが…

Sub 別ブックから貼り付ける()
  Dim 検索する As Long
Windows("部品表.xls").Activate
検索する = cells(i,2).Value
Windows("コード一覧表.xls").Activate
ActiveWindow.SmallScroll Down:=-3
Selection.AutoFilter Field:=3, Criteria1:="=検索する", Operator:= xlAnd

と、してみたものの、検索しても、その検索結果の隣のセルのコードをどうやって取得すればいいのかが、わかりませんでした。

基本事項は本で学びましたが、呪文のようなコードはよく理解できません。懸命にネットで検索して、訳して理解する努力をしてはいますが。

どうぞよろしくお願いします。

部品表というブックがあります
A列に商品名、B列に商品番号が入力してあります。C列のコードは未入力です。
A列     B列     C列      
商品名  商品番号  コード
モータ  U-1325-L  
ホルダ  R-134256

また、コード一覧表という別のブックには、A列に商品番号と、B列にコードが、何千件も入力されています。

やりたいことは
部品表のC列のコード欄に、コード一覧表ブックから商品番号と一致するコードを貼り付けしたいのです。

部品表は、何百種類もありますので、関数...続きを読む

Aベストアンサー

こんにちは。
とりあえず実用性も踏まえました。
メインの動作はワークシート関数のVLOOKUPをVBA上で使用していますので理解はしやすいかと思います。
また、質問文から察するに「部品表.xls」と「コード一覧表.xls」の両方を開いて処理されていますが「コード一覧表.xls」はプログラム内で開いて閉じているので実行するときは「コード一覧表.xls」は閉じて置いてください。
Option Explicit
Sub Sample()
 Application.ScreenUpdating = False
 Dim I As Long
 Dim xlBook
 Set xlBook = Workbooks.Open("C:\★★\コード一覧表.xls") '★要変更★
 I = 2
 Do While Range("A" & I).Value <> ""
  ThisWorkbook.Worksheets("Sheet1").Range("C" & I).Value = Application.VLookup(ThisWorkbook.Worksheets("Sheet1").Range("B" & I).Value, xlBook.Worksheets("Sheet1").Range("A2:B65535"), 2, 0)
  I = I + 1
 Loop
 xlBook.Close
 Application.ScreenUpdating = True
 MsgBox ("完了")
End Sub

こんにちは。
とりあえず実用性も踏まえました。
メインの動作はワークシート関数のVLOOKUPをVBA上で使用していますので理解はしやすいかと思います。
また、質問文から察するに「部品表.xls」と「コード一覧表.xls」の両方を開いて処理されていますが「コード一覧表.xls」はプログラム内で開いて閉じているので実行するときは「コード一覧表.xls」は閉じて置いてください。
Option Explicit
Sub Sample()
 Application.ScreenUpdating = False
 Dim I As Long
 Dim xlBook
 Set xlBook = Workbooks....続きを読む

QEXCEL VBAで計算値を四捨五入、切り上げ、切捨てする方法

ネットで探してみたのですが、計算結果を四捨五入して特定のセルを
返すにはどうしたらいいのでしょうか?

Sub hokangosa()

Dim ZPS As Double
Dim ZPOS As Double
Dim DMN As Double
MsgBox (" >>> 補間誤差自動計算 <<< ")
MsgBox (" >>> 初期値入力します <<< ")
ZPS = InputBox(">>> ステップを入力してください<<<")
ZPOS = Sheet1.Cells(22, 4).Value
DMN = ZPOS / ZPS
Sheet1.Cells(23, 6).Value = DMN
End Sub

ここでDMNの値を四捨五入したいです。

またこれとは別に切上げ、切捨ても教えていただけるとありがたいです。

Aベストアンサー

DMN = Application.WorksheetFunction.Round(ZPOS / ZPS, 0)
で、四捨五入
DMN = Application.RoundDown(ZPOS / ZPS, 0)
で切り捨て
DMN = Application.RoundUp(ZPOS / ZPS, 0)
で切り上げです。

引数で、対象桁を変更できます。

QVBA オブジェクトが空かどうか判定する

皆様のお知恵を拝借させてください。

エクセルVBAでオブジェクトを入れる変数を定義し、その変数にオブジェクト
が入っているかどうか検査したいのですがどうしたらいいでしょうか。

例えば---
Dim a As Workbook
If a <> nothing then ←この部分が分からない。このままだとエラー。
処理
End if
---------
環境
エクセル2003
WinXPsp1

Aベストアンサー

もし、aが空だったら
If a Is Nothing Then 

もし、aが空じゃなかったら
If Not a Is Nothing Then


このQ&Aを見た人がよく見るQ&A

人気Q&Aランキング