He (en el pasado) escrita aplicaciones multiplataforma (Windows / Unix) que, cuando se inicia desde la línea de comandos, manejan un escrito de usuario Ctrl- Cla combinación de la misma manera (es decir, para terminar la aplicación limpia).
¿Es posible en Windows enviar un Ctrl- C/ SIGINT / equivalente a un proceso de otro proceso (no relacionado) para solicitar que finalice limpiamente (dándole la oportunidad de ordenar los recursos, etc.)?
jstack
puede usar de manera confiable en su lugar para este asunto específico: stackoverflow.com/a/47723393/603516Respuestas:
Lo más cerca que he llegado a una solución es la aplicación de terceros SendSignal . El autor enumera el código fuente y un ejecutable. He verificado que funciona en Windows de 64 bits (ejecutándose como un programa de 32 bits, matando a otro programa de 32 bits), pero no he descubierto cómo incrustar el código en un programa de Windows (ya sea de 32 bits o 64 bits).
Cómo funciona:
(Antepóngalo
start
si lo ejecuta en un archivo por lotes).fuente
He realizado algunas investigaciones sobre este tema, que resultó ser más popular de lo que esperaba. La respuesta de KindDragon fue uno de los puntos fundamentales.
Escribí una publicación de blog más larga sobre el tema y creé un programa de demostración funcional, que demuestra el uso de este tipo de sistema para cerrar una aplicación de línea de comandos en un par de formas agradables. Esa publicación también enumera los enlaces externos que utilicé en mi investigación.
En resumen, esos programas de demostración hacen lo siguiente:
Editar: La solución modificada de KindDragon para aquellos que estén interesados en el código aquí y ahora. Si planea iniciar otros programas después de detener el primero, debe volver a habilitar el manejo de Ctrl-C; de lo contrario, el siguiente proceso heredará el estado deshabilitado del padre y no 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); } }
Además, planifique una solución de contingencia si
AttachConsole()
la señal enviada falla, por ejemplo, durmiendo, entonces esto:if (!proc.HasExited) { try { proc.Kill(); } catch (InvalidOperationException e){} }
fuente
wait()
, eliminé la opción Volver a habilitar Ctrl-C (SetConsoleCtrlHandler(null, false);
). Hice algunas pruebas (múltiples llamadas, también en procesos ya terminados) y no encontré ningún efecto secundario (¿todavía?).Supongo que llego un poco tarde en esta pregunta, pero de todos modos escribiré algo para cualquiera que tenga el mismo problema. Esta es la misma respuesta que le di a esta pregunta.
Mi problema era que me gustaría que mi aplicación fuera una aplicación GUI, pero los procesos ejecutados deberían ejecutarse en segundo plano sin ninguna ventana de consola interactiva adjunta. Creo que esta solución también debería funcionar cuando el proceso principal es un proceso de consola. Sin embargo, es posible que deba eliminar la bandera "CREATE_NO_WINDOW".
Logré resolver esto usando GenerateConsoleCtrlEvent () con una aplicación contenedora. La parte complicada es que la documentación no es realmente clara sobre cómo se puede usar y los inconvenientes que conlleva.
Mi solución se basa en lo que se describe aquí . Pero eso tampoco explicó todos los detalles y con un error, así que aquí están los detalles sobre cómo hacerlo funcionar.
Cree una nueva aplicación de ayuda "Helper.exe". Esta aplicación se ubicará entre su aplicación (padre) y el proceso hijo que desea poder cerrar. También creará el proceso hijo real. Debe tener este proceso de "intermediario" o GenerateConsoleCtrlEvent () fallará.
Utilice algún tipo de mecanismo de IPC para comunicar del padre al proceso auxiliar que el ayudante debe cerrar el proceso hijo. Cuando el asistente obtiene este evento, llama a "GenerateConsoleCtrlEvent (CTRL_BREAK, 0)", que se cierra a sí mismo y al proceso hijo. Usé un objeto de evento para esto yo mismo que el padre completa cuando quiere cancelar el proceso secundario.
Para crear su Helper.exe, créelo con CREATE_NO_WINDOW y CREATE_NEW_PROCESS_GROUP. Y al crear el proceso hijo, créelo sin marcas (0), lo que significa que derivará la consola de su padre. Si no lo hace, se ignorará el evento.
Es muy importante que cada paso se haga así. He estado probando diferentes tipos de combinaciones, pero esta combinación es la única que funciona. No puede enviar un evento CTRL_C. Devolverá el éxito, pero el proceso lo ignorará. CTRL_BREAK es el único que funciona. Realmente no importa ya que ambos llamarán a ExitProcess () al final.
Tampoco puede llamar a GenerateConsoleCtrlEvent () con una identificación de grupo de proceso de la identificación del proceso secundario, lo que permite que el proceso auxiliar continúe viviendo. Esto también fallará.
Pasé un día entero tratando de que esto funcionara. Esta solución funciona para mí, pero si alguien tiene algo más que agregar, hágalo. Busqué por toda la red muchas personas con problemas similares pero sin una solución definitiva al problema. El funcionamiento de GenerateConsoleCtrlEvent () también es un poco extraño, así que si alguien conoce más detalles al respecto, compártelo.
fuente
Editar:
Para una aplicación GUI, la forma "normal" de manejar esto en el desarrollo de Windows sería enviar un mensaje WM_CLOSE a la ventana principal del proceso.
Para una aplicación de consola, debe usar SetConsoleCtrlHandler para agregar un
CTRL_C_EVENT
.Si la aplicación no cumple con eso, puede llamar a TerminateProcess .
fuente
De alguna manera
GenerateConsoleCtrlEvent()
devuelve el error si lo llama para otro proceso, pero puede adjuntarlo a otra aplicación de consola y enviar un evento a todos los procesos secundarios.fuente
Aquí está el código que uso en mi aplicación C ++.
Puntos positivos :
Puntos negativos :
Ejemplo de uso:
fuente
fuente
Debería quedar muy claro porque por el momento no lo es. Existe una versión modificada y compilada de SendSignal para enviar Ctrl-C (por defecto solo envía Ctrl + Break). Aquí hay algunos binarios:
También he reflejado esos archivos por si acaso:
versión de 32 bits: https://www.dropbox.com/s/r96jxglhkm4sjz2/SendSignalCtrlC.exe?dl=0 versión de
64 bits: https://www.dropbox.com /s/hhe0io7mcgcle1c/SendSignalCtrlC64.exe?dl=0
Descargo de responsabilidad: yo no construí esos archivos. No se realizaron modificaciones a los archivos originales compilados. La única plataforma probada es Windows 7 de 64 bits. Se recomienda adaptar la fuente disponible en http://www.latenighthacking.com/projects/2003/sendSignal/ y compilarla usted mismo.
fuente
En Java, se usa JNA con la biblioteca Kernel32.dll, similar a una solución C ++. Ejecuta el método principal CtrlCSender como un proceso que solo obtiene la consola del proceso para enviar el evento Ctrl + C y genera el evento. Como se ejecuta por separado sin una consola, el evento Ctrl + C no necesita deshabilitarse y habilitarse nuevamente.
CtrlCSender.java - Sobre la base de Nemo1024 de y de KindDragon respuestas.
Dado un ID de proceso conocido, esta aplicación sin consola adjuntará la consola del proceso objetivo y generará un evento CTRL + C en él.
Aplicación principal : ejecuta CtrlCSender como un proceso independiente sin consola
fuente
Si. El
windows-kill
proyecto hace exactamente lo que quieres:fuente
Una solución que he encontrado desde aquí es bastante simple si tiene Python 3.x disponible en su línea de comando. Primero, guarde un archivo (ctrl_c.py) con el contenido:
Luego llame:
Si eso no funciona, recomiendo probar el proyecto windows-kill: https://github.com/alirdn/windows-kill
fuente
Un amigo mío sugirió una forma completamente diferente de resolver el problema y funcionó para mí. Utilice un vbscript como el siguiente. Se inicia y aplica, déjalo correr por 7 segundos y ciérralo usando ctrl + c .
'Ejemplo de VBScript
fuente
He encontrado todo esto demasiado complicado y se utiliza SendKeys para enviar un CTRL- C(es decir, la ventana cmd.exe) de pulsaciones de teclas a la ventana de línea de comandos como una solución.
fuente
fuente
SIGINT se puede enviar al programa usando windows-kill , por sintaxis
windows-kill -SIGINT PID
, dondePID
se puede obtener mediante pslist de Microsoft .Con respecto a la captura de SIGINT, si su programa está en Python, puede implementar el procesamiento / captura de SIGINT como en esta solución .
fuente
Según la identificación del proceso, podemos enviar la señal al proceso para terminar con fuerza o gracia o cualquier otra señal.
Enumere todo el proceso:
Para matar el proceso:
Detalles:
http://tweaks.com/windows/39559/kill-processes-from-command-prompt/
fuente