How to emulate the WinNT Task Manager?

I am writing a watchdog app which will monitor/stop/start other apps. I am able to retrieve pids for each app and CreateProcess if it has stopped running. I am able to TerminateProcess if need be. But I can not figure out how to communicate with the app in order to determine if the app is ' running' or 'not responding' (as seen with the Task Manager). I do not know if ::SendMessage() or PostMessage() is the way to go. I do have a process handle but I do not know how to get its corresponding Window handle( hWND) as needed by SendMessage() and PostMessage().  IPC? Too much work right now. Any suggestions?
Who is Participating?
chensuConnect With a Mentor Commented:
Grade this answer so that we can complete it.

Thank you.
Please take a look at the following KB article. I think it is what you need.
domenicAuthor Commented:
KB Q175030 tells you how to retrieve pids. How do you get the process' state?
The 14th Annual Expert Award Winners

The results are in! Meet the top members of our 2017 Expert Awards. Congratulations to all who qualified!

Use EnumWindows and SendMessageTimeout functions.
To get process status, you need to use Performance Data Helper:
Platform,SDK and DDK Documentation -> Platform SDK -> Windows BaseServices -> General Library -> Performance Data Helper.
Or use The Registry Interface directely.
Fortunately, there is someone already made an example. It is easier to understand and modify to fit for your usage:
Good luck.
domenicAuthor Commented:
Trestan your link displayed a valid example of determining what pids are active out there using the Registry. I am using the PSAPI calls to get me the same information with less code. However, I am interested in determining a full proof method of knowing when a process/app is in a 'not responding' state. I think Chensu has given me a clue on how to get a window handle to the process and send it a health message. Maybe we can elaborate more on this method.
OK. Use EnumWindows to enumerate all the top-level windows and call GetWindowThreadProcessId to determine to which the process belongs. Call SendMessageTimeout with a time-out period, if it fails or time out, the window may be not responding.
domenicAuthor Commented:
EnumWindows. What does it really do?!! Here is what I have so far.
Let us go over my objective - Make sure that a certain process is actually running.

EnumProcesses - gets me all pids
OpenProcess, EnumProcessModules, GetModuleFileName tells me that my.exe = this_pid

// this_pid is confirmed with the Task Manager as truly being my.exe's pid.

Here's my code:

EnumWindows( (WNDENUMPROC)CheckForResponse,                                 (LPARAM) this_pid );
                         result=WaitForSingleObject(hProcess, 20000);
if( result == WAIT_TIMEOUT )
     ProcessStatus = _T("Not Responding");
else if( result == WAIT_OBJECT_0 )
     ProcessStatus = _T("Running");
else if( result == WAIT_FAILED )
     CString ErrStr;
     ErrStr.Format( "Error=%d", GetLastError );
    AfxMessageBox( ErrStr);
BOOL CALLBACK CheckForResponse( HWND hwnd, LPARAM lParam )
      DWORD dwID;
      DWORD result;
      char ProcTitle[MAX_PATH];
                     CString Str;
      dwID = 0;
      result = GetWindowThreadProcessId( hwnd, &dwID );

      if( dwID == (DWORD)lParam )
                          // Oddly enough I get three matches for this_pid
                          // I get a window called OleMainThreadWndName
                          // I get a window with no name
                         // and I get what I expect - my.exe

           ZeroMemory( ProcTitle, MAX_PATH );
           GetWindowText( hwnd, ProcTitle, MAX_PATH );
                           Str.Format( "%s", ProcTitle );

                         // because of these three matches I get the one I
                         // really want
                          if( Str.Find( "my.exe" )  != -1 )
                                //Send it any message??
                  PostMessage( hwnd, WM_TIMER, 0, 0 );
                                //No more enumerations
                 return FALSE;
      return TRUE;

The problems I encounter are:

1. Why are there 3 matches to the pid?
2. The process gets the WM_TIMER message but WaitForSIngleObject always times out, therefore I incorrectly label it "Not Responding"
3. What use is the return value of GetWindowThreadProcessID() ?

I have tried using WM_CLOSE and it is successful but I do not want to terminate my process unneccessarily.

1. I don't understand.
2. A process object's state is signaled only when the process terminates.
3. The return value is the identifier of the thread that created the window.
domenicAuthor Commented:

Let me re-iterate problem 1. GetWindowProcessId() returns 3 hwnds with the same pid. I used GetWindowText() to see what these windows are. As I stated before, I get a window "OleMainThreadWndName", "", and "My.exe". I am confused why there are other windows associated with the pid.

Re:2. A process object's state is signaled only when the process terminates.
Are you saying that WaitForSingleObject() returns successfully only when a process objects's state terminates? Should I then send a message back to the watchdog process? Or use the SendMessageTimeout()? I have used it but I am skeptical. If SendMessageTimeout() returns TRUE is it safe to assume that the process is responding?
1. It is possible because some processes/threads (especifially system threads) may create more than one top-level window.

2. >Are you saying that WaitForSingleObject() returns successfully only when a process objects's state terminates?
In your case WaitForSingleObject(hProcess, 20000), the function succeeds only when the process terminates (WAIT_OBJECT_0) or time out (WAIT_TIMEOUT).
>If SendMessageTimeout() returns TRUE is it safe to assume that the process is responding?
Yes. Because "The function calls the window procedure for the specified window and, if the specified window belongs to a different thread, does not return until the window procedure has processed the message or the specified time-out period has elapsed.".
To clarify what Chensu has said:

WaitForSingleObject(), when called on a process, waits for the process to terminate.

SendMessageTimeout() is an imperfect solution, but it's the best you can do using the general Win32 API (meaning that it's the best thing that will work with Win95). If you receive a TRUE before the timeout, the process is definitely responding (well, it's at least responding to some messages; I suppose if the app dispatches different messages to different threads and one or more of those threads are hung you might not find that out, but this is Windows, not BeOS, so I don't think you'll see a problem).

If problem is, if you receive FALSE, it doesn't necessarily mean the process isn't responding. If could just be doing something slow. Or blocking on user input (e.g. Outlook '97's "Please close Outlook by logging out" message). Of course the longer you wait, the more sure you can be that the process really is dead, but you can never be 100% sure (especially with apps like Outlook--my recommendation is just to kill Outlook whenever you see it :-) This is why Win95 itself is so bad at distinguishing dead processes.

As far as the WM_CLOSE solution, well, I suppose that has a use. If the message doesn't respond to WM_CLOSE it's presumed frozen, so you explicitly kill it. The problem is, if the app wasn't frozen, it'll be closed now. It's sort of like an old-fashioned witch trial--toss her in the water; if she floats she's guilty and we can kill her; if she drowns she was innocent...

There may be a better solution that's NT-specific (the NT task manager certainly seems to be better at detecting frozen apps that the 95 equivalent, although it seems to miss windowless zombie processes even more often), but I don't know what it is off the top of my head.

Probably the NT 6.0 task manager will be automatable...

domenicAuthor Commented:
Payn, thanks for the information. I just wanted to add that I am writing on a NT platform. For now I am using SendMessageTimeout() and thanks to Chensu it does perform satisfactory. In the future I will investigate IPC Messaging ( like Unix - good ol' days).

About Experts Exchange .....
When we  are satisfied with the expert's answer how do we complete it?
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.