Single Instance of an Application Class (2)

This article is actually a modification of the original article "Single Instance of an Application Class" by Kevin Lussier.

Kevin used the following piece of code to restore the application after a second instance is started:

.....
HWND hWnd = ::FindWindowEx( NULL, NULL, m_strClassName, NULL );
if ( hWnd != NULL ) {
    ::ShowWindow( hWnd, SW_RESTORE );        // This is modified
    ::BringWindowToTop( hWnd );
    ::SetForegroundWindow( hWnd );
}
// Return failure
return FALSE;

This works fine!

But, if your application (actually main window) contains modeless dialog boxes, they are not going to be restored. In order to allow the application to handle ::ShowWindow(...), several modifications are made.

Step 1:

Public static data member is added to class declaration. This will contain a message identifier of the registered window message. The class declaration now becomes:

class TSingleInstance {
    public:
        static UINT MsgId;            // New data member
    protected:
        HANDLE HMutex;
        CString ClassName;
    public:
        TSingleInstance();
        ~TSingleInstance();
        BOOL Create(UINT nID);
        CString GetClassName(void) const;
};

Step 2:

Message is registered in a constructor of TSingleInstance.

UINT TSingleInstance::MsgId = 0;
TSingleInstance::TSingleInstance()
{
    HMutex = NULL;
    MsgId = ::RegisterWindowMessage("SingleInstanceOfMyApplication");
}

Step 3:

Now, previous piece of code becomes the following:

.....

HWND hWnd = ::FindWindowEx( NULL, NULL, m_strClassName, NULL );
if ( hWnd != NULL ) {
    if (MsgId != 0) {        // In case ::RegisterWindowMessage() failed
        DWORD recipients = BSM_APPLICATIONS;
        ::BroadcastSystemMessage(BSF_POSTMESSAGE,&recipients,MsgId,0,0);
    } else {
        ::ShowWindow(hWnd, SW_RESTORE);
        ::BringWindowToTop( hWnd );
        ::SetForegroundWindow( hWnd );
    }
}

// Return failure
return FALSE;

Step 4:

Main application window will receive this message and has to handle it. In order to supply the handler for registered message, following line has to be added to a message map.

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
    //{{AFX_MSG_MAP(CMainFrame)
    ON_REGISTERED_MESSAGE(TSingleInstance::MsgId,OnSingleInstanceRestore)
    ....
END_MESSAGE_MAP()
and the following line should be added to a declaration of CMainFrame class:
....
afx_msg LRESULT OnSingleInstanceRestore(WPARAM, LPARAM);
....

Step 5:

The implementation of this function should restore the main window and all other modeless dialog boxes (if they exist). Minimal implementation should only restore the main window, bring it to top and set it as a foreground window (the same as in the original implementation).

LRESULT CMainFrame::OnSingleInstanceRestore(WPARAM,LPARAM)
{
    ShowWindow(SW_RESTORE);
    // Do whatever else is necessary. Restore modeless dialogs etc.
    BringWindowToTop();
    SetForegroundWindow();
    return 0;
}

Step 6:

Everything else is the same as in the original implementation. This includes the following (see original article):

  • Add an instance of TSingleInstance class to a public section of your CWinApp derived class.
  • Add a code to CMainFrame::PreCreateWindow(CREATESTRUCT& cs).

Code:

Here is the complete implementation (I'm using different naming convention). Code in bold is a difference between this and original implementation by Kevin:

//====================================================================================
// Include file (.h)
class TSingleInstance {
    public:
        static UINT MsgId;
    protected:
        HANDLE HMutex;
        CString ClassName;
    public:
        TSingleInstance();
        ~TSingleInstance();
        BOOL Create(UINT nID);
        CString GetClassName(void) const;
};

//====================================================================================
// Source code (.cpp)
UINT TSingleInstance::MsgId = 0;
TSingleInstance::TSingleInstance()
{
    HMutex = NULL;
    MsgId = ::RegisterWindowMessage(_T("SingleInstanceOfMyApplication"));
}

TSingleInstance::~TSingleInstance()
{
    if (HMutex != NULL)
        ::ReleaseMutex(HMutex);
}

BOOL TSingleInstance::Create(UINT nID)
{
    CString strFullString;
    // Create our class name string
    if (strFullString.LoadString(nID)) {
        // Extract the first sub-string
        ::AfxExtractSubString(ClassName, strFullString, 0);
    }
    // Add the word 'Class' to the end
    ClassName += _T(" Class");
    // Create the mutex
    HMutex = ::CreateMutex(NULL, FALSE, ClassName);
    // Check for errors
    if (::GetLastError() == ERROR_ALREADY_EXISTS) {
        // Reset our mutext handle (just in case)
        HMutex = NULL;
        // The mutex already exists, which means an instance is already
        // running. Find the app and pop it up
        HWND hwnd = ::FindWindowEx(NULL, NULL, ClassName, NULL);
        if (hwnd != NULL) {
            if (MsgId != 0) {        // In case ::RegisterWindowMessage() failed
                DWORD recipients = BSM_APPLICATIONS;
                ::BroadcastSystemMessage(BSF_POSTMESSAGE,&recipients,MsgId,0,0);
            } else {
                ::ShowWindow(hwnd, SW_RESTORE);
                ::BringWindowToTop(hwnd);
                ::SetForegroundWindow(hwnd);
            }
        }
        // Return failure
        return FALSE;
    }
    // Register the unique window class name so others can find it.
    WNDCLASS wndcls;
    memset(&wndcls, 0, sizeof(WNDCLASS));
    wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
    wndcls.lpfnWndProc = AfxWndProc;
    wndcls.hInstance = ::AfxGetInstanceHandle();
    wndcls.hIcon = ::LoadIcon(wndcls.hInstance, MAKEINTRESOURCE(nID));//or AFX_IDI_STD_FRAME;
    wndcls.hCursor = ::LoadCursor(wndcls.hInstance, IDC_ARROW);
    wndcls.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
    wndcls.lpszMenuName = NULL;             // You may need to fix this
    wndcls.lpszClassName = ClassName;       // My class name
    // Register name, exit if it fails
    if (!::AfxRegisterClass(&wndcls)) {
        //::AfxMessageBox( _T("Failed to register window class!"), MB_ICONSTOP | MB_OK );
        TRACE0(_T("TSingleInstance: Failed to register window class!\n"));
        return FALSE;
    }
    // Return success
    return TRUE;
}

CString TSingleInstance::GetClassName(void) const
{
 return ClassName;
}
//====================================================================================

Last updated: 17 May 1998.



Comments

  • Single Instance of an Application(2)

    Posted by Legacy on 09/17/2002 12:00am

    Originally posted by: Renato Leite

    Works perfectly. Thanks a lot

    Reply
  • SetForegroundWindow(HWND) doesn't work

    Posted by Legacy on 12/14/2001 12:00am

    Originally posted by: Luc Bloom

    Ok my window gets the message, cause it is un-minimized and flashed, but it dosn't come to the foreground... any ideas why?

    Reply
  • You must have javascript enabled in order to post comments.

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

Top White Papers and Webcasts

  • Live Event Date: November 20, 2014 @ 2:00 p.m. ET / 11:00 a.m. PT Are you wanting to target two or more platforms such as iOS, Android, and/or Windows? You are not alone. 90% of enterprises today are targeting two or more platforms. Attend this eSeminar to discover how mobile app developers can rely on one IDE to create applications across platforms and approaches (web, native, and/or hybrid), saving time, money, and effort and introducing apps to market faster. You'll learn the trade-offs for gaining long …

  • Live Event Date: October 29, 2014 @ 11:00 a.m. ET / 8:00 a.m. PT Are you interested in building a cognitive application using the power of IBM Watson? Need a platform that provides speed and ease for rapidly deploying this application? Join Chris Madison, Watson Solution Architect, as he walks through the process of building a Watson powered application on IBM Bluemix. Chris will talk about the new Watson Services just released on IBM bluemix, but more importantly he will do a step by step cognitive …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds