Click here to Skip to main content
13,351,225 members (47,018 online)
Click here to Skip to main content
Add your own
alternative version


53 bookmarked
Posted 20 May 2002

Limiting an application to a single Instance - the MFC way

, 30 Aug 2002
Rate this:
Please Sign up or sign in to vote.
Another approach for limiting application instance


When first posted the article I wrote: "I have seen many samples on limiting application instance but some of them were too complicated while the others required multiple additions in different classes because of message handling on window level." Well, some time ago I understood that it is better not to make statements like that because actually faced so much problems that I lost myself maybe not in the complexity but in the amount of code which wrote trying to solve them and limit that damned application to a single instance. :) I wanted to have all realization in one class only and handle the messages on the application level, not windows. Note - VB 6.0 users have the simplest solution - they can check App.PrevInstance to limit instance, it's real and then ActivateApp or smth. like that.


Derive the application class from CWinAppEx and just check

function's ( with some GUID in parameter) return value and exit instance in case it is FALSE. Also add EnableShellOpen and RegisterShellFileTypes for SDI and MDI applications. That is all. ( The previous instance will popup the main window itself if you won't override OnAnotherInstance virtual function to do some specific actions when another instance is started ). Note: if lpszUID is not specified in the InitInstance(), the instance will not be limited.

BOOL CSomeApp::InitInstance( void )
    // CSomeApp is derived from CWinAppEx
    if( CWinAppEx::InitInstance( _T( "{6BDD1FC6-...}" ) ) )
        return FALSE;
    // Enable DDE Execute open
    RegisterShellFileTypes( TRUE );
    return TRUE;

Some History

Once in the MSDN I found the BroadcastSystemMessage function: MSDN: "The BroadcastSystemMessage function sends a message to the specified recipients. The recipients can be applications, installable drivers, network drivers, system-level device drivers, or any combination of these system components". Well, it allowed handling the messages on the application level and create this class.


If you look in the sources you'll see that in the InitInstance the application registers app-unique message with UID passed and holds the value returned in the private variable to identify another instance messages sent later. Then it searches for another instance using (tradition) mutexes (FindAnotherInstance function) and in case it finds it, broadcasts the unique message using BroadcastSystemMessage (PostInstanceMessage function) and exits. App. previous instance (if any) receives the message, compares it with own one and if they are equal, calls virtual function OnAnotherInstanceMessage, whose default implementation popups the main window. (These steps are required for dialog based applications and  for SDI and MDI apps when launching application executable (not associated document) and in some cases that are described later).

The BroadcastSystemMessage required SE_TCB_NAME privilege enabled on NT to send message to all desktops, so I wrote EnableTokenPrivilege function, that enables or disables privileges in the specified access token, which is called before broadcasting the message. I thought that it can be useful also outside this class and placed only its code in the article body removing the old code pieces, because the sources are totally overwritten and appeared to be too large for this article. To look at implementation you should open the source files.

BOOL CWinAppEx::EnableTokenPrivilege( LPCTSTR lpszSystemName, 
                                      BOOL    bEnable /*TRUE*/ )
    ASSERT( lpszSystemName != NULL );
    BOOL bRetVal = FALSE;
     if( ::GetVersion() < 0x80000000 ) // NT40/2K/XP // afxData ???
        HANDLE hToken = NULL;		
        if( ::OpenProcessToken( ::GetCurrentProcess(), 
            TOKEN_PRIVILEGES tp = { 0 };
            if( ::LookupPrivilegeValue( NULL, lpszSystemName, &tp.Privileges[0].Luid ) )
                tp.PrivilegeCount = 1;
                tp.Privileges[0].Attributes = ( bEnable ? SE_PRIVILEGE_ENABLED : 0 );
                // To determine whether the function adjusted all of the
                // specified privileges, call GetLastError:
                if( ::AdjustTokenPrivileges( hToken, FALSE, &tp, 
                    sizeof( TOKEN_PRIVILEGES ), (PTOKEN_PRIVILEGES)NULL, NULL ) )
                    bRetVal = ( ::GetLastError() == ERROR_SUCCESS );
            ::CloseHandle( hToken );

    return bRetVal;

Many people complained about thye lack of DDE support. They have had problems opening documents directly from explorer double-clicking them - the old implementation was just limiting its instance in any case.  MDI applications have DDE support, so the user has nothing to do for limiting the application instance when double-clicking associated document, while SDI  hasn't.

Thinking how to solve that I eventually stumbled on the reg file which is automatically generated for SDI apps (it contains all document registration) and is inlcluded into the projects - and that was the solution! I overrode CWinApp::RegisterShellFileTypes to perform DDE registration for SDI apps also. If we look in the code we'll see that first MFC registers the file types and then an additional loop is performed over all document types registering DDE. This code was also large enough to be placed here so you have to open the source files again. Now if user clicks the associated document, the SDI application opens it in the same instance, just the way MDI app does. The operating system handles that without any help from the program.

But there is one more problem - if we run the application with the associated document in parameter from the windows run dialog, then no DDE will save us and a new instance will be started. To correct that, application passes document file name to another instance and exits only if command line contains FileNew or FileOpen parameters, in other cases such as FilePrint, etc., it does not exit instance because framework will process these commands in new instance in invisible mode and will exit itself.


Registry DDE

When testing RegisterShellFileTypesEx again under XP, and then clicking the associated file, OS gave me some strange message that the associated file is not found and I should search for it, though OS opened it normally. ( I remembered that it ran normally at work under 2000 and Windows 98). Cursing my code and everything I began to compute what could cause that error, and checking registry values, removed one key by chance, after which all gone perfect. If we look in the registry under the application document's key "ddeexec" key we'll find "application" key. The reg file told us that the "application" key is optional; it defaults to the app name in "command" key. Well, I added XP version check that does not add any "Application" key and even removes it if present in case of XP OS. But frankly speaking I do not understand why it gives that error, and would be very grateful to anyone who will explain it.

CWinAppEx Class Members

Data Members

m_uMsgCheckInst Holds application unique message ID.


PostInstanceMessage Posts a message to another instance of the application (if any).
EnableTokenPrivilege Enables or disables privileges in the specified access token (Windows NT only).
RegisterShellFileTypes Registers all of your application's document types with the Windows File Manager, also performs additional registration for SDI applications.
UnregisterShellFileTypes Unregisters all of your application's document types with the Windows File Manager, also unregisters additional data required for SDI applications.


InitInstance Initializes new instance of your application running,  if has parameter specified (GUID) then returns FALSE if any other instance of application with this UID is found.
OnAnotherInstanceMessage Application receives this message from another started instance. The default implementation is as follows - the started application sends this message (with its command line if needed) to the previous one, and the previous instance receives it, processes the command line (if any) and popups the main window in this function.


GetApp Obtains a pointer to the CWinAppEx object.

Version History

  • 21-May-2002 - Posted the article.
  • 27-Aug-2002 - Mostly rewritten code, added DDE support for SDI applications, added token privilege adjustment.


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Armen Hakobyan
Software Developer (Senior) SafeNet Inc
United States United States
No Biography provided

You may also be interested in...


Comments and Discussions

QuestionRe: strange results after double-clicking in Windows Explorer Pin
Michael Adamus17-Nov-09 12:10
memberMichael Adamus17-Nov-09 12:10 
Generalif( CWinAppEx::InitInstance... should be if( !CWinAppEx::InitInstance... Pin
Iain Clarke10-Aug-09 1:54
mvpIain Clarke10-Aug-09 1:54 
GeneralGreat work and the easiest one to use in CP Pin
Ray Guan11-Jun-09 19:01
memberRay Guan11-Jun-09 19:01 
QuestionDialog Based on WinXP fast switch user mode Pin
sanjay kaledhonkar4-Apr-07 6:14
membersanjay kaledhonkar4-Apr-07 6:14 
AnswerRe: Dialog Based on WinXP fast switch user mode Pin
Armen Hakobyan4-Apr-07 21:42
memberArmen Hakobyan4-Apr-07 21:42 
GeneralRe: Dialog Based on WinXP fast switch user mode Pin
sanjay kaledhonkar4-Apr-07 22:40
membersanjay kaledhonkar4-Apr-07 22:40 
GeneralThank-you Pin
Leo Huf6-May-06 6:10
memberLeo Huf6-May-06 6:10 
Thank-you! Excellent class, extremely helpful and easy to use! Good work!

GeneralBug in OnAnotherInstanceMessage Pin
VKostka22-Nov-05 3:23
memberVKostka22-Nov-05 3:23 
GeneralDialog based apps Pin
MHillary18-May-04 6:30
memberMHillary18-May-04 6:30 
GeneralRe: Dialog based apps Pin
Mihai Moga17-Mar-06 3:56
memberMihai Moga17-Mar-06 3:56 
GeneralTypo in example Pin
MealMate8-Oct-03 13:41
memberMealMate8-Oct-03 13:41 
GeneralRe: Typo in example Pin
jefflewis1-Jan-07 14:15
memberjefflewis1-Jan-07 14:15 
GeneralI dont want to close Application on close of document. Pin
Dhirendra30-Sep-03 3:11
memberDhirendra30-Sep-03 3:11 
GeneralAnother way of limiting to single instance Pin
Enis18-Feb-03 10:54
memberEnis18-Feb-03 10:54 
GeneralThe best way Pin
Raffaele Romito21-May-03 2:24
memberRaffaele Romito21-May-03 2:24 
GeneralRe: The best way Pin
jaime_olivares10-Apr-05 22:35
memberjaime_olivares10-Apr-05 22:35 
GeneralRe: The best way (variant) Pin
jaime_olivares10-Apr-05 22:40
memberjaime_olivares10-Apr-05 22:40 
GeneralDouble click can not open file! Pin
xiaohui21-May-02 22:42
memberxiaohui21-May-02 22:42 
GeneralRe: Double click can not open file! Pin
Armen Hakobyan21-May-02 23:17
memberArmen Hakobyan21-May-02 23:17 
GeneralRe: Double click can not open file! Pin
xiaohui22-May-02 1:10
memberxiaohui22-May-02 1:10 
GeneralRe: Double click can not open file! Pin
Armen Hakobyan22-May-02 3:38
memberArmen Hakobyan22-May-02 3:38 
GeneralRe: Double click can not open file! Pin
PJ Arends22-May-02 8:47
memberPJ Arends22-May-02 8:47 
GeneralRe: Double click can not open file! Pin
Armen Hakobyan24-May-02 4:17
memberArmen Hakobyan24-May-02 4:17 
GeneralRe: Double click can not open file! Pin
Dhirendra24-Sep-03 22:11
memberDhirendra24-Sep-03 22:11 
GeneralRe: Double click can not open file! Pin
Dhirendra24-Sep-03 22:43
memberDhirendra24-Sep-03 22:43 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.180111.1 | Last Updated 31 Aug 2002
Article Copyright 2002 by Armen Hakobyan
Everything else Copyright © CodeProject, 1999-2018
Layout: fixed | fluid