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:
ERROR_ALREADY_EXISTS. FindWindow or FindWindowEx, then restore and bring the window to the front. The code is much like this:
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.
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:
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.
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.
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.
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:
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. 2. void CCSingleInstance::SetWindow(HWND hWnd)
// Store main window handle for later ones to active me.
CSingleInstance object 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.
| You must Sign In to use this message board. | |||||||||||||||||||||
|
|||||||||||||||||||||
|
|||||||||||||||||||||
|
|||||||||||||||||||||