WTL-Single instance application
WTL版本的单实例程序。
如果此程序已经有一个实例在运行,当用户再次启动一个新的程序时,通知正在运行的实例,并将此实例放到窗口的最前面。
一.实现代码:
1.SingleInstance.h类
//SingleInstance.h#pragma once#include <windows.h>class CSingleInstance{public:CSingleInstance(LPCTSTR mutexName){m_hMutex = ::CreateMutex(NULL, FALSE, mutexName);m_IsAnotherInstanceRunning = (::GetLastError()==ERROR_ALREADY_EXISTS);}~CSingleInstance(){if (m_hMutex){::CloseHandle(m_hMutex);m_hMutex = NULL;}}public:BOOL IsAnotherInstanceRunning(){return m_IsAnotherInstanceRunning;}private:HANDLE m_hMutex;BOOL m_IsAnotherInstanceRunning;};
2.应用程序的入口处
#include "MainDlg.h"#include "SingleInstance.h"CAppModule _Module;//The instance name string is generated with GuidGen toolCSingleInstance g_SingleInstance(_T("{64B21E05-75CB-4329-A4E8-C6FE192F3506}"));int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR /*lpstrCmdLine*/, int /*nCmdShow*/){if (g_SingleInstance.IsAnotherInstanceRunning()){UINT registeredMsg = ::RegisterWindowMessage(BROADCAST_MSG_NAME);ATLASSERT(registeredMsg != 0);::PostMessage(HWND_BROADCAST,registeredMsg,NULL,NULL);return 0;}//......}
3.主窗口
//MainDlg.h#pragma once//The message name string is generated with GuidGen toolLPCTSTR BROADCAST_MSG_NAME = _T("{1DF33122-865B-4A28-8249-D225842A49FB}");class CMainDlg :public CDialogImpl<CMainDlg>{private:UINT m_RegisteredMsg;public:enum { IDD = IDD_MAINDLG };BEGIN_MSG_MAP_EX(CMainDlg)REGISTERED_MESSAGE_HANDLER(m_RegisteredMsg, OnRegisteredMsg)MSG_WM_INITDIALOG(OnInitDialog)COMMAND_ID_HANDLER(IDCANCEL, OnCancel)END_MSG_MAP()public:CMainDlg(){m_RegisteredMsg = ::RegisterWindowMessage(BROADCAST_MSG_NAME);ATLASSERT(m_RegisteredMsg != 0);}public:BOOL OnInitDialog(CWindow wndFocus, LPARAM lInitParam){// center the dialog on the screenCenterWindow();// set iconsHICON hIcon = AtlLoadIconImage(IDR_MAINFRAME, LR_DEFAULTCOLOR,::GetSystemMetrics(SM_CXICON), ::GetSystemMetrics(SM_CYICON));SetIcon(hIcon, TRUE);HICON hIconSmall = AtlLoadIconImage(IDR_MAINFRAME, LR_DEFAULTCOLOR,::GetSystemMetrics(SM_CXSMICON), ::GetSystemMetrics(SM_CYSMICON));SetIcon(hIconSmall, FALSE);return TRUE;}LRESULT OnCancel(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/){// TODO: Add validation codeEndDialog(wID);return 0;}LRESULT OnRegisteredMsg(UINT uRegisteredMsg, WPARAM /*wParam*/, LPARAM /*lParam*/){//Take this instance to foregrondif (IsIconic()){ShowWindow(SW_SHOWNORMAL);}::SetForegroundWindow(m_hWnd);return 0;}};
二.小技巧
主对话框的消息映射的第一行用于添加注册消息的响应函数:
BEGIN_MSG_MAP_EX(CMainDlg)REGISTERED_MESSAGE_HANDLER(m_RegisteredMsg, OnRegisteredMsg)//......END_MSG_MAP()
其中的REGISTERED_MESSAGE_HANDLER()宏是一个自定义宏(MFC的消息映射中有一个宏ON_REGISTERED_MESSAGE()用于处理注册消息,而WTL库中则没有类似功能的宏,不过自定义一个这样的宏非常容易
):
//LRESULT OnPreProcessMessage(UINT uRegisteredMsg, WPARAM wParam, LPARAM lParam)#define REGISTERED_MESSAGE_HANDLER(uRegisteredMsg, func) \if(uMsg == uRegisteredMsg) \{ \SetMsgHandled(TRUE); \lResult = func(uMsg, wParam, lParam); \if(IsMsgHandled()) \return TRUE; \}
浙公网安备 33010602011771号