본문 바로가기

Programing/닷넷

[C#] 애플리케이션 경로

윈도우 API에 보면 현재 디렉토리의 경로를 구하는 함수가 있다.

MSDN GetCurrentDirectory 함수 : http://msdn.microsoft.com/en-us/library/windows/desktop/aa364934(v=vs.85).aspx

C#에서는 Directory.GetCurrentDirectory 메서드가 그 역할을 수행한다.



사실 이 경로보다 exe의 경로가 더 알고 싶을 경우가 있다. 예를 들면 서비스 애플리케이션의 경우 시스템이 실행을 시켜주기 때문에 현재 디렉터리나 상대 디렉터리를 사용하게 되면 엉뚱한 SYSTEM 폴더 경로를 참고하게 되기 때문이다.


이럴 경우에는 GetModuleFileName 함수를 이용하면 된다.

MSDN GetModuleFileName 함수 : http://msdn.microsoft.com/en-us/library/ms683197%28VS.85%29.aspx

닷넷의 경우는 어떤 함수들이 있을까?


WinPath.zip

1) System.Windows.Forms.Application.ExecutablePath

윈폼을 쓰고 있다면(설령 사용하고 있지 않다고 해도) 이것을 사용하면 아래와 같이 결과를 가져온다.


이 프로퍼티의 구현은 아래와 같다. 중간에 보면 UnsafeNativeMethods.GetModuleFileName 부분이 있는데, 위에서 알아본 Win32 API 함수를 호출한다는 것을 짐작해 볼 수 있다.

public static string ExecutablePath

{

    get

    {

        if (executablePath == null)

        {

            Assembly entryAssembly = Assembly.GetEntryAssembly();

            if (entryAssembly == null)

            {

                StringBuilder buffer = new StringBuilder(260);

                UnsafeNativeMethods.GetModuleFileName(
                    NativeMethods.NullHandleRef, buffer, buffer.Capacity);

                executablePath = IntSecurity.UnsafeGetFullPath(buffer.ToString());

            }

            else

            {

                string escapedCodeBase = entryAssembly.EscapedCodeBase;

                Uri uri = new Uri(escapedCodeBase);

                if (uri.Scheme == "file")

                {

                    executablePath = NativeMethods.GetLocalPath(escapedCodeBase);

                }

                else

                {

                    executablePath = uri.ToString();

                }

            }

        }

        Uri uri2 = new Uri(executablePath);

        if (uri2.Scheme == "file")

        {

            new FileIOPermission(FileIOPermissionAccess.PathDiscovery, executablePath).Demand();

        }

        return executablePath;

    }

}


2) System.Reflection.Assembly.GetExecutingAssembly().Location

리플렉션 네임스페이스에 보면 어셈블리하위에 실행하고 있는 어셈블리의 경로를 구해올 수가 있다.


GetExecutingAssembly 메서드는 아래와 같이 구현되어 있고

[MethodImpl(MethodImplOptions.NoInlining)]

public static Assembly GetExecutingAssembly()

{

    StackCrawlMark lookForMyCaller = StackCrawlMark.LookForMyCaller;

    return nGetExecutingAssembly(ref lookForMyCaller);

}


Location 프로퍼티는 아래과 같이 구현되어 있다. Location -> GetLocation() -> _GetLocation()

public virtual string Location

{

    get

    {

        string location = this.GetLocation();

        if (location != null)

        {

            new FileIOPermission(FileIOPermissionAccess.PathDiscovery, location).Demand();

        }

        return location;

    }

}


internal string GetLocation()

{

    return this.InternalAssembly._GetLocation();

}


[MethodImpl(MethodImplOptions.InternalCall)]

private extern string _GetLocation();


3) AppDomain.CurrentDomain.SetupInformation.ApplicationName

사실 이 경로는 실행파일 위치라기 보다는 실행파일이 있는 디렉터리 경로이다.

실행파일의 이름이 바뀌지 않고 이미 알고 있는 경우에는 문자열을 합치면 전체 실행파일경로로 표현을 할 수 있겠다.
 (또한 역으로 실행파일이 바뀌어서는 안되는 경우, 바뀌었는지를 #1~2와 #3을 비교해보면 알 수 있을 것이다.) 

참고로 아래와 같이 끝에 \가 붙는다.