Introduction
While I was creating an app that has the capability of starting a process, and then be able to kill it later on, I looked all over the net, and found some crazy ways of doing this. Searching, searching, searching, for a couple days, I did nothing but try to locate info on setting this up correctly (Since I never tried doing this before). Most of them I could not get to work, in their entirety, as they were written. I finally found a way that worked, without too much mish-mash. What is here, is a conglomerate of all. And needless to say, the simplest way was the key. I am sure there are better ways of doing this, but this way works for this application.
Please note that some of the techniques used in this article are based on the article Sending a message to the Main Frame Window of Another Application, given only the Process Handle by Martin-Pierre Frenette.
The basic method used is to start a process, store its process ID, and then when it comes time to kill the process, you enumerate all open windows and close the window that is associated with your process ID.
TerminateProcess()
is easier, but doesn't unload the DLLs from memory, which means it doesn't let the DLLs know the process is terminated, and leaves them floating around in memory, lost, causing problems. It should only be used in worst-case situations. system()
, WinExec()
, ShellExecute()
, and ShellExecueEx()
are easier, but you don't get as much information about the process being started. Since CreateProcess()
is very powerful, and seems rather intimidating at first, I decided to write this little article.
PostMessage()
needs a window handle to send WM_CLOSE
, so we have to use EnumWindows()
to ramble through the windows, checking to see if our PID is the same. If it is, we have a match, and have the window handle to send it.
In CSomeDlg.h
static BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam);
DWORD processPid;
In CSomeDlg.cpp
void CSomeDlg::startProcess()
{
BOOL bWorked;
STARTUPINFO suInfo;
PROCESS_INFORMATION procInfo;
CString m_Process = "C:\\wherever\\process\\we\\want\\to\\start.exe";
char *vip = "C:\\wherever\\process\\we\\want\\to\\start.exe "
"whatever command line arguments here";
memset (&suInfo, 0, sizeof(suInfo));
suInfo.cb = sizeof(suInfo);
bWorked = ::CreateProcess(m_Process,
vip,
NULL,
NULL,
FALSE,
NORMAL_PRIORITY_CLASS,
NULL,
NULL,
&suInfo,
&procInfo);
if (procInfo.dwThreadId = NULL)
{
MessageBox("nope");
}
playerPid = procInfo.dwProcessId;
}
void CSomeDlg::killProcess()
{
HANDLE ps = OpenProcess( SYNCHRONIZE|PROCESS_TERMINATE,
FALSE, processPid);
EnumWindows(EnumWindowsProc, processPid);
CloseHandle(ps) ;
}
BOOL CALLBACK CSomeDlg::EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
DWORD wndPid;
CString Title;
GetWindowThreadProcessId(hwnd, &wndPid);
CWnd::FromHandle( hwnd )->GetWindowText(Title);
if ( wndPid == (DWORD)lParam && Title.GetLength() != 0)
{
::PostMessage(hwnd, WM_CLOSE, 0, 0);
return false;
}
else
{
return true;
}
}