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 tool
CSingleInstance 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 tool
LPCTSTR 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 screen
        CenterWindow();
        // set icons
        HICON 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 code 
        EndDialog(wID);
        return 0;
    }
    
    LRESULT OnRegisteredMsg(UINT uRegisteredMsg, WPARAM /*wParam*/, LPARAM /*lParam*/)
    {
        //Take this instance to foregrond
        if (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库中则没有类似功能的宏,不过自定义一个这样的宏非常容易Open-mouthed smile):

//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; \
    }

 

posted on 2010-09-18 14:09  wudong  阅读(802)  评论(0)    收藏  举报

导航