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

  • Live Event Date: August 20, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT When you look at natural user interfaces as a developer, it isn't just fun and games. There are some very serious, real-world usage models of how things can help make the world a better place – things like Intel® RealSense™ technology. Check out this upcoming eSeminar and join the panel of experts, both from inside and outside of Intel, as they discuss how natural user interfaces will likely be getting adopted in a wide variety …

  • Savvy enterprises are discovering that the cloud holds the power to transform IT processes and support business objectives. IT departments can use the cloud to redefine the continuum of development and operations—a process that is becoming known as DevOps. Download the Executive Brief DevOps: Why IT Operations Managers Should Care About the Cloud—prepared by Frost & Sullivan and sponsored by IBM—to learn how IBM SmartCloud Application services provide a robust platform that streamlines …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds