Click here to Skip to main content
15,881,882 members
Articles / Desktop Programming / MFC

Dialog based single instance applications improved

,
Rate me:
Please Sign up or sign in to vote.
1.76/5 (10 votes)
21 Jun 2007CPOL3 min read 33.1K   282   16   1
Limiting dialog based programs to single instance by modifying the dialog template and using Mutex.

Introduction

This article is almost same as by pkhach's "Dialog based single instance applications" with a little bit of modification, i.e., adding a Mutex object for further improvement. The content of this article is almost same as that of his article. Special Thanks goes to Mr. pkhach.

Sometimes it is necessary to limit your program to only one running instance. For example, you create an Internet program that listens to the particular TCP/IP port on the user's computer, or you create a program that works in the background and puts an icon in the system tray (near the clock).

There are several good articles on CodeProject and CodeGuru discussing different techniques that you can use. For example, you can use named kernel mode objects (mutex, events, etc.), or use tokens, or you can search for your executable name in the running programs list (EnumProcesses or CreateToolhelp32Snapshot).

In this article, I will discuss using FindWindow for dialog based programs. The problem is that Windows, by default, uses a special (non unique) class name "#32770 (Dialog)" to create dialog boxes. We need to create the dialog box with our unique class name instead of this standard class name. We will see:

  1. How you can create a dialog box with your own class name.
  2. How you can use FindWindow to find your dialog box by its class name.
  3. How to use a Mutex to limit an application to one instance.

Although I use MFC in this sample, it is not limited to MFC programs only. You can do the same for ATL/WTL based programs as well as for generic Win32 applications.

Using the code

The steps to follow are as below:

  1. Create an MFC dialog based project.
  2. Open the Resource Script file (.rc), find your main dialog template, and add the following line: CLASS "SINGLE_INSTANCE_APP".
  3. In the IDE or Visual Studio Developer, click Open and locate the resource file, select "Open as:" text. By default, CLASS entry won't be there, so add CLASS "SINGLE_INSTANCE_APP" before the CAPTION "Single Instance Application".

    Screenshot - 1.jpg

    You should have something like this:

    C++
    IDD_SINGLEINSTANCE_DIALOG DIALOGEX 0, 0, 320, 200
    STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | 
    WS_CAPTION | WS_SYSMENU 
    EXSTYLE WS_EX_APPWINDOW 
    CAPTION "Single Instance Application" 
    ...

    After adding the line, the code will be:

    C++
    IDD_SINGLEINSTANCE_DIALOG DIALOGEX 0, 0, 320, 200
    STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | 
    WS_CAPTION | WS_SYSMENU 
    EXSTYLE WS_EX_APPWINDOW
    
    CLASS "SINGLE_INSTANCE_APP" 
    CAPTION "Single Instance Application" 
    ....

    This will instruct Windows to use our own Windows class "SINGLE_INSTANCE_APP" instead of the standard dialog class.

    Screenshot - 2.jpg

  4. Now, we have to register the "SINGLE_INSTANCE_APP" Windows class. The best place for this is InitInstance() of the App Class.
  5. C++
    WNDCLASS wc = {0};
    wc.style = CS_BYTEALIGNWINDOW|CS_SAVEBITS|CS_DBLCLKS;
    wc.lpfnWndProc = DefDlgProc;
    wc.cbWndExtra = DLGWINDOWEXTRA;
    wc.hInstance = m_hInstance;
    wc.hIcon = LoadIcon(IDR_MAINFRAME);
    wc.hCursor = ::LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
    wc.lpszClassName = _T("SINGLE_INSTANCE_APP"); //this name is from dialog's template
    
    ATOM cls = RegisterClass(&wc);

    Screenshot - 3.jpg

  6. After this, we create a mutex object and find our main dialog box by its class name. Then, check whether any pop up window or child window of the main application is displayed; if so, we bring that window on top. A non-NULL pointer means that our program is already running. We will simply activate it and exit.
  7. C++
    HANDLE hMutex = CreateMutex(NULL, FALSE, "CSingleInstanceApp{B98C6AA5-57C0}" );
    if ( WaitForSingleObject(hMutex, 1000) == WAIT_TIMEOUT )
    {
        //
        // There is another instance out there, but it is taking too long to
        // locate, just exit.
        return FALSE;
    }
    HWND hWndApp,hWndPopup;
    if (hWndApp = ::FindWindow(_T("SINGLE_INSTANCE_APP"),NULL))
    {
        hWndPopup = ::GetLastActivePopup(hWndApp);
    
        ::BringWindowToTop(hWndApp);
        if ( ::IsIconic(hWndPopup) )
        ::ShowWindow(hWndPopup, SW_RESTORE);
        else
        ::SetForegroundWindow(hWndPopup);
    
        ReleaseMutex(hMutex);
        CloseHandle(hMutex);
        return FALSE;
    }
    
    ReleaseMutex(hMutex);
    CloseHandle(hMutex);

    Screenshot - 4.jpg

And, that's all. You can use any class name to register your dialog application.

Points of interest

The use of the GetLastActivePopup method is used to see if any child window exists or not; if it exists, there then we need to set the focus on the child window rather than the main application. This way, when another instance of the application is run, it brings the application and the active child window to front rather then hide the child window and bring the main application to front.

License

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


Written By
Web Developer
Ukraine Ukraine

Written By
Architect
India India
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Generalfailed in generic Win32 application Pin
daxue17-Oct-07 0:12
daxue17-Oct-07 0:12 

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.