Як знайти шлях до програми в консольному додатку?
У 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 виконуваний файл). У цих випадках можливо використовувати GetModuleFileName
API 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);
}