Czy mogę wysłać ctrl-C (SIGINT) do aplikacji w systemie Windows?


91

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.)?


1
Byłem zainteresowany wysłaniem Ctrl-C do procesów usług java tylko w celu uzyskania zrzutów wątków. Wygląda na to, że jstackzamiast tego można niezawodnie wykorzystać w tej konkretnej sprawie: stackoverflow.com/a/47723393/603516
Vadzim

Odpowiedzi:


31

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:

Po długich poszukiwaniach w debugerze odkryłem, że punktem wejścia, który faktycznie wykonuje zachowanie związane z sygnałem, takim jak ctrl-break, jest kernel32! CtrlRoutine. Funkcja miała ten sam prototyp co ThreadProc, więc może być używana bezpośrednio z CreateRemoteThread, bez konieczności wstrzykiwania kodu. Jednak to nie jest eksportowany symbol! Znajduje się pod różnymi adresami (a nawet ma różne nazwy) w różnych wersjach systemu Windows. Co robić?

Oto rozwiązanie, które w końcu wymyśliłem. Instaluję program obsługi ctrl konsoli dla mojej aplikacji, a następnie generuję sygnał ctrl-break dla mojej aplikacji. Kiedy mój program obsługi zostaje wywołany, spoglądam wstecz na szczyt stosu, aby znaleźć parametry przekazane do kernel32! BaseThreadStart. Pobieram pierwszy parametr, czyli pożądany adres początkowy wątku, czyli adres kernel32! CtrlRoutine. Następnie wracam z mojego programu obsługi, wskazując, że obsłużyłem sygnał i moja aplikacja nie powinna zostać zakończona. Wracając do głównego wątku, czekam na pobranie adresu kernel32! CtrlRoutine. Kiedy już to zrobię, tworzę zdalny wątek w procesie docelowym z odkrytym adresem początkowym. Powoduje to, że procedury obsługi ctrl w procesie docelowym są oceniane tak, jakby naciśnięto ctrl-break!

Fajną rzeczą jest to, że dotyczy to tylko procesu docelowego, a celem może być każdy proces (nawet proces okienkowy). Jedną wadą jest to, że moja mała aplikacja nie może być używana w pliku wsadowym, ponieważ zabije ją, gdy wyśle ​​zdarzenie ctrl-break w celu wykrycia adresu kernel32! CtrlRoutine.

( startJeśli uruchamiasz go w pliku wsadowym, poprzedź go ciągiem ).


2
+1 - Połączony kod używa Ctrl-Break zamiast Ctrl-C, ale na pierwszy rzut oka (patrząc na dokumentację GenerateConsoleCtrlEvent) można go dostosować do Ctrl-C.
Matthew Murdoch

8
Właściwie jest funkcja, która zrobi to za ciebie, lol, "GenerateConsoleCtrlEvent". Zobacz: msdn.microsoft.com/en-us/library/ms683155(v=vs.85).aspx Zobacz także moją odpowiedź tutaj: serverfault.com/a/501045/10023
Triynko

1
Odnośnik do Github związany z powyższą odpowiedzią: github.com/walware/statet/tree/master/…
meawoppl

3
To zdumiewa fakt, że Windows jest tak stary, jak jest, a mimo to Microsoft nie dostarczył mechanizmu dla aplikacji konsolowej A do nasłuchiwania sygnału z aplikacji konsolowej B, tak aby aplikacja konsolowa B mogła nakazać aplikacji konsolowej A zamknięcie się w sposób czysty. W każdym razie, odkładając na bok MS, próbowałem SendSignal i otrzymałem komunikat „CreateRemoteThread nie powiódł się z 0x00000005”. Jakieś inne pomysły, jak zaprogramować aplikację A do nasłuchiwania sygnału (dowolnego dogodnego sygnału) i jak go następnie zasygnalizować?
David I. McIntosh,

3
@ DavidI.McIntosh wygląda na to, że chcesz utworzyć nazwane zdarzenie w obu procesach; byłbyś wtedy w stanie zasygnalizować jeden z drugiego. Sprawdź dokumentację dla CreateEvent
arolson101

58

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:

  • Uruchom program z widocznym oknem za pomocą .Net, ukryj za pomocą pinvoke, uruchom przez 6 sekund, pokaż za pomocą pinvoke, zatrzymaj za pomocą .Net.
  • Uruchom program bez okna za pomocą .Net, uruchom przez 6 sekund, zakończ, podłączając konsolę i wydając ConsoleCtrlEvent

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){}
}

4
Zainspirowany tym, stworzyłem „samodzielną” aplikację cpp, która to robi: gist.github.com/rdp/f51fb274d69c5c31b6be na wypadek, gdyby była przydatna. I tak, ta metoda najwyraźniej może wysłać ctrl + c lub ctrl + break do „dowolnego” pidu.
rogerdpack

Brak jednej z bibliotek DLL importuje plik „SetConsoleCtrlHandler”, ale to działa.
Derf Skren,

doskonały post. doskonały blog. Sugerowałbym zakończenie funkcji StopProgramWithInvisibleWindowUsingPinvoke w programie eksperymentu. Prawie porzuciłem ten pomysł, myśląc, że nie znalazłeś rozwiązania
Wilmer Saint

Aby uniknąć 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?).
56ka

FreeConsole należy wywołać natychmiast po wysłaniu GenerateConsoleCtrlEvent. Dopóki nie zostanie wywołana, Twoja aplikacja zostanie dołączona do drugiej konsoli. Jeśli druga konsola zostanie zabita przed zakończeniem zamykania, Twoja aplikacja również zostanie zakończona!
Timothy Jannace,

17

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.


6
Dzięki za rozwiązanie! To kolejny przykład tego, że Windows API jest takim strasznym bałaganem.
vitaut

8

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 .


Chcę to zrobić w aplikacji wiersza poleceń (bez okien). TerminateProcess jest mechanizmem wymuszania zabijania (podobnym do SIGKILL), więc nie daje przerywającej aplikacji żadnej możliwości wyczyszczenia.
Matthew Murdoch

@Matthew Murdoch: Zaktualizowano w celu uwzględnienia informacji o tym, jak sobie z tym poradzić w aplikacji konsoli. Za pomocą tego samego mechanizmu można również przechwytywać inne zdarzenia, w tym zamknięcie systemu Windows lub zamknięcie konsoli itp. Aby uzyskać szczegółowe informacje, zobacz MSDN.
Reed Copsey

@Reed Copsey: Ale chciałbym rozpocząć to od oddzielnego procesu. Rzuciłem okiem na GenerateConsoleCtrlEvent (przywoływane z SetConsoleCtrlHandler), ale wydaje się, że działa to tylko wtedy, gdy kończony proces znajduje się w tej samej „grupie procesów” co proces kończący… Jakieś pomysły?
Matthew Murdoch

1
Matthew: Jedynym pomysłem byłoby znalezienie procesu, znalezienie jego rodzica (konsoli), pobranie uchwytu głównego okna rodzica (konsoli) i użycie SendKeys do wysłania Ctrl + C bezpośrednio do niego. To powinno spowodować, że proces konsoli otrzyma CTRL_C_EVENT. Jednak nie próbowałem tego - nie jestem pewien, jak dobrze to zadziała.
Reed Copsey

Oto odpowiednik C ++ dla SendKeys stackoverflow.com/questions/6838363/ ... zobacz także stackoverflow.com/questions/10407769/ ... chociaż najwyraźniej nie ma gwarancji, że będzie działać nawet wtedy ...
rogerdpack

7

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.

void SendControlC(int pid)
{
    AttachConsole(pid); // attach to process console
    SetConsoleCtrlHandler(NULL, TRUE); // disable Control+C handling for our app
    GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0); // generate Control+C event
}

i jak odzyskać kontrolę? a potem wysyłam control-c, program stopar, ale nie mogę nic zrobić rękami.
Yaroslav L.,

Gdzie zwrócić kontrolę?
KindDragon

Myślę, że wywołujesz SetConsoleCtrlHandler (NULL, FALSE), aby usunąć swój program obsługi, zobacz różne inne odpowiedzi.
rogerdpack

6

Oto kod, którego używam w mojej aplikacji C ++.

Punkty pozytywne:

  • Działa z aplikacji konsoli
  • Działa z usługi Windows
  • Nie jest wymagane żadne opóźnienie
  • Nie zamyka bieżącej aplikacji

Punkty ujemne:

  • Główna konsola zostaje utracona i zostaje utworzona nowa (patrz FreeConsole )
  • Przełączanie konsoli daje dziwne rezultaty ...

// Inspired from http://stackoverflow.com/a/15281070/1529139
// and http://stackoverflow.com/q/40059902/1529139
bool signalCtrl(DWORD dwProcessId, DWORD dwCtrlEvent)
{
    bool success = false;
    DWORD thisConsoleId = GetCurrentProcessId();
    // Leave current console if it exists
    // (otherwise AttachConsole will return ERROR_ACCESS_DENIED)
    bool consoleDetached = (FreeConsole() != FALSE);

    if (AttachConsole(dwProcessId) != FALSE)
    {
        // Add a fake Ctrl-C handler for avoid instant kill is this console
        // WARNING: do not revert it or current program will be also killed
        SetConsoleCtrlHandler(nullptr, true);
        success = (GenerateConsoleCtrlEvent(dwCtrlEvent, 0) != FALSE);
        FreeConsole();
    }

    if (consoleDetached)
    {
        // Create a new console if previous was deleted by OS
        if (AttachConsole(thisConsoleId) == FALSE)
        {
            int errorCode = GetLastError();
            if (errorCode == 31) // 31=ERROR_GEN_FAILURE
            {
                AllocConsole();
            }
        }
    }
    return success;
}

Przykład użycia:

DWORD dwProcessId = ...;
if (signalCtrl(dwProcessId, CTRL_C_EVENT))
{
    cout << "Signal sent" << endl;
}

4
        void SendSIGINT( HANDLE hProcess )
        {
            DWORD pid = GetProcessId(hProcess);
            FreeConsole();
            if (AttachConsole(pid))
            {
                // Disable Ctrl-C handling for our program
                SetConsoleCtrlHandler(NULL, true);

                GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0); // SIGINT

                //Re-enable Ctrl-C handling or any subsequently started
                //programs will inherit the disabled state.
                SetConsoleCtrlHandler(NULL, false);

                WaitForSingleObject(hProcess, 10000);
            }
        }

2

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:

(2014-3-7): Zbudowałem zarówno wersję 32-bitową, jak i 64-bitową z Ctrl-C, nazywa się SendSignalCtrlC.exe i możesz ją pobrać pod adresem : https://dl.dropboxusercontent.com/u/49065779/ sendignalctrlc / x86 / SendSignalCtrlC.exe https://dl.dropboxusercontent.com/u/49065779/sendsignalctrlc/x86_64/SendSignalCtrlC.exe - Juraj Michalak

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.


2

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.

import com.sun.jna.platform.win32.Kernel32;    

public class CtrlCSender {

    public static void main(String args[]) {
        int processId = Integer.parseInt(args[0]);
        Kernel32.INSTANCE.AttachConsole(processId);
        Kernel32.INSTANCE.GenerateConsoleCtrlEvent(Kernel32.CTRL_C_EVENT, 0);
    }
}

Główna aplikacja - uruchamia CtrlCSender jako oddzielny proces bez konsoli

ProcessBuilder pb = new ProcessBuilder();
pb.command("javaw", "-cp", System.getProperty("java.class.path", "."), CtrlCSender.class.getName(), processId);
pb.redirectErrorStream();
pb.redirectOutput(ProcessBuilder.Redirect.INHERIT);
pb.redirectError(ProcessBuilder.Redirect.INHERIT);
Process ctrlCProcess = pb.start();
ctrlCProcess.waitFor();

hmm, jeśli uruchomię to z procesem PowerShell, proces pozostanie żywy. Z drugiej strony, co ciekawe, uruchomienie maszyny w trakcie na JVM rzeczywiście powoduje wyłączenie maszyny wirtualnej! Czy masz pojęcie, dlaczego proces PowerShell nie reaguje na tę technikę?
Groostav


1

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

import ctypes
import sys

kernel = ctypes.windll.kernel32

pid = int(sys.argv[1])
kernel.FreeConsole()
kernel.AttachConsole(pid)
kernel.SetConsoleCtrlHandler(None, 1)
kernel.GenerateConsoleCtrlEvent(0, 0)
sys.exit(0)

Wtedy zadzwoń:

python ctrl_c.py 12345

Jeśli to nie zadziała, polecam wypróbowanie projektu Windows-kill: https://github.com/alirdn/windows-kill


0

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

Set WshShell = WScript.CreateObject("WScript.Shell")

WshShell.Run "notepad.exe"

WshShell.AppActivate "notepad"

WScript.Sleep 7000

WshShell.SendKeys "^C"

Działa to, jeśli aplikacja ma okno, które możesz AppActive (przenieść na pierwszy plan).
rogerdpack

0

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


0
// Send [CTRL-C] to interrupt a batch file running in a Command Prompt window, even if the Command Prompt window is not visible,
// without bringing the Command Prompt window into focus.
// [CTRL-C] will have an effect on the batch file, but not on the Command Prompt  window itself -- in other words,
// [CTRL-C] will not have the same visible effect on a Command Prompt window that isn't running a batch file at the moment
// as bringing a Command Prompt window that isn't running a batch file into focus and pressing [CTRL-C] on the keyboard.
ulong ulProcessId = 0UL;
// hwC = Find Command Prompt window HWND
GetWindowThreadProcessId (hwC, (LPDWORD) &ulProcessId);
AttachConsole ((DWORD) ulProcessId);
SetConsoleCtrlHandler (NULL, TRUE);
GenerateConsoleCtrlEvent (CTRL_C_EVENT, 0UL);
SetConsoleCtrlHandler (NULL, FALSE);
FreeConsole ();

0

SIGINT można wysłać do programu przy użyciu funkcji windows-kill , według składni windows-kill -SIGINT PID, którą PIDmoż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 .


-1

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:

C:\>tasklist

Aby zabić proces:

C:\>Taskkill /IM firefox.exe /F
or
C:\>Taskkill /PID 26356 /F

Detale:

http://tweaks.com/windows/39559/kill-processes-from-command-prompt/


Przypuszczalnie to wysyła sigterm?
teknopaul

Taskkill nie wysyła CTRL-C. Sprawdź sygnały systemu Windows.
Josi
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.