Como posso obter o caminho do aplicativo em um aplicativo de console .NET?

953

Como encontro o caminho do aplicativo em um aplicativo de console?

No Windows Forms , posso usar Application.StartupPathpara encontrar o caminho atual, mas isso não parece estar disponível em um aplicativo de console.

JSmyth
fonte
5
Você instala o .NET Framework na máquina de destino (cliente, desenvolvimento)? se sua resposta for verdadeira; Portanto, você pode adicionar uma referência ao System.Windows.Forms.dll e usar Application.StartupPath! Esta é a melhor maneira, se você quiser abandonar outras exceções futuras!
Ehsan Mohammadi
AppDomain.BaseDirectory é o diretório do aplicativo. Esteja ciente de que o aplicativo pode se comportar de maneira diferente no VS env e no Win env. Mas AppDomain não deve ser o mesmo que application.path, mas espero que isso não seja apenas para o IIS.
Mertuarez # 29/16

Respostas:

1179

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

Combine isso com System.IO.Path.GetDirectoryNamese tudo o que você deseja é o diretório.

1 Conforme o comentário do Sr.Mindor:
System.Reflection.Assembly.GetExecutingAssembly().Location retorna onde a montagem executora está atualmente localizada, que pode ou não estar onde a montagem está localizada quando não está sendo executada. No caso de montagens de cópia de sombra, você obterá um caminho em um diretório temporário. System.Reflection.Assembly.GetExecutingAssembly().CodeBaseretornará o caminho 'permanente' da montagem.

Sam Axe
fonte
243
System.Reflection.Assembly.GetExecutingAssembly (). Location retorna onde o assembly em execução está atualmente localizado, que pode ou não estar onde o assembly está localizado quando não está em execução. No caso de montagens de cópia de sombra, você obterá um caminho em um diretório temporário. System.Reflection.Assembly.GetExecutingAssembly (). CodeBase retornará o caminho ' permenante ' do assembly.
Mr.Mindor 14/10
13
@ SamGoldberg: Isso depende de como é usado: stackoverflow.com/q/1068420/391656 . Ou você pode ... new Uri (System.Reflection.Assembly.GetExecutingAssembly (). CodeBase) .LocalPath
Mr.Mindor
28
GetExecutingAssemblyretorna assembly que contém o código que está sendo executado no momento . Isso pode não ser necessariamente o assembly .exe do console . Pode ser uma montagem que foi carregada de um local totalmente diferente. Você terá que usar GetEntryAssembly! Observe também que CodeBasepode não ser definido quando a montagem está no GAC. A melhor alternativa é AppDomain.CurrentDomain.BaseDirectory.
bitbonk
3
Por favor, escrever código em 4 espaços por isso é confortável para copiar
fnc12
3
se você chamar dll, System.Reflection.Assembly.GetExecutingAssembly (). O CodeBase obterá "file: /// C: /Windows/Microsoft.NET/Framework64/v4.0.30319/mscorlib.dll"
raidsan
407

Você pode usar o código a seguir para obter o diretório atual do aplicativo.

AppDomain.CurrentDomain.BaseDirectory
Richard Ev
fonte
43
Não use isso. O BaseDirectory pode ser definido em tempo de execução. Não é garantido que esteja correto (como a resposta aceita).
usr
3
+1 Essa é provavelmente a resposta que você deseja, pois compensa a cópia de sombra.
George Mauer
4
@usr O que faz você pensar que BaseDirectorypode ser definido em tempo de execução? Só tem um getter.
bitbonk
3
@bitbonk, pode ser definido no momento da criação do domínio do aplicativo.
usr
3
Não é possível que o BaseDirectory possa ser alterado em um arquivo * .lnk, no campo "Iniciar em:"?
Alexander
170

Você tem duas opções para encontrar o diretório do aplicativo, que você escolher dependerá do seu objetivo.

// 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);
Mr.Mindor
fonte
3
Só queria dizer, obviamente, há muitos mais de 2 opções, como muitas outras opções são postados ...
vapcguy
17
Se o que você está tentando fazer com o referido caminho não suporta o formato URI, o usovar localDirectory = new Uri(directory).LocalPath;
Scott Solmer
Isso está errado. O que é o executável não é um assembly .NET? A resposta certa é verificar o ambiente e inspecionar a linha de comando.
marca
@ Ukuma.Scott Isso não funciona se o caminho contém & ou #
MatsW
82

Provavelmente um pouco tarde, mas vale a pena mencionar:

Environment.GetCommandLineArgs()[0];

Ou, mais corretamente, para obter apenas o caminho do diretório:

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

Editar:

Muitas pessoas apontaram que GetCommandLineArgsnão é garantido o retorno do nome do programa. Consulte A primeira palavra na linha de comando é o nome do programa apenas por convenção . O artigo afirma que "Embora extremamente poucos programas do Windows usem essa peculiaridade (eu não conheço nenhum deles)". Portanto, é possível 'falsificar' GetCommandLineArgs, mas estamos falando de um aplicativo de console. Aplicativos de console geralmente são rápidos e sujos. Então isso se encaixa na minha filosofia do KISS.

Steve Mc
fonte
1
A situação que você alude é altamente teórica. No contexto de um aplicativo de console, não faz muito sentido usar outro método. Mantenha simples!
21312 Steve
1
@usr mmm - olhar para a coluna taskmgr cmdline faz o backup do que estou dizendo. Alguns serviços de sistema com apenas o nome do exe. Deixa pra lá. O que estou tentando dizer é que, ao desenvolver um aplicativo de console, não há necessidade de tornar as coisas mais complicadas do que precisam. Especialmente quando já temos as informações disponíveis. Agora, se você estiver executando um aplicativo de console de forma a enganar o GetCommandLineArgs, já estará pulando os bastidores e provavelmente precisará se perguntar se um aplicativo de console é o caminho certo a seguir.
Steve Mc
5
Sua solução "simples" envolve duas chamadas de método. A solução "complicada" envolve duas chamadas de método. Nenhuma diferença prática - exceto que a solução "simples" pode fornecer a resposta errada sob certas circunstâncias que não estão sob seu controle quando você está escrevendo o programa. Por que correr o risco? Use as outras duas chamadas de método e seu programa não será mais complicado, mas será mais confiável.
22413 Chris
3
Trabalhando para o meu cenário, as outras soluções não funcionaram, então obrigado por fornecer outra alternativa :-) Eu estava usando o ReSharper test runner para executar um teste de unidade MS e o código que eu estava testando precisava de uma DLL específica para estar no diretório em execução. ..e Assembly.GetExecutingDirectory () estranhamente retorna um resultado diferente.
Wallismark 4/03/15
1
@ Chris - em defesa desta resposta. Funciona para testes de unidade, a solução GetEntryAssembly não, porque GetEntryAssembly retorna nulo. As respostas que propõem GetExecutingAssembly são falsas, porque somente retornam o executável se o assembly em execução for o executável. Esta não é a simples, mas a solução correta.
marca de
44

Para qualquer pessoa interessada em aplicativos da web asp.net. Aqui estão os meus resultados de 3 métodos diferentes

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);
}

resultado

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

o aplicativo está sendo executado fisicamente em "C: \ inetpub \ SBSPortal_staging", portanto a primeira solução definitivamente não é apropriada para aplicativos da web.

rocketsarefast
fonte
42

A resposta acima foi de 90% do que eu precisava, mas retornou um Uri em vez de um caminho regular para mim.

Conforme explicado na postagem dos fóruns do MSDN, como converter o caminho do URI em caminho de arquivo normal? , Usei o seguinte:

// Get normal filepath of this assembly's permanent directory
var path = new Uri(
    System.IO.Path.GetDirectoryName(
        System.Reflection.Assembly.GetExecutingAssembly().CodeBase)
    ).LocalPath;
fracassou
fonte
1
isso funciona bem também se o exe em questão for um serviço do Windows e o diretório atual retornar C: \ Windows \ system32. O código acima retorna a localização real do exe
DaImTo 20/02/2015
Exceto se você, em seguida, tentar fazer algo assim File.CreateDirectory(path), ele vai te dar a ressalva de que ele não permite caminhos URI ...
vapcguy
1
Infelizmente, isso não funciona para caminhos que contêm um identificador de fragmento (o #caractere). O identificador e tudo o que segue são truncados do caminho resultante.
Bgfvdu3w
Por que você não troca new Urie System.IO.Path.GetDirectoryName? Isso fornece uma string de caminho normal em vez de a Uri.
Timo
Acho isso o melhor. Essa mesma abordagem funcionou de maneira confiável para mim em qualquer ambiente. Na produção, depurando localmente, teste de unidade ... Deseja abrir um arquivo de conteúdo que você incluiu ("conteúdo - copiar se for mais novo") em um teste de unidade? Está lá.
Timo
29

Você pode fazer isso:

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

você pode usar este aqui.

System.Environment.CurrentDirectory
ButtShock
fonte
Porém, isto irá obter a pasta do executável #
Iain
Isso pode ser alterado de várias maneiras (configurações de atalho, etc.) ... é melhor NÃO usá-lo.
Yousha Aleayoub
23

Se você estiver procurando uma maneira compatível com o .NET Core, use

System.AppContext.BaseDirectory

Isso foi introduzido no .NET Framework 4.6 e .NET Core 1.0 (e .NET Standard 1.3). Consulte: Propriedade AppContext.BaseDirectory .

De acordo com esta página ,

Este é o substituto preferido para AppDomain.CurrentDomain.BaseDirectory no .NET Core

Dejan
fonte
1
consulte também github.com/dotnet/runtime/issues/13051 para obter aplicativos de console dotnet independentes. A recomendação aqui é usarProcess.GetCurrentProcess().MainModule.FileName
Gavin
19

Para aplicativos de console, você pode tentar o seguinte:

System.IO.Directory.GetCurrentDirectory();

Saída (na minha máquina local):

c: \ users \ xxxxxxx \ documents \ visual studio 2012 \ Projetos \ ImageHandler \ GetDir \ bin \ Debug

Ou você pode tentar (há uma barra invertida adicional no final):

AppDomain.CurrentDomain.BaseDirectory

Resultado:

c: \ users \ xxxxxxx \ documents \ visual studio 2012 \ Projects \ ImageHandler \ GetDir \ bin \ Debug \

F.Alves
fonte
"O BaseDirectorypode ser definido em tempo de execução. NÃO é garantido que esteja correto"
Yousha Aleayoub 19/11/19
14

Eu usei esse código e obtenha a solução.

AppDomain.CurrentDomain.BaseDirectory
Solução de Software Trimantra
fonte
9

Você pode simplesmente adicionar às referências do seu projeto System.Windows.Formse usar oSystem.Windows.Forms.Application.StartupPath normalmente.

Portanto, não é necessário métodos mais complicados ou usar a reflexão.

fruggiero
fonte
Eu usei esse e funciona bem. Mas uma vez eu usei o método em meu projeto de teste de unidade. E, claro, ele não conseguiu porque estava olhando para o meu arquivo em C: \ Program Files (x86) \ MICROSOFT VISUAL STUDIO 14.0 \ Common7 \ IDE \ COMMONEXTENSIONS \ Microsoft \ TESTWINDOW
ainasiart
@ainasiart Então, como faço para que isso funcione durante o teste de unidade?
Nicholas Siegmundt
8

A linha a seguir fornecerá um caminho de aplicativo:

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

A solução acima está funcionando corretamente nas seguintes situações:

  • aplicativo simples
  • em outro domínio em que Assembly.GetEntryAssembly () retornaria nulo
  • A DLL é carregada dos recursos incorporados como uma matriz de bytes e carregada no AppDomain como Assembly.Load (byteArrayOfEmbeddedDll)
  • com mkbundlepacotes configuráveis ​​do Mono (nenhum outro método funciona)
user2126375
fonte
Sob o depurador no Linux, isso retorna: / usr / share / dotnet
Vladimir
7

Eu uso isso se o exe deve ser chamado clicando duas vezes nele

var thisPath = System.IO.Directory.GetCurrentDirectory();
developer747
fonte
5
Isso não está correto porque você pode obter diretórios aleatórios no resultado.
amuliar
este comando retorna Environment.CurrentDirectory, que pode ser alterado em tempo de execução para qualquer caminho, portanto, não é uma solução confiável.
Yury Kozlov
7

Eu tenho usado

System.AppDomain.CurrentDomain.BaseDirectory

quando eu quero encontrar um caminho relativo a uma pasta de aplicativos. Isso funciona para aplicativos ASP.Net e winform. Também não requer nenhuma referência aos assemblies System.Web.

user2346593
fonte
6

Quero dizer, por que não ap / invocar método?

    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());
                }
            }
    }

Você o usaria como o Application.StartupPath:

    Console.WriteLine("The path to this executable is: " + AppInfo.StartupPath + "\\" + System.Diagnostics.Process.GetCurrentProcess().ProcessName + ".exe");
user3596865
fonte
2
Por que p / invocar quando há tanto .NET para isso?
ProfK 03/03
7
@ user3596865 porque requer uma dependência grave do Windows e não é compatível com DNX ou Mono. E talvez haja uma mudança nas versões futuras do Windows. Novamente: por que devemos usar o pinvoke aqui?
Ben
5

Assembly.GetEntryAssembly().Location ou Assembly.GetExecutingAssembly().Location

Use em combinação com System.IO.Path.GetDirectoryName() para obter apenas o diretório.

Os caminhos de GetEntryAssembly()eGetExecutingAssembly() podem ser diferentes, embora na maioria dos casos o diretório seja o mesmo.

Com GetEntryAssembly()você tem que estar ciente de que isso pode voltar nullse o módulo de entrada é não gerenciado (ou seja, C ++ ou executável VB6). Nesses casos, é possível usar a GetModuleFileNamepartir da API do Win32:

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

em VB.net

My.Application.Info.DirectoryPath

funciona para mim (Tipo de aplicativo: Biblioteca de classes). Não tenho certeza sobre C # ... Retorna o caminho sem o nome do arquivo como sequência

dba
fonte
4
AppDomain.CurrentDomain.BaseDirectory

Resolverá o problema para consultar os arquivos de referência de terceiros com pacotes de instalação.

Nirav Mehta
fonte
11
Esta resposta já foi sugerida há 5 anos, mais de uma vez.
PL
2

Nenhum desses métodos funciona em casos especiais, como o uso de um link simbólico para o exe; eles retornarão a localização do link e não o exe real.

Portanto, pode usar QueryFullProcessImageName para contornar isso:

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) + @"\";
    }
}
Colin Lamarre
fonte
2

Experimente esta simples linha de código:

 string exePath = Path.GetDirectoryName( Application.ExecutablePath);
daniele3004
fonte
1

Outra solução é usar caminhos relativos que apontam para o caminho atual:

Path.GetFullPath(".")
blenderfreaky
fonte
Isso obtém o diretório atual, não o local do EXE inicial.
tenfour
0

Não vi ninguém converter o LocalPath fornecido pelo .Net Core em um caminho System.IO utilizável, então aqui está minha versão.

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

   return new FileInfo(exePath).DirectoryName;

}

Isso retornará o caminho formatado "C: \ xxx \ xxx" completo para onde está o seu código.

mark gamache
fonte
-1

Aqui está uma solução confiável que funciona com 32 bits e 64 bits aplicativos de .

Adicione estas referências:

using System.Diagnostics;

using System.Management;

Adicione este método ao seu projeto:

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;
}

Agora use-o assim:

int RootProcessId = Process.GetCurrentProcess().Id;

GetProcessPath(RootProcessId);

Observe que, se você souber o ID do processo, esse método retornará o ExecutePath correspondente.

Extra, para os interessados:

Process.GetProcesses() 

... fornecerá uma matriz de todos os processos em execução no momento e ...

Process.GetCurrentProcess()

... fornecerá o processo atual, juntamente com suas informações, por exemplo, ID, etc., e também controle limitado, por exemplo, Kill, etc. *

WonderWorker
fonte
-5

Você pode criar um nome de pasta como Recursos no projeto usando o Gerenciador de Soluções e colar um arquivo nos Recursos.

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);
}
Devarajan.T
fonte
6
Usar Environment.CurrentDirectory está muito errado, não use isso! esse caminho pode mudar em tempo de execução. Mesmo na inicialização, é não determinístico.
usr