Excel VBA質問箱 IV

当質問箱は、有志のボランティア精神のおかげで成り立っています。
問題が解決したら、必ずお礼をしましょうね。
本サイトの基本方針をまとめました。こちら をご一読ください。

投稿種別の選択が必要です。ご注意ください。
迷惑投稿防止のため、URLの入力を制限しています。ご了承ください。


7122 / 13644 ツリー ←次へ | 前へ→

【40994】Excel終了時の動きについて foo 06/7/27(木) 14:50 質問[未読]
【40996】Re:Excel終了時の動きについて neptune 06/7/27(木) 15:17 発言[未読]
【40998】Re:Excel終了時の動きについて foo 06/7/27(木) 15:30 お礼[未読]
【40997】Re:Excel終了時の動きについて Kein 06/7/27(木) 15:20 発言[未読]
【40999】Re:Excel終了時の動きについて foo 06/7/27(木) 15:38 発言[未読]
【41004】Re:Excel終了時の動きについて Kein 06/7/27(木) 15:56 発言[未読]
【41021】Re:Excel終了時の動きについて ichinose 06/7/27(木) 20:44 発言[未読]
【41022】Re:Excel終了時の動きについて ichinose 06/7/27(木) 21:02 発言[未読]
【41023】Re:Excel終了時の動きについて neptune 06/7/27(木) 21:13 発言[未読]
【41033】Re:Excel終了時の動きについて foo 06/7/28(金) 9:25 お礼[未読]
【41032】Re:Excel終了時の動きについて foo 06/7/28(金) 9:12 お礼[未読]
【41040】Re:Excel終了時の動きについて ichinose 06/7/28(金) 11:08 発言[未読]
【41051】Re:Excel終了時の動きについて foo 06/7/28(金) 13:13 発言[未読]
【41060】Re:Excel終了時の動きについて ichinose 06/7/28(金) 13:54 発言[未読]
【41062】Re:Excel終了時の動きについて foo 06/7/28(金) 14:12 お礼[未読]
【41076】Re:Excel終了時の動きについて ichinose 06/7/28(金) 16:57 発言[未読]
【41077】Re:Excel終了時の動きについて 追伸 ichinose 06/7/28(金) 17:05 発言[未読]
【41079】姑息技 Jaka 06/7/28(金) 17:14 発言[未読]
【41086】Re:姑息技 foo 06/7/28(金) 18:56 お礼[未読]
【41085】Re:Excel終了時の動きについて foo 06/7/28(金) 18:25 お礼[未読]

【40994】Excel終了時の動きについて
質問  foo  - 06/7/27(木) 14:50 -

引用なし
パスワード
   こんにちは、現在組んでいるマクロで、ブックのbeforecloseイベントにおいて、フラグ(グローバル変数)の値がTrueだった時にMsgBoxを出す処理を入れてます。

これがそのブックを閉じる操作の場合は期待通りの動作をするのですが、Excelを終了する時にはMsgBoxを出さずに終わってしまいます。
デバッガで見たところ、beforecloseの中でのフラグの値はFalseになっていました。

実はこの現象の要因と思われる条件が1つあります。
この要因が無ければExcel終了時でもMsgBoxが表示されました。

言葉で説明するよりサンプルコードを見ていただいた方が早いと思うので、以下に挙げます。

-----(標準モジュール)------
Public Flag As Boolean

Sub test()
  Flag = True
  
  Do While True
    newHour = Hour(Now())
    newMinute = Minute(Now())
    newSecond = Second(Now()) + 1
    waitTime = TimeSerial(newHour, newMinute, newSecond)
    Application.Wait waitTime  '(当然実際はここでもっと違う処理を行う)
    DoEvents
  Loop
End Sub
-----------------------------

-----(ThisWorkbookモジュール)------
Private Sub Workbook_BeforeClose(Cancel As Boolean)
  if Flag then MsgBox "End..."
End Sub
-----------------------------

testを実行してから、ブックを閉じようとした場合はMsgBoxが表示されますが、Excelを終了させようとした時は表示されません。

また前述のように、例えばtestのDoループ部分を削除してFlagの値をTrueにした後に、Excelを終了しようとした時は、MsgBoxが表示されました。

どういう経緯でこのような現象が起きるのか分かる方いらっしゃるでしょうか?
また、上記Doループがある時でも期待するような動作を実現するための解決案がありましたらご教授ください。

よろしくお願いします。

【40996】Re:Excel終了時の動きについて
発言  neptune  - 06/7/27(木) 15:17 -

引用なし
パスワード
   http://support.microsoft.com/kb/408871/ja
には該当しませんか?

【40997】Re:Excel終了時の動きについて
発言  Kein  - 06/7/27(木) 15:20 -

引用なし
パスワード
   まず・・
>Do While True


Do While Flag = True

の間違いですね。そして当然のことですが
>testを実行してから、ブックを閉じようとした場合
以外でも、どこかで Flag = True を代入するコードが実行されていなければ、
Workbook_BeforeCloseイベントでMsgBoxが出てくるはずが無い、ということ。
>Excelを終了する時
というイベントは無いので、そのマクロを実行するブックが開かれていて、
FlagにTrueを代入するコードを実行したときだけしか、MsgBoxを出す術は
ありません。

【40998】Re:Excel終了時の動きについて
お礼  foo  - 06/7/27(木) 15:30 -

引用なし
パスワード
   早速の情報ありがとうございます。

> ほとんどの場合、プロシージャ終了後も値は保持されますが、
> 意図しないタイミングで保持されていた Public 変数の値が破棄され、
> 使えていた変数の値が突然使えなくなる場合があります。

ですか・・・むむむ。
やはり仕方無いんでしょうかね。

私もこのページにある解決方法のように、シート上のセルに値を書き込むという方法は思いついたのですが、それだと必ず保存するかどうかを聞いてくる事になるので、あまり上手い方法じゃないなぁと思ったのでした。
他にも編集操作が入る事があるので、強制的にこの保存するかどうかを無視する訳にも行かないですし。

他に手が無いとすれば仕方無いので、この方法で逃げるしか無いか・・・

【40999】Re:Excel終了時の動きについて
発言  foo  - 06/7/27(木) 15:38 -

引用なし
パスワード
   >まず・・
>>Do While True
>↓
>
>Do While Flag = True
>
>の間違いですね。そして当然のことですが

いえ、強制ループを意図したのでこれでもOKです。
(あくまで簡易化したサンプルなので)

>>testを実行してから、ブックを閉じようとした場合
>以外でも、どこかで Flag = True を代入するコードが実行されていなければ、
>Workbook_BeforeCloseイベントでMsgBoxが出てくるはずが無い、ということ。

testを実行すれば一応グローバル変数であるFlagの値はTrue値を保持することは確認しています。
(質問時にも書きましたが・・・)

>>Excelを終了する時
>というイベントは無いので、そのマクロを実行するブックが開かれていて、
>FlagにTrueを代入するコードを実行したときだけしか、MsgBoxを出す術は
>ありません。

Excelを終了しようとすれば、当然開かれていたブックも閉じられる訳で、ブックのBeforeCloseイベントが発生しますよ。
あと、testを実行する事でFlag=Trueは実行されます。(以下略)

【41004】Re:Excel終了時の動きについて
発言  Kein  - 06/7/27(木) 15:56 -

引用なし
パスワード
   >簡易化したサンプル
ということでも、ループに入った後で肝心の Flag の扱いをどうしているのか、
が書かれてないと、回答側には誤解を与えることになります。
>testを実行すれば一応グローバル変数であるFlagの値はTrue値を保持する
それは言うまでもないことです。冒頭に Flag = True としているのだから、
誰でも分かります。そーいうことでなく
>testを実行してから、ブックを閉じようとした場合は
と書いてあったら、その逆の「実行しないでエクセルを終了しようとしたら」
なぜ MsgBox が出なくなるのか分からない。という質問のように解釈されます。
なので
>どこかで Flag = True を代入するコードが実行
される必要があるのではないですか ? と書いたわけです。
>Excelを終了しようとすれば、当然開かれていたブックも閉じられる
開かれているブックの中に「そのマクロを仕込んであるブック」があるなら
イベントが起動するのは当然ですが、質問内容にはそういうことが書いて
ないので、どのような場合(極端に言うとブックを一つも開いてなくても)
でもメッセージを出すことを想定しているのか、と解釈したわけです。
そうするとアプリケーションレベルのイベントで対処しなくてはならなく
なりますが、残念ながら Quit で反応するイベントが見当たらない、
という結論になるのです。

【41021】Re:Excel終了時の動きについて
発言  ichinose  - 06/7/27(木) 20:44 -

引用なし
パスワード
   ▼foo さん:
こんばんは。

>こんにちは、現在組んでいるマクロで、ブックのbeforecloseイベントにおいて、フラグ(グローバル変数)の値がTrueだった時にMsgBoxを出す処理を入れてます。
>
>これがそのブックを閉じる操作の場合は期待通りの動作をするのですが、Excelを終了する時にはMsgBoxを出さずに終わってしまいます。

現象、確認しました。Excel2002 SP-3では、foo さんが記述されたとおりに
コードを実行し、操作すると変数が初期化されてしまいます。

Excel終了ボタンをクリックすると、testというプログラムも
終了してしまいますねえ!!
データの保持は方法も考えられますが
(もっとも、foo さんの事象に適合するしないの問題は別ですが)
testが終了してしまうのは致命的です。


方法としては、作業用ブック(仮にBook1)の

Thisworkbookモジュールに

Public Flag as boolean

と宣言しておいて、実際はBook1は非表示に設定しておきます。

>
>-----(標準モジュール)------
>Public Flag As Boolean
>
>Sub test()
  Workbooks("book1").Flag= True
>  
  Do While Workbooks("book1").Flag=True
>    newHour = Hour(Now())
>    newMinute = Minute(Now())
>    newSecond = Second(Now()) + 1
>    waitTime = TimeSerial(newHour, newMinute, newSecond)
>    Application.Wait waitTime  '(当然実際はここでもっと違う処理を行う)
>    DoEvents
>  Loop
>End Sub
>-----------------------------
>
>-----(ThisWorkbookモジュール)------
>Private Sub Workbook_BeforeClose(Cancel As Boolean)
  if Workbooks("book1").Flag then MsgBox "End..."
>End Sub
>-----------------------------
>

なんてすると、値(Workbooks("book1").Flag)は保持されます。
よって、BeforeCloseイベントでメッセージは表示されます。


繰り返しますが、プロシジャーが終了してしまうのは、問題ですけどね!!

こうすれば、セルに保存する時の問題はクリアできるとは思いますが・・。


この現象は、要チェックですね!!

【41022】Re:Excel終了時の動きについて
発言  ichinose  - 06/7/27(木) 21:02 -

引用なし
パスワード
   この作業用ブック(Book1)というのは、
testというプロシジャーがあるブックとは別のブックですよ!!

念のために・・・。

【41023】Re:Excel終了時の動きについて
発言  neptune  - 06/7/27(木) 21:13 -

引用なし
パスワード
   セルに書くなら、Iniファイルなど、小さな別ファイルを作る方が
スマートな気がします。

【41032】Re:Excel終了時の動きについて
お礼  foo  - 06/7/28(金) 9:12 -

引用なし
パスワード
   ▼ichinose さん:

アイディアをありがとうございます。

>Excel終了ボタンをクリックすると、testというプログラムも
>終了してしまいますねえ!!
>データの保持は方法も考えられますが
>(もっとも、foo さんの事象に適合するしないの問題は別ですが)
>testが終了してしまうのは致命的です。

そうなんですよね。実はそっちの方が問題かもしれません。

で、他のworkbookに値を保存しておく方法ですが、testのあるwookbookよりも先に閉じたりしたらダメだったりしませんか?
現在マクロが動いてるworkbookが先に閉じる等順番が確定しているなら有効そうな手ではありますが、やはり今いちスッキリしませんね(それはもう仕方ないのかもしれませんが ^^;)

【41033】Re:Excel終了時の動きについて
お礼  foo  - 06/7/28(金) 9:25 -

引用なし
パスワード
   ▼neptune さん:

アイディアをありがとうございます。

>セルに書くなら、Iniファイルなど、小さな別ファイルを作る方が
>スマートな気がします。

それも手かもしれませんが、その場合は余計なファイルが増えてしまうのがちょっと。(^^;)

他の案と一緒に善し悪しを考慮しながら検討したいと思います。

【41040】Re:Excel終了時の動きについて
発言  ichinose  - 06/7/28(金) 11:08 -

引用なし
パスワード
   ▼foo さん:
おはようございます。
>で、他のworkbookに値を保存しておく方法ですが、testのあるwookbookよりも先に閉じたりしたらダメだったりしませんか?


>現在マクロが動いてるworkbookが先に閉じる等順番が確定しているなら有効そうな手ではありますが、やはり今いちスッキリしませんね(それはもう仕方ないのかもしれませんが ^^;)
このbook1にあたるブックをアドインとして(book1.xlaで作成し)
その後、「ツール」---「アドイン」でbook1.xlaを登録して、

例の
Private Sub Workbook_BeforeClose(Cancel As Boolean)
  If Workbooks("book2.xla").Flag Then MsgBox "End..."
End Sub

このイベントやtestがあるプロシジャーを実行して試してみてください。
この問題は、testの実行が止まってしまう事が問題ですが・・・。


このFLAGという変数、INTEGERやStringなら、
セルに保存するや外部ファイルに保存でも良いのですが、
もし変数がオブジェクト変数だったら・・・?
セルに全プロパティを退避させるわけにはいかないですよね?

よって、この方法が色々な面で有効だといいなあと思っています。

確認してみてください。

【41051】Re:Excel終了時の動きについて
発言  foo  - 06/7/28(金) 13:13 -

引用なし
パスワード
   ▼ichinose さん:

アドインって使った事無かったんですが、そういう使い方もできるんですね。

と思ったのですが、試してみた所 Workbooks("Book1.xla").Flag を参照する所で

実行時エラー '438':
オブジェクトは、このプロパティまたはメソッドをサポートしていません。

と言われてしまいました。

Book1.xla には標準モジュールに
  Public Flag as String
だけ書いてあるんですが、もっと何か必要なんでしょうか。

それはそれとして、今回マクロ以外にアドインのような追加モジュールを別に提供するのは避けたいと思っているため、どちらにしても今回はこの方法は使えないです。

【41060】Re:Excel終了時の動きについて
発言  ichinose  - 06/7/28(金) 13:54 -

引用なし
パスワード
   >
>Book1.xla には標準モジュールに
>  Public Flag as String
>だけ書いてあるんですが、もっと何か必要なんでしょうか。

これ、標準モジュールではなくて、

Book1.xla のThisworkbookモジュールに記述しないと

他のブックから簡単には、参照できませんよ!!
オブジェクトモジュールにPublicで記述すると
これは、ブックBook1.xlaのプロパティとして参照可能になります。


>
>それはそれとして、今回マクロ以外にアドインのような追加モジュールを別に提供するのは避けたいと思っているため、どちらにしても今回はこの方法は使えないです。

それが、残念でした・・・。
ループで監視しているコード test

これが実行されていることがネックですね?
(そうでなければ、Excelを終了をクリックしてもデータは保持されます)

この仕様を変えないと駄目かなあ??

もうちょっと考えて見ます。
試してないけど、Ontimeはどうだろう???

【41062】Re:Excel終了時の動きについて
お礼  foo  - 06/7/28(金) 14:12 -

引用なし
パスワード
   ▼ichinose さん:
>>
>>Book1.xla には標準モジュールに
>>  Public Flag as String
>>だけ書いてあるんですが、もっと何か必要なんでしょうか。
>
>これ、標準モジュールではなくて、
>
>Book1.xla のThisworkbookモジュールに記述しないと
>
>他のブックから簡単には、参照できませんよ!!

なるほど、修正したらExcel終了でも上手く行くようになりました。
ちなみに"as String"じゃなく"as Boolean"の間違いでした。(^^;)

>この仕様を変えないと駄目かなあ??

えーと、結局ダメそうなのは分かったので、素直に仕様を少し変える事になりそうです。

皆さんのアドバイス大変参考になりました。
ありがとうございました。

【41076】Re:Excel終了時の動きについて
発言  ichinose  - 06/7/28(金) 16:57 -

引用なし
パスワード
   ▼foo さん:
こんな方法で試してみてください。
新規ブックで試してみてください。


標準モジュール(Module1)に
'===============================================================
Public flag As Boolean
'================================================================
Sub test()
  newHour = Hour(Now())
  newMinute = Minute(Now())
  newSecond = Second(Now()) + 1
  waitTime = TimeSerial(newHour, newMinute, newSecond)
  Application.Wait waitTime  '(当然実際はここでもっと違う処理を行う)
End Sub
'======================================================================
Sub main()
  flag = True
  Call mc_schedule(True, -1, [TimeValue("00:00:00.60")], "test")
'                 ↑これ以下の短い間隔では駄目でした
'      駄目というのは、制御がExcelに戻らないのでxボタンが押せない
End Sub
'======================================================================
Sub subproc()
  '解除
  Call mc_schedule(False)
End Sub


別の標準モジュール(Module2)に
'=====================================================================
'スケジュール管理サブルーチン
Option Explicit
Private exetm As Variant '次の実行時刻
Private repcnt As Long '繰り返し回数
Private c_cnt As Long '現在の回数
Private reptm As Variant '実行間隔時間
Private prcnm As String '実行プロシジャー名
'========================================================================
Sub mc_schedule(ByVal on_off As Boolean, Optional ByVal rep_cnt As Long = 0, _
        Optional ByVal rep_time As Variant = 0, Optional ByVal proc_name As String = "")
'マクロ実行のスケジュールの設定を行う
'input : on_off --- true スケジュール設定 false---スケジュール解除
'    rep_cnt  実行を繰り返す回数 -1の場合は、制限なし
'    rep_time  実行間隔時間
'    proc_name 実行するプロシジャー名
  On Error Resume Next
  If on_off = True Then
    If rep_cnt > 0 Or rep_cnt = -1 Then
     reptm = rep_time
     repcnt = rep_cnt
     c_cnt = 0
     prcnm = proc_name
     End If
    exetm = Now() + reptm
    End If
  Application.OnTime EarliestTime:=exetm, Procedure:="mc_exec", Schedule:=on_off
  On Error GoTo 0
End Sub
'=================================================================
Sub mc_exec()
'スケジュール設定されたプロシジャーを実行する
  Dim wk As Variant
  wk = Application.Run(prcnm)
  If repcnt <> -1 Then c_cnt = c_cnt + 1
  If c_cnt < repcnt Or repcnt = -1 Then
    Call mc_schedule(True)
    End If
End Sub


Thisworkbookのモジュールに
'================================================================
Option Explicit
Private Sub Workbook_BeforeClose(Cancel As Boolean)
  If flag Then
    MsgBox "End..."
    subproc
    End If
End Sub


として、Module1のmainを実行してみてください。
ちゃんとメッセージが表示されます。

監視間隔が遅いのは仕方がないですが、
検討してみてください。

【41077】Re:Excel終了時の動きについて 追伸
発言  ichinose  - 06/7/28(金) 17:05 -

引用なし
パスワード
   >として、Module1のmainを実行してみてください。

実行後、Excelの終了ボタンをクリックすれば

>ちゃんとメッセージが表示されます。

でした。

>
>監視間隔が遅いのは仕方がないですが、
>検討してみてください。

【41079】姑息技
発言  Jaka  - 06/7/28(金) 17:14 -

引用なし
パスワード
   フラグだけだったら、ツールバーを作って、ボタンとか何かのキャプションに書き込んでおくとか...。
ダメ?

【41085】Re:Excel終了時の動きについて
お礼  foo  - 06/7/28(金) 18:25 -

引用なし
パスワード
   ▼ichinose さん:

フルコードの提示をありがとうございます。
早速試してみたところ、確かにこれだと上手くいくようです。
Aplication.OnTimeがミソなんですね。
参考になりました。
今回の実装に組み入れるかどうか分かりませんが、今後のために覚えておきます。

>監視間隔が遅いのは仕方がないですが、
>検討してみてください。

多分間に入っている1秒強制ウェイトの部分を実際の処理にすれば、もう少しまともに操作できるようになるように思います。

【41086】Re:姑息技
お礼  foo E-MAIL  - 06/7/28(金) 18:56 -

引用なし
パスワード
   ▼Jaka さん:
>フラグだけだったら、ツールバーを作って、ボタンとか何かのキャプションに書き込んでおくとか...。
>ダメ?

なるほど、そういう手もある訳ですね。
今回の場合は別レスでも書いたように、マクロ以外のモジュールを追加するのは避けたいため採用できないですが、有効な場面もありそうですね。

何か期待以上に色々なアドバイスをいただいて勉強になりました。

7122 / 13644 ツリー ←次へ | 前へ→
ページ:  ┃  記事番号:
2610219
(SS)C-BOARD v3.8 is Free