Excel VBA Close SaveChanges:=Falseでも保存確認が出る原因と対策|TempWB.Saved=Trueで解決

Excel VBAで一時ブックを作ってHTML化し、メール本文に使ったあと保存せず閉じたいのに「変更内容を保存しますか?」が出て困ることがあります。Microsoft 365でも環境によって再現するこの現象を、原因の考え方と最も確実な回避策(Savedフラグ)で解決します。

目次

症状:Close SaveChanges:=False を指定しても保存確認が出る

典型的なのは、VBAで作った一時的なブック(ここではTempWB)に対して、値と書式だけを貼り付け、HTMLとして書き出したりOutlookメールの本文に貼り付けたりしたあと、次のように閉じるケースです。

'(例)TempWBを保存せず閉じたい
TempWB.Close SaveChanges:=False

通常はこれで「保存しますか?」は出ません。しかし一部のユーザー環境だけ、同じMicrosoft 365のExcel・同じ言語設定であっても、次の確認が表示されることがあります。

  • 「変更内容を保存しますか?(Yes / No / Cancel)」

しかもこの確認が出ると、完全自動化したかったメール送信処理が止まり、ユーザー操作が必要になります。RPAや夜間バッチで動かしている場合は致命的です。

よくある処理の流れ(TempWBでHTML化してメール本文に使う)

「元データの見た目(セルの書式)を残したまま、メール本文に表として貼りたい」というニーズで、次のようなパターンがよく使われます。

Dim TempWB As Workbook
Dim TempWS As Worksheet
Dim src As Range

Set src = ThisWorkbook.Worksheets("集計").Range("A1:H30")

Set TempWB = Workbooks.Add(xlWBATWorksheet)
Set TempWS = TempWB.Worksheets(1)

'値と書式だけを貼り付ける(数式・リンク等を持ち込まない)
src.Copy
With TempWS.Range("A1")
    .PasteSpecial xlPasteValues
    .PasteSpecial xlPasteFormats
End With
Application.CutCopyMode = False

'(ここでHTML化してメール本文に流し込む処理…)

'最後に保存せず閉じたい
TempWB.Close SaveChanges:=False

この流れ自体は広く使われていますが、環境差により「保存確認」が出ることがあるのが問題です。

まず押さえる:CloseのSaveChangesとSavedプロパティの役割

この現象を理解するうえで重要なのが、Excelがブックの状態を「保存済みかどうか(未保存の変更があるか)」で管理している点です。Excelは内部的にWorkbook.Saved(保存フラグ)で「変更あり/なし」を判断します。

項目意味ポイント
Workbook.Savedブックに未保存の変更があるかどうかを表すフラグExcelはこのフラグを見て保存確認を出す(出さない)
Workbook.Close SaveChanges:=False閉じるときに保存しない指定原則は保存確認を出さずに閉じるが、環境・状態によって例外が起きる
Application.DisplayAlertsExcel標準の警告ダイアログを表示するか多くの確認を抑止できるが、すべての状況を完全に潰せるとは限らない

ポイントは、保存確認の発生源は「SaveChanges引数」ではなく、Excel内部の「未保存扱い(Saved=False)」であるということです。通常はSaveChanges:=Falseを渡すとExcelがよしなに処理してくれますが、何らかの理由で挙動がぶれる環境があります。

原因は「未保存フラグ(Saved=False)」が立ったままになること

結論から言うと、保存確認が出る環境では、閉じる直前のTempWB.SavedFalse(未保存の変更あり)になっています。見た目の変更がなくても、Excelは内部状態の変化を「変更」とみなします。特に一時ブックを作って貼り付けを行う処理は、以下のような内部更新が入りやすい条件が揃っています。

  • 貼り付けでスタイル(Style)やテーマ関連が取り込まれる(とくに書式貼り付け)
  • 名前定義やテーブル設定の微細な差が作られる
  • アドイン/COM拡張がWorkbookイベントやApplicationイベントをフックして、裏でプロパティを書き換える
  • 再計算やイベント(Workbook_SheetChange等)がタイミングによって発火し、結果的に「変更あり」扱いになる
  • セキュリティ製品やDLPがOffice操作を監視し、メタデータ更新や保護情報の付与を行う

これらは「同じMicrosoft 365」「同じ言語設定」でも、各PCに入っているアドインやセキュリティ製品、Officeの更新チャネル、ポリシー、周辺設定によって差が出ます。その結果、ある環境ではTempWB.Close SaveChanges:=Falseが素直に動き、別の環境では保存確認が出る、という現象になります。

最も確実な回避策:閉じる直前に TempWB.Saved = True をセットする

対処はシンプルで、閉じる直前に保存フラグを明示的に「保存済み」へ倒すことです。これによりExcelの「未保存の変更あり」という扱いを解除し、環境差に左右されにくくなります。

Application.DisplayAlerts = False
TempWB.Saved = True          '未保存フラグを強制的に落とす
TempWB.Close SaveChanges:=False
Application.DisplayAlerts = True

ポイントは、必ず「閉じる直前」に入れることです。貼り付けやHTML化の途中でSaved=Trueにしても、その後の処理でExcelが再びSaved=Falseに戻す可能性があります。

この方法が効く理由

Workbook.Savedは「最後の保存以降に変更されたか」を示す内部フラグです。捨てる前提の一時ブックであれば、実際に保存する必要はありません。そこで、閉じる前にSaved=Trueへ倒しておくと、Excelは「保存すべき変更はない」と判断し、標準の保存確認を出しません。

注意点として、このテクニックは「捨てるブック」専用です。利用者が後で手作業で内容を確認したり、別名保存したりする可能性があるブックに対して安易に使うと、変更が失われても気づけないリスクがあります。

実運用で安定させるテンプレート(復旧漏れを防ぐ)

自動化の現場では、途中でエラーが出たときにDisplayAlertsEnableEventsが元に戻らず、別のマクロやユーザー操作に影響が出るのがよくある事故です。そこで、保存確認対策と合わせて「状態復旧」をセットで書くのがおすすめです。

Sub CloseTempWorkbookSafely(ByVal TempWB As Workbook)
    Dim prevAlerts As Boolean
    Dim prevEvents As Boolean
    Dim prevScreen As Boolean

    On Error GoTo CleanUp

    prevAlerts = Application.DisplayAlerts
    prevEvents = Application.EnableEvents
    prevScreen = Application.ScreenUpdating

    Application.DisplayAlerts = False
    Application.EnableEvents = False
    Application.ScreenUpdating = False

    'クリップボード系の別プロンプト回避にもなる
    Application.CutCopyMode = False

    '最重要:未保存フラグを落としてから閉じる
    TempWB.Saved = True
    TempWB.Close SaveChanges:=False

CleanUp:
    'TempWBが既にNothing/閉じていても落ちないようにする場合は追加ガードを入れてください
    Application.DisplayAlerts = prevAlerts
    Application.EnableEvents = prevEvents
    Application.ScreenUpdating = prevScreen
End Sub

このテンプレートにしておくと、「一部環境だけ保存確認が出る」だけでなく、次のようなトラブルも同時に減らせます。

  • 他のブックのイベントが連鎖して、想定外の変更が入る
  • 貼り付け後にクリップボード確認(データ量が多い等)が出る
  • 画面更新やイベントが残って処理が重くなる/挙動が不安定になる

「一部ユーザーだけ」発生する主な要因と確認ポイント

現象の根っこは「Saved=Falseが立つ」ことですが、なぜそうなるかは環境に依存します。切り分けに使える代表例を表にまとめます。原因は一つとは限らず、複数が重なっていることもあります。

要因何が起きるか確認ポイント対処の方向性
Excel/Officeのアドイン(VBA/COM)ブックを開閉するタイミングで、名前定義・プロパティ・メタ情報を自動更新し、SavedがFalseになる問題が出るPCだけアドイン構成が違わないか(Excelのアドイン一覧、COMアドイン、企業配布の拡張)対象アドインを無効化して再現確認。無効化できない場合はSaved=Trueで吸収
Workbook/WorksheetイベントPersonal.xlsbやアドイン内のイベントが発火し、TempWBに変更を加えるVBEのプロジェクトにイベントコードがないか。アドインにイベントが仕込まれていないかApplication.EnableEvents=Falseでイベント連鎖を止める
書式貼り付けによるStyleの取り込み書式貼り付けでスタイルコレクションが更新され、微細な差が「変更」として残る値貼り付けのみだと再現するか/書式貼り付けを外すと再現が止まるか必要最低限の書式だけを設定する、最後にSaved=Trueで確実に閉じる
再計算・揮発関数タイミングで計算が走り、結果的にブック状態が更新されることがある処理中に計算が走っていないか、計算モードやシートの数式有無一時ブックは値のみで構成、必要なら計算モードを固定
セキュリティ/DLP/IRMコンテンツの取り扱いに応じてタグ付けや保護情報が付与され、内部状態が変わる問題PCだけセキュリティ製品や企業ポリシーが異なるか、監査ログSaved=Trueで回避しつつ、可能ならIT部門に例外設定を相談
ネットワーク環境・プロファイル差テンポラリ領域やユーザープロファイルの違いで、保存状態の判定がぶれることがあるOneDrive同期、プロファイル移行、リダイレクトフォルダ、権限差テンポラリ出力先をローカルに固定、処理順を見直す

この表のとおり、原因を完全に潰し込むのは手間がかかります。だからこそ、捨てるブックに対してはSaved=Trueで「保存確認だけ確実に抑止」してしまうのが現実的です。

Saved=Trueを入れても不安なときの追加対策

多くのケースではTempWB.Saved = Trueで十分ですが、運用上さらに事故を減らしたい場合は、次の追加策も有効です。

イベント連鎖を止める

他のブック(Personal.xlsbやアドイン)にイベントがあると、TempWBにも想定外の処理が走ることがあります。処理区間だけイベントを止めて、最後に戻します。

Dim prevEvents As Boolean
prevEvents = Application.EnableEvents
Application.EnableEvents = False

'…TempWB作成~貼り付け~HTML化…

TempWB.Saved = True
TempWB.Close SaveChanges:=False

Application.EnableEvents = prevEvents

クリップボード系の別プロンプトを潰す

保存確認とは別に「クリップボードに大量のデータがあります」系の確認が出ることがあります。貼り付け後にApplication.CutCopyMode = Falseを入れておくと回避しやすくなります。

一時ブックを最小構成にする

一時ブックに持ち込む要素が多いほど、内部更新も増えます。例えば次のように、値は代入で入れて、書式だけ最小限に貼る(あるいは自前で設定する)と「変更扱い」になる要素を減らせます。

With TempWS.Range("A1").Resize(src.Rows.Count, src.Columns.Count)
    .Value = src.Value                 '値は代入で
    src.Copy
    .PasteSpecial xlPasteFormats       '必要なら書式だけ
End With
Application.CutCopyMode = False

デバッグのコツ:どこでSaved=Falseになるかを見える化する

「Saved=Trueで回避する」のが最短ですが、社内標準マクロとして原因も把握しておきたい場合は、次のように状態をログに出すと切り分けが進みます。

タイミング見るもの
TempWB作成直後TempWB.Saved新規作成直後は通常True(環境によってはここから怪しい場合も)
貼り付け直後TempWB.SavedここでFalseになっていれば、貼り付けがトリガー
HTML化直後TempWB.SavedPublishObjectsやSaveAs相当の処理がトリガー
Close直前TempWB.Saved最終的にFalseなら保存確認が出る可能性が高い

VBEのイミディエイトウィンドウにDebug.Printで出すだけでも十分です。

Debug.Print "after add: ", TempWB.Saved
'…処理…
Debug.Print "after paste: ", TempWB.Saved
'…処理…
Debug.Print "before close: ", TempWB.Saved

問題が出るPCでだけ特定のタイミングでFalseになるなら、その直前の処理が「変更扱い」の引き金です。とはいえ企業環境ではアドインやセキュリティの影響が強く、原因の完全特定が難しいことも多いため、実務ではSaved=Trueで握りつぶす方がコストが低いケースがよくあります。

HTML化してメール送信用に使う場合の実装例

「TempWBに貼り付けた範囲をHTMLにして、OutlookメールのHTMLBodyに入れる」という用途では、処理が長くなりがちです。最後に確実に閉じるため、クリーンアップ処理を一箇所に集約しておくと安定します。

Function RangeToHtmlForMail(ByVal src As Range) As String
    Dim TempWB As Workbook
    Dim TempWS As Worksheet
    Dim tempPath As String
    Dim tempFile As String
    Dim prevAlerts As Boolean, prevEvents As Boolean, prevScreen As Boolean
    Dim fso As Object, ts As Object

    On Error GoTo CleanUp

    prevAlerts = Application.DisplayAlerts
    prevEvents = Application.EnableEvents
    prevScreen = Application.ScreenUpdating

    Application.DisplayAlerts = False
    Application.EnableEvents = False
    Application.ScreenUpdating = False

    Set TempWB = Workbooks.Add(xlWBATWorksheet)
    Set TempWS = TempWB.Worksheets(1)

    '値と書式だけを持ち込む
    With TempWS.Range("A1").Resize(src.Rows.Count, src.Columns.Count)
        .Value = src.Value
        src.Copy
        .PasteSpecial xlPasteFormats
    End With
    Application.CutCopyMode = False

    'HTMLファイルとして一時出力(テンポラリへ)
    tempPath = Environ$("TEMP") & "\"
    tempFile = tempPath & "TempMailTable_" & Format(Now, "yyyymmdd_hhnnss") & ".htm"

    TempWB.PublishObjects.Add( _
        SourceType:=xlSourceRange, _
        Filename:=tempFile, _
        Sheet:=TempWS.Name, _
        Source:=TempWS.UsedRange.Address, _
        HtmlType:=xlHtmlStatic).Publish True

    'HTMLを読み込んで返す
    Set fso = CreateObject("Scripting.FileSystemObject")
    Set ts = fso.OpenTextFile(tempFile, 1, False)
    RangeToHtmlForMail = ts.ReadAll
    ts.Close

CleanUp:
    On Error Resume Next

    '一時ファイル削除
    If Len(tempFile) > 0 Then
        If fso Is Nothing Then Set fso = CreateObject("Scripting.FileSystemObject")
        If fso.FileExists(tempFile) Then fso.DeleteFile tempFile, True
    End If

    '一時ブックを確実に閉じる
    If Not TempWB Is Nothing Then
        TempWB.Saved = True
        TempWB.Close SaveChanges:=False
    End If

    Application.DisplayAlerts = prevAlerts
    Application.EnableEvents = prevEvents
    Application.ScreenUpdating = prevScreen
End Function

この例では、最後に必ずTempWB.Saved = Trueを通すことで、環境差による保存確認を抑止します。さらに、エラーが出ても復旧処理が走るようにして、Excel全体の状態が壊れないようにしています。

よくある質問

Saved=Trueは「保存したこと」にするだけ?本当に安全?

Saved=Trueは「未保存の変更がない」状態をExcelに伝えるだけで、実際にファイルへ保存するわけではありません。したがって、捨てる一時ブックに限定するなら、保存確認を止める目的としては合理的です。一方で、ユーザーが後でそのブックを手で保存したい可能性があるなら、Saved=Trueで確認を潰すべきではありません。

DisplayAlerts=Falseだけでは解決しないの?

多くのケースではApplication.DisplayAlerts=Falseでも保存確認は抑止できます。ただし、環境差(アドイン、ポリシー、Excel更新差)で標準ダイアログの出方がぶれる場合や、標準ダイアログに見えて実はアドインが出している確認の場合があります。保存確認が止まりきらないときは、Saved=Trueの方が「Excelが参照する根っこの状態」を直接変えるため、安定しやすいのが実務上のメリットです。

Close FalseとClose SaveChanges:=Falseはどちらが良い?

どちらも「保存しないで閉じる」を意味します。実務上は可読性が高いSaveChanges:=Falseの方が意図が伝わりやすい一方、古いコード資産ではTempWB.Close Falseのような書き方もよく見ます。保存確認対策としては、どちらであってもTempWB.Saved = Trueを閉じる直前に入れることが本質です。

Excelの更新チャネルやビルド差の影響はある?

Microsoft 365は更新チャネル(Current Channel、Monthly Enterprise Channelなど)やビルド差で挙動が変わることがあります。特に自動化は「微妙な違い」が表面化しやすい領域です。特定のPCだけで再現するなら、アドイン構成に加えて、Officeの更新状況や企業ポリシーの差も疑ってください。ただし、現場で最優先すべきは再現有無よりも「止めない」ことなので、Saved=Trueでの吸収が有効です。

まとめ:TempWBは捨てる前提ならSavedフラグを落として確実に閉じる

Excel VBAで一時ブックを作り、値/書式だけ貼ってHTML化→メール送信に使う処理は便利ですが、環境差によって「保存しますか?」が出ることがあります。原因は多岐にわたりますが、共通しているのはExcelがTempWBを「未保存の変更あり」と判断している点です。

  • 閉じる直前にTempWB.Saved = Trueを入れて、未保存フラグを明示的に解除する
  • 合わせてDisplayAlertsEnableEventsを制御し、復旧コードを入れて運用事故を防ぐ
  • 原因究明に時間をかけるより、捨てブックは安定動作を優先して「吸収」するのが現実的

この一手間で、自動メール送信やレポート生成を「止まらない」マクロへ近づけられます。

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次