Como posso saber se um processo já está em execução usando c#?
-
09-06-2019 - |
Pergunta
Eu tenho um aplicativo winforms C# que precisa iniciar um exe externo de vez em quando, mas não desejo iniciar outro processo se um já estiver em execução, mas sim mudar para ele.
Então, como em C# eu faria isso no exemplo abaixo?
using System.Diagnostics;
...
Process foo = new Process();
foo.StartInfo.FileName = @"C:\bar\foo.exe";
foo.StartInfo.Arguments = "Username Password";
bool isRunning = //TODO: Check to see if process foo.exe is already running
if (isRunning)
{
//TODO: Switch to foo.exe process
}
else
{
foo.Start();
}
Solução
Isso deve bastar para você.
//Namespaces we need to use
using System.Diagnostics;
public bool IsProcessOpen(string name)
{
//here we're going to get a list of all running processes on
//the computer
foreach (Process clsProcess in Process.GetProcesses()) {
//now we're going to see if any of the running processes
//match the currently running processes. Be sure to not
//add the .exe to the name you provide, i.e: NOTEPAD,
//not NOTEPAD.EXE or false is always returned even if
//notepad is running.
//Remember, if you have the process running more than once,
//say IE open 4 times the loop thr way it is now will close all 4,
//if you want it to just close the first one it finds
//then add a return; after the Kill
if (clsProcess.ProcessName.Contains(name))
{
//if the process is found to be running then we
//return a true
return true;
}
}
//otherwise we return a false
return false;
}
Outras dicas
Você também pode usar o LINQ,
var processExists = Process.GetProcesses().Any(p => p.ProcessName.Contains("<your process name>"));
Usei a função AppActivate em tempo de execução VB para ativar um processo existente.Você terá que importar a dll Microsoft.VisualBasic para o projeto C#.
using System;
using System.Diagnostics;
using Microsoft.VisualBasic;
namespace ConsoleApplication3
{
class Program
{
static void Main(string[] args)
{
Process[] proc = Process.GetProcessesByName("notepad");
Interaction.AppActivate(proc[0].MainWindowTitle);
}
}
}
Você pode simplesmente enumerar processos usando Process.GetProcesses método.
Descobri que o Mutex não está funcionando como no aplicativo Console.Portanto, usar o WMI para consultar processos que podem ser vistos na janela do Gerenciador de Tarefas resolverá seu problema.
Use algo assim:
static bool isStillRunning() {
string processName = Process.GetCurrentProcess().MainModule.ModuleName;
ManagementObjectSearcher mos = new ManagementObjectSearcher();
mos.Query.QueryString = @"SELECT * FROM Win32_Process WHERE Name = '" + processName + @"'";
if (mos.Get().Count > 1)
{
return true;
}
else
return false;
}
OBSERVAÇÃO:Adicione a referência de montagem "System.Management" para ativar o tipo intellisense.
Acho que a resposta completa para o seu problema requer a compreensão do que acontece quando seu aplicativo determina que uma instância de foo.exe já está em execução, ou seja, o que '//TODO:Mudar para o processo foo.exe 'realmente significa?
Em um projeto anterior, eu precisava impedir a execução múltipla de um processo, então adicionei algum código na seção init desse processo que cria um mutex nomeado.Este mutext foi criado e adquirido antes de continuar o restante do processo.Se o processo puder criar o mutex e adquiri-lo, então ele será o primeiro em execução.Se outro processo já controla o mutex, então aquele que falha não é o primeiro, então ele sai imediatamente.
Eu estava apenas tentando impedir a execução de uma segunda instância, devido a dependências de interfaces de hardware específicas.Dependendo do que você precisa com a linha "alternar para", pode ser necessária uma solução mais específica, como um ID ou identificador de processo.
Além disso, tive acesso ao código-fonte do processo que estava tentando iniciar.Se você não puder modificar o código, adicionar o mutex obviamente não é uma opção.
Duas preocupações a ter em mente:
Seu exemplo envolveu colocar uma senha em uma linha de comando.Essa representação clara de texto de um segredo pode ser uma vulnerabilidade de segurança.
Ao enumerar processos, pergunte a si mesmo quais processos você realmente deseja enumerar.Todos os usuários, ou apenas o usuário atual?E se o usuário atual estiver conectado duas vezes (dois desktops)?
Mnebuerquo escreveu:
Além disso, eu tinha acesso ao código -fonte ao processo que estava tentando começar.Se você não pode modificar o código, adicionar o mutex obviamente não é uma opção.
Não tenho acesso ao código-fonte do processo que desejo executar.
Acabei usando o processo MainWindowHandle para mudar para o processo depois de descobrir que ele já está em execução:
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool SetForegroundWindow(IntPtr hWnd);