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

More by Author

Must Read