CInstanceChecker v1.25
Welcome to CInstanceChecker, a freeware C++ class to make your
app into a single instance. Limiting your app to single instance is more tricky
in Win32 with the removal of the hPrevInstance parameter from WinMain and the introduction
of separate address spaces.
There are numerous examples already out there of making your app single instance,
but some published code on the Internet require knowledge of undocumented or heavy
duty MFC.
Other methods such as using FindWindow & FindWindowEx are not 100% bullet proof
due to the pre-emptive Win32 environment.
This class internally uses a memory mapped file (MMF) into which the handle of
the main window of your application is stuffed. When a second instance of your app
is run, it detects that the memory mapped file exists, gets the window handle of
the first instance from the MMF and reactivates it.
Features
- Very simple API all encapsulated in a simple C++ class.
- Does not require any messing around with window or captions styles to
make your application window attributes unique.
- Much more robust implementation that other methods as already mentioned.
- The classes are fully Unicode compliant and Unicode build configurations
are included in the workspace file.
Usage
- To use the class in an MFC SDI or MDI app simply include sinstance.cpp in
your project and #include sinstance.h in your apps source file and modify
your code as follows:
- class CMyApp: public CWinApp
{
....
CInstanceChecker m_InstanceChecker
....
CMyApp::CMyApp() : m_InstanceChecker(_T("Your unique
instance identifier e.g. a GUID"))
{
....
CMyApp::InitInstance()
{
....
if (m_InstanceChecker.PreviousInstanceRunning())
{
AfxMessageBox(_T("Previous version detected, will now restore
it"), MB_OK | MB_ICONINFORMATION);
m_InstanceChecker.ActivatePreviousInstance();
return FALSE;
}
....
// create main MDI Frame window
CMainFrame* pMainFrame = new CMainFrame;
m_pMainWnd = pMainFrame;
if (!pMainFrame->LoadFrame(IDR_MAINFRAME))
return FALSE;
//Track it so any other instances can find it.
m_InstanceChecker.TrackFirstInstanceRunning(m_pMainWnd->GetSafeHwnd());
.....
}
- For dialog based apps, just do the following:
- class CTestApp: public CWinApp
{
....
CInstanceChecker m_InstanceChecker
....
CMyApp::CMyApp() : m_InstanceChecker(_T("Your unique
instance identifier e.g. a GUID"))
{
....
BOOL CTestApp::InitInstance()
{
CTestDlg dlg;
if (m_InstanceChecker.PreviousInstanceRunning())
{
AfxMessageBox(_T("Previous version detected, will now restore
it"), MB_OK | MB_ICONINFORMATION);
m_InstanceChecker.ActivatePreviousInstance();
- m_pMainWnd = NULL;
return FALSE;
}
m_pMainWnd = &dlg;
int nResponse = dlg.DoModal();
....
}
- BOOL CTestDlg::OnInitDialog()
{
__super::OnInitDialog();
.....
//Track it so any other instances can find it.
theApp.m_InstanceChecker.TrackFirstInstanceRunning(GetSafeHwnd());
}
- The key difference between the mainframe based MFC app and the dialog
based MFC app is that the call to TrackFirstInstanceRunning must be deferred
to the OnInitDialog method as that is the first opportunity where we have
the dialog HWND available to us to track.
- That's all there is to it. Your applications should now be single instance.
- For those interested the nitty gritty of the code, have a look at sinstance.cpp
Copyright
- You are allowed to include the source code in any product (commercial, shareware,
freeware or otherwise) when your product is released in binary form.
- You are allowed to modify the source code in any way you want except you
cannot modify the copyright details at the top of each module.
- If you want to distribute source code with your application, then you are
only allowed to distribute versions released by the author. This is to maintain
a single distribution point for the source code.
Updates
v1.25 (9 March 2022)
- Updated copyright details
- Updated the code to use C++ uniform initialization for all variable
declarations.
v1.24 (17 March 2020)
- Updated copyright details.
- Fixed more Clang-Tidy static code analysis warnings in the code.
v1.23 (21 September 2019)
- Fixed a number of compiler warnings when the code is compiled with VS
2019 Preview
v1.22 (2 June 2019)
- Updated copyright details.
- Updated the code to clean compile on VC 2019
v1.21 (9 September 2018)
- Fixed a number of compiler warnings when using VS 2017 15.8.2
v1.20 (15 July 2018)
- Updated copyright details
- Fixed a number of C++ core guidelines compiler warnings. These changes
mean that the code will now only compile on VC 2017 or later.
v1.19 (30 October 2017)
- Updated copyright details.
- Replaced NULL with nullptr throughout the codebase. This means that the
code now requires VC 2010 at a minimum to compile.
- Replaced BOOL throughout the codebase with bool.
- Fixed problems with the code when the _ATL_NO_AUTOMATIC_NAMESPACE define
is used. Thanks to Victor Derks for reporting this issue.
v1.18 (4 March 2016)
- Updated copyright details.
- Update the sample app project settings to more modern defaults.
- Update the code to clean compile on VC 2010 - 2015
- Added SAL annotations to all the code.
- CInstanceChecker::PreviousInstanceRunning now uses FILE_MAP_READ flag
when attempting to open the file mapping
- The ActivatePreviousInstance method now includes a new HWND
hSender parameter.
- The sample app which uses a MFC CFrameWnd now shows some text
in the client area to tell end-users what to do to exercise the code.
- After updating the instructions on how to use the class, the code
which referenced an internal _SINSTANCE_DATA global static instance has been
refactored back into the main CInstanceChecker class
- CInstanceChecker::TrackFirstInstanceRunning now takes a HWND
hWindowToTrack parameter. This parameter now eliminates the need for the
GetWindowToTrack method.
- Reworked the internals of the CInstanceChecker class to avoid use
of MFC. Instead now all the class uses ATL replacements for equivalent MFC
functionality.
- Reworked the internals of the QuitPreviousInstance method.
- Removed the need for the ActivateChecker and GetMMFFilename
methods.
- The structure which is put into the memory mapped file now is 8
bytes in size. This is to allow interop between Win32 and Win64 instances of
the same application.
- Refactored the code in ActivatePreviousInstance &
QuitPreviousInstance which finds the previous HWND into a new
FindPreviousHWND method.
- Reworked the code which serializes access to all instances of
CInstanceChecker and in the process removed the need for the mutex which
protects the memory mapped file.
v1.17 (2 February 2008)
- Updated copyright details
- Removed VC 6 style classwizard comments from the sample apps code
- Updated ActivatePreviousInstance method to support Win64 compliant data
- ActivatePreviousInstance now takes a "dwTimeout" parameter which it now
uses internally as the timeout when calling SendMessageTimeout instead of SendMessage.
The code now uses SendMessageTimeout instead of SendMessage to ensure we do
not hang if the previous instance itself is hung. Thanks to Paul Shore for suggesting
this update.
- Updated the sample apps to clean compile on VC 2008
v1.16 (17 March 2007)
- Updated copyright details.
- Optimized _INSTANCE_DATA constructor code
- Reworked how the method CInstanceChecker::GetMMFFilename creates the name
of the memory mapped filename the code requires for sharing. Now the main instance
name appears before the hard coded string. This ensures that the CInstanceChecker
class works correctly for terminal sessions i.e. kernel objects prefixed with
the value "Local\". Thanks to Mathias Berchtold for reporting this issue.
- Updated the sample app code to clean compile on VC 2005.
- QuitPreviousInstance now uses GetLastActivePopup API to ensure it posts
the WM_QUIT message to the correct window of the previous instance.
v1.15 (7 July 2006)
- Updated copyright details.
- Addition of CSINGLEINSTANCE_EXT_CLASS and CSINGLEINSTANCE_EXT_API which
allows the class to be easily used in an extension DLL.
- Removed derivation from CObject as it was not really needed.
- Updated the documentation to use the same style as the web site.
- Code now uses newer C++ style casts instead of C style casts.
- Fixed a number of level 4 warnings in the sample app.
- Updated code to compile cleanly using VC 2005.
v1.14 (30 May 2005)
- Fix for a crash where CWnd::GetLastActivePopup can sometimes return a NULL
pointer. Thanks to Dominik Reichl for reporting this bug.
v1.13 (9 May 2004)
- Updated the copyright details.
- Extended CInstanceChecker::ActivatePreviousInstance to now allow the command
line of the
second app to be passed to the original app. By default the parameter is NULL,
meaning that
you get the original behaviour which just activates the previous instance. To
respond to this
information you should add the following to your mainfrm module:
mainfrm.h
afx_msg LRESULT OnCopyData(WPARAM, LPARAM);
mainfrm.cpp
LRESULT CMyFrameWnd::OnCopyData(WPARAM wParam, LPARAM lParam)
{
COPYDATASTRUCT* pCDS = reinterpret_cast<COPYDATASTRUCT*>(lParam);
TCHAR* pszCmdLine = static_cast<TCHAR*>(pCDS->lpData);
if (pszCmdLine)
{
//DO SOMETHING with pszCmdLine here such as call AfxGetApp()->OpenDocumentFile(pszCmdLine);
}
return TRUE;
}
Also hook up your onCopyData to the windows message map using
ON_MESSAGE(WM_COPYDATA, OnCopyData)
Thanks to Ingo H. de Boer for providing this nice update.
- Following a discussion on the Codeproject.com discussion forum for
CSingleInstance on what exactly a single instance app means, Daniel Lohmann
has produced a simple function called CreateUniqueName which given a number
of settings as flags, will produce a name which is unique. You can then use this name
in the constructor for CInstanceChecker. The concept of a single instance app
is complicated by the concept of Window stations and desktops as used by NT
Services and Windows Terminal Services. In addition you might want to allow
your program to be run once per user.
v1.12 (6 February 2003)
- Was missing a call to ReleaseLock in CInstanceChecker::ActivatePreviousInstance.
Thanks to Pierrick Ingels for reporting this problem.
v1.11 (30 October 2002)
- The name of the internal memory mapped file is now based on the Mutex name
rather than the application name. An example: a client was writing a webcam
application and wanted it to run with multiple configuration for multiple camera
support. So the app can run multiple times as long as a special configuration
is given on the command line. But for that configuration only one instance is
allowed. Using the application name for the memory mapped file was tying the
single instance to the app rather than the unique mutex name. Thanks to Frank
Fesevur for this nice update.
1 May 2002
- Updated code snippets in documentation to describe how to use the class.
v1.10 (23 March 2002)
- Provided a QuitPreviousInstance method. Thanks to Jon Bennett for providing
this.
v1.09 (31 August 2001)
- Made the name of the mutex which the class uses to serialize access to itself
a parameter to the constructor. That way multiple independent apps do not block
each other while they are calling into the CSingleInstance class. Thanks to
Eugene Shmelyov for spotting this problem.
v1.08 (21 July 2001)
- Fixed a bug in the sample dialog app which was causing the app to crash.
The important change is to make sure "m_pMainWnd" is set to NULL before you
return from InitInstance. See the module "sinstancedlg.h" or the Usage section
above for the correct way to use the code in a dialog based app.
v1.07 (17 June 2001)
- Moved most of the code from CInstanceChecker::CInstanceChecker to CInstanceChecker::ActivateChecker.
This allows client code to turn on or off the instance checking code easily.
Thanks to Anders Rundegren for this addition.
v1.06 (11 January 2001)
- Now allows multiple calls to PreviousInstanceRunning without ASSERT'ing
- Removed some unnecessary VERIFY's from ActivatePreviousInstance
- Made the MMF filename used modifiable via a virtual function GetMMFFilename
- Made the window to track modifiable via a virtual function GetWindowToTrack
- Made destructor virtual since the introduction of other virtual functions
in the class
- Removed a number of unnecessary verifies
- Changed the meaning of the return value from TrackFirstInstanceRunning
v1.05 (1 January 2001)
- Added a number of asserts to CInstanceChecker::ActivatePreviousInstance
- Now includes copyright message in the source code and documentation
v1.04 (17 May 2000)
- Now includes a dialog app to demo how to use the code in a dialog based
app. Also updated the documentation re dialog based apps.
v1.03 (15 May 2000)
- Serialized access to all of the CSingleInstance class to prevent race conditions
which can occur when you app is programmatically spawned
v1.02 (28 March 2000)
- Minor update to the documentation.
v1.01 (27 March 2000)
- Now ships with a VC 5 workspace.
- Fixed a potential handle leak where the file handle m_hPrevInstance was
not being closed under certain circumstances.
- The remaining changes were made by Neville Franks.
- Changed #pragma error in sinstance header file to #pragma message. Former
wouldn't compile under VC6
- Replaced above #pragma with #include.
- Added TrackFirstInstanceRunning(), MakeMMFFilename()
- Split PreviousInstanceRunning() up into separate functions so we can call
it without needing the MainFrame window.
- Changed ActivatePreviousInstance() to return hWnd.
v1.0 (29 July 1998)
API Reference
The API consists of the public methods of the class CInstanceChecker.
Note that the constructor for CInstanceChecker takes a string which is internally
used as the name for a mutex. You should pick a unique name for this to guarantee
that it will not conflict with other apps. The sample app provided with the code
just uses a GUID. You scan generate your own GUID value using the "GUIDGEN.exe"
utility. You should also read the
information about name uniqueness as documented in the v1.13 release on 9 May 2004
above. This includes important information about complications which can occur when
you take Windows Terminal Services, services and user accounts into mind.
CInstanceChecker::PreviousInstanceRunninging
bool CInstanceChecker::PreviousInstanceRunning()
Return Value
true if a previous instance of this application is running otherwise
false.
Remarks
In response to true being sent back a "single instance" program should call ActivatePreviousInstance
and abort prematurely from the current instance of the app.
CInstanceChecker::ActivatePreviousInstance
bool CInstanceChecker::ActivatePreviousInstance(LPCTSTR
lpCmdLine = nullptr,
ULONG_PTR dwCopyDataItemData =
0, DWORD dwTimeout
= 30000, HWND hSender = nullptr)
Return Value
true on success, else false.
Parameters
lpCmdLine The command line to send to the previous instance
via a WM_COPYDATA message.
dwCopyDataItemData The value to specify in the dwData variable
in the COPYDATASTRUCT used by the WM_COPYDATA message.
dwTimeout The timeout value to use in the internal call to SendMessageTimeout
in this method.
hSender The sender HWND to use in the internal call to SendMessageTimeout.
Remarks
Activates the previous instance of the app and optionally passes it a command
line string.
CInstanceChecker::TrackFirstInstanceRunning
bool CInstanceChecker::TrackFirstInstanceRunning(HWND
hWindowToTrack)
Return Value
true on success, else false.
Parameters
hWindowToTrack The main HWND of the current instance which is to be
tracked. Normally this would be the HWND value returned in AfxGetMainWnd() if
your code is using MFC.
Remarks
You should call this when you have detected that you are the first instance of
your app to run (PreviousInstanceRunning returning false). This allows other instances
to track this instance, so that they can activate the first instance.
CInstanceChecker::QuitPreviousInstance
void CInstanceChecker::QuitPreviousInstance(int nExitCode
= 0)
Remarks
Asks the previous instance to quit by posting it a WM_QUIT message, the nExitCode
parameter corresponds to the exit code which PostQuitMessage will get in the app
as a result of the WM_QUIT message.
CInstanceChecker::FindPreviousHWND
bool CInstanceChecker::FindPreviousHWND(HWND& hPrevWnd)
Return Value
true on success, else false.
Parameters
hPrevWnd Upon successful return from this method (meaning a previous
instance exists), this parameter will contain the HWND of the previous instance.
Remarks
Finds the previous HWND for the application. This method is used internally
in ActivatePreviousInstance and QuitPreviousInstance.
Contacting the Author
PJ Naughter
Email: pjna@naughter.com
Web: http://www.naughter.com
9 March 2022