您的位置:首页 > 其它

使程序只能运行一个实例

2015-09-29 15:03 375 查看

http://blog.csdn.net/dpsying/article/details/17244759




1,目标

使我们的程序只能有一个正在运行的实例。

并且在第二次运行时,若前一个实例主窗口处于最小化状态,就让前一个实例恢复原大小显示出来。


2. 原理

前一实例进程运行期间得留下一个可供后一实例进程判断的标志,类似进程间通信,可以参考一些IPC的方式。不过这里不需要传递多少数据,仅仅有个标志就OK。

一个简单思路:程序开始时创建一个可命名的内核对象,退出时关闭。如果已存在则说明存在实例在使用这个内核对象。

对于找到前实例主窗口:有一个API,可以给窗口添加一个标志:SetProp.通过遍历桌面的子窗口,用GetProp获取标志,可以判断出我们要的窗口。


3. 实现

①新建MFC对话框应用程序,在app类中加入:

[cpp] view
plaincopy





HANDLE m_handle;  

②在InitInstance()中加入如下代码:

[cpp] view
plaincopy





    //防止多次实例  

    //用应用程序名创建一个互斥量(任意一种可命名的内核对象都行)  

    m_handle = CreateMutex(NULL, FALSE, m_pszExeName);   

    if (GetLastError() == ERROR_ALREADY_EXISTS)  

    {  

        // 前一实例已存在,退出本实例    

        return FALSE;    

    }  

③给app类添加虚函数ExitInstance(),在程序退出前关闭该内核对象引用。

[cpp] view
plaincopy





int CTestApp::ExitInstance()   

{  

    CloseHandle(m_handle);  

    return CWinApp::ExitInstance();  

}  

现在本程序只能运行一次实例了,下面使第二次运行时前实例窗口大小恢复显示。

④在dlg类 OnCreate()中给对话框添加标记:

[cpp] view
plaincopy





int CTestDlg::OnCreate(LPCREATESTRUCT lpCreateStruct)   

{  

    if (CDialog::OnCreate(lpCreateStruct) == -1)  

        return -1;  

  

    // 设置窗口标记,用的是应用程序名     

    ::SetProp(m_hWnd, AfxGetApp()->m_pszExeName, (HANDLE)1);  

  

    return 0;  

}  

⑤添加消息响应OnDestroy(),窗口销毁时去掉标记:

[cpp] view
plaincopy





void CTestDlg::OnDestroy()   

{  

    CDialog::OnDestroy();  

      

    // TODO: Add your message handler code here  

    // 删除寻找标记     

    ::RemoveProp(m_hWnd, AfxGetApp()->m_pszExeName);   

}  

⑥修改app的InitInstance(),使标记的窗口恢复大小:

[cpp] view
plaincopy





BOOL CTestApp::InitInstance()  

{  

    //防止多次实例  

    //用应用程序名创建一个互斥量(任意一种可命名的内核对象都行)  

    m_handle = CreateMutex(NULL, FALSE, m_pszExeName);   

    if (GetLastError() == ERROR_ALREADY_EXISTS)  

    {  

        //寻找先前实例的主窗口    

        //桌面句柄  

        HWND hWndPrevious = ::GetWindow(::GetDesktopWindow(),GW_CHILD);    

        //遍历桌面的子窗口  

        while (::IsWindow(hWndPrevious))   

        {    

            // 检查窗口是否有预设的标记?    

            // 有,则是我们寻找的主窗     

            if (::GetProp(hWndPrevious, m_pszExeName))    

            {     

                // 主窗口已最小化,则恢复其大小    

                if (::IsIconic(hWndPrevious))     

                {  

                    ::ShowWindow(hWndPrevious,SW_RESTORE);     

                    // 将主窗激活     

                    ::SetForegroundWindow(hWndPrevious);      

                    // 将主窗的对话框激活    

                    ::SetForegroundWindow(  ::GetLastActivePopup(hWndPrevious));    

                    // 退出本实例    

                    return FALSE;    

                }  

            }     

            // 继续寻找下一个窗口     

            hWndPrevious = ::GetWindow(hWndPrevious,GW_HWNDNEXT);    

        }     

        // 前一实例已存在,但没找到其主窗口,可能出错了,退出本实例    

        return FALSE;    

    }  

  

    ……  

  

}  

好了,大功告成!


4. 效果

效果就是没什么效果了……(当第二次运行)但是为了遵循给自己定的五步流程,仍然加上此条~


5. 源码

附上VC6源码:

http://yun.baidu.com/s/1f8ov2
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: