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: