Eu (no passado) escrito multi-plataforma (Windows / Unix) aplicações que, quando iniciado a partir da linha de comando, manipulados um digitado pelo usuário Ctrl- Ccombinação da mesma forma (ou seja, para encerrar o aplicativo limpa).
É possível no Windows enviar um Ctrl- C/ SIGINT / equivalente a um processo de outro processo (não relacionado) para solicitar que ele seja encerrado de forma limpa (dando-lhe a oportunidade de organizar recursos, etc.)?
jstack
pode ser usado de forma confiável para este assunto específico: stackoverflow.com/a/47723393/603516Respostas:
O mais próximo que cheguei de uma solução é o aplicativo de terceiros SendSignal . O autor lista o código-fonte e um executável. Eu verifiquei que ele funciona em janelas de 64 bits (executando como um programa de 32 bits, eliminando outro programa de 32 bits), mas não descobri como incorporar o código em um programa do Windows (seja de 32 bits ou 64 bits).
Como funciona:
(Preceda-o
start
se estiver executando em um arquivo em lote.)fonte
Fiz algumas pesquisas em torno desse tópico, que se tornaram mais populares do que eu esperava. A resposta de KindDragon foi um dos pontos principais.
Escrevi uma postagem mais longa no blog sobre o assunto e criei um programa de demonstração funcional, que demonstra o uso desse tipo de sistema para fechar um aplicativo de linha de comando em algumas maneiras legais. Esse post também lista links externos que usei em minha pesquisa.
Resumindo, esses programas de demonstração fazem o seguinte:
Edit: A solução alterada da KindDragon para aqueles que estão interessados no código aqui e agora. Se você planeja iniciar outros programas após interromper o primeiro, deve reativar o manuseio de Ctrl-C, caso contrário, o próximo processo herdará o estado desativado do pai e não responderá a Ctrl-C.
[DllImport("kernel32.dll", SetLastError = true)] static extern bool AttachConsole(uint dwProcessId); [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)] static extern bool FreeConsole(); [DllImport("kernel32.dll")] static extern bool SetConsoleCtrlHandler(ConsoleCtrlDelegate HandlerRoutine, bool Add); delegate bool ConsoleCtrlDelegate(CtrlTypes CtrlType); // Enumerated type for the control messages sent to the handler routine enum CtrlTypes : uint { CTRL_C_EVENT = 0, CTRL_BREAK_EVENT, CTRL_CLOSE_EVENT, CTRL_LOGOFF_EVENT = 5, CTRL_SHUTDOWN_EVENT } [DllImport("kernel32.dll")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool GenerateConsoleCtrlEvent(CtrlTypes dwCtrlEvent, uint dwProcessGroupId); public void StopProgram(Process proc) { //This does not require the console window to be visible. if (AttachConsole((uint)proc.Id)) { // Disable Ctrl-C handling for our program SetConsoleCtrlHandler(null, true); GenerateConsoleCtrlEvent(CtrlTypes.CTRL_C_EVENT, 0); //Moved this command up on suggestion from Timothy Jannace (see comments below) FreeConsole(); // Must wait here. If we don't and re-enable Ctrl-C // handling below too fast, we might terminate ourselves. proc.WaitForExit(2000); //Re-enable Ctrl-C handling or any subsequently started //programs will inherit the disabled state. SetConsoleCtrlHandler(null, false); } }
Além disso, planeje uma solução de contingência se
AttachConsole()
ou o sinal enviado falhar, por exemplo, dormindo, então:if (!proc.HasExited) { try { proc.Kill(); } catch (InvalidOperationException e){} }
fonte
wait()
eu removi o Re-enable Ctrl-C (SetConsoleCtrlHandler(null, false);
). Fiz alguns testes (várias chamadas, também em processos já encerrados) e não encontrei nenhum efeito colateral (ainda?).Acho que estou um pouco atrasado nessa questão, mas vou escrever algo de qualquer maneira para qualquer pessoa com o mesmo problema. Esta é a mesma resposta que dei a esta pergunta.
Meu problema era que eu gostaria que meu aplicativo fosse um aplicativo GUI, mas os processos executados deveriam ser executados em segundo plano, sem nenhuma janela de console interativo anexada. Acho que essa solução também deve funcionar quando o processo pai é um processo de console. Você pode ter que remover o sinalizador "CREATE_NO_WINDOW".
Consegui resolver isso usando GenerateConsoleCtrlEvent () com um aplicativo wrapper. A parte complicada é apenas que a documentação não é realmente clara sobre como exatamente pode ser usado e as armadilhas com ele.
Minha solução é baseada no que está descrito aqui . Mas isso também não explicava realmente todos os detalhes e com um erro, então aqui estão os detalhes de como fazer isso funcionar.
Crie um novo aplicativo auxiliar "Helper.exe". Este aplicativo ficará entre o seu aplicativo (pai) e o processo filho que você deseja fechar. Ele também criará o processo filho real. Você deve ter este processo de "intermediário" ou GenerateConsoleCtrlEvent () falhará.
Use algum tipo de mecanismo IPC para comunicar do pai para o processo auxiliar que o auxiliar deve fechar o processo filho. Quando o auxiliar obtém este evento, ele chama "GenerateConsoleCtrlEvent (CTRL_BREAK, 0)" que fecha a si mesmo e ao processo filho. Eu mesmo usei um objeto de evento para isso, que o pai conclui quando deseja cancelar o processo filho.
Para criar seu Helper.exe, crie-o com CREATE_NO_WINDOW e CREATE_NEW_PROCESS_GROUP. E ao criar o processo filho, crie-o sem sinalizadores (0), o que significa que ele derivará o console de seu pai. Deixar de fazer isso fará com que ele ignore o evento.
É muito importante que cada etapa seja executada assim. Tenho tentado todos os tipos de combinações, mas essa combinação é a única que funciona. Você não pode enviar um evento CTRL_C. Ele retornará sucesso, mas será ignorado pelo processo. CTRL_BREAK é o único que funciona. Realmente não importa, pois ambos chamarão ExitProcess () no final.
Você também não pode chamar GenerateConsoleCtrlEvent () com um ID de grupo de processo do ID do processo filho, permitindo diretamente que o processo auxiliar continue ativo. Isso também falhará.
Passei um dia inteiro tentando fazer isso funcionar. Esta solução funciona para mim, mas se alguém tiver mais alguma coisa a acrescentar, faça-o. Eu procurei por toda a rede muitas pessoas com problemas semelhantes, mas nenhuma solução definitiva para o problema. Como GenerateConsoleCtrlEvent () funciona também é um pouco estranho, então se alguém souber mais detalhes sobre ele, compartilhe.
fonte
Editar:
Para um aplicativo GUI, a maneira "normal" de lidar com isso no desenvolvimento do Windows seria enviar uma mensagem WM_CLOSE para a janela principal do processo.
Para um aplicativo de console, você precisa usar SetConsoleCtrlHandler para adicionar um
CTRL_C_EVENT
.Se o aplicativo não respeitar isso, você pode chamar TerminateProcess .
fonte
De alguma forma,
GenerateConsoleCtrlEvent()
retorne um erro se você chamá-lo para outro processo, mas você pode anexar a outro aplicativo de console e enviar o evento para todos os processos filho.fonte
Aqui está o código que uso em meu aplicativo C ++.
Pontos positivos:
Pontos negativos:
Exemplo de uso:
fonte
fonte
Deve ficar bem claro, porque no momento não é. Existe uma versão modificada e compilada de SendSignal para enviar Ctrl-C (por padrão, envia apenas Ctrl + Break). Aqui estão alguns binários:
Também espelhei esses arquivos para o caso de:
versão de 32 bits: https://www.dropbox.com/s/r96jxglhkm4sjz2/SendSignalCtrlC.exe?dl=0 versão de
64 bits: https://www.dropbox.com /s/hhe0io7mcgcle1c/SendSignalCtrlC64.exe?dl=0
Isenção de responsabilidade: eu não construí esses arquivos. Nenhuma modificação foi feita nos arquivos originais compilados. A única plataforma testada é a Windows 7 de 64 bits. Recomenda-se adaptar a fonte disponível em http://www.latenighthacking.com/projects/2003/sendSignal/ e compilá-la você mesmo.
fonte
Em Java, usando JNA com a biblioteca Kernel32.dll, semelhante a uma solução C ++. Executa o método principal CtrlCSender como um Processo que apenas obtém o console do processo para enviar o evento Ctrl + C e gera o evento. Como é executado separadamente sem um console, o evento Ctrl + C não precisa ser desativado e ativado novamente.
CtrlCSender.java - Baseado nas respostas do Nemo1024 e KindDragon .
Dado um ID de processo conhecido, este aplicativo sem console anexará o console do processo de destino e gerará um evento CTRL + C nele.
Aplicativo principal - executa CtrlCSender como um processo sem console separado
fonte
Sim. O
windows-kill
projeto faz exatamente o que você deseja:fonte
Uma solução que encontrei aqui é muito simples se você tiver o python 3.x disponível em sua linha de comando. Primeiro, salve um arquivo (ctrl_c.py) com o conteúdo:
Então ligue:
Se isso não funcionar, recomendo experimentar o projeto windows-kill: https://github.com/alirdn/windows-kill
fonte
Graças à resposta de Jimhark e outras respostas aqui, encontrei uma maneira de fazer isso no PowerShell:
O que fez as coisas funcionarem foi enviar o GenerateConsoleCtrlEvent para o grupo de processos desejado em vez de
all processes that share the console of the calling process
e o AttachConsole de voltathe console of the parent of the current process
.fonte
Um amigo meu sugeriu uma maneira completamente diferente de resolver o problema e funcionou para mim. Use um vbscript como abaixo. Ele inicia um aplicativo, deixe-o funcionar por 7 segundos e feche-o usando ctrl + c .
'Exemplo de VBScript
fonte
Eu achei tudo isso muito complicado e usado SendKeys para enviar uma CTRL- C(janela ou seja cmd.exe) de teclas para a janela de linha de comando como uma solução alternativa.
fonte
fonte
O SIGINT pode ser enviado para o programa usando o windows-kill , por sintaxe
windows-kill -SIGINT PID
, ondePID
pode ser obtido no pslist da Microsoft .Com relação à captura de SIGINTs, se seu programa estiver em Python, você pode implementar o processamento / captura de SIGINT como nesta solução .
fonte
Com base na identificação do processo, podemos enviar o sinal para o processo terminar de forma forçada ou normal ou qualquer outro sinal.
Liste todos os processos:
Para matar o processo:
Detalhes:
http://tweaks.com/windows/39559/kill-processes-from-command-prompt/
fonte