Excelの警告「保存していないファイルを参照しています」の原因は幽霊リンク?VBAで削除!

Excelで他のブックからシートをコピーして作業中ブックに持ってきた時、保存すると「保存していないファイルを参照しています」の警告メッセージが出るようになった。

実害はなかったのだが、保存の都度メッセージが出るようになり、煩わしくなり、ストレスを感じてきた。

もともと作業中のブックに外部リンクはなかったので、追加したシートが悪さしていることは明らかだが、シートのどこに外部リンクがあるのかが探せなかった。

その時に探した方法とは、Excelメニューの数式>名前の管理を確認、また、外部リンクは"[ブック名]"のように指定されるので、ブックを文字列 "[" で検索してヒットするかを確認したことだ。

でも、見つからなかった。

そこで、ネットで調べたところ、リンクが壊れた「幽霊リンク」というものがあるらしいことがわかった。

それは表には出てこず、Excel内部に残ることがあるらしい。

まさに私のケースはそれに該当するような気がしたわけだが、表には出てこないということで、ではどうすればよいかと考えると、VBAで削除することが考えられるのである。

ということで、VBAコードを以下に示す。 外部参照リンクをすべて表示するVBAコードである。

  1' 外部参照リンクをすべて表示する
  2Sub ScanAllExternalLinks()
  3
  4    Dim ws As Worksheet
  5    Dim lo As ListObject
  6    Dim c As Range
  7    Dim f As FormatCondition
  8    Dim nm As Name
  9    Dim msg As String
 10    Dim formula As String
 11    Dim dv As Validation
 12    Dim found As Boolean
 13
 14    Debug.Print "=== 外部リンク総合スキャン開始 ==="
 15
 16    '--- 1. 名前定義 ---
 17    For Each nm In ThisWorkbook.Names
 18        On Error Resume Next
 19        formula = nm.RefersTo
 20        On Error GoTo 0
 21        If ContainsExternalRef(formula) Then
 22            msg = "【名前定義】" & nm.Name & " = " & formula
 23            Debug.Print msg
 24            found = True
 25        End If
 26    Next nm
 27
 28    '--- 2. 各ワークシート ---
 29    For Each ws In ThisWorkbook.Worksheets
 30
 31        '--- 2-1 セルの数式 ---
 32        For Each c In ws.UsedRange.Cells
 33            If c.HasFormula Then
 34                formula = c.Formula
 35                If ContainsExternalRef(formula) Then
 36                    msg = "【数式】" & ws.Name & "!" & c.Address & " = " & formula
 37                    Debug.Print msg
 38                    found = True
 39                End If
 40            End If
 41
 42            '--- 2-2 入力規則 ---
 43            If c.Validation.Type <> xlValidateNone Then
 44                On Error Resume Next
 45                formula = c.Validation.Formula1
 46                On Error GoTo 0
 47                If ContainsExternalRef(formula) Then
 48                    msg = "【入力規則】" & ws.Name & "!" & c.Address & " = " & formula
 49                    Debug.Print msg
 50                    found = True
 51                End If
 52            End If
 53        Next c
 54
 55        '--- 2-3 条件付き書式 ---
 56        For Each f In ws.UsedRange.FormatConditions
 57            On Error Resume Next
 58            formula = ""
 59            If f.Type = xlExpression Then
 60                formula = f.Formula1
 61            ElseIf f.Type = xlCellValue Then
 62                formula = f.Formula1
 63            End If
 64            On Error GoTo 0
 65            If ContainsExternalRef(formula) Then
 66                msg = "【条件付き書式】" & ws.Name & " ルール = " & formula
 67                Debug.Print msg
 68                found = True
 69            End If
 70        Next f
 71
 72        '--- 2-4 テーブル(ListObject) ---
 73        For Each lo In ws.ListObjects
 74            formula = lo.SourceData
 75            If ContainsExternalRef(formula) Then
 76                msg = "【テーブル】" & ws.Name & "!" & lo.Name & " = " & formula
 77                Debug.Print msg
 78                found = True
 79            End If
 80        Next lo
 81
 82    Next ws
 83
 84    '--- 3. Excel が保持しているリンク一覧(壊れたリンク含む) ---
 85    Dim links As Variant
 86    links = ThisWorkbook.LinkSources(Type:=xlLinkTypeExcelLinks)
 87    If Not IsEmpty(links) Then
 88        Dim i As Long
 89        For i = LBound(links) To UBound(links)
 90            Debug.Print "【LinkSources】" & links(i)
 91            found = True
 92        Next i
 93    End If
 94
 95    If Not found Then
 96        Debug.Print "外部参照は見つかりませんでした。"
 97    End If
 98
 99    Debug.Print "=== スキャン終了 ==="
100
101End Sub
102
103
104'===== 外部リンクを判定する関数 =====
105Function ContainsExternalRef(str As String) As Boolean
106    If Len(str) = 0 Then
107        ContainsExternalRef = False
108        Exit Function
109    End If
110
111    '外部参照は [xxxx.xlsx] のように角括弧が入る
112    If InStr(str, "[") > 0 And InStr(str, "]") > 0 Then
113        ContainsExternalRef = True
114    Else
115        ContainsExternalRef = False
116    End If
117End Function

これを実行することでデバッグコンソール(イミディエイトウィンドウ)に外部リンクの一覧が出力される。

開発タブより標準モジュールを作成して、上記コードをコピペして実行すれば良い。

外部リンクの削除方法は、以下VBAを参考に適宜改変して実行すれば良い。

注意すべきは、以下コードの実行によりすべての外部リンクを削除する可能性があるので、必ず自分でコードを理解して、必要な分だけを削除するよう修正して実行すること。

 1' 外部リンクを削除する VBA
 2Sub DeleteAllExternalLinks()
 3
 4    Dim ws As Worksheet
 5    Dim lo As ListObject
 6    Dim c As Range
 7    Dim f As FormatCondition
 8    Dim nm As Name
 9    Dim dv As Validation
10    Dim formula As String
11
12    '--- 1. 名前定義 ---
13    For Each nm In ThisWorkbook.Names
14        formula = nm.RefersTo
15        If ContainsExternalRef(formula) Then
16            nm.Delete
17        End If
18    Next nm
19
20    '--- 2. 各ワークシート ---
21    For Each ws In ThisWorkbook.Worksheets
22
23        '2-1 セルの数式
24        For Each c In ws.UsedRange.Cells
25            If c.HasFormula Then
26                formula = c.Formula
27                If ContainsExternalRef(formula) Then
28                    '数式を値に置き換え
29                    c.Value = c.Value
30                End If
31            End If
32
33            '2-2 データ入力規則
34            If c.Validation.Type <> xlValidateNone Then
35                On Error Resume Next
36                formula = c.Validation.Formula1
37                On Error GoTo 0
38                If ContainsExternalRef(formula) Then
39                    c.Validation.Delete
40                End If
41            End If
42        Next c
43
44        '2-3 条件付き書式
45        For Each f In ws.UsedRange.FormatConditions
46            On Error Resume Next
47            formula = ""
48            If f.Type = xlExpression Then
49                formula = f.Formula1
50            ElseIf f.Type = xlCellValue Then
51                formula = f.Formula1
52            End If
53            On Error GoTo 0
54            If ContainsExternalRef(formula) Then
55                f.Delete
56            End If
57        Next f
58
59        '2-4 テーブル
60        For Each lo In ws.ListObjects
61            formula = lo.SourceData
62            If ContainsExternalRef(formula) Then
63                'テーブルを範囲に戻す
64                lo.Unlist
65            End If
66        Next lo
67
68    Next ws
69
70    '--- 3. LinkSourcesに残るリンクを削除 ---
71    Dim links As Variant
72    Dim i As Long
73    links = ThisWorkbook.LinkSources(Type:=xlLinkTypeExcelLinks)
74    If Not IsEmpty(links) Then
75        For i = LBound(links) To UBound(links)
76            ThisWorkbook.BreakLink Name:=links(i), Type:=xlLinkTypeExcelLinks
77        Next i
78    End If
79
80    MsgBox "すべての外部リンクを削除しました。", vbInformation
81
82End Sub

保存時は、上記の追加した標準モジュールを削除する。 これで、保存の都度出現していた「保存していないファイルを参照しています」のメッセージは出なくなるはずだ。