DOBON.NET プログラミング道: .NET Framework, VB.NET, C#, Visual Basic, Visual Studio, インストーラ, ...

自分のアプリケーションの実行ファイルのパスを取得する
VB6のApp.Pathと同じ事を行うには?

ここでは、自分自身のアプリケーションの実行ファイルのパスや、実行ファイルのあるフォルダのパスを取得する方法を紹介します。また、VB6のApp.Pathの代わりになる方法を紹介します。

Assembly.GetExecutingAssemblyを使用する方法

Locationプロパティで取得する

Assembly.GetExecutingAssemblyメソッドが返すAssemblyオブジェクトのLocationプロパティにより、自分自身のアプリケーションの実行ファイルのパスを取得することができます。

VB.NET
コードを隠すコードを選択
'自分自身の実行ファイルのパスを取得する
Dim appPath As String = _
    System.Reflection.Assembly.GetExecutingAssembly().Location
C#
コードを隠すコードを選択
//自分自身の実行ファイルのパスを取得する
string appPath = System.Reflection.Assembly.GetExecutingAssembly().Location;

Assembly.GetExecutingAssemblyメソッドはDLL内で呼び出すと、そのDLLを表すAssemblyを返します。ですので、上記のコードをDLLで呼び出すと、appPathはDLLのパスになります。

CodeBase、EscapedCodeBaseプロパティで取得する

Assembly.Locationプロパティの代わりにAssembly.CodeBaseプロパティAssembly.EscapedCodeBaseプロパティを使ってもパスを取得できます。これらのプロパティはパスをURIで返し、EscapedCodeBaseプロパティはURLエンコードされた文字列を返します。LocationプロパティとCodeBaseプロパティ(あるいはEscapedCodeBaseプロパティ)の違いは下記の補足で説明しますが、片方のプロパティで目的のパスが取得できなくても、もう片方のプロパティで取得できる場合もあります。

なおURIをWindowsで使われる普通のパス形式に変換する方法は、「URIのローカルファイルパスをWindowsのパス形式に変換する」で説明しています。

補足:上記以外のLocationとCodeBase(あるいはEscapedCodeBase)プロパティの違いについては、「Assembly.CodeBase vs. Assembly.Location - Suzanne Cook's .NET CLR Notes - Site Home - MSDN Blogs」に説明があります。これによると、例えばアセンブリがインターネットからダウンロードされた場合、CodeBaseは「http://」で始まる文字列になり、Locationは「C:\」で始まる文字列になるということです。また、ファイルがシャドウコピーされた場合は、CodeBaseはシャドウコピーされる前の場所を返し、Locationはシャドウコピーされた後の場所を返します。(例えばASP.NETにおいては、GetExecutingAssemblyメソッドが返すAssemblyのCodeBaseはbinディレクトリのDLLになり、LocationはHttpRuntime.CodegenDirプロパティが返すディレクトリのDLLになるようです。また、MbUnit.GUIのようなツールを使用した時も違うパスになるようです。)さらに、GACのアセンブリではCodeBaseがセットされないかもしれませんが、Locationは必ずセットされるということです。

これらのプロパティの違いが分かる例を以下に示します。

VB.NET
コードを隠すコードを選択
'「C:\My Application\ClassLibrary1.dll」に書かれた以下のコードを
'「C:\My Application\Application.exe」から呼び出した時の結果をコメントに記す

Console.WriteLine(System.Reflection.Assembly.GetExecutingAssembly().Location)
'C:\My Application\ClassLibrary1.dll

Console.WriteLine(System.Reflection.Assembly.GetExecutingAssembly().CodeBase)
'file:///C:/My Application/ClassLibrary1.DLL

Console.WriteLine(System.Reflection.Assembly.GetExecutingAssembly().EscapedCodeBase)
'file:///C:/My%20Application/ClassLibrary1.DLL
C#
コードを隠すコードを選択
//「C:\My Application\ClassLibrary1.dll」に書かれた以下のコードを
//「C:\My Application\Application.exe」から呼び出した時の結果をコメントに記す

Console.WriteLine(System.Reflection.Assembly.GetExecutingAssembly().Location);
//C:\My Application\ClassLibrary1.dll

Console.WriteLine(System.Reflection.Assembly.GetExecutingAssembly().CodeBase);
//file:///C:/My Application/ClassLibrary1.DLL

Console.WriteLine(System.Reflection.Assembly.GetExecutingAssembly().EscapedCodeBase);
//file:///C:/My%20Application/ClassLibrary1.DLL

Assembly.GetEntryAssemblyを使用する方法

DLL内で使用してもEXEファイルのパスを取得するには、GetExecutingAssemblyメソッドの代わりにAssembly.GetEntryAssemblyメソッドを使用します。

GetEntryAssemblyメソッドはアンマネージコードから呼び出された時などではNULLを返しますので、通常はNULLのチェックが必要です。

先ほどのGetExecutingAssemblyメソッドの使用例をGetEntryAssemblyに置き換えたものを以下に示します。

VB.NET
コードを隠すコードを選択
'「C:\My Application\ClassLibrary1.dll」に書かれた以下のコードを
'「C:\My Application\Application.exe」から呼び出した時の結果をコメントに記す

Console.WriteLine(System.Reflection.Assembly.GetEntryAssembly().Location)
'C:\My Application\Application.exe

Console.WriteLine(System.Reflection.Assembly.GetEntryAssembly().CodeBase)
'file:///C:/My Application/Application.EXE

Console.WriteLine(System.Reflection.Assembly.GetEntryAssembly().EscapedCodeBase)
'file:///C:/My%20Application/Application.EXE
C#
コードを隠すコードを選択
//「C:\My Application\ClassLibrary1.dll」に書かれた以下のコードを
//「C:\My Application\Application.exe」から呼び出した時の結果をコメントに記す

Console.WriteLine(System.Reflection.Assembly.GetEntryAssembly().Location);
//C:\My Application\Application.exe

Console.WriteLine(System.Reflection.Assembly.GetEntryAssembly().CodeBase);
//file:///C:/My Application/Application.EXE

Console.WriteLine(System.Reflection.Assembly.GetEntryAssembly().EscapedCodeBase);
//file:///C:/My%20Application/Application.EXE

Application.ExecutablePathとStartupPathプロパティを使う

Windowsフォームアプリケーションでは、アプリケーションを開始した実行ファイルのフルパスをApplication.ExecutablePathプロパティで取得できます。また、アプリケーションを開始した実行ファイルのフォルダはApplication.StartupPathプロパティで取得できます。

Application.ExecutablePathプロパティとApplication.StartupPathプロパティは、DLL内で使用したとしても、EXEファイルのパスを返します。

補足:Application.ExecutablePathは、基本的にはAssembly.GetEntryAssemblyメソッドが返すAssemblyのCodeBaseとなり、GetEntryAssemblyメソッドがNULLを返したらWin32 APIのGetModuleFileName関数の結果を返すようです。Application.StartupPathプロパティは、GetModuleFileName関数の結果からフォルダ名を返しているようです。
VB.NET
コードを隠すコードを選択
Console.WriteLine(System.Windows.Forms.Application.ExecutablePath)
'C:\My Application\Application.exe

Console.WriteLine(System.Windows.Forms.Application.StartupPath)
'C:\My Application
C#
コードを隠すコードを選択
Console.WriteLine(System.Windows.Forms.Application.ExecutablePath);
//C:\My Application\Application.exe

Console.WriteLine(System.Windows.Forms.Application.StartupPath);
//C:\My Application

VB.NETで、My.Application.Info.DirectoryPathプロパティを使う

.NET Framework 2.0以降のVB.NETでは、「My.Application.Info.DirectoryPath」によってアプリケーションのフォルダを取得できます。これは、Application.StartupPathプロパティとほぼ同等です。

補足:My.Application.Info.DirectoryPathは、基本的には「Assembly.GetEntryAssembly().Location」のフォルダですが、GetEntryAssemblyがNULLを返す時は、「Assembly.GetCallingAssembly().Location」のフォルダとなるようです。
VB.NET
コードを隠すコードを選択
Console.WriteLine(My.Application.Info.DirectoryPath)
'C:\My Application

AppDomain.CurrentDomain.BaseDirectoryプロパティを使う

現在のアプリケーションドメインのベースディレクトリは、「AppDomain.CurrentDomain.BaseDirectory」で取得できます。これは、「AppDomain.CurrentDomain.SetupInformation.ApplicationBase」と同じです。このフォルダは大抵実行ファイルのフォルダと同じになりますが、そうでない可能性もあります。

VB.NET
コードを隠すコードを選択
Console.WriteLine(System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase)
'C:\My Application\
C#
コードを隠すコードを選択
Console.WriteLine(System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase);
//C:\My Application\

結局、VB6のApp.Pathの代わりになるものは?

MSDNの「App Object Changes in Visual Basic .NET」によると、VB6のApp.Pathに代わるものは「System.Reflection.Assembly.GetExecutingAssembly().Location」とのことです。ただしこれはファイルのフルパスを返しますので、App.Pathと同じようにフォルダのパスのみを取得するのであれば、さらにPath.GetDirectoryNameメソッドを使います。

VB.NET
コードを隠すコードを選択
Public Shared Function GetAppPath() As String
    Return System.IO.Path.GetDirectoryName( _
        System.Reflection.Assembly.GetExecutingAssembly().Location)
End Function
C#
コードを隠すコードを選択
public static string GetAppPath()
{
    return System.IO.Path.GetDirectoryName(
        System.Reflection.Assembly.GetExecutingAssembly().Location);
}

また、MSDNの「HOW TO: Determine the Executing Application's Path」によると、「System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase」がApp.Pathの代わりになるとのことです。ただしこの場合、返されるパスはURIになりますので、必要ならば変換が必要になります。その方法は、「URIのローカルファイルパスをWindowsのパス形式に変換する」で説明しています。

VB.NET
コードを隠すコードを選択
Public Shared Function GetAppPath2() As String
    Dim path As String = _
        System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase
    'URIを通常のパス形式に変換する
    Dim u As New Uri(path)
    path = u.LocalPath + Uri.UnescapeDataString(u.Fragment)
    Return System.IO.Path.GetDirectoryName(path)
End Function
C#
コードを隠すコードを選択
public static string GetAppPath2()
{
    string path =
        System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase;
    //URIを通常のパス形式に変換する
    Uri u = new Uri(path);
    path = u.LocalPath + Uri.UnescapeDataString(u.Fragment);
    return System.IO.Path.GetDirectoryName(path);
}
補足:「c# - How do I find the current executable filename? - Stack Overflow」によると、Xenocode Postbuildのような仮想化された環境では、上記のどの方法でも正しく実行ファイルのフルパスを取得できないということです。ただし、実行ファイルのフォルダは「Assembly.GetEntryAssembly().Location」で、ファイル名は「Process.GetCurrentProcess().ProcessName」で正しく取得できるのため、この2つを合わせてフルパスを作成できるそうです。
  • 履歴:
  • 2011/11/22 説明を大幅に書き加えた。
  • 2012/6/27 Application.ExecutablePathとStartupPathのサンプルコードで、コメントの出力結果が逆だったのを修正。
  • 2013/7/24 構成を変更。

注意:この記事では、基本的な事柄の説明が省略されているかもしれません。初心者の方は、特に以下の点にご注意ください。

  • Windows Vista以降でUACが有効になっていると、ファイルへの書き込みに失敗する可能性があります。詳しくは、こちらをご覧ください。
  • .NET Tipsをご利用いただく際は、注意事項をお守りください。