Pentru a închide ușor aplicația, lăsându-o să se curețe, trebuie să trimitem mesajul WM_CLOSE la toate ferestrele vizibile la nivel de nivel superior deținute de aplicație. Trimiterea unui mesaj WM_CLOSE este echivalentă cu comanda Close din meniul de sistem al ferestrei. Dacă aplicația este scrisă corect, va elibera resurse și va fi completată. Trebuie să fim pregătiți pentru faptul că procesul de finalizare poate fi amânat. De exemplu, o aplicație poate cere utilizatorului dacă doresc să salveze fișierele modificate. Dacă aplicația nu se termină într-o perioadă rezonabilă de timp, nu vom mai rămâne decât să aplicăm "artileria grea" - funcția TerminateProcess.
Pentru a asigura o flexibilitate maximă în organizarea așteptărilor, am decis să scriem funcția de a opri aplicarea în conformitate cu următorul prototip.
Parametrul hWnd identifică aplicația pe care dorim să o terminăm, poate fi orice fereastră deținută de aplicație. Parametrul pfnWaitCallback specifică o funcție definită de utilizator care va fi apelată periodic în timpul așteptării. Programul poate folosi această funcție pentru a procesa mesaje în timp ce funcția așteaptă ca procesul să se termine. În plus, funcția definită de utilizator determină când este suficient să așteptați și este timpul să aplicați forța brute: valoarea returnată a funcției determină comportamentul ulterior al KillApplication.
Finalizați imediat procesul cu TerminateProcess
În primul rând, funcția definește procesele și identificatorii de flux la care face parte fereastra specificată - le vom folosi ulterior pentru a identifica aplicația care urmează să fie oprită. Funcția apoi verifică dacă fereastra specificată aparține sarcinii pe 16 biți din Windows NT. Sarcinile pe 16 biți necesită procesare specială și le vom examina separat.
În cazul cu 32 de biți, funcția deschide mânerul procesului cu drepturi de acces SYNCHRONIZE și PROCESS_TERMINATE. Dacă nu avem astfel de drepturi cu privire la procesul care urmează a fi reziliat, funcția se termină imediat cu o eroare. Apoi, funcția trimite mesajul WM_CLOSE la toate ferestrele de nivel superior care aparțin acestui proces, pentru care folosim EnumWindows. specificând KillAppEnumWindows ca funcție de enumerare. al cărui text este prezentat mai jos.
După expedierea mesajelor, funcția intră în bucla de așteptare. La fiecare 100 milisecunde, aceasta numește o funcție definită de utilizator, oferindu-i posibilitatea de a procesa mesajele acumulate și de a decide dacă să aștepte. Ciclul se produce Out se întâmplă atunci când unul dintre cele două evenimente: procesul este complet și se întoarce WaitForSingleObject WAIT_OBJECT_0, sau o funcție definită de utilizator returnează o valoare diferită de KILLAPP_WAIT. Dacă valoarea returnată a funcției utilizatorul a fost KILLAPP_TERMINATE, atunci procesul este terminat forțat prin TerminateProcess.
După cum am menționat deja, sarcinile pe 16 biți sunt tratate într-un mod special. Diferența principală dintre sarcinile pe 32 de biți pentru noi este că mai multe sarcini pe 16 biți pot partaja un proces WOW VDM, deci logica pe care am folosit-o pentru a completa aplicațiile pe 32 de biți este inadecvată. În primul rând, aici este codul funcției IsWOWProcess. care se utilizează pentru a distinge între sarcinile pe 16 biți:
IsWOWProcess listează toate mașinile virtuale WAN DOS utilizând funcția VDMEnumProcessWOW din VDMDBG.DLL. Dacă fereastra specificată ca parametru KillApplication. face parte din unul dintre aceste procese, deci avem de-a face cu o sarcină de 16 biți.
Pentru obiectivele de 16-biți, și noi trimitem mesaje WM_CLOSE la toate ferestrele de nivel superior a acestei probleme, dar acum nu ne concentrăm pe ID-ul de proces, și prin ID Flow, deoarece procesul de virtuale DOS mașinile pot conține mai multe sarcini de 16 biți, fiecare dintre acestea se realizează în fluxul său. Pentru a trimite WM_CLOSE vom folosi EnumWindows KillAppEnumWindows16 pentru a funcționa ca o funcție de transfer:
În cazul sarcinilor pe 16 biți, nu putem folosi mânerul de proces pentru a aștepta finalizarea sarcinii, deoarece procesul procesului mașinii virtuale DOS poate să nu se încheie dacă alte activități rămân în ea. Pentru a determina finalizarea sarcinii, folosim funcția IsWOWTask. care ca efect secundar returnează ID-ul sarcinii.
IsWOWTask se bazează pe funcția VDMEnumTaskWOW. exportate din VDMDBG.DLL, care a fost discutată în articolul Cum să listați sarcinile pe 16 biți în Windows NT ?.
Ca și în cazul aplicațiilor pe 32 de biți, numim o funcție definită de utilizator cu un interval de 100 de milisecunde. Dacă funcția definită de utilizator decide să înceteze sarcina cu forța, sunăm la funcția TerminateWOWTask. care nu este altceva decât o învelire în jurul VDMTerminateTaskWOW.
În concluzie, luați în considerare mai multe opțiuni pentru implementarea unei funcții personalizate pentru utilizarea cu KillApplication. Prima versiune a funcției implementează așteptarea cu un timeout fix:
Se presupune că parametrul lParam pentru KillApplication va fi momentul de așteptare. De exemplu, un astfel de apel va duce la o așteptare de 15 secunde:
O versiune mai complexă a funcției definite de utilizator, prezentată mai jos, procesează mesajele în așteptare, astfel încât funcția poate fi apelată direct în firul UI fără teama de blocare:
O variantă și mai complicată care procesează mesajele și afișează un dialog după 15 secunde de așteptare se găsește în codul sursă al aplicației demonstrative Process Viewer care însoțește acest articol.
- Q178893 HOWTO: Terminați o aplicație "curat" în Win32. Baza de cunoștințe Microsoft.