Autor Wątek: Jaki komunikat (zdarzenie) podczas killowania aplikacji?  (Przeczytany 7876 razy)

Offline Yazilim

  • Użytkownik

# Grudzień 10, 2011, 16:08:52
Witam!

Muszę przechwycić aplikację (jest to aplikacja bez okna, ma tylko wyświetlaną ikonkę w tray'u) podczas jej zamykania. Ponieważ nie ma ona okna, nie będzie wysyłany komunikat WM_CLOSE podczas jej zamykania. Zamykanie aplikacji może mieć miejsce na przykład podczas wylogowywania się użytkownika z komputera. Niestety próba przechwycenia komunikatu WM_QUIT nie powiodła  się - okazuje się, że ten komunikat nie jest wysyłany. Czy można więc w jakiś inny sposób przechwycić taką aplikację podczas jej wymuszonego zamykania? Jakie zdarzenie pojawia się wtedy w procedurze okna, które można by obsłużyć?

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline MaxGarden

  • Użytkownik
    • Profil na warsztacie

# Grudzień 10, 2011, 16:11:35
Spróbuj z WM_DESTROY.

Offline Yazilim

  • Użytkownik

# Grudzień 10, 2011, 16:27:08
Spróbuj z WM_DESTROY.
Niestety, też nie da się WM_DESTROY przechwycić. Wygląda, jakby Windows natychmiast killował aplikację bez możliwości przechwycenia tego procesu w procedurze okna.

Offline MaxGarden

  • Użytkownik
    • Profil na warsztacie

# Grudzień 10, 2011, 16:33:10
Zapewne jest łatwiejsza/lepsza metoda, ale możesz założyć hooka wtedy przechwytujesz wszystkie zdarzenia systemu (oprócz CTRL+ALT+DLT [chyba]).

Offline Xirdus

  • Redaktor

# Grudzień 10, 2011, 16:38:38
A process cannot prevent itself from being terminated.

Chyba że zrobisz DLL Injection. Osobiście nie polecam.

Offline Rolek

  • Użytkownik

# Grudzień 10, 2011, 17:09:53
Aby miec ikonkę w tryu trzeba mieć okieno(może być niewidoczne ale musi być).
WM_CLOSE informuje, że został kliknięty krzyżyk do zamykania okna(lub została wybrana opcja Zamknij z standardowego menu kontekstowego), standardową reakcją jest zniszczenie okna.
WM_DESTROY informuje, że okno jest niszczone (a właściwie jego obszar klienta jest niszczony, do pary mamy WM_NCDESTROY), nie ma standardiwej reakcji ale jeśli było to okno główne to aplikacje często wywołują PostQuitMessage do wysłania WM_QUIT.
WM_QUIT nie jest wysyłany do procedury okna tylko obsługiwany w pętli komunikatów, aplikacja może go zignorować.
Gdy ubijasz proces przez TerminateProcess (np. Menedżerem zadań) to system nie powiadamia o tym aplikacji tylko usuwa proces i zwalnia używane przez niego zasoby.

Offline Yazilim

  • Użytkownik

# Grudzień 10, 2011, 17:53:31
Gdy ubijasz proces przez TerminateProcess (np. Menedżerem zadań) to system nie powiadamia o tym aplikacji tylko usuwa proces i zwalnia używane przez niego zasoby.
Czyli prawdopodobnie wylogowanie użytkownika wywołuje TerminateProcess i dlatego nie mogę tego obsłużyć.

Offline Furry

  • Użytkownik
    • DevBlog

# Grudzień 11, 2011, 11:03:06
Co do wylogowywania to się dzieje tak, że aplikacji ma określony czas na WM_Destroy( albo Quit - nie pamiętam dokładnie), a później jest killowana. Tak wynika z moich obserwacji(na winXp mam taką aplikację napisaną i przechwytuje któreś z tych zdarzeń przy wyłączaniu).
Więc jeśli zapis długo trwa to pozostaje ci zrobienie timera zapisującego stan aplikacji albo czego tam masz
« Ostatnia zmiana: Grudzień 11, 2011, 11:05:46 wysłana przez Furry »

Offline Xender

  • Użytkownik

# Grudzień 11, 2011, 12:46:46
Ech, aplikacja może nawet zapytać użytkownika o anulowanie zamykania całego systemu czy wylogowania - spróbujcie wylogować się gdy macie otwarty notatnik z niezapisanym plikiem - gdy kliknie się "anuluj" logout zostanie przerwany. W wypadku aplikacji które nie chcą się same zamknąć często pojawia się okienko takie jak przy normalnym zamykaniu programu który nie odpowiada. [Wszystko powyżej odnosi się do XP, nowszych nie sprawdzałem] Więc nawet jeśli system killuje procesy przy wylogowaniu to jest to raczej sytuacja ostateczna, a sposó na przechwycenie tego istnieje.

Offline Yazilim

  • Użytkownik

# Grudzień 11, 2011, 14:26:14
Więc jeśli zapis długo trwa to pozostaje ci zrobienie timera zapisującego stan aplikacji albo czego tam masz
Timer nic nie pomoże, bo w momencie zamykania aplikacji muszę dać znać do serwera, że jej działanie się kończy i ustawić w nim pewne flagi. Czyli mogę to zrobić wyłącznie w momencie, kiedy rozpoznam, że aplikacja jest zamykana.

Offline Rolek

  • Użytkownik

# Grudzień 11, 2011, 14:49:48
W momencie wydania polecenia wylogowania, system wysyła WM_QUERYENDSESSION, jeśli nie masz nic przeciwko zwracasz TRUE, jeśli zwrócisz FALSE wylogowywanie zostanie przerwane. Po WM_QUERYENDSESSION następuje WM_ENDSESSION, które informuje czy wylogowywanie jest kontynuowane czy zostalo przerwane. Na obsługę tych wiadomości mamy limity czasowe więc trzeba się spieszyć, jeśli jakaś aplikacja się nie wyrobi to, w zależności od ustawień, wyświetlane jest okienko albo aplikacja jest z automatu ubijana.
« Ostatnia zmiana: Grudzień 11, 2011, 14:52:55 wysłana przez Rolek »

Offline Yazilim

  • Użytkownik

# Grudzień 12, 2011, 09:22:08
Myślałem, że WM_QUERYENDSESSION mi pomoże (nawet na stronie Microsoftu jest ładny przykład wykorzystania tego komunikatu w procedurze okna - http://msdn.microsoft.com/en-us/library/windows/desktop/aa376870%28v=vs.85%29.aspx), ale niestety dziwna rzecz, w mojej aplikacji ten komunikat nie jest odbierany. Może powodem tego jest to, że nie ma ona "prawdziwego" okna - zostało ono stworzone jako tzw. "message-only window" przy użyciu polecenia  SetParent(hWnd, HWND_MESSAGE). Dzięki temu jest domyślnie niewidoczne (choć ma procedurę okna) i wyświetla tylko ikonę w tray'u.

Offline Furry

  • Użytkownik
    • DevBlog

# Grudzień 12, 2011, 09:34:33
W momencie wydania polecenia wylogowania, system wysyła WM_QUERYENDSESSION, j... Po WM_QUERYENDSESSION następuje WM_ENDSESSION,
<facepalm> no jasne :) Sorry za pomyłkę z tym WM_DESTROY ^^

@Yazilim: to nie powinno mieć znaczenia. Ja mam aplikację która się nawet w trayu nie pokazuje i łapie ten komunikat. Może masz coś źle ustawione?

Offline Yazilim

  • Użytkownik

# Grudzień 12, 2011, 09:44:42
Ogólnie programik działa zgodnie z założeniami :) Procedura okna obsługuje poprawnie inne komunikaty, tylko coś nie może wychwycić WM_QUERYENDSESSION. Wkleiłem dokładnie kod z wcześniej zacytowanej strony MSDN Microsoftu, ale żadne okno z pytaniem o zamknięcie programu nie pojawiło się. Już prawdę mówiąc nie wiem, co tam może być nie tak...

Offline micran

  • Użytkownik
    • Micran - Warsztat

# Grudzień 12, 2011, 19:11:03
Aplikacje w Delphi zawsze niezależnie od tego czy mają okno czy nie potrafią wychwycić zamknięcie programu, więc na pewno jest możliwość chwytania odpowiedniego komunikatu w C. Są też wstawki asemblerowe, dzięki którym możesz "włamać się" do systemu operacyjnego i zczytywac z tamtąd CTRL+ALT+DEL i wszelkie inne kombinacje.
Jest też inny sposób przechwycisz w asemblerze przerwanie odpowiedzialne za zamykanie programu, podstawiając w to miejsce procedurę, która da komunikat aplikacji ze ma się zamknąć bezpiecznie, kiedy juz wszystko wyrobisz jak trzeba po prostu wstawiasz znow standardowe przerwanie i zamykasz program. Nie jestem pewien czy da się to wykonać, bo bawiłem się tym ostatnio na studiach w pascalu, ale skoro on dawał radę to C także da radę.
Szukaj także innych sposobów niż komunikaty, np. próbuj rejestrować nowe okna w windowsie ( gdzies poza ekranem), gdy windows sie wylacza/wylogowuje nie pozwala na tworzenie nowych okienek - wtedy wiesz ze trzeba kończyć.

P.S. A po co ci flagi w serwerze, jesli aplikacja sie komunikuje z nim, to nie lepiej wysyłać co 1 sekunde jakaś daną do serwera, a gdy serwer nie otrzyma tej danej przez 2-3 sekundy, automatycznie się przestawi ?
« Ostatnia zmiana: Grudzień 12, 2011, 19:13:33 wysłana przez micran »