【问题标题】:Preventing multiple instances of my application [duplicate]防止我的应用程序的多个实例[重复]
【发布时间】:2012-02-06 15:36:42
【问题描述】:

附加信息

我再次就上述问题写信(防止我的应用程序的多个实例)

如果我从程序菜单/桌面快捷方式启动两个实例,则该代码有效。但在我的环境中,

一个实例正在从窗口服务运行。

另一个来自具有相同参数的桌面快捷方式。

对如何编写代码有帮助吗?

【问题讨论】:

  • 为什么不允许?我之所以问,是因为如果该程序类似于侦听固定端口号的服务器,那么您实际上不必做任何特别的事情。
  • @hvd,有许多类型的程序,不应该允许执行多个实例。否则,系统库中就不会有互斥锁。
  • 是的,应用程序是一个服务器,但它可以为多个实例运行,但不能使用相同的参数。如果我们从窗口服务传递相同的参数并启动 ABC.exe 并从具有相同参数 ABC.exe 的桌面快捷方式启动第二个不应该启动。
  • @Griwes 我并不是说没有充分的理由,我知道有很多正当的理由。但根据原因,我认为可能有更简单的解决方案。
  • @hvd,比如什么?在这种情况下,Mutex 似乎是完美的——他希望防止使用相同的参数运行——这就是它,命名为 mutex。

标签: c++ visual-c++ mfc


【解决方案1】:

您正在寻找named mutex(以参数命名,如果它不允许应用在多个实例中运行)。

【讨论】:

    【解决方案2】:

    这是一个在大多数情况下都有效的简单解决方案:

    CreateEvent(NULL, FALSE, FALSE, "MyEvent");
    if (GetLastError() == ERROR_ALREADY_EXISTS)
    {
        // Do Stuff
        return FALSE;
    }
    

    另一种方式:

    CreateSemaphore(NULL, TRUE, TRUE, "MySemaphore");
    if (GetLastError() == ERROR_ALREADY_EXISTS)
    {
       // Do Stuff
       return FALSE;
    }
    

    还有一种方式:

    CreateMutex(NULL, TRUE, "MyMutex");
    if (GetLastError() == ERROR_ALREADY_EXISTS)
    {
       // Do Stuff
       return FALSE;
    }
    

    正如提到的另一个答案,CreateMutex 是最常见的,但它并不完美。如果您想要一个真正彻底的解决方案以及为什么上述方法不好,请查看此link on Codeproject。

    【讨论】:

    • 请注意,这些对象如果结合使用它们不能使用相同的字符串(对于lpName),否则它们会给出不同的错误。
    【解决方案3】:

    最常用的方法是使用互斥体,类似如下:

    int WINAPI WinMain(...)
    {
       const char szUniqueNamedMutex[] = "com_mycompany_apps_appname";
       HANDLE hHandle = CreateMutex( NULL, TRUE, szUniqueNamedMutex );
       if( ERROR_ALREADY_EXISTS == GetLastError() )
       {
          // Program already running somewhere
          return(1); // Exit program
       }
    
       // Program runs...
    
       // Upon app closing:
       ReleaseMutex( hHandle ); // Explicitly release mutex
       CloseHandle( hHandle ); // close handle before terminating
       return( 1 );
    }
    

    您必须确保正确关闭 - 未删除互斥锁的程序崩溃可能会阻止程序再次运行,但理论上操作系统会在进程结束后清除任何悬空的互斥锁。

    另一种常用的方法是在窗口标题中搜索程序标题:

    HWND hWnd=::FindWindow(LPCTSTR lpClassName, // pointer to class name
                           LPCTSTR lpWindowName // pointer to window name
                           );
    

    如果它为空,则没有找到窗口,因此程序没有运行。您可以使用它在关闭这个新实例之前将焦点转移到正在运行的应用程序上,这样用户就不会想知道为什么应用程序没有打开。

    if(hWnd != NULL)
    {
       ShowWindow(hWnd,SW_NORMAL);
       // exit this instance
       return(1);
    }
    

    【讨论】:

    • 你不是忘了ReleaseMutex 吗?
    • @Jesse 当你 CloseHandle 时它会被释放,但如果你有兴趣明确,调用 ReleaseMutex 就可以了。 msdn.microsoft.com/en-us/library/windows/desktop/…
    • 我认为这不是真的。我想你必须打电话给ReleaseMutex。查看此SO question 并阅读CreateMutex 的备注。但是,我确实意识到在这种情况下它可能并不重要。
    • @Jesse 看起来确实有点晦涩,但是它确实说,“使用CloseHandle函数关闭句柄。系统在进程终止时自动关闭句柄。互斥对象是当它的最后一个句柄关闭时被销毁。”(强调我的)但是我会在代码示例中添加它。
    • @jmnben:没错。当一个进程终止时,操作系统会关闭该进程拥有的所有句柄。事实上,我认为手动关闭互斥体,以防止多个并发实例至少部分违背了目的。如果您想在允许另一个实例之前确保该进程已经消失,请让操作系统为您清理句柄。过早关闭句柄可能会打开一个机会之窗,可以同时访问受保护的资源。
    【解决方案4】:

    TLDR:防止同一进程出现多个实例的唯一安全且通用的方法是使用互斥锁,因为只有这样才能保证不会给您带来竞争条件。

    在这里你有一篇关于这个主题的好文章。我在必须做类似的事情时使用它并且解决方案运行良好:AvoidingMultipleInstances。

    【讨论】:

      【解决方案5】:

      我也见过这个解决方案,没有 GetLastError():

          HANDLE hMutex = CreateMutexA(NULL, FALSE, "my mutex");
          DWORD dwMutexWaitResult = WaitForSingleObject(hMutex, 0);
          if (dwMutexWaitResult != WAIT_OBJECT_0)
          {
              MessageBox(HWND_DESKTOP, TEXT("This application is already running"), TEXT("Information"), MB_OK | MB_ICONINFORMATION);
              CloseHandle(hMutex);
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-02-11
        • 2021-05-05
        • 2011-10-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-20
        • 1970-01-01
        相关资源
        最近更新 更多