2009-09-21 8 views
14

Mam aplikację A, którą chciałbym móc wywołać dowolne inne procesy określone przez użytkownika w pliku konfiguracyjnym.Uruchamiaj dowolne podprocesy w systemie Windows i nadal kończ czystość?

Skrypt wsadowy B jest jednym z takich procesów, w których użytkownik chciałby zostać wywołany przez A. B ustawia niektóre zmienne środowiskowe, pokazuje niektóre komunikaty i wywołuje kompilator C, aby wykonać pewną pracę.

Does Okna zapewniają standardowy sposób dla dowolnych procesów zostać rozwiązana czysto? Załóżmy, że A jest uruchamiane w konsoli i otrzymuje CTRL + C. Czy może przekazać to B i C? Załóżmy, że A działa w oknie i użytkownik próbuje zamknąć okno, czy może anulować B i C?

TerminateProcess jest opcją, ale niezbyt dobrą. Jeśli A używa TerminateProcess na B, C nadal działa. Może to powodować nieprzyjemne problemy, jeśli C jest długotrwałe, ponieważ możemy uruchomić kolejną instancję C, aby działać na tych samych plikach, podczas gdy pierwsza instancja C jest nadal potajemnie w działaniu. Ponadto, TerminateProcess nie daje czystego wyjścia.

GenerateConsoleCtrlEvent brzmi nieźle i może działać, gdy wszystko działa w konsoli, ale dokumentacja mówi, że można wysłać tylko CTRL + C do swojej konsoli, a więc nie pomoże, gdyby A działało w oknie.

Czy istnieje odpowiednik SIGINT w systemie Windows? Chciałbym znaleźć taki artykuł: http://www.cons.org/cracauer/sigint.html dla systemu Windows.

+1

+1 za dobre pytanie. Zabawne nie było odpowiedzi ... Nie jestem świadomy mechanizmu podobnego do sygnału w Win32. Kiedy musiałem powiadamiać procesy potomne, wysłałem wiadomość WM_CLOSE do aplikacji GUI. Dla aplikacji konsolowych utworzyłem je, dołączając strumienie wejściowe i wyjściowe do głównej aplikacji i kiedy chciałem je zakończyć, właśnie zamknąłem strumień wejściowy. Jeśli chodzi o dzieci dzieci itp., Polegałem na moich bezpośrednich dzieciach, aby oczyścić ich zależności :). –

Odpowiedz

9

Chyba jestem trochę późno na to pytanie, ale będę pisać coś w każdym razie dla każdego, mającego ten sam problem.

Mój problem jest podobny, że chciałbym być moja aplikacja aplikacja GUI, ale procesy realizowane powinny być uruchamiane w tle bez okna konsoli interaktywnej załączeniu.

udało mi się rozwiązać przy użyciu GenerateConsoleCtrlEvent(). Trudną częścią jest po prostu to, że dokumentacja nie jest dokładnie jasna, w jaki sposób można z niej korzystać i jakie są pułapki.

Moje rozwiązanie opiera się na tym, co zostało opisane here. Ale to też nie wyjaśniło wszystkich szczegółów, więc tutaj są szczegóły, jak sprawić, żeby działało.

  1. 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ć proces "środkowego człowieka" lub GenerateConsoleCtrlEvent() zawiedzie.

  2. użyć jakiegoś mechanizmu IPC do komunikowania się z rodzicem do procesu pomocnika że pomocnik powinien zamknąć proces potomny. Gdy pomocnik dostaje to zdarzenie, wywołuje funkcję "GenerateConsoleCtrlEvent (CTRL_BREAK, 0)", która zamyka się i proces potomny. Sam użyłem obiektu zdarzenia, który rodzic kończy, gdy chce anulować proces potomny.

Aby utworzyć plik Helper.exe, utwórz go za pomocą CREATE_NO_WINDOW i CREATE_NEW_PROCESS_GROUP. Podczas tworzenia procesu potomnego utwórz go bez flag (0), co oznacza, że ​​wyprowadzi konsolę z jej elementu nadrzędnego. Niewykonanie tej czynności spowoduje ignorowanie zdarzenia.

Bardzo ważne jest, aby każdy krok został wykonany 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ż oba będą wywoływać ExitProcess() na końcu.

Nie można też nazwać GenerateConsoleCtrlEvent() z identyfikatorem procesu groupd z identyfikatorem procesu dziecko bezpośrednio umożliwiającym proces pomocnika dalej żyć. To również się nie powiedzie.

Spędziłem cały dzień próbuje dostać tę pracę. To rozwiązanie działa dla mnie, ale jeśli ktoś ma cokolwiek dodać, proszę. Poszukałem wszystkich innych osób, które znalazły wiele osób z podobnymi problemami, ale nie znalazłem jednoznacznego rozwiązania problemu. Jak działa GenerateConsoleCtrlEvent() jest również trochę dziwne, więc jeśli ktoś wie więcej szczegółów na ten temat, prosimy o udostępnienie.

+3

Należy pamiętać, że nie ma gwarancji, że procesy B lub C zostaną całkowicie usunięte po odebraniu Ctrl + C. –

+0

Chociaż nie ma gwarancji abritrary aplikacja odpowie na Ctrl + C, jeśli jest podane, że aplikacja docelowa jest w rzeczywistości znanej zakończyć czysto w odpowiedzi na Ctrl + C, to ważne jest, aby wiedzieć na temat tej metody, które mogą powodować dowolna taka znana aplikacja do czystego zakończenia. – Triynko

+0

Przyjęty odpowiedź powinna być jednym z @KindDragon –

8

Jak @Shakta powiedział GenerateConsoleCtrlEvent() jest bardzo trudne, ale można wysłać Ctrl + C bez procesu pomocnika.

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 
} 
+0

To był bardzo pomocny! Brakuje tylko jednego - trzeba zadzwonić FreeConsole przed użyciem AttachConsole, inaczej dostaniesz ERROR_ACCESS_DENIED (5), ponieważ proces wywołujący jest już podłączona do konsoli. – Yael

+0

To jest jedyna odpowiedź na kilkanaście pytań, które odniosły JAKIEKOLWIEK sukcesy dla mnie, dziękuję! –

Powiązane problemy