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
Usage
Copyright
History
API Reference
Contacting the Author

 

 

 

Features

 

 

 

Usage

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());
.....
}
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());
}

 

 

 

Copyright

 

 

 

Updates

v1.25 (9 March 2022)

v1.24 (17 March 2020)

v1.23 (21 September 2019)

v1.22 (2 June 2019)

v1.21 (9 September 2018)

v1.20 (15 July 2018)

v1.19 (30 October 2017)

v1.18 (4 March 2016)

v1.17 (2 February 2008)

v1.16 (17 March 2007)

v1.15 (7 July 2006)

v1.14 (30 May 2005)

v1.13 (9 May 2004)

v1.12 (6 February 2003)

v1.11 (30 October 2002)

1 May 2002

v1.10 (23 March 2002)

v1.09 (31 August 2001)

v1.08 (21 July 2001)

v1.07 (17 June 2001)

v1.06 (11 January 2001)

v1.05 (1 January 2001)

v1.04 (17 May 2000)

v1.03 (15 May 2000)

v1.02 (28 March 2000)

v1.01 (27 March 2000)

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