WTL-支持Single instance的CApplicationT类

为CApplicationT添加了Single instance功能支持:

#pragma once
#include <Windows.h>
#include <ATLHelper.h>
#pragma data_seg("Shared")
volatile HWND _g_hMainWindow = NULL;
#pragma data_seg()
#pragma comment(linker,"/Section:Shared,RWS")
namespace WTL
{
//CApplicationT class
template<typename T, typename TMainWindow, bool bInitializeCom = false>
class CApplicationT :
    public CAppModule
{
public:
    //Call this method in the application's entry point[_tWinMain(...)]
    int WinMain(HINSTANCE hInstance,LPTSTR lpCmdLine,int nCmdShow)
    {
        UNREFERENCED_PARAMETER(lpCmdLine);
        T* pT = static_cast<T*>(this);
        if(!(pT->OnStartup()))
            return 0;
        HRESULT hr = S_OK;
        if (bInitializeCom)
        {
            hr = ::CoInitialize(NULL);
            // If you are running on NT 4.0 or higher you can use the following 
            // call instead to make the EXE free threaded. This means that calls 
            // come in on a random RPC thread.
            //  hr = ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
            CHECKHR(hr);
        }
        // This resolves ATL window thunking problem when Microsoft Layer 
        // for Unicode (MSLU) is used
        ::DefWindowProc(NULL, 0, 0, 0L);
        pT->OnInitCommonControl();
        hr = Init(NULL, hInstance);
        CHECKHR(hr);
        int nRet = 0;
        {
            CMessageLoop msgLoop;
            AddMessageLoop(&msgLoop);
            TMainWindow wndMain;
            _g_hMainWindow = wndMain.Create(NULL,CWindow::rcDefault);
            if(_g_hMainWindow == NULL)
            {
                ATLTRACE(_T("Failed to create Main window!\n"));
                return 0;
            }
            wndMain.ShowWindow(nCmdShow);
            wndMain.UpdateWindow();
            wndMain.CenterWindow();
            nRet = msgLoop.Run();
            RemoveMessageLoop();
            _g_hMainWindow = NULL;
        }
        Term();
        if (bInitializeCom)
            ::CoUninitialize();
        pT->OnShutdown();
        return nRet;
    }
public:
    BOOL IsAnotherInstanceRunning()
    {
        return (_g_hMainWindow!=NULL);
    }
    void TakeAnotherInstanceForeground()
    {
        if (_g_hMainWindow)
        {
            CWindow mainWnd(_g_hMainWindow);
            if (mainWnd.IsIconic())
                mainWnd.ShowWindow(SW_RESTORE);
            mainWnd.SetForegroundWindow();
        }
    }
protected:
    //Override this method to do some work on start up
    BOOL OnStartup()
    {
        return TRUE;
    }
    //Override this method to do some work on shut down
    void OnShutdown()
    {}
    //Override this method to support other native controls
    void OnInitCommonControl()
    {
        AtlInitCommonControls(ICC_COOL_CLASSES|ICC_BAR_CLASSES|ICC_WIN95_CLASSES);
    }
};
//CApplication class
template<typename TMainWindow, bool bInitializeCom = false>
class CApplication :
    public CApplicationT<CApplication<TMainWindow,bInitializeCom>, TMainWindow, bInitializeCom>
{
};
}//namespace WTL

使用方法:

1.如果CApplicationT提供的功能已满足要求,不需要修改默认行为,也不需要添加Single instance功能支持,可直接用typedef定义自己的WTL应用程序类:

typedef CWinTraits<WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN> CMainWinTraits;
class CMainWindow :
    public CWindowImpl<CMainWindow,CWindow,CMainWinTraits>
{
public:
    //...
};
typedef CApplication<CMainWindow> CMainApp;
CMainApp g_MainApp;

2.如果需要使用Single instance功能,则可以覆盖OnStartup()方法,执行单程序实例检测:

class CMainApp :
    public CApplicationT<CMainApp,CMainWindow>
{
public:
    BOOL OnStartup()
    {
        //Check if another instance is running on start up
        if (IsAnotherInstanceRunning())
        {
            ::MessageBox(
                NULL,
                _T("Another instance is running.\n\nClick OK to take another instance foreground."),
                _T("WTL message"),
                MB_OK|MB_ICONINFORMATION);
            TakeAnotherInstanceForeground();
            return FALSE;
        }
        return TRUE;
    }
};

posted on 2010-10-07 15:37  wudong  阅读(530)  评论(0编辑  收藏  举报

导航