服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C/C++ - 让应用程序只运行一个实例的实现方法

让应用程序只运行一个实例的实现方法

2020-11-24 16:27C语言教程网 C/C++

我们在使用《360软件管家》时发现,在《360软件管家》已经运行了的情况下,再次点击《360软件管家》的图标,那么它不会再运行另外一个《360软件管家》,而是将已有的《360软件管家》给激活,始终只能运行一个《360软件管家》

在我们的程序当中如果要实现类似《360软件管家》的功能,就要解决两个问题,首先是要判断该程序已有一个实例在运行,其次是要将已运行的应用程序实例激活,同时退出第二个应用程序实例。

对于第一个问题,我们可以通过设置命名互斥对象或命名信标对象,在程序启动的时候检测互斥对象或信标对象,如互斥对象或信标对象已存在,则可以判断此程序已有一个实例正在运行。

第二个问题是如何找到已经运行的应用程序实例,如果我们能够找到已运行实例主窗口的指针,即可调用SetForegroundWindow来激活该实例。我们可以通过两种形式找到已运行实例的主窗口,一种形式是通过调用FindWindowEx去查找正在运行的窗口的句柄,这种方式用得比较多一些,而本文通过另一种形式去查找正在运行的窗口的句柄。通过调用SetProp给应用程序主窗口设置一个标记,用GetDesktopWindow 可以获取Windows环境下的桌面窗口的句柄,所有应用程序的主窗口都可以看成该窗口的子窗口,接着我们就可以用GetWindow函数来获得这些窗口的句柄。然后再用Win32 SDK函数GetProp查找每一个应用程序的主窗口是否包含有我们设置的标记,这样就可以找到我们要找的第一个实例主窗口。

下面演示代码是以一个单文档应用程序为例,工程名字是Mutex。

复制代码 代码如下:


1、在应用程序类InitInstance()函数中判断是否已有一个应用程序实例正在运行。

 

BOOL CMutexApp::InitInstance()

{

       //创建命名信标对象。

       HANDLE hSem=CreateSemaphore(NULL,1,1,"维新");

       if(hSem)  //信标对象创建成功。

       {

              //信标对象已经存在,则程序已有一个实例在运行。

              if(ERROR_ALREADY_EXISTS==GetLastError())

              {                 

                     CloseHandle(hSem);      //关闭信号量句柄。

 

//获取桌面窗口的一个子窗口。

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

 

                     while(::IsWindow(hWndPrev))

                     {

                     //判断窗口是否有我们预先设置的标记,如有,则是我们寻找的窗口,并将它激活。

                            if(::GetProp(hWndPrev,"维新"))  

                            {

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

                                   if (::IsIconic(hWndPrev))    

                                          ::ShowWindow(hWndPrev,SW_RESTORE);

 

                                   //将应用程序的主窗口激活。

                                   ::SetForegroundWindow(hWndPrev);

                                   return FALSE;                      //退出实例。

                            }

                            //继续寻找下一个窗口。

                            hWndPrev = ::GetWindow(hWndPrev,GW_HWNDNEXT);

                     }

                   

                     AfxMessageBox("已有一个实例在运行,但找不到它的主窗口!");

              }

       }

       else

       {

              AfxMessageBox("创建信标对象失败,程序退出!");

              return FALSE;

       }

 

       AfxEnableControlContainer();

 

       // Standard initialization

       // If you are not using these features and wish to reduce the size

       //  of your final executable, you should remove from the following

       //  the specific initialization routines you do not need.

     

#ifdef _AFXDLL

       Enable3dControls();                     // Call this when using MFC in a shared DLL

#else

       Enable3dControlsStatic();      // Call this when linking to MFC statically

#endif

 

       // Change the registry key under which our settings are stored.

       // TODO: You should modify this string to be something appropriate

       // such as the name of your company or organization.

       SetRegistryKey(_T("Local AppWizard-Generated Applications"));

 

       LoadStdProfileSettings();  // Load standard INI file options (including MRU)

 

       // Register the application's document templates.  Document templates

       //  serve as the connection between documents, frame windows and views.

 

       CSingleDocTemplate* pDocTemplate;

       pDocTemplate = new CSingleDocTemplate(

              IDR_MAINFRAME,

              RUNTIME_CLASS(CMutexDoc),

              RUNTIME_CLASS(CMainFrame),       // main SDI frame window

              RUNTIME_CLASS(CMutexView));

       AddDocTemplate(pDocTemplate);

 

       // Parse command line for standard shell commands, DDE, file open

       CCommandLineInfo cmdInfo;

       ParseCommandLine(cmdInfo);

 

       // Dispatch commands specified on the command line

       if (!ProcessShellCommand(cmdInfo))

              return FALSE;

 

       // The one and only window has been initialized, so show and update it.

       m_pMainWnd->ShowWindow(SW_SHOW);

       m_pMainWnd->UpdateWindow();

 

       return TRUE;

}

2、在框架类的OnCreate()函数中设置查找标记。

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);

 

     

       //设置查找标记。

       ::SetProp(m_hWnd,"维新",(HANDLE)1);

 

       return 0;

}

3、在程序退出是删除设置的标记,在框架类中响应WM_DESTROY消息,进行处理。

void CMainFrame::OnDestroy()

{

       CFrameWnd::OnDestroy();

     

       // TODO: Add your message handler code here

       //删除所设置的标记。

       ::RemoveProp(m_hWnd,"维新");

}

至此,使应用程序只运行一个实例的功能就完成了。

 

延伸 · 阅读

精彩推荐
  • C/C++关于C语言中E-R图的详解

    关于C语言中E-R图的详解

    今天小编就为大家分享一篇关于关于C语言中E-R图的详解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看...

    Struggler095962021-07-12
  • C/C++c/c++内存分配大小实例讲解

    c/c++内存分配大小实例讲解

    在本篇文章里小编给大家整理了一篇关于c/c++内存分配大小实例讲解内容,有需要的朋友们可以跟着学习参考下。...

    jihite5172022-02-22
  • C/C++OpenCV实现拼接图像的简单方法

    OpenCV实现拼接图像的简单方法

    这篇文章主要为大家详细介绍了OpenCV实现拼接图像的简单方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    iteye_183805102021-07-29
  • C/C++C语言main函数的三种形式实例详解

    C语言main函数的三种形式实例详解

    这篇文章主要介绍了 C语言main函数的三种形式实例详解的相关资料,需要的朋友可以参考下...

    ieearth6912021-05-16
  • C/C++深入C++拷贝构造函数的总结详解

    深入C++拷贝构造函数的总结详解

    本篇文章是对C++中拷贝构造函数进行了总结与介绍。需要的朋友参考下...

    C++教程网5182020-11-30
  • C/C++c/c++实现获取域名的IP地址

    c/c++实现获取域名的IP地址

    本文给大家汇总介绍了使用c/c++实现获取域名的IP地址的几种方法以及这些方法的核心函数gethostbyname的详细用法,非常的实用,有需要的小伙伴可以参考下...

    C++教程网10262021-03-16
  • C/C++C语言实现双人五子棋游戏

    C语言实现双人五子棋游戏

    这篇文章主要为大家详细介绍了C语言实现双人五子棋游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    两片空白7312021-11-12
  • C/C++使用C++制作简单的web服务器(续)

    使用C++制作简单的web服务器(续)

    本文承接上文《使用C++制作简单的web服务器》,把web服务器做的功能稍微强大些,主要增加的功能是从文件中读取网页并返回给客户端,而不是把网页代码...

    C++教程网5492021-02-22