Suppose I run an application, after some time this app will get closed by user. Is it possible to find out when the program exits? Can I get it\'s process id when I run that
In a quick search at google I found these two methods from msdn which can be useful:
CreateProcess and GetExitCodeProcess. This assuming you are creating a process within your application.
You can do a polling method checking the created process status. I never did this kind of thing, but seems a very strange approach to me.
CreateProcess and WaitForSingleObject is the simple way to achieve this: you get the process handle from CreateProcess, then wait for it with WFSO, not forgetting to close any handles you use. But wait... there's a problem. The problem is that - for GUI processes - both processes can hang. Why?
The problem arises because your application has a window but isn't pumping messages. If the spawned application invokes SendMessage with one of the broadcast targets (HWND_BROADCAST
or HWND_TOPMOST
), then the SendMessage won't return to the new application until all applications have handled the message - but your app can't handle the message because it isn't pumping messages.... so the new app locks up, so your wait never succeeds.... DEADLOCK.
If you have absolute control over the spawned application, then there are measures you can take, such as using SendMessageTimeout rather than SendMessage (e.g. for DDE initiations, if anybody is still using that). But there are situations which cause implicit SendMessage broadcasts over which you have no control, such as using the SetSysColors API for instance.
The only safe ways round this are (a) split off the Wait into a separate thread, (b) use a timeout on the Wait and use PeekMessage in your Wait loop to ensure that you pump messages, (c) use the MsgWaitForMultipleObjects API instead of WaitForSingleObject.
At least on Windows, there is some (underused?) C Runtime Library Functionality available for this. See C Run-Time Library Reference > Process and Environment Control.
Specifically, you have _spawnlp(_P_WAIT, cmdname, arg0, ..., argn, 0)
("spawn with argument list, using path variable to locate file") which searches cmdname in PATH and in the current directory.
Note that "Following argn, there must be a NULL pointer to mark the end of the argument list."
E.g.
#include <stdio.h>
#include <process.h>
int main() {
puts("waiting");
_spawnlp(_P_WAIT, "mspaint.exe", "mspaint.exe", 0);
puts("returned");
}
On Windows you can use WaitForSingleObject to implement this functionality.
This is a quote from here:
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <conio.h>
void _tmain( int argc, TCHAR *argv[] )
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
STARTUPINFO sj;
PROCESS_INFORMATION pj;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
ZeroMemory( &sj, sizeof(sj) );
sj.cb = sizeof(sj);
ZeroMemory( &pj, sizeof(pj) );
// Start the child process p1.exe. Make sure p1.exe is in the
// same folder as current application. Otherwise write the full path in first argument.
if(!CreateProcess(L".\\p1.exe", NULL, NULL, NULL, FALSE, 0, NULL, NULL, &sj, &pj))
{
printf( "Hello CreateProcess failed (%d)\n", GetLastError() );
getch();
return;
}
// Start child process p2.exe. Make sure p2.exe is in the
// same folder as current application. Otherwise write the full path in first argument.
if(!CreateProcess(L".\\p2.exe", NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
{
printf( "CreateProcess2 failed (%d)\n", GetLastError() );
getch();
return;
}
// Wait until child processes exit.
WaitForSingleObject( pi.hProcess, INFINITE );
WaitForSingleObject( pj.hProcess, INFINITE );
// Close process and thread handles.
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
CloseHandle( pj.hProcess );
CloseHandle( pj.hThread );
getch();
}
I would like to mention that you don't have to actually create a process, in order to be able to wait for its termination. Basically, if you know its PID, you can do this:
HANDLE h = OpenProcess(SYNCHRONIZE, TRUE, pid);
WaitForSingleObject(h, INFINITE );
Full example: https://gist.github.com/rdp/6b5fc8993089ee12b44d (leave a comment here if you'd like a compiled version made available).