Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to determine if app is really not responding as shown in Task Manager

My specific problem: I need to develop a watchdog app that needs to keep various applications running. I am using visual studio and a windows environment that supports .net 4.0 Since I am not creating those applications and I do not have access to modify them in any way I can only rely on the information provided by windows.

For the past week I've been trying to find exactly how to get the "not responding" property as shown in task manager for an application.

I have tried: 1 Using system diagnostics, getting the process information and interpreting the information within. The problem is, when an app stops working (crashes) the process is still running, the JIT Debugger message pops and reports the app crashed. At this particular moment Task Manager reports the app "Not responding" but the process information (although it does have a main window handle ) has the property Responding set to "true". I found a lot of open source task managers (top 5) and all use the "Responding" property to determine if a application is running. So the problem is : task manager shows not responding, Process property responding = True, this method to determine if an app is not responding is INVALID

2 Sending timeout messages to the main window handler. I used the SendMessageTimeout functions http://msdn.microsoft.com/en-us/library/windows/desktop/ms644952(v=vs.85).aspx *I used the SMTO_ABORTIFHUNG, SMTO_BLOCK, SMTO_NORMAL, SMTO_NOTIMEOUTIFNOTHUNG and SMTO_ERRORONEXIT And encountered the same problem: -before the application crashes: reports running ( all messages return 1) -after the application crashes (JIT debugger popup reports app crashed and displayed "Not Responding" in task manager) all the above messages sent to the process window handler return 1 . So this method to determine if app is not responding is also INVALID

I am amazed I haven't been able to find relevant resources related to my issue.

Here is some code from what I've tried:

bool IsResponding(Process process)
    {
        HandleRef handleRef = new HandleRef(process, process.MainWindowHandle);

        int timeout = 2000;
        IntPtr lpdwResult;

        IntPtr lResult = SendMessageTimeout(
            handleRef,
            0,
            IntPtr.Zero,
            IntPtr.Zero,
            1,
            1000,
            out lpdwResult);
        lResult = SendMessageTimeout(
            handleRef,
            0,
            IntPtr.Zero,
            IntPtr.Zero,
            2,
            1000,
            out lpdwResult);
        lResult = SendMessageTimeout(
           handleRef,
           0,
           IntPtr.Zero,
           IntPtr.Zero,
           0,
           1000,
           out lpdwResult);
        lResult = SendMessageTimeout(
           handleRef,
           0,
           IntPtr.Zero,
           IntPtr.Zero,
           8,
           1000,
           out lpdwResult);
        lResult = SendMessageTimeout(
           handleRef,
           0,
           IntPtr.Zero,
           IntPtr.Zero,
           20,
           1000,
           out lpdwResult);
        return lResult != IntPtr.Zero;
    }

and the testing part:

processes = Process.GetProcessesByName(Path.GetFileNameWithoutExtension("...testAppLocation.exe"));
                                bool test = processes[0].Responding;
 test =  asd.IsResponding(processes[0]);

I've run the sample in debug mode so I am sure all the messages return 1 as a value whether the actual application is running or it is crashed. And "processes[0]" was tested against a real process and does have the process information at runtime.

I am out of ideas and I still haven't figured out what resources Task manager uses to determine an application is "Not Responding".

The first solution, provided with the help of Hans Passant would look like this:

Functions to get active windows (including hung ):

   internal static class NativeMethods{
    [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool IsHungAppWindow(IntPtr hWnd);
        [DllImport("user32.dll")]
        static extern Int32 EnumWindows(EnumWindowsCallback lpEnumFunc, Int32 lParam);

        [DllImport("user32.dll")]
        public static extern void GetWindowText(IntPtr hWnd, StringBuilder lpString, Int32 nMaxCount);

        [DllImport("user32.dll")]
        static extern UInt64 GetWindowLongA(IntPtr hWnd, Int32 nIndex);

 public static readonly Int32 GWL_STYLE = -16;
        public static readonly UInt64 WS_VISIBLE = 0x10000000L;
        public static readonly UInt64 WS_BORDER = 0x00800000L;
        public static readonly UInt64 DESIRED_WS = WS_BORDER | WS_VISIBLE;

        public delegate Boolean EnumWindowsCallback(IntPtr hwnd, Int32 lParam);

        public static List<WindowWrapper> GetAllWindows()
        {
            List<WindowWrapper> windows = new List<WindowWrapper>();
            StringBuilder buffer = new StringBuilder(100);
            EnumWindows(delegate(IntPtr hwnd, Int32 lParam)
            {
                if ((GetWindowLongA(hwnd, GWL_STYLE) & DESIRED_WS) == DESIRED_WS)
                {
                    GetWindowText(hwnd, buffer, buffer.Capacity);
                    WindowWrapper wnd = new WindowWrapper();
                    wnd.handle = hwnd;
                    wnd.title = buffer.ToString();

                    windows.Add(wnd);
                }
                return true;
            }, 0);

            return windows;
        }

. . .

What I put in my is hung check-er function:
Note that for each app that is hung (JIT debugger pop-up saying it's not working) You will get 2 entries with the same window handler title: The app original window handler - which is taken over by the jit debugger will return false (that means it's not hung) while for the other entry -which is assigned a new IntPtr the IsHungAppWindow will return true

foreach (var wnd in NativeMethods.GetAllWindows())
                                {
                                    Console.WriteLine(wnd.title + " and status is " + IsHungAppWindow(wnd.Handle));




                                }

If anyone has other specific, tested solutions to this issue I would greatly appreciate them.

like image 862
user3049400 Avatar asked Nov 11 '22 17:11

user3049400


1 Answers

You'll need to pinvoke IsHungAppWindow(). It returns true when the window is replaced by the ghost window that displays "Not responding".

And keep in mind that this never means that the app crashed and not that often means that the app is actually hung. Certainly not on my pokey laptop when it tries to run VS2010+. Or most any Winforms or WPF app written by a programmer that hasn't yet mastered the art of threading. So don't just arbitrarily kill processes.

like image 117
Hans Passant Avatar answered Nov 15 '22 06:11

Hans Passant