Como posso saber se um processo está em execução?

155

Quando obtenho uma referência a System.Diagnostics.Process, como posso saber se um processo está em execução no momento?

reshefm
fonte

Respostas:

252

Esta é uma maneira de fazer isso com o nome:

Process[] pname = Process.GetProcessesByName("notepad");
if (pname.Length == 0)
  MessageBox.Show("nothing");
else
  MessageBox.Show("run");

Você pode fazer um loop em todo o processo para obter o ID para manipulação posterior:

Process[] processlist = Process.GetProcesses();
foreach(Process theprocess in processlist){
   Console.WriteLine("Process: {0} ID: {1}", theprocess.ProcessName, theprocess.Id);
}
Patrick Desjardins
fonte
Isto é exatamente o que eu estava procurando. Mesmo que este seja um post muito antigo, você poderia me explicar como isso é válido em C #. Não estou duvidando disso, vejo que funciona, mas nunca vi mais sem {}.
MatthewD
4
@ MatthewD: As instruções C # com if/elseapenas uma linha de comprimento não precisam de chaves para indicar a instrução do bloco. Isso também vale para foreache fordeclarações. Tudo se resume ao estilo de codificação.
Hallmanac
Também pesquisei sobre isso, achei essa informação, mas não a vi for. Anos de c # .net dev e eu nunca vi esse estilo. Como se costuma dizer, "você aprende algo novo todos os dias". Obrigado pela postagem e pela resposta ..
MatthewD
3
@ MatthewD sim, isso é válido para a maioria das linguagens (como Java). Geralmente, é uma boa prática evitar uma linha como essas e sempre colocar chaves, pois sempre existe a chance de você adicionar mais instruções no futuro; nesse caso, as chaves já estarão lá quando você precisar. Mas para coisas como essa, se você tem 100% de certeza de que precisa apenas de uma declaração, não há problema em fazer isso e é sintaticamente válido.
David Mordigal 03/07
1
Se você não encontrar o processo, tente remover a extensão. (Ex: .exe)
DxTx
28

Esta é a maneira mais simples que encontrei depois de usar o refletor. Eu criei um método de extensão para isso:

public static class ProcessExtensions
{
    public static bool IsRunning(this Process process)
    {
        if (process == null) 
            throw new ArgumentNullException("process");

        try
        {
            Process.GetProcessById(process.Id);
        }
        catch (ArgumentException)
        {
            return false;
        }
        return true;
    }
}

o Process.GetProcessById(processId) método chama o ProcessManager.IsProcessRunning(processId)método e lança ArgumentExceptioncaso o processo não exista. Por alguma razão, a ProcessManagerclasse é interna ...

reshefm
fonte
Essa foi uma resposta muito boa; no entanto, você não deve ter passado pelo argumento exceção nula (porque uma exceção de referência nula teria sido lançada de qualquer maneira e você não fez nada com a exceção. Além disso, você receberá uma InvalidOperationException se você não chamar o Start () ou você invocou o método close ()
.Eu publiquei
16

Solução síncrona:

void DisplayProcessStatus(Process process)
{
    process.Refresh();  // Important


    if(process.HasExited)
    {
        Console.WriteLine("Exited.");
    }
    else
    {
        Console.WriteLine("Running.");
    } 
}

Solução assíncrona:

void RegisterProcessExit(Process process)
{
    // NOTE there will be a race condition with the caller here
    //   how to fix it is left as an exercise
    process.Exited += process_Exited;
}

static void process_Exited(object sender, EventArgs e)
{
   Console.WriteLine("Process has exited.");
}
Coincoin
fonte
6
Para a primeira opção: como posso saber se o processo foi iniciado em primeiro lugar?
Reshefm
8

reshefm teve uma resposta bastante agradável; no entanto, ele não explica uma situação na qual o processo nunca foi iniciado.

Aqui está uma versão modificada do que ele postou.

    public static bool IsRunning(this Process process)
    {
        try  {Process.GetProcessById(process.Id);}
        catch (InvalidOperationException) { return false; }
        catch (ArgumentException){return false;}
        return true;
    }

Eu removi o ArgumentNullException porque, na verdade, é uma exceção de referência nula e é lançada pelo sistema de qualquer maneira. Também considerei a situação na qual o processo nunca foi iniciado, ou o método close () foi usado para fechar o arquivo. processo.

Aelphaeis
fonte
Pessoalmente, eu preferiria ver uma ArgumentNullException ao revisar uma exceção registrada do que uma NullReferenceException, já que ArgumentNullException é muito mais explícito sobre o que deu errado.
27416 Sean
1
@ Sean Eu normalmente concordo com você, mas esse é um método de extensão. Eu acho que é mais apropriado lançar uma exceção de ponteiro nulo, dada a sintaxe, apenas parece mais consistente com a chamada de métodos de objetos nulos.
Aelphaeis
Isso acionará o manipulador de eventos FirstHandledException toda vez. Maneira de spam seus logs lá amigo.
Latência
6

Deve ser uma linha:

public static class ProcessHelpers {
    public static bool IsRunning (string name) => Process.GetProcessesByName(name).Length > 0;
}
guneysus
fonte
3

Depende de quão confiável você deseja que essa função seja. Se você deseja saber se a instância específica do processo que você possui ainda está em execução e está disponível com 100% de precisão, você está sem sorte. A razão é que, a partir do objeto de processo gerenciado, existem apenas duas maneiras de identificar o processo.

O primeiro é o ID do processo. Infelizmente, os IDs de processo não são exclusivos e podem ser reciclados. A pesquisa na lista de processos por um ID correspondente indica apenas que existe um processo com o mesmo ID em execução, mas esse processo não é necessariamente seu.

O segundo item é o identificador de processo. Ele tem o mesmo problema que o ID e é mais complicado trabalhar com ele.

Se você procura confiabilidade de nível médio, basta verificar na lista de processos atual um processo com o mesmo ID.

JaredPar
fonte
1

Process.GetProcesses()é o caminho a percorrer. Mas você pode precisar usar um ou mais critérios diferentes para encontrar seu processo, dependendo de como ele está sendo executado (por exemplo, como um serviço ou aplicativo normal, independentemente de ter ou não uma barra de título).

Jeff Kotula
fonte
Se você colocar esse método em loop, isso custará muitos ciclos de CPU. Eu recomendo usar GetProcessByName () ou GetProcessByID ().
Hao Nguyen
0

Talvez (provavelmente) esteja lendo a pergunta incorretamente, mas você está procurando a propriedade HasExited que informará que o processo representado pelo objeto Process foi encerrado (normalmente ou não).

Se o processo ao qual você tem uma referência tiver uma interface do usuário, você poderá usar a propriedade Responding para determinar se a interface do usuário está respondendo atualmente à entrada do usuário ou não.

Você também pode definir EnableRaisingEvents e manipular o evento Exited (enviado de forma assíncrona) ou chamar WaitForExit () se desejar bloquear.


fonte
0

Você pode instanciar uma instância do Process uma vez para o processo desejado e continuar acompanhando o processo usando o objeto .NET Process (ele continuará rastreando até você chamar Fechar nesse objeto .NET explicitamente, mesmo se o processo que estava rastreando estiver morto [isso permite que você tenha tempo para fechar o processo, também conhecido como ExitTime etc.])

Citando http://msdn.microsoft.com/en-us/library/fb4aw7b8.aspx :

Quando um processo associado sai (ou seja, quando é desligado pelo sistema operacional por meio de uma finalização normal ou anormal), o sistema armazena informações administrativas sobre o processo e retorna ao componente que chamou WaitForExit. O componente Process pode acessar as informações, que incluem o ExitTime, usando o Handle para o processo encerrado.

Como o processo associado foi encerrado, a propriedade Handle do componente não aponta mais para um recurso de processo existente. Em vez disso, o identificador pode ser usado apenas para acessar as informações do sistema operacional sobre o recurso do processo. O sistema está ciente de identificadores para processos encerrados que não foram liberados pelos componentes do processo, portanto, mantém as informações ExitTime e Handle na memória até que o componente Process libere especificamente os recursos. Por esse motivo, sempre que você chamar Iniciar para uma instância de Processo, chame Fechar quando o processo associado terminar e você não precisar mais de informações administrativas sobre ele. Fechar libera a memória alocada para o processo encerrado.

George Birbilis
fonte
0

Tentei a solução da Coincoin:
Antes de processar um arquivo, copio-o como um arquivo temporário e o abro.
Quando terminar, fecho o aplicativo se ele ainda estiver aberto e excluo o arquivo temporário:
Eu apenas uso uma variável Process e verifico depois:

private Process openApplication;  
private void btnOpenFile_Click(object sender, EventArgs e) {  
    ...
    // copy current file to fileCache  
    ...  
    // open fileCache with proper application
    openApplication = System.Diagnostics.Process.Start( fileCache );  
}

Mais tarde eu fecho o aplicativo:

 ...   
openApplication.Refresh(); 

// close application if it is still open       
if ( !openApplication.HasExited() ) {
    openApplication.Kill();  
}

// delete temporary file  
System.IO.File.Delete( fileCache );

Funciona (até agora)

Jack Griffin
fonte
3
At openApplication.HasExited(), HasExited não é uma função. A maneira correta seria openApplication.HasExited.
caiosm1005
0

Apesar da API suportada das estruturas .Net em relação à verificação do processo existente pelo ID do processo, essas funções são muito lentas. Custa uma enorme quantidade de ciclos de CPU para executar Process.GetProcesses () ou Process.GetProcessById / Name ().

Um método muito mais rápido para verificar um processo em execução por ID é usar a API nativa OpenProcess () . Se o identificador de retorno for 0, o processo não existe. Se o identificador for diferente de 0, o processo está em execução. Não há garantia de que esse método funcione 100% o tempo todo devido à permissão.

Hao Nguyen
fonte
0

Existem muitos problemas associados a isso, pois outros parecem abordar parcialmente:

  • Não é garantido que nenhum membro da instância seja seguro para threads. Isso significa que existem condições de corrida que podem ocorrer com a vida útil do instantâneo ao tentar avaliar as propriedades do objeto.
  • O identificador do processo lançará Win32Exception para ACCESS DENIED onde permissões para avaliar esta e outras propriedades desse tipo não são permitidas.
  • Para o status ISN'RUNNING, uma ArgumentException também será gerada ao tentar avaliar algumas de suas propriedades.

Se as propriedades que outras pessoas mencionaram são internas ou não, você ainda pode obter informações através da reflexão, se a permissão permitir.

var x = obj.GetType().GetProperty("Name", BindingFlags.NonPublic | BindingFlags.Instance);

Você pode definir o código Win32 para o Snapshot ou usar o WMI, que é mais lento.

HANDLE CreateToolhelp32Snapshot(
  DWORD dwFlags,
  DWORD th32ProcessID
);

Outra opção seria OpenProcess / CloseProcess, mas você ainda terá os mesmos problemas, com exceções lançadas da mesma forma que antes.

Para WMI - OnNewEvent.Properties ["?"]:

  • "ParentProcessID"
  • "ProcessID"
  • "Nome do processo"
  • "SECURITY_DESCRIPTOR"
  • "Identificação de sessão"
  • "Sid"
  • "TIME_CREATED"
Latência
fonte
0
string process = "notepad";
if (Process.GetProcessesByName(process).Length == 0)
{
    MessageBox.Show("Working");
}
else
{
    MessageBox.Show("Not Working");
}

Além disso, você pode usar um timer para verificar o processo todas as vezes

Berkay
fonte
3
Não seria o contrário? se comprimento == 0 isso significa que não está funcionando?
Jay Jacobs
A resposta é a mesma de Patrick Desjardins: stackoverflow.com/a/262291/7713750
Rekshino 26/17
Por outro lado, comprimento> 0 significa que os processos são encontrados.
Haseeb Mir
Isso pode ter um erro ( length == 0deve ser exibido Not Working), mas ainda faz o trabalho.
Momoro 29/04