WTLVisual C++ 7.0C++/CLIWindows 2000Visual C++ 6.0Windows XPMFCIntermediateDevVisual StudioWindowsC++.NET
There can be only one...






4.69/5 (9 votes)
Limiting an application to a single instance.
Introduction
When reading Joseph Newcomer's article about this matter, I thought there must be a way to do this simpler. So based on his excellent work the past few years I've spent all my time devoted on this theorem. In the mean time I never saw any daylight and I've lost all my friends (Just kidding' ;)...
But after this long research and keeping it secret for too long I finally bring out the goods just to make sure such an important discovery like this doesn't fade away in history... uhum...
So here we go:
- We need a registered message that our application will respond to. Make this one global in your application.
static const UINT WM_CHECK_ITS_ME = RegisterWindowMessage("MY_UNIQUE_GUID");
- Now we create a mutex somewhere at the start of your program:
HANDLE hMutexOneInstance = CreateMutex( NULL, FALSE, _T("MY_UNIQUE_GUID"));
- Check the last error to see what happened:
bool AlreadyRunning = ( GetLastError() == ERROR_ALREADY_EXISTS || GetLastError() == ERROR_ACCESS_DENIED);
- Then we send out a message to all top level windows to make sure it pops up and becomes the active window. The trick here is to use HWND_BROADCAST, which is a little bit undocumented.
if ( AlreadyRunning ) { DWORD result; LRESULT ok = SendMessageTimeout(HWND_BROADCAST, WM_CHECK_ITS_ME, 0, 0, SMTO_BLOCK | SMTO_ABORTIFHUNG, 200, &result); return FALSE; // Here we quit this application // or exit(0); // or PostQuitMessage() ... etc... }
- The already running application needs to respond the registered window message, so we add a message handler to the application.
If you are using MFC edit your messagemap:ON_REGISTERED_MESSAGE( WM_CHECK_ITS_ME, OnCheckItsMe )
or WTL:MESSAGE_HANDLER(WM_CHECK_ITS_ME, OnCheckItsMe)
or plain Windows API:LRESULT CALLBACK MyWindowProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) { if (msg == WM_CHECK_ITS_ME) { ... return 0; } .... return ...; }
- Now in the handler for this message we just make sure this application becomes the foreground and active one.
LRESULT CMainFrame::OnCheckItsMe(...) { // If we are using Chris Maunder's CSystemTray it's handy m_SystemTray.MaximiseFromTray(this->m_hWnd); // or else you can call all sorts of restore/maximise functions: - ShowWindow(SW_RESTORE); - SetForegroundWindow(); - SetWindowPlacement(m_MyWindowPlacement); return WM_CHECK_ITS_ME; }
- That should work!