Click here to Skip to main content
15,867,594 members
Articles / Desktop Programming / MFC

Implementing Single Instance Application Using “File Mapping” Technique

Rate me:
Please Sign up or sign in to vote.
4.00/5 (10 votes)
29 Apr 2009CPOL3 min read 27.1K   596   20   5
Yet another single instance implementation

Introduction

The common way of creating a “single instance application” (only one instance is allowed to be running at a time) is made by the following two steps:

  1. Create a named global object (such as Mutex, Semaphore) when the application starts. If an instance is already started, it will fail with the error code ERROR_ALREADY_EXISTS.
  2. If an application instance is running, find its main window using FindWindow or FindWindowEx, then restore and bring the window to the front.

The code is much like this:

SQL
HANDLE hMutex = CreateMutex(NULL, FALSE, MUTEX_NAME);
if (GetLastError() == ERROR_ALREADY_EXISTS)
{
HWND hWnd = FindWindowEx(NULL, NULL, CLASSNAME, NULL);
if (IsWindow(hWnd))
{
ShowWindow(hWnd, SW_RESTORE);
BringWindowToTop(hWnd);
SetForegroundWindow(hWnd);
}
}

I seek a new implementation because I don't quite like the previous commonly used method. To Find the running instance’s main window, it must be created with a known class name and (or) window name, yet it’s quite awkward in MFC to do this (we must override the main windows’ PreCreateWindow function and set lpszClass and lpszName of the CREATESTRUCT). Another problem is that it is not recommended to use FindWindow.

Background

We can combine the two steps with “File Mapping” technique. File Mapping can be used to share data between processes. When the first application instance starts, it creates a named File Mapping object based on paging file (disk file used as system virtual memory), and stores its main window handle in the 4 bytes mapped share memory. The latter instance finds and opens the named File Mapping object, and retrieves the running main window handle in the mapped share memory.

File Mapping related functions are listed here:

  1. C++
    HANDLE CreateFileMapping(
    HANDLE hFile, // handle to file to map
    LPSECURITY_ATTRIBUTES lpFileMappingAttributes, // optional security attributes
    DWORD flProtect, // protection for mapping object
    DWORD dwMaximumSizeHigh, // high-order 32 bits of object size
    DWORD dwMaximumSizeLow, // low-order 32 bits of object size
    LPCTSTR lpName // name of file-mapping object
    );

    Creates a File Mapping object with a system global name. The hFile parameter can be an opened disk file handle or (HANDLE)-1 to refer to the paging file. lpName parameter is a global name of the object and is used to find the File Mapping object created by another process.

  2. C++
    HANDLE OpenFileMapping(
    DWORD dwDesiredAccess, 	// access mode
    BOOL bInheritHandle, 	// inherit flag
    LPCTSTR lpName 		// pointer to name of file-mapping object
    );
    Open the File Mapping object with name referred by "lpName" parameter.
  3. C++
    LPVOID MapViewOfFile(
    HANDLE hFileMappingObject, 	// file-mapping object to map into address space
    DWORD dwDesiredAccess, 	// access mode
    DWORD dwFileOffsetHigh, 	// high-order 32 bits of file offset
    DWORD dwFileOffsetLow, 	// low-order 32 bits of file offset
    DWORD dwNumberOfBytesToMap 	// number of bytes to map
    );

    Maps a view of file into address space of the calling process. The returned value is a VOID pointer, it points to a disk file’s offset address. The disk file can be a real file or the paging file.

Reference

I wrote a class CSingleInstance to wrap the functions and ease its using. The whole implementation contains only one source file “SingleInstance.h”. Only two lines of source code are needed to use it.

Function Reference:

C++
1. CCSingleInstance::CCSingleInstance(LPCTSTR pszUniqueName=NULL,
    int nCmdShow=SW_RESTORE)

The construction takes two parameters.

  • pszUniqueName is the File Mapping object’s global unique name, if it’s NULL, CSingleInstance will use a default name __akui__.
  • nCmdShow tells how the running instance’s main window is shown when activated.
C++
2. void CCSingleInstance::SetWindow(HWND hWnd)
// Store main window handle for later ones to active me.

Using the Code

  1. Include “SingleInstance.h
  2. Declare a global CSingleInstance object
  3. After the main window handle is valid, call SetWindow to store it

In an MFC application, just declare the CSingleInstance object in AppName.cpp, before declaration of theApp. And call SetWindow in CAppName::InitInstance() just before return when main window handle is valid.

If you want to make some changes to the source code, pay attention to the fact that a global object is created before the application actually begins running (enters WinMain). So don't call MFC functions because MFC may not have been properly initialized yet.

History

  • 29th April, 2009: Initial post

License

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


Written By
China China
From Shanghai, China

Comments and Discussions

 
Generalyour technique is the same as remoting in C# Pin
Southmountain9-Sep-20 18:20
Southmountain9-Sep-20 18:20 
GeneralIt's very convenient! Pin
Zhou Hua4-May-09 23:43
Zhou Hua4-May-09 23:43 
QuestionReinventing the wheel? Pin
Victor Nijegorodov4-May-09 22:03
Victor Nijegorodov4-May-09 22:03 
GeneralMy standard technique Pin
peterchen4-May-09 20:48
peterchen4-May-09 20:48 
GeneralGood Pin
Manish K. Agarwal30-Apr-09 18:46
Manish K. Agarwal30-Apr-09 18:46 

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.