How To Detect All Program Terminations (125689)



The information in this article applies to:

  • Microsoft Win32 Application Programming Interface (API), when used with:
    • the operating system: Microsoft Windows 95
    • the operating system: Microsoft Windows 98
    • the operating system: Microsoft Windows Millennium Edition

This article was previously published under Q125689

SUMMARY

The processes for detecting program terminations fall into two categories:

  • Win32 processes use one of the Wait Functions, WaitForSingleObject(), MsgWaitForMultipleObjects(), etc., to wait for other Win32 processes, Windows 16-bit processes, and MS-DOS-based applications to terminate.
  • Windows 16-bit processes, on the other hand, must use the TOOLHELP NotifyRegister() function. The 16-bit processes can be notified when other 16-bit processes and MS-DOS-based applications exit, but have the limitation of not being notified of Win32 process activity.

MORE INFORMATION

Win32 processes can use one of the Wait functions to wait for a spawned process. By using CreateProcess() to launch a Win32 process, 16-bit process, or MS-DOS-based application, you can fill in a PROCESS_INFORMATION structure. The hProcess field of this structure can be used to wait until the spawned process terminates. For example, the following code spawns a process and waits for its termination:
 PROCESS_INFORMATION ProcessInfo;
  STARTUPINFO StartupInfo = {0};
  StartupInfo.cb = sizeof(STARTUPINFO);
  if (CreateProcess(NULL, szCommandLine, NULL, NULL, FALSE,
        0, NULL, NULL, &StartupInfo, &ProcessInfo))
   {
       WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
       /* Process has terminated */ 
       ...
   }
   else
   {
       /* Process could not be started */ 
       ...
   }

				
If necessary, you can put this code into a separate thread to allow the initial thread to continue to execute.

NOTE: For a discussion of how the NTVDM WOW architecture may influence waiting on 16-bit applications, please see the following article in the Microsoft Knowledge Base:

105676 Starting and Terminating Windows-based Application

This synchronization method is not available to 16-bit processes. Instead, they must use the TOOLHELP NotifyRegister function to register a callback function to be called when a program terminates. This method will detect the termination of 16-bit processes and MS-DOS-based applications, but not Win32 processes.

The following code shows how to register a callback function with NotifyRegister():
   FARPROC lpfnCallback;

   lpfnCallback = MakeProcInstance(NotifyRegisterCallback, ghInst);
   if (!NotifyRegister(NULL, (LPFNNOTIFYCALLBACK)lpfnCallback,
                       NF_NORMAL))
   {
      MessageBox(NULL, "NotifyRegister Failed", "Error", MB_OK);
      FreeProcInstance(lpfnCallback);
   }
				
The next section of code demonstrates the implementation of the callback function:
   BOOL FAR PASCAL __export NotifyRegisterCallback (WORD wID,
                                                    DWORD dwData)
   {
      HTASK hTask;  // task that called the notification callback
      TASKENTRY te;

      // Check for task exiting
      switch (wID)
      {
         case NFY_EXITTASK:
            // Obtain info about the task that is terminating
            hTask = GetCurrentTask();
            te.dwSize = sizeof(TASKENTRY);
            TaskFindHandle(&te, hTask);

            // Check if the task that is terminating is our child task.
            // Also check if the hInstance of the task that is
            // terminating is the same as the hInstance of the task
            // that was WinExec'd by us earlier in the program.

            if (te.hTaskParent == ghtaskParent &&
                te.hInst == ghInstChild)
                PostMessage(ghwnd, WM_USER+509, (WORD)te.hInst, dwData);
            break;

         default:
            break;
      }
      // Pass notification to other callback functions
      return FALSE;
   }
				
The NotifyRegisterCallback() API is called by the 16-bit TOOLHELP DLL in the context of the process that is causing the event. Problems arising because of reentrancy and notification chaining makes the callback function subject to certain restrictions. For example, operations that cause TOOLHELP events cannot be done in the callback function. (See the TOOLHELP NotifyRegister function documentation in your Software Development Kit for events that cause TOOLHELP callbacks.)

There is no way a 16-bit process can be notified when a Win32 process exits. However, a 16-bit process can use TaskFirst() and TaskNext() to periodically walk the task list to determine if a Win32 process is still executing. This technique also works for 16-bit processes and MS-DOS-based applications. For example, the following code shows how to check for the existence of a process:
  BOOL StillExecuting(HINSTANCE hAppInstance)
   {
      TASKENTRY  te = {0};

      te.dwSize = sizeof(te);
      if (TaskFirst(&te))
          do
          {
             if (te.hInstance == hAppInstance)
                return TRUE;      // process found
          } while (TaskNext(&te));

      // process not found
      return FALSE;
   }
				
Refer to the TermWait sample for complete details on how to use NotifyRegister and implement a callback function. For additional information, please search in the Microsoft Knowledge Base using this word:

TERMWAIT


Modification Type:MinorLast Reviewed:9/27/2004
Keywords:kbcode kbhowto kbKernBase kbProgramming kbThread KB125689