My application is being launched from another application. When launched from that other application, there are two processes or instances that get created. One of the instances is created by a call to the wrapper function that calls CreateProcess. That function also sets the global variable to TRUE so that InitInstance() can determine what to do thereafter. The global variable is initialized to FALSE. The problem is both processes are accessing the same global variable which has two different values in InitInstance. It seems the main thread reads it as FALSE and then the secondary thread intervenes and sets it to TRUE.
How do I stop the main thread from running long enough to read the value of the variable being passed by the secondary thread and to complete all the necessary functions within InitInstance() before passing the control back to the main thread. There are certain if-else conditions that require the global variable to be TRUE first. Another part of the problem is when the executable is run outside of the other app I want to make sure it runs properly without having to wait infinitely for the global variable to be TRUE. In this case it will not be. I tried creating an event but I’m not sure how it knows how to stop the main thread and check for the global variable to be TRUE.
if (!bCheckGlobal)
WaitForSingleObject( hEvent1, INFINITE); //does this stop the main thread?
else
SetEvent(hEvent2);
…..excess code…
if (bCheckGlobal) { //if called from other app, value should be TRUE
}
else {
}
SetEvent(hEvent1);
return TRUE;
}
Andreas Masur
August 25th, 2005, 05:43 PM
I am sorry but I honestly don't understand your problem description. Can you restate what you are trying to accomplish? Process A starts your application (Process B). What main thread of which process should wait for what second thread of which process?
frutti42
August 25th, 2005, 06:29 PM
Process A starts Process B and C (two instances of my app). I would lke process C to have precendence over Process B because I would like B to start but not have its main window shown. This is necessary for the app to run properly in the other application A. Context-switching occurs causing the global variable to have two different values.
wildfrog
August 25th, 2005, 06:39 PM
As long as B and C are instances of the same application, does it matter if it's C that gets precedens over B, or could it be the other way (ie. B gets precedence over C)? Does A need to know which of them who has the most precedence?
- petter
frutti42
August 25th, 2005, 06:58 PM
Yes it matters that C gets precedence over B because in order for A to run the app properly it needs to have 2 instance running yet only one window is shown. It creates an instance of the app but never terminates it. So, A runs B while calling a wrapper function that creates C via a call to CreateProcess(the App in question). When C is created the global variable needs to set to TRUE so that the window does not show and the mutex that verifies that only one instance of the app is running is not created. Then B shall run after C making it look like only one instance of the app is running. In actuality, two are running. When the app is closed and reopened, a mutex is created to check whether or not one an instance is already running. Since we did not create one when C was created, it creates the instance. The following is the code that checks for one instance of the app.
if (!bGlobalVariable)
{
OneInstance = ::CreateMutex(NULL, FALSE, “X”);
DWORD dwMutexErr = GetLastError();
if (dwMutexErr == ERROR_ALREADY_EXISTS)
return FALSE;
if (!GlobalVariable)
//show window
return TRUE;
}
wildfrog
August 25th, 2005, 07:50 PM
Ok, it's late but are you looking for something as strange as this? It's not tested...
// APP A
{
// This assumes that the are no A, B or C already running
// create mutex limiting to only one B
HANDLE hBMutex = CreateMutex(NULL, false, "B_MUTEX");
// create semaphore, used by B to notify A (initially blocked)
HANDLE hBStartedSemaphore = CreateSemaphore(NULL, 0, 1, "B_STARTED_SEMAPHORE");
// create mutex limiting to only one C (initially blocked)
HANDLE hCMutex = CreateMutex(NULL, true, "C_MUTEX");
// Open Process B
HANDLE hProcessB = CreateProcess(...);
// Wait for notification by B
WaitForSingleObject(hBStartedSemaphore, INFINITE);
// B is up running, unlock Mutex C
ReleaseMutex(hCMutex);
// Open Process C
HANDLE hProcessC = CreateProcess(...);
// both proc are hopefully running...
}
// APP B & C
{
// Open B_MUTEX, C_MUTEX, SEMAPHORE
HANDLE hBMutex = OpenMutex(NULL, false, "B_MUTEX");
HANDLE hCMutex = OpenMutex(NULL, false, "C_MUTEX");
HANDLE hBStartedSemaphore = OpenSemaphore(NULL, false, "B_STARTED_SEMAPHORE");
// all should be there, if not, A isn't running
if (hBMutex == NULL || hCMutex == NULL || hBStartedSemaphore == NULL)
{
// App a isn't running, quit application
return 0;
}
// Get One Mutex
// If this is the first app started by A, then C_MUTEX will be blocked and
// the only one avalable is B_MUTEX
HANDLE hMutexes[] = {hBMutex, hCMutex};
DWORD dwRet = WaitForMultipleObjects(2, hMutexes, false, 0);
if (dwRet == WAIT_TIMEOUT)
{
// both Mutexes was taken, quit application
return 0;
}
if (dwRet == WAIT_OBJECT_0)
{
// we got B_MUTEX
// do whatever B need to do...
// notify App A so that it will continue to create App C
ReleaseSemaphore(hBStartedSemaphore);
} else if (dwRet == WAIT_OBJECT_0 + 1)
{
// we got C_MUTEX
// do whatever C need to do...
}
// when done, release the owned mutex (B or C) and close the handles
}
Ok, I might have mixed B & C...
- petter
frutti42
August 25th, 2005, 08:08 PM
If I insert AfxMessageBox() right before the global variable check, it's just the right amout of delay time for the global variable to read in as TRUE. Instead of using AfxMessageBox which was used just for debugging purposes, can I use any other function that will give about the same amount of delay time for this to work? Thanks!
wildfrog
August 25th, 2005, 08:34 PM
You can use Sleep(...);
- petter
kirants
August 26th, 2005, 01:45 AM
There seems to be huge confusion here.. Are you saying multiple processes are spawned ( i.e. multiple exes are launched ) . You are talking of global variable being set by multiple processes. What kind of global variable is it ? Note that normal global variables are local to a process alone. So, if the same exe is executed 2 times , each will have it's own copy of this global variable.. so, please explain more clearly.
frutti42
August 29th, 2005, 12:30 PM
Yes, multiple processes are launched, 2 to be exact from a program in which I have no control of. I cannot access program A's code. In my program, how can I stop the first process (B) from running first? The global variable is global within the process and gets set in a wrapper function, the function that will execute the second process (C) via a call to CreateProcess.
kirants
August 29th, 2005, 03:27 PM
To be frank, I am still unclear.
Could you explain in terms of A.exe, B.exe, C.exe and such terms, which one is launching which one. Which one has to wait on which one and which one has an InitInstance, wrapper function etc.. you know in a more picturesque way.. so people can visualize better ;)
frutti42
August 29th, 2005, 04:28 PM
B and C.exe are two processes that derive from the same source code. When selecting my application from A.exe's menu item, it calls a COM component that processes a menu item selection notification (wrapper function OnNotify). The global variable is initialized to 0 but set to 1 in the COM notification function. The global variable should be passed as TRUE to the InitInstance function on the first run. And it did when I inserted an AfxMessageBox right before checking to see what its value was. Without it, it was FALSE. I need the first process (B.exe) to complete before the next can begin (C.exe). How can I accomplish this? This is my revised code:
MyApp::InitInstance()
{
if (!bGlobalVariable)
CreateMutex and show window;
else
do not create mutex and do not show window (let B.exe run)
}
It looks like there are 2 exe files used here. A.exe and B.exe. Is that correct ?
It sounds like the B.exe is launched twice through CreateProcess. i.e. there are 2 instances of B.exe running at a time. Is that correct ?
What .exe is the InitInstance code you pasted part of ?
frutti42
August 29th, 2005, 04:55 PM
A and B.exe are processes of the same application or program (NameofProgram.exe). A.exe executes and sets the value of the global variable to TRUE. This gets passed along to InitInstance to not create the mutex. As A.exe is running, within OnNotify, B.exe is launched through CreateProcess causing the global variable to be FALSE. In this case, we want the mutex to be created. A and B.exe are executing the same code calling InitInstance one after the other. I need A to complete before B begins. Should it be handled in OnNotify before B.exe gets launched?
wildfrog
August 29th, 2005, 05:03 PM
There is more to a mutex than just creating one and checking if it was already created(or not)...
### App A ###
Handle hMutex = CreateMutex(....);
WaitForSingleObject(hMutex);
// owns mutex, app B cannot enter
// read or set global flag or whatever...
ReleaseMutex(hMutex);
### App B ###
Handle hMutex = CreateMutex(....);
// wait here until A is done...
WaitForSingleObject(hMutex);
// owns mutex
// read or set global flag or whatever...
ReleaseMutex(hMutex);
- petter
kirants
August 29th, 2005, 05:04 PM
I need A to complete before B begins. Should it be handled in OnNotify before B.exe gets launched?
If all you want is for first copy of your program to run, and as it starts to quit ,have another instance of it launched , can you not call CreateProcess just before you are quittin yourself ?
Again, you will need code to stop it from infinitely spawning instances of your app.
But, again, what is the mutex thing you are using supposed to achieve.
frutti42
August 29th, 2005, 05:21 PM
Please disregard the CreateMutex code. That is not the problem at hand. bGlobalVariable should be TRUE for the first process (A.exe) but somehow B.exe preempts it causing it to be FALSE. How can I stop process B from doing this? Again, A and B.exe are instances of the same application.
kirants
August 29th, 2005, 05:47 PM
global variables are not shared across instances of processes.
If your bGlobalVariable is set to TRUE in instance 1 of your application , and another instance is launched, it doesn't see bGlobalVariable set to TRUE. It still sees it's own copy which per my understand is initialized to FALSE in your application.
Do you understand ?
To put it simply, assume each instance to be a basket which say has a canvas for you to paint ( global variable ). Now, this canvas is initiliazed to be white to start with. During the program lifetime, one of the components may go and paint it red.
When you launch a new program, think of it as another basket with a canvas ( again white ). When some one in basket 1 is painting the canvas in it red, basket 2 isn't getting affected. It is still the same.
This is called as process's address space. It is a virtual space in which a process is launched which seperates it from other process.
frutti42
August 29th, 2005, 06:02 PM
Yes, I understand that global variables are not shared across instances. The global variable gets set to TRUE in instance 1 and gets read as TRUE by the InitInstance() function contained within the same source code. All I want to do is have instance 1 complete its execution before instance 2 gets launched in OnNotify. The global variable in instance 2 will be false and that's exactly what I want. When the variable does get set to TRUE, besides inserting an AfxMessageBox to allow instance1 to complete its execution, what can I use to stall instance 2 from running before 1 completes.
kirants
August 29th, 2005, 06:15 PM
Questions again..
Possibility 1 :
Instance 1 is launched
bGlobalVariable is FALSE.
Some event in it triggers it to go to TRUE ( because of OnNotify )
Instance 1 to continue running
Instance 1 is about to quit. It launches instance 2 because bGlobalVariable has been set to TRUE.
Possibility 2 :
Instance 1 is launched
bGlobalVariable is FALSE.
Some event in it triggers it to go to TRUE ( because of OnNotify )
Hence, instance 2 is launched.
Instance 1 to continue running, however, instance 2 to remain suspended until instance 1 quits.
Instance 1 is about to quit. It now triggers something that will let instance 2 resume from suspended state.
Any of these 2 possibilities close to what you are looking for ?
frutti42
August 29th, 2005, 07:20 PM
Possibilty 2 is correct. On the last line, I think you meant instance 2 to resume from suspended state. Thanks! I really appreciate your help.
kirants
August 29th, 2005, 07:35 PM
Yeah. Right.. Will edit post to correct it.
Now, to achieve this, I suggest the following:
Have a
HANDLE g_hNamedMutex = NULL;
At program entry , you would try to create it and lock it as follows:
MyApp::InitInstance()
{
g_hMutex = CreateMutex(NULL,FALSE,"whatever unique name here");
if(g_hMutex)
{
//now try to lock it.
if(WAIT_OBJECT_0 == WaitForSingleObject(g_hMutex,INFINITE))
{
//we are the owner now..
//proceed with whatever we want to do
}
}
}
MyApp::ExitInstance()
{
if(g_hMutex)
{
ReleaseMutex(g_hMutex);
CloseHandle(g_hMutex);
}
}
The above will ensure that any instance will block as long as some one has acquired the named mutex.
This will take care of your problem, instance 1 launches, creates mutex , acquires it thru WaitForSingleObject and proceeds to do whatever. Now, if the OnNotify triggers and launches the second instance, the second instance will block in WaitForSingleObject until first instance goes through ExitInstance and Releases the mutex.
Note that, in all this, the mutex is created unconditionally.
MikeAThon
August 29th, 2005, 08:54 PM
Why don't you just tell us what you're really trying to do, instead of all this "A" and "B" stuff.
You originally started this thread over four days ago, and in all that time no one here yet understands what you're trying to accomplish. Just tell us. What does the application do? Why is it important for one instance to complete before the second is launched? And what is this fixation on "global variables" if you understand that they are not shared between different instances of the same application (because of the arrangement of virtual memory space)?
Mike
PS: It is in fact possible to share a variable between different instances of the same exe, using a shared data segment (i.e., #pragma data_seg()), as explained in this article right here at Codeguru: "Sharing Data Between Different Instances of the Same Module (DLL or EXE)" at http://www.codeguru.com/Cpp/misc/misc/ipctechniques/article.php/c305/. Raymond Chen in his blog advises that there's a security risk with the approach (see "Why .shared sections are a security hole" at http://blogs.msdn.com/oldnewthing/archive/2004/08/04/208003.aspx), but if that's acceptable there's no reason not to use shared data segments. I don't think you are using this approach but tell us if you are.
frutti42
August 30th, 2005, 01:08 PM
Sorry. I know this is very confusing but I hope this explains it a bit clearer.
My program is integrated with another program. By selecting my program’s name from the other program’s menu item, it launches my application. Now the trick is this program in which my program is integrated with, creates 2 instances of my program. The first instance in which bCreateOnce is set to TRUE should never be terminated. That’s why it’s important that this variable gets set at the correct time. So, when running inside this program, I need to have two instances running for it to work. When run outside of this program, only one instance is needed. That’s why there exists another mutex that checks to see if only one instance of the program is running.
When the menu item is selected, the other program automatically calls InitInstance().The variable is set to FALSE at that time. The first instance should have the variable set to TRUE and that should happen first and only once. When it tries to create the mutex the second time around in OnNotify, I thought it would detect that the mutex already exists but it keeps saying it doesn’t. This then sets the variable to TRUE again. I need it to be TRUE only once.
This is the order in which I’d like things to happen:
1. Set bCreateOnce to TRUE.
2. Instance gets created but window does not show.
3. Upon a call to CreateProcess, bCreateOnce will be FALSE. This will create a mutex to ensure only a single visible instance of the program is running.
4. Each time the menu item is selected again, OnNotify should see that there already exists a mutex named notify so that it will not set the bvCreateOnce to TRUE again and again. Does ReleaseMutex allow the mutex to be created again? Maybe that is the problem.
5. If the user attempts to select the menu item again when the second instance is already running with the program window open, it will detect that the mutex has been created and it will fail.
The problem with code below is that the AfxGetApp()->m_pszExeName named mutex gets created first and then gets interrupted by the other thread. This thread calls InitInstance and carries the value of TRUE for bCreateOnce. Then the first instance continues running and displays the program window. It finishes and then CreateProcess is called. It detects that the mutex was already created. Thus deleting the first instance. How can I stop the first instance from creating the mutex? If I inserted an AfxMessageBox, it stalls it long enough to read in the TRUE value from OnNotify.
MyApp::InitInstance()
{
if (!bCreateOnce) //check if my program is running inside or outside the other program
{
// Run only one instance of program
m_hOneInstance = ::CreateMutex(NULL, FALSE, AfxGetApp()->m_pszExeName);
DWORD dwMutexErr = GetLastError();
if (dwMutexErr == ERROR_ALREADY_EXISTS)
{
CWnd *pPrevWnd = CWnd::GetDesktopWindow()->GetWindow(GW_CHILD);
while (pPrevWnd)
{
if ( ::GetProp(pPrevWnd->GetSafeHwnd(), AfxGetApp()->m_pszExeName) )
{
AfxMessageBox("Window found.");
if ( pPrevWnd->IsIconic() )
pPrevWnd->ShowWindow(SW_RESTORE);
pPrevWnd->SetForegroundWindow();
pPrevWnd->GetLastActivePopup()->SetForegroundWindow();
break;
}
pPrevWnd = pPrevWnd->GetWindow(GW_HWNDNEXT);
}
return FALSE;
}
}
else
AfxMessageBox("bCreateOnce is true and mutex was not created.");
if (!bCreateOnce) //do not show window for first instance
{
show window
}
}
STDMETHODIMP CWrapper::::OnNotify()
{
theApp.m_hCheckInstance = ::CreateMutex(NULL, FALSE, "notify");
if (theApp.m_hCheckInstance)
{
DWORD dwMutexErr = GetLastError();
if (dwMutexErr == ERROR_ALREADY_EXISTS)
theApp.bCreateOnce = FALSE;
else //should be TRUE only once
{
WaitForSingleObject(theApp.m_hCheckInstance, INFINITE);
theApp.bCreateOnce = TRUE;
theApp.InitInstance();
ReleaseMutex(theApp.m_hCheckInstance);
}
}
………more code
Does ReleaseMutex allow the mutex to be created again? Maybe that is the problem.Without code-tags I cannot say if that is the problem, but if you Release all handles to a Mutex, then the Mutex is closed, and you're allowed to 'recreate' it.
- petter
kirants
August 30th, 2005, 03:15 PM
Well.. Release mutex releases ownership of the mutex only. The mutex is still lying around.
A mutex object ceases to exist when all users of the mutex have called CloseHandle so kernel can clean it up.
wildfrog
August 30th, 2005, 03:24 PM
Well.. Release mutex releases ownership of the mutex only. The mutex is still lying around.You're absolutely right, and I'm totally wrong (don't know why I said that). :o
But I stand firm on the 'code-tags' part. :rolleyes:
- petter
kirants
August 30th, 2005, 03:31 PM
don't know why I said that. :o
Time to take a break, probably :cool:
But I stand firm on the 'code-tags' part. :rolleyes:
I fully second you.. :wave:
frutti42
August 30th, 2005, 03:50 PM
Sorry about that. The code tags have been inserted. :)
wildfrog
August 30th, 2005, 07:18 PM
Ok, being a programmer (or whatever you call it) and having seen lots of different 'design specifications'... some poor, some really bad, those with no design at all, and those I just don't understand (yup, yours fall into the latter one) I'm used to make up my own problems instead... and then try to solve them.
Here is my latest contribution.
Attached is a small and probably buggy console application that works like this:
1. If you run it from command prompt (or any application that is named 'cmd.exe') it will allow two instances. One 'invisible' and one 'visible'.
2. If you run it from any other application (any application not named 'cmd.exe') it will allow one 'visible' instance.
3. It will not allow two 'visible' instances (you cannot both execute one from cmd.exe and one from another app) at the same time.
Would that be to any help?
- petter
PS! I tried to use semaphores, but it just didn't seem right...
frutti42
August 31st, 2005, 12:15 PM
Thanks Wildfrog. All I needed was the function GetParentProcessExecutableName() to figure out which program was executing it. I was then able to set the variable accordingly...no mutexes and extra code needed. Thanks again and thanks everyone for trying to help me solve this very confusing puzzle. Your help is very much appreciated.
codeguru.com
Copyright Internet.com Inc., All Rights Reserved.