Як знайти шлях до програми в консольному додатку?
У Windows Forms я можу Application.StartupPathзнайти поточний шлях, але це, здається, не доступне в консольній програмі.
Як знайти шлях до програми в консольному додатку?
У Windows Forms я можу Application.StartupPathзнайти поточний шлях, але це, здається, не доступне в консольній програмі.
Відповіді:
System.Reflection.Assembly.GetExecutingAssembly(). 1Location
Поєднайте це з тим, System.IO.Path.GetDirectoryNameякщо все, що вам потрібно, - це каталог.
1 Відповідно до коментаря містера Міндора:
System.Reflection.Assembly.GetExecutingAssembly().Locationповертається там, де знаходиться збірка, що виконує, яка може бути, а може і не бути там, де збірка знаходиться під час не виконання. У випадку складання тіньових копіювальних збірок ви отримаєте шлях у тимчасовий каталог.System.Reflection.Assembly.GetExecutingAssembly().CodeBaseповерне "постійний" шлях складання.
GetExecutingAssemblyповертає збірку, що містить код, який наразі виконується . Це не обов'язково може бути збірка .exe консолі . Це може бути збірка, завантажена з абсолютно іншого місця. Вам доведеться користуватися GetEntryAssembly! Також зауважте, що це CodeBaseможе бути встановлено, коли збірка знаходиться в GAC. Краща альтернатива AppDomain.CurrentDomain.BaseDirectory.
Ви можете використовувати наступний код, щоб отримати поточний каталог додатків.
AppDomain.CurrentDomain.BaseDirectory
BaseDirectoryце можна встановити під час виконання? У ньому є лише геттер.
У вас є два варіанти пошуку каталогу програми, який ви виберете, залежатиме від вашої мети.
// 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);
var localDirectory = new Uri(directory).LocalPath;
Можливо, трохи пізно, але це варто згадати:
Environment.GetCommandLineArgs()[0];
Або правильніше отримати лише шлях до каталогу:
System.IO.Path.GetDirectoryName(Environment.GetCommandLineArgs()[0]);
Редагувати:
Небагато людей зазначили, що GetCommandLineArgsповернення назви програми не гарантовано. Див . Перше слово в командному рядку - це назва програми лише умовно . У статті зазначено, що "Хоча надзвичайно мало програм Windows використовує цю хитрість (я сам не знаю про це)". Так що можна «підробляти» GetCommandLineArgs, але ми говоримо про консольний додаток. Програми для консолей зазвичай швидкі та брудні. Отже, це відповідає моїй філософії KISS.
Для всіх, хто цікавиться веб-додатками asp.net. Ось мої результати трьох різних методів
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);
}
результат
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
додаток фізично працює з "C: \ inetpub \ SBSPortal_staging", тому перше рішення, безумовно, не підходить для веб-додатків.
Відповідь вище була на 90% від того, що мені потрібно, але повернув Урі замість звичайного шляху для мене.
Як пояснено у публікації на форумах MSDN, як конвертувати шлях URI у звичайний файловий шлях? , Я використав наступне:
// Get normal filepath of this assembly's permanent directory
var path = new Uri(
System.IO.Path.GetDirectoryName(
System.Reflection.Assembly.GetExecutingAssembly().CodeBase)
).LocalPath;
File.CreateDirectory(path), це дасть вам виняток, що він не дозволяє шляхи до URI ...
#символ). Ідентифікатор і все, що йде за ним, відсікається з отриманого шляху.
new Uriі System.IO.Path.GetDirectoryName? Це дає вам звичайний рядок шляху замість Uri.
ви можете використовувати цей замість цього.
System.Environment.CurrentDirectory
Якщо ви шукаєте спосіб, сумісний з .NET Core, використовуйте
System.AppContext.BaseDirectory
Це було представлено у .NET Framework 4.6 та .NET Core 1.0 (та .NET Standard 1.3). Дивіться: AppContext.BaseDirectory Властивість .
Відповідно до цієї сторінки ,
Це краща заміна AppDomain.CurrentDomain.BaseDirectory в .NET Core
Process.GetCurrentProcess().MainModule.FileName
Для консольних програм ви можете спробувати це:
System.IO.Directory.GetCurrentDirectory();
Вихід (на моїй локальній машині):
c: \ користувачів \ xxxxxxx \ документи \ візуальна студія 2012 \ Проекти \ ImageHandler \ GetDir \ bin \ Налагодження
Або ви можете спробувати (у кінцевому підсумку є додатковий зворотний кут):
AppDomain.CurrentDomain.BaseDirectory
Вихід:
c: \ користувачів \ xxxxxxx \ документи \ візуальна студія 2012 \ Проекти \ ImageHandler \ GetDir \ bin \ Налагодження \
BaseDirectoryможе бути встановлений під час виконання. НЕ гарантовано, що він правильний"
Я використав цей код і отримав рішення.
AppDomain.CurrentDomain.BaseDirectory
Ви можете просто додати до своїх посилань на проект, System.Windows.Formsа потім використовувати System.Windows.Forms.Application.StartupPath як завжди.
Отже, не потрібно більш складних методів чи використання рефлексії.
Я використовую це, якщо передбачається викликати exe, двічі клацнувши його
var thisPath = System.IO.Directory.GetCurrentDirectory();
Я звик
System.AppDomain.CurrentDomain.BaseDirectory
коли я хочу знайти шлях відносно папки програм. Це працює як для програм ASP.Net, так і для Winform. Він також не вимагає посилань на збори System.Web.
Наступний рядок дасть вам шлях до програми:
var applicationPath = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName)
Вищевказане рішення працює належним чином у наступних ситуаціях:
mkbundleпакетами Mono (інші методи не працюють)Я маю на увазі, чому б не метод 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());
}
}
}
Ви б використовували його так само, як Application.StartupPath:
Console.WriteLine("The path to this executable is: " + AppInfo.StartupPath + "\\" + System.Diagnostics.Process.GetCurrentProcess().ProcessName + ".exe");
Assembly.GetEntryAssembly().Location або Assembly.GetExecutingAssembly().Location
Використовуйте в поєднанні з, System.IO.Path.GetDirectoryName()щоб отримати лише каталог.
Шляхи з GetEntryAssembly() та GetExecutingAssembly()можуть бути різними, хоча для більшості випадків каталог буде однаковим.
З GetEntryAssembly()ви повинні знати , що це може повернутися , nullякщо модуль входу є некерованим (тобто C ++ або VB6 виконуваний файл). У цих випадках можливо використовувати GetModuleFileNameAPI Win32:
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern int GetModuleFileName(HandleRef hModule, StringBuilder buffer, int length);
AppDomain.CurrentDomain.BaseDirectory
Вирішить проблему, відсилаючи сторонні файли посилань з інсталяційними пакетами.
Жоден із цих методів не працює в особливих випадках, наприклад, використовуючи символьне посилання на exe, вони повернуть розташування посилання, а не фактичне exe.
Отже, використовуйте QueryFullProcessImageName, щоб обійти це:
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) + @"\";
}
}
Спробуйте цей простий рядок коду:
string exePath = Path.GetDirectoryName( Application.ExecutablePath);
Іншим рішенням є використання відносних шляхів, що вказують на поточний шлях:
Path.GetFullPath(".")
Я не бачив, щоб хтось конвертував локальний шлях, наданий .Net Core відображенням, у корисний шлях System.IO, ось ось моя версія.
public static string GetApplicationRoot()
{
var exePath = new Uri(System.Reflection.
Assembly.GetExecutingAssembly().CodeBase).LocalPath;
return new FileInfo(exePath).DirectoryName;
}
Це поверне повний шлях у форматі "C: \ xxx \ xxx" до місця, де знаходиться ваш код.
Існує багато способів отримати виконавчий шлях, який з них ми повинні використовувати, це залежить від наших потреб. Тут є посилання, в якому обговорюються різні методи.
Ось надійне рішення, яке працює з 32-бітним і 64-бітовим додатками.
Додайте ці посилання:
за допомогою System.Diagnostics;
використання System.Management;
Додайте цей метод до свого проекту:
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;
}
Тепер використовуйте його так:
int RootProcessId = Process.GetCurrentProcess().Id;
GetProcessPath(RootProcessId);
Зауважте, що якщо ви знаєте ідентифікатор процесу, то цей метод поверне відповідний ExecutePath.
Додатково для зацікавлених:
Process.GetProcesses()
... дасть вам масив усіх поточно запущених процесів, і ...
Process.GetCurrentProcess()
... дасть вам поточний процес, разом з їх інформацією, наприклад, ідентифікатор тощо, а також обмежений контроль, наприклад, вбити тощо. *
Ви можете створити ім'я папки як Ресурси в проекті за допомогою Провідника рішень, а потім можете вставити файл в Ресурси.
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);
}