Usando C # e WPF no .NET (em vez de Windows Forms ou console), qual é a maneira correta de criar um aplicativo que só pode ser executado como uma única instância?
Eu sei que tem algo a ver com alguma coisa mítica chamada mutex, raramente encontro alguém que se incomode em parar e explicar o que é um deles.
O código também precisa informar à instância já em execução que o usuário tentou iniciar uma segunda e talvez também transmitir quaisquer argumentos da linha de comando, se houver algum.
Respostas:
Aqui está um artigo muito bom sobre a solução Mutex. A abordagem descrita no artigo é vantajosa por dois motivos.
Primeiro, ele não requer uma dependência do assembly Microsoft.VisualBasic. Se meu projeto já dependesse dessa assembléia, eu provavelmente recomendaria o uso da abordagem mostrada em outra resposta . Mas, como é, não uso o assembly Microsoft.VisualBasic e prefiro não adicionar uma dependência desnecessária ao meu projeto.
Segundo, o artigo mostra como trazer a instância existente do aplicativo para o primeiro plano quando o usuário tenta iniciar outra instância. Esse é um toque muito agradável que as outras soluções Mutex descritas aqui não abordam.
ATUALIZAR
Em 1/8/2014, o artigo ao qual vinculei acima ainda está ativo, mas o blog não é atualizado há algum tempo. Isso me preocupa que, eventualmente, ele desapareça e, com ela, a solução preconizada. Estou reproduzindo o conteúdo do artigo aqui para posteridade. As palavras pertencem exclusivamente ao proprietário do blog na Sanity Free Coding .
fonte
Mutex
construtor simplesmente requer uma string, para que você possa fornecer o nome que desejar, por exemplo, "This Is My Mutex". Como um 'Mutex' é um objeto de sistema que está disponível para outros processos, normalmente você deseja que o nome seja exclusivo para que não colidir com outros nomes de 'Mutex' no mesmo sistema. No artigo, a string de aparência enigmática é um 'Guid'. Você pode gerar isso programaticamente chamandoSystem.Guid.NewGuid()
. No caso do artigo, o usuário provavelmente o gerou por meio do Visual Studio, como mostrado aqui: msdn.microsoft.com/en-us/library/ms241442(VS.80).aspxVocê pode usar a classe Mutex, mas em breve descobrirá que precisará implementar o código para transmitir os argumentos e tal. Bem, eu aprendi um truque ao programar no WinForms quando li o livro de Chris Sell . Esse truque usa a lógica que já está disponível para nós na estrutura. Eu não sei sobre você, mas quando aprendo sobre coisas que posso reutilizar na estrutura, esse é geralmente o caminho que tomo em vez de reinventar a roda. A menos, é claro, que não faça tudo o que eu quero.
Quando entrei no WPF, criei uma maneira de usar o mesmo código, mas em um aplicativo WPF. Esta solução deve atender às suas necessidades com base em sua pergunta.
Primeiro, precisamos criar nossa classe de aplicativo. Nesta classe, substituiremos o evento OnStartup e criaremos um método chamado Activate, que será usado posteriormente.
Segundo, precisaremos criar uma classe que possa gerenciar nossas instâncias. Antes de passarmos por isso, vamos realmente reutilizar algum código que está no assembly Microsoft.VisualBasic. Como estou usando o C # neste exemplo, tive que fazer uma referência ao assembly. Se você estiver usando o VB.NET, não precisará fazer nada. A classe que vamos usar é WindowsFormsApplicationBase e herdaremos nosso gerenciador de instâncias e, em seguida, aproveitaremos as propriedades e os eventos para lidar com a instância única.
Basicamente, estamos usando os bits VB para detectar instâncias únicas e processar adequadamente. O OnStartup será acionado quando a primeira instância for carregada. OnStartupNextInstance é acionado quando o aplicativo é executado novamente. Como você pode ver, eu posso entender o que foi passado na linha de comando através dos argumentos do evento. Eu defino o valor para um campo de instância. Você pode analisar a linha de comando aqui ou transmiti-la ao seu aplicativo através do construtor e da chamada para o método Activate.
Terceiro, é hora de criar nosso EntryPoint. Em vez de atualizar o aplicativo como você faria normalmente, aproveitaremos o nosso SingleInstanceManager.
Bem, espero que você seja capaz de seguir tudo, poder usar esta implementação e torná-la sua.
fonte
A partir daqui .
Um uso comum para um Mutex entre processos é garantir que apenas a instância de um programa possa ser executada por vez. Veja como é feito:
Um bom recurso do Mutex é que, se o aplicativo terminar sem que o ReleaseMutex seja chamado pela primeira vez, o CLR lançará o Mutex automaticamente.
fonte
Na verdade, o MSDN possui um aplicativo de exemplo para C # e VB para fazer exatamente isso: http://msdn.microsoft.com/en-us/library/ms771662(v=VS.90).aspx
'Another instance of the app is running. Bye'
, ele não será um usuário muito feliz. Você simplesmente DEVE (em um aplicativo GUI) alternar para esse aplicativo e passar os argumentos fornecidos - ou se os parâmetros da linha de comando não tiverem significado, será necessário abrir o aplicativo que pode ter sido minimizado.A estrutura já tem suporte para isso - é apenas que algum idiota nomeou a DLL
Microsoft.VisualBasic
e ela não foi colocadaMicrosoft.ApplicationUtils
ou algo parecido. Supere isso - ou abra o Reflector.Dica: Se você usar essa abordagem exatamente como está, e já tiver um App.xaml com recursos, etc., também desejará dar uma olhada nisso .
fonte
Este código deve ir para o método principal. Veja aqui mais informações sobre o método principal no WPF.
Método 2
Nota: Os métodos acima assumem que seu processo / aplicativo possui um nome exclusivo. Porque ele usa o nome do processo para descobrir se há processadores existentes. Portanto, se seu aplicativo tiver um nome muito comum (ou seja: Bloco de notas), a abordagem acima não funcionará.
fonte
ProcessName
retorna o nome do arquivo executável menos oexe
. Se você criar um aplicativo chamado "Bloco de Notas" e o bloco de notas do Windows estiver em execução, ele será detectado como seu aplicativo em execução.Bem, eu tenho uma classe descartável para isso que funciona facilmente na maioria dos casos de uso:
Use-o assim:
Aqui está:
fonte
Um novo que usa material Mutex e IPC e também transmite quaisquer argumentos de linha de comando para a instância em execução é o Aplicativo de Instância Única do WPF .
fonte
O código C # .NET Single Instance Application que é a referência para a resposta marcada é um ótimo começo.
No entanto, descobri que não lida muito bem com os casos em que a instância que já existe possui uma caixa de diálogo modal aberta, seja ela gerenciada (como outra forma como uma caixa about) ou não gerenciada (como a OpenFileDialog, mesmo ao usar a classe .NET padrão). Com o código original, o formulário principal é ativado, mas o modal permanece inativo, o que parece estranho, e o usuário deve clicar nele para continuar usando o aplicativo.
Portanto, criei uma classe de utilitário SingleInstance para lidar com tudo isso automaticamente para aplicativos WinForms e WPF.
Winforms :
1) modifique a classe Program da seguinte maneira:
2) modifique a classe da janela principal assim:
WPF:
1) modifique a página do aplicativo como esta (e certifique-se de definir sua ação de compilação como página para poder redefinir o método Main):
2) modifique a classe da janela principal assim:
E aqui está a classe de utilitário:
fonte
Aqui está um exemplo que permite que você tenha uma única instância de um aplicativo. Quando qualquer nova instância é carregada, eles passam seus argumentos para a instância principal que está sendo executada.
fonte
Apenas algumas considerações: há casos em que é necessário que apenas uma instância de um aplicativo não seja "coxo", como alguns acreditam. Os aplicativos de banco de dados etc. são uma ordem de magnitude mais difícil se permitirmos que várias instâncias do aplicativo acessem um banco de dados por um único usuário (você sabe, tudo isso atualiza todos os registros abertos em várias instâncias do aplicativo nos usuários) máquina etc.). Primeiro, para a "coisa de colisão de nome, não use um nome legível por humanos - use um GUID ou, melhor ainda, um GUID + o nome legível por humanos. As chances de colisão de nomes desapareceram do radar e o Mutex não se importa. Como alguém apontou, um ataque do DOS seria péssimo, mas se a pessoa mal-intencionada tiver o problema de obter o nome do mutex e incorporá-lo ao aplicativo, você é praticamente um alvo de qualquer maneira e precisará fazer MUITO mais para se proteger do que apenas mexer em um nome mutex. Além disso, se alguém usar a variante de: new Mutex (true, "some GUID plus Name", out AIsFirstInstance), você já terá seu indicador sobre se o Mutex é ou não a primeira instância.
fonte
Tantas respostas para uma pergunta aparentemente simples. Só para agitar um pouco as coisas, aqui está a minha solução para este problema.
Criar um Mutex pode ser problemático porque o JIT-er apenas o vê usando uma pequena parte do seu código e deseja marcá-lo como pronto para a coleta de lixo. Ele quer ser mais esperto do que você pensa que não usará o Mutex por tanto tempo. Na realidade, você deseja manter esse Mutex enquanto o aplicativo estiver em execução. A melhor maneira de dizer ao coletor de lixo para deixá-lo em paz com o Mutex é dizendo-lhe para mantê-lo vivo pelas diferentes gerações de coleta de garagem. Exemplo:
Tirei a ideia desta página: http://www.ai.uga.edu/~mc/SingleInstance.html
fonte
Parece que existe uma maneira realmente boa de lidar com isso:
Aplicativo de instância única WPF
Isso fornece uma classe que você pode adicionar que gerencia todo o mutex e cruff de mensagens para simplificar a sua implementação até o ponto em que é simplesmente trivial.
fonte
O código a seguir é minha solução de pipes nomeados do WCF para registrar um aplicativo de instância única. É bom porque também gera um evento quando outra instância tenta iniciar e recebe a linha de comando da outra instância.
É voltado para o WPF porque usa a
System.Windows.StartupEventHandler
classe, mas isso pode ser facilmente modificado.Este código requer uma referência a
PresentationFramework
, eSystem.ServiceModel
.Uso:
Código fonte:
fonte
Você nunca deve usar um mutex nomeado para implementar um aplicativo de instância única (ou pelo menos não para o código de produção). Código malicioso pode facilmente fazer DoS ( Negação de Serviço ) sua bunda ...
fonte
Veja o código a seguir. É uma solução excelente e simples para impedir várias instâncias de um aplicativo WPF.
fonte
Aqui está o que eu uso. Ele combinou a enumeração de processos para executar alternância e mutex para proteger contra "clickers ativos":
fonte
Encontrei a solução mais simples, semelhante à de Dale Ragan, mas ligeiramente modificada. Ele faz praticamente tudo o que você precisa e com base na classe Microsoft WindowsFormsApplicationBase padrão.
Primeiro, você cria a classe SingleInstanceController, que pode ser usada em todos os outros aplicativos de instância única, que usam o Windows Forms:
Então você pode usá-lo em seu programa da seguinte maneira:
O programa e a solução SingleInstanceController_NET devem fazer referência ao Microsoft.VisualBasic. Se você deseja apenas reativar o aplicativo em execução como uma janela normal quando o usuário tenta reiniciar o programa em execução, o segundo parâmetro no SingleInstanceController pode ser nulo. No exemplo dado, a janela é maximizada.
fonte
Atualização 2017-01-25. Depois de tentar algumas coisas, decidi usar o VisualBasic.dll, que é mais fácil e funciona melhor (pelo menos para mim). Deixei minha resposta anterior apenas como referência ...
Apenas como referência, foi assim que passei sem passar argumentos (o que não consigo encontrar nenhuma razão para fazê-lo ... quero dizer, um único aplicativo com argumentos que devem ser passados de uma instância para outra). Se a associação de arquivos for necessária, um aplicativo (conforme a expectativa padrão dos usuários) será instanciado para cada documento. Se você tiver que passar args para o aplicativo existente, acho que usaria a dll vb.
Não passando argumentos (apenas aplicativo de instância única), prefiro não registrar uma nova mensagem do Windows e não substituir o loop de mensagens, conforme definido na Matt Davis Solution. Embora não seja muito importante adicionar uma dll VisualBasic, prefiro não adicionar uma nova referência apenas para criar um aplicativo de instância única. Além disso, prefiro instanciar uma nova classe com Main em vez de chamar Shutdown a partir da substituição App.Startup para garantir a saída o mais rápido possível.
Na esperança de que alguém goste ... ou inspire um pouco :-)
A classe de inicialização do projeto deve ser definida como 'SingleInstanceApp'.
WindowHelper:
fonte
Não usando o Mutex, porém, resposta simples:
Coloque dentro do
Program.Main()
.Exemplo :
Você pode adicionar
MessageBox.Show
àif
declaração e colocar "Aplicativo já em execução".Isso pode ser útil para alguém.
fonte
As abordagens baseadas em mutex nomeado não são multiplataforma porque os mutexes nomeados não são globais no Mono. As abordagens baseadas em enumeração de processos não têm sincronização e podem resultar em comportamento incorreto (por exemplo, vários processos iniciados ao mesmo tempo podem terminar automaticamente, dependendo do tempo). As abordagens baseadas no sistema de janelas não são desejáveis em um aplicativo de console. Esta solução, construída sobre a resposta de Divin, aborda todos estes problemas:
fonte
Eu uso o Mutex na minha solução para evitar várias instâncias.
fonte
Use solução mutex:
fonte
Aqui está uma solução leve que eu uso, que permite que o aplicativo traga uma janela já existente para o primeiro plano sem recorrer a mensagens personalizadas do Windows ou pesquisar cegamente os nomes dos processos.
Edit: Você também pode armazenar e inicializar o mutex e createdNew estaticamente, mas precisará descartá-lo / liberar explicitamente o mutex assim que terminar. Pessoalmente, prefiro manter o mutex local, pois ele será descartado automaticamente, mesmo que o aplicativo seja fechado sem chegar ao final do Main.
fonte
Você também pode usar o CodeFluent Runtime, que é um conjunto gratuito de ferramentas. Ele fornece uma classe SingleInstance para implementar um aplicativo de instância única.
fonte
Adicionei um método sendMessage à classe NativeMethods.
Aparentemente, o método do método postmessage funciona, se o aplicativo não for exibido na barra de tarefas, no entanto, o uso do método sendmessage resolve isso.
fonte
Aqui está a mesma coisa implementada via Event.
fonte
[Forneci código de exemplo para aplicativos de console e wpf abaixo.]
Você só precisa verificar o valor da
createdNew
variável (exemplo abaixo!), Depois de criar a instância Mutex nomeada.O booleano
createdNew
retornará false:O booleano
createdNew
retornará true:Aplicativo de console - Exemplo:
Exemplo WPF:
fonte
Uma solução que economiza tempo para C # Winforms ...
Program.cs:
fonte
Verifique a solução proposta aqui que usa um semáforo para determinar se uma instância existente já está em execução, funciona para um aplicativo WPF e pode passar argumentos da segunda instância para a primeira instância já em execução usando um TcpListener e um TcpClient:
Também funciona para o .NET Core, não apenas para o .NET Framework.
fonte
Não consigo encontrar uma solução curta aqui, então espero que alguém goste disso:
ATUALIZADO 20/09/2018
Coloque este código no seu
Program.cs
:fonte