A Single Instance Application Class

There are two new paragraphs

What's new in the latest version
Using the DDE to make your application open a document with a double-click on its icon

Introduction

Making single-instance an application means enabling the application to recognize, at startup, if another running instance of itself exists so that, in this case, the application stops its execution. Generally, before quitting, the new instance retrieves the main window handle of the existing instance via the FindWindow() or FindWindowEx() function and uses this handle to bring the application window to foreground.
The problem can be solved in several ways. The most known solutions are:

  • Using a CMutex (a synchronization object global to the system).
  • Using shared data sections.

The small class described in this article, CSingleInstanceApp, uses the first method to implement the single-instance behaviour in a MFC application. It makes very simple to add the feature to a new project, eliminating the necessity of rewriting a consistent amount of code.

Comparison with other similar classes

In this section, I summarize the main features that distinguish my class from other similar classes you can find in this site. I hope this will help the reader to decide which code suits his needs better.

  • CSingleInstanceApp is an extension of CWinApp. This reduces the work needed to add the single-instance behaviour.
  • It uses a safe and stable method to build the class name, avoiding conflicts with other running applications.

Implementation details

For details about how to use a CMutex to implement the single-instance you can read the article "Single Instance of an application Class" by Kevin Lussier. In this article, I will discuss only the method I have used to build the window class name string. I assume that you know what a window class is and the reason why Windows requires the class registration before creating a window.
The key point to implement single-instance is that we need the registered class name to be the same in every instance of the application. Moreover, it is very important that two different applications don't use the same class name. The framework uses AfxRegisterWndClass() to register the window class but, unfortunately, this function registers a class name that is different in different instances of the same application (you can see it using the GetClassName() function). Thus, we cannot pass this string to FindWindow(). But what is the class name registered by AfxRegisterWndClass()?
To answer this question, once again, we have to browse in the MFC source code. We discover an interesting thing: AfxRegisterWndClass() generates a name for the class with the following code:

// generate a synthetic name for this class
HINSTANCE hInst = AfxGetInstanceHandle();
	if (hCursor == NULL && hbrBackground == NULL && hIcon == NULL)
		wsprintf(lpszName, _T("Afx:%x:%x"), (UINT)hInst, nClassStyle);
	else
		wsprintf(lpszName, _T("Afx:%x:%x:%x:%x:%x"), (UINT)hInst, nClassStyle,
		(UINT)hCursor, (UINT)hbrBackground, (UINT)hIcon);

Well, the idea behind the CSingleInstanceApp class is to mimic this way to generate the name string. hInst (the application instance handle), nClassStyle (the window class style), hCursor (the window cursor handle) and hbrBackground (the window background brush handle) are the same in every instance of the application. Only hIcon changes, so simply we cut it off from the class name string. Moreover, we have to make the class name application-dependent by adding to it the application name returned by the AfxGetAppName() function. This is exactly what the CheckSingleInstance() member function does. This is an excerpt from CheckSingleInstance():

if (hCursor == NULL && hbrBackground == NULL && hIcon == NULL)
	m_strClassName.Format(_T("%s:%x:%x"), lpstrAppName,
		(UINT)hInst, nClassStyle);
else
	m_strClassName.Format(_T("%s:%x:%x:%x:%x"), lpstrAppName,
		(UINT)hInst, nClassStyle, (UINT)hCursor, (UINT)hbrBackground);

How to use CSingleInstanceApp

Using this class requires the following steps:

  • Include the "CSingleInstanceApp.c" and ".h" in your project.
  • At the beginning of the application class header file #include "SingleInstanceApp.h". In the class declaration replace CWinApp with CSingleInstanceApp.
  • Add the following as the first line of the InitInstance() body of your application class:
if (!CheckSingleInstance(IDR_MAINFRAME))
	return FALSE;
  • Add the following as the first line of the PreCreateWindow() body of your frame window class:
cs.lpszClass = ((CMyApp*)AfxGetApp())->GetClassName();

Operations for CSingleInstanceApp

BOOL CheckSingleInstance(UINT nID);
CString GetClassName() const;

What's new in the latest version

The previous version of the class contained a bug: the main window produced an horrible flickering when trying to move or resize it. This is due to the fact that the window class style used the CS_HREDRAW and the CS_VREDRAW styles. Moreover, the background brush handle must be NULL, since for the mainframes, the background is automatically painted.

Using the DDE to make your application open a document with a double-click on its icon

Lots of persons noted that the application can't open another document besides the first by double-clicking its icon. This is not due to a CSingleInstanceApp bug.

Briefly, the DDE (Dynamic Data Exchange can be defined as a protocol to implement a simple form of inter-process communication). The MFC application is perfectly capable to recognize and handle the DDE command to open a document.
This feature is enabled in the InitInstance() body of your application class with the line

EnableShellOpen();

However, to enable this characteristic, you need to register the document type "manually" (unfortunately, the framework doesn't do it). You can do this from any explorer window, by selecting "Folder options" from the "View" menu. Go to the "File types" section and select your document type. Now press the "Edit..." button. When the modify dialog appears press the new "Edit..." button. Select the "Use DDE" checkbox. In the "DDE Message" edit box write the following string:

[open("%1")]

Now, disable the following line in the InitInstance() body of your application.

RegisterShellFileTypes()	// Disable this line to receive DDE messages

Now your application is able to open documents with a double click even while it's running.

Author's note

I'm continuously working to improve this class. I'll be grateful to you if you mail me your comments, advice, or bug apparition reports!

Download Demo and Source Code

Updated: May, 27 1998



Comments

  • Dialog based apps still don't work!

    Posted by Legacy on 03/15/2001 12:00am

    Originally posted by: Richard Parsell

    I've tried the methods noted in the examples and they work
    fine for apps with standard windows. The comment about a fix for dialog based apps does work, but in my case I can't depend on having the dialog title to get the handle.
    I want to use the class name to pop up the dialog.

    If anyone has a solution please let me know!
    thanks

    Reply
  • Minor fix if it's not drawing the window

    Posted by Legacy on 02/09/2000 12:00am

    Originally posted by: Otto

    I tried this one, and it worked, except that the main frame wasn't being filled in. This is using Visual C++ 5.0 (Dev Studio 97).

    The key was to change this:
    wndclass.hbrBackground = NULL;

    to this:
    wndclass.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);

    If you leave it NULL, the background will be not be drawn at all, at least not with my app, and you get nasty undrawn leftover stuff when the window is moved or resized. Also, when the window is first created, it looks transparent.

    Reply
  • Thanks!

    Posted by Legacy on 01/20/2000 12:00am

    Originally posted by: Martin Sawyer

    Thanks for helping me solve this problem.
    Your code worked flawlessly. Good job

    Reply
  • Resource Leak in destructor?

    Posted by Legacy on 10/02/1998 12:00am

    Originally posted by: Victor Vogelpoel

    [Credits to BoundsChecker]
    I'm not sure if it's necessary, but you may have to call CloseHandle on m_hMutex AFTER the mutex was released in the destructor. BC complains about a system object not being released...

    CSingleInstanceApp::~CSingleInstanceApp()
    {
    // Release the mutex
    if ( m_hMutex != NULL ) {
    ReleaseMutex( m_hMutex );
    CloseHandle(m_hMutex);
    }
    }

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Today's agile organizations pose operations teams with a tremendous challenge: to deploy new releases to production immediately after development and testing is completed. To ensure that applications are deployed successfully, an automatic and transparent process is required. We refer to this process as Zero Touch Deployment™. This white paper reviews two approaches to Zero Touch Deployment--a script-based solution and a release automation platform. The article discusses how each can solve the key …

  • On-demand Event Event Date: December 18, 2014 The Internet of Things (IoT) incorporates physical devices into business processes using predictive analytics. While it relies heavily on existing Internet technologies, it differs by including physical devices, specialized protocols, physical analytics, and a unique partner network. To capture the real business value of IoT, the industry must move beyond customized projects to general patterns and platforms. Check out this webcast and join industry experts as …

Most Popular Programming Stories

More for Developers

RSS Feeds