I will describe my problem as below
I have two applications mainApp and supervisorApp.
The supervisorApp will run along with mainApp to supervise mainApp.
supervisorApp will check status of mainApp each 30s by sending KEEP_ALIVE message to mainApp.
And supervisorApp will restart mainApp if mainApp is not responding that KEEP_ALIVE message.
And more one rule, mainApp will not allow more than two processes "mainApp.exe" run together,
that mean when started, mainApp will close immediately if there is other process "mainApp.exe"is running.
And then I will posted some main code and show my problem.
//Code for supervisorApp - Begin
void Main()
{
while (true)
{
Sleep(30000);
if(SendKeepAliveMessage() == false) //MainApp is not responding -> Restart mainApp
{
TerminateMainApp();
Sleep(2000);
StartMainApp();
}
}
}
void TerminateMainApp()
{
TerminateProcess(MainAppProcessInfo.hProcess, 0);
CloseHandle( MainAppProcessInfo.hProcess );
CloseHandle( MainAppProcessInfo.hThread );
}
bool StartMainApp()
{
ZeroMemory( &MainAppStartUpInfo, sizeof(MainAppStartUpInfo) );
MainAppStartUpInfo.cb = sizeof(MainAppStartUpInfo);
ZeroMemory( &MainAppProcessInfo, sizeof(MainAppProcessInfo) );
char commandLine[STR_LENGTH_256];
sprintf(commandLine, "mainApp.exe");
LPSTR cmd = _T(commandLine);
//Start the child process
if( !CreateProcess
(NULL, // No module name (use command line)
cmd, // 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
&MainAppStartUpInfo, // Pointer to STARTUPINFO structure
&MainAppProcessInfo // Pointer to PROCESS_INFORMATION structure
)
)
{
return false;
}
return true;
}
//Code for supervisorApp - End
//Code for mainApp - Begin
void Main()
{
if (IsThisProcessHasRun())
{
MessageBox.Show("The mainApp is running!");
return;
}
//Do something
}
bool IsThisProcessHasRun()
{
HANDLE SnapShot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
if( SnapShot == INVALID_HANDLE_VALUE )
return false;
PROCESSENTRY32 procEntry;
procEntry.dwSize = sizeof( PROCESSENTRY32 );
if( !Process32First( SnapShot, &procEntry ) )
{
CloseHandle(SnapShot);
return false;
}
int countProcess = 0;
do
{
if( strcmp( procEntry.szExeFile, "mainApp.exe" ) == 0 )
{
countProcess++;
if(countProcess == 2)
{
CloseHandle(SnapShot);
return true;
}
}
}
while( Process32Next( SnapShot, &procEntry ) );
CloseHandle(SnapShot);
return false;
}
//Code for mainApp - End
Everything is ok on windows 7, but on windows 8 I have encountered the following problem.
When mainApp.exe is crashed (Window will show the dialog with the message "the mainApp has stopped working" -> do not close it),
the supervisorMainApp send KEEP_ALIVE message and mainApp does not respond this message,
Then supervisorMainApp will call TerminateMainApp() and StartMainApp() to restart mainApp.
But when mainApp start, it will show the dialog "The mainApp is running!"...
I debug and see that, function TerminateMainApp() and StartMainApp() work fine.
When TerminateMainApp() called, in Task Manager's proceess list will remove "mainApp.exe" => it's ok
But when mainApp start, the function IsThisProcessHasRun() return true with countProcess=2, so it can not start.
And then I close Dialog's Crashed message of mainApp, IsThisProcessHasRun() false with countProcess=1, so it can start successfully!
I don't understand why? And I think if I can Dialog's Crashed message of mainApp automatically, then my problem can solve.
But maybe it is not good solution!
Someone can show me how to kill the process mainApp.exe completely?
Many thanks!
T&T
Im creating a job with CreateJobObjectA(), then creating a new process with CreateProcessA(), and when I try to assign the new process to the job I have created with AssignProcessToJobObject() it returns 0. So I GetLastError() and im getting a value of 6. Which according to Windows systems error code means The Handle is invalid. Heres my code.
HANDLE job = CreateJobObjectA( NULL, "jobName" );
if( job == NULL )
{
printf( "Job is NULL" );
}
else
{
JOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 };
jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
if( 0 == SetInformationJobObject( job, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli)))
{
printf("Could not SetInformationJobObject\n");
}
}
if( CreateProcessA( "C:\\Windows\\SysWOW64\\cmd.exe", "/c server.bat", NULL, NULL, TRUE, 0, NULL, NULL, &info, &processInfo))
{
printf("CreateProcess succeeded.\n");
if( job != NULL )
{
HANDLE derp = processInfo.hProcess;
if( derp != NULL )
{
if( 0 == AssignProcessToJobObject( job, derp ))
{
printf("Could not AssignProcessToObject\n");
DWORD err = GetLastError();
printf("derp");
}
}
}
//Can we free handles now? Not sure about this.
CloseHandle(processInfo.hProcess);
CloseHandle(processInfo.hThread);
}
The bat file is doing what it is supposed to be doing and launching a jar that runs a server. I just dont get how my Handle is invalid. Any help would be amazing. Or possibly a different way to do this?
I want to launch this new process and have it be a child process so when my main process crashes the server closes also.
Thank you.
You've got a race condition. If cmd.exe exits before you call AssignProcessToJobObject it won't work (I'm not sure what error code you get in that scenario).
Start the process suspended using the CREATE_SUSPENDED flag and don't resume it until you've already assigned it to the job.
I have a process that creates a named event, using ::CreateEvent.
In my process, I want to check whether the event exists or not, but I don't want to create the event in case it doesn't exist.
How can I do it?
I can do it like this, but then the event will be created in case it doesn't exist:
HANDLE hEvent;
hEvent= ::CreateEvent(NULL, FALSE, FALSE, _T("MyEvent"));
if (::GetLastError() != ERROR_ALREADY_EXISTS)
{
.......
}
OpenEvent does not create the event if it doesn't already exist, so your code already almost does what you want. You need to check the event handle for NULL before checking the error code:
HANDLE hEvent;
hEvent= ::OpenEvent(FALSE, FALSE, _T("MyEvent"));
if (!hEvent) // event does not already exist, or other problem
{
.......
}
CString csHandleName = "hEvent";
int nHandleinc(0);
HANDLE hHandleEvent = NULL;
while(!hHandleEvent)
{
csHandleName.Format("hEvent%d",nHandleinc);
hHandleEvent = CreateEvent(NULL,TRUE,false,csHandleName);
if (GetLastError() == ERROR_ALREADY_EXISTS )
{
CloseHandle( hHandleEvent );
hHandleEvent = NULL;
}
nHandleinc++;
}
This question already has answers here:
How to block running two instances of the same program?
(8 answers)
Closed 6 years ago.
ADDITIONAL INFORMATION
Again i am writing on the above issue (Preventing multiple instances of my application)
the code works for if i start two instances from programe menu/desktop shortcut. but in my envrironment,
one instance is running from Window Service.
another from Desktop shortcut with Same parameter.
Any help how to write the code ?
The most common method is to use a mutex, similar to the following:
int WINAPI WinMain(...)
{
const char szUniqueNamedMutex[] = "com_mycompany_apps_appname";
HANDLE hHandle = CreateMutex( NULL, TRUE, szUniqueNamedMutex );
if( ERROR_ALREADY_EXISTS == GetLastError() )
{
// Program already running somewhere
return(1); // Exit program
}
// Program runs...
// Upon app closing:
ReleaseMutex( hHandle ); // Explicitly release mutex
CloseHandle( hHandle ); // close handle before terminating
return( 1 );
}
You have to make sure that you close properly - a program crash that doesn't remove the mutex could possibly prevent the program from running again, though in theory the OS will clean up any dangling mutexes once the process ends.
Another method commonly used is to search window titles for the program title:
HWND hWnd=::FindWindow(LPCTSTR lpClassName, // pointer to class name
LPCTSTR lpWindowName // pointer to window name
);
If it's null, then the window was not found, therefore the program is not running. You can use this to bring focus to the running app before closing this new instance, so the user isn't left wondering why the app didn't open.
if(hWnd != NULL)
{
ShowWindow(hWnd,SW_NORMAL);
// exit this instance
return(1);
}
Here is a simple solution that works most of the time:
CreateEvent(NULL, FALSE, FALSE, "MyEvent");
if (GetLastError() == ERROR_ALREADY_EXISTS)
{
// Do Stuff
return FALSE;
}
Another way:
CreateSemaphore(NULL, TRUE, TRUE, "MySemaphore");
if (GetLastError() == ERROR_ALREADY_EXISTS)
{
// Do Stuff
return FALSE;
}
And another way:
CreateMutex(NULL, TRUE, "MyMutex");
if (GetLastError() == ERROR_ALREADY_EXISTS)
{
// Do Stuff
return FALSE;
}
As, the other answer mentioned, CreateMutex is the most common but it isnt perfect. If you want a really thorough solution and why the above ways are no good, check this link on Codeproject.
TLDR: The only safe and general way to prevent multiple instances of the same process is to use a mutex, since only this is guaranted to not give you a race condition.
Here you have a nice article about the subject. I used it when having to do something similar and the solution is working perfectly: AvoidingMultipleInstances.
You are looking for named mutex (named after argument, if it is what should disallow the app to run in multiple instances).
Also i've seen this solution, without GetLastError():
HANDLE hMutex = CreateMutexA(NULL, FALSE, "my mutex");
DWORD dwMutexWaitResult = WaitForSingleObject(hMutex, 0);
if (dwMutexWaitResult != WAIT_OBJECT_0)
{
MessageBox(HWND_DESKTOP, TEXT("This application is already running"), TEXT("Information"), MB_OK | MB_ICONINFORMATION);
CloseHandle(hMutex);
}
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);
}