[WinAPI] Cum aflu daca o aplicatie ramane "agatata"?

Folosire Windows API in programe C/C++ (forum moderat)
Post Reply
User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3778
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi
Contact:

[WinAPI] Cum aflu daca o aplicatie ramane "agatata"?

Post by Ovidiu Cucu » 28 May 2008, 17:40

Problema
Exista posibilitatea ca o aplicatie, dupa un timp mai lung de functionare sa ramana "agatata" si sa nu-si mai faca treaba. Posibile cauze ar fi greseli de programare cum ar fi bucle infinite, alocari de resurse fara dezalocarile corespunzatoare, etc. In acest caz ar fi bine sa se ia masuri cum ar fi in primul rand semnalarea problemei.
Cum s-ar putea rezova acest lucru prin program?

Rezolvare
Cea mai usoara metoda este sa folosim functia IsHungAppWindow.
Aceasta intoarce non-zero daca aplicatia respectiva nu asteapta input si nu a apelat PeekMessage in ultimile 5 secunde.
S-ar parea ca IsHungAppWindow este folosita si in Task Manager.
Task Manager (Windows XP).gif
Task Manager (Windows XP).gif (17.24 KiB) Viewed 2543 times
Exemplu 1

Code: Select all

DWORD CALLBACK ApplicationWatchDogThread(LPVOID pParam)
{
   DWORD dwRetCode = 0;
   HWND hWnd = (HWND)pParam;
   while(true)
   {
      if(::IsHungAppWindow(hWnd))
      {
         // signal "application hung".
         break;
      }
      else
      {
         DWORD dwError = ::GetLastError();
         if(dwError)
         {
            // error; for example, the window (no longer) exists.
            dwRetCode = dwError; 
            break;
         }
      }
   }
   return dwRetCode;
}
O metoda alternativa (mult trambitata pe toate canalele) ar fi trimiterea unui mesaj WM_NULL folosind functia API SendMessageTimeout.
In exemplul de mai jos se semnaleaza o aplicatie ca "agatata" daca nu proceseaza WM_NULL timp de 20 secunde.

Exemplu 2

Code: Select all

DWORD CALLBACK ApplicationWatchDogThread(LPVOID pParam)
{
   HWND hWnd = (HWND)pParam;
   DWORD dwResult = 0;
   while(true)
   {
      ::SetLastError(0); // just in case
      DWORD dwStart = ::GetTickCount();
      LRESULT lRet = ::SendMessageTimeout(hWnd, WM_NULL, 0, 0, SMTO_NORMAL,
                                          20000, &dwResult);
      DWORD dwEnd = ::GetTickCount();
      if((dwEnd - dwStart) >= 20000)
      {
         // signal "application hung".
         break;
      }
      else 
      {
         ::Sleep(500);
      }
   }
   return 0;
}
Nota
IsHungAppWindow face parte din categoria "documented but not recomended" (vezi MSDN).
Totusi (cel putin pe Windows XP, unde am testat) functioneaza si este absolut OK pentru supravegheat aplicatii care pot fi considerate "agatate" daca nu raspund mai mult de 5 secunde.


<< Back to Windows API Index



Post Reply