過去にたくさんの質問を受けてきましたが、そんな中で「Excelをバージョンアップしたら、それまで動いていたマクロが動かなくなった」というのがあります。まぁ、一般的には動きます。あのね、考えてみてください。Excelの新しいバージョンを作るには3~4年かかるんです。その間、Microsoft MVPなどのように、世界中のメチャクチャ詳しい専門家たちが、よってたかって動作確認をします。私もよくやりました。そうした動作確認で気がつかない不具合なんて、まずありません。もちろん100%完璧とは言いません。プログラムに不具合はつきものです。ですが、動作確認で発見されないような不具合なんて、一般の人が普通にExcelを使っているのでしたら、まず遭遇しませんって。そんなもんです。同じような質問で「Windowsをバージョンアップしたら、Excelのマクロが動かなくなった」というのも、よく聞く話です。こちらは、さらに可能性が低いです。ExcelとWindowsは、別のシステムですから、Windowsの変化によってExcelに影響が出ることは少ないです。少ないですけど、珍しくそうした事例が起きました。前置きが長くなりましたが、今回は「Windows 10にしたら、それまで動いていたマクロがエラーになる」という話です。その原因と対処法を詳しく解説します。
順を追って解説します。たとえば、ブックを開くマクロを考えてみましょう。ここでは、マクロが書かれているブックが「Macro.xlsm」とし、開くブックを「Book1.xlsx」とします。また、ここでは、2つのブックとも「C:\Workフォルダに保存されている」とします。この、保存されているフォルダが重要ですから、覚えておいてください。
もし「Book1.xlsx」が保存されているフォルダを"決め打ち"するのでしたら、次のように簡単なコードで実現できます。
Sub Macro1() Workbooks.Open "C:\Work\Book1.xlsx" End Sub
しかし、このように"別ブックを開く"ようなマクロでは、開きたいブックのパス(ここでは"C:\Work\")を正確に指定しなければなりませんから、マクロで開くブックを「どこでも、お好きなフォルダに保存しといてください」という訳にはいきません。マクロを実行するたびに、パソコンの中を全ファイル検索するなど非現実的です。そこでこういうケースでは、マクロで開くブックを「マクロが書かれているブックと同じフォルダに保存しといてください」という手法が一般的です。マクロが書かれているブックは、ThisWorkbookという単語で特定できます。さらに、Pathプロパティを調べれば、そのブックが保存されているパスが分かります。マクロが書かれているブックと、マクロで開くブックが同じフォルダに保存されているのでしたら、次のようなコードにします。
Sub Macro2() Workbooks.Open ThisWorkbook.Path & "\Book1.xlsx" End Sub
実行すると、Book1.xlsxが開かれます。では、もう少しだけ複雑にしましょう。マクロで開くブックの名前が「Book1.xlsx」のように固定されていなかったら。たとえば、基幹システムや取引先などから毎月ブックやCSVファイルが提供されると。そうしたファイルの名前が、たとえば「2021-04.xlsx」だったり「4月分データ.csv」みたいに。これ、来月には「2021-05.xlsx」や「5月分データ.csv」のようにファイル名が変わります。このように「マクロで開くブックの名前は毎回変わるけど、とにかく、マクロが書かれているブックと同じフォルダに保存されているブックを開く」と。そうなると、開くブックの名前を、マクロで毎回調べなければなりません。そんなときは、次のようにします。
Sub Macro3() Dim A As String A = Dir(ThisWorkbook.Path & "\*.xlsx") Workbooks.Open ThisWorkbook.Path & "\" & A End Sub
あるいは、保存されているパスを一度変数に入れて、次のように書くことも多いです。
Sub Macro4() Dim A As String, P As String P = ThisWorkbook.Path & "\" A = Dir(P & "*.xlsx") Workbooks.Open P & A End Sub
もちろん、このマクロも正常に動作します。なお、Dir関数がよく分からないという方は、ぜひ下記の動画をご覧ください。メチャクチャ詳しく解説しています。
さて、問題はここからです。このようにマクロを作って「2つのブックを、どこか同じフォルダに保存してください」と指示し、誰か(マクロを運用する人)に渡します。その運用する人が、上記のように「C:\Workフォルダ」などに保存してくれればいいのですが、多くのパソコンビギナーは、何かとファイルやショートカットなどを「デスクトップ」や「ドキュメント」に保存しがちです。よく、デスクトップに大量のアイコンが並んでいるのを見たことはありませんか?あれです。では、今回使う2つのブック(Macro.xlsmとBook1.xlsx)を「ドキュメント」フォルダに保存したとしましょう。
「2つのブックを、どこか同じフォルダに保存してください」と言われたのですから、何も間違っていません。デスクトップがアイコンだらけになっていたからといって、そんなの個人の自由です。もちろん、上級者からは鼻で笑われるでしょうけどw 自ら「わたし、パソコンのシロウトなんです~」と言っているようなものですから。いずれにしても「C:\Workフォルダ」に保存したときは正常に動作したマクロと開きたいブックを「ドキュメント」フォルダに保存しました。さあ、先と同じマクロを実行してみましょう。
エラーです。まったく同じマクロでありながら、ブックが保存されているフォルダによってはエラーになります。さらに、これはWindows 10を使っていると、パソコンによってはエラーになるという、何とも悩ましい現象です。
保存されているフォルダによって、何が異なるのかを調べてみましょう。どう考えても怪しいのは「ThisWorkbook.Path」つまり「"マクロが書かれているブック"が保存されているパス」です。それを画面に表示してみましょう。まずは、正しく動作する「C:\Workフォルダに保存した」場合から。
Sub Macro5() MsgBox ThisWorkbook.Path End Sub
何も問題はありません。では次に、マクロがエラーになった「ドキュメントフォルダに保存した」ケースです。同じコードを実行すると、次のような結果になります。
ドキュメントフォルダのパスは、お使いのパソコン内ではなく、インターネット上のURLになっています。ファイルの存在を確認するDir関数は、Cドライブなどローカルのパソコン内では正しく動作しますが、http://などで始まる、インターネット上のURLには対応していません。今回のエラーは、これが原因です。
ご存じない方が多いのですけど、Windows 10では「ドキュメント」フォルダ、「デスクトップ」フォルダ、「ピクチャ」フォルダに保存したファイルは、お使いのパソコン内だけではなく、OneDrive内にも保存されます。OneDriveというのは、Microsoftが提供しているオンラインストレージです。ご存じない方は、"OneDrive"でググってください。ファイルをOneDriveに保存しておくと、複数のパソコンで同じファイルを操作できます。たとえば、会社のデスクトップパソコンで作成したファイルを「ドキュメント」フォルダや「デスクトップ」フォルダに保存しておけば、外出先で使うノートパソコンでも、同じファイルが同じフォルダに保存されています。外出先でファイルを編集して、会社に戻ってデスクトップパソコンを起動すれば、編集後のファイルをそのまま使用できます。まぁ、確かに便利な仕組みです。しかし、この便利な仕組みを実現するためには、ファイルがインターネット上に保存されていなければなりません。そして、インターネット上に保存されているブックでは、そのブックが保存されているパスに対して、Dir関数などを使用できないということです。この問題、けっこう根が深いと感じます。理由は、いくつかあります。
このページを読んでいるあなた、この件知っていましたか?知らない人が多いと思います。世の中は"クラウド時代"です。パソコンは、ネットに接続しているのが当然のように言われています。なので、この期に及んでは、ファイルをクラウドに保存することなど、特別に珍しいことではありません。Excelだって、標準の設定では、作成したブックの保存先はOneDriveになっています。そんなご時世ですから、こうしたWindows 10の仕様も、それほど大きな話題にならなかったのではないかと。だから知らない人が多いのでしょう。
Windows 10が一般にリリースされたのは、2015年です。本稿執筆時点から見れば、もう6年も前です。その間、複数台のパソコンにWindows 10を導入し使ってきました。しかし、私の記憶が正しければ、最初からこういう仕様ではありませんでした。昔は、Windows 10であっても、「ドキュメント」フォルダや「デスクトップ」フォルダのファイルが、ローカルのパソコン内に保存されていました。自動的にOneDriveへ保存されるようになったのは、2020年頃だったような気がします。すみません、正確には認知していません。私のところでも、気がついたらこうなっていました。もちろん、OneDriveに保存しないようになっているWindows 10も、私の手元に複数台あります。つまり、今回の「マクロがエラーになる」件は、すべてのWindows 10で起きるわけではありません。だから、よけいに悩ましいです。
ちなみに、この「自動的にOneDriveに保存する」というのは、設定で変更できます。Windowsの設定を変更すれば、従来のようにローカルパソコンだけへ保存されます。その方法は「Windows 10 ドキュメント OneDrive」や「Windows 10 デスクトップ OneDrive」などのキーワードでググってください。図解で詳しく解説しているページが見つかります。なお、自分のWindows 10がどちらなのかは、エクスプローラを見れば分かります。
「デスクトップ」「ドキュメント」「ピクチャ」の左に、何やらアイコンが表示されているのが分かりますか?このアイコンが表示されていたら、OneDriveに保存されています。
今回マクロがエラーになった根本的な原因は、
Sub Macro6() ''ブックを開く(OK) Workbooks.Open ThisWorkbook.Path & "\Book1.xlsx" End Sub Sub Macro7() ''上書き保存(OK) Workbooks.Open ThisWorkbook.Path & "\Book1.xlsx" ActiveWorkbook.Save End Sub Sub Macro8() ''名前をつけて保存(OK) Workbooks.Add ActiveWorkbook.SaveAs ThisWorkbook.Path & "\Book2.xlsx" End Sub
ブックを開いたり、ブックを保存するような操作では、基本的に問題はないようです。しかし、次のような操作はエラーになります。
Sub Macro9() ''画像を挿入する(Error) ActiveSheet.Pictures.Insert ThisWorkbook.Path & "\Sample1.jpg" End Sub Sub Macro10() ''CSVファイルを開く(Error) Open ThisWorkbook.Path & "\Sample.csv" For Input As #1 ''何かの処理 Close #1 End Sub Sub Macro11() ''Accessのデータを開く(Error) Dim DB As Database Set DB = OpenDatabase(ThisWorkbook.Path & "\Sample.mdb") ''何かの処理 DB.Close End Sub
Excelのブックではない外部ファイルを操作してみましたが全滅です。ちなみに最後のMacro11は、ちゃんとDAOに参照設定しています。エラーは「ファイルが見つからない」ということでした。まぁ、今さらJETエンジンを使うのもどうかと思いますがw すみません、私の環境にはACEエンジンを入れていないものでして。ACEエンジンでaccdbファイルを開くのは試していません。勝手な想像ですけど、たぶんダメだと思います。また、ファイルの存在を確認するDir関数だけでなく、次のようなファイル操作もアウトです。
Sub Macro12() ''ファイル名の変更(Error) Name ThisWorkbook.Path & "\Book1.xlsx" As ThisWorkbook.Path & "\Book2.xlsx" End Sub Sub Macro13() ''ファイルの削除(Error) Kill ThisWorkbook.Path & "\Book1.xlsx" End Sub Sub Macro14() ''ファイルのコピー(Error) FileCopy ThisWorkbook.Path & "\Book1.xlsx", "C:\Work\Sample.xlsx" End Sub Sub Macro15() ''ファイル保存日時の取得(Error) MsgBox FileDateTime(ThisWorkbook.Path & "\Book1.xlsx") End Sub Sub Macro16() ''サブフォルダの作成(Error) MkDir ThisWorkbook.Path & "\Data" End Sub
思いつくままに動作確認してみましたが、こうしてみると、けっこういろいろなケースがありますね。最後に、この問題が根深いと感じるもうひとつの理由は、
ほんこれ・・・w
では、どうすればいいかと。方法は2つしかありません。
「デスクトップ」フォルダや「ドキュメント」フォルダに保存したファイルは、インターネット上のOneDriveだけに存在するのではありません。ちゃんと、お使いのパソコン内にも同じファイルが保存されています。ブックのPathプロパティが、パソコン内のパスである「C:\~」ではなく、URLの「https://~」を返すというのが根本的な問題です。ですからVBAで、明示的に「C:\~」のパスを指定してやればいいです。
ここで考えるべきことは3つあります。
2.と3.に関しては簡単に解決できます。クラウドのOneDriveと、ローカルパソコンのフォルダを同期させるのですから、Windows 10はおそらく同期させるローカルのパス「C:\Users\<ユーザー名>\OneDrive」を、どこかに設定として保持しているはずです。「たぶん、ここにあんじゃね?」と当たりをつけたら一発で見つかりました。環境変数に設定されています。
上記の「offic」というのが、いま使っているWindows 10のユーザー名です。余談ですけど、本当は「officetanaka」としたかったのですが、寝ぼけていたのか酔っ払っていたのか、「offic」まで入力してEnterキーを押してしまったようです。もう数年前の話です。さらに最近では、新しいパソコンにWindows 10を入れたとき、同じアカウントだとユーザー名まで勝手に引き継いじゃいます。インストール時に変更すればいいのですが、もし同期でトラブルがあったら嫌なので、もうこのままにしていますw 皆様も、ユーザー名を入力するときは指さし確認をオススメします。環境変数というのは、大昔のMS-DOS時代に使われていた仕組みで、よくconfig.sysに記述しました。OSの設定みたいなものです。大昔の仕組みですが、今でも現役で使われています。そして、VBAには、この環境変数の内容を取得する関数が用意されています。Environ関数です。
Sub Macro17() MsgBox Environ("OneDrive") End Sub
これで、ローカルに保存されているパスは分かりました。問題は
私は心配性なので、何らかの事情でMicrosoftが、このURLを変更する可能性もあるのでは?と考えてしまいます。でも、もしある日急にこのURLが変更されたら、それこそ世界中で大混乱になるだろうし、さすがにそんなことはしないだろうなと。心配ではありますが、ここはひとつ「https://d.docs.live.net/」部分は今後も変わらないとしましょう。「*****」部分は、OneDriveのアカウントに紐付けられたユーザーIDです。見ると、16進数×16文字で表されています。ここも、15文字だったり17文字と文字数が可変では処理が煩雑になりそうです。まぁ、でも、先の「https://d.docs.live.net/」部分は固定であるとしたのですから、この16進数×16文字も固定と考えましょう。ちなみに、この文字数で表されるIDの数は、18,446,744,073,709,551,616個( 約1,844京)です。世界の人口よりもだいぶ大きいですから、おそらく大丈夫でしょう。さあ、そうなるとURL部分の文字数は全部で「24文字+16文字=40文字」です。つまり、41文字目から後ろがローカルのパスですから、次のように処理できます。
Sub Macro18() Dim P As String P = ThisWorkbook.Path MsgBox Environ("OneDrive") & Mid(P, 41) End Sub
文字列の右全部を抜き出すには、Right関数よりもMid関数の方が簡単です。全体の文字数を調べなくていいですからね。結果は次のとおりです。ThisWorkbook.Pathの結果を一度変数Pに入れているのは、本当はこのパスを、条件分岐で調べなければならないからです。
ここで「ん?」と、気になった方もいらっしゃるでしょう。フォルダ名やファイル名を区切るパスセパレータに「\」と「/」の2種類が混在しているぞと。それでいいのか?って。いいんです!(キリ 実は、Windowsのルールでは、パスセパレータは「\」でも「/」でもよく、ひとつのパスの中に混在してもOKとなっています。さらには、相対パスを表す「..」なんかも指定できたりします。かなり寛容なんですね。さあ、上記でエラーになったマクロは、次のように書き換えればいいです。
【エラーになるコード】 Sub Macro4() Dim A As String, P As String P = ThisWorkbook.Path & "\" A = Dir(P & "*.xlsx") Workbooks.Open P & A End Sub
【正常に動作するコード】 Sub Macro19() Dim A As String, P As String P = ThisWorkbook.Path & "\" If Left(P, 4) = "http" Then P = Environ("OneDrive") & Mid(P, 41) A = Dir(P & "*.xlsx") Workbooks.Open P & A End Sub
修正自体は、1行を追加するだけなのですが、先にも詳解したように、このエラーは「パソコン(というかWindows 10)の状態」+「保存されているフォルダの場所」+「パスに対して何の操作をしているか」という3つの要因が絡んできます。マクロがエラーになったときは、冷静に原因を突き止めてください。