Mam (w przeszłości) napisany wieloplatformowy (Windows / Unix) aplikacje, które po uruchomieniu z wiersza polecenia obsługiwane przez użytkownika wpisane Ctrl- Cpołączenie w taki sam sposób (czyli do zakończenia stosowania czysto).
Czy w systemie Windows można wysłać Ctrl- C/ SIGINT / odpowiednik procesu z innego (niepowiązanego) procesu, aby zażądać jego czystego zakończenia (dając mu możliwość uporządkowania zasobów itp.)?
jstack
zamiast tego można niezawodnie wykorzystać w tej konkretnej sprawie: stackoverflow.com/a/47723393/603516Odpowiedzi:
Najbliższym rozwiązaniem jest aplikacja SendSignal innej firmy. Autor wymienia kod źródłowy i plik wykonywalny. Sprawdziłem, że działa w 64-bitowych oknach (działa jako program 32-bitowy, zabijając inny program 32-bitowy), ale nie wymyśliłem, jak osadzić kod w programie Windows (ani 32-bitowym lub 64-bitowy).
Jak to działa:
(
start
Jeśli uruchamiasz go w pliku wsadowym, poprzedź go ciągiem ).źródło
Zrobiłem kilka badań na ten temat, który okazał się bardziej popularny niż się spodziewałem. Odpowiedź KindDragon była jednym z kluczowych punktów.
Napisałem na ten temat dłuższy wpis na blogu i stworzyłem działający program demonstracyjny, który demonstruje użycie tego typu systemu do zamknięcia aplikacji wiersza poleceń w kilku fajnych modach. Ten post zawiera również listę linków zewnętrznych, których użyłem w moich badaniach.
Krótko mówiąc, te programy demonstracyjne wykonują następujące czynności:
Edycja: zmienione rozwiązanie od KindDragon dla tych, którzy są zainteresowani kodem tu i teraz. Jeśli planujesz uruchomić inne programy po zatrzymaniu pierwszego, powinieneś ponownie włączyć obsługę Ctrl-C, w przeciwnym razie następny proces odziedziczy stan wyłączenia rodzica i nie będzie reagował na 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); } }
Zaplanuj również rozwiązanie awaryjne, jeśli
AttachConsole()
lub wysłany sygnał zawiedzie, na przykład spanie, to:if (!proc.HasExited) { try { proc.Kill(); } catch (InvalidOperationException e){} }
źródło
wait()
, usunąłem ponownie włącz Ctrl-C (SetConsoleCtrlHandler(null, false);
). Zrobiłem kilka testów (wiele wywołań, także na już zakończonych procesach) i nie znalazłem żadnego efektu ubocznego (jeszcze?).Chyba trochę się spóźniłem z tym pytaniem, ale i tak napiszę coś dla każdego, kto ma ten sam problem. To ta sama odpowiedź, jaką udzieliłem na to pytanie.
Mój problem polegał na tym, że chciałbym, aby moja aplikacja była aplikacją GUI, ale wykonywane procesy powinny być uruchamiane w tle bez dołączonego interaktywnego okna konsoli. Myślę, że to rozwiązanie powinno również działać, gdy proces nadrzędny jest procesem konsoli. Może być jednak konieczne usunięcie flagi „CREATE_NO_WINDOW”.
Udało mi się to rozwiązać za pomocą GenerateConsoleCtrlEvent () z aplikacją opakowującą. Najtrudniejsze jest po prostu to, że dokumentacja nie jest do końca jasna, jak można go używać i jakie są z nim pułapki.
Moje rozwiązanie opiera się na tym, co opisano tutaj . Ale to też nie wyjaśniło wszystkich szczegółów i zawiera błąd, więc oto szczegóły, jak to działa.
Utwórz nową aplikację pomocniczą „Helper.exe”. Ta aplikacja będzie znajdować się między Twoją aplikacją (rodzicem) a procesem podrzędnym, który chcesz zamknąć. Stworzy również rzeczywisty proces potomny. Musisz mieć ten proces "pośrednika" lub GenerateConsoleCtrlEvent () nie powiedzie się.
Użyj pewnego rodzaju mechanizmu IPC, aby przekazać od rodzica do procesu pomocniczego, że osoba pomagająca powinna zamknąć proces potomny. Gdy pomocnik otrzyma to zdarzenie, wywołuje „GenerateConsoleCtrlEvent (CTRL_BREAK, 0)”, co zamyka siebie i proces potomny. Użyłem do tego obiektu zdarzenia, który rodzic wykonuje, gdy chce anulować proces potomny.
Aby utworzyć plik Helper.exe, utwórz go za pomocą CREATE_NO_WINDOW i CREATE_NEW_PROCESS_GROUP. Tworząc proces potomny, stwórz go bez flag (0), co oznacza, że uzyska konsolę od swojego rodzica. Niezastosowanie się do tego spowoduje zignorowanie zdarzenia.
Bardzo ważne jest, aby każdy krok był wykonywany w ten sposób. Próbowałem różnych kombinacji, ale ta kombinacja jest jedyną, która działa. Nie możesz wysłać zdarzenia CTRL_C. Zwróci sukces, ale zostanie zignorowany przez proces. CTRL_BREAK jest jedynym, który działa. Nie ma to większego znaczenia, ponieważ w końcu oboje wywołają ExitProcess ().
Nie można również wywołać GenerateConsoleCtrlEvent () z identyfikatorem grupy procesów będącym identyfikatorem procesu potomnego, co pozwala bezpośrednio procesowi pomocniczemu na kontynuowanie życia. To również się nie powiedzie.
Spędziłem cały dzień, starając się, aby to zadziałało. U mnie to rozwiązanie działa, ale jeśli ktoś ma coś jeszcze do dodania, zrób to. Przeszukałem całą sieć, znajdując wiele osób z podobnymi problemami, ale bez konkretnego rozwiązania problemu. Sposób działania GenerateConsoleCtrlEvent () jest również trochę dziwny, więc jeśli ktoś zna więcej szczegółów na ten temat, udostępnij.
źródło
Edytować:
W przypadku aplikacji z interfejsem graficznym „normalnym” sposobem rozwiązania tego problemu w programowaniu w systemie Windows byłoby wysłanie komunikatu WM_CLOSE do głównego okna procesu.
W przypadku aplikacji konsolowej musisz użyć SetConsoleCtrlHandler, aby dodać plik
CTRL_C_EVENT
.Jeśli aplikacja tego nie honoruje, możesz wywołać TerminateProcess .
źródło
W jakiś sposób
GenerateConsoleCtrlEvent()
zwraca błąd, jeśli wywołasz go dla innego procesu, ale możesz podłączyć się do innej aplikacji konsoli i wysłać zdarzenie do wszystkich procesów podrzędnych.źródło
Oto kod, którego używam w mojej aplikacji C ++.
Punkty pozytywne:
Punkty ujemne:
Przykład użycia:
źródło
źródło
Powinno być jasne, ponieważ w tej chwili tak nie jest. Istnieje zmodyfikowana i skompilowana wersja SendSignal do wysyłania Ctrl-C (domyślnie wysyła tylko Ctrl + Break). Oto kilka plików binarnych:
Na wszelki wypadek dublowałem te pliki:
wersja 32-bitowa: https://www.dropbox.com/s/r96jxglhkm4sjz2/SendSignalCtrlC.exe?dl=0 Wersja
64-bitowa: https://www.dropbox.com /s/hhe0io7mcgcle1c/SendSignalCtrlC64.exe?dl=0
Zastrzeżenie: nie zbudowałem tych plików. W skompilowanych oryginalnych plikach nie dokonano żadnych modyfikacji. Jedyną testowaną platformą jest 64-bitowy Windows 7. Zaleca się dostosowanie źródła dostępnego pod adresem http://www.latenighthacking.com/projects/2003/sendSignal/ i samodzielne skompilowanie.
źródło
W Javie przy użyciu JNA z biblioteką Kernel32.dll, podobnie do rozwiązania C ++. Uruchamia główną metodę CtrlCSender jako Process, która po prostu pobiera konsolę procesu do wysłania zdarzenia Ctrl + C do i generuje zdarzenie. Ponieważ działa oddzielnie bez konsoli, zdarzenie Ctrl + C nie musi być wyłączane i ponownie włączane.
CtrlCSender.java - Na podstawie odpowiedzi Nemo1024 i KindDragon .
Mając znany identyfikator procesu, ta aplikacja bez konsoli dołączy konsolę docelowego procesu i wygeneruje na niej zdarzenie CTRL + C.
Główna aplikacja - uruchamia CtrlCSender jako oddzielny proces bez konsoli
źródło
Tak.
windows-kill
Projekt robi dokładnie to, co chcesz:źródło
Rozwiązanie, które tutaj znalazłem , jest dość proste, jeśli masz Python 3.x dostępny w linii poleceń. Najpierw zapisz plik (ctrl_c.py) z zawartością:
Wtedy zadzwoń:
Jeśli to nie zadziała, polecam wypróbowanie projektu Windows-kill: https://github.com/alirdn/windows-kill
źródło
Mój przyjaciel zaproponował zupełnie inny sposób rozwiązania problemu i to zadziałało. Użyj VBScript, jak poniżej. Uruchamia się i aplikacja, pozwól jej działać przez 7 sekund i zamknij za pomocą ctrl + c .
„Przykład VBScript
źródło
Wszystko to wydaje mi się zbyt skomplikowane i jako obejście tego problemu użyłem SendKeys do wysłania naciśnięcia klawisza CTRL- Cdo okna wiersza poleceń (tj. Okna cmd.exe).
źródło
źródło
SIGINT można wysłać do programu przy użyciu funkcji windows-kill , według składni
windows-kill -SIGINT PID
, którąPID
można uzyskać z pslist firmy Microsoft .Jeśli chodzi o przechwytywanie SIGINT, jeśli twój program jest w Pythonie, możesz zaimplementować przetwarzanie / przechwytywanie SIGINT jak w tym rozwiązaniu .
źródło
Bazując na identyfikatorze procesu, możemy wysłać sygnał do zakończenia procesu w celu wymuszenia lub pełnego wdzięku lub dowolnego innego sygnału.
Wymień wszystkie procesy:
Aby zabić proces:
Detale:
http://tweaks.com/windows/39559/kill-processes-from-command-prompt/
źródło