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(); 
}
Foi útil?

Solução

Isso deve bastar para você.

Verifique os processos

//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:

  1. 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.

  2. 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);
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top