参考资料
http://www.codeproject.com/KB/cpp/avoidmultinstance.aspx
使用了共享数据段的方法来保存主窗口句柄,
*. 避免了FindWindow时, 对于自解压程序或带窗口标题的程序, 找不到窗口句柄的情况.
*. 避免了条件竞争(EnumWindows, SendMessage到窗口句柄)
对于sdi
#include "stdafx.h" #include "ActiveMe.h" #include "MainFrm.h" #include "ActiveMeDoc.h" #include "ActiveMeView.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #pragma comment(linker, "/SECTION:.shareData,RWS") #pragma data_seg(".shareData") HWND hInstanceWnd = NULL; #pragma data_seg() ///////////////////////////////////////////////////////////////////////////// // CActiveMeApp
/** * @note * G_GUID_PROG 由GUIDGEN.EXE产生 */ #define G_GUID_PROG "{3B2E6EE7-612A-448a-97DD-FB6EAFFCE921}" DWORD CActiveMeApp::IsInstanceRunning() { BOOL bExistMutex = FALSE; DWORD dwRc = S_FALSE; HANDLE hMutex = NULL; try { hMutex = ::CreateMutex(NULL, FALSE, G_GUID_PROG); dwRc = GetLastError(); if((!hMutex) || (ERROR_ALREADY_EXISTS == dwRc) || (ERROR_ACCESS_DENIED == dwRc)) { throw((DWORD)S_OK); } else { throw((DWORD)S_FALSE); } } catch (CException* e) { e->Delete(); dwRc = S_FALSE; } catch(DWORD dwE) { dwRc = dwE; } if((S_OK == dwRc) && hMutex) { CloseHandle(hMutex); hMutex = NULL; } return dwRc; } DWORD CActiveMeApp::ActiveInstanceExist() { HWND hOther = hInstanceWnd; if (hOther != NULL) { ::SetForegroundWindow(hOther); if (IsIconic(hOther)) ::ShowWindow(hOther, SW_RESTORE); } return S_OK; } BOOL CActiveMeApp::InitInstance() { if(S_OK == IsInstanceRunning()) { ActiveInstanceExist(); return FALSE; }
// MainFrm.cpp : implementation of the CMainFrame class // #include "stdafx.h" #include "ActiveMe.h" #include "MainFrm.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif extern HWND hInstanceWnd;
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CFrameWnd::OnCreate(lpCreateStruct) == -1) return -1; if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) || !m_wndToolBar.LoadToolBar(IDR_MAINFRAME)) { TRACE0("Failed to create toolbar/n"); return -1; // fail to create } if (!m_wndStatusBar.Create(this) || !m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT))) { TRACE0("Failed to create status bar/n"); return -1; // fail to create } // TODO: Delete these three lines if you don't want the toolbar to // be dockable m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY); EnableDocking(CBRS_ALIGN_ANY); DockControlBar(&m_wndToolBar); hInstanceWnd = m_hWnd; return 0; }
对于mdi, 添加代码和sdi相同.
对于Dlg, 不同的地方是 hInstanceWnd的赋初值的地方到了Dlg:OnInitDialog中
BOOL CActiveMeDlgDlg::OnInitDialog() { CDialog::OnInitDialog(); // Add "About..." menu item to system menu. // IDM_ABOUTBOX must be in the system command range. ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != NULL) { CString strAboutMenu; strAboutMenu.LoadString(IDS_ABOUTBOX); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } // Set the icon for this dialog. The framework does this automatically // when the application's main window is not a dialog SetIcon(m_hIcon, TRUE); // Set big icon SetIcon(m_hIcon, FALSE); // Set small icon // TODO: Add extra initialization here hInstanceWnd = m_hWnd; return TRUE; // return TRUE unless you set the focus to a control }
对于mfc console
// stdafx.h : include file for standard system include files, // or project specific include files that are used frequently, but // are changed infrequently // #if !defined(AFX_STDAFX_H__501C5FBD_3F7B_494A_94F9_A14B83F36200__INCLUDED_) #define AFX_STDAFX_H__501C5FBD_3F7B_494A_94F9_A14B83F36200__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 /** for GetConsoleWindow */ #define _WIN32_WINNT 0x0500 #define WINVER 0x0500
// ActiveMeConsole.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include "ActiveMeConsole.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // The one and only application object #pragma comment(linker, "/SECTION:.shareData,RWS") #pragma data_seg(".shareData") HWND hInstanceWnd = NULL; #pragma data_seg() CWinApp theApp; using namespace std; DWORD IsInstanceRunning(); DWORD ActiveInstanceExist(); void MsgLoopBeforeQuit(); int _tmain(int argc, TCHAR* argv[], TCHAR* envp[]) { int nRetCode = 0; // initialize MFC and print and error on failure HMODULE hModule = ::GetModuleHandle(NULL); if (!AfxWinInit(hModule, NULL, ::GetCommandLine(), 0)) { // TODO: change error code to suit your needs cerr << _T("Fatal Error: MFC initialization failed") << endl; nRetCode = 1; } else { if(S_OK == IsInstanceRunning()) { ActiveInstanceExist(); /**@note * 退出控制台程序, 使用下面的2中方法都可以 */ //PostMessage(GetConsoleWindow(), WM_CLOSE, 0, 0); PostQuitMessage(0); MsgLoopBeforeQuit(); return FALSE; } hInstanceWnd = GetConsoleWindow(); // TODO: code your application's behavior here. CString strHello; strHello.LoadString(IDS_HELLO); cout << (LPCTSTR)strHello << endl; } printf("程序运行中..., 按任意键结束/n"); getchar(); return nRetCode; } void MsgLoopBeforeQuit() { MSG msg; while (GetMessage (&msg, NULL, 0, 0)) { TranslateMessage (&msg); DispatchMessage (&msg); } } /** * @note * G_GUID_PROG 由GUIDGEN.EXE产生 */ #define G_GUID_PROG "{3B2E6EE7-612A-448a-97DD-FB6EAFFCE921}" DWORD IsInstanceRunning() { DWORD dwRc = S_FALSE; HANDLE hMutex = NULL; try { hMutex = ::CreateMutex(NULL, FALSE, G_GUID_PROG); dwRc = GetLastError(); if((!hMutex) || (ERROR_ALREADY_EXISTS == dwRc) || (ERROR_ACCESS_DENIED == dwRc)) { throw((DWORD)S_OK); } else { throw((DWORD)S_FALSE); } } catch (CException* e) { e->Delete(); dwRc = S_FALSE; } catch(DWORD dwE) { dwRc = dwE; } if((S_OK == dwRc) && hMutex) { CloseHandle(hMutex); hMutex = NULL; } return dwRc; } DWORD ActiveInstanceExist() { HWND hOther = hInstanceWnd; if (hOther != NULL) { ::SetForegroundWindow(hOther); if (IsIconic(hOther)) ::ShowWindow(hOther, SW_RESTORE); } return S_OK; }
对于纯Win32Console
/** * @file ActiveMeWin32Console.cpp * @brief 在纯win32控制台程序下, 激活已经运行的程序实例 */ /** for GetConsoleWindow */ #define _WIN32_WINNT 0x0500 #define WINVER 0x0500 #include <windows.h> #include <stdlib.h> #include <stdio.h> #include <vector> #pragma comment(linker, "/SECTION:.shareData,RWS") #pragma data_seg(".shareData") HWND hInstanceWnd = NULL; #pragma data_seg() using namespace std; DWORD IsInstanceRunning(); DWORD ActiveInstanceExist(); void MsgLoopBeforeQuit(); int main(int argc, char* argv[]) { if(S_OK == IsInstanceRunning()) { ActiveInstanceExist(); /**@note * 退出控制台程序, 使用下面的2中方法都可以 */ //PostMessage(GetConsoleWindow(), WM_CLOSE, 0, 0); PostQuitMessage(0); MsgLoopBeforeQuit(); return FALSE; } hInstanceWnd = GetConsoleWindow(); printf("程序正在运行..., 按任意键结束/n"); getchar(); return 0; } void MsgLoopBeforeQuit() { MSG msg; while (GetMessage (&msg, NULL, 0, 0)) { TranslateMessage (&msg); DispatchMessage (&msg); } } /** * @note * G_GUID_PROG 由GUIDGEN.EXE产生 */ #define G_GUID_PROG "{3B2E6EE7-612A-448a-97DD-FB6EAFFCE921}" DWORD IsInstanceRunning() { DWORD dwRc = S_FALSE; HANDLE hMutex = NULL; try { hMutex = ::CreateMutex(NULL, FALSE, G_GUID_PROG); dwRc = GetLastError(); if((!hMutex) || (ERROR_ALREADY_EXISTS == dwRc) || (ERROR_ACCESS_DENIED == dwRc)) { throw((DWORD)S_OK); } else { throw((DWORD)S_FALSE); } } catch(DWORD dwE) { dwRc = dwE; } catch(...) { dwRc = S_FALSE; } if((S_OK == dwRc) && hMutex) { CloseHandle(hMutex); hMutex = NULL; } return dwRc; } DWORD ActiveInstanceExist() { HWND hOther = hInstanceWnd; if (hOther != NULL) { ::SetForegroundWindow(hOther); if (IsIconic(hOther)) ::ShowWindow(hOther, SW_RESTORE); } return S_OK; }
工程下载点: