Làm cách nào tôi có thể nhận đường dẫn của ứng dụng trong ứng dụng bảng điều khiển .NET?


953

Làm cách nào để tìm đường dẫn của ứng dụng trong ứng dụng bảng điều khiển?

Trong Windows Forms , tôi có thể sử dụng Application.StartupPathđể tìm đường dẫn hiện tại, nhưng dường như điều này không có sẵn trong một ứng dụng bảng điều khiển.


5
Bạn có cài đặt .NET Framework trên máy đích (Client, Development) không? nếu câu trả lời của bạn là đúng; Vì vậy, bạn có thể thêm một tham chiếu đến System.Windows.Forms.dll và sử dụng Application.StartupPath! Đây là cách tốt nhất nếu bạn muốn loại bỏ các ngoại lệ trong tương lai!
Ehsan Mohammadi

AppDomain.BaseDirectory là thư mục ứng dụng. Xin lưu ý rằng ứng dụng có thể hoạt động khác nhau trong VS env và Win env. Nhưng AppDomain không giống với application.path nhưng tôi hy vọng rằng điều này không chỉ dành cho IIS.
Mertuarez

Câu trả lời:


1179

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

Kết hợp với System.IO.Path.GetDirectoryNamenếu tất cả những gì bạn muốn là thư mục.

1 Theo nhận xét của Mr.Mindor:
System.Reflection.Assembly.GetExecutingAssembly().Location trả về vị trí lắp ráp thực thi hiện tại, có thể hoặc không thể là nơi lắp ráp được đặt khi không thực hiện. Trong trường hợp tập hợp sao chép bóng, bạn sẽ nhận được một đường dẫn trong thư mục tạm thời. System.Reflection.Assembly.GetExecutingAssembly().CodeBasesẽ trả lại đường dẫn 'vĩnh viễn' của lắp ráp.


243
System.Reflection.Assugging.GetExecutingAssugging (). Location trả về vị trí lắp ráp thực thi hiện tại , có thể hoặc không thể là nơi lắp ráp được đặt khi không thực thi. Trong trường hợp tập hợp sao chép bóng, bạn sẽ nhận được một đường dẫn trong thư mục tạm thời. System.Reflection.Assugging.GetExecutingAssugging (). CodeBase sẽ trả về đường dẫn ' permenant ' của lắp ráp.
Mr.Mindor

13
@SamGoldberg: Điều đó phụ thuộc vào cách sử dụng: stackoverflow.com/q/1068420/391656 . Hoặc bạn có thể ... Uri mới (System.Reflection.Assugging.GetExecutingAssugging (). CodeBase) .LocalPath
Mr.Mindor

28
GetExecutingAssemblytrả về lắp ráp có chứa mã hiện đang thực thi . Đây có thể không nhất thiết phải là hội đồng điều khiển .exe . Nó có thể là một hội đồng đã được tải từ một vị trí hoàn toàn khác. Bạn sẽ phải sử dụng GetEntryAssembly! Cũng lưu ý rằng CodeBasecó thể không được đặt khi lắp ráp trong GAC. Sự thay thế tốt hơn là AppDomain.CurrentDomain.BaseDirectory.
bitbonk

3
Vui lòng viết mã trong 4 khoảng trắng để thoải mái sao chép
fnc12

3
nếu bạn gọi dll, System.Reflection.Assugging.GetExecutingAssugging (). CodeBase sẽ nhận được "file: /// C: /Windows/Microsoft.NET/Framework64/v4.0.30319/mscorlib.dll"
raidsan

407

Bạn có thể sử dụng đoạn mã sau để lấy thư mục ứng dụng hiện tại.

AppDomain.CurrentDomain.BaseDirectory

43
Đừng dùng cái này. BaseDirectory có thể được đặt trong thời gian chạy. Nó không được đảm bảo là chính xác (giống như câu trả lời được chấp nhận).
usr

3
+1 Đây có thể là câu trả lời bạn muốn vì nó bù cho việc sao chép bóng.
George Mauer

4
@usr Điều gì khiến bạn nghĩ rằng BaseDirectorycó thể được đặt trong thời gian chạy? Nó chỉ có một getter.
bitbonk

3
@bitbonk nó có thể được đặt tại thời điểm tạo appdomain.
usr

3
Không phải là BaseDirectory có thể được thay đổi trong tệp * .lnk, trong trường "Bắt đầu trong:"?
Alexander

170

Bạn có hai tùy chọn để tìm thư mục của ứng dụng mà bạn chọn sẽ phụ thuộc vào mục đích của bạn.

// to get the location the assembly is executing from
//(not necessarily where the it normally resides on disk)
// in the case of the using shadow copies, for instance in NUnit tests, 
// this will be in a temp directory.
string path = System.Reflection.Assembly.GetExecutingAssembly().Location;

//To get the location the assembly normally resides on disk or the install directory
string path = System.Reflection.Assembly.GetExecutingAssembly().CodeBase;

//once you have the path you get the directory with:
var directory = System.IO.Path.GetDirectoryName(path);

3
Chỉ muốn nói, rõ ràng có nhiều hơn 2 lựa chọn bởi có bao nhiêu lựa chọn khác được đăng ...
vapcguy

17
Nếu bất cứ điều gì bạn đang cố gắng thực hiện với đường dẫn đã nói không hỗ trợ định dạng URI, hãy sử dụngvar localDirectory = new Uri(directory).LocalPath;
Scott Solmer

Điều này chỉ sai. Thực thi là gì không phải là một hội đồng .NET? Câu trả lời đúng là kiểm tra môi trường và kiểm tra dòng lệnh.
đánh dấu

@ Ukuma.Scott Điều này không hoạt động nếu đường dẫn chứa & hoặc #
MatsW

82

Có lẽ hơi muộn nhưng điều này đáng được đề cập:

Environment.GetCommandLineArgs()[0];

Hay chính xác hơn là chỉ lấy đường dẫn thư mục:

System.IO.Path.GetDirectoryName(Environment.GetCommandLineArgs()[0]);

Biên tập:

Khá nhiều người đã chỉ ra rằng GetCommandLineArgskhông đảm bảo trả lại tên chương trình. Xem Từ đầu tiên trên dòng lệnh là tên chương trình chỉ theo quy ước . Bài báo viết rằng "Mặc dù rất ít chương trình Windows sử dụng cách giải quyết này (tôi không biết về bản thân mình)". Vì vậy, có thể 'giả mạo' GetCommandLineArgs, nhưng chúng ta đang nói về một ứng dụng giao diện điều khiển. Các ứng dụng Console thường nhanh và bẩn. Vì vậy, điều này phù hợp với triết lý KISS của tôi.


1
@usr tình huống bạn ám chỉ là rất lý thuyết. Trong ngữ cảnh của một ứng dụng giao diện điều khiển, nó thực sự không có ý nghĩa để sử dụng bất kỳ phương pháp nào khác. Giữ cho nó đơn giản!
Steve Mc

1
@usr mmm - nhìn vào cột cmdline taskmgr sao lưu những gì tôi đang nói. Một vài dịch vụ hệ thống chỉ với tên exe. Đừng bận tâm. Điều tôi đang cố gắng nói là khi phát triển ứng dụng console, không cần phải làm mọi thứ phức tạp hơn mức cần thiết. Đặc biệt là khi chúng tôi đã có sẵn thông tin. Bây giờ, nếu bạn đang chạy một ứng dụng bảng điều khiển theo cách để lừa GetCommandLineArss thì bạn đã nhảy qua các vòng và bạn có thể cần phải tự hỏi liệu ứng dụng bảng điều khiển có đi đúng hướng hay không.
Steve Mc

5
Giải pháp "đơn giản" của bạn liên quan đến hai cuộc gọi phương thức. Giải pháp "phức tạp" liên quan đến hai cuộc gọi phương thức. Không có sự khác biệt thực tế - ngoại trừ giải pháp "đơn giản" có thể cung cấp cho bạn câu trả lời sai trong những trường hợp nhất định không thuộc quyền kiểm soát của bạn khi bạn viết chương trình. Tại sao phải mạo hiểm? Sử dụng hai cuộc gọi phương thức khác, và chương trình của bạn sẽ không phức tạp hơn nhưng sẽ đáng tin cậy hơn.
Chris

3
Làm việc cho kịch bản của tôi, các giải pháp khác thì không, vì vậy cảm ơn vì đã cung cấp một giải pháp thay thế khác :-) Tôi đang sử dụng trình chạy thử nghiệm ReSharper để chạy thử nghiệm Đơn vị MS và mã tôi đang kiểm tra cần một tệp cụ thể để có trong thư mục thực thi. ..và hội.GetExecutingDirectory () kỳ lạ trả về một kết quả khác.
wallismark 4/03/2015

1
@Chris - để bảo vệ câu trả lời này. Nó hoạt động cho các bài kiểm tra đơn vị, giải pháp GetEntryAssugging không, vì GetEntryAssugging trả về null. Các câu trả lời đề xuất GetExecutingAssugging là không có thật, bởi vì chúng chỉ trả về tệp thực thi nếu tập hợp thực thi là tệp thực thi. Đây không phải là đơn giản, nhưng giải pháp chính xác.
đánh dấu

44

Đối với bất cứ ai quan tâm đến các ứng dụng web asp.net. Dưới đây là kết quả của tôi về 3 phương pháp khác nhau

protected void Application_Start(object sender, EventArgs e)
{
  string p1 = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
  string p2 = System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath;
  string p3 = this.Server.MapPath("");
  Console.WriteLine("p1 = " + p1);
  Console.WriteLine("p2 = " + p2);
  Console.WriteLine("p3 = " + p3);
}

kết quả

p1 = C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files\root\a897dd66\ec73ff95\assembly\dl3\ff65202d\29daade3_5e84cc01
p2 = C:\inetpub\SBSPortal_staging\
p3 = C:\inetpub\SBSPortal_staging

ứng dụng đang chạy thực tế từ "C: \ inetpub \ SBSPortal_staging", vì vậy giải pháp đầu tiên chắc chắn không phù hợp với các ứng dụng web.


42

Câu trả lời ở trên là 90% những gì tôi cần, nhưng đã trả lại một Uri thay vì một con đường thông thường cho tôi.

Như đã giải thích trong bài đăng trên diễn đàn MSDN, Làm thế nào để chuyển đổi đường dẫn URI thành filepath bình thường? , Tôi đã sử dụng như sau:

// Get normal filepath of this assembly's permanent directory
var path = new Uri(
    System.IO.Path.GetDirectoryName(
        System.Reflection.Assembly.GetExecutingAssembly().CodeBase)
    ).LocalPath;

1
điều này cũng hoạt động tốt nếu exe trong câu hỏi là một dịch vụ windows và thư mục hiện tại trả về C: \ Windows \ system32. Đoạn mã trên trả về vị trí thực tế của exe
DaImTo 20/2/2015

Ngoại trừ nếu sau đó bạn cố gắng làm một cái gì đó như thế File.CreateDirectory(path), nó sẽ cho bạn ngoại lệ rằng nó không cho phép các đường dẫn URI ...
vapcguy

1
Thật không may, điều này không hoạt động đối với các đường dẫn có chứa định danh phân đoạn ( #ký tự). Mã định danh và mọi thứ theo sau nó được cắt từ đường dẫn kết quả.
bgfvdu3w

Tại sao bạn không trao đổi new UriSystem.IO.Path.GetDirectoryName? Điều đó cung cấp cho bạn một chuỗi đường dẫn bình thường thay vì a Uri.
Timo

Tôi thấy đây là một trong những tốt nhất. Cách tiếp cận tương tự này đã làm việc đáng tin cậy cho tôi trong bất kỳ môi trường nào. Trong sản xuất, gỡ lỗi cục bộ, kiểm tra đơn vị ... Bạn muốn mở tệp nội dung mà bạn đã đưa vào ("nội dung - sao chép nếu mới hơn") trong kiểm tra đơn vị? Nó đây rồi.
Timo

29

Bạn có thể đang tìm cách để làm điều này:

System.IO.Path.GetDirectoryName(
    System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase)

23

bạn có thể sử dụng cái này thay thế

System.Environment.CurrentDirectory

Điều này sẽ nhận được thư mục của thực thi mặc dù
Iain

Điều này có thể được thay đổi theo số cách (cài đặt phím tắt, v.v.) ... tốt hơn là KHÔNG sử dụng nó.
Yousha Aleayoub

23

Nếu bạn đang tìm kiếm một cách tương thích .NET Core, hãy sử dụng

System.AppContext.BaseDirectory

Điều này đã được giới thiệu trong .NET Framework 4.6 và .NET Core 1.0 (và .NET Standard 1.3). Xem: Thuộc tính AppContext.BaseDirectory .

Theo trang này ,

Đây là sự thay thế ưa thích cho AppDomain.CienDomain.BaseDirectory trong .NET Core


1
xem thêm github.com/dotnet/racer/issues/13051 để biết các ứng dụng bảng điều khiển dotnet độc lập. Đề xuất ở đây là sử dụngProcess.GetCurrentProcess().MainModule.FileName
Gavin

19

Đối với Ứng dụng Bảng điều khiển, bạn có thể thử điều này:

System.IO.Directory.GetCurrentDirectory();

Đầu ra (trên máy cục bộ của tôi):

c: \ users \ xxxxxxx \ Documents \ visual studio 2012 \ Project \ ImageHandler \ GetDir \ bin \ Debug

Hoặc bạn có thể thử (cuối cùng có một dấu gạch chéo ngược):

AppDomain.CurrentDomain.BaseDirectory

Đầu ra:

c: \ users \ xxxxxxx \ Documents \ visual studio 2012 \ Project \ ImageHandler \ GetDir \ bin \ Debug \


"Có BaseDirectorythể được đặt trong thời gian chạy. Nó không được đảm bảo là chính xác"
Yousha Aleayoub


9

Bạn chỉ có thể thêm vào tài liệu tham khảo dự án của bạn System.Windows.Formsvà sau đó sử dụng System.Windows.Forms.Application.StartupPath như bình thường.

Vì vậy, không cần cho các phương pháp phức tạp hơn hoặc sử dụng sự phản ánh.


Tôi đã sử dụng cái đó, và nó hoạt động tốt. Nhưng một lần tôi đã sử dụng phương pháp có nó trong dự án thử nghiệm đơn vị của tôi. Và tất nhiên, nó đã thất bại vì nó đang tìm kiếm tệp của tôi trong C: \ PROGRAM FILES (X86) \ MICROSOFT VISUAL STUDIO 14.0 \ COMMON7 \ IDE \ COMMONEXTENSION \ MICROSOFT \ TESTWINDOW
bắt đầu từ

@ainasiart vậy làm thế nào để tôi làm việc này trong khi kiểm tra đơn vị ??
Nicholas Siegmundt

8

Dòng sau sẽ cung cấp cho bạn một đường dẫn ứng dụng:

var applicationPath = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName)

Giải pháp trên đang hoạt động đúng trong các tình huống sau:

  • ứng dụng đơn giản
  • trong một tên miền khác, nơi mà Hội đồng.GetEntryAssugging () sẽ trả về null
  • DLL được tải từ các tài nguyên được nhúng dưới dạng một mảng byte và được tải vào AppDomain dưới dạng Association.Load (byteArrayOfEmbeddedDll)
  • với mkbundlecác gói của Mono (không có phương pháp nào khác hoạt động)

Theo trình gỡ lỗi trên linux, nó trả về: / usr / share / dotnet
Vladimir

7

Tôi sử dụng điều này nếu exe được gọi là bằng cách nhấp đúp vào nó

var thisPath = System.IO.Directory.GetCurrentDirectory();

5
Điều này là không chính xác bởi vì bạn có thể nhận được các thư mục ngẫu nhiên trong kết quả.
kỳ lạ

Lệnh này trả về môi trường. Hiện tạiDirectory, có thể được thay đổi trong thời gian chạy thành bất kỳ đường dẫn nào, vì vậy nó không phải là một giải pháp đáng tin cậy.
Yury Kozlov

7

tôi đã sử dụng

System.AppDomain.CurrentDomain.BaseDirectory

khi tôi muốn tìm một đường dẫn liên quan đến một thư mục ứng dụng. Điều này hoạt động cho cả hai ứng dụng ASP.Net và winform. Nó cũng không yêu cầu bất kỳ tham chiếu nào đến các hội đồng System.Web.


6

Ý tôi là, tại sao không phương thức ap / invoke?

    using System;
    using System.IO;
    using System.Runtime.InteropServices;
    using System.Text;
    public class AppInfo
    {
            [DllImport("kernel32.dll", CharSet = CharSet.Auto, ExactSpelling = false)]
            private static extern int GetModuleFileName(HandleRef hModule, StringBuilder buffer, int length);
            private static HandleRef NullHandleRef = new HandleRef(null, IntPtr.Zero);
            public static string StartupPath
            {
                get
                {
                    StringBuilder stringBuilder = new StringBuilder(260);
                    GetModuleFileName(NullHandleRef, stringBuilder, stringBuilder.Capacity);
                    return Path.GetDirectoryName(stringBuilder.ToString());
                }
            }
    }

Bạn sẽ sử dụng nó giống như Application.StartupPath:

    Console.WriteLine("The path to this executable is: " + AppInfo.StartupPath + "\\" + System.Diagnostics.Process.GetCurrentProcess().ProcessName + ".exe");

2
Tại sao p / gọi khi có quá nhiều .NET cho việc này?
ProfK

7
@ user3596865 vì nó yêu cầu một sự phụ thuộc lớn vào Windows và không tương thích với DNX hoặc Mono. Và có thể có một sự thay đổi đột phá trong các Phiên bản Windows trong tương lai. Vì vậy, một lần nữa: tại sao chúng ta nên sử dụng pinvoke ở đây?
Ben

5

Assembly.GetEntryAssembly().Location hoặc là Assembly.GetExecutingAssembly().Location

Sử dụng kết hợp với System.IO.Path.GetDirectoryName()để chỉ nhận được thư mục.

Các đường dẫn từ GetEntryAssembly()GetExecutingAssembly()có thể khác nhau, mặc dù trong hầu hết các trường hợp, thư mục sẽ giống nhau.

Với GetEntryAssembly()bạn phải lưu ý rằng điều này có thể trở lại nullnếu mô-đun nhập không được quản lý (tức là thực thi C ++ hoặc VB6). Trong những trường hợp đó, có thể sử dụng GetModuleFileNametừ API Win32:

[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern int GetModuleFileName(HandleRef hModule, StringBuilder buffer, int length);

5

trong VB.net

My.Application.Info.DirectoryPath

làm việc cho tôi (Loại ứng dụng: Thư viện lớp). Không chắc chắn về C # ... Trả về đường dẫn w / o Tên tệp dưới dạng chuỗi


4
AppDomain.CurrentDomain.BaseDirectory

Sẽ giải quyết vấn đề để giới thiệu các tệp tham chiếu của bên thứ 3 với các gói cài đặt.


11
Câu trả lời này đã được đề xuất 5 năm trước, thậm chí hơn một lần.
PL

2

Không có phương pháp nào trong số này hoạt động trong các trường hợp đặc biệt như sử dụng liên kết tượng trưng đến exe, chúng sẽ trả về vị trí của liên kết chứ không phải exe thực tế.

Vì vậy, có thể sử dụng QueryFullProcessImageName để khắc phục điều đó:

using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Diagnostics;

internal static class NativeMethods
{
    [DllImport("kernel32.dll", SetLastError = true)]
    internal static extern bool QueryFullProcessImageName([In]IntPtr hProcess, [In]int dwFlags, [Out]StringBuilder lpExeName, ref int lpdwSize);

    [DllImport("kernel32.dll", SetLastError = true)]
    internal static extern IntPtr OpenProcess(
        UInt32 dwDesiredAccess,
        [MarshalAs(UnmanagedType.Bool)]
        Boolean bInheritHandle,
        Int32 dwProcessId
    );
}

public static class utils
{

    private const UInt32 PROCESS_QUERY_INFORMATION = 0x400;
    private const UInt32 PROCESS_VM_READ = 0x010;

    public static string getfolder()
    {
        Int32 pid = Process.GetCurrentProcess().Id;
        int capacity = 2000;
        StringBuilder sb = new StringBuilder(capacity);
        IntPtr proc;

        if ((proc = NativeMethods.OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, pid)) == IntPtr.Zero)
            return "";

        NativeMethods.QueryFullProcessImageName(proc, 0, sb, ref capacity);

        string fullPath = sb.ToString(0, capacity);

        return Path.GetDirectoryName(fullPath) + @"\";
    }
}

2

Hãy thử dòng mã đơn giản này:

 string exePath = Path.GetDirectoryName( Application.ExecutablePath);

1

Một giải pháp khác là sử dụng các đường dẫn tương đối trỏ đến đường dẫn hiện tại:

Path.GetFullPath(".")

Điều này nhận được thư mục hiện tại, không phải vị trí của EXE bắt đầu.
tenfour

0

Tôi không thấy ai chuyển đổi LocalPath được cung cấp bởi sự phản chiếu .Net Core thành đường dẫn System.IO có thể sử dụng được nên đây là phiên bản của tôi.

public static string GetApplicationRoot()
{
   var exePath = new Uri(System.Reflection.
   Assembly.GetExecutingAssembly().CodeBase).LocalPath;

   return new FileInfo(exePath).DirectoryName;

}

Điều này sẽ trả lại đường dẫn được định dạng "C: \ xxx \ xxx" đầy đủ đến nơi mã của bạn.



-1

Đây là một giải pháp đáng tin cậy hoạt động với các ứng dụng 32 bit64 bit .

Thêm các tài liệu tham khảo:

sử dụng System.Diagnostics;

sử dụng System.Man Management;

Thêm phương pháp này vào dự án của bạn:

public static string GetProcessPath(int processId)
{
    string MethodResult = "";
    try
    {
        string Query = "SELECT ExecutablePath FROM Win32_Process WHERE ProcessId = " + processId;

        using (ManagementObjectSearcher mos = new ManagementObjectSearcher(Query))
        {
            using (ManagementObjectCollection moc = mos.Get())
            {
                string ExecutablePath = (from mo in moc.Cast<ManagementObject>() select mo["ExecutablePath"]).First().ToString();

                MethodResult = ExecutablePath;

            }

        }

    }
    catch //(Exception ex)
    {
        //ex.HandleException();
    }
    return MethodResult;
}

Bây giờ sử dụng nó như vậy:

int RootProcessId = Process.GetCurrentProcess().Id;

GetProcessPath(RootProcessId);

Lưu ý rằng nếu bạn biết id của tiến trình, thì phương thức này sẽ trả về ExecutePath tương ứng.

Thêm, cho những người quan tâm:

Process.GetProcesses() 

... sẽ cung cấp cho bạn một mảng của tất cả các quy trình hiện đang chạy và ...

Process.GetCurrentProcess()

... sẽ cung cấp cho bạn quy trình hiện tại, cùng với thông tin của họ, ví dụ như Id, v.v. và cả kiểm soát hạn chế, ví dụ: Kill, v.v. *


-5

Bạn có thể tạo tên thư mục là Tài nguyên trong dự án bằng Solution Explorer, sau đó bạn có thể dán tệp trong Tài nguyên.

private void Form1_Load(object sender, EventArgs e) {
    string appName = Environment.CurrentDirectory;
    int l = appName.Length;
    int h = appName.LastIndexOf("bin");
    string ll = appName.Remove(h);                
    string g = ll + "Resources\\sample.txt";
    System.Diagnostics.Process.Start(g);
}

6
Sử dụng Môi trường. Hiện tạiDirectory là rất sai, đừng sử dụng cái này! đường dẫn này có thể thay đổi khi chạy. Ngay cả khi khởi động nó là không xác định.
usr
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.