絶対パス指定と相対パス指定

「カレントフォルダ」を誤解していないでしょうか。
掲示板に時々挙げられる話題です。 「カレントフォルダ」とか「カレントパス」が、言葉だけそのまま一人歩きするため、結構、誤解されたままで済まされているのでは?、と疑問になりました。 「相対パス指定」を使う限りは「カレントフォルダ」が起点になるのでその所在は重要なのですが、Excelの場合は、前後に行なう「ファイルを開く」の操作などで「カレントフォルダ」は一定しません。 この状況を知らないで、「カレントフォルダ」とは「そのブックを開いたフォルダのこと」と信じてしまっている人が多いような気がします。



「カレントフォルダ」とはどこ?
「カレントフォルダ」は、「CurDir関数」で取得できます。これがどこのフォルダを指しているのか確認してみましょう。
スタートメニューからMicrosoft Excelを開く
まず、スタートメニューから単純に「Microsoft Excel」を開きます。

続いて、「Visual Basic Editor」を開きます。(Alt+F11で開きます。)
Visual Basic Editorで標準モジュールを追加
開いたら、プロジェクトエクスプローラでプロジェクト名を右クリックして、標準モジュールを追加します。

Subプロシージャを作成します。
CurDirを表示するプロシージャを作成する
記述は下記からコピーして貼り付ければそのまま動かせます。

Sub カレントフォルダの表示()
MsgBox "現在のカレントフォルダは" & vbCrLf & _
    CurDir & vbCrLf & "です。"
End Sub

では、作成したマクロを動かしてみて下さい。
作成したプロシージャを起動させる
これは、ツールバーのマクロから起動させる画面です。Visual Basic Editor側で起動させても構いません。

このようなメッセージが表示されるはずです。
CurDirがメッセージに表示される

ここで表示されるフォルダは「オプション」で指定されています。
「オプション」の指定を確認する
デフォルトでは、ログインしたユーザーの「マイドキュメント」フォルダになっていますが、任意に変更していればその指定のフォルダが表示されたはずです。 ここで変更することは可能ですが、変更したフォルダはExcelを一旦閉じないと有効になりません。

既存のブックを開くと「カレントフォルダ」は移動するか(1)
では、まず、既存のブックを「エクスプローラ」や「フォルダ」ウィンドウからダブルクリックするなどで開いてみます。
既存のブックを「エクスプローラ」から開く
※ここで開く既存のブックは、最初に表示された「カレントフォルダ」とは違う(できれば違うドライブ)のフォルダとして下さい。

開いたら、先ほど作成しておいた「カレントフォルダ表示」マクロを起動します。
「カレントフォルダ表示」マクロを起動
Excelが起動していない状態から開いた場合は、上記の作業でプロシージャを作成して起動させて下さい。

このようなメッセージが表示されるはずです。
CurDirがメッセージに表示される
どうでしょう、「カレントフォルダ」が当初表示されたフォルダから変動していないですよね。

既存のブックを開くと「カレントフォルダ」は移動するか(2)
次は、Excelの「開く」のダイアログから先ほど開いた既存ブックを開いてみます。
「開く」のダイアログから開く

開いたら、前回同様に作成しておいた「カレントフォルダ表示」マクロを起動します。
CurDirがメッセージに表示される
今度は、「カレントフォルダ」が開いた既存ブックのフォルダに移ったのが分かります。

ここで、今、開いたブックを閉じてしまって、再度、「カレントフォルダ表示」マクロを起動してみます。
CurDirがメッセージに表示される
それでも、「カレントフォルダ」は元には戻らずそのままです。 つまり、最後にこのような方法で開いたブックのフォルダになってしまうのです。 所望するブックを開いて一旦「カレントフォルダ」がそのブックのフォルダになったとしても、さらに後から他のブックを開いた場合は「カレントフォルダ」も移動してしまい、 それは閉じた後でも元には戻らないということになります。
さらに、「開く」のダイアログで他のドライブやフォルダを開き、実際に既存ブックを開くことなくキャンセルした場合でも「カレントフォルダ」も移動してしまいます。

既存のブックを開くと「カレントフォルダ」は移動するか(3)
では、マクロから既存ブックを開いたらどうなるでしょう。
既存ブックを開くマクロを作成
(上の「実験」を行なった状態をリセットするため、Excelは新しく開き直して下さい。)
コードは以下のようになっていますが、既存ブックのフォルダ/ファイル名は実情に合わせて変更が必要です。

Sub マクロからブックを開く()
Workbooks.Open "C:\TEMP\HURIGANA1.xls"
ThisWorkbook.Activate
Call カレントフォルダの表示
End Sub

では、この「マクロからブックを開く」マクロを実行してみます。
既存ブックを開くマクロを実行

このようなメッセージが表示されるはずです。
CurDirがメッセージに表示される
やはり、「エクスプローラ」から開いたものと同様の結果になりました。同じマクロでも「GetOpenFilenameメソッド」を使って「開く」のダイアログを表示させてファイル名を受け取る場合は「カレントフォルダ」は移動します。

これらのことから分かることは....
これらのことから分かることは、マクロの記述上で他のファイルやブックを取り扱う場合に、フォルダの記述を「カレントフォルダ」に任せて省略してしまうことは危険だということです。
また、逆に、「カレントフォルダ」を使わないと他のファイルやブックを扱うことができないと思っている人もいるようですが、ほとんどの場合でそのようなことはなく、フルパスでファイル名を指定すれば良いはずです。
「カレントフォルダ」を利用するなら、「カレントフォルダ」の状態をコントロールすることも含めて利用するようにしなければなりません。

でもマクロ上では「相対パス」で指定して利用したい。
マクロで他のファイルやブックを扱うような仕組みを用意して配布先での利用を考えた場合、配布先でのフォルダ構成が分からないため「相対パス」で指定することで環境依存部分を吸収させたいと考えるケースがあります。
この考え方は「もっとも」なことですが、ここまで説明してきたことを理解しないでやってしまうととんでもないことになるのは、もうお分かりですね。
誤解されていた方は、おそらく、「カレントフォルダ」を「自ブックの所在フォルダ」だと思っていたでしょうから、そうだとするなら「自ブックの所在フォルダ」をそのまま使うようにして下さい。
実行されているマクロが収容されている「自ブックの所在フォルダ」は、

ThisWorkbook.Path
です。
上のようなケースでもThisWorkbook.Path」は正しく「自ブックの所在フォルダ」を指します。他ブックを開いたり閉じたりしても影響は受けません。
もし、「自ブックの所在フォルダ」の配下にある「DATA」フォルダを指定するというなら、

ThisWorkbook.Path & "\DATA"
これで済みます。

それでもマクロ上では「相対パス」で指定して利用したい。
そうですか。それでは、まず、「カレントフォルダ」を任意のフォルダに移動させることを考えてみましょう。
「カレントフォルダ」を任意のフォルダに移動させるにはChDirステートメント」を使います。
「カレントフォルダ」を「自ブックの所在フォルダ」に移動させるなら、

ChDir ThisWorkbook.Path
と、これだけになってしまうのですが、ここに問題があります。
「ステートメント」という類のものはWindowsができる以前からマイクロソフトBASICに搭載されていたもので、 ネットワークに関しての対応がないことと、それ以前に「ドライブ」を超えられない問題があります。
まず、「カレントドライブ」を変更するのがChDriveステートメント」です。これを併用すればローカルドライブと、ドライブシンボルにマウントされたネットワークドライブまでの「カレントフォルダ」の移動は可能です。 ChDriveステートメント」では最初の1文字しか認識しないので、元のフォルダ名をそのまま指定してしまえば良いので、

ChDrive ThisWorkbook.Path
ChDir ThisWorkbook.Path
と2つの「ステートメント」を連記して下さい。当然、ChDirステートメント」が後でなければいけません。
この後に、

MsgBox "現在のカレントフォルダは" & vbCrLf & _
    CurDir & vbCrLf & "です。"
これを追加しておけば、「カレントフォルダ」が確認できます。

\\」で始まるネットワーク上の共有名(あるいはその配下)のフォルダを「カレントフォルダ」にしようという場合は、全く方法が違います。 上記のような「ステートメント」では吸収できないので、以下のような方法を採ります。

'カレントディレクトリのチェンジ(Windows2000以降)
Sub ChangeCurPath()
    CreateObject("WScript.Shell").CurrentDirectory = ThisWorkbook.Path
End Sub
但し、この方法は「WSH」を利用していますので、デフォルトで「WSH」がインストールされていないWindows9x/NTでは「WSH」をインストールしないと動作しません。 ただ、「WSH」を利用しない方法として、APIを用いる方法もあります。

Option Explicit
'カレントディレクトリのチェンジ
Declare Function SetCurrentDirectory Lib "kernel32" _
    Alias "SetCurrentDirectoryA" (ByVal lpPathName As String) As Long

'カレントディレクトリのチェンジ(Windows9x/NTも可?)
Sub ChangeCurPath()
    SetCurrentDirectory ThisWorkbook.Path
End Sub
※但し、Windows9x/NT環境は手元にないので、この記述の動作確認はできていません。

「相対パス」を「絶対パス」に変換する。
「相対パス」のままExcelワークブックを開いたりすることは可能だと思いますが、一旦、「絶対パス」に変換させてしまった方が何かの問題発生時などでの対応が簡単でしょう。
単に「カレントフォルダ」を変換するというのではなく、「相対パス」のままで上位や下位のフォルダを指定して「絶対パス」に変換させることが可能です。
ここでは、「FSO」を利用する方法を紹介します。
定数(cnsPath)に「自フォルダ」「親フォルダ」「配下のDATAフォルダ」などを用意したので、コメント位置を変えて試してみて下さい。

Option Explicit
'Const cnsPath = ""      ' 自フォルダ
Const cnsPath = "../"   ' 親フォルダ
'Const cnsPath = "DATA"  ' 配下のDATAフォルダ

' 相対パスより絶対パスを取得(FSO)
Sub GetCurPath()
    ' 参照設定:Microsoft Scripting Runtime
    Dim objFso As FileSystemObject

    Set objFso = New FileSystemObject
    MsgBox FSO.GetAbsolutePathName(cnsPath)
    Set objFso = Nothing
End Sub