 |
|
 |
My solution is the named mutex. My project uses MFC/VC6.
CXApp::CNCardApp()
{
m_hRunning = NULL;
}
BOOL CXApp::InitInstance()
{
// m_hRunning is a HANDLE of member variable of CXApp.
m_hRunning = ::CreateMutex(NULL, TRUE, _T("Here is the name of mutex."));
if(m_hRunning)
{
if(ERROR_ALREADY_EXISTS == ::GetLastError())
return FALSE;
}
......
}
int CXApp::ExitInstance()
{
if(NULL != m_hRunning)
{
::CloseHandle(m_hRunning);
m_hRunning = NULL;
}
return CWinApp::ExitInstance();
}
It really works. Is there any problem?
|
|
|
|
 |
|
 |
It should be fine.
After all this time I'm not entirely agree with the article. It's just lame
Should I ever work again on windoze, I would try using something like a unix local socket for the purpose. connect() call would be used to check it there is already another instance running, and if so send() would be used to send command line arguments to the first instance. No explicit locking is required. Something like this:
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
void do_send(int s, void const* buf, size_t len)
{
while(len)
{
ssize_t n = write(s, buf, len);
if(n < 0)
abort();
len -= n;
buf = (char*)buf + n;
}
}
int do_recv(int s, void* buf, size_t len)
{
while(len)
{
ssize_t n = read(s, buf, len);
if(n < 0)
abort();
else if(!n) return -1;
len -= n;
buf = (char*)buf + n;
}
return 0;
}
int main(int ac, char** av)
{
int s = socket(PF_UNIX, SOCK_STREAM, 0);
if(-1 == s)
abort();
sockaddr_un sa = { AF_UNIX, "\0my_app" };
while(true)
{
if(connect(s, (sockaddr*)&sa, sizeof sa))
{
if(bind(s, (sockaddr*)&sa, sizeof sa))
continue; listen(s, 1);
break;
}
else
{
do_send(s, &ac, sizeof ac);
for(; ac--; ++av)
{
int len = strlen(*av);
do_send(s, &len, sizeof len);
do_send(s, *av, len);
}
exit(0);
}
}
while(true)
{
fd_set read;
FD_ZERO(&read);
FD_SET(s, &read);
int r = select(s + 1, &read, 0, 0, 0);
if(r < 0)
break; if(r > 0)
{
if(FD_ISSET(s, &read))
{
int c = accept(s, 0, 0);
if(-1 == c)
continue;
if(do_recv(c, &ac, sizeof ac))
{
close(c);
continue;
}
for(int i = 0; i < ac; ++i)
{
int len;
if(do_recv(c, &len, sizeof len))
break;
char arg[len + 1];
if(do_recv(c, arg, len))
break;
arg[len] = 0;
printf("arg %u: %s\n", i, arg);
if(1 == i && !strcmp("stop", arg))
exit(0);
}
close(c);
continue;
}
}
}
}
$ ./exp &
[1] 18484
$ ./exp hi there
arg 0: ./exp
arg 1: hi
arg 2: there
$ ./exp bye
arg 0: ./exp
arg 1: bye
$ ./exp stop
arg 0: ./exp
arg 1: stop
[1]+ Done ./exp
$
--
Maxim Yegorushkin
|
|
|
|
 |
|
 |
Above code sufficient to make app as single instance but how do you pass any command line args to First instance ???
|
|
|
|
 |
|
 |
Here is what I inted to do when using events for process communication.
step1:
Create an unique event in the ininstance method in Reset mode.
Check if event is already created.
If event not created then create event and create screenControl thread to listen for set/reset of that event.
If event is there then means window is already present and hence
set the event here so that running thread can wakeup.
// OnlyOne.cpp
// global data
HANDLE hEvent;
int ShutDownFlag;
void ScreenMonitor(LPVOID pParam);
// COnlyOneApp initialization
BOOL COnlyOneApp::InitInstance()
{
///// other stuff...
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(COnlyOneDoc),
RUNTIME_CLASS(CMainFrame), RUNTIME_CLASS(COnlyOneView));
AddDocTemplate(pDocTemplate);
//------
hEvent = CreateEvent(NULL,TRUE,FALSE,_T("ONLYONE-APP"));
AlreadyRunning = ( ::GetLastError() == ERROR_ALREADY_EXISTS || ::GetLastError() == ERROR_ACCESS_DENIED);
if (AlreadyRunning) {
MessageBox(NULL,"Already Running....","Message!!",MB_OK);
SetEvent(hEvent);
return TRUE;
}
//-------
// Parse command line for standard shell commands, DDE, file open
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
// Dispatch commands specified on the command line
if (!ProcessShellCommand(cmdInfo))
return FALSE;
//--------
CWinThread *wndThread = AfxBeginThread((AFX_THREADPROC)ScreenMonitor, m_pMainWnd->GetSafeHwnd(),THREAD_PRIORITY_NORMAL,0,0);
if (wndThread == NULL)
{
MessageBox(NULL,"Could not Create Thread...","MSG",MB_OK);
return FALSE;
}
//-------
m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->UpdateWindow();
return TRUE;
}
step 2:
Thread method. This method waits for events to set. When event is set which signifies same application tried to start, this thread brings first instance in the foreground.
// COnlyOneApp message handlers
void ScreenMonitor(LPVOID pParam)
{
CWnd* wnd;
while(ShutDownFlag)
{
WaitForSingleObject (hEvent, INFINITE);
wnd = CWnd::FromHandlePermanent(static_cast(pParam));
if (wnd->IsIconic())
wnd->ShowWindow(SW_RESTORE);
wnd->SetForegroundWindow();
ResetEvent(hEvent);
}
}
|
|
|
|
 |
|
 |
This is why Microsoft invented named mutexes and later added prefixes of Global\ and Local\
You don't need any of this code.
|
|
|
|
 |
|
 |
Nice to see you almost took my comments on board about supporting console applications, yours supports Win32, but not quite activation for a console application (you can't do this without threads).
This does make your version SIMPLE, small and very inflexible. Your example also demonstrates some of the worst aspects of C++ providing little abstraction from the user and your inner workings (maybe this was not one of you objectives).
It looks also like you still don't understand the use of synchronization objects for protecting shared memory access. Or the use of sleeping threads very very very low CPU overhead.
As for starting applications at the same time, multi-processor systems, terminal server, remote starting applications, or applications started by other applications.
Your solution is simple, but there again so is the version in the MSDN, I prefer my example as it teaches more programming concepts to the reader.
Thanks for sharing you example with the world anyway.
BTW, Did you actually read my objectives?
- Use of sleeping threads to handle activation, and not use post/send message.
- Abstraction classes, using "pimple" methods, interface and implementation classes.
- Use of a memory mapped file to share data between instances.
- Low user footprint, instantiate a single object and call create; user has to do no more.
- Allow command line passing, sending command line from new instance to the old instance.
|
|
|
|
 |
|
 |
Thank you for your comments.
I'll add the synchronization but it will break the simplicity.
|
|
|
|
 |
|
 |
Say, for example, that the user starts 2 other instances of the application:
- the first writes the command line and posts the message
- the second writes (or -worse- partially writes) its command line before the already running instance gets the first message
So, what happens? You can easily guess...
You should at least use a mutex, or some other form of synchronization, to protect the buffer until its content gets parsed by the receiving instance.
The same applies for the first time, when the app creates the shared memory: what would happen if you start 2 instances for the first time almost simultaneously?
Paolo
------
"airplane is cool, but space shuttle is even better" (J. Kaczorowski)
|
|
|
|
 |
|
 |
Please, tell me the way I can start more then 1 instance of any application simultaneously.
|
|
|
|
 |
|
 |
*joke* I guess you can try with two computers!
Don't mind his post!
|
|
|
|
 |
|
 |
So you don't mind to write correct code...
BTW, there are several ways to start multiple instances *almost* simultaneously. For example selecting some files associated with the application and pressing Enter. How many times it happened to me, while I was trying to open only one!
Or one could have a script or batch file to pass some items or commands to a running application through the command line.
Or it could happen that you click two files separately and because of the heavy CPU load the code portion that handles multiple instances is executed *almost* simultaneously.
Don't you think an additional synchronization object is an acceptable compromise?
Paolo
------
"airplane is cool, but space shuttle is even better" (J. Kaczorowski)
|
|
|
|
 |
|
 |
In the case of pressing Enter while having multiple files selected assotiated with application I must ensure that the first instance will get all the file names. All-or-nothing. To do so, all the other instances must communicate with the first instance to pass its command lines. This communication must be serialized and the first instance can't ignore it. Adding a mutex does not solve this problem.
This will not be a simple solution.
I'll think about this and check out does race condition can really take place.
|
|
|
|
 |
|
 |
MaximE wrote:
This communication must be serialized and the first instance can't ignore it. Adding a mutex does not solve this problem.
You can use the mutex if you pass the ownership to the instance receiving the message. That is, when creating the shared memory you simply use the mutex as a critical-section wrapper, and when sending the message the calling instance gains ownership with WaitForSingleObject and the receving one releases it with ReleaseMutex. Other instances will wait until each message is processed and will be automatically serialized.
Paolo
------
"airplane is cool, but space shuttle is even better" (J. Kaczorowski)
|
|
|
|
 |
|
 |
Thank you for comments. I'll add it.
|
|
|
|
 |
|