【VBA】ブックを開いたとき・保存時に自動実行するイベント処理の方法(コピペOK)

VBA
スポンサーリンク
スポンサーリンク
  1. この記事でわかること
  2. どんな場面で使う?
  3. 完成イメージ(Before / After)
  4. 実行前の準備
    1. バックアップを取る
    2. Excelをマクロ有効ブック(.xlsm)で保存する
    3. シート構成を確認する(実務版で使用)
  5. 手順(コピペ → 動作確認まで約5分)
    1. 1. VBE(コードを書く画面)を開く
    2. 2. ThisWorkbook モジュールを開く(ここが最重要)
    3. 3. イベントプロシージャを自動生成する
    4. 4. コードを貼り付けて保存する
  6. コード(基本版)– Workbook_Open で起動時メッセージ表示
    1. 書き換えポイント
  7. コード(応用版)– Workbook_BeforeSave で保存前チェック(空欄警告)
    1. 書き換えポイント
  8. コード(実務版)– 開く→データ更新→保存時バックアップ→閉じる前ログ記録
    1. 書き換えポイント
  9. よくある落とし穴5選
    1. 1. コードを標準モジュールに書いて「動かない」
    2. 2. プロシージャ名のスペルミスで認識されない
    3. 3. EnableEvents = False を戻し忘れて全イベントが停止
    4. 4. BeforeClose で Cancel = True にしたらブックが閉じられない
    5. 5. マクロのセキュリティ設定でイベントがブロックされる
    6. VBAのWorkbook_Openが動かないときの対処法
    7. VBAのEnableEventsがFalseのまま戻らなくなったときの対処法
  10. FAQ
    1. Q1: Worksheet_Change と Workbook_Open は何が違う?
    2. Q2: Workbook_Open で重い処理を入れたらブックの起動が遅くなる?
    3. Q3: BeforeSave の SaveAsUI パラメータは何?
    4. Q4: イベントを一時的に無効にしたいときは?
    5. Q5: BeforeClose で「保存しますか?」のダイアログを自作したい
  11. まとめ
    1. 関連記事
  12. 次にやりたくなること

この記事でわかること

  • ブックを開いたときに自動実行する方法(Workbook_Open)
  • 保存するときに自動チェックを入れる方法(Workbook_BeforeSave)
  • 開く→データ更新→保存時バックアップ→閉じる前ログ記録を自動化する方法

対象: Excel 2016以降 / Microsoft 365、Windows 10/11

どんな場面で使う?

  • ブックを開いたときに自動でデータを更新・集計したい
  • 保存前に必須項目の空欄チェックを自動で走らせたい
  • 保存時にバックアップファイルを自動作成したい
  • ブックを閉じるときにログを記録して操作履歴を残したい—

完成イメージ(Before / After)

Before(手動で毎回マクロ実行・目視チェック):

操作 所要時間
ブックを開いて手動でマクロ実行 毎回30秒
保存前に空欄がないか目視確認 毎回1〜2分
バックアップを手動でコピー 毎回1分

After(イベント処理で全自動):

操作 所要時間
ブックを開くだけで自動実行 0秒(自動)
保存するだけで空欄チェック 0秒(自動)
保存時にバックアップも自動作成 0秒(自動)

自分も以前、ブックを開くたびに Alt+F8 で集計マクロを手動実行していた。毎朝同じ操作を繰り返すのが正直めんどくさかった。Workbook_Open にコードを入れてからは、ブックを開くだけで最新データに更新されるようになった。朝の手作業が完全になくなった。この記事で「開いたら勝手に動く」仕組みをサクッと作れるようになってほしい。

ポイント: このイベント処理のコードは、通常のマクロと貼り付け場所が違う。標準モジュール(Module1)ではなく「ThisWorkbook」モジュールに書く。ここを間違えると動かない。

なお、セルの値が変わったときに自動実行する方法は セルの値が変わったら自動実行(Worksheet_Change) で解説している。今回はその「ブック版」にあたる。

実行前の準備

バックアップを取る

イベント処理は意図しないタイミングで実行されることがある。必ずファイルのコピーを別フォルダに保存してから作業する。

Excelをマクロ有効ブック(.xlsm)で保存する

拡張子が .xlsx のままだとマクロが保存できない。

  1. 「ファイル」→「名前を付けて保存」
  2. ファイルの種類を「Excelマクロ有効ブック (*.xlsm)」に変更
  3. 保存

シート構成を確認する(実務版で使用)

実務版コードは以下のシート構成を前提としている:

シート名 用途
データ 元データ(A列に数値)
集計 集計結果(B2に合計値、A1に最終更新日時)
ログ 操作ログ(日時・操作・ユーザー名)※なければ自動作成

基本版・応用版はシート構成を問わない。

手順(コピペ → 動作確認まで約5分)

1. VBE(コードを書く画面)を開く

Excelで Alt + F11 を押す。

2. ThisWorkbook モジュールを開く(ここが最重要)

標準モジュールではない。 VBEの左側「プロジェクトエクスプローラー」で以下を探す:


VBAProject (ファイル名.xlsm)
  └─ Microsoft Excel Objects
      ├─ Sheet1 (Sheet1)
      ├─ Sheet2 (Sheet2)
      └─ ThisWorkbook    ← ★ここをダブルクリック

ThisWorkbook をダブルクリックすると、右側にコードウィンドウが開く。

3. イベントプロシージャを自動生成する

コードウィンドウ上部に2つのドロップダウンがある:

  1. 左のドロップダウンから「Workbook」を選択
  2. 右のドロップダウンからイベント名(Open / BeforeSave / BeforeClose)を選択
  3. プロシージャの枠(Private Sub ... End Sub)が自動で挿入される

この方法なら、プロシージャ名のスペルミスを防げる。

4. コードを貼り付けて保存する

自動生成されたプロシージャの中に、下のコードの中身を貼り付ける。貼り付けたらブックを保存して閉じ、再度開いて動作を確認する。

ボタンに割り当てて手動でも実行したい場合は マクロをボタン1つで実行する方法 を参照。ただしイベントプロシージャは Private Sub なので、ボタンに割り当てるには別途標準モジュールに呼び出し用の Sub を作る必要がある。

コード(基本版)– Workbook_Open で起動時メッセージ表示

まずは最小限のコードで動作を確認する。ブックを開いたときにメッセージが表示されれば成功。


'============================================================
' ■ ブックを開いたとき自動実行(基本版)
'   → ブックを開くとメッセージを表示
'   → 貼り付け場所: ThisWorkbook モジュール
'============================================================
Private Sub Workbook_Open()

    '--- ★書き換えポイント ---
    Dim msg As String
    msg = "データを更新しました。" '← 表示するメッセージ
    '--- ★ここまで ---

    MsgBox msg, vbInformation, "自動実行"

End Sub

書き換えポイント

変数 説明 初期値
msg 起動時に表示するメッセージ "データを更新しました。"

確認方法: コードを貼り付けたら、ブックを保存して閉じる。再度ブックを開いたときにメッセージが出れば成功。

コード(応用版)– Workbook_BeforeSave で保存前チェック(空欄警告)

保存しようとしたとき、指定範囲に空欄がないかチェックする。空欄があれば警告を出し、保存をキャンセルするか選べる。


'============================================================
' ■ 保存前に空欄チェック(応用版)
'   → Ctrl+S や上書き保存の前に自動チェック
'   → 空欄があれば警告して保存を中止(キャンセル可)
'   → 貼り付け場所: ThisWorkbook モジュール
'============================================================
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)

    '--- ★書き換えポイント ---
    Dim checkSheet As String
    checkSheet = "Sheet1"           '← チェック対象のシート名

    Dim checkRange As String
    checkRange = "A2:D20"           '← チェック対象の範囲
    '--- ★ここまで ---

    Dim ws As Worksheet
    Set ws = ThisWorkbook.Worksheets(checkSheet)

    Dim rng As Range
    Set rng = ws.Range(checkRange)

    '--- 空欄を検出
    Dim emptyCell As Range
    Dim emptyCount As Long
    emptyCount = 0

    For Each emptyCell In rng
        If emptyCell.Value = "" Then
            emptyCount = emptyCount + 1
        End If
    Next emptyCell

    '--- 空欄がなければそのまま保存
    If emptyCount = 0 Then Exit Sub

    '--- 空欄があれば警告
    Dim ans As VbMsgBoxResult
    ans = MsgBox(checkSheet & " の " & checkRange & " に空欄が " & emptyCount & " 個あります。" & vbCrLf & vbCrLf & _
                 "このまま保存しますか?", vbYesNo + vbExclamation, "保存前チェック")

    If ans = vbNo Then
        Cancel = True   '← 保存をキャンセル
        MsgBox "保存をキャンセルしました。空欄を確認してください。", vbInformation
    End If

End Sub

書き換えポイント

変数 説明 初期値
checkSheet チェック対象のシート名 "Sheet1"
checkRange チェック対象の範囲 "A2:D20"

ポイント: Cancel = True にすると保存が中止される。ユーザーに「保存するかどうか」を選ばせるダイアログを入れているので、強制キャンセルにはならない。

指定時刻にマクロを自動実行したい場合は 指定時刻にマクロを自動実行する方法(Application.OnTime) を参照。イベントトリガーと時刻トリガーは使い分けると便利。

コード(実務版)– 開く→データ更新→保存時バックアップ→閉じる前ログ記録

実務では複数のイベントを組み合わせて使うことが多い。この実務版では以下の3つを自動化する:

  1. ブックを開いたとき: 集計シートのデータを更新
  2. 保存するとき: バックアップファイルを自動作成
  3. 閉じる前: ログシートに操作日時を記録

この仕組みを入れてからは、ブックを開いたらデータ更新、保存時にバックアップ、閉じる前にログ記録という一連の流れが全自動で回っている。手作業ゼロで管理できるのが快適。もっと早く知りたかった。


'============================================================
' ■ ブックイベント一括管理(実務版)
'   → 開く: データ更新 / 保存: バックアップ / 閉じる前: ログ記録
'   → 貼り付け場所: ThisWorkbook モジュール
'   → すべてのコードをThisWorkbookに貼り付ける
'============================================================

'------------------------------------------------------------
' 【1】ブックを開いたとき: データ更新
'------------------------------------------------------------
Private Sub Workbook_Open()

    On Error GoTo ErrHandler

    '--- ★書き換えポイント ---
    Dim srcSheet As String
    srcSheet = "データ"               '← 元データのシート名

    Dim dstSheet As String
    dstSheet = "集計"                  '← 集計先のシート名

    Dim srcRange As String
    srcRange = "A2"                    '← 元データの開始セル

    Dim dstCell As String
    dstCell = "B2"                     '← 集計値を書き込むセル
    '--- ★ここまで ---

    Application.EnableEvents = False   '← イベントの二重実行を防ぐ

    Dim wsSrc As Worksheet
    Set wsSrc = ThisWorkbook.Worksheets(srcSheet)

    Dim wsDst As Worksheet
    Set wsDst = ThisWorkbook.Worksheets(dstSheet)

    '--- 元データの最終行を取得
    Dim lastRow As Long
    lastRow = wsSrc.Cells(wsSrc.Rows.Count, "A").End(xlUp).Row

    '--- 合計値を集計シートに転記
    If lastRow >= 2 Then
        wsDst.Range(dstCell).Value = Application.WorksheetFunction.Sum( _
            wsSrc.Range(srcRange & ":" & wsSrc.Cells(lastRow, "A").Address))
    End If

    wsDst.Range("A1").Value = "最終更新: " & Format(Now, "yyyy/mm/dd hh:nn:ss")

    MsgBox "データを更新しました(" & Format(Now, "hh:nn") & ")", vbInformation, "自動更新"

Cleanup:
    Application.EnableEvents = True    '← 必ず戻す
    Exit Sub

ErrHandler:
    MsgBox "データ更新でエラーが発生しました。" & vbCrLf & _
           "エラー内容: " & Err.Description, vbExclamation
    Resume Cleanup

End Sub

'------------------------------------------------------------
' 【2】保存するとき: バックアップファイルを自動作成
'------------------------------------------------------------
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)

    On Error GoTo ErrHandler

    '--- ★書き換えポイント ---
    Dim backupFolder As String
    backupFolder = ThisWorkbook.Path & "\backup"  '← バックアップ先フォルダ
    '--- ★ここまで ---

    Application.EnableEvents = False

    '--- バックアップフォルダがなければ作成
    If Dir(backupFolder, vbDirectory) = "" Then
        MkDir backupFolder
    End If

    '--- バックアップファイル名(日時付き)
    Dim backupName As String
    backupName = backupFolder & "\" & _
                 Replace(ThisWorkbook.Name, ".xlsm", "") & _
                 "_" & Format(Now, "yyyymmdd_hhnnss") & ".xlsm"

    '--- バックアップを作成
    ThisWorkbook.SaveCopyAs backupName

Cleanup:
    Application.EnableEvents = True
    Exit Sub

ErrHandler:
    MsgBox "バックアップの作成でエラーが発生しました。" & vbCrLf & _
           "エラー内容: " & Err.Description, vbExclamation
    Resume Cleanup

End Sub

'------------------------------------------------------------
' 【3】閉じる前: ログシートに操作日時を記録
'------------------------------------------------------------
Private Sub Workbook_BeforeClose(Cancel As Boolean)

    On Error GoTo ErrHandler

    '--- ★書き換えポイント ---
    Dim logSheet As String
    logSheet = "ログ"                  '← ログ記録先のシート名
    '--- ★ここまで ---

    Application.EnableEvents = False   '← イベントの二重実行を防ぐ

    '--- ログシートが存在するか確認
    Dim wsLog As Worksheet
    On Error Resume Next
    Set wsLog = ThisWorkbook.Worksheets(logSheet)
    On Error GoTo ErrHandler

    If wsLog Is Nothing Then
        '--- ログシートがなければ作成
        Set wsLog = ThisWorkbook.Worksheets.Add( _
            After:=ThisWorkbook.Worksheets(ThisWorkbook.Worksheets.Count))
        wsLog.Name = logSheet
        wsLog.Range("A1").Value = "日時"
        wsLog.Range("B1").Value = "操作"
        wsLog.Range("C1").Value = "ユーザー"
    End If

    '--- 最終行の次にログを追記
    Dim nextRow As Long
    nextRow = wsLog.Cells(wsLog.Rows.Count, "A").End(xlUp).Row + 1

    wsLog.Cells(nextRow, "A").Value = Format(Now, "yyyy/mm/dd hh:nn:ss")
    wsLog.Cells(nextRow, "B").Value = "ブックを閉じる"
    wsLog.Cells(nextRow, "C").Value = Application.UserName

    '--- 保存してから閉じる
    '   ※ EnableEvents=False中なのでBeforeSaveは再発火しない
    ThisWorkbook.Save

Cleanup:
    Application.EnableEvents = True    '← 必ず戻す
    Exit Sub

ErrHandler:
    MsgBox "ログ記録でエラーが発生しました。" & vbCrLf & _
           "エラー内容: " & Err.Description, vbExclamation
    Resume Cleanup

End Sub

書き換えポイント

変数 説明 初期値
srcSheet 元データのシート名(Open用) "データ"
dstSheet 集計先のシート名(Open用) "集計"
srcRange 元データの開始セル(Open用) "A2"
dstCell 集計値の書き込みセル(Open用) "B2"
backupFolder バックアップ先フォルダ(BeforeSave用) ThisWorkbook.Path & "\backup"
logSheet ログ記録先のシート名(BeforeClose用) "ログ"

ファイルの自動保存やバックアップの詳細は ブックを自動保存する方法 も参照。

よくある落とし穴5選

1. コードを標準モジュールに書いて「動かない」

自分もこれで30分溶かした。Workbook_Open のコードを Module1 に書いてしまい、ブックを開いても何も起きなかった。原因は単純で、イベントプロシージャは ThisWorkbook モジュールにしか書けない

症状 原因 対策
ブックを開いても何も起きない コードが Module1 にある VBEの左側で「ThisWorkbook」をダブルクリックしてコードを移動する

2. プロシージャ名のスペルミスで認識されない

症状 原因 対策
正しい場所に書いたのに動かない Workbook_open WorkBook_Open などスペルが違う コードウィンドウ上部のドロップダウンから自動生成する。手入力しない

3. EnableEvents = False を戻し忘れて全イベントが停止

症状 原因 対策
1回目は動くが、2回目以降すべてのイベントが動かない EnableEvents = False のまま放置 On Error GoTo で必ず True に戻す。実務版コードのように Cleanup ラベルを使う

応急処置: イミディエイトウィンドウ(Ctrl+G)で Application.EnableEvents = True を実行すれば復旧する。

4. BeforeClose で Cancel = True にしたらブックが閉じられない

症状 原因 対策
×ボタンを押してもブックが閉じない 無条件に Cancel = True を設定している 特定の条件でのみ Cancel = True にする。デバッグ中は一時的にコメントアウトする

5. マクロのセキュリティ設定でイベントがブロックされる

症状 原因 対策
自分のPCでは動くが別のPCで動かない マクロが無効になっている 「コンテンツの有効化」をクリックする。または「ファイル→オプション→セキュリティセンター→信頼できる場所」にフォルダを追加する

VBAのWorkbook_Openが動かないときの対処法

「Workbook_Openを書いたのにブックを開いても何も起きない」という場合、原因はコードを標準モジュールに書いていることが多い。Workbook_OpenはThisWorkbookモジュールに書く必要がある。VBEの左側ツリーで「ThisWorkbook」をダブルクリックして開き、そこにコードを貼り付けること。

VBAのEnableEventsがFalseのまま戻らなくなったときの対処法

「イベント処理が全く動かなくなった」という場合、原因はどこかで Application.EnableEvents = False を設定したまま戻し忘れていることだ。イミディエイトウィンドウで Application.EnableEvents = True を直接実行すれば復旧する。

FAQ

Q1: Worksheet_Change と Workbook_Open は何が違う?

比較項目 Worksheet_Change Workbook_Open / BeforeSave
トリガー セルの値が変わったとき ブックを開いたとき / 保存するとき
発火頻度 セル変更のたび(高頻度) ブック操作時(低頻度)
貼り付け場所 シートモジュール(Sheet1等) ThisWorkbook モジュール
主な用途 入力に応じた即時処理 起動時の初期化・保存前チェック

詳しくは セルの値が変わったら自動実行(Worksheet_Change) を参照。

Q2: Workbook_Open で重い処理を入れたらブックの起動が遅くなる?

はい。重い処理(大量データ集計、外部ファイル読み込みなど)を入れると、ブックが開くまで時間がかかる。対策は2つ:

  1. Application.ScreenUpdating = False で画面更新を止めて処理を高速化する
  2. Application.OnTime Now + TimeValue("00:00:01"), "処理名" で1秒遅延させてから実行する(ブック自体はすぐ開く)

Q3: BeforeSave の SaveAsUI パラメータは何?

SaveAsUI は Boolean 値。True = 「名前を付けて保存」、False = 「上書き保存」。処理を分けたい場合に使う:


Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
    If SaveAsUI Then
        '--- 「名前を付けて保存」のときだけ実行する処理
    Else
        '--- 「上書き保存」のときだけ実行する処理
    End If
End Sub

Q4: イベントを一時的に無効にしたいときは?

Application.EnableEvents = False で全イベントを一時停止できる。処理後に必ず True に戻すこと。 戻し忘れの応急処置は、イミディエイトウィンドウ(Ctrl+G)で以下を実行:


Application.EnableEvents = True

エラー処理と EnableEvents の安全な組み合わせ方は エラー処理(On Error)で止まらないマクロを作る方法 を参照。

Q5: BeforeClose で「保存しますか?」のダイアログを自作したい

Workbook_BeforeClose の中で ThisWorkbook.Saved プロパティをチェックする:


Private Sub Workbook_BeforeClose(Cancel As Boolean)
    If Not ThisWorkbook.Saved Then
        Dim ans As VbMsgBoxResult
        ans = MsgBox("変更が保存されていません。保存しますか?", _
                     vbYesNoCancel + vbExclamation)
        Select Case ans
            Case vbYes:    ThisWorkbook.Save
            Case vbCancel: Cancel = True  '← 閉じるのをキャンセル
            ' vbNo → 保存せず閉じる
        End Select
    End If
End Sub

ブックの保存と閉じる操作をまとめて自動化したい場合は ブックを保存して閉じる方法 も参照。

まとめ

  • Workbook_Open: ブックを開いたときに自動実行。起動時のデータ更新やメッセージ表示に使う
  • Workbook_BeforeSave: 保存前に自動チェック。空欄チェックやバックアップ作成に使う
  • Workbook_BeforeClose: 閉じる前に自動処理。ログ記録や保存確認に使う
  • 貼り付け場所は ThisWorkbook モジュール(標準モジュールでは動かない)
  • EnableEvents の制御を忘れないこと(On Error GoTo で True に戻すのが安全)

関連記事

次にやりたくなること

コメント

タイトルとURLをコピーしました