Call to WaitForSingleObject not clear in combination with CreateProcess - c++

I came across the following code in a program that keeps track of processes:
void StartProcess(const std::wstring& processName, const CString& argument)
{
...
STARTUPINFO stInfo;
PROCESS_INFORMATION prInfo;
ZeroMemory( &stInfo, sizeof(stInfo) );
stInfo.cb = sizeof(stInfo);
stInfo.dwFlags=STARTF_USESHOWWINDOW;
stInfo.wShowWindow=SW_SHOWDEFAULT;
bRet = CreateProcess(NULL,
(LPTSTR)(LPCTSTR)sCmdline,
NULL,
NULL,
TRUE,
CREATE_NEW_CONSOLE | NORMAL_PRIORITY_CLASS,
NULL,
_T("."),
&stInfo,
&prInfo);
// Create process has gone OK and we have to wait.
if (bRet)
{
bRet = FALSE;
int nRetWait = WaitForSingleObject(prInfo.hProcess,0);
if (nRetWait == WAIT_OBJECT_0)
{
// Get the exit code of the process
DWORD dwExitCode = 0;
::GetExitCodeProcess(prInfo.hProcess, &dwExitCode);
if (0 == dwExitCode)
{
// The program succeeded
m_StartedServices.push_back(prInfo.dwProcessId;);
bRet = TRUE;
}
}
}
}
The code should start a process and then in a later stadium terminate it (using m_StartedServices). However I am wondering what added value the calls to WaitForSingleObject and GetExitCodeProcess have. I have looked around a bit and it seems that the WaitForSingleObject with a timeout of 0 is used to check if a process is still running, but it is just created, so why check? And why check the exit code of a process that is still running?
Can anybody clear this up?
Also I found that calls:
CloseHandle(prInfo.hThread);
CloseHandle(prInfo.hProcess);
are missing in this function. Have I found a handle leak, or is there some magic that would automatically close the handles?

Related

Detecting a process crash in C++/Win32

I'm working on a software that contains 2 programs : the Qt Main exe + an OpenGL Game exe
We use always the Qt Main exe at the first. When we click on the button "start game", we execute the OpenGL Game exe. No probleme to do that.
The problem is that sometime we have a crash in the OpenGL Game exe and we want to send a crash report containing the log to our compagny crash-report mail.
I found a function (registerwaitforsingleobject) in Win32 API but I don't know if the process has crashed or not :
https://learn.microsoft.com/en-gb/windows/desktop/api/winbase/nf-winbase-registerwaitforsingleobject
I would like to use only the win32 api (WinXP-WinVist to Win10)
Thanks in advance
I found the solution to my problem : I used GetExitCodeProcess function from the Win32 API (https://learn.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-getexitcodeprocess).
This is the example code :
int main(int argc, char** arv)
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
const char * prgm = "CrashedProcess.exe";
LPSTR prgmLpstr = const_cast<LPSTR>(prgm);
// Start the child process.
if (!CreateProcess(NULL, // No module name (use command line)
prgmLpstr, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi) // Pointer to PROCESS_INFORMATION structure
)
{
printf("CreateProcess failed (%d).\n", GetLastError());
return -1;
}
// Wait until child process exits.
auto ret = WaitForSingleObject(pi.hProcess, INFINITE);
printf("WaitForSingleObject ret = %x\n", ret);
if (ret == WAIT_OBJECT_0)
{
printf("WaitForSingleObject ret ret == WAIT_OBJECT_0\n");
}
BOOL b = FALSE;
DWORD n = 0;
b = GetExitCodeProcess(pi.hProcess, &n);
if (n == 0xC0000005)
{
printf("Process Crashed !!!\n");
}
// Close process and thread handles.
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
printf("WaitForSingleObject end\n");
return 0;
}
CrashedProcess.exe source code :
int main()
{
int * ptr = nullptr;
*ptr = 123;
return 0;
}
Use a ready-made solution such as CrashRpt http://crashrpt.sourceforge.net/. It will install a proper handler and report/submit what you need when exceptions are thrown.
You can use Interprocess Communications with a pipe.
Send a message at time laps (for example, 1 second). If there's no response you can be almost sure that the other program is crashed.
Another approach, less elegant, is testing for a log file, modified every x-seconds, with a value meaning "I'm still alive, not crashed".
Assuming the program you care about has a normal Windows event loop, the more or less standard way to check that it's processing messages in a reasonably timely fashion is to use SendMessageTimeout to send it a WM_NULL message.
The program won't do anything in response to the WM_NULL, but SendMessageTimeout will time out if the message stays in its message queue for too long (where you pick what "too long" means when you make the call). So you send it, and then check whether it timed out or not.
But note: this only applies to programs that does process Windows messages. If it doesn't have a message loop, it'll always timeout. Oh, and a program is multi-threaded, one thread can "crash" (e.g., go into an infinite loop) while others continue to operate normally, so it's not always easy to even define what "crashed" means.

RegisterWaitForSingleObject crash sometime if handle is closed immediately

I'm getting a crash sometimes in RegisterWaitForSingleObject (1 out of 10). It seems that although RegisterWaitForSingleObject returns, the internal thread pool is not yet ready.
HANDLE processHandle = OpenProcess (PROCESS_ALL_ACCESS, FALSE, processID);
// CRASH IN INTERNAL SOMETIMES
RegisterWaitForSingleObject (&hWaitForChild_,processHandle,OnChildProcessExit, 0,INFINITE,WT_EXECUTEONLYONCE);
// If I sleep here, then it seems ok.
//std::this_thread::sleep_for (std::chrono::milliseconds (10));
CloseHandle (processHandle);
I can replicate this with a simple sample here. 1 in 10 times, it will crash. How should I be synchronizing it properly without resorting to sleep hack.
https://filedn.com/l3TGy7Y83c247u0RDYa9fkp/temp/stackoverflow/testregister.cpp
based on your code spinet:
// THIS CRASHS HERE SOMETIMES
if (! RegisterWaitForSingleObject (
&hWaitForChild_
,processHandle
, OnChildProcessExit
, 0 //this
, INFINITE
, WT_EXECUTEONLYONCE))
{
LogDebug ("RegisterWaitForSingleObject failed");
}
// If this is enabled, then it won't crash
//std::this_thread::sleep_for (std::chrono::milliseconds (10));
if (! CloseHandle (processHandle)) // !!!
LogDebug ("RegisterWaitForSingleObject Closehandle failed");
so you close processHandle just after you call RegisterWaitForSingleObject for this handle. however if read about RegisterWaitForSingleObject:
If this handle is closed while the wait is still pending, the
function's behavior is undefined.
if look more deep - try understand - how is RegisterWaitForSingleObject worked internally ? it pass processHandle to some worker thread. and this thread begin wait for this handle. but this is (pass handle to another thread) is asynchronous operation - say for example internally can be started new thread with this handle as argument, or it can be passed to already existing working thread via some signal. but anyway - worked thread got this handle and begin wait some later. from another side - you just close processHandle after RegisterWaitForSingleObject return control. so here race - what will be first - or worked thread begin wait on handle (in this case all will be work) or you close this handle. in case you close this handle first - worked thread will be try wait on already invalid handle and raise exception - STATUS_THREADPOOL_HANDLE_EXCEPTION.
// If this is enabled, then it won't crash
//std::this_thread::sleep_for (std::chrono::milliseconds (10));
of course - by sleep you give time for worked thread to begin wait on handle. in this case he begin wait before you close handle.
solution - you must not close handle, until WAITORTIMERCALLBACK Callback will be not called. you need allocate some context, where place processHandle and pass this context to RegisterWaitForSingleObject. and when you callback will be called - you got pointer to your context back and here and close handle.
also note, that you not need open separate, second, handle for child process, but can use process handle returned by CreateProcess
Ok, I managed to solve it by keeping the handle around until I call Unregisterwait. It seems to be stable. Thanks to the answers.
I met the same problem like you that an exception occurred while debugging in Visual Studio. I tried many time and finally found the reason. If you close the handle of the process newly created, the program would crash. I tried to close the handles in the callback function, it works perfectly, like this:
typedef struct {
LPTSTR pszCmdLine;
HANDLE hEvent;
} THREAD_PARAM;
typedef struct {
TCHAR szCmdLine[1024];
HANDLE hWaitObject;
DWORD dwProcessId;
HANDLE hProcess;
DWORD dwThreadId;
HANDLE hThread;
} OBJECT_PARAM;
static void CALLBACK WaitObjectCallback(LPVOID lpParam, BOOLEAN TimerOrWaitFired)
{
OBJECT_PARAM *pobp = static_cast<OBJECT_PARAM *>(lpParam);
TCHAR szInfo[1024] = { 0 };
DWORD dwExitCode = 0;
GetExitCodeProcess(pobp->hProcess, &dwExitCode);
wnsprintf(szInfo, ARRAYSIZE(szInfo), _T("process %u [%s] exit: %u\n"), pobp->dwProcessId, pobp->szCmdLine, dwExitCode);
OutputDebugString(szInfo);
//
// unregister the wait object handle and close the process handle finally
//
UnregisterWait(pobp->hWaitObject);
CloseHandle(pobp->hProcess);
CloseHandle(pobp->hThread);
GlobalFree(lpParam);
}
static DWORD CALLBACK ThreadFunction(LPVOID lpParam)
{
THREAD_PARAM *pthp = static_cast<THREAD_PARAM *>(lpParam);
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi = { 0 };
BOOL bResult;
bResult = CreateProcess(nullptr, pthp->pszCmdLine, nullptr, nullptr, FALSE, 0, nullptr, nullptr, &si, &pi);
if (bResult)
{
OBJECT_PARAM *pobp = static_cast<OBJECT_PARAM *>(GlobalAlloc(GPTR, sizeof(OBJECT_PARAM)));
// make copy of the command line and other informations of the newly created process
lstrcpyn(pobp->szCmdLine, pthp->pszCmdLine, ARRAYSIZE(pobp->szCmdLine));
pobp->dwProcessId = pi.dwProcessId;
pobp->hProcess = pi.hProcess;
pobp->dwThreadId = pi.dwThreadId;
pobp->hThread = pi.hThread;
bResult = RegisterWaitForSingleObject(&pobp->hWaitObject, pi.hProcess, WaitObjectCallback, pobp, INFINITE, WT_EXECUTEONLYONCE);
// once it failed...
if (!bResult)
{
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
}
// Notify the thread creator that the process is created successfully
SetEvent(pthp->hEvent);
return 0;
}

WINAPI - Close mutex without being the owner

I'm trying to close a mutex in another application.
I'm using the WinAPI ("windows.h").
Here's my code to close this mutex:
DWORD pid = 0;
hMyWnd = FindWindow(NULL, "TheFamousWindowName");
GetWindowThreadProcessId(hMyWnd, &pid);
HANDLE hProc = OpenProcess(PROCESS_DUP_HANDLE, 0, pid);
HANDLE hMutex = OpenMutex(MUTEX_ALL_ACCESS, false, "TheEvilMutex"); // hMutex isn't null
WaitForSingleObject(hMutex, 10000); // Wait 10 seconds, nothing happens
if (!DuplicateHandle(hProc, hMutex, NULL, 0, 0, false, DUPLICATE_CLOSE_SOURCE)) {
// Arrive always here because of error 288
// And the mutex is still there, not closed
}
ReleaseMutex(hMutex);
CloseHandle(hMutex);
The problem is when I call
DuplicateHandle(hProc, hMutex, NULL, 0, 0, false, DUPLICATE_CLOSE_SOURCE)
I got the error 288 with
GetLastError()
labeled as "Attempt to release mutex not owned by caller" and the mutex isn't closed
Now, I know that I'm not the owner, but I can't see a solution to close this mutex.
I've seen some programs doing it like Process Explorer or Process Hacker. I've looked into the code of this last on GitHub but didn't find anything about how it close a mutex without being the owner.
I've also checked this thread
how does procexp close a mutex held by another process? but I can't get it working.
Thanks for reading me.
Hoping someone could help me.
EDIT :
Thanks to #RbMm, replacing
DuplicateHandle(hProc, hMutex, NULL, 0, 0, false, DUPLICATE_CLOSE_SOURCE)
with
DuplicateHandle((HANDLE)-1, hMutex, NULL, 0, 0, false, DUPLICATE_CLOSE_SOURCE)
solved error 288, but the mutex isn't closed with this.
in call DuplicateHandle(hProc, hMutex, NULL, 0, 0, false, DUPLICATE_CLOSE_SOURCE) hMutex must be handle that is valid in the context of the hProc. but hMutex is handle in current process, not in hProc. so in this line of code you try close arbitrary handle in context of hProc, but not your hMutex. and result of this will be arbitrary. may be you close some handle. may be this handle not exist at all, or handle is protected from close.
And the mutex is still there, not closed
of course it not closed and can not be closed. for close it you need call
DuplicateHandle(NtCurrentProcess(), hMutex, NULL, 0, 0, false, DUPLICATE_CLOSE_SOURCE);
because of error 288
i absolute sure that DuplicateHandle never return this error. ERROR_NOT_OWNER you got from ReleaseMutex(hMutex);
for close mutex in another process - need use handle value of this mutex in target process, not in self process. this code is done work:
void CloseRemote(ULONG dwProcessId, PCWSTR Name)
{
// create any file
HANDLE hFile = OpenMutex(MAXIMUM_ALLOWED, FALSE, Name);
if (hFile != INVALID_HANDLE_VALUE)
{
if (HANDLE hProcess = OpenProcess(PROCESS_DUP_HANDLE, FALSE, dwProcessId))
{
NTSTATUS status;
ULONG cb = 0x80000;
union {
PSYSTEM_HANDLE_INFORMATION_EX pshi;
PVOID pv;
};
do
{
status = STATUS_INSUFFICIENT_RESOURCES;
if (pv = LocalAlloc(0, cb))
{
if (0 <= (status = ZwQuerySystemInformation(SystemExtendedHandleInformation, pv, cb, &cb)))
{
if (ULONG_PTR NumberOfHandles = pshi->NumberOfHandles)
{
ULONG_PTR UniqueProcessId = GetCurrentProcessId();
PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Handles = pshi->Handles;
do
{
// search for created file
if (Handles->UniqueProcessId == UniqueProcessId && Handles->HandleValue == (ULONG_PTR)hFile)
{
// we got it !
PVOID Object = Handles->Object;
NumberOfHandles = pshi->NumberOfHandles, Handles = pshi->Handles;
do
{
if (Object == Handles->Object && Handles->UniqueProcessId == dwProcessId)
{
DuplicateHandle(hProcess, (HANDLE)Handles->HandleValue, 0, 0, 0, 0, DUPLICATE_CLOSE_SOURCE);
}
} while (Handles++, --NumberOfHandles);
break;
}
} while (Handles++, --NumberOfHandles);
}
}
LocalFree(pv);
}
} while (status == STATUS_INFO_LENGTH_MISMATCH);
CloseHandle(hProcess);
}
CloseHandle(hFile);
}
}

C++ thread termination with waiting window

So, the code goes somehow like this:
MAIN(){
/*waiting window class declaration*/
threadinfo* oThread=new threadinfo(); //An object that will help me know when to finish the thread
QueueUserWorkItem((LPTHREAD_START_ROUTINE)waitingWindow, (void*)mThread, WT_EXECUTELONGFUNCTION);
function_that_takes_time();
oThread->setTerminated(); //set member terminated to bool true
/*continue with other things*/
}
and waitingWindow function that will run on that thread
MSG msg;
hwndWaiting=CreateWindow(...) // here the window is created
while (msg.message != WM_QUIT)
{
if (PeekMessage(&msg, null, 0U, 0U, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
if(oThread->isTerminated()) // isTerminated returns bool true if terminated
{
delete oThread;
ExitThread(0);
}
}
}
ExitThread(0);
Is ExitThread a good way to remove the waiting window, and safely remove the thread? (at least I'm 100% sure this way when to end it).
I'm asking this because this works nice in Windows XP, but will crash with "the application has stopped working" on Windows 7.
Thanks for the help.
The best way to end threads in general, is to let them "gracefully" finish up by themselves. You could tell the thread to end by setting an event, for example:
HANDLE hevent_die = CreateEvent(...);
HANDLE hthread_something = CreateThread(...); // or _beginthread()
...
DWORD WINAPI thread_func (LPVOID param)
{
while(working && WaitForSingleObject(hevent_die, 0)!=WAIT_OBJECT_0)
{
...
}
return 0;
}
while (msg.message != WM_QUIT)
{
...
if(WaitForSingleObject(hthread_something, 0) == WAIT_OBJECT_0)
{
// do things if needed
}
}
SetEvent(hevent_die);
WaitForSingleObject(hthread_something, INFINITE);
CloseHandle(hthread_something);
CloseHandle(hevent_die);
hthread_something = 0;
hevent_die = 0;
If you are using nested loops inside the thread function, they too will have to end if they receive the event.
You should exit your loop and thread cleanly so that any destructors are called correctly. Don't use ExitThread(), just use a flag to indicate when to exit the loop and then just exit your waitingWindow function at the end.

C++, How to determine if a Windows Process is running?

This is concerning Windows XP processes.
I have a process running, let's call it Process1. Process1 creates a new process, Process2, and saves its id.
Now, at some point Process1 wants Process2 to do something, so it first needs to make sure that Process2 is still alive and that the user has not not killed it.
How can I check that this process is still running?
Since I created it, I have the Process ID, I would think there is some library function along the lines of IsProcessIDValid( id ) but I can't find it on MSDN
You can use GetExitCodeProcess. It will return STILL_ACTIVE (259) if the process is still running (or if it happened to exit with that exit code :( ).
The process handle will be signaled if it exits.
So the following will work (error handling removed for brevity):
BOOL IsProcessRunning(DWORD pid)
{
HANDLE process = OpenProcess(SYNCHRONIZE, FALSE, pid);
DWORD ret = WaitForSingleObject(process, 0);
CloseHandle(process);
return ret == WAIT_TIMEOUT;
}
Note that process ID's can be recycled - it's better to cache the handle that is returned from the CreateProcess call.
You can also use the threadpool API's (SetThreadpoolWait on Vista+, RegisterWaitForSingleObject on older platforms) to receive a callback when the process exits.
EDIT: I missed the "want to do something to the process" part of the original question. You can use this technique if it is ok to have potentially stale data for some small window or if you want to fail an operation without even attempting it. You will still have to handle the case where the action fails because the process has exited.
#include <cstdio>
#include <windows.h>
#include <tlhelp32.h>
/*!
\brief Check if a process is running
\param [in] processName Name of process to check if is running
\returns \c True if the process is running, or \c False if the process is not running
*/
bool IsProcessRunning(const wchar_t *processName)
{
bool exists = false;
PROCESSENTRY32 entry;
entry.dwSize = sizeof(PROCESSENTRY32);
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if (Process32First(snapshot, &entry))
while (Process32Next(snapshot, &entry))
if (!wcsicmp(entry.szExeFile, processName))
exists = true;
CloseHandle(snapshot);
return exists;
}
The solution provided by #user152949, as it was noted in commentaries, skips the first process and doesn't break when "exists" is set to true. Let me provide a fixed version:
#include <windows.h>
#include <tlhelp32.h>
#include <tchar.h>
bool IsProcessRunning(const TCHAR* const executableName) {
PROCESSENTRY32 entry;
entry.dwSize = sizeof(PROCESSENTRY32);
const auto snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if (!Process32First(snapshot, &entry)) {
CloseHandle(snapshot);
return false;
}
do {
if (!_tcsicmp(entry.szExeFile, executableName)) {
CloseHandle(snapshot);
return true;
}
} while (Process32Next(snapshot, &entry));
CloseHandle(snapshot);
return false;
}
I found this today, it is from 2003. It finds a process by name, you don't even need the pid.
\#include windows.h
\#include tlhelp32.h
\#include iostream.h
int FIND_PROC_BY_NAME(const char *);
int main(int argc, char *argv[])
{
// Check whether a process is currently running, or not
char szName[100]="notepad.exe"; // Name of process to find
int isRunning;
isRunning=FIND_PROC_BY_NAME(szName);
// Note: isRunning=0 means process not found, =1 means yes, it is found in memor
return isRunning;
}
int FIND_PROC_BY_NAME(const char *szToFind)
// Created: 12/29/2000 (RK)
// Last modified: 6/16/2003 (RK)
// Please report any problems or bugs to kochhar#physiology.wisc.edu
// The latest version of this routine can be found at:
// http://www.neurophys.wisc.edu/ravi/software/killproc/
// Check whether the process "szToFind" is currently running in memory
// This works for Win/95/98/ME and also Win/NT/2000/XP
// The process name is case-insensitive, i.e. "notepad.exe" and "NOTEPAD.EXE"
// will both work (for szToFind)
// Return codes are as follows:
// 0 = Process was not found
// 1 = Process was found
// 605 = Unable to search for process
// 606 = Unable to identify system type
// 607 = Unsupported OS
// 632 = Process name is invalid
// Change history:
// 3/10/2002 - Fixed memory leak in some cases (hSnapShot and
// and hSnapShotm were not being closed sometimes)
// 6/13/2003 - Removed iFound (was not being used, as pointed out
// by John Emmas)
{
BOOL bResult,bResultm;
DWORD aiPID[1000],iCb=1000,iNumProc,iV2000=0;
DWORD iCbneeded,i;
char szName[MAX_PATH],szToFindUpper[MAX_PATH];
HANDLE hProc,hSnapShot,hSnapShotm;
OSVERSIONINFO osvi;
HINSTANCE hInstLib;
int iLen,iLenP,indx;
HMODULE hMod;
PROCESSENTRY32 procentry;
MODULEENTRY32 modentry;
// PSAPI Function Pointers.
BOOL (WINAPI *lpfEnumProcesses)( DWORD *, DWORD cb, DWORD * );
BOOL (WINAPI *lpfEnumProcessModules)( HANDLE, HMODULE *,
DWORD, LPDWORD );
DWORD (WINAPI *lpfGetModuleBaseName)( HANDLE, HMODULE,
LPTSTR, DWORD );
// ToolHelp Function Pointers.
HANDLE (WINAPI *lpfCreateToolhelp32Snapshot)(DWORD,DWORD) ;
BOOL (WINAPI *lpfProcess32First)(HANDLE,LPPROCESSENTRY32) ;
BOOL (WINAPI *lpfProcess32Next)(HANDLE,LPPROCESSENTRY32) ;
BOOL (WINAPI *lpfModule32First)(HANDLE,LPMODULEENTRY32) ;
BOOL (WINAPI *lpfModule32Next)(HANDLE,LPMODULEENTRY32) ;
// Transfer Process name into "szToFindUpper" and
// convert it to upper case
iLenP=strlen(szToFind);
if(iLenP<1 || iLenP>MAX_PATH) return 632;
for(indx=0;indx<iLenP;indx++)
szToFindUpper[indx]=toupper(szToFind[indx]);
szToFindUpper[iLenP]=0;
// First check what version of Windows we're in
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
bResult=GetVersionEx(&osvi);
if(!bResult) // Unable to identify system version
return 606;
// At Present we only support Win/NT/2000 or Win/9x/ME
if((osvi.dwPlatformId != VER_PLATFORM_WIN32_NT) &&
(osvi.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS))
return 607;
if(osvi.dwPlatformId==VER_PLATFORM_WIN32_NT)
{
// Win/NT or 2000 or XP
// Load library and get the procedures explicitly. We do
// this so that we don't have to worry about modules using
// this code failing to load under Windows 95, because
// it can't resolve references to the PSAPI.DLL.
hInstLib = LoadLibraryA("PSAPI.DLL");
if(hInstLib == NULL)
return 605;
// Get procedure addresses.
lpfEnumProcesses = (BOOL(WINAPI *)(DWORD *,DWORD,DWORD*))
GetProcAddress( hInstLib, "EnumProcesses" ) ;
lpfEnumProcessModules = (BOOL(WINAPI *)(HANDLE, HMODULE *,
DWORD, LPDWORD)) GetProcAddress( hInstLib,
"EnumProcessModules" ) ;
lpfGetModuleBaseName =(DWORD (WINAPI *)(HANDLE, HMODULE,
LPTSTR, DWORD )) GetProcAddress( hInstLib,
"GetModuleBaseNameA" ) ;
if( lpfEnumProcesses == NULL ||
lpfEnumProcessModules == NULL ||
lpfGetModuleBaseName == NULL)
{
FreeLibrary(hInstLib);
return 605;
}
bResult=lpfEnumProcesses(aiPID,iCb,&iCbneeded);
if(!bResult)
{
// Unable to get process list, EnumProcesses failed
FreeLibrary(hInstLib);
return 605;
}
// How many processes are there?
iNumProc=iCbneeded/sizeof(DWORD);
// Get and match the name of each process
for(i=0;i<iNumProc;i++)
{
// Get the (module) name for this process
strcpy(szName,"Unknown");
// First, get a handle to the process
hProc=OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ,FALSE,
aiPID[i]);
// Now, get the process name
if(hProc)
{
if(lpfEnumProcessModules(hProc,&hMod,sizeof(hMod),&iCbneeded) )
{
iLen=lpfGetModuleBaseName(hProc,hMod,szName,MAX_PATH);
}
}
CloseHandle(hProc);
// Match regardless of lower or upper case
if(strcmp(_strupr(szName),szToFindUpper)==0)
{
// Process found
FreeLibrary(hInstLib);
return 1;
}
}
}
if(osvi.dwPlatformId==VER_PLATFORM_WIN32_WINDOWS)
{
// Win/95 or 98 or ME
hInstLib = LoadLibraryA("Kernel32.DLL");
if( hInstLib == NULL )
return FALSE ;
// Get procedure addresses.
// We are linking to these functions of Kernel32
// explicitly, because otherwise a module using
// this code would fail to load under Windows NT,
// which does not have the Toolhelp32
// functions in the Kernel 32.
lpfCreateToolhelp32Snapshot=
(HANDLE(WINAPI *)(DWORD,DWORD))
GetProcAddress( hInstLib,
"CreateToolhelp32Snapshot" ) ;
lpfProcess32First=
(BOOL(WINAPI *)(HANDLE,LPPROCESSENTRY32))
GetProcAddress( hInstLib, "Process32First" ) ;
lpfProcess32Next=
(BOOL(WINAPI *)(HANDLE,LPPROCESSENTRY32))
GetProcAddress( hInstLib, "Process32Next" ) ;
lpfModule32First=
(BOOL(WINAPI *)(HANDLE,LPMODULEENTRY32))
GetProcAddress( hInstLib, "Module32First" ) ;
lpfModule32Next=
(BOOL(WINAPI *)(HANDLE,LPMODULEENTRY32))
GetProcAddress( hInstLib, "Module32Next" ) ;
if( lpfProcess32Next == NULL ||
lpfProcess32First == NULL ||
lpfModule32Next == NULL ||
lpfModule32First == NULL ||
lpfCreateToolhelp32Snapshot == NULL )
{
FreeLibrary(hInstLib);
return 605;
}
// The Process32.. and Module32.. routines return names in all uppercase
// Get a handle to a Toolhelp snapshot of all the systems processes.
hSnapShot = lpfCreateToolhelp32Snapshot(
TH32CS_SNAPPROCESS, 0 ) ;
if( hSnapShot == INVALID_HANDLE_VALUE )
{
FreeLibrary(hInstLib);
return 605;
}
// Get the first process' information.
procentry.dwSize = sizeof(PROCESSENTRY32);
bResult=lpfProcess32First(hSnapShot,&procentry);
// While there are processes, keep looping and checking.
while(bResult)
{
// Get a handle to a Toolhelp snapshot of this process.
hSnapShotm = lpfCreateToolhelp32Snapshot(
TH32CS_SNAPMODULE, procentry.th32ProcessID) ;
if( hSnapShotm == INVALID_HANDLE_VALUE )
{
CloseHandle(hSnapShot);
FreeLibrary(hInstLib);
return 605;
}
// Get the module list for this process
modentry.dwSize=sizeof(MODULEENTRY32);
bResultm=lpfModule32First(hSnapShotm,&modentry);
// While there are modules, keep looping and checking
while(bResultm)
{
if(strcmp(modentry.szModule,szToFindUpper)==0)
{
// Process found
CloseHandle(hSnapShotm);
CloseHandle(hSnapShot);
FreeLibrary(hInstLib);
return 1;
}
else
{ // Look for next modules for this process
modentry.dwSize=sizeof(MODULEENTRY32);
bResultm=lpfModule32Next(hSnapShotm,&modentry);
}
}
//Keep looking
CloseHandle(hSnapShotm);
procentry.dwSize = sizeof(PROCESSENTRY32);
bResult = lpfProcess32Next(hSnapShot,&procentry);
}
CloseHandle(hSnapShot);
}
FreeLibrary(hInstLib);
return 0;
}
Another way of monitoring a child-process is to create a worker thread that will :
call CreateProcess()
call WaitForSingleObject() // the worker thread will now wait till the child-process finishes execution. it's possible to grab the return code (from the main() function) too.
You can never check and see if a process is running, you can only check to see if a process was running at some point in the recent past. A process is an entity that is not controlled by your application and can exit at any moment in time. There is no way to guaranteed that a process will not exit in between the check to see if it's running and the corresponding action.
The best approach is to just do the action required and catch the exception that would be thrown if the process was not running.
call EnumProcesses() and check if the PID is in the list.
http://msdn.microsoft.com/en-us/library/ms682629%28VS.85%29.aspx
JaredPar is right in that you can't know if the process is running. You can only know if the process was running at the moment you checked. It might have died in the mean time.
You also have to be aware the PIDs can be recycled pretty quickly. So just because there's a process out there with your PID, it doesn't mean that it's your process.
Have the processes share a GUID. (Process 1 could generate the GUID and pass it to Process 2 on the command line.) Process 2 should create a named mutex with that GUID. When Process 1 wants to check, it can do a WaitForSingleObject on the mutex with a 0 timeout. If Process 2 is gone, the return code will tell you that the mutex was abandoned, otherwise you'll get a timeout.
You may find if a process (given its name or PID) is running or not by iterating over the running processes simply by taking a snapshot of running processes via CreateToolhelp32Snapshot, and by using Process32First and Process32Next calls on that snapshot.
Then you may use th32ProcessID field or szExeFile field of the resulting PROCESSENTRY32 struct depending on whether you want to search by PID or executable name. A simple implementation can be found here.
While writing a monitoring tool, i took a slightly different approach.
It felt a bit wasteful to spin up an extra thread just to use WaitForSingleObject or even the RegisterWaitForSingleObject (which does that for you). Since in my case i don't need to know the exact instant a process has closed, just that it indeed HAS closed.
I'm using the GetProcessTimes() instead:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms683223(v=vs.85).aspx
GetProcessTimes() will return a FILETIME struct for the process's ExitTime only if the process has actually exited. So is just a matter of checking if the ExitTime struct is populated and if the time isn't 0;
This solution SHOULD account the case where a process has been killed but it's PID was reused by another process. GetProcessTimes needs a handle to the process, not the PID. So the OS should know that the handle is to a process that was running at some point, but not any more, and give you the exit time.
Relying on the ExitCode felt dirty :/
This is a solution that I've used in the past. Although the example here is in VB.net - I've used this technique with c and c++. It bypasses all the issues with Process IDs & Process handles, and return codes. Windows is very faithful in releasing the mutex no matter how Process2 is terminated. I hope it is helpful to someone...
**PROCESS1 :-**
Randomize()
mutexname = "myprocess" & Mid(Format(CDbl(Long.MaxValue) * Rnd(), "00000000000000000000"), 1, 16)
hnd = CreateMutex(0, False, mutexname)
' pass this name to Process2
File.WriteAllText("mutexname.txt", mutexname)
<start Process2>
<wait for Process2 to start>
pr = WaitForSingleObject(hnd, 0)
ReleaseMutex(hnd)
If pr = WAIT_OBJECT_0 Then
<Process2 not running>
Else
<Process2 is running>
End If
...
CloseHandle(hnd)
EXIT
**PROCESS2 :-**
mutexname = File.ReadAllText("mutexname.txt")
hnd = OpenMutex(MUTEX_ALL_ACCESS Or SYNCHRONIZE, True, mutexname)
...
ReleaseMutex(hnd)
CloseHandle(hnd)
EXIT
char tmp[200] = "taskkill /f /im chrome.exe && \"C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe\"
while (1)
{
FILE* f;
f = _popen("tasklist", "r");
char b[512];
bzero(b, 512);
while (fgets(b, 512, f) != NULL)
{
if (strncmp(b, "chrome.exe", 8) == 0)
{
printf("Chrome running!\n");
system(tmp);
}
else
{
printf("Chrome NOT running!\n");
}
}
Sleep(1000);
}