はじめに
先日納品したExcelのVBAのプロジェクトで、お客様から「使えないんだけど、、、」という問い合わせをもらったので、調べてみたらけっこうハマったのでメモっておきます。
原因
エラーの内容を見ると、どうもフォルダの作成時に失敗している模様。
フォルダの作成にはMakeSureDirectoryPathExists()を使っているのですが、どうもこれがFalseを返しているようです。
この関数は、引数として与えたパスにフォルダが存在していなければ勝手に作ってくれるという便利関数なのですが、普通に使っている分にはよほどエラー(False)を返してくることはありません。
今回も、普通に適切なパスを渡してやっているはずなのに、お客様の環境ではエラーになるとのことでした。
最初はOSやエクセルのバージョンも疑いましたが、特に問題なし。
ふと思いついて、エクセルがOneDriveフォルダにある場合はどうなるんだろう?と思い、自分の環境でOneDriveフォルダの中に問題のエクセルを放り込んで実行してみたところ、見事に問題を再現することができました。
どうやら、OneDriveフォルダにおいてあるエクセルのVBAでThisWorkbook.Pathを参照すると、OneDriveのインターネット上のファイルパスが返ってくるようなのです。
例えばこんな感じになります。
https://から始まるパスになっていますね。
こんなパスを使ってフォルダを作ろうとしてもうまくいくわけがありません。
OneDriveフォルダはローカルのフォルダと同期しているので、自分としては、ローカルのフォルダパスを指定したつもりなのに、外部URLの形でファイルパスが返ってくるようです。
解決方法
まあ、問題のエクセルファイルをOneDriveでないフォルダにおいておけば問題ないのですが、それではお客様も納得しない場合もあるかもしれません。
しかし、調べてみたところ、プログラム側で簡単に解決する方法はないようです。
もう少し正確に言うと、あるにはあるけど不確実な部分があったり、割と難解なコードが増えたりするので、できれば避けたいという感じです。
そんなわけで色々探して、やっとみつけました。
「これならギリ許容か」というくらいスレスレの解決策です。
詳細は以下を見て下さい。
簡単に言うと、OneDrive上にエクセルファイルを置き、そのファイルが置いてあるフォルダのシンボリックリンクをOneDriveではないフォルダに置く、というものです。
- OneDrive上にフォルダを作り、そこに対象のエクセルを置く
- OneDriveでないローカルフォルダを用意する
- コマンドプロンプトを管理者権限で起動する
- コマンドプロンプトでシンボリックリンクを作成する
- 作成されたシンボリックリンク内のエクセルを使う
もう少し詳しく書いてみます。
ローカルフォルダを用意する
まず、以下のようにOneDrive配下ではないところにローカルフォルダを用意します。
※以下の画像では分かりやすいようにOneDrive上のフォルダも表示しています。
ここでは、デスクトップ上に「local」というフォルダを用意しました。
やりたいことは、この「local」フォルダの配下に、新しいシンボリックリンクをつくることです。
シンボリックリンクとは、ショートカットみたいなものです。
コマンドプロンプトを管理者権限で起動する
次に、コマンドプロンプトを管理者権限で起動します。
私がやってみた限り、管理者権限でないと「権限がない」といって怒られます。
コマンドプロンプトを管理者権限で起動するには、Windowsのスタートメニューをクリックしたあと「cmd」と入力して、表示される選択肢から「管理者で実行」を選択します。
もう少し詳しく解説します。
まず、Windowsアイコンをクリックすると以下のような画面が出てくると思います。
ここで、カーソルはどこにもないのですが、とりあえず「cmd」と打ってみます。
すると、以下のように候補となるアプリケーションが出てくるので、「管理者として実行」を選択します。
すると、コマンドプロンプトが起動します。見た目ではあまり分かりませんが、管理者権限で起動されているはずです。
シンボリックリンクを作成するコマンドを入力する
次に、シンボリックリンクを作成するコマンドを入力します。
書式は以下となります。
mklink /d "C:\Original\Folder\Location" "C:\Users\NAME\OneDrive\FOLDERNAME\"
簡単にこのコマンドの意味を解説しておきます。
最初のmklinkはコマンドの名前ですね。
/d オプションは、ディレクトリのシンボリックリンクを作成することを示します。
その次は作成するシンボリックリンク名を指定します。
そして最後は、リンクの元となるフォルダを指定します。
上記を踏まえ、「local」フォルダの下にさらに「atarashii_folder」というシンボリックフォルダーを作ることにした場合、実際に入力するコマンドは以下になります(※1)。
mklink /d "C:\Users\username\Desktop\local\atarashii_folder" "C:\Users\username\OneDrive\ドキュメント\one_drive"
※1 「atarashii_folder」という部分は任意の名前にしてください。ここだけは手打ちをする必要があります(既存のフォルダを指定するのではなく、「作成するシンボリック名」を指定する必要があるためです。)。
実際に入力した結果はこんな感じになります。
Tips
フォルダの全パスを手入力するのは難しいので、以下のようにアドレスバーからパスをコピーして、コマンドプロンプトのウィンドウ内で右クリックしましょう。すると、コマンドプロンプトに貼り付けることができます。
結果を確認
シンボリックリンクを作成すると、ローカルフォルダにショートカットのようなアイコンができています。
このフォルダの中に入ると、エクセルファイルがあるはずなので、そこから起動すると、ThisWorkbook.Pathが期待通りローカルPCのパスを返してくれます(下参照)。
これで無事にローカルPCのパスを取得できるようになりました。
お客様にこの手順を踏んでもらうのは、なかなか難しいかもしれませんが、参考になれば幸いです。
コメント